diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 450524693f..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "BUG" -labels: '' -assignees: '' - ---- - -### Describe the bug -A clear and concise description of what the bug is. - -### To Reproduce -To help us to reproduce this bug, please provide information below: - -1. Your Python version. -2. The version of xinference you use. -3. Versions of crucial packages. -4. Full stack of the error. -5. Minimized code to reproduce the error. - -### Expected behavior -A clear and concise description of what you expected to happen. - -### Additional context -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000000..dd62dee44a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,77 @@ +name: "Bug Report" +description: Submit a bug report to help us improve Xinference. You should provide useful information AMAP rather than simply describing what happened. / 提交一个问题报告来帮助我们改进 Xinference。你必须提供有用的信息而不只是描述发生的现象,否则将不予处理。 +body: + - type: textarea + id: system-info + attributes: + label: System Info / 系統信息 + description: Your operating environment / 您的运行环境信息 + placeholder: Includes Cuda version, transformers / llama-cpp-python / vllm version, Python version, operating system... / 包括Cuda版本,transformers / llama-cpp-python / vllm版本,Python版本,操作系统等。 + validations: + required: true + + - type: checkboxes + id: information-scripts-examples + attributes: + label: Running Xinference with Docker? / 是否使用 Docker 运行 Xinfernece? + description: 'How are you using Xinference? / 以何种方式使用 Xinference?' + options: + - label: docker / docker + - label: pip install / 通过 pip install 安装 + - label: installation from source / 从源码安装 + + - type: textarea + id: start-way + attributes: + label: Version info / 版本信息 + description: The version of Xinference you are running / Xinference 版本 + validations: + required: true + + - type: textarea + id: commandline + attributes: + label: The command used to start Xinference / 用以启动 xinference 的命令 + description: | + Please provide the command used to start Xinference. + If it is a distributed scenario, the commands for starting the supervisor and worker need to be listed separately. + If it is a Docker scenario, please provide the complete command for starting Xinference through Docker. + If it is another method, please describe it specifically. + + 请提供启动 xinference 的命令。 + 如果是分布式场景,启动 supervisor 和 worker 的命令需要分别列出。 + 如果是docker场景,请提供通过 docker 启动 xinference 的完整命令。 + 如果是其他方式,请具体描述。 + validations: + required: true + + - type: textarea + id: reproduction + validations: + required: true + attributes: + label: Reproduction / 复现过程 + description: | + Please provide a code example that reproduces the problem you encountered, preferably with a minimal reproduction unit. + If you have code snippets, error messages, stack traces, please provide them here as well. + Please format your code correctly using code tags. See https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting + Do not use screenshots, as they are difficult to read and (more importantly) do not allow others to copy and paste your code. + + 请提供能重现您遇到的问题的代码示例,最好是最小复现单元。 + 如果您有代码片段、错误信息、堆栈跟踪、涉及的命令行操作等也请在此提供。 + 请使用代码标签正确格式化您的代码。请参见 https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks#syntax-highlighting + 请勿使用截图,因为截图难以阅读,而且(更重要的是)不允许他人复制粘贴您的代码。 + placeholder: | + Steps to reproduce the behavior/复现Bug的步骤: + + 1. + 2. + 3. + + - type: textarea + id: expected-behavior + validations: + required: true + attributes: + label: Expected behavior / 期待表现 + description: "A clear and concise description of what you would expect to happen. / 简单描述您期望发生的事情。" \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index a61ec537d4..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -### Is your feature request related to a problem? Please describe -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -### Describe the solution you'd like -A clear and concise description of what you want to happen. - -### Describe alternatives you've considered -A clear and concise description of any alternative solutions or features you've considered. - -### Additional context -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000000..81bac43d89 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,34 @@ +name: "Feature request" +description: Submit a request for a new Xinference feature / 提交一个新的 Xinference 的功能建议 +labels: [ "feature" ] +body: + - type: textarea + id: feature-request + validations: + required: true + attributes: + label: Feature request / 功能建议 + description: | + A brief description of the functional proposal. + 对功能建议的简述。 + + - type: textarea + id: motivation + validations: + required: true + attributes: + label: Motivation / 动机 + description: | + Your motivation for making the suggestion. If that motivation is related to another GitHub issue, link to it here. + 您提出建议的动机。如果该动机与另一个 GitHub 问题有关,请在此处提供对应的链接。 + + - type: textarea + id: contribution + validations: + required: true + attributes: + label: Your contribution / 您的贡献 + description: | + + Your PR link or any other link you can help with. + 您的PR链接或者其他您能提供帮助的链接。 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md deleted file mode 100644 index 02357a9207..0000000000 --- a/.github/ISSUE_TEMPLATE/other.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Other -about: Submit other issues here. -title: '' -labels: '' -assignees: '' - ---- - -Note that the issue tracker is NOT the place for general support. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 4510ec6419..0000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: Question -about: Ask a question here. -title: 'QUESTION' -labels: 'question' -assignees: '' ---- - -Note that the issue tracker is NOT the place for general support. diff --git a/.github/workflows/docker-cd.yaml b/.github/workflows/docker-cd.yaml index 72aec06d03..e5ef82e27f 100644 --- a/.github/workflows/docker-cd.yaml +++ b/.github/workflows/docker-cd.yaml @@ -14,10 +14,10 @@ concurrency: jobs: build: - runs-on: ubuntu-latest + runs-on: self-hosted strategy: matrix: - python-version: [ "3.10" ] + python-version: [ "3.9" ] steps: - name: Check out code uses: actions/checkout@v3 @@ -38,10 +38,6 @@ jobs: DOCKER_ORG: ${{ secrets.DOCKERHUB_USERNAME }} PY_VERSION: ${{ matrix.python-version }} run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" if [[ "$GITHUB_REF" =~ ^"refs/tags/" ]]; then export GIT_TAG=$(echo "$GITHUB_REF" | sed -e "s/refs\/tags\///g") fi @@ -65,6 +61,7 @@ jobs: docker push "$DOCKER_ORG/xinference:${IMAGE_TAG}" docker build -t "$DOCKER_ORG/xinference:${IMAGE_TAG}-cpu" --progress=plain -f xinference/deploy/docker/cpu.Dockerfile . docker push "$DOCKER_ORG/xinference:${IMAGE_TAG}-cpu" + echo "XINFERENCE_IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV done if [[ -n "$GIT_TAG" ]]; then @@ -72,4 +69,35 @@ jobs: docker push "$DOCKER_ORG/xinference:latest" docker tag "$DOCKER_ORG/xinference:${GIT_TAG}-cpu" "$DOCKER_ORG/xinference:latest-cpu" docker push "$DOCKER_ORG/xinference:latest-cpu" + echo "XINFERENCE_GIT_TAG=${GIT_TAG}" >> $GITHUB_ENV fi + + - name: Log in to Aliyun Docker Hub + uses: docker/login-action@v1 + with: + registry: registry.cn-hangzhou.aliyuncs.com + username: ${{ secrets.DOCKERHUB_ALIYUN_USERNAME }} + password: ${{ secrets.DOCKERHUB_ALIYUN_PASSWORD }} + + - name: Push docker image to Aliyun + shell: bash + if: ${{ github.repository == 'xorbitsai/inference' }} + env: + DOCKER_ORG: registry.cn-hangzhou.aliyuncs.com/xprobe_xinference + run: | + docker tag "xprobe/xinference:${XINFERENCE_IMAGE_TAG}" "${DOCKER_ORG}/xinference:${XINFERENCE_IMAGE_TAG}" + docker push "${DOCKER_ORG}/xinference:${XINFERENCE_IMAGE_TAG}" + docker tag "xprobe/xinference:${XINFERENCE_IMAGE_TAG}-cpu" "${DOCKER_ORG}/xinference:${XINFERENCE_IMAGE_TAG}-cpu" + docker push "${DOCKER_ORG}/xinference:${XINFERENCE_IMAGE_TAG}-cpu" + if [[ -n "$XINFERENCE_GIT_TAG" ]]; then + docker tag "xprobe/xinference:${XINFERENCE_GIT_TAG}" "$DOCKER_ORG/xinference:latest" + docker push "$DOCKER_ORG/xinference:latest" + docker tag "xprobe/xinference:${XINFERENCE_GIT_TAG}-cpu" "$DOCKER_ORG/xinference:latest-cpu" + docker push "$DOCKER_ORG/xinference:latest-cpu" + fi + + - name: Clean docker image cache + shell: bash + if: ${{ github.repository == 'xorbitsai/inference' }} + run: | + docker system prune -f -a diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml new file mode 100644 index 0000000000..688992e9d2 --- /dev/null +++ b/.github/workflows/issue.yaml @@ -0,0 +1,24 @@ +name: Close inactive issues +on: + schedule: + - cron: "0 19 * * *" + workflow_dispatch: + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v9 + with: + days-before-issue-stale: 7 + days-before-issue-close: 5 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open for 7 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 5 days since being marked as stale." + days-before-pr-stale: -1 + days-before-pr-close: -1 + operations-per-run: 500 + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml index 885fff36a3..94343bef57 100644 --- a/.github/workflows/python.yaml +++ b/.github/workflows/python.yaml @@ -47,7 +47,7 @@ jobs: - name: mypy run: pip install mypy && mypy --install-types --non-interactive xinference - name: codespell - run: pip install codespell && codespell xinference + run: pip install codespell && codespell --ignore-words-list thirdparty xinference - name: Set up Node.js uses: actions/setup-node@v1 with: @@ -66,22 +66,24 @@ jobs: env: CONDA_ENV: test SELF_HOST_PYTHON: /root/miniconda3/envs/inference_test/bin/python + SELF_HOST_CONDA: /root/miniconda3/condabin/conda defaults: run: shell: bash -l {0} strategy: fail-fast: false matrix: - os: [ "ubuntu-latest", "macos-latest", "windows-latest" ] + os: [ "ubuntu-latest", "macos-12", "windows-latest" ] python-version: [ "3.8", "3.9", "3.10", "3.11" ] module: [ "xinference" ] exclude: - - { os: macos-latest, python-version: 3.9 } - - { os: macos-latest, python-version: 3.10 } + - { os: macos-12, python-version: 3.9 } + - { os: macos-12, python-version: 3.10 } - { os: windows-latest, python-version: 3.9 } - { os: windows-latest, python-version: 3.10 } include: - { os: self-hosted, module: gpu, python-version: 3.9} + - { os: macos-latest, module: metal, python-version: "3.10" } steps: - name: Check out code @@ -91,7 +93,7 @@ jobs: submodules: recursive - name: Set up conda ${{ matrix.python-version }} - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 if: ${{ matrix.module != 'gpu' }} with: python-version: ${{ matrix.python-version }} @@ -109,7 +111,10 @@ jobs: sudo rm -rf "/usr/local/share/boost" sudo rm -rf "$AGENT_TOOLSDIRECTORY" fi - pip install "llama-cpp-python>=0.2.23,!=0.2.58" + if [ "$MODULE" == "metal" ]; then + pip install mlx-lm + fi + pip install "llama-cpp-python==0.2.77" --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu pip install transformers pip install attrdict pip install "timm>=0.9.16" @@ -119,14 +124,17 @@ jobs: pip install sentencepiece pip install transformers_stream_generator pip install bitsandbytes - pip install ctransformers pip install "sentence-transformers>=2.3.1" - pip install s3fs pip install modelscope pip install diffusers pip install protobuf + pip install FlagEmbedding + pip install "tenacity>=8.2.0,<8.4.0" pip install -e ".[dev]" pip install "jinja2==3.1.2" + pip install tensorizer + pip install eva-decord + pip install jj-pytorchvideo working-directory: . - name: Test with pytest @@ -134,7 +142,7 @@ jobs: MODULE: ${{ matrix.module }} run: | if [ "$MODULE" == "gpu" ]; then - ${{ env.SELF_HOST_PYTHON }} -m pip install "openai>1" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "openai>1,<1.40" ${{ env.SELF_HOST_PYTHON }} -m pip install -U modelscope ${{ env.SELF_HOST_PYTHON }} -m pip install -U sse_starlette ${{ env.SELF_HOST_PYTHON }} -m pip install -U xoscar @@ -142,18 +150,54 @@ jobs: ${{ env.SELF_HOST_PYTHON }} -m pip install -U "passlib[bcrypt]" ${{ env.SELF_HOST_PYTHON }} -m pip install -U "aioprometheus[starlette]" ${{ env.SELF_HOST_PYTHON }} -m pip install -U "pynvml" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "transformers" + ${{ env.SELF_HOST_CONDA }} install -c conda-forge pynini=2.1.5 + ${{ env.SELF_HOST_CONDA }} install -c conda-forge "ffmpeg<7" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U funasr + ${{ env.SELF_HOST_PYTHON }} -m pip install -U nemo_text_processing<1.1.0 + ${{ env.SELF_HOST_PYTHON }} -m pip install -U omegaconf~=2.3.0 + ${{ env.SELF_HOST_PYTHON }} -m pip install -U WeTextProcessing<1.0.4 + ${{ env.SELF_HOST_PYTHON }} -m pip install -U librosa + ${{ env.SELF_HOST_PYTHON }} -m pip install -U xxhash + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "ChatTTS>0.1" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U HyperPyYAML + ${{ env.SELF_HOST_PYTHON }} -m pip uninstall -y matcha-tts + ${{ env.SELF_HOST_PYTHON }} -m pip install -U onnxruntime-gpu==1.16.0; sys_platform == 'linux' + ${{ env.SELF_HOST_PYTHON }} -m pip install -U openai-whisper + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "torch==2.3.1" "torchaudio==2.3.1" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "loguru" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "natsort" + ${{ env.SELF_HOST_PYTHON }} -m pip install -U "loralib" + ${{ env.SELF_HOST_PYTHON }} -m pip uninstall -y opencc + ${{ env.SELF_HOST_PYTHON }} -m pip uninstall -y "faster_whisper" + ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ + -W ignore::PendingDeprecationWarning \ + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/image/tests/test_stable_diffusion.py && \ ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ -W ignore::PendingDeprecationWarning \ - --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/image/tests/test_stable_diffusion.py + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_whisper.py && \ ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ -W ignore::PendingDeprecationWarning \ - --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_whisper.py + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_funasr.py && \ + ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ + -W ignore::PendingDeprecationWarning \ + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_chattts.py && \ + ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ + -W ignore::PendingDeprecationWarning \ + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_cosyvoice.py && \ + ${{ env.SELF_HOST_PYTHON }} -m pytest --timeout=1500 \ + -W ignore::PendingDeprecationWarning \ + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/audio/tests/test_fish_speech.py + elif [ "$MODULE" == "metal" ]; then + pytest --timeout=1500 \ + -W ignore::PendingDeprecationWarning \ + --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/model/llm/mlx/tests/test_mlx.py else pytest --timeout=1500 \ -W ignore::PendingDeprecationWarning \ --cov-config=setup.cfg --cov-report=xml --cov=xinference xinference/client/tests/test_client.py pytest --timeout=1500 \ -W ignore::PendingDeprecationWarning \ - --cov-config=setup.cfg --cov-report=xml --cov=xinference --ignore xinference/client/tests/test_client.py --ignore xinference/model/image/tests/test_stable_diffusion.py --ignore xinference/model/audio/tests/test_whisper.py xinference + --cov-config=setup.cfg --cov-report=xml --cov=xinference --ignore xinference/client/tests/test_client.py --ignore xinference/model/image/tests/test_stable_diffusion.py --ignore xinference/model/audio/tests xinference fi working-directory: . diff --git a/.gitignore b/.gitignore index 5940628faa..648fa3a462 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,9 @@ dmypy.json .vscode *.iml +# VIM +*.sw* + # web staff node_modules/ static/ @@ -141,4 +144,4 @@ doc/source/savefig/ asv/results -.DS_Store \ No newline at end of file +.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f2693ca23a..61d19c86ae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,29 +4,36 @@ repos: rev: 23.12.0 hooks: - id: black + exclude: thirdparty - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: end-of-file-fixer + exclude: ^xinference/thirdparty - id: trailing-whitespace + exclude: thirdparty - repo: https://github.com/PyCQA/flake8 rev: 6.0.0 hooks: - id: flake8 args: [--config, setup.cfg] + exclude: thirdparty - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: - id: isort args: [--sp, setup.cfg] + exclude: thirdparty - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.9.0 hooks: - id: mypy additional_dependencies: ["tokenize-rt==3.2.0", "types-requests", "types-tabulate"] args: [--ignore-missing-imports, --follow-imports, skip] + exclude: thirdparty - repo: https://github.com/codespell-project/codespell rev: v2.2.2 hooks: - id: codespell args: [ --config, setup.cfg] + exclude: thirdparty diff --git a/README.md b/README.md index 4006f9a168..fbee3a41e5 100644 --- a/README.md +++ b/README.md @@ -26,23 +26,27 @@ potential of cutting-edge AI models. ## 🔥 Hot Topics ### Framework Enhancements +- Support Continuous batching for Transformers engine: [#1724](https://github.com/xorbitsai/inference/pull/1724) +- Support MLX backend for Apple Silicon chips: [#1765](https://github.com/xorbitsai/inference/pull/1765) - Support specifying worker and GPU indexes for launching models: [#1195](https://github.com/xorbitsai/inference/pull/1195) - Support SGLang backend: [#1161](https://github.com/xorbitsai/inference/pull/1161) - Support LoRA for LLM and image models: [#1080](https://github.com/xorbitsai/inference/pull/1080) - Support speech recognition model: [#929](https://github.com/xorbitsai/inference/pull/929) - Metrics support: [#906](https://github.com/xorbitsai/inference/pull/906) -- Docker image: [#855](https://github.com/xorbitsai/inference/pull/855) -- Support multimodal: [#829](https://github.com/xorbitsai/inference/pull/829) ### New Models -- Built-in support for [Qwen1.5 32B](https://huggingface.co/Qwen/Qwen1.5-32B-Chat): [#1249](https://github.com/xorbitsai/inference/pull/1249) -- Built-in support for [OmniLMM](https://github.com/OpenBMB/OmniLMM): [#1171](https://github.com/xorbitsai/inference/pull/1171) -- Built-in support for [Gemma](https://github.com/google-deepmind/gemma): [#1024](https://github.com/xorbitsai/inference/pull/1024) -- Built-in support for [Qwen1.5](https://github.com/QwenLM/Qwen1.5): [#994](https://github.com/xorbitsai/inference/pull/994) -- Built-in support for [Yi-VL](https://github.com/01-ai/Yi): [#946](https://github.com/xorbitsai/inference/pull/946) -- Built-in support for [Whisper](https://github.com/openai/whisper): [#929](https://github.com/xorbitsai/inference/pull/929) +- Built-in support for [CogVideoX](https://github.com/THUDM/CogVideo): [#2049](https://github.com/xorbitsai/inference/pull/2049) +- Built-in support for [flux.1-schnell & flux.1-dev](https://www.basedlabs.ai/tools/flux1): [#2007](https://github.com/xorbitsai/inference/pull/2007) +- Built-in support for [MiniCPM-V 2.6](https://github.com/OpenBMB/MiniCPM-V): [#2031](https://github.com/xorbitsai/inference/pull/2031) +- Built-in support for [Kolors](https://huggingface.co/Kwai-Kolors/Kolors): [#2028](https://github.com/xorbitsai/inference/pull/2028) +- Built-in support for [SenseVoice](https://github.com/FunAudioLLM/SenseVoice): [#2008](https://github.com/xorbitsai/inference/pull/2008) +- Built-in support for [Mistral Large 2](https://mistral.ai/news/mistral-large-2407/): [#1944](https://github.com/xorbitsai/inference/pull/1944) +- Built-in support for [llama3.1](https://ai.meta.com/blog/meta-llama-3-1/): [#1932](https://github.com/xorbitsai/inference/pull/1932) +- Built-in support for [Mistral Nemo](https://mistral.ai/news/mistral-nemo/): [#1936](https://github.com/xorbitsai/inference/pull/1936) ### Integrations - [Dify](https://docs.dify.ai/advanced/model-configuration/xinference): an LLMOps platform that enables developers (and even non-developers) to quickly build useful applications based on large language models, ensuring they are visual, operable, and improvable. +- [FastGPT](https://github.com/labring/FastGPT): a knowledge-based platform built on the LLM, offers out-of-the-box data processing and model invocation capabilities, allows for workflow orchestration through Flow visualization. - [Chatbox](https://chatboxai.app/): a desktop client for multiple cutting-edge LLM models, available on Windows, Mac and Linux. +- [RAGFlow](https://github.com/infiniflow/ragflow): is an open-source RAG engine based on deep document understanding. ## Key Features @@ -93,7 +97,7 @@ with popular third-party libraries including [LangChain](https://python.langchai ### Jupyter Notebook -The lightest way to experience Xinference is to try our [Juypter Notebook on Google Colab](https://colab.research.google.com/github/xorbitsai/inference/blob/main/examples/Xinference_Quick_Start.ipynb). +The lightest way to experience Xinference is to try our [Jupyter Notebook on Google Colab](https://colab.research.google.com/github/xorbitsai/inference/blob/main/examples/Xinference_Quick_Start.ipynb). ### Docker @@ -103,6 +107,24 @@ Nvidia GPU users can start Xinference server using [Xinference Docker Image](htt docker run --name xinference -d -p 9997:9997 -e XINFERENCE_HOME=/data -v :/data --gpus all xprobe/xinference:latest xinference-local -H 0.0.0.0 ``` +### K8s via helm + +Ensure that you have GPU support in your Kubernetes cluster, then install as follows. + +``` +# add repo +helm repo add xinference https://xorbitsai.github.io/xinference-helm-charts + +# update indexes and query xinference versions +helm repo update xinference +helm search repo xinference/xinference --devel --versions + +# install xinference +helm install xinference xinference/xinference -n xinference --version 0.0.1-v +``` + +For more customized installation methods on K8s, please refer to the [documentation](https://inference.readthedocs.io/en/latest/getting_started/using_kubernetes.html). + ### Quick Start Install Xinference by using pip as follows. (For more options, see [Installation page](https://inference.readthedocs.io/en/latest/getting_started/installation.html).) diff --git a/README_zh_CN.md b/README_zh_CN.md index e0f8ebb057..34b9c4621e 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -23,23 +23,27 @@ Xorbits Inference(Xinference)是一个性能强大且功能全面的分布 ## 🔥 近期热点 ### 框架增强 +- 支持 Transformers 引擎的持续批处理: [#1724](https://github.com/xorbitsai/inference/pull/1724) +- 支持针对苹果芯片优化的MLX后端: [#1765](https://github.com/xorbitsai/inference/pull/1765) - 支持加载模型时指定 worker 和 GPU 索引: [#1195](https://github.com/xorbitsai/inference/pull/1195) - 支持 SGLang 后端: [#1161](https://github.com/xorbitsai/inference/pull/1161) - 支持LLM和图像模型的LoRA: [#1080](https://github.com/xorbitsai/inference/pull/1080) - 支持语音识别模型: [#929](https://github.com/xorbitsai/inference/pull/929) - 增加 Metrics 统计信息: [#906](https://github.com/xorbitsai/inference/pull/906) -- Docker 镜像支持: [#855](https://github.com/xorbitsai/inference/pull/855) -- 支持多模态模型:[#829](https://github.com/xorbitsai/inference/pull/829) ### 新模型 -- 内置 [Qwen1.5 32B](https://huggingface.co/Qwen/Qwen1.5-32B-Chat): [#1249](https://github.com/xorbitsai/inference/pull/1249) -- 内置 [OmniLMM](https://github.com/OpenBMB/OmniLMM): [#1171](https://github.com/xorbitsai/inference/pull/1171) -- 内置 [Gemma](https://github.com/google-deepmind/gemma): [#1024](https://github.com/xorbitsai/inference/pull/1024) -- 内置 [Qwen1.5](https://github.com/QwenLM/Qwen1.5): [#994](https://github.com/xorbitsai/inference/pull/994) -- 内置 [Yi-VL](https://github.com/01-ai/Yi): [#946](https://github.com/xorbitsai/inference/pull/946) -- 内置 [Whisper](https://github.com/openai/whisper): [#929](https://github.com/xorbitsai/inference/pull/929) +- 内置 [CogVideoX](https://github.com/THUDM/CogVideo): [#2049](https://github.com/xorbitsai/inference/pull/2049) +- 内置 [flux.1-schnell & flux.1-dev](https://www.basedlabs.ai/tools/flux1): [#2007](https://github.com/xorbitsai/inference/pull/2007) +- 内置 [MiniCPM-V 2.6](https://github.com/OpenBMB/MiniCPM-V): [#2031](https://github.com/xorbitsai/inference/pull/2031) +- 内置 [Kolors](https://huggingface.co/Kwai-Kolors/Kolors): [#2028](https://github.com/xorbitsai/inference/pull/2028) +- 内置 [SenseVoice](https://github.com/FunAudioLLM/SenseVoice): [#2008](https://github.com/xorbitsai/inference/pull/2008) +- 内置 [Mistral Large 2](https://mistral.ai/news/mistral-large-2407/): [#1944](https://github.com/xorbitsai/inference/pull/1944) +- 内置 [llama3.1](https://ai.meta.com/blog/meta-llama-3-1/): [#1932](https://github.com/xorbitsai/inference/pull/1932) +- 内置 [Mistral Nemo](https://mistral.ai/news/mistral-nemo/): [#1936](https://github.com/xorbitsai/inference/pull/1936) ### 集成 +- [FastGPT](https://doc.fastai.site/docs/development/custom-models/xinference/):一个基于 LLM 大模型的开源 AI 知识库构建平台。提供了开箱即用的数据处理、模型调用、RAG 检索、可视化 AI 工作流编排等能力,帮助您轻松实现复杂的问答场景。 - [Dify](https://docs.dify.ai/advanced/model-configuration/xinference): 一个涵盖了大型语言模型开发、部署、维护和优化的 LLMOps 平台。 - [Chatbox](https://chatboxai.app/): 一个支持前沿大语言模型的桌面客户端,支持 Windows,Mac,以及 Linux。 +- [RAGFlow](https://github.com/infiniflow/ragflow): 是一款基于深度文档理解构建的开源 RAG 引擎。 ## 主要功能 🌟 **模型推理,轻而易举**:大语言模型,语音识别模型,多模态模型的部署流程被大大简化。一个命令即可完成模型的部署工作。 @@ -87,6 +91,24 @@ Xorbits Inference(Xinference)是一个性能强大且功能全面的分布 Nvidia GPU 用户可以使用[Xinference Docker 镜像](https://inference.readthedocs.io/zh-cn/latest/getting_started/using_docker_image.html) 启动 Xinference 服务器。在执行安装命令之前,确保你的系统中已经安装了 [Docker](https://docs.docker.com/get-docker/) 和 [CUDA](https://developer.nvidia.com/cuda-downloads)。 +### Kubernetes + +确保你的 Kubernetes 集群开启了 GPU 支持,然后通过 `helm` 进行如下方式的安装。 + +``` +# 新增xinference仓库 +helm repo add xinference https://xorbitsai.github.io/xinference-helm-charts + +# 更新仓库,查询可安装的版本 +helm repo update xinference +helm search repo xinference/xinference --devel --versions + +# 在K8s中安装xinference +helm install xinference xinference/xinference -n xinference --version 0.0.1-v +``` + +更多定制化安装方式,请参考[文档](https://inference.readthedocs.io/en/latest/getting_started/using_kubernetes.html)。 + ### 快速开始 使用 pip 安装 Xinference,操作如下。(更多选项,请参阅[安装页面](https://inference.readthedocs.io/zh-cn/latest/getting_started/installation.html)。) diff --git a/benchmark/README.md b/benchmark/README.md index 2b50c0cf00..4c0ffc2ebd 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -8,17 +8,33 @@ wget https://huggingface.co/datasets/anon8231489123/ShareGPT_Vicuna_unfiltered/r ``` ## Benchmarking latency + +This tool will sample prompts from dataset, and run benchmark with serialized requests. + ```bash python benchmark_latency.py --dataset /path/to/ShareGPT_V3_unfiltered_cleaned_split.json \ --tokenizer /path/to/tokenizer \ - --num-prompt 100 + --num-prompt 100 \ --model-uid ${model_uid} ``` ## Benchmarking serving + +This tool will sample prompts from dataset, and run benchmark with parallel requests. + ```bash python benchmark_serving.py --dataset /path/to/ShareGPT_V3_unfiltered_cleaned_split.json \ --tokenizer /path/to/tokenizer \ - --num-prompt 100 - --model-uid ${model_uid} + --model-uid ${model_uid} \ + --num-prompt 100 --concurrency 50 +``` + +## Benchmarking long context serving + +This tool will generate long prompts to sort random numbers, according to specified context length. + +``` +python benchmark/benchmark_long.py --context-length ${context_length} --tokenizer /path/to/tokenizer \ + --model-uid ${model_uid} \ + --num-prompts 32 -c 16 ``` diff --git a/benchmark/benchmark_latency.py b/benchmark/benchmark_latency.py index 7b607cef51..3ae8125436 100644 --- a/benchmark/benchmark_latency.py +++ b/benchmark/benchmark_latency.py @@ -16,28 +16,27 @@ import asyncio import logging import random -import time -from typing import List, Tuple import numpy as np -from utils import get_tokenizer, sample_requests, send_request +from utils import get_tokenizer, sample_requests +from benchmark_runner import BenchmarkRunner + logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -REQUEST_LATENCY: List[Tuple[int, int, float]] = [] - -async def benchmark( - api_url: str, - model_uid: str, - input_requests: List[Tuple[str, int, int]], -) -> None: - for request in input_requests: - prompt, prompt_len, output_len = request - await send_request( - api_url, model_uid, prompt, prompt_len, output_len, REQUEST_LATENCY - ) +class LatencyBenchmarkRunner(BenchmarkRunner): + async def _run(self): + total_requests = len(self.input_requests) + for i, request in enumerate(self.input_requests): + await self.send_request(request) + remaining = total_requests - (i + 1) + print( + f"\rProcessed {i + 1}/{total_requests} requests, {remaining} remaining.", + end="", + ) + print("") def main(args: argparse.Namespace): @@ -53,35 +52,17 @@ def main(args: argparse.Namespace): input_requests = sample_requests(args.dataset, args.num_prompts, tokenizer) logger.info("Benchmark starts.") - benchmark_start_time = time.time() - - asyncio.run( - benchmark( - api_url, - model_uid, - input_requests, - ) - ) - benchmark_end_time = time.time() - benchmark_time = benchmark_end_time - benchmark_start_time - print(f"Total time: {benchmark_time:.2f} s") - print(f"Throughput: {len(REQUEST_LATENCY) / benchmark_time:.2f} requests/s") - - # Compute the latency statistics. - avg_latency = np.mean([latency for _, _, latency in REQUEST_LATENCY]) - print(f"Average latency: {avg_latency:.2f} s") - avg_per_token_latency = np.mean( - [ - latency / (prompt_len + output_len) - for prompt_len, output_len, latency in REQUEST_LATENCY - ] + benchmark = LatencyBenchmarkRunner( + api_url, + model_uid, + input_requests, + args.stream, + args.api_key, ) - print(f"Average latency per token: {avg_per_token_latency:.2f} s") - avg_per_output_token_latency = np.mean( - [latency / output_len for _, output_len, latency in REQUEST_LATENCY] - ) - print("Average latency per output token: " f"{avg_per_output_token_latency:.2f} s") + asyncio.run(benchmark.run()) + + benchmark.print_stats() if __name__ == "__main__": @@ -106,6 +87,15 @@ def main(args: argparse.Namespace): help="Trust remote code from huggingface.", ) parser.add_argument("--model-uid", type=str, help="Xinference model UID.") + parser.add_argument( + "--stream", action="store_true", help="Enable streaming responses." + ) + parser.add_argument( + "--api-key", + type=str, + default=None, + help="Authorization api key", + ) args = parser.parse_args() main(args) diff --git a/benchmark/benchmark_long.py b/benchmark/benchmark_long.py new file mode 100644 index 0000000000..75a0d43530 --- /dev/null +++ b/benchmark/benchmark_long.py @@ -0,0 +1,124 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import asyncio +import logging +import random + +import numpy as np + +from utils import generate_sorting_prompts, get_tokenizer +from benchmark_runner import ConcurrentBenchmarkRunner + + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class LongBenchmarkRunner(ConcurrentBenchmarkRunner): + async def _run(self): + tasks = [] + for i in range(self.concurrency): + tasks.append(asyncio.create_task(self.worker(i))) + + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + async def worker(self, i: int): + r = random.Random(i) + index = r.randint(0, len(self.input_requests) - 1) + while self.left > 0: + request = self.input_requests[index] + index += 1 + index = index % len(self.input_requests) + await self.send_request(request) + self.left -= 1 + # pring longer space to overwrite the previous when left decrease + print("\rdone_request, left %d " % (self.left), end="") + # The last one + print("") + + +def main(args: argparse.Namespace): + if args.concurrency > args.num_prompts: + print("Fix concurrency with num_prompts %d" % (args.num_prompts)) + args.concurrency = args.num_prompts + print(args) + + random.seed(args.seed) + np.random.seed(args.seed) + + api_url = f"http://{args.host}:{args.port}/v1/chat/completions" + model_uid = args.model_uid + + logger.info("Preparing for benchmark.") + tokenizer = get_tokenizer(args.tokenizer, trust_remote_code=args.trust_remote_code) + # XXX: generate_sorting_prompts() currently only generate prompts 1/2 to 2/3 of context_length, + # because tokenizers vary by models, consider improve in the future. + input_requests = generate_sorting_prompts( + args.concurrency, args.context_length, args.context_length / 2 - 20, tokenizer + ) + + logger.info("Benchmark starts.") + + benchmark = LongBenchmarkRunner( + api_url, + model_uid, + input_requests, + args.stream, + concurrency=args.concurrency, + api_key=args.api_key, + ) + asyncio.run(benchmark.run()) + + benchmark.print_stats() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Benchmark the online serving throughput with long context." + ) + parser.add_argument("--host", type=str, default="localhost") + parser.add_argument("--port", type=int, default=9997) + parser.add_argument( + "--tokenizer", type=str, required=True, help="Name or path of the tokenizer." + ) + parser.add_argument( + "--context-length", type=int, default=32768, help="model context_length." + ) + parser.add_argument( + "--num-prompts", type=int, default=16, help="Number of prompts to process." + ) + parser.add_argument( + "--concurrency", + "-c", + type=int, + default=16, + help="Set the concurrency of request to send", + ) + parser.add_argument( + "--trust-remote-code", + action="store_true", + help="Trust remote code from huggingface.", + ) + parser.add_argument("--model-uid", type=str, help="Xinference model UID.") + parser.add_argument( + "--api-key", type=str, default=None, help="Authorization api key", + ) + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--stream", action="store_true", help="Enable streaming responses." + ) + args = parser.parse_args() + main(args) diff --git a/benchmark/benchmark_rerank.py b/benchmark/benchmark_rerank.py new file mode 100644 index 0000000000..09e87d8758 --- /dev/null +++ b/benchmark/benchmark_rerank.py @@ -0,0 +1,186 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import asyncio +import logging +import random +import time +import aiohttp +from typing import List, Dict, Optional +from datasets import load_dataset +import numpy as np +from benchmark_runner import ConcurrentBenchmarkRunner + + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class RerankBenchmarkRunner(ConcurrentBenchmarkRunner): + def __init__( + self, + api_url: str, + model_uid: str, + input_requests: List[Dict], + stream: bool, + top_n: int, + concurrency: int, + api_key: Optional[str] = None, + ): + super().__init__( + api_url, + model_uid, + input_requests, + stream, + concurrency, + api_key, + ) + self.top_n = top_n + + async def _run(self): + tasks = [] + for i in range(self.concurrency): + tasks.append(asyncio.create_task(self.worker(i))) + + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + async def worker(self, i: int): + r = random.Random(i) + index = r.randint(0, len(self.input_requests) - 1) + while self.left > 0: + request = self.input_requests[index] + index += 1 + index = index % len(self.input_requests) + await self.send_request(request) + self.left -= 1 + # pring longer space to overwrite the previous when left decrease + print("\rdone_request, left %d " % (self.left), end="") + # The last one + print("") + + async def send_request(self, request, warming_up: bool = False): + prompt, documents = request["query"], request["positive"] + request_start_time = time.time() + + pload = { + "model": self.model_uid, + "top_n": self.top_n, + "query": prompt, + "documents": documents, + } + + headers = {"User-Agent": "Benchmark Client"} + if self.api_key: + headers["Authorization"] = f"Bearer {self.api_key}" + + timeout = aiohttp.ClientTimeout(total=3 * 3600) + async with aiohttp.ClientSession(timeout=timeout) as session: + async with session.post( + self.api_url, headers=headers, json=pload + ) as response: + resp = await response.json() + if response.status == 200: + request_end_time = time.time() + request_latency = request_end_time - request_start_time + if not warming_up: + self.outputs.append(request_latency) + else: + logger.error(f"Failed to create chat completion: {resp}") + + +def main(args: argparse.Namespace): + print(args) + + random.seed(args.seed) + np.random.seed(args.seed) + + api_url = f"http://{args.host}:{args.port}/v1/rerank" + model_uid = args.model_uid + + logger.info("Preparing for benchmark.") + dataset = load_dataset(args.dataset) + input_requests = dataset["test"].remove_columns("negative").to_list() + if args.num_query > 0: + input_requests = input_requests[: args.num_query] + else: + args.num_query = len(input_requests) + + logger.info("Benchmark starts.") + + benchmark = RerankBenchmarkRunner( + api_url, + model_uid, + input_requests, + args.stream, + top_n=args.top_n, + concurrency=args.concurrency, + api_key=args.api_key, + ) + asyncio.run(benchmark.run()) + + # TODO: Print the results of request_latency in detail. + # benchmark.print_stats() needs to be overridden + print(f"Total time: {benchmark.benchmark_time:.2f} s") + print(f"Throughput: {args.num_query / benchmark.benchmark_time:.2f} requests/s") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Stress test the rerank model.") + parser.add_argument("--host", type=str, default="localhost") + parser.add_argument("--port", type=int, default=9997) + parser.add_argument( + "--dataset", + type=str, + default="mteb/scidocs-reranking", + help="Path to the dataset.", + ) + parser.add_argument( + "--concurrency", + "-c", + type=int, + default=16, + help="Set the concurrency of request to send", + ) + parser.add_argument( + "--top-n", + "-n", + type=int, + default=5, + help="Set the top n to the rerank", + ) + parser.add_argument( + "--num-query", + "-q", + type=int, + default=-1, + help="Set the query dataset count, default is all", + ) + parser.add_argument( + "--trust-remote-code", + action="store_true", + help="Trust remote code from huggingface.", + ) + parser.add_argument( + "--model-uid", type=str, required=True, help="Xinference model UID." + ) + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--stream", action="store_true", help="Enable streaming responses." + ) + parser.add_argument( + "--api-key", type=str, default=None, help="Authorization api key", + ) + args = parser.parse_args() + main(args) diff --git a/benchmark/benchmark_runner.py b/benchmark/benchmark_runner.py new file mode 100644 index 0000000000..78bcff0ecc --- /dev/null +++ b/benchmark/benchmark_runner.py @@ -0,0 +1,380 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import aiohttp +import json +import sys +import traceback +import warnings +import logging +from dataclasses import dataclass, field +import time +from typing import List, Optional, Tuple + +import numpy as np + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +AIOHTTP_TIMEOUT = aiohttp.ClientTimeout(total=3 * 3600) + + +def remove_prefix(text: str, prefix: str) -> str: + if text.startswith(prefix): + return text[len(prefix) :].strip() + return text.strip() + + +@dataclass +class RequestOutput: + success: bool = False + prompt_len: int = 0 + completion_tokens: int = 0 + latency: float = 0.0 + ttft: float = 0.0 + itl: List[float] = field(default_factory=list) # List of inter-token latencies + error: str = "" + + +class BenchmarkRunner: + def __init__( + self, + api_url: str, + model_uid: str, + input_requests: List[Tuple[str, int, int]], + stream: bool, + api_key: Optional[str]=None, + ): + self.api_url = api_url + self.model_uid = model_uid + self.input_requests = input_requests + self.outputs: List[RequestOutput] = [] + self.benchmark_time = None + self.stream = stream + self.api_key = api_key + + async def run(self): + await self.warm_up() + start_time = time.time() + await self._run() + end_time = time.time() + self.benchmark_time = end_time - start_time + + async def warm_up(self, num_requests: int = 5): + logger.info("Warming up...") + for i in range(min(num_requests, len(self.input_requests))): + request = self.input_requests[i] + await self.send_request(request, warming_up=True) + logger.info("Warm-up completed.") + + async def _run(self): + pass + + async def send_request(self, request: tuple, warming_up: bool = False): + prompt, prompt_len, output_len = request + + if self.stream: + pload = { + "model": self.model_uid, + "n": 1, + "temperature": 0.6, + "top_p": 0.9, + "max_tokens": output_len, + "stream": True, + "messages": [{"role": "user", "content": prompt}], + "stream_options": {"include_usage": True}, + } + else: + pload = { + "model": self.model_uid, + "n": 1, + "temperature": 0.6, + "top_p": 0.9, + "max_tokens": output_len, + "stream": False, + "messages": [{"role": "user", "content": prompt}], + } + + headers = {"User-Agent": "Benchmark Client"} + if self.api_key: + headers["Authorization"] = f"Bearer {self.api_key}" + + async with aiohttp.ClientSession(timeout=AIOHTTP_TIMEOUT) as session: + output = RequestOutput(prompt_len=prompt_len) + ttft = 0.0 + st = time.perf_counter() + most_recent_timestamp = st + + try: + async with session.post( + self.api_url, headers=headers, json=pload + ) as response: + if response.status == 200: + if self.stream: + async for chunk_bytes in response.content: + # { + # "id": "chataec79465-dfea-46af-81b9-c28124063fc0", + # "model": "llama-3-instruct", + # "created": 1721202668, + # "object": "chat.completion.chunk", + # "choices": [ + # { + # "index": 0, + # "delta": {"role": "assistant", "content": ""}, + # "finish_reason": null, + # } + # ], + # } + chunk_bytes = chunk_bytes.strip() + if not chunk_bytes: + continue + + chunk = remove_prefix(chunk_bytes.decode("utf-8"), "data:") + + if chunk == "[DONE]": + latency = time.perf_counter() - st + else: + timestamp = time.perf_counter() + data = json.loads(chunk) + + # First token + if ttft == 0.0: + ttft = time.perf_counter() - st + output.ttft = ttft + + # Decoding phase + else: + output.itl.append(timestamp - most_recent_timestamp) + + most_recent_timestamp = timestamp + + output.latency = latency + output.success = True + output.completion_tokens = data["usage"]["completion_tokens"] + else: + resp = await response.json() + output.latency = time.perf_counter() - st + output.success = True + output.completion_tokens = resp["usage"]["completion_tokens"] + except Exception: + output.success = False + exc_info = sys.exc_info() + output.error = "".join(traceback.format_exception(*exc_info)) + + if not warming_up: + self.outputs.append(output) + + def print_stats(self): + total_time = self.benchmark_time + + if self.stream: + # Initialize variables for metrics + total_input = 0 + completed = 0 + actual_output_lens = [] + itls = [] + tpots = [] + ttfts = [] + + for output in self.outputs: + if output.success: + actual_output_lens.append(output.completion_tokens) + total_input += output.prompt_len + if output.completion_tokens > 1: + tpots.append( + (output.latency - output.ttft) + / (output.completion_tokens - 1) + ) + itls += output.itl + ttfts.append(output.ttft) + completed += 1 + else: + actual_output_lens.append(0) + + if completed == 0: + warnings.warn( + "All requests failed. This is likely due to a misconfiguration " + "on the benchmark arguments.", + stacklevel=2, + ) + + # Calculate statistics + total_output = sum(actual_output_lens) + request_throughput = completed / total_time if total_time > 0 else 0 + input_throughput = total_input / total_time if total_time > 0 else 0 + output_throughput = total_output / total_time if total_time > 0 else 0 + + mean_ttft = np.mean(ttfts) * 1000 if ttfts else 0 + median_ttft = np.median(ttfts) * 1000 if ttfts else 0 + std_ttft = np.std(ttfts) * 1000 if ttfts else 0 + p99_ttft = np.percentile(ttfts, 99) * 1000 if ttfts else 0 + + mean_tpot = np.mean(tpots) * 1000 if tpots else 0 + median_tpot = np.median(tpots) * 1000 if tpots else 0 + std_tpot = np.std(tpots) * 1000 if tpots else 0 + p99_tpot = np.percentile(tpots, 99) * 1000 if tpots else 0 + + mean_itl = np.mean(itls) * 1000 if itls else 0 + median_itl = np.median(itls) * 1000 if itls else 0 + std_itl = np.std(itls) * 1000 if itls else 0 + p99_itl = np.percentile(itls, 99) * 1000 if itls else 0 + + # Print benchmark results + print("{s:{c}^{n}}".format(s=" Benchmark Result ", n=50, c="=")) + print("{:<40} {:<10}".format("Successful requests:", completed)) + print("{:<40} {:<10.2f}".format("Benchmark duration (s):", total_time)) + print("{:<40} {:<10}".format("Total input tokens:", total_input)) + print("{:<40} {:<10}".format("Total generated tokens:", total_output)) + print( + "{:<40} {:<10.2f}".format( + "Request throughput (req/s):", request_throughput + ) + ) + print( + "{:<40} {:<10.2f}".format( + "Input token throughput (tok/s):", input_throughput + ) + ) + print( + "{:<40} {:<10.2f}".format( + "Output token throughput (tok/s):", output_throughput + ) + ) + + print("{s:{c}^{n}}".format(s="Time to First Token", n=50, c="-")) + print("{:<40} {:<10.4f}".format("Mean TTFT (ms):", mean_ttft)) + print("{:<40} {:<10.4f}".format("Median TTFT (ms):", median_ttft)) + print("{:<40} {:<10.4f}".format("Std TTFT (ms):", std_ttft)) + print("{:<40} {:<10.4f}".format("P99 TTFT (ms):", p99_ttft)) + + print( + "{s:{c}^{n}}".format( + s="Time per Output Token (excl. 1st token)", n=50, c="-" + ) + ) + print("{:<40} {:<10.4f}".format("Mean TPOT (ms):", mean_tpot)) + print("{:<40} {:<10.4f}".format("Median TPOT (ms):", median_tpot)) + print("{:<40} {:<10.4f}".format("Std TPOT (ms):", std_tpot)) + print("{:<40} {:<10.4f}".format("P99 TPOT (ms):", p99_tpot)) + + print("{s:{c}^{n}}".format(s="Inter-token Latency", n=50, c="-")) + print("{:<40} {:<10.4f}".format("Mean ITL (ms):", mean_itl)) + print("{:<40} {:<10.4f}".format("Median ITL (ms):", median_itl)) + print("{:<40} {:<10.4f}".format("Std ITL (ms):", std_itl)) + print("{:<40} {:<10.4f}".format("P99 ITL (ms):", p99_itl)) + + print("=" * 50) + else: + # Initialize variables for metrics + total_input = 0 + completed = 0 + actual_output_lens = [] + latencies = [] + per_token_latencies = [] + per_output_token_latencies = [] + + for output in self.outputs: + if output.success: + actual_output_lens.append(output.completion_tokens) + total_input += output.prompt_len + latencies.append(output.latency) + per_token_latencies.append( + output.latency / (output.prompt_len + output.completion_tokens) + ) + if output.completion_tokens > 0: + per_output_token_latencies.append( + output.latency / output.completion_tokens + ) + completed += 1 + else: + actual_output_lens.append(0) + + if completed == 0: + warnings.warn( + "All requests failed. This is likely due to a misconfiguration " + "on the benchmark arguments.", + stacklevel=2, + ) + + # Calculate statistics + total_output = sum(actual_output_lens) + request_throughput = len(self.outputs) / total_time if total_time > 0 else 0 + input_throughput = total_input / total_time if total_time > 0 else 0 + output_throughput = total_output / total_time if total_time > 0 else 0 + + mean_latency = np.mean(latencies) if latencies else 0 + mean_per_token_latency = ( + np.mean(per_token_latencies) if per_token_latencies else 0 + ) + mean_per_output_token_latency = ( + np.mean(per_output_token_latencies) if per_output_token_latencies else 0 + ) + + # Print benchmark results + print("{s:{c}^{n}}".format(s=" Benchmark Result ", n=50, c="=")) + print("{:<40} {:<10}".format("Successful requests:", completed)) + print("{:<40} {:<10.2f}".format("Benchmark duration (s):", total_time)) + print("{:<40} {:<10}".format("Total input tokens:", total_input)) + print("{:<40} {:<10}".format("Total generated tokens:", total_output)) + print( + "{:<40} {:<10.2f}".format( + "Request throughput (req/s):", request_throughput + ) + ) + print( + "{:<40} {:<10.2f}".format( + "Input token throughput (tok/s):", input_throughput + ) + ) + print( + "{:<40} {:<10.2f}".format( + "Output token throughput (tok/s):", output_throughput + ) + ) + + print("{s:{c}^{n}}".format(s="Latency Statistics", n=50, c="-")) + print("{:<40} {:<10.4f}".format("Mean latency (s):", mean_latency)) + print( + "{:<40} {:<10.4f}".format( + "Mean latency per token (s):", mean_per_token_latency + ) + ) + print( + "{:<40} {:<10.4f}".format( + "Mean latency per output token (s):", mean_per_output_token_latency + ) + ) + + print("=" * 50) + + print(f"Total time: {total_time:.2f} s") + print(f"Throughput: {len(self.outputs) / total_time:.2f} requests/s") + + +class ConcurrentBenchmarkRunner(BenchmarkRunner): + def __init__( + self, + api_url: str, + model_uid: str, + input_requests: List[Tuple[str, int, int]], + stream: bool, + concurrency: int, + api_key: Optional[str]=None, + ): + super().__init__(api_url, model_uid, input_requests, stream, api_key) + self.concurrency = concurrency + self.left = len(input_requests) + + async def worker(self): + pass diff --git a/benchmark/benchmark_serving.py b/benchmark/benchmark_serving.py index a474abdac8..105cce0976 100644 --- a/benchmark/benchmark_serving.py +++ b/benchmark/benchmark_serving.py @@ -16,63 +16,83 @@ import asyncio import logging import random -import time -from typing import AsyncGenerator, List, Tuple +from typing import List, Tuple, Optional import numpy as np -from utils import sample_requests, get_tokenizer, send_request +from utils import sample_requests, get_tokenizer +from benchmark_runner import ConcurrentBenchmarkRunner logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -REQUEST_LATENCY: List[Tuple[int, int, float]] = [] - - -async def get_request( - input_requests: List[Tuple[str, int, int]], - request_rate: float, -) -> AsyncGenerator[Tuple[str, int, int], None]: - it = iter(input_requests) - for request in it: - yield request - - if request_rate == float("inf"): - # If the request rate is infinity, then we don't need to wait. - continue - # Sample the request interval from the exponential distribution. - interval = np.random.exponential(1.0 / request_rate) - # The next request will be sent after the interval. - await asyncio.sleep(interval) - - -async def benchmark( - api_url: str, - model_uid: str, - input_requests: List[Tuple[str, int, int]], - request_rate: float, -) -> None: - tasks: List[asyncio.Task] = [] - async for request in get_request(input_requests, request_rate): - prompt, prompt_len, output_len = request - task = asyncio.create_task( - send_request( - api_url, - model_uid, - prompt, - prompt_len, - output_len, - REQUEST_LATENCY, - ) +class ServingBenchmarkRunner(ConcurrentBenchmarkRunner): + def __init__( + self, + api_url: str, + model_uid: str, + input_requests: List[Tuple[str, int, int]], + stream: bool, + concurrency: int, + request_rate: float, + api_key: Optional[str] = None, + ): + super().__init__( + api_url, + model_uid, + input_requests, + stream, + concurrency, + api_key, ) - tasks.append(task) - await asyncio.gather(*tasks) + self.request_rate = request_rate + self.queue = None # delay the creation of the queue + + async def _run(self): + tasks = [] + + for _ in range(self.concurrency): + tasks.append(asyncio.create_task(self.worker())) + + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + async def warm_up(self, num_requests: int = 5): + if self.queue is None: + self.queue = asyncio.Queue(len(self.input_requests)) + + logger.info(f"Enqueuing {len(self.input_requests)} requests.") + for req in iter(self.input_requests): + await self.queue.put(req) + await super().warm_up(num_requests) + + async def worker(self): + """ + wait request dispatch by run(), and then send_request. + When all request is done, most worker will hang on self.queue, + but at least one worker will exit""" + while self.left > 0: + request = await self.queue.get() + await self.send_request(request) + self.left -= 1 + print("\rdone_request, left %d " % (self.left), end="") + + if self.request_rate != float("inf"): + # If the request rate is infinity, then we don't need to wait. + # Sample the request interval from the exponential distribution. + interval = np.random.exponential(1.0 / self.request_rate) + # The next request will be sent after the interval. + await asyncio.sleep(interval) + print("") def main(args: argparse.Namespace): + if args.concurrency > args.num_prompts: + print("Fix concurrency with num_prompts %d" % (args.num_prompts)) + args.concurrency = args.num_prompts print(args) + random.seed(args.seed) np.random.seed(args.seed) @@ -81,41 +101,27 @@ def main(args: argparse.Namespace): logger.info("Preparing for benchmark.") tokenizer = get_tokenizer(args.tokenizer, trust_remote_code=args.trust_remote_code) - input_requests = sample_requests(args.dataset, args.num_prompts, tokenizer) + input_requests = sample_requests( + args.dataset, + args.num_prompts, + tokenizer, + prompt_len_limit=args.prompt_len_limit, + ) logger.info("Benchmark starts.") - benchmark_start_time = time.time() - asyncio.run( - benchmark( - api_url, - model_uid, - input_requests, - args.request_rate, - ) - ) - benchmark_end_time = time.time() - benchmark_time = benchmark_end_time - benchmark_start_time - print(f"Total time: {benchmark_time:.2f} s") - print(f"Throughput: {args.num_prompts / benchmark_time:.2f} requests/s") - - # Compute the latency statistics. - avg_latency = np.mean([latency for _, _, latency in REQUEST_LATENCY]) - print(f"Average latency: {avg_latency:.2f} s") - avg_per_token_latency = np.mean( - [ - latency / (prompt_len + output_len) - for prompt_len, output_len, latency in REQUEST_LATENCY - ] - ) - print(f"Average latency per token: {avg_per_token_latency:.2f} s") - avg_per_output_token_latency = np.mean( - [latency / output_len for _, output_len, latency in REQUEST_LATENCY] - ) - print("Average latency per output token: " f"{avg_per_output_token_latency:.2f} s") - throughput = ( - sum([output_len for _, output_len, _ in REQUEST_LATENCY]) / benchmark_time + + benchmark = ServingBenchmarkRunner( + api_url, + model_uid, + input_requests, + args.stream, + request_rate=args.request_rate, + concurrency=args.concurrency, + api_key=args.api_key, ) - print(f"Throughput: {throughput} tokens/s") + asyncio.run(benchmark.run()) + + benchmark.print_stats() if __name__ == "__main__": @@ -133,6 +139,22 @@ def main(args: argparse.Namespace): parser.add_argument( "--num-prompts", type=int, default=100, help="Number of prompts to process." ) + parser.add_argument( + "--prompt-len-limit", type=int, default=1024, help="Prompt length limitation." + ) + parser.add_argument( + "--api-key", + type=str, + default=None, + help="Authorization api key", + ) + parser.add_argument( + "--concurrency", + "-c", + type=int, + default=100, + help="Set the concurrency of request to send", + ) parser.add_argument( "--request-rate", type=float, @@ -149,5 +171,8 @@ def main(args: argparse.Namespace): help="Trust remote code from huggingface.", ) parser.add_argument("--model-uid", type=str, help="Xinference model UID.") + parser.add_argument( + "--stream", action="store_true", help="Enable streaming responses." + ) args = parser.parse_args() main(args) diff --git a/benchmark/utils.py b/benchmark/utils.py index 2f1121ea1c..8372d2e916 100644 --- a/benchmark/utils.py +++ b/benchmark/utils.py @@ -12,16 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import aiohttp import json import logging import random -import time from typing import TYPE_CHECKING, List, Tuple -import openai from transformers import AutoTokenizer, PreTrainedTokenizerFast +logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -97,6 +95,7 @@ def sample_requests( dataset_path: str, num_requests: int, tokenizer: "PreTrainedTokenizerBase", + prompt_len_limit: int = 1024, ) -> List[Tuple[str, int, int]]: # Load the dataset. with open(dataset_path) as f: @@ -128,7 +127,10 @@ def sample_requests( # This is because TGI causes errors when the input or output length # is too short. continue - if prompt_len > 1024 or prompt_len + output_len > 2048: + if ( + prompt_len > prompt_len_limit + or prompt_len + output_len > prompt_len_limit * 2 + ): # Prune too long sequences. continue filtered_dataset.append((prompt, prompt_len, output_len)) @@ -138,36 +140,28 @@ def sample_requests( return sampled_requests -async def send_request( - api_url: str, - model_uid: str, - prompt: str, - prompt_len: int, - output_len: int, - stats: List[Tuple[int, int, float]], # output. -) -> None: - request_start_time = time.time() - - pload = { - "model": model_uid, - "n": 1, - "temperature": 1.0, - "top_p": 1.0, - "max_tokens": output_len, - "stream": False, - "messages": [{"role": "user", "content": prompt}] - } - - headers = {"User-Agent": "Benchmark Client"} - - timeout = aiohttp.ClientTimeout(total=3 * 3600) - async with aiohttp.ClientSession(timeout=timeout) as session: - async with session.post(api_url, headers=headers, json=pload) as response: - resp = await response.json() - if response.status == 200: - completion_tokens = resp['usage']['completion_tokens'] - request_end_time = time.time() - request_latency = request_end_time - request_start_time - stats.append((prompt_len, completion_tokens, request_latency)) - else: - logger.error(f"Failed to create chat completion: {resp}") +def generate_sorting_prompts( + num_prompts: int, + context_length: int, + prompt_len_limit: int, + tokenizer: "PreTrainedTokenizerBase", +) -> List[Tuple[str, int, int]]: + prompts = [] + for i in range(0, num_prompts): + random_nums = [] + _prompt_len = 0 + while True: + r_str = "%s" % random.randint(0, 99) + r_len = len(r_str) + 1 + if r_len + _prompt_len > prompt_len_limit: + break + random_nums.append(r_str) + _prompt_len += r_len + prompt = "Sort the numbers:" + ",".join(random_nums) + prompts.append(prompt) + prompt_token_ids = tokenizer(prompts).input_ids + dataset = [] + for i in range(0, len(prompts)): + prompt_len = len(prompt_token_ids[i]) + dataset.append((prompts[i], prompt_len, context_length - prompt_len)) + return dataset diff --git a/doc/Makefile b/doc/Makefile index 32655ef182..e2700039c5 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -11,7 +11,7 @@ BUILDDIR = build # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SOURCEDIR) -I18NSPHINXLANGS = -l zh_CN -l ja_JP +I18NSPHINXLANGS = -l zh_CN # Put it first so that "make" without argument is like "make help". help: @@ -22,9 +22,6 @@ help: html_zh_cn: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) -t zh_cn -D language='zh_CN' "$(SOURCEDIR)" $(BUILDDIR)/html_zh_cn -html_ja_jp: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) -t ja_jp -D language='ja_JP' "$(SOURCEDIR)" $(BUILDDIR)/html_ja_jp - gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale $(SPHINXINTL) update -p $(BUILDDIR)/locale $(I18NSPHINXLANGS) diff --git a/doc/source/_static/speculative.gif b/doc/source/_static/speculative.gif deleted file mode 100644 index 16cd57e193..0000000000 Binary files a/doc/source/_static/speculative.gif and /dev/null differ diff --git a/doc/source/_static/speculative_decoding.jpeg b/doc/source/_static/speculative_decoding.jpeg deleted file mode 100644 index d5b1e46cf1..0000000000 Binary files a/doc/source/_static/speculative_decoding.jpeg and /dev/null differ diff --git a/doc/source/development/xinference_internals.rst b/doc/source/development/xinference_internals.rst index 5fbe0f3e21..4bdb8fc57a 100644 --- a/doc/source/development/xinference_internals.rst +++ b/doc/source/development/xinference_internals.rst @@ -7,9 +7,9 @@ The internals of Xinference Overview ======== -Xinference leverages `Xoscar `_, an actor programming framework we designed, +Xinference leverages `Xoscar `_, an actor programming framework we designed, as its core component to manage machines, devices, and model inference processes. Each actor serves as a basic -unit for model inference and various inference backends can be integrate into the actor, enabling us to support +unit for model inference and various inference backends can be integrate into the actor, enabling us to support multiple inference engines and hardware. These actors are hosted and scheduled within actor pools, which are designed to be asynchronous and non-blocking and function as resource pools. @@ -46,7 +46,7 @@ Entry Points Take the command-lines we implemented as examples: - ``xinference``: Provides commands for model management, including registering/unregistering models, listing all - registered/running models, and launching or terminating specific models. + registered/running models, and launching or terminating specific models. It also features interactive commands like generate and chat for testing and interacting with deployed models in real-time. - ``xinference-local``: Starts a local Xinference service. @@ -69,11 +69,11 @@ Python projects define command-line console entry points in `setup.cfg` or `setu xinference-supervisor = xinference.deploy.cmdline:supervisor xinference-worker = xinference.deploy.cmdline:worker -The command-line ``xinference`` can be refered to code in ``xinference.deploy.cmdline:cli``. +The command-line ``xinference`` can be referred to code in ``xinference.deploy.cmdline:cli``. Click ----- -We use Click to implement a specific command-line: +We use Click to implement a specific command-line: :: @@ -96,7 +96,7 @@ For example, the ``xinference-local`` command allows you to define the host addr Actor ===== -Xinference is fundamentally based on `Xoscar `_, our actor framework, +Xinference is fundamentally based on `Xoscar `_, our actor framework, which can manage computational resources and Python processes to support scalable and concurrent programming. The following is a pseudocode demonstrating how our Worker Actor works, the actual Worker Actor is more complex than this. @@ -106,14 +106,14 @@ The following is a pseudocode demonstrating how our Worker Actor works, the actu class WorkerActor(xo.Actor): def __init__(self, *args, **kwargs): - ... - async def launch_model(self, model_id, n_gpu, ...): + ... + async def launch_model(self, model_id, n_gpu, ...): # launch an inference engine, use specific model class to load model checkpoints ... - async def list_models(self): + async def list_models(self): # list models on this actor ... - async def terminate_model(self, model_id): + async def terminate_model(self, model_id): # terminate the model ... async def __post_create__(self): @@ -121,7 +121,7 @@ The following is a pseudocode demonstrating how our Worker Actor works, the actu ... async def __pre_destroy__(self): # called before the actor instance is destroyed - ... + ... We use the ``WorkerActor`` as an example to illustrate how we build the Xinference. Each actor class is a standard Python class that inherits from ``xoscar.Actor``. An instance of this class is a specific actor @@ -131,13 +131,13 @@ within the actor pool. For instance, the model inference ``WorkerActor`` needs to launch the model (``launch_model``), list the models in this actor (``list_models``), terminate a model (``terminate_model``). There are two special methods worth noting. The ``__post_create__`` is invoked before the actor is created, allowing for necessary initializations. - The ``__pre_destroy__`` is called after the actor is destroyed, allowing for cleanup or finalization tasks. + The ``__pre_destroy__`` is called after the actor is destroyed, allowing for cleanup or finalization tasks. - **Reference Actor and Invoke Methods**: When an actor is created, it yields a reference variable so that other actors can reference it. The actor reference can also be referenced with the address. Suppose the ``WorkerActor`` is created and the reference variable is ``worker_ref``, the ``launch_model`` method of this actor class can - be invoked by calling ``worker_ref.launch_model()``. - Even if the actor's method is originally a synchronized method, when called with an actor reference, it will + be invoked by calling ``worker_ref.launch_model()``. + Even if the actor's method is originally a synchronized method, when called with an actor reference, it will become as an asynchronous method. - **Inference Engine**: The actor can manage the process, and the inference engine is also a process. In the launch @@ -152,12 +152,12 @@ Asynchronous Programming Both Xinference and Xoscar highly utilize asynchronous programming of ``asyncio``. Asynchronous programming is a programming paradigm that does not block. -Instead, requests and function calls are issued and executed in the background -and results are returned in the future. This enables us to perform +Instead, requests and function calls are issued and executed in the background +and results are returned in the future. This enables us to perform activities concurrently. -If you're not familiar with Pythons's ``asyncio``, you can see more tutorials for help: - +If you're not familiar with Pythons's ``asyncio``, you can see more tutorials for help: + - `Python Asyncio Tutorial `__ - `Real Python's asyncio Tutorial `__ @@ -168,7 +168,7 @@ If you're not familiar with Pythons's ``asyncio``, you can see more tutorials fo Model ===== -Xinference supports different types of models including large language models (LLMs), image models, audio models, embedding models, etc. +Xinference supports different types of models including large language models (LLMs), image models, audio models, embedding models, etc. All models are implemented in `model/ `_. LLM @@ -216,46 +216,46 @@ usually comes with various sizes, quantization methods, and file formats. For instance, the ``model_format`` could be ``pytorch`` (using Hugging Face Transformers or vLLM as backend), ``ggmlv3`` (a tensor library associated with llama.cpp), or ``gptq`` (a post-training quantization framework). The ``model_id`` defines the repository of the model hub from which Xinference downloads the checkpoint files. -Furthermore, due to distinct instruction-tuning processes, different model families have varying prompt styles. +Furthermore, due to distinct instruction-tuning processes, different model families have varying prompt styles. The ``prompt_style`` in the JSON file specifies how to format prompts for this particular model. For example, ``system_prompt`` and ``roles`` are used to specify the instructions and personality of the model. Code Walkthrough ================ -The main code is located in the `xinference/ `_: +The main code is located in the `xinference/ `_: -- `api/ `_: `restful_api.py `_ +- `api/ `_: `restful_api.py `_ is the core part that sets up and runs the RESTful APIs. It integrates an authentication service (the specific code is located in `oauth2/ `_), as some or all endpointsrequire user authentication. -- `client/ `_: This is the client of Xinference. - +- `client/ `_: This is the client of Xinference. + - `oscar/ `_ defines the Actor Client which acts as a client interface for interacting with models deployed in a Xinference cluster. - + - `restful/ `_ implements a RESTful client for interacting with a Xinference service. -- `core/ `_: This is the core part of Xinference. - +- `core/ `_: This is the core part of Xinference. + - `metrics.py `_ and `resource.py `_ defines a set of tools for collecting and reporting metrics and the status of node resources, including model throughput, latency, the usage of CPU and GPU, memory usage, and more. - + - `image_interface.py `_ and - `chat_interface.py `_ - implement `Gradio `_ interfaces for image and chat models, respectively. - These interfaces allow users to interact with models through a Web UI, such as generating images or engaging in chat. + `chat_interface.py `_ + implement `Gradio `_ interfaces for image and chat models, respectively. + These interfaces allow users to interact with models through a Web UI, such as generating images or engaging in chat. They build user interfaces using the gradio package and communicate with backend models through our RESTful APIs. - + - `worker.py `_ and - `supervisor.py `_ + `supervisor.py `_ respectively define the logic for worker actors and supervisor actor. Worker actors are responsible for carrying out specific model computation tasks, while supervisor actors manage the lifecycle of worker nodes, schedule tasks, and monitor system states. - + - `status_guard.py `_ implements a status monitor to track the status of models (like creating, updating, terminating, etc.). It allows querying status information of model instances and managing these statuses based on the model's UID. @@ -265,7 +265,7 @@ The main code is located in the `xinference/ `_ defines an event collector for gathering and - reporting various runtime events of models, such as information, warnings, and errors. + reporting various runtime events of models, such as information, warnings, and errors. `model.py `_ defines a Model Actor, the core component for direct model interactions. The Model Actor is responsible for executing model inference requests, handling input and output data streams, and supports various types of model operations. diff --git a/doc/source/gen_docs.py b/doc/source/gen_docs.py index 5537560802..68e381edf6 100644 --- a/doc/source/gen_docs.py +++ b/doc/source/gen_docs.py @@ -17,6 +17,7 @@ from collections import defaultdict from jinja2 import Environment, FileSystemLoader +from xinference.model.llm.llm_family import SUPPORTED_ENGINES, check_engine_by_spec_parameters from xinference.model.llm.vllm.core import VLLM_INSTALLED, VLLM_SUPPORTED_MODELS, VLLM_SUPPORTED_CHAT_MODELS MODEL_HUB_HUGGING_FACE = "Hugging Face" @@ -60,6 +61,7 @@ def main(): sorted_models = [] output_dir = './models/builtin/llm' os.makedirs(output_dir, exist_ok=True) + current_files = {f for f in os.listdir(output_dir) if os.path.isfile(os.path.join(output_dir, f))} for model_name in sorted(model_by_names, key=str.lower): @@ -72,6 +74,22 @@ def main(): 'url': f"https://huggingface.co/{model_spec['model_id']}" }] + # model engines + engines = [] + for engine in SUPPORTED_ENGINES: + for quantization in model_spec['quantizations']: + size = model_spec['model_size_in_billions'] + if isinstance(size, str) and '_' not in size: + size = int(size) + try: + check_engine_by_spec_parameters(engine, model_name, model_spec['model_format'], + size, quantization) + except ValueError: + continue + else: + engines.append(engine) + model_spec['engines'] = sorted(list(set(engines)), reverse=True) + # manual merge if model_name in model_by_names_modelscope.keys(): @@ -89,11 +107,19 @@ def get_unique_id(spec): }) rendered = env.get_template('llm.rst.jinja').render(model) - output_file_path = os.path.join(output_dir, f"{model['model_name'].lower()}.rst") + output_file_name = f"{model['model_name'].lower()}.rst" + if output_file_name in current_files: + current_files.remove(output_file_name) + output_file_path = os.path.join(output_dir, output_file_name) with open(output_file_path, 'w') as output_file: output_file.write(rendered) print(output_file_path) + if current_files: + for f in current_files: + print(f"remove {f}") + os.remove(os.path.join(output_dir, f)) + index_file_path = os.path.join(output_dir, "index.rst") with open(index_file_path, "w") as file: rendered_index = env.get_template('llm_index.rst.jinja').render(models=sorted_models) @@ -176,6 +202,7 @@ def get_unique_id(spec): if not available_controlnet: available_controlnet = None model["available_controlnet"] = available_controlnet + model["model_ability"] = ', '.join(model.get("model_ability")) rendered = env.get_template('image.rst.jinja').render(model) output_file_path = os.path.join(output_dir, f"{model['model_name'].lower()}.rst") with open(output_file_path, 'w') as output_file: @@ -204,6 +231,25 @@ def get_unique_id(spec): rendered_index = env.get_template('audio_index.rst.jinja').render(models=sorted_models) file.write(rendered_index) + with open('../../xinference/model/video/model_spec.json', 'r') as file: + models = json.load(file) + + sorted_models = sorted(models, key=lambda x: x['model_name'].lower()) + output_dir = './models/builtin/video' + os.makedirs(output_dir, exist_ok=True) + + for model in sorted_models: + model["model_ability"] = ', '.join(model.get("model_ability")) + rendered = env.get_template('video.rst.jinja').render(model) + output_file_path = os.path.join(output_dir, f"{model['model_name'].lower()}.rst") + with open(output_file_path, 'w') as output_file: + output_file.write(rendered) + + index_file_path = os.path.join(output_dir, "index.rst") + with open(index_file_path, "w") as file: + rendered_index = env.get_template('video_index.rst.jinja').render(models=sorted_models) + file.write(rendered_index) + if VLLM_INSTALLED: vllm_models = gen_vllm_models() groups = [', '.join("``%s``" % m for m in group) for group in vllm_models] diff --git a/doc/source/getting_started/environments.rst b/doc/source/getting_started/environments.rst index 861921e9a2..575abbf2a1 100644 --- a/doc/source/getting_started/environments.rst +++ b/doc/source/getting_started/environments.rst @@ -36,7 +36,8 @@ XINFERENCE_DISABLE_HEALTH_CHECK Xinference will automatically report health check at Xinference startup. Setting this environment to 1 can disable health check. -XINFERENCE_DISABLE_VLLM -~~~~~~~~~~~~~~~~~~~~~~~~ -Xinference will automatically use vLLM as backend if conditions are met. -Setting this environment to 1 can disable the use of vLLM. \ No newline at end of file +XINFERENCE_DISABLE_METRICS +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Xinference will by default enable the metrics exporter on the supervisor and worker. +Setting this environment to 1 will disable the /metrics endpoint on the supervisor +and the HTTP service (only provide the /metrics endpoint) on the worker. diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst index ee9d2cd6dd..521fc22be7 100644 --- a/doc/source/getting_started/index.rst +++ b/doc/source/getting_started/index.rst @@ -12,5 +12,6 @@ Getting Started using_xinference logging using_docker_image + using_kubernetes troubleshooting environments diff --git a/doc/source/getting_started/installation.rst b/doc/source/getting_started/installation.rst index 2f0600d9f6..9dd563a0fc 100644 --- a/doc/source/getting_started/installation.rst +++ b/doc/source/getting_started/installation.rst @@ -10,11 +10,13 @@ If you aim to serve all supported models, you can install all the necessary depe pip install "xinference[all]" .. note:: - If you want to serve models in GGML format, it's advised to install the GGML dependencies manually based on your hardware specifications to enable acceleration. For more details, see the :ref:`installation_ggml` section. + If you want to serve models in GGUF format, it's advised to install the ``llama-cpp-python`` dependency manually based on your hardware specifications to enable acceleration. For more details, see the :ref:`installation_gguf` section. If you want to install only the necessary backends, here's a breakdown of how to do it. +.. _inference_backend: + Transformers Backend ~~~~~~~~~~~~~~~~~~~~ PyTorch (transformers) supports the inference of most state-of-art models. It is the default backend for models in PyTorch format:: @@ -28,7 +30,8 @@ vLLM is a fast and easy-to-use library for LLM inference and serving. Xinference - The model format is ``pytorch``, ``gptq`` or ``awq``. - When the model format is ``pytorch``, the quantization is ``none``. -- When the model format is ``gptq`` or ``awq``, the quantization is ``Int4``. +- When the model format is ``awq``, the quantization is ``Int4``. +- When the model format is ``gptq``, the quantization is ``Int3``, ``Int4`` or ``Int8``. - The system is Linux and has at least one CUDA device - The model family (for custom models) / model name (for builtin models) is within the list of models supported by vLLM @@ -36,36 +39,47 @@ Currently, supported models include: .. vllm_start -- ``llama-2``, ``llama-2-chat`` -- ``baichuan``, ``baichuan-chat``, ``baichuan-2-chat`` -- ``internlm-16k``, ``internlm-chat-7b``, ``internlm-chat-8k``, ``internlm-chat-20b`` -- ``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2`` -- ``Yi``, ``Yi-chat`` +- ``llama-2``, ``llama-3``, ``llama-3.1``, ``llama-2-chat``, ``llama-3-instruct``, ``llama-3.1-instruct`` +- ``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``, ``mistral-instruct-v0.3``, ``mistral-nemo-instruct``, ``mistral-large-instruct`` +- ``codestral-v0.1`` +- ``Yi``, ``Yi-1.5``, ``Yi-chat``, ``Yi-1.5-chat``, ``Yi-1.5-chat-16k`` - ``code-llama``, ``code-llama-python``, ``code-llama-instruct`` -- ``vicuna-v1.3``, ``vicuna-v1.5`` +- ``deepseek``, ``deepseek-coder``, ``deepseek-chat``, ``deepseek-coder-instruct`` +- ``codeqwen1.5``, ``codeqwen1.5-chat`` +- ``baichuan-2-chat`` +- ``internlm2-chat`` +- ``internlm2.5-chat``, ``internlm2.5-chat-1m`` - ``qwen-chat`` -- ``mixtral-instruct-v0.1`` +- ``mixtral-instruct-v0.1``, ``mixtral-8x22B-instruct-v0.1`` - ``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k`` -- ``deepseek-chat``, ``deepseek-coder-instruct`` -- ``qwen1.5-chat`` -- ``gemma-it`` +- ``glm4-chat``, ``glm4-chat-1m`` +- ``codegeex4`` +- ``qwen1.5-chat``, ``qwen1.5-moe-chat`` +- ``qwen2-instruct``, ``qwen2-moe-instruct`` +- ``gemma-it``, ``gemma-2-it`` - ``orion-chat``, ``orion-chat-rag`` +- ``c4ai-command-r-v01`` .. vllm_end To install Xinference and vLLM:: pip install "xinference[vllm]" + + # FlashInfer is optional but required for specific functionalities such as sliding window attention with Gemma 2. + # For CUDA 12.4 & torch 2.4 to support sliding window attention for gemma 2 and llama 3.1 style rope + pip install flashinfer -i https://flashinfer.ai/whl/cu124/torch2.4 + # For other CUDA & torch versions, please check https://docs.flashinfer.ai/installation.html + -.. _installation_ggml: +.. _installation_gguf: -GGML Backend -~~~~~~~~~~~~ -It's advised to install the GGML dependencies manually based on your hardware specifications to enable acceleration. +Llama.cpp Backend +~~~~~~~~~~~~~~~~~ +Xinference supports models in ``gguf`` format via ``llama-cpp-python``. It's advised to install the llama.cpp-related dependencies manually based on your hardware specifications to enable acceleration. Initial setup:: pip install xinference - pip install ctransformers Hardware-Specific installations: @@ -80,3 +94,31 @@ Hardware-Specific installations: - AMD cards:: CMAKE_ARGS="-DLLAMA_HIPBLAS=on" pip install llama-cpp-python + + +SGLang Backend +~~~~~~~~~~~~~~ +SGLang has a high-performance inference runtime with RadixAttention. It significantly accelerates the execution of complex LLM programs by automatic KV cache reuse across multiple calls. And it also supports other common techniques like continuous batching and tensor parallelism. + +Initial setup:: + + pip install 'xinference[sglang]' + + # For CUDA 12.4 & torch 2.4 to support sliding window attention for gemma 2 and llama 3.1 style rope + pip install flashinfer -i https://flashinfer.ai/whl/cu124/torch2.4 + # For other CUDA & torch versions, please check https://docs.flashinfer.ai/installation.html + + +MLX Backend +~~~~~~~~~~~ +MLX-lm is designed for Apple silicon users to run LLM efficiently. + +Initial setup:: + + pip install 'xinference[mlx]' + +Other Platforms +~~~~~~~~~~~~~~~ + +* :ref:`Ascend NPU ` + diff --git a/doc/source/getting_started/installation_npu.rst b/doc/source/getting_started/installation_npu.rst new file mode 100644 index 0000000000..8202661487 --- /dev/null +++ b/doc/source/getting_started/installation_npu.rst @@ -0,0 +1,47 @@ +.. _installation_npu: + + +================================= +Installation Guide for Ascend NPU +================================= +Xinference can run on Ascend NPU, follow below instructions to install. + + +Installing PyTorch and Ascend extension for PyTorch +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Install PyTorch CPU version and corresponding Ascend extension. + +Take PyTorch v2.1.0 as example. + + .. code-block:: bash + + pip3 install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cpu + +Then install `Ascend extension for PyTorch `_. + + .. code-block:: bash + + pip3 install 'numpy<2.0' + pip3 install decorator + pip3 install torch-npu==2.1.0.post3 + +Running below command to see if it correctly prints the Ascend NPU count. + +.. code-block:: bash + + python -c "import torch; import torch_npu; print(torch.npu.device_count())" + +Installing Xinference +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + pip3 install xinference + +Now you can use xinference according to :ref:`doc `. +``Transformers`` backend is the only available engine supported for Ascend NPU for open source version. + +Enterprise Support +~~~~~~~~~~~~~~~~~~ +If you encounter any performance or other issues for Ascend NPU, please reach out to us +via `link `_. diff --git a/doc/source/getting_started/troubleshooting.rst b/doc/source/getting_started/troubleshooting.rst index 728dc25891..0ff1e82459 100644 --- a/doc/source/getting_started/troubleshooting.rst +++ b/doc/source/getting_started/troubleshooting.rst @@ -99,4 +99,11 @@ You can increase its size by setting the ``--shm-size`` parameter as follows: .. code:: bash - docker run --shm-size=128g ... \ No newline at end of file + docker run --shm-size=128g ... + + +Missing ``model_engine`` parameter when launching LLM models +============================================================ + +Since version ``v0.11.0``, launching LLM models requires an additional ``model_engine`` parameter. +For specific information, please refer to :ref:`here `. diff --git a/doc/source/getting_started/using_docker_image.rst b/doc/source/getting_started/using_docker_image.rst index 4ae66edd0b..7f335e3b31 100644 --- a/doc/source/getting_started/using_docker_image.rst +++ b/doc/source/getting_started/using_docker_image.rst @@ -11,16 +11,18 @@ Prerequisites ============= * The image can only run in an environment with GPUs and CUDA installed, because Xinference in the image relies on Nvidia GPUs for acceleration. * CUDA must be successfully installed on the host machine. This can be determined by whether you can successfully execute the ``nvidia-smi`` command. -* The CUDA version in the docker image is ``12.1``, and the CUDA version on the host machine should ideally be consistent with it. Be sure to keep the CUDA version on your host machine between ``11.8`` and ``12.2``, even if it is inconsistent. +* The CUDA version in the docker image is ``12.4``, and the CUDA version on the host machine should be ``12.4`` or above, and the NVIDIA driver version should be ``550`` or above. Docker Image ============ The official image of Xinference is available on DockerHub in the repository ``xprobe/xinference``. -There are two kinds of image tags available: +Available tags include: * ``nightly-main``: This image is built daily from the `GitHub main branch `_ and generally does not guarantee stability. * ``v``: This image is built each time a Xinference release version is published, and it is typically more stable. +* ``latest``: This image is built with the latest Xinference release version. +* For CPU version, add ``-cpu`` suffix, e.g. ``nightly-main-cpu``. Dockerfile for custom build diff --git a/doc/source/getting_started/using_kubernetes.rst b/doc/source/getting_started/using_kubernetes.rst new file mode 100644 index 0000000000..e0b96af685 --- /dev/null +++ b/doc/source/getting_started/using_kubernetes.rst @@ -0,0 +1,81 @@ +.. _using_kubernetes: + +######################## +Xinference on Kubernetes +######################## + +************ +Helm Support +************ +Xinference provides a method for installation in a Kubernetes cluster via ``Helm`` . + + +Prerequisites +============= +* You have a fully functional Kubernetes cluster. +* Enable GPU support in Kubernetes, refer to `here `_. +* ``Helm`` is correctly installed. + + +Steps +===== +#. Add xinference helm repo. + + .. code-block:: bash + + helm repo add xinference https://xorbitsai.github.io/xinference-helm-charts + +#. Update xinference helm repo indexes and query versions. + + .. code-block:: bash + + helm repo update xinference + helm search repo xinference/xinference --devel --versions + +#. Install + + .. code-block:: bash + + helm install xinference xinference/xinference -n xinference --version + + +Customized Installation +======================= +The installation method mentioned above sets up a Xinference cluster similar to a single-machine setup, +with only one worker and all startup parameters at their default values. +However, this is usually not the desired setup. + +Below are some common custom installation configurations. + +#. I need to download models from ``ModelScope``. + + .. code-block:: bash + + helm install xinference xinference/xinference -n xinference --version --set config.model_src="modelscope" + +#. I want to use cpu image of xinference (or use any other version of xinference images). + + .. code-block:: bash + + helm install xinference xinference/xinference -n xinference --version --set config.xinference_image="" + +#. I want to have 4 Xinference workers, with each worker managing 4 GPUs. + + .. code-block:: bash + + helm install xinference xinference/xinference -n xinference --version --set config.worker_num=4 --set config.gpu_per_worker="4" + +The above installation method is based on Helm ``--set`` option. +For more complex custom installations, such as multiple workers with shared storage, +it is highly recommended to use your own ``values.yaml`` file with Helm ``-f`` option for installation. + +The default ``values.yaml`` file is located `here `_. +Some examples can be found `here `_. + + +****************** +KubeBlocks Support +****************** +You can also install Xinference in Kubernetes using the third-party ``KubeBlocks``. +This method is not maintained by Xinference and does not guarantee timely updates or availability. +Please refer to the documentation at `here `_. diff --git a/doc/source/getting_started/using_xinference.rst b/doc/source/getting_started/using_xinference.rst index 143a683abb..b8cc47458a 100644 --- a/doc/source/getting_started/using_xinference.rst +++ b/doc/source/getting_started/using_xinference.rst @@ -99,6 +99,53 @@ Please ensure that the version of the client matches the version of the Xinferen pip install xinference-client==${SERVER_VERSION} +.. _about_model_engine: + +About Model Engine +------------------ +Since ``v0.11.0`` , before launching the LLM model, you need to specify the inference engine you want to run. +Currently, xinference supports the following inference engines: + +* ``vllm`` +* ``sglang`` +* ``llama.cpp`` +* ``transformers`` + +About the details of these inference engine, please refer to :ref:`here `. + +Note that when launching a LLM model, the ``model_format`` and ``quantization`` of the model you want to launch +is closely related to the inference engine. + +You can use ``xinference engine`` command to query the combination of parameters of the model you want to launch. +This will demonstrate under what conditions a model can run on which inference engines. + +For example: + +#. I would like to query about which inference engines the ``qwen-chat`` model can run on, and what are their respective parameters. + +.. code-block:: bash + + xinference engine -e --model-name qwen-chat + +#. I want to run ``qwen-chat`` with ``VLLM`` as the inference engine, but I don't know how to configure the other parameters. + +.. code-block:: bash + + xinference engine -e --model-name qwen-chat --model-engine vllm + +#. I want to launch the ``qwen-chat`` model in the ``GGUF`` format, and I need to know how to configure the remaining parameters. + +.. code-block:: bash + + xinference engine -e --model-name qwen-chat -f ggufv2 + + +In summary, compared to previous versions, when launching LLM models, +you need to additionally pass the ``model_engine`` parameter. +You can retrieve information about the supported inference engines and their related parameter combinations +through the ``xinference engine`` command. + + Run Llama-2 ----------- @@ -122,7 +169,7 @@ This create a new model instance with unique ID ``my-llama-2``: .. code-tab:: bash shell - xinference launch -u my-llama-2 -n llama-2-chat -s 13 -f pytorch + xinference launch --model-engine -u my-llama-2 -n llama-2-chat -s 13 -f pytorch .. code-tab:: bash cURL @@ -131,6 +178,7 @@ This create a new model instance with unique ID ``my-llama-2``: -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ + "model_engine": "", "model_uid": "my-llama-2", "model_name": "llama-2-chat", "model_format": "pytorch", @@ -142,6 +190,7 @@ This create a new model instance with unique ID ``my-llama-2``: from xinference.client import RESTfulClient client = RESTfulClient("http://127.0.0.1:9997") model_uid = client.launch_model( + model_engine="", model_uid="my-llama-2", model_name="llama-2-chat", model_format="pytorch", @@ -160,7 +209,7 @@ This create a new model instance with unique ID ``my-llama-2``: .. code-block:: bash - xinference launch -u my-llama-2 -n llama-2-chat -s 13 -f pytorch --gpu_memory_utilization 0.9 + xinference launch --model-engine vllm -u my-llama-2 -n llama-2-chat -s 13 -f pytorch --gpu_memory_utilization 0.9 `gpu_memory_utilization=0.9` will pass to vllm when launching model. @@ -338,8 +387,10 @@ On each of the other servers where you want to run Xinference workers, run the f .. code-block:: bash - xinference-worker -e "http://${supervisor_host}:9997" + xinference-worker -e "http://${supervisor_host}:9997" -H "${worker_host}" +.. note:: + Note that you must replace ``${worker_host}`` with the actual host of your worker server. .. note:: Note that if you need to interact with the Xinference in a cluster via the command line, @@ -359,52 +410,19 @@ Run On Nvidia GPU Host .. code-block:: bash - docker run -p 9997:9997 --rm --gpus all xprobe/xinference:latest + docker run -e XINFERENCE_MODEL_SRC=modelscope -p 9998:9997 --gpus all xprobe/xinference: xinference-local -H 0.0.0.0 --log-level debug Run On CPU Only Host ----------------------- .. code-block:: bash - docker run -p 9997:9997 --rm xprobe/xinference:latest-cpu - - -Using Xinference On Kubernetes -============================== - -To use Xinference on Kubernetes, `KubeBlocks `_ is required to help the installation. - -The following steps assume Kubernetes is already installed. - -1. Download cli tool kbcli for KubeBlocks, see `install kbcli `_. - -Make sure kbcli version is at least v0.7.1. - -2. Install KubeBlocks using kbcli command, see `install KubeBlocks with kbcli `_. - -3. Enable Xinference addon, run the following command: - -.. code-block:: bash - - kbcli addon enable xinference - -4. Use kbcli to start Xinference cluster, run the following command: - -.. code-block:: bash - - kbcli cluster create xinference + docker run -e XINFERENCE_MODEL_SRC=modelscope -p 9998:9997 xprobe/xinference:-cpu xinference-local -H 0.0.0.0 --log-level debug -If the Kubernetes node doesn't have GPU on it, run the command with extra flag: +Replace ```` with Xinference versions, e.g. ``v0.10.3``, ``latest`` can be used for the latest version. -.. code-block:: bash - - kbcli cluster create xinference --cpu-mode - -Use -h to read the help documentation for more options: - -.. code-block:: bash +For more docker usage, refer to :ref:`Using Docker Image `. - kbcli cluster create xinference -h What's Next? ============ diff --git a/doc/source/index.rst b/doc/source/index.rst index d5f3bce3e9..926cb8dca0 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -104,6 +104,15 @@ Developing Real-world AI Applications with Xinference ] print(model.rerank(corpus, query)) + .. code-tab:: python Video + + from xinference.client import Client + + client = Client("http://localhost:9997") + model = client.get_model("MODEL_UID") + + model.text_to_video("") + Getting Started --------------- @@ -189,12 +198,18 @@ Explore the API .. grid:: 2 - .. grid-item-card:: Audio + .. grid-item-card:: Audio :link: audio :link-type: ref Learn how to turn audio into text or text into audio with Xinference. + .. grid-item-card:: Video + :link: video + :link-type: ref + + Learn how to generate video with Xinference. + Getting Involved ---------------- diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/examples/ai_podcast.po b/doc/source/locale/ja_JP/LC_MESSAGES/examples/ai_podcast.po deleted file mode 100644 index 3289645cc7..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/examples/ai_podcast.po +++ /dev/null @@ -1,180 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/examples/ai_podcast.rst:5 -msgid "Example: AI Podcast 🎙" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:7 -msgid "**Description**:" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:9 -msgid "🎙️AI Podcast - Voice Conversations with Multiple Agents on M2 Max 💻" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:11 -msgid "**Support Language** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:13 -msgid "English (AI_Podcast.py)" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:15 -msgid "Chinese (AI_Podcast_ZH.py)" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:17 -msgid "**Used Technology (EN version)** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:19 -msgid "" -"@ `OpenAI `_ 's `whisper " -"`_" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:21 -msgid "" -"@ `ggerganov `_ 's `ggml " -"`_" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:23 -msgid "" -"@ `WizardLM_AI `_ 's `wizardlm v1.0 " -"`_" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:25 -msgid "" -"@ `lmsysorg `_ 's `vicuna v1.3 " -"`_" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:27 -msgid "@ `Xinference `_ as a launcher" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:29 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:31 -msgid "" -"Generate the Wizardlm Model and Vicuna Model when the program is " -"launching with Xorbits Inference. Initiate the Chatroom by giving the two" -" chatbot their names and telling them that there is a human user called " -"\"username\", where \"username\" is given by user's input. Initialize a " -"empty chat history for the chatroom." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:35 -msgid "" -"Use Audio device to store recording into file, and transcribe the file " -"using OpenAI's Whisper to receive a human readable text as string." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:37 -msgid "" -"Based on the input message string, determine which agents the user want " -"to talk to. Call the target agents and parse in the input string and chat" -" history for the model to generate." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:40 -msgid "" -"When the responses are ready, use Macos's \"Say\" Command to produce " -"audio through speaker. Each agents have their own voice while speaking." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:43 -msgid "" -"Store the user input and the agent response into chat history, and " -"recursively looping the program until user explicitly says words like " -"\"see you\" in their responses." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:46 -msgid "**Highlight Features with Xinference** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:48 -msgid "" -"With Xinference's distributed system, we can easily deploy two different " -"models in the same session and in the same \"chatroom\". With enough " -"resources, the framework can deploy any amount of models you like at the " -"same time." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:51 -msgid "" -"With Xinference, you can deploy the model easily by just adding a few " -"lines of code. For examples, for launching the vicuna model in the demo, " -"just by::" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:68 -msgid "" -"Then, the Xinference client will handle \"target model downloading and " -"caching\", \"set up environment and process for the model\", and \"run " -"the service at selected endpoint. \" You are now ready to play with your " -"llm model." -msgstr "" - -#: ../../source/examples/ai_podcast.rst:71 -msgid "**Original Demo Video** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:73 -msgid "" -"`🎙️AI Podcast - Voice Conversations with Multiple Agents on M2 Max💻🔥🤖 " -"`_" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:75 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:77 -msgid "" -"`AI_Podcast " -"`_" -" (English Version)" -msgstr "" - -#: ../../source/examples/ai_podcast.rst:79 -msgid "" -"`AI_Podcast_ZH " -"`_" -" (Chinese Version)" -msgstr "" - -#~ msgid "AI_Podcast_ZH (Chinese Version)" -#~ msgstr "" - -#~ msgid "" -#~ "`AI_Podcast_ZH " -#~ "`" -#~ " (Chinese Version)" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/examples/chatbot.po b/doc/source/locale/ja_JP/LC_MESSAGES/examples/chatbot.po deleted file mode 100644 index ff102fb760..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/examples/chatbot.po +++ /dev/null @@ -1,107 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/examples/chatbot.rst:5 -msgid "Example: CLI chatbot 🤖️" -msgstr "" - -#: ../../source/examples/chatbot.rst:7 -msgid "**Description**:" -msgstr "" - -#: ../../source/examples/chatbot.rst:9 -msgid "" -"Demonstrate how to interact with Xinference to play with LLM chat " -"functionality with an AI agent in command line💻" -msgstr "" - -#: ../../source/examples/chatbot.rst:11 -msgid "**Used Technology**:" -msgstr "" - -#: ../../source/examples/chatbot.rst:13 -msgid "" -"@ `ggerganov `_ 's `ggml " -"`_" -msgstr "" - -#: ../../source/examples/chatbot.rst:15 -msgid "@ `Xinference `_ as a launcher" -msgstr "" - -#: ../../source/examples/chatbot.rst:17 -msgid "" -"@ All LLaMA and Chatglm models supported by `Xorbitsio inference " -"`_" -msgstr "" - -#: ../../source/examples/chatbot.rst:19 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/examples/chatbot.rst:21 -msgid "" -"Take the user command line input in the terminal and grab the required " -"parameters for model launching." -msgstr "" - -#: ../../source/examples/chatbot.rst:23 -msgid "" -"Launch the Xinference frameworks and automatically deploy the model user " -"demanded into the cluster." -msgstr "" - -#: ../../source/examples/chatbot.rst:25 -msgid "Initialize an empty chat history to store all the context in the chatroom." -msgstr "" - -#: ../../source/examples/chatbot.rst:27 -msgid "" -"Recursively ask for user's input as prompt and let the model to generate " -"response based on the prompt and the chat history. Show the Output of the" -" response in the terminal." -msgstr "" - -#: ../../source/examples/chatbot.rst:30 -msgid "" -"Store the user's input and agent's response into the chat history as " -"context for the upcoming rounds." -msgstr "" - -#: ../../source/examples/chatbot.rst:32 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/examples/chatbot.rst:33 -msgid "" -"`chat " -"`_" -msgstr "" - -#~ msgid "Example: chatbot 🤖️" -#~ msgstr "" - -#~ msgid "" -#~ "Demonstrate how to interact with " -#~ "Xinference to play with LLM chat " -#~ "functionality with an AI agent 💻" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/examples/gradio_chatinterface.po b/doc/source/locale/ja_JP/LC_MESSAGES/examples/gradio_chatinterface.po deleted file mode 100644 index 46def45fbc..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/examples/gradio_chatinterface.po +++ /dev/null @@ -1,96 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/examples/gradio_chatinterface.rst:5 -msgid "Example: Gradio ChatInterface🤗" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:7 -msgid "**Description**:" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:9 -msgid "" -"This example showcases how to build a chatbot with 120 lines of code with" -" Gradio ChatInterface and Xinference local LLM" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:11 -msgid "**Used Technology**:" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:13 -msgid "" -"@ `Xinference `_ as a LLM model " -"hosting service" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:15 -msgid "" -"@ `Gradio `_ as a web interface for" -" the chatbot" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:17 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:19 -msgid "" -"Parse user-provided command line arguments to capture essential model " -"parameters such as model name, size, format, and quantization." -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:21 -msgid "" -"Establish a connection to the Xinference framework and deploy the " -"specified model, ensuring it's ready for real-time interactions." -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:23 -msgid "" -"Implement helper functions (flatten and to_chat) to efficiently handle " -"and store chat interactions, ensuring the model has context for " -"generating relevant responses." -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:25 -msgid "" -"Set up an interactive chat interface using Gradio, allowing users to " -"communicate with the model in a user-friendly environment." -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:27 -msgid "" -"Activate the Gradio web interface, enabling users to start their chat " -"sessions and receive model-generated responses based on their queries." -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:29 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/examples/gradio_chatinterface.rst:30 -msgid "" -"`Gradio ChatInterface " -"`_" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/examples/index.po b/doc/source/locale/ja_JP/LC_MESSAGES/examples/index.po deleted file mode 100644 index e112d11bb6..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/examples/index.po +++ /dev/null @@ -1,161 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/examples/index.rst:5 -msgid "Examples" -msgstr "" - -#: ../../source/examples/index.rst:17 -msgid "" -"Here you can find examples and resources to learn about how to use " -"Xinference." -msgstr "" - -#: ../../source/examples/index.rst:20 -msgid "Demos" -msgstr "" - -#: ../../source/examples/index.rst:22 -msgid "End-to-end applications of using Xinference:" -msgstr "" - -#: ../../source/examples/index.rst:24 -msgid "`Voice Conversations with AI Agents on M2 Max `_" -msgstr "" - -#: ../../source/examples/index.rst:26 -msgid "`Interacting with LLM Models: A Command-Line Example `_" -msgstr "" - -#: ../../source/examples/index.rst:28 -msgid "" -"`Interacting with LLM Models: A Gradio ChatInterface Example " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:30 -msgid "`PDF Chatbot with Local LLM and Embeddings `_" -msgstr "" - -#: ../../source/examples/index.rst:32 -msgid "" -"`Local Doc Conversations with LangChain and Streamlit " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:34 -msgid "" -"If you come across other examples in your own workflows we encourage you " -"to contribute a `PR `_!" -msgstr "" - -#: ../../source/examples/index.rst:38 -msgid "Tutorials" -msgstr "" - -#: ../../source/examples/index.rst:40 -msgid "" -"The following tutorials cover the basics of using Xinference in different" -" scenarios:" -msgstr "" - -#: ../../source/examples/index.rst:42 -msgid "" -"`[Notebook] Question-answering(QA) Application with Xinference, Milvus " -"and LangChain " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:44 -msgid "" -"`Using Xinference local LLMs within LlamaIndex " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:46 -msgid "" -"`[Chinese] 如何让 Chatbox 接入开源大模型,实现免费聊天 " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:48 -msgid "" -"`[Chinese] 摆脱 OpenAI 依赖,8 分钟教你用开源生态构建全栈 AI 应用 " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:50 -msgid "" -"`[Chinese] 使用全套开源工具构建 LLM 应用实战: 在 Dify 调用 Baichuan 开源模型能力 " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:54 -msgid "Third-Party Library Integrations" -msgstr "" - -#: ../../source/examples/index.rst:56 -msgid "" -"Xinference is designed to seamlessly integrate and deploy open-sourced AI" -" models, so we want to incorporate support for mainstream toolkits in the" -" AI landscape. Xinference can be used with the following third-party " -"libraries:" -msgstr "" - -#: ../../source/examples/index.rst:59 -msgid "" -"LangChain `Text Embedding Models " -"`_" -" and `LLMs " -"`_" -msgstr "" - -#: ../../source/examples/index.rst:61 -msgid "" -"`LlamaIndex Xinference LLM " -"`_" -msgstr "" - -#~ msgid "" -#~ "`Using Xinference local LLMs within " -#~ "LlamaIndex `_" -#~ msgstr "" - -#~ msgid "" -#~ "`[Chinese] 如何让 Chatbox 接入开源大模型,实现免费聊天 " -#~ "`_" -#~ msgstr "" - -#~ msgid "" -#~ "`[Chinese] 使用全套开源工具构建 LLM 应用实战 " -#~ "`_" -#~ msgstr "" - -#~ msgid "End-to-end examples of using Xinference for various tasks:" -#~ msgstr "" - -#~ msgid "" -#~ "`Build a QA Application with Xinference" -#~ " and LangChain " -#~ "`_" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/examples/pdf_chatbot.po b/doc/source/locale/ja_JP/LC_MESSAGES/examples/pdf_chatbot.po deleted file mode 100644 index 3580e07072..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/examples/pdf_chatbot.po +++ /dev/null @@ -1,95 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/examples/pdf_chatbot.rst:5 -msgid "Example: PDF Chatbot📚" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:7 -msgid "**Description**:" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:9 -msgid "" -"This example showcases how to build a PDF chatbot with local LLM and " -"Embedding models" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:11 -msgid "**Used Technology**:" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:13 -msgid "" -"@ `Xinference `_ as a LLM model " -"hosting service" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:15 -msgid "" -"@ `LlamaIndex `_ for " -"orchestrating the entire RAG pipeline" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:17 -msgid "@ `Streamlit `_ for interactive UI" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:19 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:21 -msgid "" -"Crafted a Dockerfile to simplify the process and ensure easy " -"reproducibility." -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:23 -msgid "Set up models with Xinference and expose two ports for accessing them." -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:25 -msgid "" -"Leverage Streamlit for seamless file uploads and interactive " -"communication with the chat engine." -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:27 -msgid "5x faster doc embedding than OpenAI's API." -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:29 -msgid "" -"Leveraging the power of GGML to offload models to the GPU, ensuring swift" -" acceleration. Less long waits for returns." -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:31 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/examples/pdf_chatbot.rst:32 -msgid "" -"`PDF Chatbot `_" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/accessing_models.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/accessing_models.po deleted file mode 100644 index 7c7d87ed1a..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/accessing_models.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/getting_started/accessing_models.rst:5 -msgid "Accessing Models" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:8 -msgid "" -"Suppose you have started the Xinference server endpoint at " -"``http://127.0.0.1:9997``." -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:10 -msgid "" -"Please refer to :ref:`Launching Models ` guide to get " -"your model running." -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:13 -msgid "Using Xinference Client" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:17 -msgid "Large Language Model" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:18 -msgid "" -"When the abilities of the LLM include \"chat,\" we can converse with it " -"using the model's chat interface:" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:34 -msgid "The response will look like:" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:61 -msgid "Embedding Model" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:63 -msgid "" -"To interact with Xinference's embedding model, i.e., inputting a text and" -" getting an embedding from ``RESTfulClient``:" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:72 -msgid "The response will be:" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:93 -msgid "Using OpenAI Python SDK" -msgstr "" - -#: ../../source/getting_started/accessing_models.rst:95 -msgid "" -"Xinference provides an OpenAI-compatible RESTful interface. Thus, you can" -" also use the OpenAI Python SDK to chat with the model via the service's " -"endpoint:" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/installation.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/installation.po deleted file mode 100644 index 202a5abb70..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/installation.po +++ /dev/null @@ -1,163 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-29 11:05+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.0\n" - -#: ../../source/getting_started/installation.rst:5 -msgid "Installation" -msgstr "" - -#: ../../source/getting_started/installation.rst:6 -msgid "" -"Xinference can be installed with ``pip`` on Linux, Windows, and macOS. To" -" run models using Xinference, you will need to install the backend " -"corresponding to the type of model you intend to serve." -msgstr "" - -#: ../../source/getting_started/installation.rst:8 -msgid "" -"If you aim to serve all supported models, you can install all the " -"necessary dependencies with a single command::" -msgstr "" - -#: ../../source/getting_started/installation.rst:13 -msgid "" -"If you want to serve models in GGML format, it's advised to install the " -"GGML dependencies manually based on your hardware specifications to " -"enable acceleration. For more details, see the :ref:`installation_ggml` " -"section." -msgstr "" - -#: ../../source/getting_started/installation.rst:16 -msgid "" -"If you want to install only the necessary backends, here's a breakdown of" -" how to do it." -msgstr "" - -#: ../../source/getting_started/installation.rst:19 -msgid "Transformers Backend" -msgstr "" - -#: ../../source/getting_started/installation.rst:20 -msgid "" -"PyTorch (transformers) supports the inference of most state-of-art " -"models. It is the default backend for models in PyTorch format::" -msgstr "" - -#: ../../source/getting_started/installation.rst:26 -msgid "vLLM Backend" -msgstr "" - -#: ../../source/getting_started/installation.rst:27 -msgid "" -"vLLM is a fast and easy-to-use library for LLM inference and serving. " -"Xinference will choose vLLM as the backend to achieve better throughput " -"when the following conditions are met:" -msgstr "" - -#: ../../source/getting_started/installation.rst:29 -msgid "The model format is PyTorch or GPTQ" -msgstr "" - -#: ../../source/getting_started/installation.rst:30 -msgid "The quantization method is GPTQ 4 bit or none" -msgstr "" - -#: ../../source/getting_started/installation.rst:31 -msgid "The system is Linux and has at least one CUDA device" -msgstr "" - -#: ../../source/getting_started/installation.rst:32 -msgid "The model is within the list of models supported by vLLM." -msgstr "" - -#: ../../source/getting_started/installation.rst:34 -msgid "Currently, supported models include:" -msgstr "" - -#: ../../source/getting_started/installation.rst:36 -msgid "``llama-2``, ``llama-2-chat``" -msgstr "" - -#: ../../source/getting_started/installation.rst:37 -msgid "``baichuan``, ``baichuan-chat``" -msgstr "" - -#: ../../source/getting_started/installation.rst:38 -msgid "``internlm``, ``internlm-20b``, ``internlm-chat``, ``internlm-chat-20b``" -msgstr "" - -#: ../../source/getting_started/installation.rst:39 -msgid "``vicuna-v1.3``, ``vicuna-v1.5``" -msgstr "" - -#: ../../source/getting_started/installation.rst:40 -msgid "``Yi``, ``Yi-chat``" -msgstr "" - -#: ../../source/getting_started/installation.rst:41 -msgid "``qwen-chat``" -msgstr "" - -#: ../../source/getting_started/installation.rst:42 -msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" -msgstr "" - -#: ../../source/getting_started/installation.rst:43 -msgid "``mistral-instruct-v0.1``" -msgstr "" - -#: ../../source/getting_started/installation.rst:44 -msgid "``chatglm3``" -msgstr "" - -#: ../../source/getting_started/installation.rst:46 -msgid "To install Xinference and vLLM::" -msgstr "" - -#: ../../source/getting_started/installation.rst:53 -msgid "GGML Backend" -msgstr "" - -#: ../../source/getting_started/installation.rst:54 -msgid "" -"It's advised to install the GGML dependencies manually based on your " -"hardware specifications to enable acceleration." -msgstr "" - -#: ../../source/getting_started/installation.rst:56 -msgid "Initial setup::" -msgstr "" - -#: ../../source/getting_started/installation.rst:61 -msgid "Hardware-Specific installations:" -msgstr "" - -#: ../../source/getting_started/installation.rst:63 -msgid "Apple Silicon::" -msgstr "" - -#: ../../source/getting_started/installation.rst:67 -msgid "Nvidia cards::" -msgstr "" - -#: ../../source/getting_started/installation.rst:71 -msgid "AMD cards::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/launching_models.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/launching_models.po deleted file mode 100644 index dd91f43cc2..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/launching_models.po +++ /dev/null @@ -1,63 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/getting_started/launching_models.rst:5 -msgid "Launching Models" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:7 -msgid "You can launch models using Xinference's command line tool or client." -msgstr "" - -#: ../../source/getting_started/launching_models.rst:9 -msgid "First, make sure you have installed the Xinference SDK:" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:16 -msgid "Launching models with CLI" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:18 -msgid "" -"Suppose you have started the Xinference server endpoint at " -"``http://127.0.0.1:9997``." -msgstr "" - -#: ../../source/getting_started/launching_models.rst:21 -msgid "To launch an instance of Llama2 chat model:" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:30 -msgid "To launch an instance of General Text Embeddings (GTE) model:" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:40 -msgid "Launching models with client" -msgstr "" - -#: ../../source/getting_started/launching_models.rst:49 -msgid "" -"Once the model instance is launched, the system will return the model's " -"UID. You will need to use this model's UID as a handle to interact with " -"the model using the client. You can also list the running models using " -"the ``list_models`` method:" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/logging.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/logging.po deleted file mode 100644 index 081ee531ad..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/logging.po +++ /dev/null @@ -1,104 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/getting_started/logging.rst:5 -msgid "Logging in Xinference" -msgstr "" - -#: ../../source/getting_started/logging.rst:8 -msgid "Configure Log Level" -msgstr "" - -#: ../../source/getting_started/logging.rst:9 -msgid "" -"You can configure the log level with the ``--log-level`` option. For " -"example, starting a local cluster with ``DEBUG`` log level:" -msgstr "" - -#: ../../source/getting_started/logging.rst:18 -msgid "Log Files" -msgstr "" - -#: ../../source/getting_started/logging.rst:19 -msgid "" -"Xinference supports log rotation of log files. By default, logs rotate " -"when they reach 100MB (maxBytes), and up to 30 backup files (backupCount)" -" are kept. Note that the log level configured above takes effect in both " -"the command line logs and the log files." -msgstr "" - -#: ../../source/getting_started/logging.rst:24 -msgid "Log Directory Structure" -msgstr "" - -#: ../../source/getting_started/logging.rst:25 -msgid "" -"All the logs are stored in the ``/logs`` directory, " -"where ```` can be configured as mentioned in " -":ref:`using_xinference`." -msgstr "" - -#: ../../source/getting_started/logging.rst:27 -msgid "" -"Xinference creates a subdirectory under the log directory " -"``/logs``. The name of the subdirectory corresponds to " -"the Xinference cluster startup time in milliseconds." -msgstr "" - -#: ../../source/getting_started/logging.rst:31 -msgid "Local deployment" -msgstr "" - -#: ../../source/getting_started/logging.rst:32 -msgid "" -"In a local deployment, the logs of Xinference supervisor and Xinference " -"workers are combined into a single file. An example of the log directory " -"structure is shown below::" -msgstr "" - -#: ../../source/getting_started/logging.rst:38 -msgid "" -"where ``1699503558105`` is the timestamp when the Xinference cluster was " -"created. Therefore, when you create a cluster locally multiple times, you" -" can look for the corresponding logs based on this timestamp." -msgstr "" - -#: ../../source/getting_started/logging.rst:42 -msgid "Distributed deployment" -msgstr "" - -#: ../../source/getting_started/logging.rst:43 -msgid "" -"In a distributed deployment, Xinference supervisor and Xinference workers" -" each create their own subdirectory under the log directory. The name of " -"the subdirectory starts with the role name, followed by the role startup " -"time in milliseconds. An example of the log directory structure is shown " -"below::" -msgstr "" - -#~ msgid "" -#~ "In a local deployment, the logs of" -#~ " Xinference supervisor and Xorbits workers" -#~ " are combined into a single file. " -#~ "An example of the log directory " -#~ "structure is shown below::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/troubleshooting.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/troubleshooting.po deleted file mode 100644 index e716c44118..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/troubleshooting.po +++ /dev/null @@ -1,118 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-02 17:07+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/getting_started/troubleshooting.rst:5 -msgid "Troubleshooting" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:9 -msgid "No huggingface repo access" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:11 -msgid "" -"Sometimes, you may face errors accessing huggingface models, such as the " -"following message when accessing `llama2`:" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:18 -msgid "" -"This typically indicates either a lack of access rights to the repository" -" or missing huggingface access tokens. The following sections provide " -"guidance on addressing these issues." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:22 -msgid "Get access to the huggingface repo" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:24 -msgid "" -"To obtain access, navigate to the desired huggingface repository and " -"agree to its terms and conditions. As an illustration, for the `llama2` " -"model, you can use this link: `https://huggingface.co/meta-llama/Llama-2" -"-7b-hf `_." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:29 -msgid "Set up credentials to access huggingface" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:31 -msgid "" -"Your credential to access huggingface can be found online at " -"`https://huggingface.co/settings/tokens " -"`_." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:33 -msgid "" -"You can set the token as an environmental variable, with ``export " -"HUGGING_FACE_HUB_TOKEN=your_token_here``." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:36 -msgid "Download models from ModelScope" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:38 -msgid "" -"When the network connection to HuggingFace is blocked, you can also " -"choose to download models from ModelScope, especially for Chinese users. " -"For a detailed list of supported models and settings, please refer to " -":ref:`models_download`." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:43 -msgid "Incompatibility Between NVIDIA Driver and PyTorch Version" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:45 -msgid "If you are using a NVIDIA GPU, you may face the following error:" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:56 -msgid "" -"This typically indicates that your CUDA driver version is not compatible " -"with the PyTorch version you are using." -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:58 -msgid "" -"Go to `https://pytorch.org `_ to install a PyTorch " -"version that has been compiled with your version of the CUDA driver. **Do" -" not install a cuda version smaller than 11.8, preferably between 11.8 " -"and 12.1.**" -msgstr "" - -#: ../../source/getting_started/troubleshooting.rst:61 -msgid "" -"Say if your CUDA driver version is 11.8, then you can install PyTorch " -"with the following command:" -msgstr "" - -#~ msgid "" -#~ "Go to `https://pytorch.org `_" -#~ " to install a PyTorch version that" -#~ " has been compiled with your version" -#~ " of the CUDA driver." -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/using_xinference.po b/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/using_xinference.po deleted file mode 100644 index ac2a8bd9a1..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/using_xinference.po +++ /dev/null @@ -1,383 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/getting_started/using_xinference.rst:5 -msgid "Using Xinference" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:9 -msgid "Run Xinference Locally" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:11 -msgid "" -"Let's start by running Xinference on a local machine and running a " -"classic LLM model: ``llama-2-chat``." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:13 -msgid "" -"After this quickstart, you will move on to learning how to deploy " -"Xinference in a cluster environment." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:16 -msgid "Start Local Server" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:18 -msgid "" -"First, please ensure that you have installed Xinference according to the " -"instructions provided :ref:`here `. To start a local " -"instance of Xinference, run the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:23 -#: ../../source/getting_started/using_xinference.rst:65 -msgid "shell" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:29 -#: ../../source/getting_started/using_xinference.rst:71 -msgid "output" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:39 -msgid "" -"By default, Xinference uses ``/.xinference`` as home path to store " -"necessary files such as logs and models, where ```` is the home " -"path of current user." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:42 -msgid "" -"You can change this directory by configuring the environment variable " -"``XINFERENCE_HOME``. For example:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:49 -msgid "" -"Congrats! You now have Xinference running on your local machine. Once " -"Xinference is running, there are multiple ways we can try it: via the web" -" UI, via cURL, via the command line, or via the Xinference's python " -"client." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:52 -msgid "" -"You can visit the web UI at `http://127.0.0.1:9997/ui " -"`_ and visit `http://127.0.0.1:9997/docs " -"`_ to inspect the API docs." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:55 -msgid "" -"You can install the Xinference command line tool and Python client using " -"the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:61 -msgid "" -"The command line tool is ``xinference``. You can list the commands that " -"can be used by running:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:95 -msgid "" -"You can install the Xinference Python client with minimal dependencies " -"using the following command. Please ensure that the version of the client" -" matches the version of the Xinference server." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:103 -msgid "Run Llama-2" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:105 -msgid "" -"Let's start by running a built-in model: ``llama-2-chat``. When you start" -" a model for the first time, Xinference will download the model " -"parameters from HuggingFace, which might take a few minutes depending on " -"the size of the model weights. We cache the model files locally, so " -"there's no need to redownload them for subsequent starts." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:110 -msgid "" -"Xinference also allows you to download models from other sites. You can " -"do this by setting an environment variable when launching Xinference. For" -" example, if you want to download models from `modelscope " -"`_, do the following:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:118 -msgid "" -"We can specify the model's UID using the ``--model-uid`` or ``-u`` flag. " -"If not specified, Xinference will generate a random ID. This create a new" -" model instance with unique ID ``my-llama-2``:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:156 -msgid "" -"Congrats! You now have ``llama-2-chat`` running by Xinference. Once the " -"model is running, we can try it out either command line, via cURL, or via" -" Xinference's python client:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:221 -msgid "" -"Xinference provides OpenAI-compatible APIs for its supported models, so " -"you can use Xinference as a local drop-in replacement for OpenAI APIs. " -"For example:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:237 -msgid "The following OpenAI APIs are supported:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:239 -msgid "" -"Chat Completions: `https://platform.openai.com/docs/api-reference/chat " -"`_" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:241 -msgid "" -"Completions: `https://platform.openai.com/docs/api-reference/completions " -"`_" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:243 -msgid "" -"Embeddings: `https://platform.openai.com/docs/api-reference/embeddings " -"`_" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:246 -msgid "Manage Models" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:248 -msgid "" -"In addition to launching models, Xinference offers various ways to manage" -" the entire lifecycle of models. You can manage models in Xinference " -"through the command line, cURL, or Xinference's python client." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:251 -msgid "" -"You can list all models of a certain type that are available to launch in" -" Xinference:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:269 -msgid "" -"The following command gives you the currently running models in " -"Xinference:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:287 -msgid "" -"When you no longer need a model that is currently running, you can remove" -" it in the following way to free up the resources it occupies:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:306 -msgid "Deploy Xinference In a Cluster" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:308 -msgid "" -"To deploy Xinference in a cluster, you need to start a Xinference " -"supervisor on one server and Xinference workers on the other servers." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:311 -msgid "" -"First, make sure you have already installed Xinference on each of the " -"servers according to the instructions provided :ref:`here " -"`. Then follow the steps below:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:315 -msgid "Start the Supervisor" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:316 -msgid "" -"On the server where you want to run the Xinference supervisor, run the " -"following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:322 -msgid "" -"Replace ``${supervisor_host}`` with the actual host of your supervisor " -"server." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:325 -msgid "" -"You can the supervisor's web UI at `http://${supervisor_host}:9997/ui " -"`_ and visit " -"`http://${supervisor_host}:9997/docs " -"`_ to inspect the API docs." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:329 -msgid "Start the Workers" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:331 -msgid "" -"On each of the other servers where you want to run Xinference workers, " -"run the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:339 -msgid "" -"Note that if you need to interact with the Xinference in a cluster via " -"the command line, you should include the ``-e`` or ``--endpoint`` flag to" -" specify the supervisor server's endpoint. For example:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:347 -msgid "Using Xinference With Docker" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:349 -msgid "To start Xinference in a Docker container, run the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:352 -msgid "Run On Nvidia GPU Host" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:359 -msgid "Run On CPU Only Host" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:367 -msgid "Using Xinference On Kubernetes" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:369 -msgid "" -"To use Xinference on Kubernetes, `KubeBlocks `_ " -"is required to help the installation." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:371 -msgid "The following steps assume Kubernetes is already installed." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:373 -msgid "" -"Download cli tool kbcli for KubeBlocks, see `install kbcli " -"`_." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:375 -msgid "Make sure kbcli version is at least v0.7.1." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:377 -msgid "" -"Install KubeBlocks using kbcli command, see `install KubeBlocks with " -"kbcli `_." -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:379 -msgid "Enable Xinference addon, run the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:385 -msgid "Use kbcli to start Xinference cluster, run the following command:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:391 -msgid "" -"If the Kubernetes node doesn't have GPU on it, run the command with extra" -" flag:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:397 -msgid "Use -h to read the help documentation for more options:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:404 -msgid "What's Next?" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:406 -msgid "" -"Congratulations on getting started with Xinference! To help you navigate " -"and make the most out of this powerful tool, here are some resources and " -"guides:" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:409 -msgid "" -":ref:`How to Use Client APIs for Different Types of Models " -"`" -msgstr "" - -#: ../../source/getting_started/using_xinference.rst:411 -msgid ":ref:`Choosing the Right Backends for Your Needs `" -msgstr "" - -#~ msgid "Configure Xinference Home Path" -#~ msgstr "" - -#~ msgid "Using Xinference Locally" -#~ msgstr "" - -#~ msgid "To start a local instance of Xinference, run the following command:" -#~ msgstr "" - -#~ msgid "Using Xinference In a Cluster" -#~ msgstr "" - -#~ msgid "" -#~ "To deploy Xinference in a cluster, " -#~ "you need to start a Xinference " -#~ "supervisor on one server and Xinference" -#~ " workers on the other servers. Follow" -#~ " the steps below:" -#~ msgstr "" - -#~ msgid "Starting the Supervisor" -#~ msgstr "" - -#~ msgid "" -#~ "Replace ${supervisor_host} with the actual " -#~ "host of your supervisor server." -#~ msgstr "" - -#~ msgid "Starting the Workers" -#~ msgstr "" - -#~ msgid "" -#~ "Once Xinference is running, an endpoint" -#~ " will be accessible for model " -#~ "management via CLI or Xinference client." -#~ msgstr "" diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/index.po b/doc/source/locale/ja_JP/LC_MESSAGES/index.po deleted file mode 100644 index 0c37d06c70..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/index.po +++ /dev/null @@ -1,113 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-29 16:06+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" - -#: ../../source/index.rst:5 -msgid "Welcome to Xinference!" -msgstr "" - -#: ../../source/index.rst:18 -msgid "" -"Xorbits Inference (Xinference) is an open-source platform to streamline " -"the operation and integration of a wide array of AI models. With " -"Xinference, you're empowered to run inference using any open-source LLMs," -" embedding models, and multimodal models either in the cloud or on your " -"own premises, and create robust AI-driven applications." -msgstr "" - -#: ../../source/index.rst:24 -msgid "Developing Real-world AI Applications with Xinference" -msgstr "" - -#: ../../source/index.rst:80 -msgid "Getting Started" -msgstr "" - -#: ../../source/index.rst:84 -msgid "Install Xinference" -msgstr "" - -#: ../../source/index.rst:88 -msgid "Install Xinference on Linux, Windows, and macOS." -msgstr "" - -#: ../../source/index.rst:90 -msgid "Try it out!" -msgstr "" - -#: ../../source/index.rst:94 -msgid "Start by running Xinference on a local machine." -msgstr "" - -#: ../../source/index.rst:99 -msgid "Explore models" -msgstr "" - -#: ../../source/index.rst:103 -msgid "Explore a wide range of models supported by Xinference." -msgstr "" - -#: ../../source/index.rst:105 -msgid "Register your own model" -msgstr "" - -#: ../../source/index.rst:109 -msgid "Register model weights and turn it into an API." -msgstr "" - -#: ../../source/index.rst:113 -msgid "Getting Involved" -msgstr "" - -#: ../../source/index.rst:122 -msgid "Get Latest News" -msgstr "" - -#: ../../source/index.rst:130 -msgid ":fab:`twitter` Follow us on Twitter" -msgstr "" - -#: ../../source/index.rst:135 -msgid ":fab:`zhihu` Read our blogs" -msgstr "" - -#: ../../source/index.rst:142 -msgid "Get Support" -msgstr "" - -#: ../../source/index.rst:150 -msgid ":fab:`weixin` Find community on WeChat" -msgstr "" - -#: ../../source/index.rst:155 -msgid ":fab:`slack` Find community on Slack" -msgstr "" - -#: ../../source/index.rst:160 -msgid ":fab:`github` Open an issue" -msgstr "" - -#: ../../source/index.rst:167 -msgid "Contribute to Xinference" -msgstr "" - -#: ../../source/index.rst:175 -msgid ":fab:`github` Create a pull request" -msgstr "" diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi-200k.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi-200k.po deleted file mode 100644 index 3988dde6d4..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi-200k.po +++ /dev/null @@ -1,100 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-13 12:00+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/Yi-200k.rst:6 -msgid "Yi-200k" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:8 -msgid "**Context Length:** 204800" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:9 -msgid "**Model Name:** Yi-200k" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:10 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:11 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:12 -msgid "" -"**Description:** The Yi series models are large language models trained " -"from scratch by developers at 01.AI. The first public release contains " -"two bilingual (English/Chinese) base models with the parameter sizes of " -"6B and 34B. Both of them are trained with 4K sequence length and can be " -"extended to 32K during inference time." -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:15 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:18 -msgid "Model Spec 1 (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:20 -#: ../../source/models/builtin/Yi-200k.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:21 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:22 -#: ../../source/models/builtin/Yi-200k.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:23 -msgid "**Model ID:** 01-ai/Yi-6B-200K" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:25 -#: ../../source/models/builtin/Yi-200k.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"`${quantization}` with your chosen quantization method from the options " -"listed above::" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:32 -msgid "Model Spec 2 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:35 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:37 -msgid "**Model ID:** 01-ai/Yi-34B-200K" -msgstr "" - -#: ../../source/models/builtin/Yi-200k.rst:47 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi.po deleted file mode 100644 index 0bde01b05f..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/Yi.po +++ /dev/null @@ -1,97 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-13 12:00+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/Yi.rst:6 -msgid "Yi" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:8 -msgid "**Context Length:** 4096" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:9 -msgid "**Model Name:** Yi" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:10 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:11 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:12 -msgid "" -"**Description:** The Yi series models are large language models trained " -"from scratch by developers at 01.AI. The first public release contains " -"two bilingual (English/Chinese) base models with the parameter sizes of " -"6B and 34B. Both of them are trained with 4K sequence length and can be " -"extended to 32K during inference time." -msgstr "" - -#: ../../source/models/builtin/Yi.rst:15 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:18 -msgid "Model Spec 1 (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:20 ../../source/models/builtin/Yi.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:21 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:22 ../../source/models/builtin/Yi.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:23 -msgid "**Model ID:** 01-ai/Yi-6B" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:25 ../../source/models/builtin/Yi.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"`${quantization}` with your chosen quantization method from the options " -"listed above::" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:32 -msgid "Model Spec 2 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:35 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:37 -msgid "**Model ID:** 01-ai/Yi-34B" -msgstr "" - -#: ../../source/models/builtin/Yi.rst:47 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2-chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2-chat.po deleted file mode 100644 index c1377aae85..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2-chat.po +++ /dev/null @@ -1,114 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/baichuan-2-chat.rst:5 -msgid "Baichuan-2-Chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:7 -msgid "**Context Length:** 4096" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:8 -msgid "**Model Name:** baichuan-2-chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:9 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:10 -msgid "**Abilities:** embed, generate, chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:11 -msgid "" -"**Description:** Baichuan2-chat is a fine-tuned version of the Baichuan " -"LLM, specializing in chatting." -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:17 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:19 -#: ../../source/models/builtin/baichuan-2-chat.rst:38 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:21 -#: ../../source/models/builtin/baichuan-2-chat.rst:40 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:22 -msgid "**Model ID:** baichuan-inc/Baichuan2-7B-Chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:23 -msgid "**Model Revision:** 2ce891951e000c36c65442608a0b95fd09b405dc" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:25 -#: ../../source/models/builtin/baichuan-2-chat.rst:44 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:32 -#: ../../source/models/builtin/baichuan-2-chat.rst:51 -msgid "Not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:36 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:39 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:41 -msgid "**Model ID:** baichuan-inc/Baichuan2-13B-Chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-2-chat.rst:42 -msgid "**Model Revision:** a56c793eb7a721ab6c270f779024e0375e8afd4a" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2.po deleted file mode 100644 index 79ccb3a355..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-2.po +++ /dev/null @@ -1,106 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/baichuan-2.rst:5 -msgid "Baichuan-2" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:7 -msgid "**Context Length:** 4096" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:8 -msgid "**Model Name:** baichuan-2" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:9 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:10 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:11 -msgid "" -"**Description:** Baichuan2 is an open-source Transformer based LLM that " -"is trained on both Chinese and English data." -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:17 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:19 -#: ../../source/models/builtin/baichuan-2.rst:36 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:21 -#: ../../source/models/builtin/baichuan-2.rst:38 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:22 -msgid "**Model ID:** baichuan-inc/Baichuan2-7B-Base" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:24 -#: ../../source/models/builtin/baichuan-2.rst:41 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:31 -#: ../../source/models/builtin/baichuan-2.rst:48 -msgid "Not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:34 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:37 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/baichuan-2.rst:39 -msgid "**Model ID:** baichuan-inc/Baichuan2-13B-Base" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-chat.po deleted file mode 100644 index f267d13ba1..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan-chat.po +++ /dev/null @@ -1,76 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/baichuan-chat.rst:5 -msgid "Baichuan Chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:7 -msgid "**Model Name:** baichuan-chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:14 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:15 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:16 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:17 -msgid "**Model ID:** baichuan-inc/Baichuan-13B-Chat" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:19 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/baichuan-chat.rst:26 -msgid "Not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan.po deleted file mode 100644 index 94e88f6c31..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/baichuan.po +++ /dev/null @@ -1,122 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/baichuan.rst:5 -msgid "Baichuan" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:7 -msgid "**Model Name:** baichuan" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:15 -msgid "Model Spec 1 (ggmlv3)" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:17 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:18 -#: ../../source/models/builtin/baichuan.rst:35 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:19 -msgid "" -"**Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, " -"q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:20 -msgid "**Model ID:** TheBloke/baichuan-llama-7B-GGML" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:22 -#: ../../source/models/builtin/baichuan.rst:39 -#: ../../source/models/builtin/baichuan.rst:56 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:29 -msgid "" -"For utilizing the Apple Metal GPU for acceleration, select the q4_0 and " -"q4_1 quantizations." -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:32 -msgid "Model Spec 2 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:34 -#: ../../source/models/builtin/baichuan.rst:51 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:36 -#: ../../source/models/builtin/baichuan.rst:53 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:37 -msgid "**Model ID:** baichuan-inc/Baichuan-7B" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:46 -#: ../../source/models/builtin/baichuan.rst:63 -msgid "Not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:49 -msgid "Model Spec 3 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:52 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/baichuan.rst:54 -msgid "**Model ID:** baichuan-inc/Baichuan-13B-Base" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en-v1.5.po deleted file mode 100644 index ca8da624b8..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:5 -msgid "bge-base-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:7 -msgid "**Model Name:** bge-base-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:14 -msgid "**Dimensions:** 768" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-base-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-en-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en.po deleted file mode 100644 index 417b82647c..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-en.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-base-en.rst:5 -msgid "bge-base-en" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:7 -msgid "**Model Name:** bge-base-en" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:14 -msgid "**Dimensions:** 768" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:16 -msgid "**Model ID:** BAAI/bge-base-en" -msgstr "" - -#: ../../source/models/builtin/bge-base-en.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh-v1.5.po deleted file mode 100644 index f45b1ac480..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:5 -msgid "bge-base-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:7 -msgid "**Model Name:** bge-base-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:14 -msgid "**Dimensions:** 768" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-base-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh.po deleted file mode 100644 index 97f49c6f59..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-base-zh.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-base-zh.rst:5 -msgid "bge-base-zh" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:7 -msgid "**Model Name:** bge-base-zh" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:16 -msgid "**Model ID:** BAAI/bge-base-zh" -msgstr "" - -#: ../../source/models/builtin/bge-base-zh.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en-v1.5.po deleted file mode 100644 index 922242c375..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:5 -msgid "bge-large-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:7 -msgid "**Model Name:** bge-large-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-large-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-en-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en.po deleted file mode 100644 index fd7d9d4fd6..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-en.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-large-en.rst:5 -msgid "bge-large-en" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:7 -msgid "**Model Name:** bge-large-en" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:16 -msgid "**Model ID:** BAAI/bge-large-en" -msgstr "" - -#: ../../source/models/builtin/bge-large-en.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-noinstruct.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-noinstruct.po deleted file mode 100644 index 68e7b1c958..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-noinstruct.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:5 -msgid "bge-large-zh-noinstruct" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:7 -msgid "**Model Name:** bge-large-zh-noinstruct" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:16 -msgid "**Model ID:** BAAI/bge-large-zh-noinstruct" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-noinstruct.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-v1.5.po deleted file mode 100644 index a5138e9302..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:5 -msgid "bge-large-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:7 -msgid "**Model Name:** bge-large-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-large-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh.po deleted file mode 100644 index 2096059464..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-large-zh.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-large-zh.rst:5 -msgid "bge-large-en" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:7 -msgid "**Model Name:** bge-large-zh" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:16 -msgid "**Model ID:** BAAI/bge-large-zh" -msgstr "" - -#: ../../source/models/builtin/bge-large-zh.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-en-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-en-v1.5.po deleted file mode 100644 index 88e42c35f9..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-en-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:5 -msgid "bge-small-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:7 -msgid "**Model Name:** bge-small-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:14 -msgid "**Dimensions:** 384" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-small-en-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-en-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh-v1.5.po deleted file mode 100644 index e05784936f..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh-v1.5.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:5 -msgid "bge-small-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:7 -msgid "**Model Name:** bge-small-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:14 -msgid "**Dimensions:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:16 -msgid "**Model ID:** BAAI/bge-small-zh-v1.5" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh-v1.5.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh.po deleted file mode 100644 index a181a676ff..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/bge-small-zh.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/bge-small-zh.rst:5 -msgid "bge-large-en" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:7 -msgid "**Model Name:** bge_small_zh" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:14 -msgid "**Dimensions:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:16 -msgid "**Model ID:** BAAI/bge_small_zh" -msgstr "" - -#: ../../source/models/builtin/bge-small-zh.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm.po deleted file mode 100644 index b8ad527901..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm.po +++ /dev/null @@ -1,98 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/chatglm.rst:5 -msgid "ChatGLM" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:7 -msgid "**Model Name:** chatglm" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:15 -msgid "Model Spec 1 (ggmlv3, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:17 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:18 -#: ../../source/models/builtin/chatglm.rst:31 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:19 -msgid "**Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:20 -msgid "**Model ID:** Xorbits/chatglm-6B-GGML" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:22 -#: ../../source/models/builtin/chatglm.rst:35 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:28 -msgid "Model Spec 2 (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:30 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:32 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:33 -msgid "**Model ID:** THUDM/chatglm-6b" -msgstr "" - -#: ../../source/models/builtin/chatglm.rst:42 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2-32k.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2-32k.po deleted file mode 100644 index 7835ae324f..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2-32k.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/chatglm2-32k.rst:5 -msgid "ChatGLM2 32k" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:7 -msgid "**Model Name:** chatglm2-32k" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:15 -msgid "Model Spec 1 (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:18 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:20 -msgid "**Model ID:** THUDM/chatglm2-6b-32k" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/chatglm2-32k.rst:29 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2.po deleted file mode 100644 index e96f2026b5..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm2.po +++ /dev/null @@ -1,98 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/chatglm2.rst:5 -msgid "ChatGLM2" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:7 -msgid "**Model Name:** chatglm2" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:15 -msgid "Model Spec 1 (ggmlv3, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:17 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:18 -#: ../../source/models/builtin/chatglm2.rst:31 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:19 -msgid "**Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:20 -msgid "**Model ID:** Xorbits/chatglm2-6B-GGML" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:22 -#: ../../source/models/builtin/chatglm2.rst:35 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:28 -msgid "Model Spec 2 (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:30 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:32 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:33 -msgid "**Model ID:** THUDM/chatglm2-6b" -msgstr "" - -#: ../../source/models/builtin/chatglm2.rst:42 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3-32k.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3-32k.po deleted file mode 100644 index cbf6983fb9..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3-32k.po +++ /dev/null @@ -1,82 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/chatglm3-32k.rst:6 -msgid "ChatGLM3-32K" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:8 -msgid "**Context Length:** 32768" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:9 -msgid "**Model Name:** chatglm3-32k" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:10 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:11 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:12 -msgid "" -"**Description:** ChatGLM3 is the third generation of ChatGLM, still open-" -"source and trained on Chinese and English data." -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:15 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:18 -msgid "Model Spec (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:20 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:21 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:22 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:23 -msgid "**Model ID:** THUDM/chatglm3-6b-32k" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:25 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/chatglm3-32k.rst:32 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3.po deleted file mode 100644 index b915c3932e..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/chatglm3.po +++ /dev/null @@ -1,82 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/chatglm3.rst:6 -msgid "ChatGLM3" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:8 -msgid "**Context Length:** 8192" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:9 -msgid "**Model Name:** chatglm3" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:10 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:11 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:12 -msgid "" -"**Description:** ChatGLM3 is the third generation of ChatGLM, still open-" -"source and trained on Chinese and English data." -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:15 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:18 -msgid "Model Spec (pytorch, 6 Billion)" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:20 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:21 -msgid "**Model Size (in billions):** 6" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:22 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:23 -msgid "**Model ID:** THUDM/chatglm3-6b" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:25 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/chatglm3.rst:32 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-instruct.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-instruct.po deleted file mode 100644 index 74e20905fa..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-instruct.po +++ /dev/null @@ -1,116 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/code-llama-instruct.rst:6 -msgid "Code-Llama-Instruct" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:8 -msgid "**Context Length:** 100000" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:9 -msgid "**Model Name:** code-llama-instruct" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:10 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:11 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:17 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:19 -#: ../../source/models/builtin/code-llama-instruct.rst:36 -#: ../../source/models/builtin/code-llama-instruct.rst:54 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:21 -#: ../../source/models/builtin/code-llama-instruct.rst:38 -#: ../../source/models/builtin/code-llama-instruct.rst:56 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:22 -msgid "**Model ID:** codellama/CodeLlama-7b-Instruct-hf" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:24 -#: ../../source/models/builtin/code-llama-instruct.rst:41 -#: ../../source/models/builtin/code-llama-instruct.rst:59 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:31 -#: ../../source/models/builtin/code-llama-instruct.rst:49 -#: ../../source/models/builtin/code-llama-instruct.rst:67 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:34 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:37 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:39 -msgid "**Model ID:** codellama/CodeLlama-13b-Instruct-hf" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:52 -msgid "Model Spec 3 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:55 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/code-llama-instruct.rst:57 -msgid "**Model ID:** codellama/CodeLlama-34b-Instruct-hf" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-python.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-python.po deleted file mode 100644 index cd3faea25e..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama-python.po +++ /dev/null @@ -1,116 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/code-llama-python.rst:6 -msgid "Code-Llama-Python" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:8 -msgid "**Context Length:** 100000" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:9 -msgid "**Model Name:** code-llama-python" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:10 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:11 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:17 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:19 -#: ../../source/models/builtin/code-llama-python.rst:36 -#: ../../source/models/builtin/code-llama-python.rst:53 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:21 -#: ../../source/models/builtin/code-llama-python.rst:38 -#: ../../source/models/builtin/code-llama-python.rst:55 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:22 -msgid "**Model ID:** TheBloke/CodeLlama-7B-Python-fp16" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:24 -#: ../../source/models/builtin/code-llama-python.rst:41 -#: ../../source/models/builtin/code-llama-python.rst:58 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:31 -#: ../../source/models/builtin/code-llama-python.rst:48 -#: ../../source/models/builtin/code-llama-python.rst:65 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:34 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:37 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:39 -msgid "**Model ID:** TheBloke/CodeLlama-13B-Python-fp16" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:51 -msgid "Model Spec 3 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:54 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/code-llama-python.rst:56 -msgid "**Model ID:** TheBloke/CodeLlama-34B-Python-fp16" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama.po deleted file mode 100644 index 7f10c1b7e7..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/code-llama.po +++ /dev/null @@ -1,116 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/code-llama.rst:5 -msgid "Code-Llama" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:7 -msgid "**Context Length:** 100000" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:8 -msgid "**Model Name:** code-llama" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:9 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:10 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:13 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:16 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:18 -#: ../../source/models/builtin/code-llama.rst:35 -#: ../../source/models/builtin/code-llama.rst:52 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:19 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:20 -#: ../../source/models/builtin/code-llama.rst:37 -#: ../../source/models/builtin/code-llama.rst:54 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:21 -msgid "**Model ID:** TheBloke/CodeLlama-7B-fp16" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:23 -#: ../../source/models/builtin/code-llama.rst:40 -#: ../../source/models/builtin/code-llama.rst:57 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:30 -#: ../../source/models/builtin/code-llama.rst:47 -#: ../../source/models/builtin/code-llama.rst:64 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:33 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:36 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:38 -msgid "**Model ID:** TheBloke/CodeLlama-13B-fp16" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:50 -msgid "Model Spec 3 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:53 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/code-llama.rst:55 -msgid "**Model ID:** TheBloke/CodeLlama-34B-fp16" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/e5-large-v2.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/e5-large-v2.po deleted file mode 100644 index 5df20a610a..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/e5-large-v2.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/e5-large-v2.rst:5 -msgid "gte-large" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:7 -msgid "**Model Name:** e5-large-v2" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:16 -msgid "**Model ID:** intfloat/e5-large-v2" -msgstr "" - -#: ../../source/models/builtin/e5-large-v2.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon-instruct.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon-instruct.po deleted file mode 100644 index a75cc2cb38..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon-instruct.po +++ /dev/null @@ -1,96 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/falcon-instruct.rst:5 -msgid "Falcon Instruct" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:7 -msgid "**Model Name:** falcon-instruct" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:15 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:17 -#: ../../source/models/builtin/falcon-instruct.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:19 -#: ../../source/models/builtin/falcon-instruct.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:20 -msgid "**Model ID:** tiiuae/falcon-7b-instruct" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:22 -#: ../../source/models/builtin/falcon-instruct.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:29 -#: ../../source/models/builtin/falcon-instruct.rst:46 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:32 -msgid "Model Spec 2 (pytorch, 40 Billion)" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:35 -msgid "**Model Size (in billions):** 40" -msgstr "" - -#: ../../source/models/builtin/falcon-instruct.rst:37 -msgid "**Model ID:** tiiuae/falcon-40b-instruct" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon.po deleted file mode 100644 index 085bdab8da..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/falcon.po +++ /dev/null @@ -1,96 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/falcon.rst:5 -msgid "Falcon" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:7 -msgid "**Model Name:** falcon" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:15 -msgid "Model Spec 2 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:17 -#: ../../source/models/builtin/falcon.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:19 -#: ../../source/models/builtin/falcon.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:20 -msgid "**Model ID:** tiiuae/falcon-7b" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:22 -#: ../../source/models/builtin/falcon.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:29 -#: ../../source/models/builtin/falcon.rst:46 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/falcon.rst:32 -msgid "Model Spec 1 (pytorch, 40 Billion)" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:35 -msgid "**Model Size (in billions):** 40" -msgstr "" - -#: ../../source/models/builtin/falcon.rst:37 -msgid "**Model ID:** tiiuae/falcon-40b" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-base.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-base.po deleted file mode 100644 index 79e1a7a3a2..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-base.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/gte-base.rst:5 -msgid "gte-base" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:7 -msgid "**Model Name:** gte-base" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:14 -msgid "**Dimensions:** 768" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:16 -msgid "**Model ID:** thenlper/gte-large" -msgstr "" - -#: ../../source/models/builtin/gte-base.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-large.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-large.po deleted file mode 100644 index 267ad355d1..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/gte-large.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/gte-large.rst:5 -msgid "gte-large" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:7 -msgid "**Model Name:** gte-large" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:16 -msgid "**Model ID:** thenlper/gte-large" -msgstr "" - -#: ../../source/models/builtin/gte-large.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/index.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/index.po deleted file mode 100644 index 523e761bfd..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/index.po +++ /dev/null @@ -1,214 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/index.rst:5 -msgid "Builtin Models" -msgstr "" - -#~ msgid "Built-in Models" -#~ msgstr "" - -#~ msgid "Large Language Models" -#~ msgstr "" - -#~ msgid "Text Generation Models" -#~ msgstr "" - -#~ msgid ":ref:`Baichuan `" -#~ msgstr "" - -#~ msgid ":ref:`Baichuan-2 `" -#~ msgstr "" - -#~ msgid ":ref:`Falcon `" -#~ msgstr "" - -#~ msgid ":ref:`InternLM `" -#~ msgstr "" - -#~ msgid ":ref:`InternLM 20B `" -#~ msgstr "" - -#~ msgid ":ref:`Llama-2 `" -#~ msgstr "" - -#~ msgid ":ref:`OPT `" -#~ msgstr "" - -#~ msgid ":ref:`Yi `" -#~ msgstr "" - -#~ msgid ":ref:`Yi-200k `" -#~ msgstr "" - -#~ msgid "Chat & Instruction-following Models" -#~ msgstr "" - -#~ msgid ":ref:`Baichuan Chat `" -#~ msgstr "" - -#~ msgid ":ref:`Baichuan-2 Chat `" -#~ msgstr "" - -#~ msgid ":ref:`ChatGLM `" -#~ msgstr "" - -#~ msgid ":ref:`ChatGLM2 `" -#~ msgstr "" - -#~ msgid ":ref:`ChatGLM2-32k `" -#~ msgstr "" - -#~ msgid ":ref:`ChatGLM3 `" -#~ msgstr "" - -#~ msgid ":ref:`ChatGLM3-32k `" -#~ msgstr "" - -#~ msgid ":ref:`CodeLlama-Instruct `" -#~ msgstr "" - -#~ msgid ":ref:`Falcon Instruct `" -#~ msgstr "" - -#~ msgid ":ref:`InternLM Chat `" -#~ msgstr "" - -#~ msgid ":ref:`InternLM Chat 20B `" -#~ msgstr "" - -#~ msgid ":ref:`InternLM Chat 8K `" -#~ msgstr "" - -#~ msgid ":ref:`Llama-2 Chat `" -#~ msgstr "" - -#~ msgid ":ref:`OpenBuddy v11.1 `" -#~ msgstr "" - -#~ msgid ":ref:`Orca Mini `" -#~ msgstr "" - -#~ msgid ":ref:`Qwen Chat `" -#~ msgstr "" - -#~ msgid ":ref:`Vicuna v1.3 `" -#~ msgstr "" - -#~ msgid ":ref:`Vicuna v1.5 `" -#~ msgstr "" - -#~ msgid ":ref:`Vicuna v1.5 16k `" -#~ msgstr "" - -#~ msgid ":ref:`WizardLM v1.0 `" -#~ msgstr "" - -#~ msgid ":ref:`WizardMath v1.0 `" -#~ msgstr "" - -#~ msgid ":ref:`Zephyr-7B-α `" -#~ msgstr "" - -#~ msgid ":ref:`Zephyr-7B-β `" -#~ msgstr "" - -#~ msgid "Code Generation Models" -#~ msgstr "" - -#~ msgid ":ref:`Starcoder `" -#~ msgstr "" - -#~ msgid ":ref:`StarCoderPlus `" -#~ msgstr "" - -#~ msgid ":ref:`Code-Llama `" -#~ msgstr "" - -#~ msgid ":ref:`Code-Llama-Python `" -#~ msgstr "" - -#~ msgid ":ref:`WizardCoder-Python-v1.0 `" -#~ msgstr "" - -#~ msgid "Code Assistant Models" -#~ msgstr "" - -#~ msgid ":ref:`Starchat-beta `" -#~ msgstr "" - -#~ msgid "Embedding Models" -#~ msgstr "" - -#~ msgid "Language: English" -#~ msgstr "" - -#~ msgid ":ref:`bge-large-en `" -#~ msgstr "" - -#~ msgid ":ref:`bge-large-en-v1.5 `" -#~ msgstr "" - -#~ msgid ":ref:`bge-base-en `" -#~ msgstr "" - -#~ msgid ":ref:`bge-base-en-v1.5 `" -#~ msgstr "" - -#~ msgid ":ref:`gte-large `" -#~ msgstr "" - -#~ msgid ":ref:`gte-base `" -#~ msgstr "" - -#~ msgid ":ref:`e5-large-v2 `" -#~ msgstr "" - -#~ msgid ":ref:`bge-small-en-v1.5 `" -#~ msgstr "" - -#~ msgid "Language: Chinese" -#~ msgstr "" - -#~ msgid ":ref:`bge-large-zh `" -#~ msgstr "" - -#~ msgid ":ref:`bge-large-zh-noinstruct `" -#~ msgstr "" - -#~ msgid ":ref:`bge-large-zh-v1.5 `" -#~ msgstr "" - -#~ msgid ":ref:`bge-base-zh `" -#~ msgstr "" - -#~ msgid ":ref:`bge-base-zh-v1.5 `" -#~ msgstr "" - -#~ msgid ":ref:`multilingual-e5-large `" -#~ msgstr "" - -#~ msgid ":ref:`bge-small-zh `" -#~ msgstr "" - -#~ msgid ":ref:`bge-small-zh-v1.5 `" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-20b.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-20b.po deleted file mode 100644 index a0ed3b4914..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-20b.po +++ /dev/null @@ -1,75 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/internlm-20b.rst:5 -msgid "InternLM-20B Model" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:7 -msgid "**Context Length:** 16384" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:8 -msgid "**Model Name:** internlm-20b" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:9 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:10 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:11 -msgid "" -"**Description:** Pre-trained on over 2.3T Tokens containing high-quality " -"English, Chinese, and code data." -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:17 -msgid "Model Spec (pytorch, 20 Billion)" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:19 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:20 -msgid "**Model Size (in billions):** 20" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:21 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:22 -msgid "**Model ID:** internlm/internlm-20b" -msgstr "" - -#: ../../source/models/builtin/internlm-20b.rst:23 -msgid "**Model Revision:** f0433b0db933a9adfa169f756ab8547f67ccef1d" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-20b.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-20b.po deleted file mode 100644 index ed34f0a948..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-20b.po +++ /dev/null @@ -1,72 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/internlm-chat-20b.rst:5 -msgid "InternLM-Chat-20B" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:7 -msgid "**Context Length:** 16384" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:8 -msgid "**Model Name:** internlm-chat-20b" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:9 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:10 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:11 -msgid "" -"**Description:** Pre-trained on over 2.3T Tokens containing high-quality " -"English, Chinese, and code data. The Chat version has undergone SFT and " -"RLHF training." -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:17 -msgid "Model Spec (pytorch, 20 Billion)" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:19 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:20 -msgid "**Model Size (in billions):** 20" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:21 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-20b.rst:22 -msgid "**Model ID:** internlm/internlm-chat-20b" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-8k.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-8k.po deleted file mode 100644 index f7a27b423a..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat-8k.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/internlm-chat-8k.rst:6 -msgid "InternLM Chat 8K" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:8 -msgid "**Model Name:** internlm-chat-8k" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:9 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:10 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:13 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:16 -msgid "Model Spec (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:18 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:19 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:20 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:21 -msgid "**Model ID:** internlm/internlm-chat-7b-8k" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:23 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/internlm-chat-8k.rst:29 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat.po deleted file mode 100644 index 504d48e012..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm-chat.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/internlm-chat.rst:5 -msgid "InternLM Chat" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:7 -msgid "**Model Name:** internlm-chat" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:15 -msgid "Model Spec (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:20 -msgid "**Model ID:** internlm/internlm-chat-7b" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/internlm-chat.rst:28 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm.po deleted file mode 100644 index 51c2b94952..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/internlm.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/internlm.rst:5 -msgid "InternLM" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:7 -msgid "**Model Name:** internlm" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:15 -msgid "Model Spec (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:20 -msgid "**Model ID:** internlm/internlm-7b" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/internlm.rst:28 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2-chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2-chat.po deleted file mode 100644 index c458ef02b6..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2-chat.po +++ /dev/null @@ -1,156 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/llama-2-chat.rst:5 -msgid "Llama-2 Chat" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:7 -msgid "**Model Name:** llama-2-chat" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:15 -msgid "Model Spec 1 (ggmlv3, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:17 -#: ../../source/models/builtin/llama-2-chat.rst:30 -#: ../../source/models/builtin/llama-2-chat.rst:44 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:18 -#: ../../source/models/builtin/llama-2-chat.rst:58 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:19 -#: ../../source/models/builtin/llama-2-chat.rst:32 -#: ../../source/models/builtin/llama-2-chat.rst:46 -msgid "" -"**Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, " -"q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:20 -msgid "**Model ID:** TheBloke/Llama-2-7B-Chat-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:22 -#: ../../source/models/builtin/llama-2-chat.rst:35 -#: ../../source/models/builtin/llama-2-chat.rst:49 -#: ../../source/models/builtin/llama-2-chat.rst:62 -#: ../../source/models/builtin/llama-2-chat.rst:80 -#: ../../source/models/builtin/llama-2-chat.rst:97 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:28 -msgid "Model Spec 2 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:31 -#: ../../source/models/builtin/llama-2-chat.rst:76 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:33 -msgid "**Model ID:** TheBloke/Llama-2-13B-chat-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:42 -msgid "Model Spec 3 (ggmlv3, 70 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:45 -#: ../../source/models/builtin/llama-2-chat.rst:93 -msgid "**Model Size (in billions):** 70" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:47 -msgid "**Model ID:** TheBloke/Llama-2-70B-Chat-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:55 -msgid "Model Spec 4 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:57 -#: ../../source/models/builtin/llama-2-chat.rst:75 -#: ../../source/models/builtin/llama-2-chat.rst:92 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:59 -#: ../../source/models/builtin/llama-2-chat.rst:77 -#: ../../source/models/builtin/llama-2-chat.rst:94 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:60 -msgid "**Model ID:** meta-llama/Llama-2-7b-chat-hf" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:69 -#: ../../source/models/builtin/llama-2-chat.rst:87 -#: ../../source/models/builtin/llama-2-chat.rst:104 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:73 -msgid "Model Spec 5 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:78 -msgid "**Model ID:** meta-llama/Llama-2-13b-chat-hf" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:90 -msgid "Model Spec 6 (pytorch, 70 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2-chat.rst:95 -msgid "**Model ID:** meta-llama/Llama-2-70b-chat-hf" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2.po deleted file mode 100644 index 39db6f5c22..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/llama-2.po +++ /dev/null @@ -1,156 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/llama-2.rst:5 -msgid "Llama-2" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:7 -msgid "**Model Name:** llama-2" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:15 -msgid "Model Spec 1 (ggmlv3, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:17 -#: ../../source/models/builtin/llama-2.rst:30 -#: ../../source/models/builtin/llama-2.rst:43 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:18 -#: ../../source/models/builtin/llama-2.rst:57 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:19 -#: ../../source/models/builtin/llama-2.rst:32 -#: ../../source/models/builtin/llama-2.rst:45 -msgid "" -"**Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, " -"q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:20 -msgid "**Model ID:** TheBloke/Llama-2-7B-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:22 -#: ../../source/models/builtin/llama-2.rst:35 -#: ../../source/models/builtin/llama-2.rst:48 -#: ../../source/models/builtin/llama-2.rst:61 -#: ../../source/models/builtin/llama-2.rst:78 -#: ../../source/models/builtin/llama-2.rst:95 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:28 -msgid "Model Spec 2 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:31 -#: ../../source/models/builtin/llama-2.rst:74 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:33 -msgid "**Model ID:** TheBloke/Llama-2-13B-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:41 -msgid "Model Spec 3 (ggmlv3, 70 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:44 -#: ../../source/models/builtin/llama-2.rst:91 -msgid "**Model Size (in billions):** 70" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:46 -msgid "**Model ID:** TheBloke/Llama-2-70B-GGML" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:54 -msgid "Model Spec 4 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:56 -#: ../../source/models/builtin/llama-2.rst:73 -#: ../../source/models/builtin/llama-2.rst:90 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:58 -#: ../../source/models/builtin/llama-2.rst:75 -#: ../../source/models/builtin/llama-2.rst:92 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:59 -msgid "**Model ID:** meta-llama/Llama-2-7b-hf" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:68 -#: ../../source/models/builtin/llama-2.rst:85 -#: ../../source/models/builtin/llama-2.rst:102 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:71 -msgid "Model Spec 5 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:76 -msgid "**Model ID:** meta-llama/Llama-2-13b-hf" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:88 -msgid "Model Spec 6 (pytorch, 70 Billion)" -msgstr "" - -#: ../../source/models/builtin/llama-2.rst:93 -msgid "**Model ID:** meta-llama/Llama-2-70b-hf" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/multilingual-e5-large.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/multilingual-e5-large.po deleted file mode 100644 index 5bf6fed901..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/multilingual-e5-large.po +++ /dev/null @@ -1,57 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/multilingual-e5-large.rst:5 -msgid "bge-base-zh" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:7 -msgid "**Model Name:** multilingual-e5-large" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:8 -msgid "**Languages:** zh" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:9 -msgid "**Abilities:** embed" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:14 -msgid "**Dimensions:** 1024" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:15 -msgid "**Max Tokens:** 512" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:16 -msgid "**Model ID:** intfloat/multilingual-e5-large" -msgstr "" - -#: ../../source/models/builtin/multilingual-e5-large.rst:18 -msgid "Execute the following command to launch the model::" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/openbuddy.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/openbuddy.po deleted file mode 100644 index 66c861628d..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/openbuddy.po +++ /dev/null @@ -1,82 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/openbuddy.rst:5 -msgid "OpenBuddy" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:7 -msgid "**Model Name:** OpenBuddy" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:15 -msgid "Model Spec 1 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:17 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:18 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:19 -msgid "" -"**Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_1, Q4_K_S, " -"Q4_K_M, Q5_0, Q5_1, Q5_K_S, Q5_K_M, Q6_K, Q8_0" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:20 -msgid "**Model ID:** TheBloke/OpenBuddy-Llama2-13B-v11.1-GGML" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/openbuddy.rst:29 -msgid "Multiple rounds chat is disabled for better translation." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/opt.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/opt.po deleted file mode 100644 index 44651fc155..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/opt.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/opt.rst:5 -msgid "OPT" -msgstr "" - -#: ../../source/models/builtin/opt.rst:7 -msgid "**Model Name:** opt" -msgstr "" - -#: ../../source/models/builtin/opt.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/opt.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/opt.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/opt.rst:15 -msgid "Model Spec 1 (pytorch, 1 Billion)" -msgstr "" - -#: ../../source/models/builtin/opt.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/opt.rst:18 -msgid "**Model Size (in billions):** 1" -msgstr "" - -#: ../../source/models/builtin/opt.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/opt.rst:20 -msgid "**Model ID:** facebook/opt-125m" -msgstr "" - -#: ../../source/models/builtin/opt.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/opt.rst:29 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/orca_mini.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/orca_mini.po deleted file mode 100644 index f0c83a9f86..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/orca_mini.po +++ /dev/null @@ -1,106 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/orca_mini.rst:5 -msgid "Orca Mini" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:7 -msgid "**Model Name:** orca" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:15 -msgid "Model Spec 1 (ggmlv3, 3 Billion)" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:17 -#: ../../source/models/builtin/orca_mini.rst:30 -#: ../../source/models/builtin/orca_mini.rst:43 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:18 -msgid "**Model Size (in billions):** 3" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:19 -#: ../../source/models/builtin/orca_mini.rst:32 -#: ../../source/models/builtin/orca_mini.rst:45 -msgid "**Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:20 -msgid "**Model ID:** TheBloke/orca_mini_3B-GGML" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:22 -#: ../../source/models/builtin/orca_mini.rst:35 -#: ../../source/models/builtin/orca_mini.rst:48 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:28 -msgid "Model Spec 2 (ggmlv3, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:31 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:33 -msgid "**Model ID:** TheBloke/orca_mini_7B-GGML" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:41 -msgid "Model Spec 3 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:44 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/orca_mini.rst:46 -msgid "**Model ID:** TheBloke/orca_mini_13B-GGML" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/qwen-chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/qwen-chat.po deleted file mode 100644 index 352d34849f..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/qwen-chat.po +++ /dev/null @@ -1,102 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-16 11:22+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/qwen-chat.rst:5 -msgid "Qwen Chat" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:7 -msgid "**Model Name:** qwen-chat" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:8 -msgid "**Languages:** en, zh" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:15 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:17 -#: ../../source/models/builtin/qwen-chat.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:20 -msgid "**Model ID:** Qwen/Qwen-7B-Chat" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:29 -#: ../../source/models/builtin/qwen-chat.rst:45 -msgid "4-bit and 8-bit quantization are not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:32 -msgid "Model Spec 2 (pytorch, 14 Billion)" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:35 -msgid "**Model Size (in billions):** 14" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:36 -msgid "**Quantizations:** none" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:37 -msgid "**Model ID:** Qwen/Qwen-14B-Chat" -msgstr "" - -#: ../../source/models/builtin/qwen-chat.rst:39 -msgid "Execute the following command to launch the model::" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starchat-beta.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starchat-beta.po deleted file mode 100644 index be581abc38..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starchat-beta.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/starchat-beta.rst:5 -msgid "Starchat-beta" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:7 -msgid "**Model Name:** starchat-beta" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:15 -msgid "Model Spec (pytorch, 16 Billion)" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:18 -msgid "**Model Size (in billions):** 16" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:20 -msgid "**Model ID:** HuggingFaceH4/starchat-beta" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/starchat-beta.rst:29 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoder.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoder.po deleted file mode 100644 index a842f7aae5..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoder.po +++ /dev/null @@ -1,61 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/starcoder.rst:5 -msgid "StarCoder" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:7 -msgid "**Model Name:** starcoder" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:9 -msgid "**Abilities:** generate" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:15 -msgid "Model Spec (ggmlv3, 16 Billion)" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:17 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:18 -msgid "**Model Size (in billions):** 16" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:19 -msgid "**Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0" -msgstr "" - -#: ../../source/models/builtin/starcoder.rst:20 -msgid "**Model ID:** TheBloke/starcoder-GGML" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoderplus.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoderplus.po deleted file mode 100644 index 7fa413967a..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/starcoderplus.po +++ /dev/null @@ -1,80 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/starcoderplus.rst:5 -msgid "StarCoderPlus" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:7 -msgid "**Model Name:** starcoderplus" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:9 -msgid "**Abilities:** embed, generate" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:15 -msgid "Model Spec (pytorch, 16 Billion)" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:17 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:18 -msgid "**Model Size (in billions):** 16" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:19 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:20 -msgid "**Model ID:** bigcode/starcoderplus" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:22 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/starcoderplus.rst:29 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.3.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.3.po deleted file mode 100644 index df86672410..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.3.po +++ /dev/null @@ -1,168 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/vicuna-v1.3.rst:5 -msgid "Vicuna v1.3" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:7 -msgid "**Model Name:** vicuna-v1.3" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:15 -msgid "Model Spec 1 (ggmlv3, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:17 -#: ../../source/models/builtin/vicuna-v1.3.rst:31 -#: ../../source/models/builtin/vicuna-v1.3.rst:45 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:18 -#: ../../source/models/builtin/vicuna-v1.3.rst:60 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:19 -#: ../../source/models/builtin/vicuna-v1.3.rst:33 -#: ../../source/models/builtin/vicuna-v1.3.rst:47 -msgid "" -"**Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, " -"q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:20 -msgid "**Model ID:** TheBloke/vicuna-7B-v1.3-GGML" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:21 -msgid "**File Name Template:** vicuna-7b-v1.3.ggmlv3.{quantization}.bin" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:23 -#: ../../source/models/builtin/vicuna-v1.3.rst:37 -#: ../../source/models/builtin/vicuna-v1.3.rst:51 -#: ../../source/models/builtin/vicuna-v1.3.rst:64 -#: ../../source/models/builtin/vicuna-v1.3.rst:81 -#: ../../source/models/builtin/vicuna-v1.3.rst:98 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:29 -msgid "Model Spec 2 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:32 -#: ../../source/models/builtin/vicuna-v1.3.rst:77 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:34 -msgid "**Model ID:** TheBloke/vicuna-13b-v1.3.0-GGML" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:35 -msgid "**File Name Template:** vicuna-13b-v1.3.0.ggmlv3.{quantization}.bin" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:43 -msgid "Model Spec 3 (ggmlv3, 33 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:46 -#: ../../source/models/builtin/vicuna-v1.3.rst:94 -msgid "**Model Size (in billions):** 33" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:48 -msgid "**Model ID:** TheBloke/vicuna-33B-GGML" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:49 -msgid "**File Name Template:** vicuna-33b.ggmlv3.{quantization}.bin" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:57 -msgid "Model Spec 6 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:59 -#: ../../source/models/builtin/vicuna-v1.3.rst:76 -#: ../../source/models/builtin/vicuna-v1.3.rst:93 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:61 -#: ../../source/models/builtin/vicuna-v1.3.rst:78 -#: ../../source/models/builtin/vicuna-v1.3.rst:95 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:62 -msgid "**Model ID:** lmsys/vicuna-7b-v1.3" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:71 -#: ../../source/models/builtin/vicuna-v1.3.rst:88 -#: ../../source/models/builtin/vicuna-v1.3.rst:105 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:74 -msgid "Model Spec 5 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:79 -msgid "**Model ID:** lmsys/vicuna-13b-v1.3" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:91 -msgid "Model Spec 4 (pytorch, 33 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.3.rst:96 -msgid "**Model ID:** lmsys/vicuna-33b-v1.3" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5-16k.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5-16k.po deleted file mode 100644 index b60beb75e6..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5-16k.po +++ /dev/null @@ -1,96 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:5 -msgid "Vicuna v1.5-16k" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:7 -msgid "**Model Name:** vicuna-v1.5-16k" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:15 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:17 -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:19 -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:20 -msgid "**Model ID:** lmsys/vicuna-7b-v1.5-16k" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:22 -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:29 -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:46 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:32 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:35 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5-16k.rst:37 -msgid "**Model ID:** lmsys/vicuna-13b-v1.5-16k" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5.po deleted file mode 100644 index 8b2df625e8..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/vicuna-v1.5.po +++ /dev/null @@ -1,96 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/vicuna-v1.5.rst:5 -msgid "Vicuna v1.5" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:7 -msgid "**Model Name:** vicuna-v1.5" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:15 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:17 -#: ../../source/models/builtin/vicuna-v1.5.rst:34 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:19 -#: ../../source/models/builtin/vicuna-v1.5.rst:36 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:20 -msgid "**Model ID:** lmsys/vicuna-7b-v1.5" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:22 -#: ../../source/models/builtin/vicuna-v1.5.rst:39 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:29 -#: ../../source/models/builtin/vicuna-v1.5.rst:46 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:32 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:35 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/vicuna-v1.5.rst:37 -msgid "**Model ID:** lmsys/vicuna-13b-v1.5" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardcoder-python-v1.0.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardcoder-python-v1.0.po deleted file mode 100644 index 48d6ed4369..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardcoder-python-v1.0.po +++ /dev/null @@ -1,160 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:5 -msgid "WizardCoder-Python-v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:7 -msgid "**Context Length:** 100000" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:8 -msgid "**Model Name:** wizardcoder-python-v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:9 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:10 -msgid "**Abilities:** generate, chat" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:13 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:16 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:18 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:36 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:53 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:19 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:71 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:20 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:38 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:55 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:21 -msgid "**Model ID:** WizardLM/WizardCoder-Python-7B-V1.0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:23 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:41 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:58 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:75 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:89 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:103 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:30 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:48 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:65 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:34 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:37 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:84 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:39 -msgid "**Model ID:** WizardLM/WizardCoder-Python-13B-V1.0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:51 -msgid "Model Spec 3 (pytorch, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:54 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:98 -msgid "**Model Size (in billions):** 34" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:56 -msgid "**Model ID:** WizardLM/WizardCoder-Python-34B-V1.0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:68 -msgid "Model Spec 4 (ggufv2, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:70 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:83 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:97 -msgid "**Model Format:** ggufv2" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:72 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:85 -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:99 -msgid "" -"**Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, " -"Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:73 -msgid "**Model ID:** TheBloke/WizardCoder-Python-7B-V1.0-GGUF" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:81 -msgid "Model Spec 5 (ggufv2, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:86 -msgid "**Model ID:** TheBloke/WizardCoder-Python-13B-V1.0-GGUF" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:87 -msgid "**File Name Template:** wizardcoder-python-13b-v1.0.{quantization}.gguf" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:95 -msgid "Model Spec 6 (ggufv2, 34 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:100 -msgid "**Model ID:** TheBloke/WizardCoder-Python-34B-V1.0-GGUF" -msgstr "" - -#: ../../source/models/builtin/wizardcoder-python-v1.0.rst:101 -msgid "**File Name Template:** wizardcoder-python-34b-v1.0.{quantization}.gguf" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardlm-v1.0.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardlm-v1.0.po deleted file mode 100644 index 1f67c8ba0e..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardlm-v1.0.po +++ /dev/null @@ -1,93 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:5 -msgid "WizardLM v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:7 -msgid "**Model Name:** wizardlm-v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:15 -msgid "Model Spec 1 (ggmlv3, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:17 -#: ../../source/models/builtin/wizardlm-v1.0.rst:30 -msgid "**Model Format:** ggmlv3" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:19 -#: ../../source/models/builtin/wizardlm-v1.0.rst:32 -msgid "" -"**Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, " -"q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:20 -msgid "**Model ID:** TheBloke/WizardLM-7B-V1.0-Uncensored-GGML" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:22 -#: ../../source/models/builtin/wizardlm-v1.0.rst:35 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:28 -msgid "Model Spec 2 (ggmlv3, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:31 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/wizardlm-v1.0.rst:33 -msgid "**Model ID:** TheBloke/WizardLM-13B-V1.0-Uncensored-GGML" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardmath-v1.0.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardmath-v1.0.po deleted file mode 100644 index af7a6be974..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/wizardmath-v1.0.po +++ /dev/null @@ -1,112 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:5 -msgid "WizardMath v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:7 -msgid "**Model Name:** wizardmath-v1.0" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:8 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:9 -msgid "**Abilities:** embed, chat" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:12 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:15 -msgid "Model Spec 1 (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:17 -#: ../../source/models/builtin/wizardmath-v1.0.rst:34 -#: ../../source/models/builtin/wizardmath-v1.0.rst:51 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:18 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:19 -#: ../../source/models/builtin/wizardmath-v1.0.rst:36 -#: ../../source/models/builtin/wizardmath-v1.0.rst:53 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:20 -msgid "**Model ID:** WizardLM/WizardMath-7B-V1.0" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:22 -#: ../../source/models/builtin/wizardmath-v1.0.rst:39 -#: ../../source/models/builtin/wizardmath-v1.0.rst:56 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:29 -#: ../../source/models/builtin/wizardmath-v1.0.rst:46 -#: ../../source/models/builtin/wizardmath-v1.0.rst:63 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:32 -msgid "Model Spec 2 (pytorch, 13 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:35 -msgid "**Model Size (in billions):** 13" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:37 -msgid "**Model ID:** WizardLM/WizardMath-13B-V1.0" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:49 -msgid "Model Spec 3 (pytorch, 70 Billion)" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:52 -msgid "**Model Size (in billions):** 70" -msgstr "" - -#: ../../source/models/builtin/wizardmath-v1.0.rst:54 -msgid "**Model ID:** WizardLM/WizardMath-70B-V1.0" -msgstr "" - -#~ msgid "" -#~ "Execute the following command to launch" -#~ " the model, remember to replace " -#~ "`${quantization}` with your chosen " -#~ "quantization method from the options " -#~ "listed above::" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-alpha.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-alpha.po deleted file mode 100644 index 600835c685..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-alpha.po +++ /dev/null @@ -1,82 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:5 -msgid "Zephyr-7B-alpha" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:7 -msgid "**Context Length:** 8192" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:8 -msgid "**Model Name:** zephyr-7b-alpha" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:9 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:10 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:11 -msgid "" -"**Description:** Zephyr-7B-α is the first model in the series, and is a " -"fine-tuned version of mistralai/Mistral-7B-v0.1." -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:17 -msgid "Model Spec (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:19 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:21 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:22 -msgid "**Model ID:** HuggingFaceH4/zephyr-7b-alpha" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:24 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-alpha.rst:31 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-beta.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-beta.po deleted file mode 100644 index 8769041e78..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/builtin/zephyr-7b-beta.po +++ /dev/null @@ -1,86 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-11-01 10:48+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:5 -msgid "Zephyr-7B-beta" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:7 -msgid "**Context Length:** 8192" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:8 -msgid "**Model Name:** zephyr-7b-beta" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:9 -msgid "**Languages:** en" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:10 -msgid "**Abilities:** chat" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:11 -msgid "" -"**Description:** Zephyr-7B-β is the second model in the series, and is a " -"fine-tuned version of mistralai/Mistral-7B-v0.1." -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:14 -msgid "Specifications" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:17 -msgid "Model Spec (pytorch, 7 Billion)" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:19 -msgid "**Model Format:** pytorch" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:20 -msgid "**Model Size (in billions):** 7" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:21 -msgid "**Quantizations:** 4-bit, 8-bit, none" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:22 -msgid "**Model ID:** HuggingFaceH4/zephyr-7b-beta" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:23 -msgid "**Model Revision:** 3bac358730f8806e5c3dc7c7e19eb36e045bf720" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:25 -msgid "" -"Execute the following command to launch the model, remember to replace " -"``${quantization}`` with your chosen quantization method from the options" -" listed above::" -msgstr "" - -#: ../../source/models/builtin/zephyr-7b-beta.rst:32 -msgid "4-bit quantization is not supported on macOS." -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/custom.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/custom.po deleted file mode 100644 index ce9838b71b..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/custom.po +++ /dev/null @@ -1,291 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/models/custom.rst:5 -msgid "Custom Models" -msgstr "" - -#: ../../source/models/custom.rst:6 -msgid "" -"Xinference provides a flexible and comprehensive way to integrate, " -"manage, and utilize custom models." -msgstr "" - -#: ../../source/models/custom.rst:9 -msgid "Define a custom LLM model" -msgstr "" - -#: ../../source/models/custom.rst:11 -msgid "Define a custom LLM model based on the following template:" -msgstr "" - -#: ../../source/models/custom.rst:51 ../../source/models/custom.rst:179 -msgid "" -"model_name: A string defining the name of the model. The name must start " -"with a letter or a digit and can only contain letters, digits, " -"underscores, or dashes." -msgstr "" - -#: ../../source/models/custom.rst:52 -msgid "" -"context_length: context_length: An optional integer that specifies the " -"maximum context size the model was trained to accommodate, encompassing " -"both the input and output lengths. If not defined, the default value is " -"2048 tokens (~1,500 words)." -msgstr "" - -#: ../../source/models/custom.rst:53 -msgid "" -"model_lang: A list of strings representing the supported languages for " -"the model. Example: [\"en\"], which means that the model supports " -"English." -msgstr "" - -#: ../../source/models/custom.rst:54 -msgid "" -"model_ability: A list of strings defining the abilities of the model. It " -"could include options like \"embed\", \"generate\", and \"chat\". In this" -" case, the model has the ability to \"generate\"." -msgstr "" - -#: ../../source/models/custom.rst:60 -msgid "" -"model_specs: An array of objects defining the specifications of the " -"model. These include:" -msgstr "" - -#: ../../source/models/custom.rst:56 -msgid "" -"model_format: A string that defines the model format, could be " -"\"pytorch\" or \"ggmlv3\"." -msgstr "" - -#: ../../source/models/custom.rst:57 -msgid "" -"model_size_in_billions: An integer defining the size of the model in " -"billions of parameters." -msgstr "" - -#: ../../source/models/custom.rst:58 -msgid "" -"quantizations: A list of strings defining the available quantizations for" -" the model. For PyTorch models, it could be \"4-bit\", \"8-bit\", or " -"\"none\". For ggmlv3 models, the quantizations should correspond to " -"values that work with the ``model_file_name_template``." -msgstr "" - -#: ../../source/models/custom.rst:59 -msgid "" -"model_id: A string representing the model ID, possibly referring to an " -"identifier used by Hugging Face. **If model_uri is missing, Xinference " -"will try to download the model from the huggingface repository specified " -"here.**." -msgstr "" - -#: ../../source/models/custom.rst:60 -msgid "" -"model_uri: A string representing the URI where the model can be loaded " -"from, such as \"file:///path/to/llama-2-7b\". **When the model format is " -"ggmlv3 or ggufv2, model_uri must be the specific file path. When the " -"model format is pytorch, model_uri must be the path to the directory " -"containing the model files.** If model URI is absent, Xinference will try" -" to download the model from Hugging Face with the model ID." -msgstr "" - -#: ../../source/models/custom.rst:61 -msgid "" -"model_file_name_template: Required by ggml/gguf models. An f-string " -"template used for defining the model file name based on the quantization." -" **Note that this field is just a template for the format of the " -"ggmlv3/ggufv2 model file, do not fill in the specific path of the model " -"file.**" -msgstr "" - -#: ../../source/models/custom.rst:62 -msgid "" -"prompt_style: An optional field that could be required by chat models to " -"define the style of prompts. The given example has this set to None, but " -"additional details could be found in a referenced file " -"xinference/model/llm/tests/test_utils.py. You can also specify this field" -" as a string, which will use the builtin prompt style in Xinference. For " -"example:" -msgstr "" - -#: ../../source/models/custom.rst:71 -msgid "Xinference supports these builtin prompt styles in common usage:" -msgstr "" - -#: ../../source/models/custom.rst:75 -msgid "baichuan-chat" -msgstr "" - -#: ../../source/models/custom.rst:94 -msgid "chatglm3" -msgstr "" - -#: ../../source/models/custom.rst:107 -msgid "qwen-chat" -msgstr "" - -#: ../../source/models/custom.rst:124 -msgid "llama-2-chat" -msgstr "" - -#: ../../source/models/custom.rst:145 -msgid "vicuna-v1.5" -msgstr "" - -#: ../../source/models/custom.rst:160 -msgid "" -"The above lists some commonly used built-in prompt styles. The full list " -"of supported prompt styles can be found on the Xinference web UI." -msgstr "" - -#: ../../source/models/custom.rst:164 -msgid "Define a custom embedding model" -msgstr "" - -#: ../../source/models/custom.rst:166 -msgid "Define a custom embedding model based on the following template:" -msgstr "" - -#: ../../source/models/custom.rst:180 -msgid "dimensions: A integer that specifies the embedding dimensions." -msgstr "" - -#: ../../source/models/custom.rst:181 -msgid "" -"max_tokens: A integer that represents the max sequence length that the " -"embedding model supports." -msgstr "" - -#: ../../source/models/custom.rst:182 -msgid "" -"language: A list of strings representing the supported languages for the " -"model. Example: [\"en\"], which means that the model supports English." -msgstr "" - -#: ../../source/models/custom.rst:183 -msgid "" -"model_id: A string representing the model ID, possibly referring to an " -"identifier used by Hugging Face." -msgstr "" - -#: ../../source/models/custom.rst:184 -msgid "" -"model_uri: A string representing the URI where the model can be loaded " -"from, such as \"file:///path/to/your_model\". If model URI is absent, " -"Xinference will try to download the model from Hugging Face with the " -"model ID." -msgstr "" - -#: ../../source/models/custom.rst:187 -msgid "Register a Custom Model" -msgstr "" - -#: ../../source/models/custom.rst:189 -msgid "Register a custom model programmatically:" -msgstr "" - -#: ../../source/models/custom.rst:204 ../../source/models/custom.rst:222 -#: ../../source/models/custom.rst:237 ../../source/models/custom.rst:292 -msgid "Or via CLI:" -msgstr "" - -#: ../../source/models/custom.rst:210 -msgid "" -"Note that replace the ```` above with ``LLM`` or " -"``embedding``. The same as below." -msgstr "" - -#: ../../source/models/custom.rst:214 -msgid "List the Built-in and Custom Models" -msgstr "" - -#: ../../source/models/custom.rst:216 -msgid "List built-in and custom models programmatically:" -msgstr "" - -#: ../../source/models/custom.rst:229 -msgid "Launch the Custom Model" -msgstr "" - -#: ../../source/models/custom.rst:231 -msgid "Launch the custom model programmatically:" -msgstr "" - -#: ../../source/models/custom.rst:244 -msgid "Interact with the Custom Model" -msgstr "" - -#: ../../source/models/custom.rst:246 -msgid "Invoke the model programmatically:" -msgstr "" - -#: ../../source/models/custom.rst:253 -msgid "Result:" -msgstr "" - -#: ../../source/models/custom.rst:277 -msgid "Or via CLI, replace ``${UID}`` with real model UID:" -msgstr "" - -#: ../../source/models/custom.rst:284 -msgid "Unregister the Custom Model" -msgstr "" - -#: ../../source/models/custom.rst:286 -msgid "Unregister the custom model programmatically:" -msgstr "" - -#~ msgid "Define a custom model" -#~ msgstr "" - -#~ msgid "Define a custom model based on the following template:" -#~ msgstr "" - -#~ msgid "" -#~ "model_uri: A string representing the URI" -#~ " where the model can be loaded " -#~ "from, such as \"file:///path/to/llama-2-7b\". " -#~ "If model URI is absent, Xinference " -#~ "will try to download the model " -#~ "from Hugging Face with the model " -#~ "ID." -#~ msgstr "" - -#~ msgid "" -#~ "model_file_name_template: Required by ggml " -#~ "models. An f-string template used for" -#~ " defining the model file name based" -#~ " on the quantization." -#~ msgstr "" - -#~ msgid "" -#~ "prompt_style: An optional field that " -#~ "could be required by chat models " -#~ "to define the style of prompts. " -#~ "The given example has this set to" -#~ " None, but additional details could " -#~ "be found in a referenced file " -#~ "xinference/model/llm/tests/test_utils.py." -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/sources/sources.po b/doc/source/locale/ja_JP/LC_MESSAGES/models/sources/sources.po deleted file mode 100644 index f137613f8c..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/sources/sources.po +++ /dev/null @@ -1,71 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-02 16:27+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" - -#: ../../source/models/sources/sources.rst:5 -msgid "Download Sources" -msgstr "" - -#: ../../source/models/sources/sources.rst:7 -msgid "Xinference supports downloading various models from different sources." -msgstr "" - -#: ../../source/models/sources/sources.rst:10 -msgid "HuggingFace" -msgstr "" - -#: ../../source/models/sources/sources.rst:11 -msgid "" -"Xinference directly downloads the required models from the official " -"`Hugging Face model repository `_ by " -"default." -msgstr "" - -#: ../../source/models/sources/sources.rst:14 -msgid "" -"If you have trouble connecting to Huggingface, you can use a mirror " -"website to download with setting the environment variable " -"``HF_ENDPOINT=https://hf-mirror.com``." -msgstr "" - -#: ../../source/models/sources/sources.rst:18 -msgid "ModelScope" -msgstr "" - -#: ../../source/models/sources/sources.rst:20 -msgid "" -"When Xinference detects that the system's language is set to Simplified " -"Chinese, it will automatically set the model download source to " -"`ModelScope `_." -msgstr "" - -#: ../../source/models/sources/sources.rst:23 -msgid "" -"You can also achieve this by manually setting an environment variable " -"``XINFERENCE_MODEL_SRC=modelscope``." -msgstr "" - -#: ../../source/models/sources/sources.rst:25 -msgid "" -"Please check the detail page of a model to confirm whether the model " -"supports downloading from ModelScope. If a model spec supports " -"downloading from ModelScope, the \"Model Hubs\" section in the spec " -"information will include \"ModelScope\"." -msgstr "" diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/reference/index.po b/doc/source/locale/ja_JP/LC_MESSAGES/reference/index.po deleted file mode 100644 index ffc74b6399..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/reference/index.po +++ /dev/null @@ -1,321 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/reference/index.rst:5 -msgid "API Reference" -msgstr "" - -#: ../../source/reference/index.rst:9 -msgid "Client" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client `\\ " -"\\(base\\_url\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.describe_model " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Get model information via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.get_model " -"`\\ \\(model\\_uid\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Launch the model based on the parameters on the server via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.get_model_registration " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Get the model with the model type and model name registered on the server." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.launch_model " -"`\\ \\(model\\_name\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.list_model_registrations " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "List models registered on the server." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.list_models " -"`\\ \\(\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Retrieve the model specifications from the Server." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.register_model " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Register a custom model." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.terminate_model " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Terminate the specific model running on the server." -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "" -":py:obj:`xinference.client.Client.unregister_model " -"`\\ \\(...\\)" -msgstr "" - -#: ../../source/reference/index.rst:25::1 -msgid "Unregister a custom model." -msgstr "" - -#: ../../source/reference/index.rst:27 -msgid "Model Handles" -msgstr "" - -#: ../../source/reference/index.rst:31 -msgid "ChatglmCppChatModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulChatglmCppChatModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle.chat " -"`\\ " -"\\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -"Given a list of messages comprising a conversation, the ChatGLM model " -"will return a response via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle.create_embedding" -" " -"`\\" -" \\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -#: ../../source/reference/index.rst:52::1 -#: ../../source/reference/index.rst:62::1 -#: ../../source/reference/index.rst:73::1 -msgid "Create an Embedding from user input via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:42 -msgid "ChatModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulChatModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatModelHandle.chat " -"`\\ \\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -"Given a list of messages comprising a conversation, the model will return" -" a response via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatModelHandle.create_embedding " -"`\\ " -"\\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatModelHandle.generate " -"`\\ \\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:52::1 -#: ../../source/reference/index.rst:73::1 -msgid "" -"Creates a completion for the provided prompt and parameters via RESTful " -"APIs." -msgstr "" - -#: ../../source/reference/index.rst:54 -msgid "EmbeddingModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:62::1 -msgid "" -":py:obj:`xinference.client.handlers.EmbeddingModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:62::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulEmbeddingModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:62::1 -msgid "" -":py:obj:`xinference.client.handlers.EmbeddingModelHandle.create_embedding" -" `\\ " -"\\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:64 -msgid "GenerateModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:73::1 -msgid "" -":py:obj:`xinference.client.handlers.GenerateModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:73::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulGenerateModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:73::1 -msgid "" -":py:obj:`xinference.client.handlers.GenerateModelHandle.create_embedding " -"`\\ " -"\\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:73::1 -msgid "" -":py:obj:`xinference.client.handlers.GenerateModelHandle.generate " -"`\\ \\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:75 -msgid "ImageModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:81::1 -msgid "" -":py:obj:`xinference.client.handlers.ImageModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:81::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulImageModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:81::1 -msgid "" -":py:obj:`xinference.client.handlers.ImageModelHandle.text_to_image " -"`\\ " -"\\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:81::1 -msgid "Creates an image by the input text." -msgstr "" - -#~ msgid "" -#~ "alias of " -#~ ":py:class:`xinference.client.restful.restful_client.RESTfulChatglmCppChatModelHandle`" -#~ msgstr "" - -#~ msgid "" -#~ "alias of " -#~ ":py:class:`xinference.client.restful.restful_client.RESTfulChatModelHandle`" -#~ msgstr "" - -#~ msgid "" -#~ "alias of " -#~ ":py:class:`xinference.client.restful.restful_client.RESTfulEmbeddingModelHandle`" -#~ msgstr "" - -#~ msgid "" -#~ "alias of " -#~ ":py:class:`xinference.client.restful.restful_client.RESTfulGenerateModelHandle`" -#~ msgstr "" - -#~ msgid "" -#~ "alias of " -#~ ":py:class:`xinference.client.restful.restful_client.RESTfulImageModelHandle`" -#~ msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/backends.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/backends.po deleted file mode 100644 index a6d96528d8..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/backends.po +++ /dev/null @@ -1,158 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-02 17:07+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/backends.rst:5 -msgid "Backends" -msgstr "" - -#: ../../source/user_guide/backends.rst:7 -msgid "" -"Xinference supports multiple backends for different models. After the " -"user specifies the model, xinference will automatically select the " -"appropriate backend." -msgstr "" - -#: ../../source/user_guide/backends.rst:11 -msgid "llama-cpp-python" -msgstr "" - -#: ../../source/user_guide/backends.rst:12 -msgid "" -"`llama-cpp-python `_ is the " -"python binding of `llama.cpp`. `llama-cpp` is developed based on the " -"tensor library `ggml`, supporting inference of the LLaMA series models " -"and their variants." -msgstr "" - -#: ../../source/user_guide/backends.rst:16 -msgid "" -"We recommend that users install `llama-cpp-python` on the worker " -"themselves and adjust the `cmake` parameters according to the hardware to" -" achieve the best inference efficiency. Please refer to the `llama-cpp-" -"python installation guide `_." -msgstr "" - -#: ../../source/user_guide/backends.rst:21 -msgid "ctransformers" -msgstr "" - -#: ../../source/user_guide/backends.rst:22 -msgid "" -"CTransformers provide python bindings for the Transformer models " -"implemented in C/C++ using GGML library." -msgstr "" - -#: ../../source/user_guide/backends.rst:24 -msgid "" -"We recommend that users install `ctransformers` on the worker themselves " -"and adjust the parameters according to the hardware to achieve the best " -"inference efficiency. Please refer to the `ctransformers installation " -"guide `_." -msgstr "" - -#: ../../source/user_guide/backends.rst:30 -msgid "transformers" -msgstr "" - -#: ../../source/user_guide/backends.rst:31 -msgid "" -"Transformers supports the inference of most state-of-art models. It is " -"the default backend for models in PyTorch format." -msgstr "" - -#: ../../source/user_guide/backends.rst:34 -msgid "vLLM" -msgstr "" - -#: ../../source/user_guide/backends.rst:35 -msgid "vLLM is a fast and easy-to-use library for LLM inference and serving." -msgstr "" - -#: ../../source/user_guide/backends.rst:37 -msgid "" -"vLLM is fast with: - State-of-the-art serving throughput - Efficient " -"management of attention key and value memory with PagedAttention - " -"Continuous batching of incoming requests - Optimized CUDA kernels" -msgstr "" - -#: ../../source/user_guide/backends.rst:43 -msgid "" -"When the following conditions are met, Xinference will choose vLLM as the" -" inference engine:" -msgstr "" - -#: ../../source/user_guide/backends.rst:45 -msgid "The model format is PyTorch" -msgstr "" - -#: ../../source/user_guide/backends.rst:46 -msgid "The quantization method is none" -msgstr "" - -#: ../../source/user_guide/backends.rst:47 -msgid "The system is Linux and has at least one CUDA device" -msgstr "" - -#: ../../source/user_guide/backends.rst:48 -msgid "The model is within the list of models supported by vLLM." -msgstr "" - -#: ../../source/user_guide/backends.rst:50 -msgid "Currently, supported model includes:" -msgstr "" - -#: ../../source/user_guide/backends.rst:52 -msgid "``llama-2``, ``llama-2-chat``" -msgstr "" - -#: ../../source/user_guide/backends.rst:53 -msgid "``baichuan``, ``baichuan-chat``" -msgstr "" - -#: ../../source/user_guide/backends.rst:54 -msgid "``internlm``, ``internlm-20b``, ``internlm-chat``, ``internlm-chat-20b``" -msgstr "" - -#: ../../source/user_guide/backends.rst:55 -msgid "``vicuna-v1.3``, ``vicuna-v1.5``" -msgstr "" - -#: ../../source/user_guide/backends.rst:56 -msgid "``Yi``, ``Yi-chat``" -msgstr "" - -#: ../../source/user_guide/backends.rst:57 -msgid "``qwen-chat``" -msgstr "" - -#: ../../source/user_guide/backends.rst:58 -msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" -msgstr "" - -#: ../../source/user_guide/backends.rst:59 -msgid "``mistral-instruct-v0.1``" -msgstr "" - -#: ../../source/user_guide/backends.rst:60 -msgid "``chatglm3``" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/cache_management.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/cache_management.po deleted file mode 100644 index d2f356a026..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/cache_management.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/cache_management.rst:5 -msgid "Cache Management" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/client_api.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/client_api.po deleted file mode 100644 index 2fb64db257..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/client_api.po +++ /dev/null @@ -1,98 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/client_api.rst:5 -msgid "Client API" -msgstr "" - -#: ../../source/user_guide/client_api.rst:7 -msgid "Complete Client API Reference: :ref:`reference_index`" -msgstr "" - -#: ../../source/user_guide/client_api.rst:9 -msgid "" -"To utilize the Client API, initiate the xinference server using the " -"command below:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:18 -msgid "" -"Based on the log above, the endpoint is `http://127.0.0.1:9997`. Users " -"can connect to the xinference server through this endpoint using the " -"Client." -msgstr "" - -#: ../../source/user_guide/client_api.rst:20 -msgid "" -"Models are categorized into LLM, embedding, image, etc. We plan to " -"introduce more model types in the future." -msgstr "" - -#: ../../source/user_guide/client_api.rst:23 -msgid "LLM" -msgstr "" - -#: ../../source/user_guide/client_api.rst:25 -msgid "To list the available built-in LLM models:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:38 -msgid "To initialize an LLM and chat:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:63 -msgid "Embedding" -msgstr "" - -#: ../../source/user_guide/client_api.rst:65 -msgid "To list the available built-in embedding models:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:78 -msgid "To launch an embedding model and embed text:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:92 -#: ../../source/user_guide/client_api.rst:138 -#: ../../source/user_guide/client_api.rst:168 -msgid "Output:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:110 -msgid "Image" -msgstr "" - -#: ../../source/user_guide/client_api.rst:112 -msgid "To list the available built-in image models:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:123 -msgid "To initiate an image model and generate an image using a text prompt:" -msgstr "" - -#: ../../source/user_guide/client_api.rst:147 -msgid "Rerank" -msgstr "" - -#: ../../source/user_guide/client_api.rst:148 -msgid "To launch a rerank model and compute the similarity scores:" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/AI_Podcast.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/AI_Podcast.po deleted file mode 100644 index dc8984eb51..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/AI_Podcast.po +++ /dev/null @@ -1,168 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-07 11:39+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/examples/AI_Podcast.rst:3 -msgid "Example: AI Podcast 🎙" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:5 -msgid "**Description**:" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:7 -msgid "🎙️AI Podcast - Voice Conversations with Multiple Agents on M2 Max 💻" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:9 -msgid "**Support Language** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:11 -msgid "English (AI_Podcast.py)" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:13 -msgid "Chinese (AI_Podcast_ZH.py)" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:15 -msgid "**Used Technology (EN version)** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:17 -msgid "" -"@ `OpenAI `_ 's `whisper " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:19 -msgid "" -"@ `ggerganov `_ 's `ggml " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:21 -msgid "" -"@ `WizardLM_AI `_ 's `wizardlm v1.0 " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:23 -msgid "" -"@ `lmsysorg `_ 's `vicuna v1.3 " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:25 -msgid "@ `Xinference `_ as a launcher" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:27 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:29 -msgid "" -"Generate the Wizardlm Model and Vicuna Model when the program is " -"launching with Xorbits Inference. Initiate the Chatroom by giving the two" -" chatbot their names and telling them that there is a human user called " -"\"username\", where \"username\" is given by user's input. Initialize a " -"empty chat history for the chatroom." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:33 -msgid "" -"Use Audio device to store recording into file, and transcribe the file " -"using OpenAI's Whisper to receive a human readable text as string." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:35 -msgid "" -"Based on the input message string, determine which agents the user want " -"to talk to. Call the target agents and parse in the input string and chat" -" history for the model to generate." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:38 -msgid "" -"When the responses are ready, use Macos's \"Say\" Command to produce " -"audio through speaker. Each agents have their own voice while speaking." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:41 -msgid "" -"Store the user input and the agent response into chat history, and " -"recursively looping the program until user explicitly says words like " -"\"see you\" in their responses." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:44 -msgid "**Highlight Features with Xinference** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:46 -msgid "" -"With Xinference's distributed system, we can easily deploy two different " -"models in the same session and in the same \"chatroom\". With enough " -"resources, the framework can deploy any amount of models you like at the " -"same time." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:49 -msgid "" -"With Xinference, you can deploy the model easily by just adding a few " -"lines of code. For examples, for launching the vicuna model in the demo, " -"just by::" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:66 -msgid "" -"Then, the Xinference clinet will handle \"target model downloading and " -"caching\", \"set up environment and process for the model\", and \"run " -"the service at selected endpoint. \" You are now ready to play with your " -"llm model." -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:69 -msgid "**Original Demo Video** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:71 -msgid "" -"`🎙️AI Podcast - Voice Conversations with Multiple Agents on M2 Max💻🔥🤖 " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:73 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:75 -msgid "" -"`AI_Podcast " -"`_" -" (English Version)" -msgstr "" - -#: ../../source/user_guide/examples/AI_Podcast.rst:77 -msgid "AI_Podcast_ZH (Chinese Version)" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/chat.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/chat.po deleted file mode 100644 index a2d6b4784e..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/examples/chat.po +++ /dev/null @@ -1,98 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-07 11:39+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/examples/chat.rst:3 -msgid "Example: chatbot 🤖️" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:5 -msgid "**Description**:" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:7 -msgid "" -"Demonstrate how to interact with Xinference to play with LLM chat " -"functionality with an AI agent 💻" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:9 -msgid "**Used Technology**:" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:11 -msgid "" -"@ `ggerganov `_ 's `ggml " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:13 -msgid "@ `Xinference `_ as a launcher" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:15 -msgid "" -"@ All LLaMA and Chatglm models supported by `Xorbitsio inference " -"`_" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:17 -msgid "**Detailed Explanation on the Demo Functionality** :" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:19 -msgid "" -"Take the user command line input in the terminal and grab the required " -"parameters for model lanuching." -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:21 -msgid "" -"Launch the Xinference frameworks and automatically deploy the model user " -"demanded into the cluster." -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:23 -msgid "Initialize an empty chat history to store all the context in the chatroom." -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:25 -msgid "" -"Recursively ask for user's input as prompt and let the model to generate " -"response based on the prompt and the chat history. Show the Output of the" -" response in the terminal." -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:28 -msgid "" -"Store the user's input and agent's response into the chat history as " -"context for the upcoming rounds." -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:30 -msgid "**Source Code** :" -msgstr "" - -#: ../../source/user_guide/examples/chat.rst:31 -msgid "" -"`chat " -"`_" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/faq.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/faq.po deleted file mode 100644 index 88e233e6ca..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/faq.po +++ /dev/null @@ -1,25 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-07 11:39+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/faq.rst:3 -msgid "FAQ 📚" -msgstr "" - diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/index.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/index.po deleted file mode 100644 index e3fb00f47e..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/index.po +++ /dev/null @@ -1,24 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/index.rst:5 -msgid "User Guide" -msgstr "" diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/spec_decoding.po b/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/spec_decoding.po deleted file mode 100644 index f83e68f599..0000000000 --- a/doc/source/locale/ja_JP/LC_MESSAGES/user_guide/spec_decoding.po +++ /dev/null @@ -1,117 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-02 18:00+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/spec_decoding.rst:5 -msgid "Speculative Decoding (experimental)" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:9 -msgid "" -"Speculative decoding is a method designed to speed up the inference " -"process of large language models (LLMs). This technique involves using a " -"smaller, quicker \"draft\" model to produce several tokens in advance. " -"These tokens are then checked by a more extensive \"target\" model. If " -"the larger model confirms the tokens generated by the draft model, it " -"leads to significant savings in memory bandwidth and processing time per " -"token. However, if the tokens from the draft model don't match the " -"predictions of the larger model, they are discarded." -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:15 -msgid "Launching a speculative LLM" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:16 -msgid "" -"Using speculative decoding in Xinference is straightforward. The only " -"distinction between speculative decoding and regular decoding is the way " -"to initiate an LLM:" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:35 -msgid "" -"``Client.launch_speculative_llm`` is an experimental API, which may be " -"removed in the future releases." -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:37 -msgid "After launching the model, you can use it just like a regular model:" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:52 -msgid "Performance" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:53 -msgid "The effectiveness of speculative decoding relies on:" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:55 -msgid "The size difference between the models - the larger, the better." -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:56 -msgid "" -"The similarity between the logits produced by the draft model and the " -"target model." -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:58 -#, python-format -msgid "" -"In the example above, the target model is about five times larger than " -"the draft model, and the two models are well aligned. Approximately 86% " -"of the draft tokens are accepted by the target model, resulting in a 25% " -"increase in speed." -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:61 -msgid "References" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:62 -msgid "" -"[1] `Fast Inference from Transformers via Speculative Decoding " -"`_" -msgstr "" - -#: ../../source/user_guide/spec_decoding.rst:63 -msgid "" -"[2] `Accelerating Large Language Model Decoding with Speculative Sampling" -" `_" -msgstr "" - -#~ msgid "" -#~ "In the example above, the target " -#~ "model is about five times larger " -#~ "than the draft model, and the two" -#~ " models are well aligned. Approximately " -#~ "86% of the draft tokens are " -#~ "accepted by the target model, resulting" -#~ " in a 25% increase in speed. " -#~ "References ~~~~~~~~~~ - [1] `Fast " -#~ "Inference from Transformers via Speculative" -#~ " Decoding `_ - " -#~ "[2] `Accelerating Large Language Model " -#~ "Decoding with Speculative Sampling " -#~ "`_" -#~ msgstr "" - diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/development/xinference_internals.po b/doc/source/locale/zh_CN/LC_MESSAGES/development/xinference_internals.po index 186aeba521..9969ec843a 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/development/xinference_internals.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/development/xinference_internals.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-23 22:22+0800\n" +"POT-Creation-Date: 2024-05-31 11:46+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -165,7 +165,7 @@ msgstr "Python 项目会在 `setup.cfg` 或 `setup.py` 中定义命令行控制 #: ../../source/development/xinference_internals.rst:72 msgid "" -"The command-line ``xinference`` can be refered to code in " +"The command-line ``xinference`` can be referred to code in " "``xinference.deploy.cmdline:cli``." msgstr "命令行 ``xinference`` 可参考 ``xinference.deploy.cmdline:cli`` 中的代码。" @@ -243,9 +243,9 @@ msgstr "" "**引用 Actor 和调用方法**:当创建一个 Actor 时,它会产生一个引用变量," "以便其他 Actor 可以引用它。Actor 也可以用 IP 地址来引用。假设创建了 ``" "WorkerActor``,且引用变量为 ``worker_ref``,那么就可以通过调用 ``worker_" -"ref.launch_model()`` 来调用该 Actor 类的 ``launch_model``。" -"即使 actor 中的方法原来是一个传统的阻塞式的方法,当我们使用引用变量调用这个方法时," -"它也变成了一个异步方法。" +"ref.launch_model()`` 来调用该 Actor 类的 ``launch_model``。即使 actor 中" +"的方法原来是一个传统的阻塞式的方法,当我们使用引用变量调用这个方法时,它" +"也变成了一个异步方法。" #: ../../source/development/xinference_internals.rst:143 msgid "" @@ -279,9 +279,10 @@ msgid "" "in the background and results are returned in the future. This enables us" " to perform activities concurrently." msgstr "" -"Xinference 和 Xoscar 非常依赖异步编程库 ``asyncio``。异步编程是一种非阻塞的编程范式。" -"相比于传统的阻塞式的函数调用,异步编程中的请求或函数调用在后台执行,运行结果在未来某个时刻返回。" -"异步编程的优势是使得可以同时并发进行很多不同的活动或任务。" +"Xinference 和 Xoscar 非常依赖异步编程库 ``asyncio``。异步编程是一种非阻塞" +"的编程范式。相比于传统的阻塞式的函数调用,异步编程中的请求或函数调用在" +"后台执行,运行结果在未来某个时刻返回。异步编程的优势是使得可以同时并发" +"进行很多不同的活动或任务。" #: ../../source/development/xinference_internals.rst:159 msgid "" @@ -291,12 +292,16 @@ msgstr "如果您不熟悉 Python 的 ``asyncio``,可以查看更多教程以 #: ../../source/development/xinference_internals.rst:161 msgid "" -"`Python Asyncio Tutorial `__" -msgstr "`Python Asyncio 教程 `__" +"`Python Asyncio Tutorial `__" +msgstr "" +"`Python Asyncio 教程 `__" #: ../../source/development/xinference_internals.rst:163 msgid "" -"`Real Python's asyncio Tutorial `__" +"`Real Python's asyncio Tutorial `__" msgstr "`Real Python asyncio 教程 `__" #: ../../source/development/xinference_internals.rst:165 @@ -333,8 +338,8 @@ msgid "" " LLMs." msgstr "" "以 `model/llm/ `_ 为例,它主要管理和启动 LLM,包括加载、配置" -"和运行大语言模型。" +"xinference/model/llm>`_ 为例,它主要管理和启动 LLM,包括加载、配置和运行" +"大语言模型。" #: ../../source/development/xinference_internals.rst:181 msgid "" @@ -732,4 +737,3 @@ msgstr "" #~ "Both Xinference and Xoscar highly " #~ "utilize coroutine programming of ``asyncio``." #~ msgstr "Xinference 和 Xoscar 都高度利用了 ``asyncio`` 进行协程编程。" - diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/environments.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/environments.po index a912a8a7b7..e8a2a368b6 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/environments.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/environments.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-11 13:33+0800\n" +"POT-Creation-Date: 2024-07-28 22:01+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -96,18 +96,21 @@ msgid "" "Xinference will automatically report health check at Xinference startup. " "Setting this environment to 1 can disable health check." msgstr "" -"在满足条件时,Xinference 会自动汇报worker健康状况,设置改" -"环境变量为 1可以禁用健康检查。" +"在满足条件时,Xinference 会自动汇报worker健康状况,设置改环境变量为 1可以" +"禁用健康检查。" #: ../../source/getting_started/environments.rst:40 -msgid "XINFERENCE_DISABLE_VLLM" +#, fuzzy +msgid "XINFERENCE_DISABLE_METRICS" msgstr "XINFERENCE_DISABLE_VLLM" #: ../../source/getting_started/environments.rst:41 msgid "" -"Xinference will automatically use vLLM as backend if conditions are met. " -"Setting this environment to 1 can disable the use of vLLM." +"Xinference will by default enable the metrics exporter on the supervisor " +"and worker. Setting this environment to 1 will disable the /metrics " +"endpoint on the supervisor and the HTTP service (only provide the " +"/metrics endpoint) on the worker." msgstr "" -"在满足条件时,Xinference 会自动使用 vLLM 作为推理引擎提供推理效率,设置改" -"环境变量为 1可以禁用 vLLM。" - +"Xinference 会默认在 supervisor 和 worker 上启用 metrics exporter。设置" +"环境变量为 1可以在 supervisor 上禁用 /metrics 端点,并在 worker 上禁用 " +"HTTP 服务(仅提供 /metrics 端点)" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation.po index ffd572cdc5..c04979d7ff 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-02 15:27+0800\n" +"POT-Creation-Date: 2024-08-15 11:43+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -16,7 +16,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.14.0\n" +"Generated-By: Babel 2.11.0\n" #: ../../source/getting_started/installation.rst:5 msgid "Installation" @@ -39,13 +39,13 @@ msgstr "如果你希望能够推理所有支持的模型,可以用以下命令 #: ../../source/getting_started/installation.rst:13 msgid "" -"If you want to serve models in GGML format, it's advised to install the " -"GGML dependencies manually based on your hardware specifications to " -"enable acceleration. For more details, see the :ref:`installation_ggml` " -"section." +"If you want to serve models in GGUF format, it's advised to install the " +"``llama-cpp-python`` dependency manually based on your hardware " +"specifications to enable acceleration. For more details, see the " +":ref:`installation_gguf` section." msgstr "" -"如果你想使用 GGML 格式的模型,建议根据当前使用的硬件手动安装所需要的依赖" -",以充分利用硬件的加速能力。更多细节可以参考 :ref:`installation_ggml` " +"如果你想使用 GGUF 格式的模型,建议根据当前使用的硬件手动安装所需要的依赖" +",以充分利用硬件的加速能力。更多细节可以参考 :ref:`installation_gguf` " "这一章节。" #: ../../source/getting_started/installation.rst:16 @@ -54,11 +54,11 @@ msgid "" " how to do it." msgstr "如果你只想安装必要的依赖,接下来是如何操作的详细步骤。" -#: ../../source/getting_started/installation.rst:19 +#: ../../source/getting_started/installation.rst:21 msgid "Transformers Backend" msgstr "Transformers 引擎" -#: ../../source/getting_started/installation.rst:20 +#: ../../source/getting_started/installation.rst:22 msgid "" "PyTorch (transformers) supports the inference of most state-of-art " "models. It is the default backend for models in PyTorch format::" @@ -66,11 +66,11 @@ msgstr "" "PyTorch(transformers) 引擎支持几乎有所的最新模型,这是 Pytorch 模型默认" "使用的引擎:" -#: ../../source/getting_started/installation.rst:26 +#: ../../source/getting_started/installation.rst:28 msgid "vLLM Backend" msgstr "vLLM 引擎" -#: ../../source/getting_started/installation.rst:27 +#: ../../source/getting_started/installation.rst:29 msgid "" "vLLM is a fast and easy-to-use library for LLM inference and serving. " "Xinference will choose vLLM as the backend to achieve better throughput " @@ -79,133 +79,206 @@ msgstr "" "vLLM 是一个支持高并发的高性能大模型推理引擎。当满足以下条件时,Xinference" " 会自动选择 vllm 作为引擎来达到更高的吞吐量:" -#: ../../source/getting_started/installation.rst:29 +#: ../../source/getting_started/installation.rst:31 msgid "The model format is ``pytorch``, ``gptq`` or ``awq``." msgstr "模型格式为 ``pytorch`` , ``gptq`` 或者 ``awq`` 。" -#: ../../source/getting_started/installation.rst:30 +#: ../../source/getting_started/installation.rst:32 msgid "When the model format is ``pytorch``, the quantization is ``none``." msgstr "当模型格式为 ``pytorch`` 时,量化选项需为 ``none`` 。" -#: ../../source/getting_started/installation.rst:31 +#: ../../source/getting_started/installation.rst:33 +msgid "When the model format is ``awq``, the quantization is ``Int4``." +msgstr "当模型格式为 ``awq`` 时,量化选项需为 ``Int4`` 。" + +#: ../../source/getting_started/installation.rst:34 msgid "" -"When the model format is ``gptq`` or ``awq``, the quantization is " -"``Int4``." -msgstr "当模型格式为 ``gptq`` 或 ``awq`` 时,量化选项需为 ``Int4`` 。" +"When the model format is ``gptq``, the quantization is ``Int3``, ``Int4``" +" or ``Int8``." +msgstr "" +"当模型格式为 ``gptq`` 时,量化选项需为 ``Int3`` 、 ``Int4`` 或者 ``Int8``" +" 。" -#: ../../source/getting_started/installation.rst:32 +#: ../../source/getting_started/installation.rst:35 msgid "The system is Linux and has at least one CUDA device" msgstr "操作系统为 Linux 并且至少有一个支持 CUDA 的设备" -#: ../../source/getting_started/installation.rst:33 +#: ../../source/getting_started/installation.rst:36 msgid "" "The model family (for custom models) / model name (for builtin models) is" " within the list of models supported by vLLM" -msgstr "自定义模型的 ``model_family`` 字段和内置模型的 ``model_name`` 字段在 vLLM" +msgstr "" +"自定义模型的 ``model_family`` 字段和内置模型的 ``model_name`` 字段在 vLLM" " 的支持列表中。" -#: ../../source/getting_started/installation.rst:35 +#: ../../source/getting_started/installation.rst:38 msgid "Currently, supported models include:" msgstr "目前,支持的模型包括:" -#: ../../source/getting_started/installation.rst:39 -msgid "``llama-2``, ``llama-2-chat``" -msgstr "``llama-2``, ``llama-2-chat``" +#: ../../source/getting_started/installation.rst:42 +msgid "" +"``llama-2``, ``llama-3``, ``llama-3.1``, ``llama-2-chat``, " +"``llama-3-instruct``, ``llama-3.1-instruct``" +msgstr "" -#: ../../source/getting_started/installation.rst:40 +#: ../../source/getting_started/installation.rst:43 msgid "``baichuan``, ``baichuan-chat``, ``baichuan-2-chat``" -msgstr "``baichuan``, ``baichuan-chat``, ``baichuan-2-chat``" +msgstr "" -#: ../../source/getting_started/installation.rst:41 +#: ../../source/getting_started/installation.rst:44 msgid "" "``internlm-16k``, ``internlm-chat-7b``, ``internlm-chat-8k``, ``internlm-" "chat-20b``" -msgstr "``internlm-16k``, ``internlm-chat-7b``, ``internlm-chat-8k``, ``internlm-" -"chat-20b``" - -#: ../../source/getting_started/installation.rst:42 -msgid "``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``" msgstr "" -#: ../../source/getting_started/installation.rst:43 -msgid "``Yi``, ``Yi-chat``" -msgstr "``Yi``, ``Yi-chat``" - -#: ../../source/getting_started/installation.rst:44 -msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" -msgstr "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" - #: ../../source/getting_started/installation.rst:45 -msgid "``vicuna-v1.3``, ``vicuna-v1.5``" -msgstr "``vicuna-v1.3``, ``vicuna-v1.5``" +msgid "" +"``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``, " +"``mistral-instruct-v0.3``, ``mistral-nemo-instruct``, ``mistral-large-" +"instruct``" +msgstr "" #: ../../source/getting_started/installation.rst:46 -msgid "``qwen-chat``" -msgstr "``qwen-chat``" +msgid "``codestral-v0.1``" +msgstr "" #: ../../source/getting_started/installation.rst:47 -msgid "``mixtral-instruct-v0.1``" -msgstr "``mistral-instruct-v0.1``" +msgid "``Yi``, ``Yi-1.5``, ``Yi-chat``, ``Yi-1.5-chat``, ``Yi-1.5-chat-16k``" +msgstr "" #: ../../source/getting_started/installation.rst:48 -msgid "``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k``" +msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" msgstr "" #: ../../source/getting_started/installation.rst:49 -msgid "``deepseek-chat``, ``deepseek-coder-instruct``" +msgid "" +"``deepseek``, ``deepseek-coder``, ``deepseek-chat``, ``deepseek-coder-" +"instruct``" msgstr "" #: ../../source/getting_started/installation.rst:50 -msgid "``qwen1.5-chat``" -msgstr "``qwen1.5-chat``" +msgid "``codeqwen1.5``, ``codeqwen1.5-chat``" +msgstr "" #: ../../source/getting_started/installation.rst:51 -msgid "``gemma-it``" +msgid "``vicuna-v1.3``, ``vicuna-v1.5``" msgstr "" #: ../../source/getting_started/installation.rst:52 -msgid "``orion-chat``, ``orion-chat-rag``" +msgid "``internlm2-chat``" +msgstr "" + +#: ../../source/getting_started/installation.rst:53 +msgid "``internlm2.5-chat``, ``internlm2.5-chat-1m``" +msgstr "" + +#: ../../source/getting_started/installation.rst:54 +msgid "``qwen-chat``" msgstr "" #: ../../source/getting_started/installation.rst:55 -msgid "To install Xinference and vLLM::" -msgstr "安装 xinference 和 vLLM:" +msgid "``mixtral-instruct-v0.1``, ``mixtral-8x22B-instruct-v0.1``" +msgstr "" + +#: ../../source/getting_started/installation.rst:56 +msgid "``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k``" +msgstr "" + +#: ../../source/getting_started/installation.rst:57 +msgid "``glm4-chat``, ``glm4-chat-1m``" +msgstr "" + +#: ../../source/getting_started/installation.rst:58 +msgid "``codegeex4``" +msgstr "" + +#: ../../source/getting_started/installation.rst:59 +msgid "``qwen1.5-chat``, ``qwen1.5-moe-chat``" +msgstr "" + +#: ../../source/getting_started/installation.rst:60 +msgid "``qwen2-instruct``, ``qwen2-moe-instruct``" +msgstr "" + +#: ../../source/getting_started/installation.rst:61 +msgid "``gemma-it``, ``gemma-2-it``" +msgstr "" #: ../../source/getting_started/installation.rst:62 -msgid "GGML Backend" -msgstr "GGML 引擎" +msgid "``orion-chat``, ``orion-chat-rag``" +msgstr "" #: ../../source/getting_started/installation.rst:63 +msgid "``c4ai-command-r-v01``" +msgstr "" + +#: ../../source/getting_started/installation.rst:66 +msgid "To install Xinference and vLLM::" +msgstr "安装 xinference 和 vLLM:" + +#: ../../source/getting_started/installation.rst:79 +msgid "Llama.cpp Backend" +msgstr "Llama.cpp 引擎" + +#: ../../source/getting_started/installation.rst:80 msgid "" -"It's advised to install the GGML dependencies manually based on your " -"hardware specifications to enable acceleration." +"Xinference supports models in ``gguf`` format via ``llama-cpp-python``. " +"It's advised to install the llama.cpp-related dependencies manually based" +" on your hardware specifications to enable acceleration." msgstr "" -"当使用 GGML 引擎时,建议根据当前使用的硬件手动安装依赖,从而获得最佳的" -"加速效果。" +"Xinference 通过 ``llama-cpp-python`` 支持 ``gguf`` 格式的模型" +"。建议根据当前使用的硬件手动安装依赖,从而获得最佳的加速效果。" -#: ../../source/getting_started/installation.rst:65 +#: ../../source/getting_started/installation.rst:82 +#: ../../source/getting_started/installation.rst:105 +#: ../../source/getting_started/installation.rst:118 msgid "Initial setup::" msgstr "初始步骤:" -#: ../../source/getting_started/installation.rst:70 +#: ../../source/getting_started/installation.rst:86 msgid "Hardware-Specific installations:" msgstr "不同硬件的安装方式:" -#: ../../source/getting_started/installation.rst:72 +#: ../../source/getting_started/installation.rst:88 msgid "Apple Silicon::" msgstr "Apple M系列" -#: ../../source/getting_started/installation.rst:76 +#: ../../source/getting_started/installation.rst:92 msgid "Nvidia cards::" msgstr "英伟达显卡:" -#: ../../source/getting_started/installation.rst:80 +#: ../../source/getting_started/installation.rst:96 msgid "AMD cards::" msgstr "AMD 显卡:" -#~ msgid "The quantization method is GPTQ 4 bit or none" -#~ msgstr "量化方式必须是 GPTQ 4 bit 或者 none" +#: ../../source/getting_started/installation.rst:102 +msgid "SGLang Backend" +msgstr "SGLang 引擎" + +#: ../../source/getting_started/installation.rst:103 +msgid "" +"SGLang has a high-performance inference runtime with RadixAttention. It " +"significantly accelerates the execution of complex LLM programs by " +"automatic KV cache reuse across multiple calls. And it also supports " +"other common techniques like continuous batching and tensor parallelism." +msgstr "" +"SGLang 具有基于 RadixAttention 的高性能推理运行时。它通过在多个调用之间" +"自动重用KV缓存,显著加速了复杂 LLM 程序的执行。它还支持其他常见推理技术," +"如连续批处理和张量并行处理。" -#~ msgid "``chatglm3``" -#~ msgstr "``chatglm3``" +#: ../../source/getting_started/installation.rst:115 +msgid "MLX Backend" +msgstr "MLX 引擎" + +#: ../../source/getting_started/installation.rst:116 +msgid "MLX-lm is designed for Apple silicon users to run LLM efficiently." +msgstr "MLX-lm 用来在苹果 silicon 芯片上提供高效的 LLM 推理。" + +#: ../../source/getting_started/installation.rst:123 +msgid "Other Platforms" +msgstr "其他平台" + +#: ../../source/getting_started/installation.rst:125 +msgid ":ref:`Ascend NPU `" +msgstr "" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation_npu.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation_npu.po new file mode 100644 index 0000000000..85657a774b --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/installation_npu.po @@ -0,0 +1,79 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-30 17:00+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/getting_started/installation_npu.rst:6 +msgid "Installation Guide for Ascend NPU" +msgstr "在昇腾 NPU 上安装" + +#: ../../source/getting_started/installation_npu.rst:7 +msgid "Xinference can run on Ascend NPU, follow below instructions to install." +msgstr "Xinference 能在昇腾 NPU 上运行,使用如下命令安装。" + +#: ../../source/getting_started/installation_npu.rst:11 +msgid "Installing PyTorch and Ascend extension for PyTorch" +msgstr "安装 PyTorch 和昇腾扩展" + +#: ../../source/getting_started/installation_npu.rst:12 +msgid "Install PyTorch CPU version and corresponding Ascend extension." +msgstr "安装 PyTorch CPU 版本和相应的昇腾扩展。" + +#: ../../source/getting_started/installation_npu.rst:14 +msgid "Take PyTorch v2.1.0 as example." +msgstr "以 PyTorch v2.1.0 为例。" + +#: ../../source/getting_started/installation_npu.rst:20 +msgid "" +"Then install `Ascend extension for PyTorch " +"`_." +msgstr "" +"接着安装 `昇腾 PyTorch 扩展 " +"`_." + +#: ../../source/getting_started/installation_npu.rst:28 +msgid "Running below command to see if it correctly prints the Ascend NPU count." +msgstr "运行如下命令查看,如果正常运行,会打印昇腾 NPU 的个数。" + +#: ../../source/getting_started/installation_npu.rst:35 +msgid "Installing Xinference" +msgstr "安装 Xinference" + +#: ../../source/getting_started/installation_npu.rst:41 +msgid "" +"Now you can use xinference according to :ref:`doc `. " +"``Transformers`` backend is the only available engine supported for " +"Ascend NPU for open source version." +msgstr "" +"现在你可以参考 :ref:`文档 ` 来使用 Xinference。" +"``Transformers`` 是开源唯一支持的昇腾 NPU 的引擎。" + +#: ../../source/getting_started/installation_npu.rst:45 +msgid "Enterprise Support" +msgstr "企业支持" + +#: ../../source/getting_started/installation_npu.rst:46 +msgid "" +"If you encounter any performance or other issues for Ascend NPU, please " +"reach out to us via `link `_." +msgstr "" +"如果你在昇腾 NPU 遇到任何性能和其他问题,欢迎垂询 Xinference 企业版," +"在 `这里 `_ 可以找到我们,亦可以 " +"`填写表单 `_ 申请企业版试用。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/troubleshooting.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/troubleshooting.po index 971fbdefb5..48eeaa064d 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/troubleshooting.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/troubleshooting.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-05 11:25+0800\n" +"POT-Creation-Date: 2024-05-11 10:26+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.11.0\n" #: ../../source/getting_started/troubleshooting.rst:5 msgid "Troubleshooting" @@ -125,16 +125,18 @@ msgstr "在启动 Xinference 时记得要加上 ``-H 0.0.0.0`` 参数:" msgid "" "Then Xinference service will listen on all network interfaces (not " "limited to ``127.0.0.1`` or ``localhost``)." -msgstr "那么 Xinference 服务将监听所有网络接口(而不仅限于 ``127.0.0.1`` 或 ``localhost``)。" - +msgstr "" +"那么 Xinference 服务将监听所有网络接口(而不仅限于 ``127.0.0.1`` 或 ``" +"localhost``)。" #: ../../source/getting_started/troubleshooting.rst:73 msgid "" "If you are using the :ref:`using_docker_image`, please add ``-p " ":9997`` during the docker run command, then access is available " "through ``:`` of the local machine." -msgstr "如果使用的是 :ref:`using_docker_image`,请在 Docker 运行命令中 加上 ``-p :9997`` ," -",你就可以通过本地机器的 ``:`` 进行访问。" +msgstr "" +"如果使用的是 :ref:`using_docker_image`,请在 Docker 运行命令中 加上 ``-p " +":9997`` ,,你就可以通过本地机器的 ``:`` 进行访问。" #: ../../source/getting_started/troubleshooting.rst:78 msgid "" @@ -147,7 +149,9 @@ msgid "" "Xinference by default uses HuggingFace as the source for models. If your " "machines are in Mainland China, there might be accessibility issues when " "using built-in models." -msgstr "Xinference 默认使用 HuggingFace作为模型源。如果你的机器在中国大陆,使用内置模型可能会有访问问题。" +msgstr "" +"Xinference 默认使用 HuggingFace作为模型源。如果你的机器在中国大陆,使用" +"内置模型可能会有访问问题。" #: ../../source/getting_started/troubleshooting.rst:84 msgid "" @@ -155,15 +159,17 @@ msgid "" "``XINFERENCE_MODEL_SRC=modelscope`` when starting the Xinference to " "change the model source to ModelScope, which is optimized for Mainland " "China." -msgstr "要解决这个问题,可以在启动 Xinference 时添加环境变量 ``XINFERENCE_MODEL_SRC=modelscope``," -"将模型源更改为 ModelScope,在中国大陆速度下载更快。" - +msgstr "" +"要解决这个问题,可以在启动 Xinference 时添加环境变量 ``XINFERENCE_MODEL_" +"SRC=modelscope``,将模型源更改为 ModelScope,在中国大陆速度下载更快。" #: ../../source/getting_started/troubleshooting.rst:88 msgid "" "If you’re starting Xinference with Docker, include ``-e XINFERENCE_MODEL" "_SRC=modelscope`` during the docker run command." -msgstr "如果你用 Docker 启动 Xinference,可以在 Docker 命令中包含 ``-e XINFERENCE_MODEL_SRC=modelscope`` 选项。" +msgstr "" +"如果你用 Docker 启动 Xinference,可以在 Docker 命令中包含 ``-e XINFERENCE" +"_MODEL_SRC=modelscope`` 选项。" #: ../../source/getting_started/troubleshooting.rst:92 msgid "" @@ -186,3 +192,15 @@ msgid "" "follows:" msgstr "你可以通过设置参数 ``--shm-size`` 来增加它的大小:" +#: ../../source/getting_started/troubleshooting.rst:106 +msgid "Missing ``model_engine`` parameter when launching LLM models" +msgstr "加载 LLM 模型时提示缺失 ``model_engine`` 参数" + +#: ../../source/getting_started/troubleshooting.rst:108 +msgid "" +"Since version ``v0.11.0``, launching LLM models requires an additional " +"``model_engine`` parameter. For specific information, please refer to " +":ref:`here `." +msgstr "" +"自 ``v0.11.0`` 版本开始,加载 LLM 模型时需要传入额外参数 ``model_engine`` 。" +"具体信息请参考 :ref:`这里 ` 。" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_docker_image.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_docker_image.po index f85504aba6..ae41dc7823 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_docker_image.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_docker_image.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-16 12:13+0800\n" +"POT-Creation-Date: 2024-07-04 15:14+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.11.0\n" #: ../../source/getting_started/using_docker_image.rst:5 msgid "Xinference Docker Image" @@ -25,7 +25,7 @@ msgstr "Docker 镜像" #: ../../source/getting_started/using_docker_image.rst:7 msgid "Xinference provides official images for use on Dockerhub." -msgstr "Xinference 在 Dockerhub 中上传了官方镜像。" +msgstr "Xinference 在 Dockerhub 和 阿里云容器镜像服务 中上传了官方镜像。" #: ../../source/getting_started/using_docker_image.rst:11 msgid "Prerequisites" @@ -35,7 +35,9 @@ msgstr "准备工作" msgid "" "The image can only run in an environment with GPUs and CUDA installed, " "because Xinference in the image relies on Nvidia GPUs for acceleration." -msgstr "Xinference 使用 GPU 加速推理,该镜像需要在有 GPU 显卡并且安装 CUDA 的机器上运行。" +msgstr "" +"Xinference 使用 GPU 加速推理,该镜像需要在有 GPU 显卡并且安装 CUDA 的机器" +"上运行。" #: ../../source/getting_started/using_docker_image.rst:13 msgid "" @@ -46,13 +48,12 @@ msgstr "保证 CUDA 在机器上正确安装。可以使用 ``nvidia-smi`` 检 #: ../../source/getting_started/using_docker_image.rst:14 msgid "" -"The CUDA version in the docker image is ``12.1``, and the CUDA version on" -" the host machine should ideally be consistent with it. Be sure to keep " -"the CUDA version on your host machine between ``11.8`` and ``12.2``, even" -" if it is inconsistent." +"The CUDA version in the docker image is ``12.4``, and the CUDA version on" +" the host machine should be ``12.4`` or above, and the NVIDIA driver " +"version should be ``550`` or above." msgstr "" -"镜像中的 CUDA 版本是 ``12.1`` ,推荐机器上的版本与之保持一致。如果不一致,需要保证CUDA 版本在 ``11.8`` 与 " -"``12.2`` 之间。" +"镜像中的 CUDA 版本为 ``12.4`` 。为了不出现预期之外的问题,请将宿主机的 CUDA 版本和 NVIDIA Driver 版本分别" +"升级到 ``12.4`` 和 ``550`` 以上。" #: ../../source/getting_started/using_docker_image.rst:18 msgid "Docker Image" @@ -61,28 +62,45 @@ msgstr "Docker 镜像" #: ../../source/getting_started/using_docker_image.rst:19 msgid "" "The official image of Xinference is available on DockerHub in the " -"repository ``xprobe/xinference``. There are two kinds of image tags " -"available:" -msgstr "Xinference 的官方镜像在 Dockerhub 的 ``xprobe/xinference`` 仓库里。目前有两个版本可以获取:" +"repository ``xprobe/xinference``. Available tags include:" +msgstr "" +"当前,可以通过两个渠道拉取 Xinference 的官方镜像。" +"1. 在 Dockerhub 的 ``xprobe/xinference`` 仓库里。" +"2. Dockerhub 中的镜像会同步上传一份到阿里云公共镜像仓库中,供访问 Dockerhub 有困难的用户拉取。" +"拉取命令:``docker pull registry.cn-hangzhou.aliyuncs.com/xprobe_xinference/xinference:`` 。目前可用的标签包括:" #: ../../source/getting_started/using_docker_image.rst:22 msgid "" "``nightly-main``: This image is built daily from the `GitHub main branch " "`_ and generally does not " "guarantee stability." -msgstr "``nightly-main``: 这个镜像会每天从 GitHub main 分支更新制作,不保证稳定可靠。" +msgstr "" +"``nightly-main``: 这个镜像会每天从 GitHub main 分支更新制作,不保证稳定" +"可靠。" #: ../../source/getting_started/using_docker_image.rst:23 msgid "" "``v``: This image is built each time a Xinference " "release version is published, and it is typically more stable." -msgstr "``v``: 这个镜像会在 Xinference 每次发布的时候制作,通常可以认为是稳定可靠的。" +msgstr "" +"``v``: 这个镜像会在 Xinference 每次发布的时候制作,通常" +"可以认为是稳定可靠的。" + +#: ../../source/getting_started/using_docker_image.rst:24 +msgid "" +"``latest``: This image is built with the latest Xinference release " +"version." +msgstr "``latest``: 这个镜像会在 Xinference 发布时指向最新的发布版本" -#: ../../source/getting_started/using_docker_image.rst:27 +#: ../../source/getting_started/using_docker_image.rst:25 +msgid "For CPU version, add ``-cpu`` suffix, e.g. ``nightly-main-cpu``." +msgstr "对于 CPU 版本,增加 ``-cpu`` 后缀,如 ``nightly-main-cpu``。" + +#: ../../source/getting_started/using_docker_image.rst:29 msgid "Dockerfile for custom build" msgstr "自定义镜像" -#: ../../source/getting_started/using_docker_image.rst:28 +#: ../../source/getting_started/using_docker_image.rst:30 msgid "" "If you need to build the Xinference image according to your own " "requirements, the source code for the Dockerfile is located at " @@ -91,54 +109,57 @@ msgid "" " for reference. Please make sure to be in the top-level directory of " "Xinference when using this Dockerfile. For example:" msgstr "" -"如果需要安装额外的依赖,可以参考 `xinference/deploy/docker/Dockerfile " -"`_" -" 。请确保使用 Dockerfile 制作镜像时在 Xinference 项目的根目录下。比如:" +"如果需要安装额外的依赖,可以参考 `xinference/deploy/docker/Dockerfile <" +"https://github.com/xorbitsai/inference/tree/main/xinference/deploy/docker" +"/Dockerfile>`_ 。请确保使用 Dockerfile 制作镜像时在 Xinference 项目的" +"根目录下。比如:" -#: ../../source/getting_started/using_docker_image.rst:39 +#: ../../source/getting_started/using_docker_image.rst:41 msgid "Image usage" msgstr "使用镜像" -#: ../../source/getting_started/using_docker_image.rst:40 +#: ../../source/getting_started/using_docker_image.rst:42 msgid "" "You can start Xinference in the container like this, simultaneously " "mapping port 9997 in the container to port 9998 on the host, enabling " "debug logging, and downloading models from modelscope." msgstr "" -"你可以使用如下方式在容器内启动 Xinference,同时将 9997 端口映射到宿主机的 9998 端口,并且指定日志级别为 " -"DEBUG,也可以指定需要的环境变量。" +"你可以使用如下方式在容器内启动 Xinference,同时将 9997 端口映射到宿主机的" +" 9998 端口,并且指定日志级别为 DEBUG,也可以指定需要的环境变量。" -#: ../../source/getting_started/using_docker_image.rst:48 +#: ../../source/getting_started/using_docker_image.rst:50 msgid "" "The option ``--gpus`` is essential and cannot be omitted, because as " "mentioned earlier, the image requires the host machine to have a GPU. " "Otherwise, errors will occur." -msgstr "``--gpus`` 必须指定,正如前文描述,镜像必须运行在有 GPU 的机器上,否则会出现错误。" +msgstr "" +"``--gpus`` 必须指定,正如前文描述,镜像必须运行在有 GPU 的机器上,否则会" +"出现错误。" -#: ../../source/getting_started/using_docker_image.rst:49 +#: ../../source/getting_started/using_docker_image.rst:51 msgid "" "The ``-H 0.0.0.0`` parameter after the ``xinference-local`` command " "cannot be omitted. Otherwise, the host machine may not be able to access " "the port inside the container." msgstr "``-H 0.0.0.0`` 也是必须指定的,否则在容器外无法连接到 Xinference 服务。" -#: ../../source/getting_started/using_docker_image.rst:50 +#: ../../source/getting_started/using_docker_image.rst:52 msgid "" "You can add multiple ``-e`` options to introduce multiple environment " "variables." msgstr "可以指定多个 ``-e`` 选项赋值多个环境变量。" -#: ../../source/getting_started/using_docker_image.rst:53 +#: ../../source/getting_started/using_docker_image.rst:55 msgid "" "Certainly, if you prefer, you can also manually enter the docker " "container and start Xinference in any desired way." msgstr "当然,也可以运行容器后,进入容器内手动拉起 Xinference。" -#: ../../source/getting_started/using_docker_image.rst:57 +#: ../../source/getting_started/using_docker_image.rst:59 msgid "Mount your volume for loading and saving models" msgstr "挂载模型目录" -#: ../../source/getting_started/using_docker_image.rst:58 +#: ../../source/getting_started/using_docker_image.rst:60 msgid "" "The image does not contain any model files by default, and it downloads " "the models into the container. Typically, you would need to mount a " @@ -147,10 +168,11 @@ msgid "" "need to specify a volume when running the Docker image and configure " "environment variables for Xinference:" msgstr "" -"默认情况下,镜像中不包含任何模型文件,使用过程中会在容器内下载模型。如果需要使用已经下载好的模型,需要将宿主机的目录挂载到容器内。这种情况下,需要在运行容器时指定本地卷,并且为" -" Xinference 配置环境变量。" +"默认情况下,镜像中不包含任何模型文件,使用过程中会在容器内下载模型。如果" +"需要使用已经下载好的模型,需要将宿主机的目录挂载到容器内。这种情况下," +"需要在运行容器时指定本地卷,并且为 Xinference 配置环境变量。" -#: ../../source/getting_started/using_docker_image.rst:67 +#: ../../source/getting_started/using_docker_image.rst:69 msgid "" "The principle behind the above command is to mount the specified " "directory from the host machine into the container, and then set the " @@ -161,11 +183,12 @@ msgid "" "time you run it, you can directly use the existing models without the " "need for repetitive downloads." msgstr "" -"上述命令的原理是将主机上指定的目录挂载到容器中,并设置 ``XINFERENCE_HOME`` " -"环境变量指向容器内的该目录。这样,所有下载的模型文件将存储在您在主机上指定的目录中。您无需担心在 Docker " -"容器停止时丢失这些文件,下次运行容器时,您可以直接使用现有的模型,无需重复下载。" +"上述命令的原理是将主机上指定的目录挂载到容器中,并设置 ``XINFERENCE_HOME`" +"` 环境变量指向容器内的该目录。这样,所有下载的模型文件将存储在您在主机上" +"指定的目录中。您无需担心在 Docker 容器停止时丢失这些文件,下次运行容器时" +",您可以直接使用现有的模型,无需重复下载。" -#: ../../source/getting_started/using_docker_image.rst:71 +#: ../../source/getting_started/using_docker_image.rst:73 msgid "" "If you downloaded the model using the default path on the host machine, " "and since the xinference cache directory stores the model using symbolic " @@ -176,7 +199,9 @@ msgid "" "HuggingFace and Modelscope are located at /.cache/huggingface " "and /.cache/modelscope. The command would be like:" msgstr "" -"如果你在宿主机使用的默认路径下载的模型,由于 xinference cache 目录是用的软链的方式存储模型," -"需要将原文件所在的目录也挂载到容器内。例如你使用 huggingface 和 modelscope 作为模型仓库," -"那么需要将这两个对应的目录挂载到容器内,一般对应的 cache 目录分别在 /.cache/huggingface " -"和 /.cache/modelscope,使用的命令如下:" +"如果你在宿主机使用的默认路径下载的模型,由于 xinference cache 目录是用的" +"软链的方式存储模型,需要将原文件所在的目录也挂载到容器内。例如你使用 " +"huggingface 和 modelscope 作为模型仓库,那么需要将这两个对应的目录挂载到" +"容器内,一般对应的 cache 目录分别在 /.cache/huggingface 和 <" +"home_path>/.cache/modelscope,使用的命令如下:" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_kubernetes.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_kubernetes.po new file mode 100644 index 0000000000..ccf8255707 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_kubernetes.po @@ -0,0 +1,140 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-02 15:15+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.11.0\n" + +#: ../../source/getting_started/using_kubernetes.rst:5 +msgid "Xinference on Kubernetes" +msgstr "在 Kubernetes 集群中安装 Xinference" + +#: ../../source/getting_started/using_kubernetes.rst:9 +msgid "Helm Support" +msgstr "基于原生 Helm 的方式" + +#: ../../source/getting_started/using_kubernetes.rst:10 +msgid "" +"Xinference provides a method for installation in a Kubernetes cluster via" +" ``Helm`` ." +msgstr "" +"Xinference 提供基于原生 Helm 在 Kubernetes 集群中安装的方式。" + +#: ../../source/getting_started/using_kubernetes.rst:14 +msgid "Prerequisites" +msgstr "" +"准备条件" + +#: ../../source/getting_started/using_kubernetes.rst:15 +msgid "You have a fully functional Kubernetes cluster." +msgstr "" +"一个可用的 Kubernetes 集群。" + +#: ../../source/getting_started/using_kubernetes.rst:16 +msgid "" +"Enable GPU support in Kubernetes, refer to `here " +"`_." +msgstr "" +"在 Kubernetes 中开启 GPU 支持,参考 `这里 `_ 。" + +#: ../../source/getting_started/using_kubernetes.rst:17 +msgid "``Helm`` is correctly installed." +msgstr "" +"正确安装 ``Helm`` 。" + +#: ../../source/getting_started/using_kubernetes.rst:21 +msgid "Steps" +msgstr "" +"具体步骤" + +#: ../../source/getting_started/using_kubernetes.rst:22 +msgid "Add xinference helm repo." +msgstr "新增 Xinference Helm 仓库" + +#: ../../source/getting_started/using_kubernetes.rst:28 +msgid "Update xinference helm repo indexes and query versions." +msgstr "更新仓库索引,查询可安装版本" + +#: ../../source/getting_started/using_kubernetes.rst:35 +msgid "Install" +msgstr "安装" + +#: ../../source/getting_started/using_kubernetes.rst:43 +msgid "Customized Installation" +msgstr "自定义安装" + +#: ../../source/getting_started/using_kubernetes.rst:44 +msgid "" +"The installation method mentioned above sets up a Xinference cluster " +"similar to a single-machine setup, with only one worker and all startup " +"parameters at their default values. However, this is usually not the " +"desired setup." +msgstr "" +"上述安装方式安装了一个类似单机的 Xinference ,也就是只有一个节点,同时其他启动参数均保持默认。" + +#: ../../source/getting_started/using_kubernetes.rst:48 +msgid "Below are some common custom installation configurations." +msgstr "下面展示了一些常见的自定义安装配置。" + +#: ../../source/getting_started/using_kubernetes.rst:50 +msgid "I need to download models from ``ModelScope``." +msgstr "我需要从 ``ModelScope`` 下载模型。" + +#: ../../source/getting_started/using_kubernetes.rst:56 +msgid "" +"I want to use cpu image of xinference (or use any other version of " +"xinference images)." +msgstr "我想使用 cpu 版本的 Xinference 镜像(或者其他版本的镜像)。" + +#: ../../source/getting_started/using_kubernetes.rst:62 +msgid "I want to have 4 Xinference workers, with each worker managing 4 GPUs." +msgstr "我需要启动 4 个 Xinference worker 节点,每个 worker 管理 4 个 GPU。" + +#: ../../source/getting_started/using_kubernetes.rst:68 +msgid "" +"The above installation method is based on Helm ``--set`` option. For more" +" complex custom installations, such as multiple workers with shared " +"storage, it is highly recommended to use your own ``values.yaml`` file " +"with Helm ``-f`` option for installation." +msgstr "" +"上面的安装方式基于 Helm ``--set`` 选项。对于更加复杂的自定义安装场景,例如多个 worker 共享存储," +"非常推荐使用你自己的 ``values.yaml`` 文件,然后通过 Helm ``-f`` 选项进行安装。" + +#: ../../source/getting_started/using_kubernetes.rst:72 +msgid "" +"The default ``values.yaml`` file is located `here " +"`_. Some examples can be " +"found `here `_." +msgstr "" +"默认安装方式对应的 ``values.yaml`` 文件位于 `这里 `_ 。" +"而 `这里 `_ 有一些示例供参考。" + +#: ../../source/getting_started/using_kubernetes.rst:78 +msgid "KubeBlocks Support" +msgstr "基于第三方 KubeBlocks 的方式" + +#: ../../source/getting_started/using_kubernetes.rst:79 +msgid "" +"You can also install Xinference in Kubernetes using the third-party " +"``KubeBlocks``. This method is not maintained by Xinference and does not " +"guarantee timely updates or availability. Please refer to the " +"documentation at `here `_." +msgstr "" +"你也可以通过第三方的 ``KubeBlocks`` 来在 K8s 集群中安装 Xinference 。这种方式不是 Xinference 官方维护的," +"因此无法严格保证实时更新和可用性。请参考 `文档 `_ 。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_xinference.po b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_xinference.po index 45df8430b5..af00e9da42 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_xinference.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/getting_started/using_xinference.po @@ -2,13 +2,11 @@ # Copyright (C) 2023, Xorbits Inc. # This file is distributed under the same license as the Xinference package. # FIRST AUTHOR , 2023. -# -#, fuzzy msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-05 10:42+0800\n" +"POT-Creation-Date: 2024-08-02 15:15+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +15,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.11.0\n" #: ../../source/getting_started/using_xinference.rst:5 msgid "Using Xinference" @@ -31,13 +29,17 @@ msgstr "本地运行 Xinference" msgid "" "Let's start by running Xinference on a local machine and running a " "classic LLM model: ``llama-2-chat``." -msgstr "让我们以一个经典的大语言模型 ``llama-2-chat`` 来展示如何在本地用 Xinference 运行大模型。" +msgstr "" +"让我们以一个经典的大语言模型 ``llama-2-chat`` 来展示如何在本地用 " +"Xinference 运行大模型。" #: ../../source/getting_started/using_xinference.rst:13 msgid "" "After this quickstart, you will move on to learning how to deploy " "Xinference in a cluster environment." -msgstr "在这个快速入门之后,可以继续学习如何在一个分布式集群环境下部署 Xinference。" +msgstr "" +"在这个快速入门之后,可以继续学习如何在一个分布式集群环境下部署 Xinference" +"。" #: ../../source/getting_started/using_xinference.rst:16 msgid "Start Local Server" @@ -49,8 +51,8 @@ msgid "" "instructions provided :ref:`here `. To start a local " "instance of Xinference, run the following command:" msgstr "" -"首先,请根据这个 :ref:`文档 ` 的指导确保本地安装了 Xinference。使用以下命令拉起本地的 " -"Xinference 服务:" +"首先,请根据这个 :ref:`文档 ` 的指导确保本地安装了 " +"Xinference。使用以下命令拉起本地的 Xinference 服务:" #: ../../source/getting_started/using_xinference.rst:23 #: ../../source/getting_started/using_xinference.rst:65 @@ -68,8 +70,9 @@ msgid "" "necessary files such as logs and models, where ```` is the home " "path of current user." msgstr "" -"默认情况下,Xinference 会使用 ``/.xinference`` " -"作为主目录来存储一些必要的信息,比如日志文件和模型文件,其中 ```` 就是当前用户的主目录。" +"默认情况下,Xinference 会使用 ``/.xinference`` 作为主目录来存储一些" +"必要的信息,比如日志文件和模型文件,其中 ```` 就是当前用户的主目录" +"。" #: ../../source/getting_started/using_xinference.rst:42 msgid "" @@ -84,8 +87,9 @@ msgid "" " UI, via cURL, via the command line, or via the Xinference's python " "client." msgstr "" -"恭喜!你已经在本地拉起了 Xinference 服务。一旦 Xinference 服务运行起来,可以有多种方式来使用,包括使用网页、cURL " -"命令、命令行或者是 Xinference 的 Python SDK。" +"恭喜!你已经在本地拉起了 Xinference 服务。一旦 Xinference 服务运行起来," +"可以有多种方式来使用,包括使用网页、cURL 命令、命令行或者是 Xinference 的" +" Python SDK。" #: ../../source/getting_started/using_xinference.rst:52 msgid "" @@ -93,8 +97,9 @@ msgid "" "`_ and visit `http://127.0.0.1:9997/docs " "`_ to inspect the API docs." msgstr "" -"可以通过访问 `http://127.0.0.1:9997/ui `_ 来使用 UI,访问 " -"`http://127.0.0.1:9997/docs `_ 来查看 API 文档。" +"可以通过访问 `http://127.0.0.1:9997/ui `_ 来" +"使用 UI,访问 `http://127.0.0.1:9997/docs `_ " +"来查看 API 文档。" #: ../../source/getting_started/using_xinference.rst:55 msgid "" @@ -114,14 +119,102 @@ msgid "" "using the following command. Please ensure that the version of the client" " matches the version of the Xinference server." msgstr "" -"如果只需要安装 Xinference 的 Python SDK,可以使用以下命令安装最少依赖。需要注意的是版本必须和 Xinference " -"服务的版本保持匹配。" +"如果只需要安装 Xinference 的 Python SDK,可以使用以下命令安装最少依赖。" +"需要注意的是版本必须和 Xinference 服务的版本保持匹配。" + +#: ../../source/getting_started/using_xinference.rst:105 +msgid "About Model Engine" +msgstr "关于模型的推理引擎" + +#: ../../source/getting_started/using_xinference.rst:106 +msgid "" +"Since ``v0.11.0`` , before launching the LLM model, you need to specify " +"the inference engine you want to run. Currently, xinference supports the " +"following inference engines:" +msgstr "" +"自 ``v0.11.0`` 版本开始,在加载 LLM 模型之前,你需要指定具体的推理引擎。" +"当前,Xinference 支持以下推理引擎:" + +#: ../../source/getting_started/using_xinference.rst:109 +msgid "``vllm``" +msgstr "" + +#: ../../source/getting_started/using_xinference.rst:110 +msgid "``sglang``" +msgstr "" + +#: ../../source/getting_started/using_xinference.rst:111 +msgid "``llama.cpp``" +msgstr "" + +#: ../../source/getting_started/using_xinference.rst:112 +msgid "``transformers``" +msgstr "" + +#: ../../source/getting_started/using_xinference.rst:114 +msgid "" +"About the details of these inference engine, please refer to :ref:`here " +"`." +msgstr "关于这些推理引擎的详细信息,请参考 :ref:`这里 ` 。" + +#: ../../source/getting_started/using_xinference.rst:116 +msgid "" +"Note that when launching a LLM model, the ``model_format`` and " +"``quantization`` of the model you want to launch is closely related to " +"the inference engine." +msgstr "" +"注意,当加载 LLM 模型时,所能运行的引擎与 ``model_format`` 和 ``" +"quantization`` 参数息息相关。" + +#: ../../source/getting_started/using_xinference.rst:119 +msgid "" +"You can use ``xinference engine`` command to query the combination of " +"parameters of the model you want to launch. This will demonstrate under " +"what conditions a model can run on which inference engines." +msgstr "Xinference 提供了 ``xinference engine`` 命令帮助你查询相关的参数组合。" + +#: ../../source/getting_started/using_xinference.rst:122 +msgid "For example:" +msgstr "例如:" + +#: ../../source/getting_started/using_xinference.rst:124 +msgid "" +"I would like to query about which inference engines the ``qwen-chat`` " +"model can run on, and what are their respective parameters." +msgstr "" +"我想查询与 ``qwen-chat`` 模型相关的参数组合,以决定它能够怎样跑在各种推理" +"引擎上。" -#: ../../source/getting_started/using_xinference.rst:103 +#: ../../source/getting_started/using_xinference.rst:130 +msgid "" +"I want to run ``qwen-chat`` with ``VLLM`` as the inference engine, but I " +"don't know how to configure the other parameters." +msgstr "" +"我想将 ``qwen-chat`` 跑在 ``VLLM`` 推理引擎上,但是我不知道什么样的其他" +"参数符合这个要求。" + +#: ../../source/getting_started/using_xinference.rst:136 +msgid "" +"I want to launch the ``qwen-chat`` model in the ``GGUF`` format, and I " +"need to know how to configure the remaining parameters." +msgstr "我想加载 ``GGUF`` 格式的 ``qwen-chat`` 模型,我需要知道其余的参数组合。" + +#: ../../source/getting_started/using_xinference.rst:143 +msgid "" +"In summary, compared to previous versions, when launching LLM models, you" +" need to additionally pass the ``model_engine`` parameter. You can " +"retrieve information about the supported inference engines and their " +"related parameter combinations through the ``xinference engine`` command." +msgstr "" +"总之,相比于之前的版本,当加载 LLM 模型时,需要额外传入 ``model_engine`` " +"参数。你可以通过 ``xinference engine`` 命令查询你想运行的推理引擎与其他" +"参数组合的关系。" + +#: ../../source/getting_started/using_xinference.rst:150 msgid "Run Llama-2" msgstr "运行 Llama-2" -#: ../../source/getting_started/using_xinference.rst:105 +#: ../../source/getting_started/using_xinference.rst:152 msgid "" "Let's start by running a built-in model: ``llama-2-chat``. When you start" " a model for the first time, Xinference will download the model " @@ -129,308 +222,244 @@ msgid "" "the size of the model weights. We cache the model files locally, so " "there's no need to redownload them for subsequent starts." msgstr "" -"让我们来运行一个内置的 ``llama-2-chat`` 模型。当你需要运行一个模型时,第一次运行是要从HuggingFace " -"下载模型参数,一般来说需要根据模型大小下载10到30分钟不等。当下载完成后,Xinference本地会有缓存的处理,以后再运行相同的模型不需要重新下载。" +"让我们来运行一个内置的 ``llama-2-chat`` 模型。当你需要运行一个模型时," +"第一次运行是要从HuggingFace 下载模型参数,一般来说需要根据模型大小下载10" +"到30分钟不等。当下载完成后,Xinference本地会有缓存的处理,以后再运行相同" +"的模型不需要重新下载。" -#: ../../source/getting_started/using_xinference.rst:110 +#: ../../source/getting_started/using_xinference.rst:157 msgid "" "Xinference also allows you to download models from other sites. You can " "do this by setting an environment variable when launching Xinference. For" " example, if you want to download models from `modelscope " "`_, do the following:" msgstr "" -"Xinference 也允许从其他模型托管平台下载模型。可以通过在拉起 Xinference 时指定环境变量,比如,如果想要从 " -"ModelScope 中下载模型,可以使用如下命令:" +"Xinference 也允许从其他模型托管平台下载模型。可以通过在拉起 Xinference 时" +"指定环境变量,比如,如果想要从 ModelScope 中下载模型,可以使用如下命令:" -#: ../../source/getting_started/using_xinference.rst:118 -#, fuzzy +#: ../../source/getting_started/using_xinference.rst:165 msgid "" "We can specify the model's UID using the ``--model-uid`` or ``-u`` flag. " "If not specified, Xinference will generate a unique ID. This create a new" " model instance with unique ID ``my-llama-2``:" msgstr "" -"可以使用 ``--model-uid`` 或者 ``-u`` 参数指定模型的 UID,如果没有指定,Xinference 会随机生成一个 " -"ID,下面的命令就是手动指定了 ID 为 ``my-llama-2``:" +"可以使用 ``--model-uid`` 或者 ``-u`` 参数指定模型的 UID,如果没有指定," +"Xinference 会随机生成一个 ID,下面的命令就是手动指定了 ID 为 ``my-llama-2" +"``:" -#: ../../source/getting_started/using_xinference.rst:157 +#: ../../source/getting_started/using_xinference.rst:206 msgid "" "For some engines, such as vllm, users need to specify the engine-related " "parameters when running models. In this case, you can directly specify " "the parameter name and value in the command line, for example:" msgstr "" -"对于一些推理引擎,比如 vllm,用户需要在运行模型时指定引擎相关的参数,这种情况下直接在命令行中指定" -"对应的参数名和值即可,比如:" +"对于一些推理引擎,比如 vllm,用户需要在运行模型时指定引擎相关的参数,这种" +"情况下直接在命令行中指定对应的参数名和值即可,比如:" -#: ../../source/getting_started/using_xinference.rst:165 +#: ../../source/getting_started/using_xinference.rst:214 msgid "`gpu_memory_utilization=0.9` will pass to vllm when launching model." msgstr "在运行模型时,`gpu_memory_utilization=0.9` 会传到 vllm 后端。" -#: ../../source/getting_started/using_xinference.rst:167 -#, fuzzy +#: ../../source/getting_started/using_xinference.rst:216 msgid "" "Congrats! You now have ``llama-2-chat`` running by Xinference. Once the " "model is running, we can try it out either via cURL, or via Xinference's " "python client:" msgstr "" -"到这一步,恭喜你已经成功通过 Xinference 将 ``llama-2-chat`` " -"运行起来了。一旦这个模型在运行中,我们可以通过命令行、cURL 或者是 Python 代码来预支交互:" +"到这一步,恭喜你已经成功通过 Xinference 将 ``llama-2-chat`` 运行起来了。" +"一旦这个模型在运行中,我们可以通过命令行、cURL 或者是 Python 代码来预支" +"交互:" -#: ../../source/getting_started/using_xinference.rst:227 +#: ../../source/getting_started/using_xinference.rst:276 msgid "" "Xinference provides OpenAI-compatible APIs for its supported models, so " "you can use Xinference as a local drop-in replacement for OpenAI APIs. " "For example:" -msgstr "Xinference 提供了与 OpenAI 兼容的 API,所以可以将 Xinference 运行的模型当成 OpenAI的本地替代。比如:" +msgstr "" +"Xinference 提供了与 OpenAI 兼容的 API,所以可以将 Xinference 运行的模型" +"当成 OpenAI的本地替代。比如:" -#: ../../source/getting_started/using_xinference.rst:243 +#: ../../source/getting_started/using_xinference.rst:292 msgid "The following OpenAI APIs are supported:" msgstr "以下是支持的 OpenAI 的 API:" -#: ../../source/getting_started/using_xinference.rst:245 +#: ../../source/getting_started/using_xinference.rst:294 msgid "" "Chat Completions: `https://platform.openai.com/docs/api-reference/chat " "`_" msgstr "" -"对话生成:`https://platform.openai.com/docs/api-reference/chat " -"`_" +"对话生成:`https://platform.openai.com/docs/api-reference/chat `_" -#: ../../source/getting_started/using_xinference.rst:247 +#: ../../source/getting_started/using_xinference.rst:296 msgid "" "Completions: `https://platform.openai.com/docs/api-reference/completions " "`_" msgstr "" -"生成: `https://platform.openai.com/docs/api-reference/completions " -"`_" +"生成: `https://platform.openai.com/docs/api-reference/completions `_" -#: ../../source/getting_started/using_xinference.rst:249 +#: ../../source/getting_started/using_xinference.rst:298 msgid "" "Embeddings: `https://platform.openai.com/docs/api-reference/embeddings " "`_" msgstr "" -"向量生成:`https://platform.openai.com/docs/api-reference/embeddings " -"`_" +"向量生成:`https://platform.openai.com/docs/api-reference/embeddings <" +"https://platform.openai.com/docs/api-reference/embeddings>`_" -#: ../../source/getting_started/using_xinference.rst:252 +#: ../../source/getting_started/using_xinference.rst:301 msgid "Manage Models" msgstr "管理模型" -#: ../../source/getting_started/using_xinference.rst:254 +#: ../../source/getting_started/using_xinference.rst:303 msgid "" "In addition to launching models, Xinference offers various ways to manage" " the entire lifecycle of models. You can manage models in Xinference " "through the command line, cURL, or Xinference's python client." -msgstr "除了启动模型,Xinference 提供了管理模型整个生命周期的能力。同样的,你可以使用命令行、cURL 以及 Python 代码来管理:" +msgstr "" +"除了启动模型,Xinference 提供了管理模型整个生命周期的能力。同样的,你可以" +"使用命令行、cURL 以及 Python 代码来管理:" -#: ../../source/getting_started/using_xinference.rst:257 +#: ../../source/getting_started/using_xinference.rst:306 msgid "" "You can list all models of a certain type that are available to launch in" " Xinference:" msgstr "可以列出所有 Xinference 支持的指定类型的模型:" -#: ../../source/getting_started/using_xinference.rst:275 +#: ../../source/getting_started/using_xinference.rst:324 msgid "" "The following command gives you the currently running models in " "Xinference:" msgstr "接下来的命令可以列出所有在运行的模型:" -#: ../../source/getting_started/using_xinference.rst:293 +#: ../../source/getting_started/using_xinference.rst:342 msgid "" "When you no longer need a model that is currently running, you can remove" " it in the following way to free up the resources it occupies:" msgstr "当你不需要某个正在运行的模型,可以通过以下的方式来停止它并释放资源:" -#: ../../source/getting_started/using_xinference.rst:312 +#: ../../source/getting_started/using_xinference.rst:361 msgid "Deploy Xinference In a Cluster" msgstr "集群中部署 Xinference" -#: ../../source/getting_started/using_xinference.rst:314 +#: ../../source/getting_started/using_xinference.rst:363 msgid "" "To deploy Xinference in a cluster, you need to start a Xinference " "supervisor on one server and Xinference workers on the other servers." -msgstr "若要在集群环境中部署 Xinference,需要在一台机器中启动 supervisor 节点,并在当前或者其他节点启动 worker 节点" +msgstr "" +"若要在集群环境中部署 Xinference,需要在一台机器中启动 supervisor 节点,并" +"在当前或者其他节点启动 worker 节点" -#: ../../source/getting_started/using_xinference.rst:317 +#: ../../source/getting_started/using_xinference.rst:366 msgid "" "First, make sure you have already installed Xinference on each of the " "servers according to the instructions provided :ref:`here " "`. Then follow the steps below:" -msgstr "首先,根据 :ref:`文档 ` 确保所有的服务器上都安装了 Xinference。接下来按照步骤:" +msgstr "" +"首先,根据 :ref:`文档 ` 确保所有的服务器上都安装了 " +"Xinference。接下来按照步骤:" -#: ../../source/getting_started/using_xinference.rst:321 +#: ../../source/getting_started/using_xinference.rst:370 msgid "Start the Supervisor" msgstr "启动 Supervisor" -#: ../../source/getting_started/using_xinference.rst:322 +#: ../../source/getting_started/using_xinference.rst:371 msgid "" "On the server where you want to run the Xinference supervisor, run the " "following command:" msgstr "在服务器上执行以下命令来启动 Supervisor 节点:" -#: ../../source/getting_started/using_xinference.rst:328 +#: ../../source/getting_started/using_xinference.rst:377 msgid "" "Replace ``${supervisor_host}`` with the actual host of your supervisor " "server." msgstr "用当前节点的 IP 来替换 ``${supervisor_host}``。" -#: ../../source/getting_started/using_xinference.rst:331 +#: ../../source/getting_started/using_xinference.rst:380 msgid "" "You can the supervisor's web UI at `http://${supervisor_host}:9997/ui " "`_ and visit " "`http://${supervisor_host}:9997/docs " "`_ to inspect the API docs." msgstr "" -"可以在 `http://${supervisor_host}:9997/ui " -"`_ 访问 web UI,在 " -"`http://${supervisor_host}:9997/docs " -"`_ 访问 API 文档。" +"可以在 `http://${supervisor_host}:9997/ui `_ 访问 web UI,在 `http://${supervisor_host}:9997/docs `_ 访问 API 文档。" -#: ../../source/getting_started/using_xinference.rst:335 +#: ../../source/getting_started/using_xinference.rst:384 msgid "Start the Workers" msgstr "启动 Worker" -#: ../../source/getting_started/using_xinference.rst:337 +#: ../../source/getting_started/using_xinference.rst:386 msgid "" "On each of the other servers where you want to run Xinference workers, " "run the following command:" msgstr "在需要启动 Xinference worker 的机器上执行以下命令:" -#: ../../source/getting_started/using_xinference.rst:345 +#: ../../source/getting_started/using_xinference.rst:393 +msgid "" +"Note that you must replace ``${worker_host}`` with the actual host of " +"your worker server." +msgstr "需要注意的是,必须使用当前Worker节点的 IP 来替换 ``${worker_host}``。" + +#: ../../source/getting_started/using_xinference.rst:396 msgid "" "Note that if you need to interact with the Xinference in a cluster via " "the command line, you should include the ``-e`` or ``--endpoint`` flag to" " specify the supervisor server's endpoint. For example:" msgstr "" -"需要注意的是,如果你需要通过命令行与集群交互,应该通过 ``-e`` 或者 ``--endpoint`` 参数来指定 supervisor " -"的地址,比如:" +"需要注意的是,如果你需要通过命令行与集群交互,应该通过 ``-e`` 或者 ``--" +"endpoint`` 参数来指定 supervisor 的地址,比如:" -#: ../../source/getting_started/using_xinference.rst:353 +#: ../../source/getting_started/using_xinference.rst:404 msgid "Using Xinference With Docker" msgstr "使用 Docker 部署 Xinference" -#: ../../source/getting_started/using_xinference.rst:355 +#: ../../source/getting_started/using_xinference.rst:406 msgid "To start Xinference in a Docker container, run the following command:" msgstr "用以下命令在容器中运行 Xinference:" -#: ../../source/getting_started/using_xinference.rst:358 +#: ../../source/getting_started/using_xinference.rst:409 msgid "Run On Nvidia GPU Host" msgstr "在拥有英伟达显卡的机器上运行" -#: ../../source/getting_started/using_xinference.rst:365 +#: ../../source/getting_started/using_xinference.rst:416 msgid "Run On CPU Only Host" msgstr "在只有 CPU 的机器上运行" -#: ../../source/getting_started/using_xinference.rst:373 -msgid "Using Xinference On Kubernetes" -msgstr "在 Kubernetes 环境中运行 Xinference" - -#: ../../source/getting_started/using_xinference.rst:375 +#: ../../source/getting_started/using_xinference.rst:422 msgid "" -"To use Xinference on Kubernetes, `KubeBlocks `_ " -"is required to help the installation." +"Replace ```` with Xinference versions, e.g. ``v0.10.3``, " +"``latest`` can be used for the latest version." msgstr "" -"如果想在 Kubernetes 中运行 Xinference,需要通过 `KubeBlocks " -"`_ 来帮助安装。" +"将 ```` 替换为 Xinference 的版本,比如 ``v0.10.3``,可以用 " +"``latest`` 来用于最新版本。" -#: ../../source/getting_started/using_xinference.rst:377 -msgid "The following steps assume Kubernetes is already installed." -msgstr "假设已经有一个可以使用的 Kubernetes 环境。" - -#: ../../source/getting_started/using_xinference.rst:379 +#: ../../source/getting_started/using_xinference.rst:424 msgid "" -"Download cli tool kbcli for KubeBlocks, see `install kbcli " -"`_." -msgstr "" -"下载 KubeBlocks 的命令行工具,可以参考 `文档 " -"`_. " - -#: ../../source/getting_started/using_xinference.rst:381 -msgid "Make sure kbcli version is at least v0.7.1." -msgstr "确保 kbcli 的版本至少为 v0.7.1。" +"For more docker usage, refer to :ref:`Using Docker Image " +"`." +msgstr "更多 docker 使用,请参考 :ref:`使用 docker 镜像 `。" -#: ../../source/getting_started/using_xinference.rst:383 -msgid "" -"Install KubeBlocks using kbcli command, see `install KubeBlocks with " -"kbcli `_." -msgstr "" -"通过 kbcli 安装 KubeBlocks,参考 `文档 kbcli " -"`_." - -#: ../../source/getting_started/using_xinference.rst:385 -msgid "Enable Xinference addon, run the following command:" -msgstr "用以下命令打开 Xinference 插件:" - -#: ../../source/getting_started/using_xinference.rst:391 -msgid "Use kbcli to start Xinference cluster, run the following command:" -msgstr "使用 kbcli 来拉起 Xinference 集群:" - -#: ../../source/getting_started/using_xinference.rst:397 -msgid "" -"If the Kubernetes node doesn't have GPU on it, run the command with extra" -" flag:" -msgstr "如果 Kubernetes 节点没有 GPU 设备,需要加上额外的参数:" - -#: ../../source/getting_started/using_xinference.rst:403 -msgid "Use -h to read the help documentation for more options:" -msgstr "使用 -h 获取帮助文档" - -#: ../../source/getting_started/using_xinference.rst:410 +#: ../../source/getting_started/using_xinference.rst:428 msgid "What's Next?" msgstr "更多" -#: ../../source/getting_started/using_xinference.rst:412 +#: ../../source/getting_started/using_xinference.rst:430 msgid "" "Congratulations on getting started with Xinference! To help you navigate " "and make the most out of this powerful tool, here are some resources and " "guides:" -msgstr "恭喜你,已经初步掌握了 Xinference 的用法!为了帮助你更好地使用工具,下面是其他的一些文档和指导资源:" +msgstr "" +"恭喜你,已经初步掌握了 Xinference 的用法!为了帮助你更好地使用工具,下面" +"是其他的一些文档和指导资源:" -#: ../../source/getting_started/using_xinference.rst:415 +#: ../../source/getting_started/using_xinference.rst:433 msgid "" ":ref:`How to Use Client APIs for Different Types of Models " "`" msgstr ":ref:`如何使用 Python 创建不同类型的模型 `" -#: ../../source/getting_started/using_xinference.rst:417 +#: ../../source/getting_started/using_xinference.rst:435 msgid ":ref:`Choosing the Right Backends for Your Needs `" msgstr ":ref:`选择正确的推理引擎 ` " - -#~ msgid "Configure Xinference Home Path" -#~ msgstr "" - -#~ msgid "Using Xinference Locally" -#~ msgstr "" - -#~ msgid "To start a local instance of Xinference, run the following command:" -#~ msgstr "" - -#~ msgid "Using Xinference In a Cluster" -#~ msgstr "" - -#~ msgid "" -#~ "To deploy Xinference in a cluster, " -#~ "you need to start a Xinference " -#~ "supervisor on one server and Xinference" -#~ " workers on the other servers. Follow" -#~ " the steps below:" -#~ msgstr "" - -#~ msgid "Starting the Supervisor" -#~ msgstr "" - -#~ msgid "" -#~ "Replace ${supervisor_host} with the actual " -#~ "host of your supervisor server." -#~ msgstr "" - -#~ msgid "Starting the Workers" -#~ msgstr "" - -#~ msgid "" -#~ "Once Xinference is running, an endpoint" -#~ " will be accessible for model " -#~ "management via CLI or Xinference client." -#~ msgstr "" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/index.po index 29a2689be6..070313bac4 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/index.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-01 16:47+0800\n" +"POT-Creation-Date: 2024-08-18 15:28+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,13 +17,13 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/index.rst:5 msgid "Welcome to Xinference!" msgstr "欢迎来到 Xinference!" -#: ../../source/index.rst:18 +#: ../../source/index.rst:19 msgid "" "Xorbits Inference (Xinference) is an open-source platform to streamline " "the operation and integration of a wide array of AI models. With " @@ -35,143 +35,151 @@ msgstr "" "和集成。借助 Xinference,您可以使用任何开源 LLM、嵌入模型和多模态模型在" "云端或本地环境中运行推理,并创建强大的 AI 应用。" -#: ../../source/index.rst:24 +#: ../../source/index.rst:25 msgid "Developing Real-world AI Applications with Xinference" msgstr "使用 Xinference 开发真实场景的 AI 应用" -#: ../../source/index.rst:108 +#: ../../source/index.rst:118 msgid "Getting Started" msgstr "入门指南" -#: ../../source/index.rst:112 +#: ../../source/index.rst:122 msgid "Install Xinference" msgstr "安装 Xinference" -#: ../../source/index.rst:116 +#: ../../source/index.rst:126 msgid "Install Xinference on Linux, Windows, and macOS." msgstr "在 Linux、Windows 和 macOS 上安装 Xinference。" -#: ../../source/index.rst:118 +#: ../../source/index.rst:128 msgid "Try it out!" msgstr "立即体验!" -#: ../../source/index.rst:122 +#: ../../source/index.rst:132 msgid "Start by running Xinference on a local machine." msgstr "首先在本地计算机上运行 Xinference。" -#: ../../source/index.rst:127 +#: ../../source/index.rst:137 msgid "Explore models" msgstr "探索模型" -#: ../../source/index.rst:131 +#: ../../source/index.rst:141 msgid "Explore a wide range of models supported by Xinference." msgstr "探索 Xinference 支持的各种模型。" -#: ../../source/index.rst:133 +#: ../../source/index.rst:143 msgid "Register your own model" msgstr "注册你自己的模型" -#: ../../source/index.rst:137 +#: ../../source/index.rst:147 msgid "Register model weights and turn it into an API." msgstr "注册模型权重,并转化为 API" -#: ../../source/index.rst:142 +#: ../../source/index.rst:152 msgid "Explore the API" msgstr "探索 API" -#: ../../source/index.rst:146 +#: ../../source/index.rst:156 msgid "Chat & Generate" msgstr "聊天 & 生成" -#: ../../source/index.rst:150 +#: ../../source/index.rst:160 msgid "Learn how to chat with LLMs in Xinference." msgstr "学习如何在 Xinference 中与 LLM聊天。" -#: ../../source/index.rst:152 +#: ../../source/index.rst:162 msgid "Tools" msgstr "工具" -#: ../../source/index.rst:156 +#: ../../source/index.rst:166 msgid "Learn how to connect LLM with external tools." msgstr "学习如何将 LLM 与外部工具连接起来。" -#: ../../source/index.rst:161 +#: ../../source/index.rst:171 msgid "Embeddings" msgstr "嵌入" -#: ../../source/index.rst:165 +#: ../../source/index.rst:175 msgid "Learn how to create text embeddings in Xinference." msgstr "学习如何在 Xinference 中创建文本嵌入。" -#: ../../source/index.rst:167 +#: ../../source/index.rst:177 msgid "Rerank" msgstr "重排序" -#: ../../source/index.rst:171 +#: ../../source/index.rst:181 msgid "Learn how to use rerank models in Xinference." msgstr "学习如何在 Xinference 中使用重排序模型。" -#: ../../source/index.rst:176 +#: ../../source/index.rst:186 msgid "Images" msgstr "图像" -#: ../../source/index.rst:180 +#: ../../source/index.rst:190 msgid "Learn how to generate images with Xinference." msgstr "学习如何使用Xinference生成图像。" -#: ../../source/index.rst:182 +#: ../../source/index.rst:192 msgid "Vision" msgstr "视觉" -#: ../../source/index.rst:186 +#: ../../source/index.rst:196 msgid "Learn how to process image with LLMs." msgstr "学习如何使用 LLM 处理图像。" -#: ../../source/index.rst:191 +#: ../../source/index.rst:201 msgid "Audio" msgstr "音频" -#: ../../source/index.rst:195 +#: ../../source/index.rst:205 msgid "Learn how to turn audio into text or text into audio with Xinference." msgstr "学习如何使用 Xinference 将音频转换为文本或将文本转换为音频。" -#: ../../source/index.rst:199 +#: ../../source/index.rst:207 +msgid "Video" +msgstr "视频" + +#: ../../source/index.rst:211 +msgid "Learn how to generate video with Xinference." +msgstr "学习如何使用Xinference生成视频。" + +#: ../../source/index.rst:215 msgid "Getting Involved" msgstr "参与我们" -#: ../../source/index.rst:208 +#: ../../source/index.rst:224 msgid "Get Latest News" msgstr "最新资讯" -#: ../../source/index.rst:216 +#: ../../source/index.rst:232 msgid ":fab:`twitter` Follow us on Twitter" msgstr ":fab:`twitter` 在 Twitter 上关注我们" -#: ../../source/index.rst:221 +#: ../../source/index.rst:237 msgid ":fab:`zhihu` Read our blogs" msgstr ":fab:`zhihu` 阅读知乎博客" -#: ../../source/index.rst:228 +#: ../../source/index.rst:244 msgid "Get Support" msgstr "寻求帮助" -#: ../../source/index.rst:236 +#: ../../source/index.rst:252 msgid ":fab:`weixin` Find community on WeChat" msgstr ":fab:`weixin` 微信社区" -#: ../../source/index.rst:241 +#: ../../source/index.rst:257 msgid ":fab:`slack` Find community on Slack" msgstr ":fab:`slack` Slack 社区" -#: ../../source/index.rst:246 +#: ../../source/index.rst:262 msgid ":fab:`github` Open an issue" msgstr ":fab:`github` 在 Github 上提 issue" -#: ../../source/index.rst:253 +#: ../../source/index.rst:269 msgid "Contribute to Xinference" msgstr "贡献" -#: ../../source/index.rst:261 +#: ../../source/index.rst:277 msgid ":fab:`github` Create a pull request" msgstr ":fab:`github` 在 Github 上提 PR" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-dev.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-dev.po new file mode 100644 index 0000000000..bf5a08b979 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-dev.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/flux.1-dev.rst:5 +msgid "FLUX.1-dev" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:7 +msgid "**Model Name:** FLUX.1-dev" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:9 +msgid "**Abilities:** text2image" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:15 +msgid "**Model ID:** black-forest-labs/FLUX.1-dev" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-dev.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-schnell.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-schnell.po new file mode 100644 index 0000000000..a41f15bcb2 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/flux.1-schnell.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:5 +msgid "FLUX.1-schnell" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:7 +msgid "**Model Name:** FLUX.1-schnell" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:9 +msgid "**Abilities:** text2image" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:15 +msgid "**Model ID:** black-forest-labs/FLUX.1-schnell" +msgstr "" + +#: ../../source/models/builtin/image/flux.1-schnell.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/models/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/index.po similarity index 51% rename from doc/source/locale/ja_JP/LC_MESSAGES/models/index.po rename to doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/index.po index 44d2fbd121..99bd9d9719 100644 --- a/doc/source/locale/ja_JP/LC_MESSAGES/models/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/index.po @@ -1,25 +1,29 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) 2023, Xorbits Inc. # This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. +# FIRST AUTHOR , 2024. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" +"POT-Creation-Date: 2024-03-11 13:33+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" "Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.14.0\n" -#: ../../source/models/index.rst:5 -msgid "Models" -msgstr "" +#: ../../source/models/builtin/image/index.rst:5 +msgid "Image Models" +msgstr "图像模型" + +#: ../../source/models/builtin/image/index.rst:7 +msgid "The following is a list of built-in image models in Xinference:" +msgstr "以下是 Xinference 中内置的图像模型列表:" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/kolors.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/kolors.po new file mode 100644 index 0000000000..a922c2144c --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/kolors.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/kolors.rst:5 +msgid "kolors" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:7 +msgid "**Model Name:** kolors" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:9 +msgid "**Abilities:** text2image, image2image" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:15 +msgid "**Model ID:** Kwai-Kolors/Kolors-diffusers" +msgstr "" + +#: ../../source/models/builtin/image/kolors.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd-turbo.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd-turbo.po new file mode 100644 index 0000000000..b7c9b2c84e --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd-turbo.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/sd-turbo.rst:5 +msgid "sd-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:7 +msgid "**Model Name:** sd-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:9 +msgid "**Abilities:** text2image" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:15 +msgid "**Model ID:** stabilityai/sd-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sd-turbo.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd3-medium.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd3-medium.po new file mode 100644 index 0000000000..dbc54fdbef --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sd3-medium.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/sd3-medium.rst:5 +msgid "sd3-medium" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:7 +msgid "**Model Name:** sd3-medium" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:9 +msgid "**Abilities:** text2image, image2image" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:15 +msgid "**Model ID:** stabilityai/stable-diffusion-3-medium-diffusers" +msgstr "" + +#: ../../source/models/builtin/image/sd3-medium.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sdxl-turbo.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sdxl-turbo.po new file mode 100644 index 0000000000..01cc607778 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/sdxl-turbo.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:5 +msgid "sdxl-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:7 +msgid "**Model Name:** sdxl-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:9 +msgid "**Abilities:** text2image" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:15 +msgid "**Model ID:** stabilityai/sdxl-turbo" +msgstr "" + +#: ../../source/models/builtin/image/sdxl-turbo.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-2-inpainting.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-2-inpainting.po new file mode 100644 index 0000000000..08518a4c3b --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-2-inpainting.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-28 22:01+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:5 +msgid "stable-diffusion-2-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:7 +msgid "**Model Name:** stable-diffusion-2-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:9 +msgid "**Abilities:** inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:15 +msgid "**Model ID:** stabilityai/stable-diffusion-2-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-2-inpainting.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-inpainting.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-inpainting.po new file mode 100644 index 0000000000..d015dc4cb7 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-inpainting.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-28 22:01+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:5 +msgid "stable-diffusion-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:7 +msgid "**Model Name:** stable-diffusion-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:9 +msgid "**Abilities:** inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:15 +msgid "**Model ID:** runwayml/stable-diffusion-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-inpainting.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-v1.5.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-v1.5.po new file mode 100644 index 0000000000..7c377fe935 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-v1.5.po @@ -0,0 +1,55 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:5 +msgid "stable-diffusion-v1.5" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:7 +msgid "**Model Name:** stable-diffusion-v1.5" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:9 +msgid "**Abilities:** text2image, image2image" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:10 +msgid "" +"**Available ControlNet:** ['canny', 'mlsd', 'hed', 'scribble', " +"'openpose', 'normal', 'seg']" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:15 +msgid "**Model ID:** runwayml/stable-diffusion-v1-5" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-v1.5.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-base-1.0.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-base-1.0.po new file mode 100644 index 0000000000..8ea547b71c --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-base-1.0.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:5 +msgid "stable-diffusion-xl-base-1.0" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:7 +msgid "**Model Name:** stable-diffusion-xl-base-1.0" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:9 +msgid "**Abilities:** text2image, image2image" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:10 +msgid "**Available ControlNet:** ['canny', 'depth', 'zoe-depth']" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:15 +msgid "**Model ID:** stabilityai/stable-diffusion-xl-base-1.0" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-base-1.0.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-inpainting.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-inpainting.po new file mode 100644 index 0000000000..abb05df510 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/image/stable-diffusion-xl-inpainting.po @@ -0,0 +1,53 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-28 22:01+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:5 +msgid "stable-diffusion-xl-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:7 +msgid "**Model Name:** stable-diffusion-xl-inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:8 +msgid "**Model Family:** stable_diffusion" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:9 +msgid "**Abilities:** inpainting" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:10 +msgid "**Available ControlNet:** None" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:13 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:15 +msgid "**Model ID:** diffusers/stable-diffusion-xl-1.0-inpainting-0.1" +msgstr "" + +#: ../../source/models/builtin/image/stable-diffusion-xl-inpainting.rst:17 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/cogvideox-2b.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/cogvideox-2b.po new file mode 100644 index 0000000000..5653fa0839 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/cogvideox-2b.po @@ -0,0 +1,49 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-13 17:44+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:5 +msgid "CogVideoX-2b" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:7 +msgid "**Model Name:** CogVideoX-2b" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:8 +msgid "**Model Family:** CogVideoX" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:9 +msgid "**Abilities:** text2video" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:12 +msgid "Specifications" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:14 +msgid "**Model ID:** THUDM/CogVideoX-2b" +msgstr "" + +#: ../../source/models/builtin/video/cogvideox-2b.rst:16 +msgid "Execute the following command to launch the model::" +msgstr "" + diff --git a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/index.po similarity index 51% rename from doc/source/locale/ja_JP/LC_MESSAGES/getting_started/index.po rename to doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/index.po index ceb70ed3ef..436fa8d3ec 100644 --- a/doc/source/locale/ja_JP/LC_MESSAGES/getting_started/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/builtin/video/index.po @@ -1,25 +1,29 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) 2023, Xorbits Inc. # This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. +# FIRST AUTHOR , 2024. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-10-16 10:33+0800\n" +"POT-Creation-Date: 2024-08-13 17:44+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language: ja_JP\n" -"Language-Team: ja_JP \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" "Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.14.0\n" -#: ../../source/getting_started/index.rst:5 -msgid "Getting Started" -msgstr "" +#: ../../source/models/builtin/video/index.rst:5 +msgid "Video Models" +msgstr "视频模型" + +#: ../../source/models/builtin/video/index.rst:7 +msgid "The following is a list of built-in video models in Xinference:" +msgstr "以下是 Xinference 中内置的视频模型列表:" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/custom.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/custom.po index c7505111b1..03a7e356cd 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/custom.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/custom.po @@ -3,12 +3,11 @@ # This file is distributed under the same license as the Xinference package. # FIRST AUTHOR , 2023. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-05 16:10+0800\n" +"POT-Creation-Date: 2024-08-15 11:39+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -29,15 +28,50 @@ msgid "" "manage, and utilize custom models." msgstr "Xinference 提供了一种灵活而全面的方式来集成、管理和应用自定义模型。" -#: ../../source/models/custom.rst:9 +#: ../../source/models/custom.rst:10 +msgid "Directly launch an existing model" +msgstr "无需注册而直接启动自定义模型" + +#: ../../source/models/custom.rst:11 +msgid "" +"Since ``v0.14.0``, you can directly launch an existing model by passing " +"``model_path`` to the launch interface without downloading it. This way " +"requires that the model's ``model_family`` is among the built-in " +"supported models, and eliminates the hassle of registering the model." +msgstr "" +"从 ``v0.14.0`` 版本开始,如果你需要注册的模型的家族是 Xinference 内置支持" +"的模型,你可以直接通过 launch 接口中的 ``model_path`` 参数来启动它,从而" +"免去注册步骤的麻烦。现在非常推荐使用这种方式。" + +#: ../../source/models/custom.rst:15 +msgid "For example:" +msgstr "例如:" + +#: ../../source/models/custom.rst:47 +msgid "" +"The above example demonstrates how to directly launch a qwen1.5-chat " +"model file without registering it." +msgstr "上面的例子展示了当我已有 qwen1.5-chat 模型文件时,如何直接 launch 它。" + +#: ../../source/models/custom.rst:49 +msgid "" +"For distributed scenarios, if your model file is on a specific worker, " +"you can directly launch it using the ``worker_ip`` and ``model_path`` " +"parameters with the launch interface." +msgstr "" +"对于分布式场景,将你的模型文件置于某个 worker ,然后通过 launch 接口的 ``" +"worker_ip`` 和 ``model_path`` 参数来达到直接 launch 的效果。" + +#: ../../source/models/custom.rst:53 msgid "Define a custom LLM model" msgstr "定义自定义大语言模型" -#: ../../source/models/custom.rst:11 +#: ../../source/models/custom.rst:55 msgid "Define a custom LLM model based on the following template:" msgstr "基于以下模板定义一个自定义大语言模型:" -#: ../../source/models/custom.rst:52 ../../source/models/custom.rst:181 +#: ../../source/models/custom.rst:96 ../../source/models/custom.rst:225 +#: ../../source/models/custom.rst:248 msgid "" "model_name: A string defining the name of the model. The name must start " "with a letter or a digit and can only contain letters, digits, " @@ -46,7 +80,7 @@ msgstr "" "model_name: 模型名称。名称必须以字母或数字开头,且只能包含字母、数字、" "下划线或短划线。" -#: ../../source/models/custom.rst:53 +#: ../../source/models/custom.rst:97 msgid "" "context_length: context_length: An optional integer that specifies the " "maximum context size the model was trained to accommodate, encompassing " @@ -56,7 +90,7 @@ msgstr "" "context_length: 一个可选的整数,模型支持的最大上下文长度,包括输入和输出" "长度。如果未定义,默认值为2048个token(约1,500个词)。" -#: ../../source/models/custom.rst:54 +#: ../../source/models/custom.rst:98 msgid "" "model_lang: A list of strings representing the supported languages for " "the model. Example: [\"en\"], which means that the model supports " @@ -65,7 +99,7 @@ msgstr "" "model_lang: 一个字符串列表,表示模型支持的语言。例如:['en'],表示该模型" "支持英语。" -#: ../../source/models/custom.rst:55 +#: ../../source/models/custom.rst:99 msgid "" "model_ability: A list of strings defining the abilities of the model. It " "could include options like \"embed\", \"generate\", and \"chat\". In this" @@ -74,7 +108,7 @@ msgstr "" "model_ability: 一个字符串列表,定义模型的能力。它可以包括像 'embed'、'" "generate' 和 'chat' 这样的选项。示例表示模型具有 'generate' 的能力。" -#: ../../source/models/custom.rst:56 +#: ../../source/models/custom.rst:100 msgid "" "model_family: A required string representing the family of the model you " "want to register. The optional values are the model names of all :ref" @@ -83,40 +117,42 @@ msgid "" " Note that you should choose the model family based on the ability of the" " model you want to register. For example, if you want to register the " "``llama-2`` model, do not fill in ``llama-2-chat`` as the model family." -msgstr "model_family: 必需字段,表示你要注册的模型的家族(类别)。" -"可选值来自于 Xinference :ref:`所有内置模型的模型名 `。如果你要注册的模型不在其中,填入 ``other`` 。" -"注意,此字段的值必须根据模型能力填入。例如,如果你注册的是自定义 ``llama-2`` 模型,千万不要填入 ``llama-2-chat`` 。" +msgstr "" +"model_family: 必需字段,表示你要注册的模型的家族(类别)。可选值来自于 " +"Xinference :ref:`所有内置模型的模型名 `。如果你要注册的" +"模型不在其中,填入 ``other`` 。注意,此字段的值必须根据模型能力填入。例如" +",如果你注册的是自定义 ``llama-2`` 模型,千万不要填入 ``llama-2-chat`` 。" -#: ../../source/models/custom.rst:62 +#: ../../source/models/custom.rst:106 msgid "" "model_specs: An array of objects defining the specifications of the " "model. These include:" msgstr "model_specs: 一个包含定义模型规格的对象数组。这些规格包括:" -#: ../../source/models/custom.rst:58 +#: ../../source/models/custom.rst:102 msgid "" -"model_format: A string that defines the model format, could be " -"\"pytorch\" or \"ggmlv3\"." -msgstr "model_format: 一个定义模型格式的字符串,可以是 'pytorch' 或 'ggmlv3'。" +"model_format: A string that defines the model format, like \"pytorch\" or" +" \"ggufv2\"." +msgstr "model_format: 一个定义模型格式的字符串,可以是 'pytorch' 或 'ggufv2'。" -#: ../../source/models/custom.rst:59 +#: ../../source/models/custom.rst:103 msgid "" "model_size_in_billions: An integer defining the size of the model in " "billions of parameters." msgstr "model_size_in_billions: 一个整数,定义模型的参数量,以十亿为单位。" -#: ../../source/models/custom.rst:60 +#: ../../source/models/custom.rst:104 msgid "" "quantizations: A list of strings defining the available quantizations for" " the model. For PyTorch models, it could be \"4-bit\", \"8-bit\", or " -"\"none\". For ggmlv3 models, the quantizations should correspond to " +"\"none\". For ggufv2 models, the quantizations should correspond to " "values that work with the ``model_file_name_template``." msgstr "" "quantizations: 一个字符串列表,定义模型的量化方式。对于 PyTorch 模型,它" -"可以是 \"4-bit\"、\"8-bit\" 或 \"none\"。对于 ggmlv3 模型,量化方式应与 `" +"可以是 \"4-bit\"、\"8-bit\" 或 \"none\"。对于 ggufv2 模型,量化方式应与 `" "`model_file_name_template`` 中的值对应。" -#: ../../source/models/custom.rst:61 +#: ../../source/models/custom.rst:105 msgid "" "model_id: A string representing the model ID, possibly referring to an " "identifier used by Hugging Face. **If model_uri is missing, Xinference " @@ -127,32 +163,31 @@ msgstr "" "如果 model_uri 字段缺失,Xinference 将尝试从此id指示的HuggingFace仓库下载" "该模型。" -#: ../../source/models/custom.rst:62 +#: ../../source/models/custom.rst:106 msgid "" "model_uri: A string representing the URI where the model can be loaded " "from, such as \"file:///path/to/llama-2-7b\". **When the model format is " -"ggmlv3 or ggufv2, model_uri must be the specific file path. When the " -"model format is pytorch, model_uri must be the path to the directory " -"containing the model files.** If model URI is absent, Xinference will try" -" to download the model from Hugging Face with the model ID." +"ggufv2, model_uri must be the specific file path. When the model format " +"is pytorch, model_uri must be the path to the directory containing the " +"model files.** If model URI is absent, Xinference will try to download " +"the model from Hugging Face with the model ID." msgstr "" "model_uri:表示模型文件位置的字符串,例如本地目录:\"file:///path/to/" -"llama-2-7b\"。当 model_format 是 ggmlv3 或者 ggufv2 ,此字段必须是具体的" +"llama-2-7b\"。当 model_format 是 ggufv2 ,此字段必须是具体的" "模型文件路径。而当 model_format 是 pytorch 时,此字段必须是一个包含所有" "模型文件的目录。" -#: ../../source/models/custom.rst:63 +#: ../../source/models/custom.rst:107 msgid "" -"model_file_name_template: Required by ggml/gguf models. An f-string " -"template used for defining the model file name based on the quantization." -" **Note that this field is just a template for the format of the " -"ggmlv3/ggufv2 model file, do not fill in the specific path of the model " -"file.**" +"model_file_name_template: Required by gguf models. An f-string template " +"used for defining the model file name based on the quantization. **Note " +"that this field is just a template for the format of the ggufv2 model " +"file, do not fill in the specific path of the model file.**" msgstr "" -"model_file_name_template: ggml 模型所需。一个 f-string 模板,用于根据量化" +"model_file_name_template: gguf 模型所需。一个 f-string 模板,用于根据量化" "定义模型文件名。注意,这里不要填入文件的路径。" -#: ../../source/models/custom.rst:64 +#: ../../source/models/custom.rst:108 msgid "" "prompt_style: If the ``model_family`` field is not ``other``, this field " "does not need to be filled in. ``prompt_style`` is an optional field that" @@ -162,36 +197,37 @@ msgid "" "can also specify this field as a string, which will use the builtin " "prompt style in Xinference. For example:" msgstr "" -"prompt_style: 如果上述 ``model_family`` 字段不是 ``other`` ,则无需设置此字段。 ``prompt_style`` 是一个可选字段,表示 ``chat`` 模型需要的提示词样式。给定的示例将" -"其设置为 None,但可以在引用的文件 xinference/model/llm/tests/test_utils." -"py 中找到更多详细信息。你也可以指定一个字符串,以使用内置模型的提示词样式" -"。" +"prompt_style: 如果上述 ``model_family`` 字段不是 ``other`` ,则无需设置" +"此字段。 ``prompt_style`` 是一个可选字段,表示 ``chat`` 模型需要的提示词" +"样式。给定的示例将其设置为 None,但可以在引用的文件 xinference/model/llm/" +"tests/test_utils.py 中找到更多详细信息。你也可以指定一个字符串,以使用" +"内置模型的提示词样式。" -#: ../../source/models/custom.rst:73 +#: ../../source/models/custom.rst:117 msgid "Xinference supports these builtin prompt styles in common usage:" msgstr "Xinference 支持这些内置、常用的提示词样式:" -#: ../../source/models/custom.rst:77 +#: ../../source/models/custom.rst:121 msgid "baichuan-chat" msgstr "" -#: ../../source/models/custom.rst:96 +#: ../../source/models/custom.rst:140 msgid "chatglm3" msgstr "" -#: ../../source/models/custom.rst:109 +#: ../../source/models/custom.rst:153 msgid "qwen-chat" msgstr "" -#: ../../source/models/custom.rst:126 +#: ../../source/models/custom.rst:170 msgid "llama-2-chat" msgstr "" -#: ../../source/models/custom.rst:147 +#: ../../source/models/custom.rst:191 msgid "vicuna-v1.5" msgstr "" -#: ../../source/models/custom.rst:162 +#: ../../source/models/custom.rst:206 msgid "" "The above lists some commonly used built-in prompt styles. The full list " "of supported prompt styles can be found on the Xinference web UI." @@ -199,25 +235,25 @@ msgstr "" "以上列举出了最常使用的提示词样式。完整的支持列表可以通过 Xinference 页面" "的 register model 面板查看。" -#: ../../source/models/custom.rst:166 +#: ../../source/models/custom.rst:210 msgid "Define a custom embedding model" msgstr "定义自定义 embedding 模型" -#: ../../source/models/custom.rst:168 +#: ../../source/models/custom.rst:212 msgid "Define a custom embedding model based on the following template:" msgstr "基于以下模板定义一个自定义 embedding 模型:" -#: ../../source/models/custom.rst:182 +#: ../../source/models/custom.rst:226 msgid "dimensions: A integer that specifies the embedding dimensions." msgstr "dimensions: 表示 embedding 维度的整型值。" -#: ../../source/models/custom.rst:183 +#: ../../source/models/custom.rst:227 msgid "" "max_tokens: A integer that represents the max sequence length that the " "embedding model supports." msgstr "max_tokens: 表示 embedding 模型支持的最大输入序列长度的整型值。" -#: ../../source/models/custom.rst:184 +#: ../../source/models/custom.rst:228 ../../source/models/custom.rst:250 msgid "" "language: A list of strings representing the supported languages for the " "model. Example: [\"en\"], which means that the model supports English." @@ -225,7 +261,7 @@ msgstr "" "model_lang: 一个字符串列表,表示模型支持的语言。例如:['en'],表示该模型" "支持英语。" -#: ../../source/models/custom.rst:185 +#: ../../source/models/custom.rst:229 ../../source/models/custom.rst:251 msgid "" "model_id: A string representing the model ID, possibly referring to an " "identifier used by Hugging Face." @@ -233,7 +269,7 @@ msgstr "" "model_id: 一个表示模型标识的字符串,类似 HuggingFace 或 ModelScope 使用的" "标识符。" -#: ../../source/models/custom.rst:186 +#: ../../source/models/custom.rst:230 ../../source/models/custom.rst:252 msgid "" "model_uri: A string representing the URI where the model can be loaded " "from, such as \"file:///path/to/your_model\". If model URI is absent, " @@ -244,62 +280,80 @@ msgstr "" "如果模型 URI 不存在,Xinference 将尝试使用 model_id 从 HuggingFace 或 " "ModelScope 下载模型。" -#: ../../source/models/custom.rst:189 +#: ../../source/models/custom.rst:234 +msgid "Define a custom Rerank model" +msgstr "定义自定义 rerank 模型" + +#: ../../source/models/custom.rst:236 +msgid "Define a custom rerank model based on the following template:" +msgstr "基于以下模板定义一个自定义大语言模型:" + +#: ../../source/models/custom.rst:249 +msgid "" +"type: A string defining the type of the model, including ``normal``, " +"``LLM-based`` and ``LLM-based layerwise``." +msgstr "" +"type: 表示模型的类型,可选值包括 ``normal``、``LLM-based`` 和 ``LLM-based" +" layerwise``。" + +#: ../../source/models/custom.rst:256 msgid "Register a Custom Model" msgstr "注册一个自定义模型" -#: ../../source/models/custom.rst:191 +#: ../../source/models/custom.rst:258 msgid "Register a custom model programmatically:" msgstr "以代码的方式注册自定义模型" -#: ../../source/models/custom.rst:206 ../../source/models/custom.rst:224 -#: ../../source/models/custom.rst:239 ../../source/models/custom.rst:294 +#: ../../source/models/custom.rst:273 ../../source/models/custom.rst:291 +#: ../../source/models/custom.rst:306 ../../source/models/custom.rst:361 msgid "Or via CLI:" msgstr "以命令行的方式" -#: ../../source/models/custom.rst:212 +#: ../../source/models/custom.rst:279 msgid "" -"Note that replace the ```` above with ``LLM`` or " -"``embedding``. The same as below." -msgstr "注意将以下部分的 ```` 替换为 ``LLM`` 或者 ``embedding`` 。" +"Note that replace the ```` above with ``LLM``, ``embedding`` " +"or ``rerank``. The same as below." +msgstr "" +"注意将以下部分的 ```` 替换为 ``LLM``、``embedding`` 或 ``" +"rerank`` 。" -#: ../../source/models/custom.rst:216 +#: ../../source/models/custom.rst:283 msgid "List the Built-in and Custom Models" msgstr "列举内置和自定义模型" -#: ../../source/models/custom.rst:218 +#: ../../source/models/custom.rst:285 msgid "List built-in and custom models programmatically:" msgstr "以代码的方式列举内置和自定义模型" -#: ../../source/models/custom.rst:231 +#: ../../source/models/custom.rst:298 msgid "Launch the Custom Model" msgstr "启动自定义模型" -#: ../../source/models/custom.rst:233 +#: ../../source/models/custom.rst:300 msgid "Launch the custom model programmatically:" msgstr "以代码的方式启动自定义模型" -#: ../../source/models/custom.rst:246 +#: ../../source/models/custom.rst:313 msgid "Interact with the Custom Model" msgstr "使用自定义模型" -#: ../../source/models/custom.rst:248 +#: ../../source/models/custom.rst:315 msgid "Invoke the model programmatically:" msgstr "以代码的方式调用模型" -#: ../../source/models/custom.rst:255 +#: ../../source/models/custom.rst:322 msgid "Result:" msgstr "结果为:" -#: ../../source/models/custom.rst:279 +#: ../../source/models/custom.rst:346 msgid "Or via CLI, replace ``${UID}`` with real model UID:" msgstr "或者以命令行的方式,用实际的模型 UID 替换 ``${UID}``:" -#: ../../source/models/custom.rst:286 +#: ../../source/models/custom.rst:353 msgid "Unregister the Custom Model" msgstr "注销自定义模型" -#: ../../source/models/custom.rst:288 +#: ../../source/models/custom.rst:355 msgid "Unregister the custom model programmatically:" msgstr "以代码的方式注销自定义模型" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/index.po index 222ece7826..d3951e82e0 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/index.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-07 17:52+0800\n" +"POT-Creation-Date: 2024-08-13 17:44+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/models/index.rst:5 msgid "Models" @@ -77,7 +77,15 @@ msgstr "" msgid "Rerank models" msgstr "重排序模型" -#: ../../source/models/index.rst:69 +#: ../../source/models/index.rst:67 +msgid "video" +msgstr "" + +#: ../../source/models/index.rst:71 +msgid "Video models" +msgstr "视频模型" + +#: ../../source/models/index.rst:75 msgid "" "You can see all the built-in models supported by xinference :ref:`here " "`. If the model you need is not available, " @@ -88,11 +96,11 @@ msgstr "" "内置模型。如果你需要的模型不可用,Xinference 还允许你注册自己的 :ref:`" "自定义模型 `。" -#: ../../source/models/index.rst:74 +#: ../../source/models/index.rst:80 msgid "Launch and Terminate Model" msgstr "启动和停止模型" -#: ../../source/models/index.rst:76 +#: ../../source/models/index.rst:82 msgid "" "Each running model instance will be assigned a unique model uid. By " "default, the model uid is equal to the model name. This unique id can be " @@ -103,91 +111,99 @@ msgstr "" "名。这个 ID 是后续使用模型实例的句柄,启动命令 ``--model-uid`` 选项可以" "手动指定它。" -#: ../../source/models/index.rst:80 +#: ../../source/models/index.rst:86 msgid "" "You can launch a model in Xinference either via command line or " "Xinference's Python client:" msgstr "你可以通过命令行或者 Xinference 的 Python 客户端来启动一个模型。" -#: ../../source/models/index.rst:105 +#: ../../source/models/index.rst:113 msgid "" "For model type ``LLM``, launching the model requires not only specifying " -"the model name, but also the size of the parameters and the model format." -" Please refer to the list of LLM :ref:`model families " -"`." +"the model name, but also the size of the parameters , the model format " +"and the model engine. Please refer to the list of LLM :ref:`model " +"families `." msgstr "" -"对于模型类型 ``LLM``,启动模型不仅需要指定模型名称,还需要参数的大小和" -"模型格式。请参考 :ref:`models_llm_index` 文档。" +"对于模型类型 ``LLM``,启动模型不仅需要指定模型名称,还需要参数的大小、" +"模型格式以及模型引擎。请参考 :ref:`models_llm_index` 文档。" -#: ../../source/models/index.rst:108 +#: ../../source/models/index.rst:116 msgid "" "The following command gives you the currently running models in " "Xinference:" msgstr "以下命令可以列出 Xinference 中正在运行的模型:" -#: ../../source/models/index.rst:129 +#: ../../source/models/index.rst:137 msgid "" "When you no longer need a model that is currently running, you can remove" " it in the following way to free up the resources it occupies:" msgstr "当你不再需要当前正在运行的模型时,以下列方式释放其占用的资源:" -#: ../../source/models/index.rst:153 +#: ../../source/models/index.rst:161 msgid "Model Usage" msgstr "模型使用" -#: ../../source/models/index.rst:158 +#: ../../source/models/index.rst:166 msgid "Chat & Generate" msgstr "聊天 & 生成" -#: ../../source/models/index.rst:162 +#: ../../source/models/index.rst:170 msgid "Learn how to chat with LLMs in Xinference." msgstr "学习如何在 Xinference 中与 LLM聊天。" -#: ../../source/models/index.rst:164 +#: ../../source/models/index.rst:172 msgid "Tools" msgstr "工具" -#: ../../source/models/index.rst:168 +#: ../../source/models/index.rst:176 msgid "Learn how to connect LLM with external tools." msgstr "学习如何将 LLM 与外部工具连接起来。" -#: ../../source/models/index.rst:173 +#: ../../source/models/index.rst:181 msgid "Embeddings" msgstr "嵌入" -#: ../../source/models/index.rst:177 +#: ../../source/models/index.rst:185 msgid "Learn how to create text embeddings in Xinference." msgstr "学习如何在 Xinference 中创建文本嵌入。" -#: ../../source/models/index.rst:179 +#: ../../source/models/index.rst:187 msgid "Rerank" msgstr "重排序" -#: ../../source/models/index.rst:183 +#: ../../source/models/index.rst:191 msgid "Learn how to use rerank models in Xinference." msgstr "学习如何在 Xinference 中使用重排序模型。" -#: ../../source/models/index.rst:188 +#: ../../source/models/index.rst:196 msgid "Images" msgstr "图像" -#: ../../source/models/index.rst:192 +#: ../../source/models/index.rst:200 msgid "Learn how to generate images with Xinference." msgstr "学习如何使用Xinference生成图像。" -#: ../../source/models/index.rst:194 +#: ../../source/models/index.rst:202 msgid "Vision" msgstr "视觉" -#: ../../source/models/index.rst:198 +#: ../../source/models/index.rst:206 msgid "Learn how to process image with LLMs." msgstr "学习如何使用 LLM 处理图像。" -#: ../../source/models/index.rst:203 +#: ../../source/models/index.rst:211 msgid "Audio" msgstr "音频" -#: ../../source/models/index.rst:207 +#: ../../source/models/index.rst:215 msgid "Learn how to turn audio into text or text into audio with Xinference." msgstr "学习如何使用 Xinference 将音频转换为文本或将文本转换为音频。" +#: ../../source/models/index.rst:217 +msgid "Video" +msgstr "视频" + +#: ../../source/models/index.rst:221 +msgid "Learn how to generate video with Xinference." +msgstr "学习如何使用Xinference生成视频。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/lora.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/lora.po index 7d603622f8..5d2133c6c4 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/lora.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/lora.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-08 12:40+0800\n" +"POT-Creation-Date: 2024-05-16 14:18+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,27 +25,47 @@ msgstr "集成LoRA" msgid "" "Currently, Xinference supports launching ``LLM`` and ``image`` models " "with an attached LoRA fine-tuned model." -msgstr "当前,Xinference 可以在启动 ``LLM`` 和 ``image`` 模型时连带一个 LoRA 微调模型用以辅助基础模型。" +msgstr "" +"当前,Xinference 可以在启动 ``LLM`` 和 ``image`` 模型时连带一个 LoRA 微调" +"模型用以辅助基础模型。" #: ../../source/models/lora.rst:10 msgid "Usage" msgstr "使用方式" -#: ../../source/models/lora.rst:11 +#: ../../source/models/lora.rst:13 +msgid "Launch" +msgstr "启动" + +#: ../../source/models/lora.rst:14 msgid "" "Different from built-in models, xinference currently does not involve " "managing LoRA models. Users need to first download the LoRA model " "themselves and then provide the storage path of the model files to " "xinference." msgstr "" -"不同于内置模型,Xinference 目前不会涉及管理 LoRA 模型。用户需要首先下载对应的 LoRA 模型," -"然后将模型存储路径提供给 Xinference 。" +"不同于内置模型,Xinference 目前不会涉及管理 LoRA 模型。用户需要首先下载" +"对应的 LoRA 模型,然后将模型存储路径提供给 Xinference 。" + +#: ../../source/models/lora.rst:54 +msgid "Apply" +msgstr "应用" + +#: ../../source/models/lora.rst:55 +msgid "" +"For LLM models, you can only configure one lora model you want when you " +"use the model. Specifically, specify that the ``lora_name`` parameter be " +"configured in the ``generate_config``. ``lora_name`` corresponds to the " +"name of the lora in the LAUNCH procedure described above." +msgstr "" +"对于大语言模型,使用时指定其中一个 lora 。具体地,在 ``generate_config`` 参数中配置 ``lora_name`` 参数。" +"``lora_name`` 对应 launch 过程中你的配置。" -#: ../../source/models/lora.rst:38 +#: ../../source/models/lora.rst:75 msgid "Note" msgstr "注意事项" -#: ../../source/models/lora.rst:40 +#: ../../source/models/lora.rst:77 msgid "" "The options ``image_lora_load_kwargs`` and ``image_lora_fuse_kwargs`` are" " only applicable to models with model_type ``image``. They correspond to " @@ -53,18 +73,27 @@ msgid "" "of the ``diffusers`` library. If launching an LLM model, these parameters" " are not required." msgstr "" -"上述 ``image_lora_load_kwargs`` 和 ``image_lora_fuse_kwargs`` 选项只应用于 ``image`` 模型。它们对应" -"于 ``diffusers`` 库的 ``load_lora_weights`` 和 ``fuse_lora`` 接口中的额外参数。" -"如果启动的是 ``LLM`` 模型,则无需设置这些选项。" +"上述 ``image_lora_load_kwargs`` 和 ``image_lora_fuse_kwargs`` 选项只应用" +"于 ``image`` 模型。它们对应于 ``diffusers`` 库的 ``load_lora_weights`` 和" +" ``fuse_lora`` 接口中的额外参数。如果启动的是 ``LLM`` 模型,则无需设置" +"这些选项。" -#: ../../source/models/lora.rst:44 +#: ../../source/models/lora.rst:81 +msgid "" +"You need to add the parameter lora_name during inference to specify the " +"corresponding lora model. You can specify it in the Additional Inputs " +"option." +msgstr "" + +#: ../../source/models/lora.rst:83 msgid "" "For LLM chat models, currently only LoRA models are supported that do not" " change the prompt style." msgstr "" -"对于 ``LLM`` 聊天模型,当前仅支持那些微调后不更改原始基础模型的提示词模版的 LoRA 模型。" +"对于 ``LLM`` 聊天模型,当前仅支持那些微调后不更改原始基础模型的提示词模版" +"的 LoRA 模型。" -#: ../../source/models/lora.rst:46 +#: ../../source/models/lora.rst:85 msgid "When using GPU, both LoRA and its base model occupy the same devices." -msgstr "" -"使用 GPU 时,LoRA 模型与其基础模型在同样的设备上,不会对其他模型造成影响。" +msgstr "使用 GPU 时,LoRA 模型与其基础模型在同样的设备上,不会对其他模型造成影响。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/audio.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/audio.po index 04bb51a3e3..55072b6766 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/audio.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/audio.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-01 16:47+0800\n" +"POT-Creation-Date: 2024-08-18 19:26+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/models/model_abilities/audio.rst:5 msgid "Audio (Experimental)" @@ -32,8 +32,8 @@ msgid "Introduction" msgstr "介绍" #: ../../source/models/model_abilities/audio.rst:14 -msgid "The Audio API provides two methods for interacting with audio:" -msgstr "Audio API提供了两种与音频交互的方法:" +msgid "The Audio API provides three methods for interacting with audio:" +msgstr "Audio API提供了三种与音频交互的方法:" #: ../../source/models/model_abilities/audio.rst:17 msgid "The transcriptions endpoint transcribes audio into the input language." @@ -43,93 +43,229 @@ msgstr "转录终端将音频转录为输入语言。" msgid "The translations endpoint translates audio into English." msgstr "翻译端点将音频转换为英文。" -#: ../../source/models/model_abilities/audio.rst:25 +#: ../../source/models/model_abilities/audio.rst:19 +msgid "The speech endpoint generates audio from the input text." +msgstr "转录终端将音频转录为输入语言。" + +#: ../../source/models/model_abilities/audio.rst:26 msgid "API ENDPOINT" msgstr "API 端点" -#: ../../source/models/model_abilities/audio.rst:26 +#: ../../source/models/model_abilities/audio.rst:27 msgid "OpenAI-compatible ENDPOINT" msgstr "OpenAI 兼容端点" -#: ../../source/models/model_abilities/audio.rst:28 +#: ../../source/models/model_abilities/audio.rst:29 msgid "Transcription API" msgstr "" -#: ../../source/models/model_abilities/audio.rst:29 +#: ../../source/models/model_abilities/audio.rst:30 msgid "/v1/audio/transcriptions" msgstr "" -#: ../../source/models/model_abilities/audio.rst:31 +#: ../../source/models/model_abilities/audio.rst:32 msgid "Translation API" msgstr "" -#: ../../source/models/model_abilities/audio.rst:32 +#: ../../source/models/model_abilities/audio.rst:33 msgid "/v1/audio/translations" msgstr "" #: ../../source/models/model_abilities/audio.rst:35 +msgid "Speech API" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:36 +msgid "/v1/audio/speech" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:40 msgid "Supported models" msgstr "支持的模型列表" -#: ../../source/models/model_abilities/audio.rst:37 +#: ../../source/models/model_abilities/audio.rst:42 msgid "The audio API is supported with the following models in Xinference:" msgstr "在Xinference中,以下模型支持音频API:" -#: ../../source/models/model_abilities/audio.rst:39 +#: ../../source/models/model_abilities/audio.rst:45 +msgid "Audio to text" +msgstr "语音转文本" + +#: ../../source/models/model_abilities/audio.rst:47 msgid "whisper-tiny" msgstr "" -#: ../../source/models/model_abilities/audio.rst:40 +#: ../../source/models/model_abilities/audio.rst:48 msgid "whisper-tiny.en" msgstr "" -#: ../../source/models/model_abilities/audio.rst:41 +#: ../../source/models/model_abilities/audio.rst:49 msgid "whisper-base" msgstr "" -#: ../../source/models/model_abilities/audio.rst:42 +#: ../../source/models/model_abilities/audio.rst:50 msgid "whisper-base.en" msgstr "" -#: ../../source/models/model_abilities/audio.rst:43 +#: ../../source/models/model_abilities/audio.rst:51 msgid "whisper-medium" msgstr "" -#: ../../source/models/model_abilities/audio.rst:44 +#: ../../source/models/model_abilities/audio.rst:52 msgid "whisper-medium.en" msgstr "" -#: ../../source/models/model_abilities/audio.rst:45 +#: ../../source/models/model_abilities/audio.rst:53 msgid "whisper-large-v3" msgstr "" -#: ../../source/models/model_abilities/audio.rst:49 +#: ../../source/models/model_abilities/audio.rst:54 +msgid "Belle-distilwhisper-large-v2-zh" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:55 +msgid "Belle-whisper-large-v2-zh" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:56 +msgid "Belle-whisper-large-v3-zh" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:57 +msgid "SenseVoiceSmall" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:61 +msgid "Text to audio" +msgstr "文本转语音" + +#: ../../source/models/model_abilities/audio.rst:63 +msgid "ChatTTS" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:64 +msgid "CosyVoice" +msgstr "" + +#: ../../source/models/model_abilities/audio.rst:67 msgid "Quickstart" msgstr "快速入门" -#: ../../source/models/model_abilities/audio.rst:52 +#: ../../source/models/model_abilities/audio.rst:70 msgid "Transcription" msgstr "转录" -#: ../../source/models/model_abilities/audio.rst:54 +#: ../../source/models/model_abilities/audio.rst:72 msgid "" "The Transcription API mimics OpenAI's `create transcriptions API " "`_. We can try Transcription API out " "either via cURL, OpenAI Client, or Xinference's python client:" -msgstr "Transcription API 模仿了 OpenAI 的 `create transcriptions API `_。" -"你可以通过 cURL、OpenAI Client 或者 Xinference 的 Python 客户端来尝试 Transcription API:" +msgstr "" +"Transcription API 模仿了 OpenAI 的 `create transcriptions API `_。你" +"可以通过 cURL、OpenAI Client 或者 Xinference 的 Python 客户端来尝试 " +"Transcription API:" -#: ../../source/models/model_abilities/audio.rst:105 +#: ../../source/models/model_abilities/audio.rst:123 msgid "Translation" msgstr "翻译" -#: ../../source/models/model_abilities/audio.rst:107 +#: ../../source/models/model_abilities/audio.rst:125 msgid "" "The Translation API mimics OpenAI's `create translations API " "`_. We can try Translation API out " "either via cURL, OpenAI Client, or Xinference's python client:" -msgstr "Translation API 模仿了 OpenAI 的 `create translations API `_。" -"你可以通过 cURL、OpenAI Client 或 Xinference 的 Python 客户端来尝试使用 Translation API:" +msgstr "" +"Translation API 模仿了 OpenAI 的 `create translations API `_。你可以" +"通过 cURL、OpenAI Client 或 Xinference 的 Python 客户端来尝试使用 " +"Translation API:" + +#: ../../source/models/model_abilities/audio.rst:175 +msgid "Speech" +msgstr "语音" + +#: ../../source/models/model_abilities/audio.rst:179 +msgid "" +"The Speech API mimics OpenAI's `create speech API " +"`_. We" +" can try Speech API out either via cURL, OpenAI Client, or Xinference's " +"python client:" +msgstr "" +"Transcription API 模仿了 OpenAI 的 `create speech API `_。你可以通过 cURL、" +"OpenAI Client 或者 Xinference 的 Python 客户端来尝试 Speech API:" + +#: ../../source/models/model_abilities/audio.rst:182 +msgid "Speech API use non-stream by default as" +msgstr "Speech API 默认使用非流式" + +#: ../../source/models/model_abilities/audio.rst:184 +msgid "" +"The stream output of ChatTTS is not as good as the non-stream output, " +"please refer to: https://github.com/2noise/ChatTTS/pull/564" +msgstr "" +"ChatTTS 的流式输出不如非流式的效果好,参考:https://github.com/2noise/" +"ChatTTS/pull/564" + +#: ../../source/models/model_abilities/audio.rst:185 +msgid "" +"The stream requires ffmpeg<7: " +"https://pytorch.org/audio/stable/installation.html#optional-dependencies" +msgstr "" +"流式要求 ffmpeg<7:https://pytorch.org/audio/stable/installation.html#" +"optional-dependencies" + +#: ../../source/models/model_abilities/audio.rst:237 +msgid "ChatTTS Usage" +msgstr "ChatTTS 使用" + +#: ../../source/models/model_abilities/audio.rst:239 +msgid "Basic usage, refer to :ref:`audio speech usage `." +msgstr "基本使用,参考 :ref:`语音使用章节 `。" + +#: ../../source/models/model_abilities/audio.rst:241 +msgid "" +"Fixed tone color. We can use fixed tone color provided by " +"https://github.com/6drf21e/ChatTTS_Speaker, Download the " +"`evaluation_result.csv " +"`_" +" , take ``seed_2155`` as example, we get the ``emb_data`` of it." +msgstr "" +"固定音色。我们可以使用由 https://github.com/6drf21e/ChatTTS_Speaker 提供" +"的固定音色,下载 `evaluation_result.csv `_ ,以 ``seed_2155`` " +"音色作为例子,我们使用 ``emb_data`` 列的数据。" + +#: ../../source/models/model_abilities/audio.rst:254 +msgid "Use the fixed tone color of ``seed_2155`` to generate speech." +msgstr "使用 ``seed_2155`` 固定音色来创建语音。" + +#: ../../source/models/model_abilities/audio.rst:270 +msgid "CosyVoice Usage" +msgstr "CosyVoice 模型使用" + +#: ../../source/models/model_abilities/audio.rst:272 +msgid "Basic usage, launch model ``CosyVoice-300M-SFT``." +msgstr "基本使用,加载模型 ``CosyVoice-300M-SFT``。" + +#: ../../source/models/model_abilities/audio.rst:321 +msgid "Clone voice, launch model ``CosyVoice-300M``." +msgstr "克隆声音,加载模型 ``CosyVoice-300M``。" + +#: ../../source/models/model_abilities/audio.rst:344 +msgid "Cross lingual usage, launch model ``CosyVoice-300M``." +msgstr "跨语言使用,加载模型 ``CosyVoice-300M``。" + +#: ../../source/models/model_abilities/audio.rst:363 +msgid "Instruction based, launch model ``CosyVoice-300M-Instruct``." +msgstr "基于指令的声音合成,加载模型 ``CosyVoice-300M-Instruct``。" + +#: ../../source/models/model_abilities/audio.rst:380 +msgid "" +"More instructions and examples, could be found at https://fun-audio-" +"llm.github.io/ ." +msgstr "更多指令和例子,可以参考 https://fun-audio-llm.github.io/ 。" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/image.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/image.po index f6ecd538ce..66b4935516 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/image.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/image.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-01 16:47+0800\n" +"POT-Creation-Date: 2024-08-09 19:13+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,11 +17,11 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/models/model_abilities/image.rst:5 -msgid "Images (Experimental)" -msgstr "图像(实验性质)" +msgid "Images" +msgstr "图像" #: ../../source/models/model_abilities/image.rst:7 msgid "Learn how to generate images with Xinference." @@ -97,35 +97,107 @@ msgstr "" msgid "stable-diffusion-xl-base-1.0" msgstr "" -#: ../../source/models/model_abilities/image.rst:46 +#: ../../source/models/model_abilities/image.rst:43 +msgid "sd3-medium" +msgstr "" + +#: ../../source/models/model_abilities/image.rst:44 +msgid "FLUX.1-schnell" +msgstr "" + +#: ../../source/models/model_abilities/image.rst:45 +msgid "FLUX.1-dev" +msgstr "" + +#: ../../source/models/model_abilities/image.rst:49 msgid "Quickstart" msgstr "快速入门" -#: ../../source/models/model_abilities/image.rst:49 +#: ../../source/models/model_abilities/image.rst:52 msgid "Text-to-image" msgstr "文生图" -#: ../../source/models/model_abilities/image.rst:51 +#: ../../source/models/model_abilities/image.rst:54 msgid "" "The Text-to-image API mimics OpenAI's `create images API " "`_. We can " "try Text-to-image API out either via cURL, OpenAI Client, or Xinference's" " python client:" -msgstr "可以通过 cURL、OpenAI Client 或 Xinference 的方式尝试使用 Text-to-image API。" +msgstr "" +"可以通过 cURL、OpenAI Client 或 Xinference 的方式尝试使用 Text-to-image " +"API。" + +#: ../../source/models/model_abilities/image.rst:109 +msgid "Tips for Large Image Models including SD3-Medium, FLUX.1" +msgstr "大型图像模型部署(sd3-medium、FLUX.1 系列)贴士" + +#: ../../source/models/model_abilities/image.rst:111 +msgid "Useful extra parameters can be passed to launch including:" +msgstr "有用的传递给加载模型的额外参数包括:" + +#: ../../source/models/model_abilities/image.rst:113 +msgid "" +"``--cpu_offload True``: specifying ``True`` will offload the components " +"of the model to CPU during inference in order to save memory, while " +"seeing a slight increase in inference latency. Model offloading will only" +" move a model component onto the GPU when it needs to be executed, while " +"keeping the remaining components on the CPU." +msgstr "" +"``--cpu_offload True``:指定 ``True`` 会在推理过程中将模型的组件卸载到 CPU 上以节省内存," +"这会导致推理延迟略有增加。模型卸载仅会在需要执行时将模型组件移动到 GPU 上,同时保持其余组件在 CPU 上" + +#: ../../source/models/model_abilities/image.rst:117 +msgid "" +"``--quantize_text_encoder ``: We leveraged the " +"``bitsandbytes`` library to load and quantize the T5-XXL text encoder to " +"8-bit precision. This allows you to keep using all text encoders " +"while only slightly impacting performance." +msgstr "``--quantize_text_encoder ``:我们利用 ``bitsandbytes`` 库" +"加载并量化 T5-XXL 文本编码器至8位精度。这使得你能够在仅轻微影响性能的情况下继续使用全部文本编码器。" + +#: ../../source/models/model_abilities/image.rst:120 +msgid "" +"``--text_encoder_3 None``, for sd3-medium, removing the memory-intensive " +"4.7B parameter T5-XXL text encoder during inference can significantly " +"decrease the memory requirements with only a slight loss in performance." +msgstr "" +"``--text_encoder_3 None``,对于 sd3-medium," +"移除在推理过程中内存密集型的47亿参数T5-XXL文本编码器可以显著降低内存需求,而仅造成性能上的轻微损失。" + +#: ../../source/models/model_abilities/image.rst:124 +msgid "" +"If you are trying to run large image models liek sd3-medium or FLUX.1 " +"series on GPU card that has less memory than 24GB, you may encounter OOM " +"when launching or inference. Try below solutions." +msgstr "如果你试图在显存小于24GB的GPU上运行像sd3-medium或FLUX.1系列这样的大型图像模型," +"你在启动或推理过程中可能会遇到显存溢出(OOM)的问题。尝试以下解决方案。" + +#: ../../source/models/model_abilities/image.rst:128 +msgid "For FLUX.1 series, try to apply quantization." +msgstr "对于 FLUX.1 系列,尝试应用量化。" + +#: ../../source/models/model_abilities/image.rst:134 +msgid "For sd3-medium, apply quantization to ``text_encoder_3``." +msgstr "对于 sd3-medium 模型,对 ``text_encoder_3`` 应用量化。" + +#: ../../source/models/model_abilities/image.rst:141 +msgid "Or removing memory-intensive T5-XXL text encoder for sd3-medium." +msgstr "或者,移除 sd3-medium 模型中内存密集型的 T5-XXL 文本编码器。" -#: ../../source/models/model_abilities/image.rst:107 +#: ../../source/models/model_abilities/image.rst:148 msgid "Image-to-image" msgstr "图生图" -#: ../../source/models/model_abilities/image.rst:109 +#: ../../source/models/model_abilities/image.rst:150 msgid "You can find more examples of Images API in the tutorial notebook:" msgstr "你可以在教程笔记本中找到更多 Images API 的示例。" -#: ../../source/models/model_abilities/image.rst:113 +#: ../../source/models/model_abilities/image.rst:154 msgid "Stable Diffusion ControlNet" msgstr "" -#: ../../source/models/model_abilities/image.rst:116 +#: ../../source/models/model_abilities/image.rst:157 msgid "Learn from a Stable Diffusion ControlNet example" msgstr "学习一个 Stable Diffusion 控制网络的示例" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/video.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/video.po new file mode 100644 index 0000000000..15660a07c4 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/video.po @@ -0,0 +1,101 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-13 17:44+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: ../../source/models/model_abilities/video.rst:5 +msgid "Video (Experimental)" +msgstr "视频(实验性质)" + +#: ../../source/models/model_abilities/video.rst:7 +msgid "Learn how to generate videos with Xinference." +msgstr "学习如何使用 Xinference 生成视频" + +#: ../../source/models/model_abilities/video.rst:11 +msgid "Introduction" +msgstr "介绍" + +#: ../../source/models/model_abilities/video.rst:14 +msgid "The Video API provides the ability to interact with videos:" +msgstr "Video API 提供了和视频交互的方式:" + +#: ../../source/models/model_abilities/video.rst:17 +msgid "" +"The text-to-video endpoint create videos from scratch based on a text " +"prompt." +msgstr "Text-to-video 端点将一段文本提示词从头开始创建视频" + +#: ../../source/models/model_abilities/video.rst:24 +msgid "API ENDPOINT" +msgstr "API 端点" + +#: ../../source/models/model_abilities/video.rst:25 +msgid "OpenAI-compatible ENDPOINT" +msgstr "OpenAI 兼容端点" + +#: ../../source/models/model_abilities/video.rst:27 +msgid "Text-to-Video API" +msgstr "" + +#: ../../source/models/model_abilities/video.rst:28 +msgid "/v1/video/generations" +msgstr "" + +#: ../../source/models/model_abilities/video.rst:31 +msgid "Supported models" +msgstr "支持的模型列表" + +#: ../../source/models/model_abilities/video.rst:33 +msgid "" +"The Text-to-video API is supported with the following models in " +"Xinference:" +msgstr "Text-to-video API 在 Xinference 中支持以下模型:" + +#: ../../source/models/model_abilities/video.rst:35 +msgid "CogVideoX-2b" +msgstr "" + +#: ../../source/models/model_abilities/video.rst:39 +msgid "Quickstart" +msgstr "快速入门" + +#: ../../source/models/model_abilities/video.rst:42 +msgid "Text-to-video" +msgstr "文生视频" + +#: ../../source/models/model_abilities/video.rst:44 +msgid "" +"You can try Text-to-video API out either via cURL, or Xinference's python" +" client:" +msgstr "可以通过 cURL 或 Xinference 的方式尝试使用 Text-to-video API" + +#: ../../source/models/model_abilities/video.rst:72 +msgid "Tips when running on GPU whose memory less than 24GB" +msgstr "在小于 24GB 显存的 GPU 上运行贴士" + +#: ../../source/models/model_abilities/video.rst:74 +msgid "" +"Text-to-video will occupy huge GPU memory, for instance, running " +"CogVideoX may require up to around 35 GB GPU memory. When running on GPU " +"whose memory is less than 24 GB, we recommend to add ``--cpu_offload " +"True`` when launching model." +msgstr "" +"Text-to-video 会占用大量显存,举例来说,运行 CogVideoX 可能会使用到约 35 GB 的显存," +"当在小于 24 GB 的 GPU 上运行时,推荐添加 ``--cpu_offload True`` 来加载模型。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/vision.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/vision.po index 0ed3e0bb7e..2da5ae6a84 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/vision.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_abilities/vision.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-01 16:47+0800\n" +"POT-Creation-Date: 2024-08-20 11:56+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.13.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/models/model_abilities/vision.rst:5 msgid "Vision" @@ -37,8 +37,9 @@ msgid "" "answer questions about them. Within Xinference, this indicates that " "certain models are capable of processing image inputs when conducting " "dialogues via the Chat API." -msgstr "通过 ``vision`` 能力,您可以让模型接收图像并回答有关它们的问题。" -"在 Xinference 中,这表示某些模型在通过 Chat API 进行对话时能够处理图像输入。" +msgstr "" +"通过 ``vision`` 能力,您可以让模型接收图像并回答有关它们的问题。在 " +"Xinference 中,这表示某些模型在通过 Chat API 进行对话时能够处理图像输入。" #: ../../source/models/model_abilities/vision.rst:19 msgid "Supported models" @@ -51,37 +52,75 @@ msgid "" msgstr "在 Xinference 中支持 ``vision`` 功能的模型如下:" #: ../../source/models/model_abilities/vision.rst:23 -msgid "qwen-vl-chat" +msgid ":ref:`qwen-vl-chat `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:24 +msgid ":ref:`deepseek-vl-chat `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:25 +msgid ":ref:`yi-vl-chat `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:26 +msgid ":ref:`omnilmm `" msgstr "" #: ../../source/models/model_abilities/vision.rst:27 +msgid ":ref:`internvl-chat `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:28 +msgid ":ref:`cogvlm2 `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:29 +msgid ":ref:`MiniCPM-Llama3-V 2.5 `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:30 +msgid ":ref:`GLM-4V `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:31 +msgid ":ref:`MiniCPM-Llama3-V 2.6 `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:32 +msgid ":ref:`internvl2 `" +msgstr "" + +#: ../../source/models/model_abilities/vision.rst:36 msgid "Quickstart" msgstr "快速入门" -#: ../../source/models/model_abilities/vision.rst:29 +#: ../../source/models/model_abilities/vision.rst:38 msgid "" "Images are made available to the model in two main ways: by passing a " "link to the image or by passing the base64 encoded image directly in the " "request." -msgstr "模型可以通过两种主要方式获取图像:通过传递图像的链接或直接在请求中传递 base64 编码的图像。" +msgstr "" +"模型可以通过两种主要方式获取图像:通过传递图像的链接或直接在请求中传递 " +"base64 编码的图像。" -#: ../../source/models/model_abilities/vision.rst:33 +#: ../../source/models/model_abilities/vision.rst:42 msgid "Example using OpenAI Client" msgstr "使用 OpenAI 客户端的示例" -#: ../../source/models/model_abilities/vision.rst:64 +#: ../../source/models/model_abilities/vision.rst:73 msgid "Uploading base 64 encoded images" msgstr "上传 Base64 编码的图片" -#: ../../source/models/model_abilities/vision.rst:106 +#: ../../source/models/model_abilities/vision.rst:115 msgid "You can find more examples of ``vision`` ability in the tutorial notebook:" msgstr "你可以在教程笔记本中找到更多关于 ``vision`` 能力的示例。" -#: ../../source/models/model_abilities/vision.rst:110 +#: ../../source/models/model_abilities/vision.rst:119 msgid "Qwen VL Chat" msgstr "" -#: ../../source/models/model_abilities/vision.rst:113 +#: ../../source/models/model_abilities/vision.rst:122 msgid "Learn vision ability from a example using qwen-vl-chat" msgstr "通过使用 qwen-vl-chat 的示例来学习使用 LLM 的视觉能力" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/models/model_memory.po b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_memory.po new file mode 100644 index 0000000000..3b48d5e92d --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/models/model_memory.po @@ -0,0 +1,129 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-06-06 17:26+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.15.0\n" + +#: ../../source/models/model_memory.rst:5 +msgid "Model Memory Calculation" +msgstr "模型显存使用量计算" + +#: ../../source/models/model_memory.rst:7 +msgid "" +"For better planning of VMEM usage, xinference provided tool for model " +"memory calculation: ``cal-model-mem``" +msgstr "为了更好规划显存使用, Xinference 提供了计算模型显存使用量的工具:``cal-model-mem``" + +#: ../../source/models/model_memory.rst:9 +msgid "Use algorithm from https://github.com/RahulSChand/gpu_poor" +msgstr "算法来自:https://github.com/RahulSChand/gpu_poor" + +#: ../../source/models/model_memory.rst:11 +msgid "Output: model_mem, kv_cache, overhead, active_mem" +msgstr "输出:model_mem, kv_cache, overhead, active_mem" + +#: ../../source/models/model_memory.rst:13 +msgid "" +"Example: To calculate memory usage for qwen1.5-chat, run the following " +"command:" +msgstr "示例:计算 qwen1.5-chat 模型的显存用量,可以运行以下示例指令:" + +#: ../../source/models/model_memory.rst:37 +msgid "Syntax" +msgstr "语法" + +#: ../../source/models/model_memory.rst:39 +msgid "--size-in-billions {model_size}" +msgstr "" + +#: ../../source/models/model_memory.rst:42 +msgid "-s {model_size}" +msgstr "" + +#: ../../source/models/model_memory.rst:45 +msgid "" +"Set the model size. Specify the model size in billions of parameters. " +"Format accept 1_8 and 1.8. For example, 7 for 7.0B model size." +msgstr "设置模型大小。以十亿个参数为单位指定模型大小。参数格式接受形式如 1_8 和 1.8. 例如,7 表示 7.0B 的模型大小。" + +#: ../../source/models/model_memory.rst:50 +msgid "--quantization {precision}" +msgstr "" + +#: ../../source/models/model_memory.rst:53 +msgid "-q {precision} *(Optional)*" +msgstr "-q {precision} *(可选)*" + +#: ../../source/models/model_memory.rst:56 +msgid "" +"Define the quantization settings for the model. For example, Int4 for " +"INT4 quantization." +msgstr "指定模型的量化配置。例如:Int4 参数表示使用 INT4 量化。" + +#: ../../source/models/model_memory.rst:60 +msgid "--model-name {model_name}" +msgstr "" + +#: ../../source/models/model_memory.rst:63 +msgid "-n {model_name} *(Optional)*" +msgstr "-n {model_name} *(可选)*" + +#: ../../source/models/model_memory.rst:66 +msgid "" +"Specify the model's name. If provided, fetch model config from " +"huggingface/modelscope; If not specified, use default model layer to " +"estimate." +msgstr "" +"指定模型名称。如果提供此参数,将从 huggingface/modelscope 中获取模型配置;如果没有指定,将使用默认的 layer " +"参数粗略估计。" + +#: ../../source/models/model_memory.rst:70 +msgid "--context-length {context_length}" +msgstr "" + +#: ../../source/models/model_memory.rst:73 +msgid "-c {context_length}" +msgstr "" + +#: ../../source/models/model_memory.rst:76 +msgid "" +"Specify the maximum number of tokens(context length) that your model " +"support." +msgstr "指定模型的最大上下文长度。" + +#: ../../source/models/model_memory.rst:79 +msgid "--model-format {format}" +msgstr "" + +#: ../../source/models/model_memory.rst:82 +msgid "-f {format}" +msgstr "" + +#: ../../source/models/model_memory.rst:85 +msgid "Specify the format of the model, e.g. pytorch, ggmlv3, etc." +msgstr "指定模型的格式,例如:pytorch, ggmlv3, etc." + +#: ../../source/models/model_memory.rst:89 +msgid "" +"The environment variable ``HF_ENDPOINT`` could set the endpoint of " +"HuggingFace. e.g. hf-mirror, etc. Please refer to :ref:`this document " +"`" +msgstr "" +"利用环境变量 ``HF_ENDPOINT`` 可设置 HuggingFace 服务器的 Endpoint。例如,当网络不佳时可以选择 hf-" +"mirror 作为 Endpoint. 更多请参考 :ref:`此文档 `" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/reference/index.po b/doc/source/locale/zh_CN/LC_MESSAGES/reference/index.po index c6c77e6dd2..7612ac1155 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/reference/index.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/reference/index.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-27 15:43+0800\n" +"POT-Creation-Date: 2024-08-13 17:44+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.14.0\n" #: ../../source/reference/index.rst:5 msgid "API Reference" @@ -30,7 +30,7 @@ msgstr "" #: ../../source/reference/index.rst:25::1 msgid "" ":py:obj:`xinference.client.Client `\\ " -"\\(base\\_url\\)" +"\\(base\\_url\\[\\, api\\_key\\]\\)" msgstr "" #: ../../source/reference/index.rst:25::1 @@ -124,173 +124,170 @@ msgid "Model Handles" msgstr "" #: ../../source/reference/index.rst:31 -msgid "ChatglmCppChatModelHandle" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle " -"`\\" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -"alias of " -":py:class:`~xinference.client.restful.restful_client.RESTfulChatglmCppChatModelHandle`" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle.chat " -"`\\ " -"\\(prompt\\)" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -"Given a list of messages comprising a conversation, the ChatGLM model " -"will return a response via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:40::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatglmCppChatModelHandle.create_embedding" -" " -"`\\" -" \\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:40::1 -#: ../../source/reference/index.rst:52::1 -#: ../../source/reference/index.rst:62::1 -#: ../../source/reference/index.rst:73::1 -msgid "Create an Embedding from user input via RESTful APIs." -msgstr "" - -#: ../../source/reference/index.rst:42 msgid "ChatModelHandle" msgstr "" -#: ../../source/reference/index.rst:52::1 +#: ../../source/reference/index.rst:40::1 msgid "" ":py:obj:`xinference.client.handlers.ChatModelHandle " "`\\" msgstr "" -#: ../../source/reference/index.rst:52::1 +#: ../../source/reference/index.rst:40::1 msgid "" "alias of " ":py:class:`~xinference.client.restful.restful_client.RESTfulChatModelHandle`" msgstr "" -#: ../../source/reference/index.rst:52::1 +#: ../../source/reference/index.rst:40::1 msgid "" ":py:obj:`xinference.client.handlers.ChatModelHandle.chat " "`\\ \\(prompt\\)" msgstr "" -#: ../../source/reference/index.rst:52::1 +#: ../../source/reference/index.rst:40::1 msgid "" "Given a list of messages comprising a conversation, the model will return" " a response via RESTful APIs." msgstr "" -#: ../../source/reference/index.rst:52::1 -msgid "" -":py:obj:`xinference.client.handlers.ChatModelHandle.create_embedding " -"`\\ " -"\\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:52::1 +#: ../../source/reference/index.rst:40::1 msgid "" ":py:obj:`xinference.client.handlers.ChatModelHandle.generate " "`\\ \\(prompt\\)" msgstr "" -#: ../../source/reference/index.rst:52::1 -#: ../../source/reference/index.rst:73::1 +#: ../../source/reference/index.rst:40::1 +#: ../../source/reference/index.rst:60::1 msgid "" "Creates a completion for the provided prompt and parameters via RESTful " "APIs." msgstr "" -#: ../../source/reference/index.rst:54 +#: ../../source/reference/index.rst:42 msgid "EmbeddingModelHandle" msgstr "" -#: ../../source/reference/index.rst:62::1 +#: ../../source/reference/index.rst:50::1 msgid "" ":py:obj:`xinference.client.handlers.EmbeddingModelHandle " "`\\" msgstr "" -#: ../../source/reference/index.rst:62::1 +#: ../../source/reference/index.rst:50::1 msgid "" "alias of " ":py:class:`~xinference.client.restful.restful_client.RESTfulEmbeddingModelHandle`" msgstr "" -#: ../../source/reference/index.rst:62::1 +#: ../../source/reference/index.rst:50::1 msgid "" ":py:obj:`xinference.client.handlers.EmbeddingModelHandle.create_embedding" " `\\ " -"\\(input\\)" +"\\(...\\)" msgstr "" -#: ../../source/reference/index.rst:64 +#: ../../source/reference/index.rst:50::1 +msgid "Create an Embedding from user input via RESTful APIs." +msgstr "" + +#: ../../source/reference/index.rst:52 msgid "GenerateModelHandle" msgstr "" -#: ../../source/reference/index.rst:73::1 +#: ../../source/reference/index.rst:60::1 msgid "" ":py:obj:`xinference.client.handlers.GenerateModelHandle " "`\\" msgstr "" -#: ../../source/reference/index.rst:73::1 +#: ../../source/reference/index.rst:60::1 msgid "" "alias of " ":py:class:`~xinference.client.restful.restful_client.RESTfulGenerateModelHandle`" msgstr "" -#: ../../source/reference/index.rst:73::1 -msgid "" -":py:obj:`xinference.client.handlers.GenerateModelHandle.create_embedding " -"`\\ " -"\\(input\\)" -msgstr "" - -#: ../../source/reference/index.rst:73::1 +#: ../../source/reference/index.rst:60::1 msgid "" ":py:obj:`xinference.client.handlers.GenerateModelHandle.generate " "`\\ \\(prompt\\)" msgstr "" -#: ../../source/reference/index.rst:75 +#: ../../source/reference/index.rst:62 msgid "ImageModelHandle" msgstr "" -#: ../../source/reference/index.rst:81::1 +#: ../../source/reference/index.rst:70::1 msgid "" ":py:obj:`xinference.client.handlers.ImageModelHandle " "`\\" msgstr "" -#: ../../source/reference/index.rst:81::1 +#: ../../source/reference/index.rst:70::1 msgid "" "alias of " ":py:class:`~xinference.client.restful.restful_client.RESTfulImageModelHandle`" msgstr "" -#: ../../source/reference/index.rst:81::1 +#: ../../source/reference/index.rst:70::1 msgid "" ":py:obj:`xinference.client.handlers.ImageModelHandle.text_to_image " "`\\ " "\\(prompt\\)" msgstr "" -#: ../../source/reference/index.rst:81::1 +#: ../../source/reference/index.rst:70::1 msgid "Creates an image by the input text." msgstr "" +#: ../../source/reference/index.rst:72 +msgid "AudioModelHandle" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "" +":py:obj:`xinference.client.handlers.AudioModelHandle " +"`\\" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "" +"alias of " +":py:class:`~xinference.client.restful.restful_client.RESTfulAudioModelHandle`" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "" +":py:obj:`xinference.client.handlers.AudioModelHandle.transcriptions " +"`\\ " +"\\(audio\\)" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "Transcribes audio into the input language." +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "" +":py:obj:`xinference.client.handlers.AudioModelHandle.translations " +"`\\ \\(audio\\)" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "Translates audio into English." +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "" +":py:obj:`xinference.client.handlers.AudioModelHandle.speech " +"`\\ \\(input\\)" +msgstr "" + +#: ../../source/reference/index.rst:82::1 +msgid "Generates audio from the input text." +msgstr "" + +#: ../../source/reference/index.rst:84 +msgid "VideoModelHandle" +msgstr "" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/backends.po b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/backends.po index d34b601d33..08a03e75e8 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/backends.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/backends.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-02 15:27+0800\n" +"POT-Creation-Date: 2024-08-20 11:56+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -33,8 +33,8 @@ msgstr "" "自动选择合适的引擎" #: ../../source/user_guide/backends.rst:11 -msgid "llama-cpp-python" -msgstr "llama-cpp-python" +msgid "llama.cpp" +msgstr "" #: ../../source/user_guide/backends.rst:12 msgid "" @@ -60,92 +60,73 @@ msgstr "" "github.com/abetlen/llama-cpp-python#installation-with-openblas--cublas--" "clblast--metal>`_ 。" -#: ../../source/user_guide/backends.rst:21 -msgid "ctransformers" -msgstr "ctransformers" - #: ../../source/user_guide/backends.rst:22 -msgid "" -"CTransformers provide python bindings for the Transformer models " -"implemented in C/C++ using GGML library." -msgstr "" -"CTransformers 基于 GGML 使用 C++ 实现了 transformer 模型的推理,并提供了 " -"Python 接口。" - -#: ../../source/user_guide/backends.rst:24 -msgid "" -"We recommend that users install `ctransformers` on the worker themselves " -"and adjust the parameters according to the hardware to achieve the best " -"inference efficiency. Please refer to the `ctransformers installation " -"guide `_." -msgstr "" -"推荐用户手动安装 `ctransformers`,根据当前使用的硬件,指定对应的编译选项" -"以获得最好的推理性能。可以参考 `ctransformers 安装指南 `_. 。" - -#: ../../source/user_guide/backends.rst:30 msgid "transformers" msgstr "transformers" -#: ../../source/user_guide/backends.rst:31 +#: ../../source/user_guide/backends.rst:23 msgid "" "Transformers supports the inference of most state-of-art models. It is " "the default backend for models in PyTorch format." msgstr "Transformers 支持绝大部分新出的模型。是 Pytorch 格式模型默认使用的引擎。" -#: ../../source/user_guide/backends.rst:34 +#: ../../source/user_guide/backends.rst:26 msgid "vLLM" msgstr "vLLM" -#: ../../source/user_guide/backends.rst:35 +#: ../../source/user_guide/backends.rst:27 msgid "vLLM is a fast and easy-to-use library for LLM inference and serving." msgstr "vLLM 是一个非常高效并且易用的大语言模型推理引擎。" -#: ../../source/user_guide/backends.rst:37 +#: ../../source/user_guide/backends.rst:29 msgid "vLLM is fast with:" msgstr "vLLM 具有以下特点:" -#: ../../source/user_guide/backends.rst:39 +#: ../../source/user_guide/backends.rst:31 msgid "State-of-the-art serving throughput" msgstr "领先的推理吞吐量" -#: ../../source/user_guide/backends.rst:40 +#: ../../source/user_guide/backends.rst:32 msgid "Efficient management of attention key and value memory with PagedAttention" msgstr "使用 PagedAttention 高效管理注意力键和值记忆" -#: ../../source/user_guide/backends.rst:41 +#: ../../source/user_guide/backends.rst:33 msgid "Continuous batching of incoming requests" msgstr "对传入请求进行连续批处理" -#: ../../source/user_guide/backends.rst:42 +#: ../../source/user_guide/backends.rst:34 msgid "Optimized CUDA kernels" msgstr "优化的 CUDA 内核" -#: ../../source/user_guide/backends.rst:44 +#: ../../source/user_guide/backends.rst:36 msgid "" "When the following conditions are met, Xinference will choose vLLM as the" " inference engine:" msgstr "当满足以下条件时,Xinference 会自动选择 vLLM 作为推理引擎:" -#: ../../source/user_guide/backends.rst:46 +#: ../../source/user_guide/backends.rst:38 msgid "The model format is ``pytorch``, ``gptq`` or ``awq``." msgstr "模型格式为 ``pytorch`` , ``gptq`` 或者 ``awq`` 。" -#: ../../source/user_guide/backends.rst:47 +#: ../../source/user_guide/backends.rst:39 msgid "When the model format is ``pytorch``, the quantization is ``none``." msgstr "当模型格式为 ``pytorch`` 时,量化选项需为 ``none`` 。" -#: ../../source/user_guide/backends.rst:48 +#: ../../source/user_guide/backends.rst:40 +msgid "When the model format is ``awq``, the quantization is ``Int4``." +msgstr "当模型格式为 ``awq`` 时,量化选项需为 ``Int4`` 。" + +#: ../../source/user_guide/backends.rst:41 msgid "" -"When the model format is ``gptq`` or ``awq``, the quantization is " -"``Int4``." -msgstr "当模型格式为 ``gptq`` 或 ``awq`` 时,量化选项需为 ``Int4`` 。" +"When the model format is ``gptq``, the quantization is ``Int3``, ``Int4``" +" or ``Int8``." +msgstr "当模型格式为 ``gptq`` 时,量化选项需为 ``Int3``, ``Int4`` 或 ``Int8`` 。" -#: ../../source/user_guide/backends.rst:49 +#: ../../source/user_guide/backends.rst:42 msgid "The system is Linux and has at least one CUDA device" msgstr "操作系统为 Linux 并且至少有一个支持 CUDA 的设备" -#: ../../source/user_guide/backends.rst:50 +#: ../../source/user_guide/backends.rst:43 msgid "" "The model family (for custom models) / model name (for builtin models) is" " within the list of models supported by vLLM" @@ -153,77 +134,151 @@ msgstr "" "自定义模型的 ``model_family`` 字段和内置模型的 ``model_name`` 字段在 vLLM" " 的支持列表中。" -#: ../../source/user_guide/backends.rst:52 +#: ../../source/user_guide/backends.rst:45 msgid "Currently, supported model includes:" msgstr "目前,支持的模型包括:" +#: ../../source/user_guide/backends.rst:49 +msgid "" +"``llama-2``, ``llama-3``, ``llama-3.1``, ``llama-2-chat``, " +"``llama-3-instruct``, ``llama-3.1-instruct``" +msgstr "" + +#: ../../source/user_guide/backends.rst:50 +msgid "" +"``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``, " +"``mistral-instruct-v0.3``, ``mistral-nemo-instruct``, ``mistral-large-" +"instruct``" +msgstr "" + +#: ../../source/user_guide/backends.rst:51 +msgid "``codestral-v0.1``" +msgstr "" + +#: ../../source/user_guide/backends.rst:52 +msgid "``Yi``, ``Yi-1.5``, ``Yi-chat``, ``Yi-1.5-chat``, ``Yi-1.5-chat-16k``" +msgstr "" + +#: ../../source/user_guide/backends.rst:53 +msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" +msgstr "" + +#: ../../source/user_guide/backends.rst:54 +msgid "" +"``deepseek``, ``deepseek-coder``, ``deepseek-chat``, ``deepseek-coder-" +"instruct``" +msgstr "" + +#: ../../source/user_guide/backends.rst:55 +msgid "``codeqwen1.5``, ``codeqwen1.5-chat``" +msgstr "" + #: ../../source/user_guide/backends.rst:56 -msgid "``llama-2``, ``llama-2-chat``" -msgstr "``llama-2``, ``llama-2-chat``" +msgid "``baichuan-2-chat``" +msgstr "" #: ../../source/user_guide/backends.rst:57 -msgid "``baichuan``, ``baichuan-chat``, ``baichuan-2-chat``" +msgid "``internlm2-chat``" msgstr "" #: ../../source/user_guide/backends.rst:58 -msgid "" -"``internlm-16k``, ``internlm-chat-7b``, ``internlm-chat-8k``, ``internlm-" -"chat-20b``" +msgid "``internlm2.5-chat``, ``internlm2.5-chat-1m``" msgstr "" #: ../../source/user_guide/backends.rst:59 -msgid "``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``" +msgid "``qwen-chat``" msgstr "" #: ../../source/user_guide/backends.rst:60 -msgid "``Yi``, ``Yi-chat``" -msgstr "``Yi``, ``Yi-chat``" +msgid "``mixtral-instruct-v0.1``, ``mixtral-8x22B-instruct-v0.1``" +msgstr "" #: ../../source/user_guide/backends.rst:61 -msgid "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" -msgstr "``code-llama``, ``code-llama-python``, ``code-llama-instruct``" +msgid "``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k``" +msgstr "" #: ../../source/user_guide/backends.rst:62 -msgid "``vicuna-v1.3``, ``vicuna-v1.5``" -msgstr "``vicuna-v1.3``, ``vicuna-v1.5``" +msgid "``glm4-chat``, ``glm4-chat-1m``" +msgstr "" #: ../../source/user_guide/backends.rst:63 -msgid "``qwen-chat``" +msgid "``codegeex4``" msgstr "" #: ../../source/user_guide/backends.rst:64 -msgid "``mixtral-instruct-v0.1``" +msgid "``qwen1.5-chat``, ``qwen1.5-moe-chat``" msgstr "" #: ../../source/user_guide/backends.rst:65 -msgid "``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k``" +msgid "``qwen2-instruct``, ``qwen2-moe-instruct``" msgstr "" #: ../../source/user_guide/backends.rst:66 -msgid "``deepseek-chat``, ``deepseek-coder-instruct``" +msgid "``gemma-it``, ``gemma-2-it``" msgstr "" #: ../../source/user_guide/backends.rst:67 -msgid "``qwen1.5-chat``" +msgid "``orion-chat``, ``orion-chat-rag``" msgstr "" #: ../../source/user_guide/backends.rst:68 -msgid "``gemma-it``" +msgid "``c4ai-command-r-v01``" msgstr "" -#: ../../source/user_guide/backends.rst:69 -msgid "``orion-chat``, ``orion-chat-rag``" +#: ../../source/user_guide/backends.rst:72 +msgid "SGLang" msgstr "" +#: ../../source/user_guide/backends.rst:73 +msgid "" +"`SGLang `_ has a high-performance " +"inference runtime with RadixAttention. It significantly accelerates the " +"execution of complex LLM programs by automatic KV cache reuse across " +"multiple calls. And it also supports other common techniques like " +"continuous batching and tensor parallelism." +msgstr "" +"`SGLang `_ 具有基于 RadixAttention" +" 的高性能推理运行时。它通过在多个调用之间自动重用KV缓存,显著加速了复杂 " +"LLM 程序的执行。它还支持其他常见推理技术,如连续批处理和张量并行处理。" + +#: ../../source/user_guide/backends.rst:78 +msgid "MLX" +msgstr "" + +#: ../../source/user_guide/backends.rst:79 +msgid "" +"`MLX `_ " +"provides efficient runtime to run LLM on Apple silicon. It's recommended " +"to use for Mac users when running on Apple silicon if the model has MLX " +"format support." +msgstr "" +"`MLX `_ 提供在" +"苹果 silicon 芯片上高效运行 LLM 的方式。在模型包含 MLX 格式的时候,推荐" +"使用苹果 silicon 芯片的 Mac 用户使用 MLX 引擎。" + +#~ msgid "``llama-2``, ``llama-3``, ``llama-2-chat``, ``llama-3-instruct``" +#~ msgstr "" + +#~ msgid "``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``" +#~ msgstr "" + #~ msgid "" -#~ "vLLM is fast with: - State-of-" -#~ "the-art serving throughput - Efficient" -#~ " management of attention key and " -#~ "value memory with PagedAttention - " -#~ "Continuous batching of incoming requests " -#~ "- Optimized CUDA kernels" +#~ "``llama-2``, ``llama-3``, ``llama-2-chat``, " +#~ "``llama-3-instruct``, ``llama-3.1``, " +#~ "``llama-3.1-instruct``" +#~ msgstr "" + +#~ msgid "``gemma-it``" +#~ msgstr "" + +#~ msgid "``baichuan``, ``baichuan-chat``, ``baichuan-2-chat``" +#~ msgstr "" + +#~ msgid "" +#~ "``internlm-16k``, ``internlm-chat-7b``, " +#~ "``internlm-chat-8k``, ``internlm-chat-20b``" +#~ msgstr "" + +#~ msgid "``vicuna-v1.3``, ``vicuna-v1.5``" #~ msgstr "" -#~ "vLLM 优势主要体现在:提供最高的吞吐能力" -#~ ",高效的显存管理,批量处理的能力," -#~ "以及优化的 CUDA 实现。" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/client_api.po b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/client_api.po index 134def615b..9f9cc45647 100644 --- a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/client_api.po +++ b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/client_api.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Xinference \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-10 11:33+0800\n" +"POT-Creation-Date: 2024-05-11 10:26+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,7 +17,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" +"Generated-By: Babel 2.11.0\n" #: ../../source/user_guide/client_api.rst:5 msgid "Client API" @@ -39,14 +39,16 @@ msgid "" "can connect to the xinference server through this endpoint using the " "Client." msgstr "" -"在命令日志里会打印服务地址,上述日志中为 `http://127.0.0.1:9997`。用户可以通过 Client 连接 Xinference " -"服务。" +"在命令日志里会打印服务地址,上述日志中为 `http://127.0.0.1:9997`。用户" +"可以通过 Client 连接 Xinference 服务。" #: ../../source/user_guide/client_api.rst:20 msgid "" "Models are categorized into LLM, embedding, image, etc. We plan to " "introduce more model types in the future." -msgstr "所有模型被分为 LLM、embedding、rerank 等类型。后续可能会支持更多类型的模型。" +msgstr "" +"所有模型被分为 LLM、embedding、rerank 等类型。后续可能会支持更多类型的" +"模型。" #: ../../source/user_guide/client_api.rst:23 msgid "LLM" @@ -61,88 +63,112 @@ msgid "To initialize an LLM and chat:" msgstr "初始化一个大语言模型并且与之对话:" #: ../../source/user_guide/client_api.rst:41 -#: ../../source/user_guide/client_api.rst:162 -#: ../../source/user_guide/client_api.rst:233 +#: ../../source/user_guide/client_api.rst:163 +#: ../../source/user_guide/client_api.rst:234 +#: ../../source/user_guide/client_api.rst:303 msgid "Xinference Client" msgstr "Xinference Client" -#: ../../source/user_guide/client_api.rst:66 -#: ../../source/user_guide/client_api.rst:194 -#: ../../source/user_guide/client_api.rst:257 +#: ../../source/user_guide/client_api.rst:67 +#: ../../source/user_guide/client_api.rst:195 +#: ../../source/user_guide/client_api.rst:258 +#: ../../source/user_guide/client_api.rst:327 msgid "OpenAI Client" msgstr "OpenAI Client" -#: ../../source/user_guide/client_api.rst:68 +#: ../../source/user_guide/client_api.rst:69 msgid "" "Openai client request with the same function as before, excluding launch " "model. More details refer to: https://platform.openai.com/docs/api-" "reference/chat?lang=python" msgstr "" -"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口兼容。" -"Openai 使用方式可以参考 https://platform.openai.com/docs/api-reference/chat?lang=python" +"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口" +"兼容。Openai 使用方式可以参考 https://platform.openai.com/docs/api-" +"reference/chat?lang=python" -#: ../../source/user_guide/client_api.rst:90 +#: ../../source/user_guide/client_api.rst:91 msgid "OpenAI Client Tool Calls" msgstr "OpenAI 工具调用" -#: ../../source/user_guide/client_api.rst:135 -#: ../../source/user_guide/client_api.rst:176 -#: ../../source/user_guide/client_api.rst:208 -#: ../../source/user_guide/client_api.rst:248 -#: ../../source/user_guide/client_api.rst:272 -#: ../../source/user_guide/client_api.rst:300 +#: ../../source/user_guide/client_api.rst:136 +#: ../../source/user_guide/client_api.rst:177 +#: ../../source/user_guide/client_api.rst:209 +#: ../../source/user_guide/client_api.rst:249 +#: ../../source/user_guide/client_api.rst:273 +#: ../../source/user_guide/client_api.rst:317 +#: ../../source/user_guide/client_api.rst:342 +#: ../../source/user_guide/client_api.rst:371 msgid "Output:" msgstr "输出:" -#: ../../source/user_guide/client_api.rst:144 +#: ../../source/user_guide/client_api.rst:145 msgid "Embedding" msgstr "Embedding" -#: ../../source/user_guide/client_api.rst:146 +#: ../../source/user_guide/client_api.rst:147 msgid "To list the available built-in embedding models:" msgstr "列出所有内置支持的 embedding 模型:" -#: ../../source/user_guide/client_api.rst:159 +#: ../../source/user_guide/client_api.rst:160 msgid "To launch an embedding model and embed text:" msgstr "拉起 embedding 模型并使用文本向量化:" -#: ../../source/user_guide/client_api.rst:196 +#: ../../source/user_guide/client_api.rst:197 msgid "" "Openai client request with the same function as before, excluding launch " "model. More details refer to: https://platform.openai.com/docs/api-" "reference/embeddings?lang=python" msgstr "" -"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口兼容。" -"Openai 使用方式可以参考 https://platform.openai.com/docs/api-reference/embeddings?lang=python" - +"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口" +"兼容。Openai 使用方式可以参考 https://platform.openai.com/docs/api-" +"reference/embeddings?lang=python" -#: ../../source/user_guide/client_api.rst:215 +#: ../../source/user_guide/client_api.rst:216 msgid "Image" msgstr "图片" -#: ../../source/user_guide/client_api.rst:217 +#: ../../source/user_guide/client_api.rst:218 +#: ../../source/user_guide/client_api.rst:283 msgid "To list the available built-in image models:" msgstr "列出所有内置的文生图模型:" -#: ../../source/user_guide/client_api.rst:230 +#: ../../source/user_guide/client_api.rst:231 msgid "To initiate an image model and generate an image using a text prompt:" msgstr "初始化一个文生图模型并通过提示词生成图片:" -#: ../../source/user_guide/client_api.rst:259 +#: ../../source/user_guide/client_api.rst:260 msgid "" "Openai client request with the same function as before, excluding launch " "model. More details refer to: https://platform.openai.com/docs/api-" "reference/images/create?lang=python" msgstr "" -"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口兼容。" -"Openai 使用方式可以参考 https://platform.openai.com/docs/api-reference/images/create?lang=python" +"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口" +"兼容。Openai 使用方式可以参考 https://platform.openai.com/docs/api-" +"reference/images/create?lang=python" +#: ../../source/user_guide/client_api.rst:281 +msgid "Audio" +msgstr "" + +#: ../../source/user_guide/client_api.rst:300 +msgid "To initiate an audio model and get text from an audio:" +msgstr "初始化一个语音模型并通过语音生成文字:" + +#: ../../source/user_guide/client_api.rst:329 +msgid "" +"Openai client request with the same function as before. More details " +"refer to: https://platform.openai.com/docs/api-" +"reference/audio/createTranscription" +msgstr "" +"使用 Openai 发送请求时,除了创建模型,其余的请求都保持与 Openai 的接口" +"兼容。Openai 使用方式可以参考 https://platform.openai.com/docs/api-" +"reference/images/create?lang=python" -#: ../../source/user_guide/client_api.rst:279 +#: ../../source/user_guide/client_api.rst:350 msgid "Rerank" msgstr "Rerank" -#: ../../source/user_guide/client_api.rst:280 +#: ../../source/user_guide/client_api.rst:351 msgid "To launch a rerank model and compute the similarity scores:" msgstr "拉起 rerank 模型并计算文本相似度:" diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/continuous_batching.po b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/continuous_batching.po new file mode 100644 index 0000000000..427e855a09 --- /dev/null +++ b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/continuous_batching.po @@ -0,0 +1,142 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2023, Xorbits Inc. +# This file is distributed under the same license as the Xinference package. +# FIRST AUTHOR , 2024. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Xinference \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-04 16:08+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.11.0\n" + +#: ../../source/user_guide/continuous_batching.rst:5 +msgid "Continuous Batching (experimental)" +msgstr "连续批处理(实验性质)" + +#: ../../source/user_guide/continuous_batching.rst:7 +msgid "" +"Continuous batching, as a means to improve throughput during model " +"serving, has already been implemented in inference engines like ``VLLM``." +" Xinference aims to provide this optimization capability when using the " +"transformers engine as well." +msgstr "" +"连续批处理是诸如 ``VLLM`` 这样的推理引擎中提升吞吐的重要技术。Xinference " +"旨在通过这项技术提升 ``transformers`` 推理引擎的吞吐。" + +#: ../../source/user_guide/continuous_batching.rst:11 +msgid "Usage" +msgstr "使用方式" + +#: ../../source/user_guide/continuous_batching.rst:12 +msgid "Currently, this feature can be enabled under the following conditions:" +msgstr "当前,此功能在满足以下条件时开启:" + +#: ../../source/user_guide/continuous_batching.rst:14 +msgid "" +"First, set the environment variable " +"``XINFERENCE_TRANSFORMERS_ENABLE_BATCHING`` to ``1`` when starting " +"xinference. For example:" +msgstr "" +"首先,启动 Xinference 时需要将环境变量 ``XINFERENCE_TRANSFORMERS_ENABLE_" +"BATCHING`` 置为 ``1`` 。" + +#: ../../source/user_guide/continuous_batching.rst:21 +msgid "" +"Then, ensure that the ``transformers`` engine is selected when launching " +"the model. For example:" +msgstr "然后,启动 LLM 模型时选择 ``transformers`` 推理引擎。例如:" + +#: ../../source/user_guide/continuous_batching.rst:57 +msgid "" +"Once this feature is enabled, all requests for LLMs will be managed by " +"continuous batching, and the average throughput of requests made to a " +"single model will increase. The usage of the LLM interface remains " +"exactly the same as before, with no differences." +msgstr "" +"一旦此功能开启,LLM 模型的所有接口将被此功能接管。所有接口的使用方式没有" +"任何变化。" + +#: ../../source/user_guide/continuous_batching.rst:63 +msgid "Abort your request" +msgstr "中止请求" + +#: ../../source/user_guide/continuous_batching.rst:64 +msgid "In this mode, you can abort requests that are in the process of inference." +msgstr "" +"此功能中,你可以优雅地中止正在推理中的请求。" + +#: ../../source/user_guide/continuous_batching.rst:66 +msgid "First, add ``request_id`` option in ``generate_config``. For example:" +msgstr "" +"首先,在推理请求的 ``generate_config`` 中指定 ``request_id`` 选项。例如:" + +#: ../../source/user_guide/continuous_batching.rst:75 +msgid "" +"Then, abort the request using the ``request_id`` you have set. For " +"example:" +msgstr "" +"接着,带着你指定的 ``request_id`` 去中止该请求。例如:" + +#: ../../source/user_guide/continuous_batching.rst:83 +msgid "" +"Note that if your request has already finished, aborting the request will" +" be a no-op." +msgstr "" +"注意,如果你的请求已经结束,那么此操作将什么都不做。" + +#: ../../source/user_guide/continuous_batching.rst:86 +msgid "Note" +msgstr "注意事项" + +#: ../../source/user_guide/continuous_batching.rst:88 +msgid "" +"Currently, this feature only supports the ``generate``, ``chat`` and " +"``vision`` tasks for ``LLM`` models. The ``tool call`` tasks are not " +"supported." +msgstr "" +"当前,此功能仅支持 LLM 模型的 ``generate``, ``chat`` 和 ``vision`` (多" +"模态) 功能。``tool call`` (工具调用)暂时不支持。" + +#: ../../source/user_guide/continuous_batching.rst:90 +msgid "" +"For ``vision`` tasks, currently only ``qwen-vl-chat``, ``cogvlm2``, and " +"``glm-4v`` models are supported. More models will be supported in the " +"future. Please let us know your requirements." +msgstr "" +"对于多模态任务,当前支持 ``qwen-vl-chat`` ,``cogvlm2`` 和 ``glm-4v`` " +"模型。未来将加入更多模型,敬请期待。" + +#: ../../source/user_guide/continuous_batching.rst:92 +msgid "" +"If using GPU inference, this method will consume more GPU memory. Please " +"be cautious when increasing the number of concurrent requests to the same" +" model. The ``launch_model`` interface provides the ``max_num_seqs`` " +"parameter to adjust the concurrency level, with a default value of " +"``16``." +msgstr "" +"如果使用 GPU 推理,此功能对显存要求较高。因此请谨慎提高对同一个模型的并发" +"请求量。``launch_model`` 接口提供可选参数 ``max_num_seqs`` 用于调整并发度" +",默认值为 ``16`` 。" + +#: ../../source/user_guide/continuous_batching.rst:95 +msgid "" +"This feature is still in the experimental stage, and we welcome your " +"active feedback on any issues." +msgstr "此功能仍处于实验阶段,欢迎反馈任何问题。" + +#: ../../source/user_guide/continuous_batching.rst:97 +msgid "" +"After a period of testing, this method will remain enabled by default, " +"and the original inference method will be deprecated." +msgstr "" +"一段时间的测试之后,此功能将代替原来的 transformers 推理逻辑成为默认行为" +"。原来的推理逻辑将被摒弃。" + diff --git a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/spec_decoding.po b/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/spec_decoding.po deleted file mode 100644 index 17b38581a6..0000000000 --- a/doc/source/locale/zh_CN/LC_MESSAGES/user_guide/spec_decoding.po +++ /dev/null @@ -1,109 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2023, Xorbits Inc. -# This file is distributed under the same license as the Xinference package. -# FIRST AUTHOR , 2023. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Xinference \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-01-02 18:00+0800\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language: zh_CN\n" -"Language-Team: zh_CN \n" -"Plural-Forms: nplurals=1; plural=0;\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.12.1\n" - -#: ../../source/user_guide/spec_decoding.rst:5 -msgid "Speculative Decoding (experimental)" -msgstr "投机采样(实验性质)" - -#: ../../source/user_guide/spec_decoding.rst:9 -msgid "" -"Speculative decoding is a method designed to speed up the inference " -"process of large language models (LLMs). This technique involves using a " -"smaller, quicker \"draft\" model to produce several tokens in advance. " -"These tokens are then checked by a more extensive \"target\" model. If " -"the larger model confirms the tokens generated by the draft model, it " -"leads to significant savings in memory bandwidth and processing time per " -"token. However, if the tokens from the draft model don't match the " -"predictions of the larger model, they are discarded." -msgstr "" -"投机采样是一种加速大语言模型推理的方法。这项技术使用了一个小且快速的 \"草稿\" 模型生成多个 token,然后用相对大且慢的 \"目标\" " -"模型检查生成的 token 是否合理。如果大模型接受小模型生成的 token,那么 token " -"生成的速度会大幅上升。如果大模型没有接受小模型生成的 token,那么需要大模型重新生成 token。" - -#: ../../source/user_guide/spec_decoding.rst:15 -msgid "Launching a speculative LLM" -msgstr "使用投机采样的大语言模型" - -#: ../../source/user_guide/spec_decoding.rst:16 -msgid "" -"Using speculative decoding in Xinference is straightforward. The only " -"distinction between speculative decoding and regular decoding is the way " -"to initiate an LLM:" -msgstr "在 Xinference 中使用投机采样非常简单。与普通大语言模型拉起的方式唯一的区别就是在初始化模型时使用特定的方式:" - -#: ../../source/user_guide/spec_decoding.rst:35 -msgid "" -"``Client.launch_speculative_llm`` is an experimental API, which may be " -"removed in the future releases." -msgstr "``Client.launch_speculative_llm`` 是一个实验性质的 API,可能会在将来修改或者移除。" - -#: ../../source/user_guide/spec_decoding.rst:37 -msgid "After launching the model, you can use it just like a regular model:" -msgstr "在模型拉起之后,使用方式与普通的大语言模型没有区别:" - -#: ../../source/user_guide/spec_decoding.rst:52 -msgid "Performance" -msgstr "性能" - -#: ../../source/user_guide/spec_decoding.rst:53 -msgid "The effectiveness of speculative decoding relies on:" -msgstr "投机采样的效率取决于:" - -#: ../../source/user_guide/spec_decoding.rst:55 -msgid "The size difference between the models - the larger, the better." -msgstr "大模型与小模型尺寸大小的差别。" - -#: ../../source/user_guide/spec_decoding.rst:56 -msgid "" -"The similarity between the logits produced by the draft model and the " -"target model." -msgstr "大模型与小模型输出的概率分布相似度。" - -#: ../../source/user_guide/spec_decoding.rst:58 -msgid "" -"In the example above, the target model is about five times larger than " -"the draft model, and the two models are well aligned. Approximately 86% " -"of the draft tokens are accepted by the target model, resulting in a 25% " -"increase in speed." -msgstr "" -"在上面的例子里,大模型的尺寸是小模型的五倍,并且这两个模型是对齐好的。小模型生成的token 中 86% 被大模型接受,使得推理效率有 25% " -"的提升。" - -#: ../../source/user_guide/spec_decoding.rst:61 -msgid "References" -msgstr "参考" - -#: ../../source/user_guide/spec_decoding.rst:62 -msgid "" -"[1] `Fast Inference from Transformers via Speculative Decoding " -"`_" -msgstr "" -"[1] `Fast Inference from Transformers via Speculative Decoding " -"`_" - -#: ../../source/user_guide/spec_decoding.rst:63 -msgid "" -"[2] `Accelerating Large Language Model Decoding with Speculative Sampling" -" `_" -msgstr "" -"[2] `Accelerating Large Language Model Decoding with Speculative Sampling" -" `_" - diff --git a/doc/source/models/builtin/audio/belle-whisper-large-v3-zh.rst b/doc/source/models/builtin/audio/belle-whisper-large-v3-zh.rst new file mode 100644 index 0000000000..e2e514e97b --- /dev/null +++ b/doc/source/models/builtin/audio/belle-whisper-large-v3-zh.rst @@ -0,0 +1,19 @@ +.. _models_builtin_belle-whisper-large-v3-zh: + +========================= +Belle-whisper-large-v3-zh +========================= + +- **Model Name:** Belle-whisper-large-v3-zh +- **Model Family:** whisper +- **Abilities:** audio-to-text +- **Multilingual:** False + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** BELLE-2/Belle-whisper-large-v3-zh + +Execute the following command to launch the model:: + + xinference launch --model-name Belle-whisper-large-v3-zh --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/chattts.rst b/doc/source/models/builtin/audio/chattts.rst new file mode 100644 index 0000000000..2ce0b89795 --- /dev/null +++ b/doc/source/models/builtin/audio/chattts.rst @@ -0,0 +1,19 @@ +.. _models_builtin_chattts: + +======= +ChatTTS +======= + +- **Model Name:** ChatTTS +- **Model Family:** ChatTTS +- **Abilities:** text-to-audio +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** 2Noise/ChatTTS + +Execute the following command to launch the model:: + + xinference launch --model-name ChatTTS --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/cosyvoice-300m-instruct.rst b/doc/source/models/builtin/audio/cosyvoice-300m-instruct.rst new file mode 100644 index 0000000000..9e438f04d5 --- /dev/null +++ b/doc/source/models/builtin/audio/cosyvoice-300m-instruct.rst @@ -0,0 +1,19 @@ +.. _models_builtin_cosyvoice-300m-instruct: + +======================= +CosyVoice-300M-Instruct +======================= + +- **Model Name:** CosyVoice-300M-Instruct +- **Model Family:** CosyVoice +- **Abilities:** text-to-audio +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** model-scope/CosyVoice-300M-Instruct + +Execute the following command to launch the model:: + + xinference launch --model-name CosyVoice-300M-Instruct --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/cosyvoice-300m-sft.rst b/doc/source/models/builtin/audio/cosyvoice-300m-sft.rst new file mode 100644 index 0000000000..4aa6864d31 --- /dev/null +++ b/doc/source/models/builtin/audio/cosyvoice-300m-sft.rst @@ -0,0 +1,19 @@ +.. _models_builtin_cosyvoice-300m-sft: + +================== +CosyVoice-300M-SFT +================== + +- **Model Name:** CosyVoice-300M-SFT +- **Model Family:** CosyVoice +- **Abilities:** text-to-audio +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** model-scope/CosyVoice-300M-SFT + +Execute the following command to launch the model:: + + xinference launch --model-name CosyVoice-300M-SFT --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/cosyvoice-300m.rst b/doc/source/models/builtin/audio/cosyvoice-300m.rst new file mode 100644 index 0000000000..f667546dbd --- /dev/null +++ b/doc/source/models/builtin/audio/cosyvoice-300m.rst @@ -0,0 +1,19 @@ +.. _models_builtin_cosyvoice-300m: + +============== +CosyVoice-300M +============== + +- **Model Name:** CosyVoice-300M +- **Model Family:** CosyVoice +- **Abilities:** audio-to-audio +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** model-scope/CosyVoice-300M + +Execute the following command to launch the model:: + + xinference launch --model-name CosyVoice-300M --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/fishspeech-1.2-sft.rst b/doc/source/models/builtin/audio/fishspeech-1.2-sft.rst new file mode 100644 index 0000000000..3afac1f7e3 --- /dev/null +++ b/doc/source/models/builtin/audio/fishspeech-1.2-sft.rst @@ -0,0 +1,19 @@ +.. _models_builtin_fishspeech-1.2-sft: + +================== +FishSpeech-1.2-SFT +================== + +- **Model Name:** FishSpeech-1.2-SFT +- **Model Family:** FishAudio +- **Abilities:** text-to-audio +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** fishaudio/fish-speech-1.2-sft + +Execute the following command to launch the model:: + + xinference launch --model-name FishSpeech-1.2-SFT --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/audio/index.rst b/doc/source/models/builtin/audio/index.rst index 066a79d270..8959b2b94f 100644 --- a/doc/source/models/builtin/audio/index.rst +++ b/doc/source/models/builtin/audio/index.rst @@ -15,6 +15,20 @@ The following is a list of built-in audio models in Xinference: belle-whisper-large-v2-zh + belle-whisper-large-v3-zh + + chattts + + cosyvoice-300m + + cosyvoice-300m-instruct + + cosyvoice-300m-sft + + fishspeech-1.2-sft + + sensevoicesmall + whisper-base whisper-base.en diff --git a/doc/source/models/builtin/audio/sensevoicesmall.rst b/doc/source/models/builtin/audio/sensevoicesmall.rst new file mode 100644 index 0000000000..2873a1351b --- /dev/null +++ b/doc/source/models/builtin/audio/sensevoicesmall.rst @@ -0,0 +1,19 @@ +.. _models_builtin_sensevoicesmall: + +=============== +SenseVoiceSmall +=============== + +- **Model Name:** SenseVoiceSmall +- **Model Family:** funasr +- **Abilities:** audio-to-text +- **Multilingual:** True + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** FunAudioLLM/SenseVoiceSmall + +Execute the following command to launch the model:: + + xinference launch --model-name SenseVoiceSmall --model-type audio \ No newline at end of file diff --git a/doc/source/models/builtin/embedding/gte-qwen2.rst b/doc/source/models/builtin/embedding/gte-qwen2.rst new file mode 100644 index 0000000000..a88fdece9d --- /dev/null +++ b/doc/source/models/builtin/embedding/gte-qwen2.rst @@ -0,0 +1,21 @@ +.. _models_builtin_gte-qwen2: + +========= +gte-Qwen2 +========= + +- **Model Name:** gte-Qwen2 +- **Languages:** zh, en +- **Abilities:** embed + +Specifications +^^^^^^^^^^^^^^ + +- **Dimensions:** 3584 +- **Max Tokens:** 32000 +- **Model ID:** Alibaba-NLP/gte-Qwen2-7B-instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model:: + + xinference launch --model-name gte-Qwen2 --model-type embedding \ No newline at end of file diff --git a/doc/source/models/builtin/embedding/index.rst b/doc/source/models/builtin/embedding/index.rst index e816de4b46..5afa52c21d 100644 --- a/doc/source/models/builtin/embedding/index.rst +++ b/doc/source/models/builtin/embedding/index.rst @@ -45,12 +45,20 @@ The following is a list of built-in embedding models in Xinference: gte-large + gte-qwen2 + jina-embeddings-v2-base-en jina-embeddings-v2-base-zh jina-embeddings-v2-small-en + m3e-base + + m3e-large + + m3e-small + multilingual-e5-large text2vec-base-chinese diff --git a/doc/source/models/builtin/embedding/m3e-base.rst b/doc/source/models/builtin/embedding/m3e-base.rst new file mode 100644 index 0000000000..b2bc2ad342 --- /dev/null +++ b/doc/source/models/builtin/embedding/m3e-base.rst @@ -0,0 +1,21 @@ +.. _models_builtin_m3e-base: + +======== +m3e-base +======== + +- **Model Name:** m3e-base +- **Languages:** zh, en +- **Abilities:** embed + +Specifications +^^^^^^^^^^^^^^ + +- **Dimensions:** 768 +- **Max Tokens:** 512 +- **Model ID:** moka-ai/m3e-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model:: + + xinference launch --model-name m3e-base --model-type embedding \ No newline at end of file diff --git a/doc/source/models/builtin/embedding/m3e-large.rst b/doc/source/models/builtin/embedding/m3e-large.rst new file mode 100644 index 0000000000..25524feaaf --- /dev/null +++ b/doc/source/models/builtin/embedding/m3e-large.rst @@ -0,0 +1,21 @@ +.. _models_builtin_m3e-large: + +========= +m3e-large +========= + +- **Model Name:** m3e-large +- **Languages:** zh, en +- **Abilities:** embed + +Specifications +^^^^^^^^^^^^^^ + +- **Dimensions:** 1024 +- **Max Tokens:** 512 +- **Model ID:** moka-ai/m3e-large +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model:: + + xinference launch --model-name m3e-large --model-type embedding \ No newline at end of file diff --git a/doc/source/models/builtin/embedding/m3e-small.rst b/doc/source/models/builtin/embedding/m3e-small.rst new file mode 100644 index 0000000000..2e001edccf --- /dev/null +++ b/doc/source/models/builtin/embedding/m3e-small.rst @@ -0,0 +1,21 @@ +.. _models_builtin_m3e-small: + +========= +m3e-small +========= + +- **Model Name:** m3e-small +- **Languages:** zh, en +- **Abilities:** embed + +Specifications +^^^^^^^^^^^^^^ + +- **Dimensions:** 512 +- **Max Tokens:** 512 +- **Model ID:** moka-ai/m3e-small +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model:: + + xinference launch --model-name m3e-small --model-type embedding \ No newline at end of file diff --git a/doc/source/models/builtin/image/flux.1-dev.rst b/doc/source/models/builtin/image/flux.1-dev.rst new file mode 100644 index 0000000000..829bcbfd75 --- /dev/null +++ b/doc/source/models/builtin/image/flux.1-dev.rst @@ -0,0 +1,19 @@ +.. _models_builtin_flux.1-dev: + +========== +FLUX.1-dev +========== + +- **Model Name:** FLUX.1-dev +- **Model Family:** stable_diffusion +- **Abilities:** text2image +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** black-forest-labs/FLUX.1-dev + +Execute the following command to launch the model:: + + xinference launch --model-name FLUX.1-dev --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/flux.1-schnell.rst b/doc/source/models/builtin/image/flux.1-schnell.rst new file mode 100644 index 0000000000..268f5a1720 --- /dev/null +++ b/doc/source/models/builtin/image/flux.1-schnell.rst @@ -0,0 +1,19 @@ +.. _models_builtin_flux.1-schnell: + +============== +FLUX.1-schnell +============== + +- **Model Name:** FLUX.1-schnell +- **Model Family:** stable_diffusion +- **Abilities:** text2image +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** black-forest-labs/FLUX.1-schnell + +Execute the following command to launch the model:: + + xinference launch --model-name FLUX.1-schnell --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/index.rst b/doc/source/models/builtin/image/index.rst index 7b15e9bcb2..5bc8744338 100644 --- a/doc/source/models/builtin/image/index.rst +++ b/doc/source/models/builtin/image/index.rst @@ -11,11 +11,25 @@ The following is a list of built-in image models in Xinference: :maxdepth: 1 + flux.1-dev + + flux.1-schnell + + kolors + sd-turbo + sd3-medium + sdxl-turbo + stable-diffusion-2-inpainting + + stable-diffusion-inpainting + stable-diffusion-v1.5 stable-diffusion-xl-base-1.0 + + stable-diffusion-xl-inpainting \ No newline at end of file diff --git a/doc/source/models/builtin/image/kolors.rst b/doc/source/models/builtin/image/kolors.rst new file mode 100644 index 0000000000..19d11c4201 --- /dev/null +++ b/doc/source/models/builtin/image/kolors.rst @@ -0,0 +1,19 @@ +.. _models_builtin_kolors: + +====== +kolors +====== + +- **Model Name:** kolors +- **Model Family:** stable_diffusion +- **Abilities:** text2image, image2image +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** Kwai-Kolors/Kolors-diffusers + +Execute the following command to launch the model:: + + xinference launch --model-name kolors --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/sd-turbo.rst b/doc/source/models/builtin/image/sd-turbo.rst index 75a12e228e..e799b423a3 100644 --- a/doc/source/models/builtin/image/sd-turbo.rst +++ b/doc/source/models/builtin/image/sd-turbo.rst @@ -6,7 +6,7 @@ sd-turbo - **Model Name:** sd-turbo - **Model Family:** stable_diffusion -- **Abilities:** text-to-image +- **Abilities:** text2image - **Available ControlNet:** None Specifications diff --git a/doc/source/models/builtin/image/sd3-medium.rst b/doc/source/models/builtin/image/sd3-medium.rst new file mode 100644 index 0000000000..c69b4a708b --- /dev/null +++ b/doc/source/models/builtin/image/sd3-medium.rst @@ -0,0 +1,19 @@ +.. _models_builtin_sd3-medium: + +========== +sd3-medium +========== + +- **Model Name:** sd3-medium +- **Model Family:** stable_diffusion +- **Abilities:** text2image, image2image +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** stabilityai/stable-diffusion-3-medium-diffusers + +Execute the following command to launch the model:: + + xinference launch --model-name sd3-medium --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/sdxl-turbo.rst b/doc/source/models/builtin/image/sdxl-turbo.rst index a1d7780d80..878b10079f 100644 --- a/doc/source/models/builtin/image/sdxl-turbo.rst +++ b/doc/source/models/builtin/image/sdxl-turbo.rst @@ -6,7 +6,7 @@ sdxl-turbo - **Model Name:** sdxl-turbo - **Model Family:** stable_diffusion -- **Abilities:** text-to-image +- **Abilities:** text2image - **Available ControlNet:** None Specifications diff --git a/doc/source/models/builtin/image/stable-diffusion-2-inpainting.rst b/doc/source/models/builtin/image/stable-diffusion-2-inpainting.rst new file mode 100644 index 0000000000..6009cd37a3 --- /dev/null +++ b/doc/source/models/builtin/image/stable-diffusion-2-inpainting.rst @@ -0,0 +1,19 @@ +.. _models_builtin_stable-diffusion-2-inpainting: + +============================= +stable-diffusion-2-inpainting +============================= + +- **Model Name:** stable-diffusion-2-inpainting +- **Model Family:** stable_diffusion +- **Abilities:** inpainting +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** stabilityai/stable-diffusion-2-inpainting + +Execute the following command to launch the model:: + + xinference launch --model-name stable-diffusion-2-inpainting --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/stable-diffusion-inpainting.rst b/doc/source/models/builtin/image/stable-diffusion-inpainting.rst new file mode 100644 index 0000000000..76f1274048 --- /dev/null +++ b/doc/source/models/builtin/image/stable-diffusion-inpainting.rst @@ -0,0 +1,19 @@ +.. _models_builtin_stable-diffusion-inpainting: + +=========================== +stable-diffusion-inpainting +=========================== + +- **Model Name:** stable-diffusion-inpainting +- **Model Family:** stable_diffusion +- **Abilities:** inpainting +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** runwayml/stable-diffusion-inpainting + +Execute the following command to launch the model:: + + xinference launch --model-name stable-diffusion-inpainting --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/image/stable-diffusion-v1.5.rst b/doc/source/models/builtin/image/stable-diffusion-v1.5.rst index 23a7afe89b..5a0c73adcd 100644 --- a/doc/source/models/builtin/image/stable-diffusion-v1.5.rst +++ b/doc/source/models/builtin/image/stable-diffusion-v1.5.rst @@ -6,7 +6,7 @@ stable-diffusion-v1.5 - **Model Name:** stable-diffusion-v1.5 - **Model Family:** stable_diffusion -- **Abilities:** text-to-image +- **Abilities:** text2image, image2image - **Available ControlNet:** ['canny', 'mlsd', 'hed', 'scribble', 'openpose', 'normal', 'seg'] Specifications diff --git a/doc/source/models/builtin/image/stable-diffusion-xl-base-1.0.rst b/doc/source/models/builtin/image/stable-diffusion-xl-base-1.0.rst index d98bdd1865..a4f7518dbf 100644 --- a/doc/source/models/builtin/image/stable-diffusion-xl-base-1.0.rst +++ b/doc/source/models/builtin/image/stable-diffusion-xl-base-1.0.rst @@ -6,7 +6,7 @@ stable-diffusion-xl-base-1.0 - **Model Name:** stable-diffusion-xl-base-1.0 - **Model Family:** stable_diffusion -- **Abilities:** text-to-image +- **Abilities:** text2image, image2image - **Available ControlNet:** ['canny', 'depth', 'zoe-depth'] Specifications diff --git a/doc/source/models/builtin/image/stable-diffusion-xl-inpainting.rst b/doc/source/models/builtin/image/stable-diffusion-xl-inpainting.rst new file mode 100644 index 0000000000..61a72cc044 --- /dev/null +++ b/doc/source/models/builtin/image/stable-diffusion-xl-inpainting.rst @@ -0,0 +1,19 @@ +.. _models_builtin_stable-diffusion-xl-inpainting: + +============================== +stable-diffusion-xl-inpainting +============================== + +- **Model Name:** stable-diffusion-xl-inpainting +- **Model Family:** stable_diffusion +- **Abilities:** inpainting +- **Available ControlNet:** None + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** diffusers/stable-diffusion-xl-1.0-inpainting-0.1 + +Execute the following command to launch the model:: + + xinference launch --model-name stable-diffusion-xl-inpainting --model-type image \ No newline at end of file diff --git a/doc/source/models/builtin/index.rst b/doc/source/models/builtin/index.rst index 6e1d55b906..6b3ac98cee 100644 --- a/doc/source/models/builtin/index.rst +++ b/doc/source/models/builtin/index.rst @@ -12,3 +12,4 @@ Builtin Models image/index audio/index rerank/index + video/index diff --git a/doc/source/models/builtin/llm/aquila2-chat-16k.rst b/doc/source/models/builtin/llm/aquila2-chat-16k.rst index 866bd03f9e..c47aa13a7d 100644 --- a/doc/source/models/builtin/llm/aquila2-chat-16k.rst +++ b/doc/source/models/builtin/llm/aquila2-chat-16k.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/AquilaChat2-7B-16K - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat-16k --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat-16k --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 34 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/AquilaChat2-34B-16K-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat-16k --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat-16k --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} Model Spec 3 (gptq, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (gptq, 34 Billion) - **Model Format:** gptq - **Model Size (in billions):** 34 - **Quantizations:** Int4 +- **Engines**: Transformers - **Model ID:** TheBloke/AquilaChat2-34B-16K-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat-16k --size-in-billions 34 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat-16k --size-in-billions 34 --model-format gptq --quantization ${quantization} Model Spec 4 (awq, 34 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (awq, 34 Billion) - **Model Format:** awq - **Model Size (in billions):** 34 - **Quantizations:** Int4 +- **Engines**: Transformers - **Model ID:** TheBloke/AquilaChat2-34B-16K-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat-16k --size-in-billions 34 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat-16k --size-in-billions 34 --model-format awq --quantization ${quantization} Model Spec 5 (pytorch, 34 Billion) @@ -80,11 +84,12 @@ Model Spec 5 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/AquilaChat2-34B-16K - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat-16k --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat-16k --size-in-billions 34 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/aquila2-chat.rst b/doc/source/models/builtin/llm/aquila2-chat.rst index c81747450e..a90bd80c64 100644 --- a/doc/source/models/builtin/llm/aquila2-chat.rst +++ b/doc/source/models/builtin/llm/aquila2-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/AquilaChat2-7B - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 34 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/AquilaChat2-34B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} Model Spec 3 (gptq, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (gptq, 34 Billion) - **Model Format:** gptq - **Model Size (in billions):** 34 - **Quantizations:** Int4 +- **Engines**: Transformers - **Model ID:** TheBloke/AquilaChat2-34B-GPTQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 34 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 34 --model-format gptq --quantization ${quantization} Model Spec 4 (awq, 34 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (awq, 34 Billion) - **Model Format:** awq - **Model Size (in billions):** 34 - **Quantizations:** Int4 +- **Engines**: Transformers - **Model ID:** TheBloke/AquilaChat2-34B-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 34 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 34 --model-format awq --quantization ${quantization} Model Spec 5 (pytorch, 34 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/AquilaChat2-34B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 6 (pytorch, 70 Billion) @@ -95,11 +100,12 @@ Model Spec 6 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/AquilaChat2-70B-Expr - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2-chat --size-in-billions 70 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2-chat --size-in-billions 70 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/aquila2.rst b/doc/source/models/builtin/llm/aquila2.rst index 96397e324a..6fb702310b 100644 --- a/doc/source/models/builtin/llm/aquila2.rst +++ b/doc/source/models/builtin/llm/aquila2.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/Aquila2-7B - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 34 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/Aquila2-34B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2 --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2 --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 70 Billion) @@ -50,11 +52,12 @@ Model Spec 3 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** BAAI/Aquila2-70B-Expr - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name aquila2 --size-in-billions 70 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name aquila2 --size-in-billions 70 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/baichuan-2-chat.rst b/doc/source/models/builtin/llm/baichuan-2-chat.rst index 6ee587706c..03716a7e75 100644 --- a/doc/source/models/builtin/llm/baichuan-2-chat.rst +++ b/doc/source/models/builtin/llm/baichuan-2-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** baichuan-inc/Baichuan2-7B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name baichuan-2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name baichuan-2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** baichuan-inc/Baichuan2-13B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name baichuan-2-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name baichuan-2-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/baichuan-2.rst b/doc/source/models/builtin/llm/baichuan-2.rst index 72359b3bb7..631e99dc05 100644 --- a/doc/source/models/builtin/llm/baichuan-2.rst +++ b/doc/source/models/builtin/llm/baichuan-2.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** baichuan-inc/Baichuan2-7B-Base - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name baichuan-2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name baichuan-2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** baichuan-inc/Baichuan2-13B-Base - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name baichuan-2 --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name baichuan-2 --size-in-billions 13 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/baichuan-chat.rst b/doc/source/models/builtin/llm/baichuan-chat.rst deleted file mode 100644 index 85c66655ca..0000000000 --- a/doc/source/models/builtin/llm/baichuan-chat.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_baichuan-chat: - -======================================== -baichuan-chat -======================================== - -- **Context Length:** 4096 -- **Model Name:** baichuan-chat -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** Baichuan-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 13 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** baichuan-inc/Baichuan-13B-Chat -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name baichuan-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/baichuan.rst b/doc/source/models/builtin/llm/baichuan.rst deleted file mode 100644 index 5347cb97e1..0000000000 --- a/doc/source/models/builtin/llm/baichuan.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _models_llm_baichuan: - -======================================== -baichuan -======================================== - -- **Context Length:** 4096 -- **Model Name:** baichuan -- **Languages:** en, zh -- **Abilities:** generate -- **Description:** Baichuan is an open-source Transformer based LLM that is trained on both Chinese and English data. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 7 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/baichuan-llama-7B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name baichuan --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** baichuan-inc/Baichuan-7B -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name baichuan --size-in-billions 7 --model-format pytorch --quantization ${quantization} - - -Model Spec 3 (pytorch, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 13 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** baichuan-inc/Baichuan-13B-Base -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name baichuan --size-in-billions 13 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/c4ai-command-r-v01.rst b/doc/source/models/builtin/llm/c4ai-command-r-v01.rst new file mode 100644 index 0000000000..22594c385c --- /dev/null +++ b/doc/source/models/builtin/llm/c4ai-command-r-v01.rst @@ -0,0 +1,111 @@ +.. _models_llm_c4ai-command-r-v01: + +======================================== +c4ai-command-r-v01 +======================================== + +- **Context Length:** 131072 +- **Model Name:** c4ai-command-r-v01 +- **Languages:** en, fr, de, es, it, pt, ja, ko, zh, ar +- **Abilities:** chat +- **Description:** C4AI Command-R(+) is a research release of a 35 and 104 billion parameter highly performant generative model. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 35 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 35 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** CohereForAI/c4ai-command-r-v01 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 35 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 35 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 35 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** CohereForAI/c4ai-command-r-v01-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 35 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (ggufv2, 35 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 35 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** andrewcanis/c4ai-command-r-v01-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 35 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 4 (pytorch, 104 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 104 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** CohereForAI/c4ai-command-r-plus +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 104 --model-format pytorch --quantization ${quantization} + + +Model Spec 5 (pytorch, 104 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 104 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** CohereForAI/c4ai-command-r-plus-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 104 --model-format pytorch --quantization ${quantization} + + +Model Spec 6 (gptq, 104 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 104 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** alpindale/c4ai-command-r-plus-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name c4ai-command-r-v01 --size-in-billions 104 --model-format gptq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/chatglm.rst b/doc/source/models/builtin/llm/chatglm.rst deleted file mode 100644 index a79c1a1637..0000000000 --- a/doc/source/models/builtin/llm/chatglm.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_chatglm: - -======================================== -chatglm -======================================== - -- **Context Length:** 2048 -- **Model Name:** chatglm -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** ChatGLM is an open-source General Language Model (GLM) based LLM trained on both Chinese and English data. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 6 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** Xorbits/chatglm-6B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm --size-in-billions 6 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (pytorch, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 6 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** THUDM/chatglm-6b -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm --size-in-billions 6 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/chatglm2-32k.rst b/doc/source/models/builtin/llm/chatglm2-32k.rst deleted file mode 100644 index f14e8b93b4..0000000000 --- a/doc/source/models/builtin/llm/chatglm2-32k.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_chatglm2-32k: - -======================================== -chatglm2-32k -======================================== - -- **Context Length:** 32768 -- **Model Name:** chatglm2-32k -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** ChatGLM2-32k is a special version of ChatGLM2, with a context window of 32k tokens instead of 8k. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 6 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** THUDM/chatglm2-6b-32k -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm2-32k --size-in-billions 6 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/chatglm2.rst b/doc/source/models/builtin/llm/chatglm2.rst deleted file mode 100644 index ed730f9423..0000000000 --- a/doc/source/models/builtin/llm/chatglm2.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_chatglm2: - -======================================== -chatglm2 -======================================== - -- **Context Length:** 8192 -- **Model Name:** chatglm2 -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** ChatGLM2 is the second generation of ChatGLM, still open-source and trained on Chinese and English data. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 6 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** Xorbits/chatglm2-6B-GGML -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm2 --size-in-billions 6 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (pytorch, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 6 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** THUDM/chatglm2-6b -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm2 --size-in-billions 6 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/chatglm3-128k.rst b/doc/source/models/builtin/llm/chatglm3-128k.rst index 94a2fcd29f..410669fd83 100644 --- a/doc/source/models/builtin/llm/chatglm3-128k.rst +++ b/doc/source/models/builtin/llm/chatglm3-128k.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 6 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** THUDM/chatglm3-6b-128k - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name chatglm3-128k --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name chatglm3-128k --size-in-billions 6 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/chatglm3-32k.rst b/doc/source/models/builtin/llm/chatglm3-32k.rst index f9c724ec94..b728ce3fad 100644 --- a/doc/source/models/builtin/llm/chatglm3-32k.rst +++ b/doc/source/models/builtin/llm/chatglm3-32k.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 6 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** THUDM/chatglm3-6b-32k - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name chatglm3-32k --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name chatglm3-32k --size-in-billions 6 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/chatglm3.rst b/doc/source/models/builtin/llm/chatglm3.rst index 9212f0b488..baf7a0fa08 100644 --- a/doc/source/models/builtin/llm/chatglm3.rst +++ b/doc/source/models/builtin/llm/chatglm3.rst @@ -14,32 +14,18 @@ Specifications ^^^^^^^^^^^^^^ -Model Spec 1 (ggmlv3, 6 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 6 -- **Quantizations:** q4_0 -- **Model ID:** Xorbits/chatglm3-6B-GGML -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name chatglm3 --size-in-billions 6 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (pytorch, 6 Billion) +Model Spec 1 (pytorch, 6 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** THUDM/chatglm3-6b - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name chatglm3 --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name chatglm3 --size-in-billions 6 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/code-llama-instruct.rst b/doc/source/models/builtin/llm/code-llama-instruct.rst index 6265741c5d..7a67e6f0d8 100644 --- a/doc/source/models/builtin/llm/code-llama-instruct.rst +++ b/doc/source/models/builtin/llm/code-llama-instruct.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** codellama/CodeLlama-7b-Instruct-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** codellama/CodeLlama-13b-Instruct-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** codellama/CodeLlama-34b-Instruct-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-7B-Instruct-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 5 (ggufv2, 13 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (ggufv2, 13 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 13 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-13B-Instruct-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} Model Spec 6 (ggufv2, 34 Billion) @@ -95,11 +100,12 @@ Model Spec 6 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-34B-Instruct-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-instruct --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-instruct --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/code-llama-python.rst b/doc/source/models/builtin/llm/code-llama-python.rst index 4512a6884e..cc21cdf8f8 100644 --- a/doc/source/models/builtin/llm/code-llama-python.rst +++ b/doc/source/models/builtin/llm/code-llama-python.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-7B-Python-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-13B-Python-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-34B-Python-fp16 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-7B-Python-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 5 (ggufv2, 13 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (ggufv2, 13 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 13 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-13B-Python-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} Model Spec 6 (ggufv2, 34 Billion) @@ -95,11 +100,12 @@ Model Spec 6 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-34B-Python-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama-python --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama-python --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/code-llama.rst b/doc/source/models/builtin/llm/code-llama.rst index 2842f41733..731df906db 100644 --- a/doc/source/models/builtin/llm/code-llama.rst +++ b/doc/source/models/builtin/llm/code-llama.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-7B-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-13B-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** TheBloke/CodeLlama-34B-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-7B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 5 (ggufv2, 13 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (ggufv2, 13 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 13 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-13B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} Model Spec 6 (ggufv2, 34 Billion) @@ -95,11 +100,12 @@ Model Spec 6 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/CodeLlama-34B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name code-llama --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name code-llama --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/codegeex4.rst b/doc/source/models/builtin/llm/codegeex4.rst new file mode 100644 index 0000000000..8ab5e7248c --- /dev/null +++ b/doc/source/models/builtin/llm/codegeex4.rst @@ -0,0 +1,47 @@ +.. _models_llm_codegeex4: + +======================================== +codegeex4 +======================================== + +- **Context Length:** 131072 +- **Model Name:** codegeex4 +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** the open-source version of the latest CodeGeeX4 model series + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** THUDM/codegeex4-all-9b +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codegeex4 --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** IQ2_M, IQ3_M, Q4_K_M, Q5_K_M, Q6_K_L, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** THUDM/codegeex4-all-9b-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codegeex4 --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/codeqwen1.5-chat.rst b/doc/source/models/builtin/llm/codeqwen1.5-chat.rst new file mode 100644 index 0000000000..ea1b832bb4 --- /dev/null +++ b/doc/source/models/builtin/llm/codeqwen1.5-chat.rst @@ -0,0 +1,63 @@ +.. _models_llm_codeqwen1.5-chat: + +======================================== +codeqwen1.5-chat +======================================== + +- **Context Length:** 65536 +- **Model Name:** codeqwen1.5-chat +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp +- **Model ID:** Qwen/CodeQwen1.5-7B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codeqwen1.5-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 2 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** Qwen/CodeQwen1.5-7B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codeqwen1.5-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (awq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** Qwen/CodeQwen1.5-7B-Chat-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codeqwen1.5-chat --size-in-billions 7 --model-format awq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/codeqwen1.5.rst b/doc/source/models/builtin/llm/codeqwen1.5.rst new file mode 100644 index 0000000000..7b22268ca3 --- /dev/null +++ b/doc/source/models/builtin/llm/codeqwen1.5.rst @@ -0,0 +1,31 @@ +.. _models_llm_codeqwen1.5: + +======================================== +codeqwen1.5 +======================================== + +- **Context Length:** 65536 +- **Model Name:** codeqwen1.5 +- **Languages:** en, zh +- **Abilities:** generate +- **Description:** CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** Qwen/CodeQwen1.5-7B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codeqwen1.5 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/codeshell-chat.rst b/doc/source/models/builtin/llm/codeshell-chat.rst index 0d70d74a61..0cb4394bbd 100644 --- a/doc/source/models/builtin/llm/codeshell-chat.rst +++ b/doc/source/models/builtin/llm/codeshell-chat.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** WisdomShell/CodeShell-7B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name codeshell-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name codeshell-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/codeshell.rst b/doc/source/models/builtin/llm/codeshell.rst index e3c0e4dffb..8a9d7a5059 100644 --- a/doc/source/models/builtin/llm/codeshell.rst +++ b/doc/source/models/builtin/llm/codeshell.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** WisdomShell/CodeShell-7B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name codeshell --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name codeshell --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/codestral-v0.1.rst b/doc/source/models/builtin/llm/codestral-v0.1.rst new file mode 100644 index 0000000000..dd75ffad66 --- /dev/null +++ b/doc/source/models/builtin/llm/codestral-v0.1.rst @@ -0,0 +1,79 @@ +.. _models_llm_codestral-v0.1: + +======================================== +codestral-v0.1 +======================================== + +- **Context Length:** 32768 +- **Model Name:** codestral-v0.1 +- **Languages:** en +- **Abilities:** generate +- **Description:** Codestrall-22B-v0.1 is trained on a diverse dataset of 80+ programming languages, including the most popular ones, such as Python, Java, C, C++, JavaScript, and Bash + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 22 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 22 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** mistralai/Mistral-7B-Instruct-v0.2 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codestral-v0.1 --size-in-billions 22 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 22 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 22 +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_K_S, Q4_K_M, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** bartowski/Codestral-22B-v0.1-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codestral-v0.1 --size-in-billions 22 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 3 (mlx, 22 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 22 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Codestral-22B-v0.1-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codestral-v0.1 --size-in-billions 22 --model-format mlx --quantization ${quantization} + + +Model Spec 4 (mlx, 22 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 22 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Codestral-22B-v0.1-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name codestral-v0.1 --size-in-billions 22 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/cogvlm2-video-llama3-chat.rst b/doc/source/models/builtin/llm/cogvlm2-video-llama3-chat.rst new file mode 100644 index 0000000000..0b3720c08f --- /dev/null +++ b/doc/source/models/builtin/llm/cogvlm2-video-llama3-chat.rst @@ -0,0 +1,31 @@ +.. _models_llm_cogvlm2-video-llama3-chat: + +======================================== +cogvlm2-video-llama3-chat +======================================== + +- **Context Length:** 8192 +- **Model Name:** cogvlm2-video-llama3-chat +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** CogVLM2-Video achieves state-of-the-art performance on multiple video question answering tasks. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 12 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** THUDM/cogvlm2-video-llama3-chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name cogvlm2-video-llama3-chat --size-in-billions 12 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/cogvlm2.rst b/doc/source/models/builtin/llm/cogvlm2.rst new file mode 100644 index 0000000000..58ba147c2a --- /dev/null +++ b/doc/source/models/builtin/llm/cogvlm2.rst @@ -0,0 +1,47 @@ +.. _models_llm_cogvlm2: + +======================================== +cogvlm2 +======================================== + +- **Context Length:** 8192 +- **Model Name:** cogvlm2 +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** CogVLM2 have achieved good results in many lists compared to the previous generation of CogVLM open source models. Its excellent performance can compete with some non-open source models. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 20 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 20 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** THUDM/cogvlm2-llama3-chinese-chat-19B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name cogvlm2 --size-in-billions 20 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 20 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 20 +- **Quantizations:** int4 +- **Engines**: Transformers +- **Model ID:** THUDM/cogvlm2-llama3-chinese-chat-19B-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name cogvlm2 --size-in-billions 20 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/csg-wukong-chat-v0.1.rst b/doc/source/models/builtin/llm/csg-wukong-chat-v0.1.rst new file mode 100644 index 0000000000..027d1c6951 --- /dev/null +++ b/doc/source/models/builtin/llm/csg-wukong-chat-v0.1.rst @@ -0,0 +1,47 @@ +.. _models_llm_csg-wukong-chat-v0.1: + +======================================== +csg-wukong-chat-v0.1 +======================================== + +- **Context Length:** 32768 +- **Model Name:** csg-wukong-chat-v0.1 +- **Languages:** en +- **Abilities:** chat +- **Description:** csg-wukong-1B is a 1 billion-parameter small language model(SLM) pretrained on 1T tokens. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 1 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 1 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** opencsg/csg-wukong-1B-chat-v0.1 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name csg-wukong-chat-v0.1 --size-in-billions 1 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 1 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 1 +- **Quantizations:** Q2_K, Q3_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_1, Q4_K_S, Q4_K_M, Q5_0, Q5_1, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** RichardErkhov/opencsg_-_csg-wukong-1B-chat-v0.1-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name csg-wukong-chat-v0.1 --size-in-billions 1 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/deepseek-chat.rst b/doc/source/models/builtin/llm/deepseek-chat.rst index 1e75ce8357..a33986c7b4 100644 --- a/doc/source/models/builtin/llm/deepseek-chat.rst +++ b/doc/source/models/builtin/llm/deepseek-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** deepseek-ai/deepseek-llm-7b-chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 67 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 67 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 67 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** deepseek-ai/deepseek-llm-67b-chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-chat --size-in-billions 67 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-chat --size-in-billions 67 --model-format pytorch --quantization ${quantization} Model Spec 3 (ggufv2, 7 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/deepseek-llm-7B-chat-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 4 (ggufv2, 67 Billion) @@ -65,11 +68,12 @@ Model Spec 4 (ggufv2, 67 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 67 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/deepseek-llm-67b-chat-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-chat --size-in-billions 67 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-chat --size-in-billions 67 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/deepseek-coder-instruct.rst b/doc/source/models/builtin/llm/deepseek-coder-instruct.rst index d80377faea..f4a14477b0 100644 --- a/doc/source/models/builtin/llm/deepseek-coder-instruct.rst +++ b/doc/source/models/builtin/llm/deepseek-coder-instruct.rst @@ -4,7 +4,7 @@ deepseek-coder-instruct ======================================== -- **Context Length:** 4096 +- **Context Length:** 16384 - **Model Name:** deepseek-coder-instruct - **Languages:** en, zh - **Abilities:** chat @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 1_3 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 1_3 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** deepseek-ai/deepseek-coder-1.3b-instruct - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 6_7 Billion) @@ -35,71 +36,204 @@ Model Spec 2 (pytorch, 6_7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6_7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** deepseek-ai/deepseek-coder-6.7b-instruct - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format pytorch --quantization ${quantization} -Model Spec 3 (pytorch, 33 Billion) +Model Spec 3 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-coder-7b-instruct-v1.5 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (pytorch, 33 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** pytorch - **Model Size (in billions):** 33 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** deepseek-ai/deepseek-coder-33b-instruct - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 33 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 33 --model-format pytorch --quantization ${quantization} -Model Spec 4 (ggufv2, 1_3 Billion) +Model Spec 5 (ggufv2, 1_3 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 1_3 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/deepseek-coder-1.3b-instruct-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format ggufv2 --quantization ${quantization} -Model Spec 5 (ggufv2, 6_7 Billion) +Model Spec 6 (ggufv2, 6_7 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 6_7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/deepseek-coder-6.7B-instruct-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** LoneStriker/deepseek-coder-7b-instruct-v1.5-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} -Model Spec 6 (ggufv2, 33 Billion) +Model Spec 8 (ggufv2, 33 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 33 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/deepseek-coder-33B-instruct-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-coder-instruct --size-in-billions 33 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 33 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 9 (gptq, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 1_3 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-1.3b-instruct-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format gptq --quantization ${quantization} + + +Model Spec 10 (gptq, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 6_7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-6.7B-instruct-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format gptq --quantization ${quantization} + + +Model Spec 11 (gptq, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 33 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-33B-instruct-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 33 --model-format gptq --quantization ${quantization} + + +Model Spec 12 (awq, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 1_3 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-1.3b-instruct-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 1_3 --model-format awq --quantization ${quantization} + + +Model Spec 13 (awq, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 6_7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-6.7B-instruct-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 6_7 --model-format awq --quantization ${quantization} + + +Model Spec 14 (awq, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 33 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-33B-instruct-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder-instruct --size-in-billions 33 --model-format awq --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/deepseek-coder.rst b/doc/source/models/builtin/llm/deepseek-coder.rst new file mode 100644 index 0000000000..84a3edc1b8 --- /dev/null +++ b/doc/source/models/builtin/llm/deepseek-coder.rst @@ -0,0 +1,239 @@ +.. _models_llm_deepseek-coder: + +======================================== +deepseek-coder +======================================== + +- **Context Length:** 16384 +- **Model Name:** deepseek-coder +- **Languages:** en, zh +- **Abilities:** generate +- **Description:** Deepseek Coder is composed of a series of code language models, each trained from scratch on 2T tokens, with a composition of 87% code and 13% natural language in both English and Chinese. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 1_3 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-coder-1.3b-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 1_3 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 6_7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-coder-6.7b-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 6_7 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-coder-7b-base-v1.5 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (pytorch, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 33 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-coder-33b-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 33 --model-format pytorch --quantization ${quantization} + + +Model Spec 5 (ggufv2, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 1_3 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/deepseek-coder-1.3b-base-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 1_3 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 6 (ggufv2, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 6_7 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/deepseek-coder-6.7B-base-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 6_7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** dagbs/deepseek-coder-7b-base-v1.5-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 8 (ggufv2, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 33 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/deepseek-coder-33B-base-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 33 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 9 (gptq, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 1_3 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-1.3b-base-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 1_3 --model-format gptq --quantization ${quantization} + + +Model Spec 10 (gptq, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 6_7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-6.7B-base-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 6_7 --model-format gptq --quantization ${quantization} + + +Model Spec 11 (gptq, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 33 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-33B-base-GPTQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 33 --model-format gptq --quantization ${quantization} + + +Model Spec 12 (awq, 1_3 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 1_3 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-1.3b-base-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 1_3 --model-format awq --quantization ${quantization} + + +Model Spec 13 (awq, 6_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 6_7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-6.7B-base-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 6_7 --model-format awq --quantization ${quantization} + + +Model Spec 14 (awq, 33 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 33 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TheBloke/deepseek-coder-33B-base-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek-coder --size-in-billions 33 --model-format awq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/deepseek-vl-chat.rst b/doc/source/models/builtin/llm/deepseek-vl-chat.rst index b6507b921e..ae00c384eb 100644 --- a/doc/source/models/builtin/llm/deepseek-vl-chat.rst +++ b/doc/source/models/builtin/llm/deepseek-vl-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 1_3 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 1_3 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** deepseek-ai/deepseek-vl-1.3b-chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-vl-chat --size-in-billions 1_3 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-vl-chat --size-in-billions 1_3 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** deepseek-ai/deepseek-vl-7b-chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name deepseek-vl-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name deepseek-vl-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/deepseek.rst b/doc/source/models/builtin/llm/deepseek.rst new file mode 100644 index 0000000000..d961c97eeb --- /dev/null +++ b/doc/source/models/builtin/llm/deepseek.rst @@ -0,0 +1,79 @@ +.. _models_llm_deepseek: + +======================================== +deepseek +======================================== + +- **Context Length:** 4096 +- **Model Name:** deepseek +- **Languages:** en, zh +- **Abilities:** generate +- **Description:** DeepSeek LLM, trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-llm-7b-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 67 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 67 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** deepseek-ai/deepseek-llm-67b-base +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek --size-in-billions 67 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/deepseek-llm-7B-chat-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 4 (ggufv2, 67 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 67 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/deepseek-llm-67b-chat-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name deepseek --size-in-billions 67 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/falcon-instruct.rst b/doc/source/models/builtin/llm/falcon-instruct.rst deleted file mode 100644 index d473a283c9..0000000000 --- a/doc/source/models/builtin/llm/falcon-instruct.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_falcon-instruct: - -======================================== -falcon-instruct -======================================== - -- **Context Length:** 2048 -- **Model Name:** falcon-instruct -- **Languages:** en -- **Abilities:** chat -- **Description:** Falcon-instruct is a fine-tuned version of the Falcon LLM, specializing in chatting. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** tiiuae/falcon-7b-instruct -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name falcon-instruct --size-in-billions 7 --model-format pytorch --quantization ${quantization} - - -Model Spec 2 (pytorch, 40 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 40 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** tiiuae/falcon-40b-instruct -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name falcon-instruct --size-in-billions 40 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/falcon.rst b/doc/source/models/builtin/llm/falcon.rst deleted file mode 100644 index 77264c6d9b..0000000000 --- a/doc/source/models/builtin/llm/falcon.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_falcon: - -======================================== -falcon -======================================== - -- **Context Length:** 2048 -- **Model Name:** falcon -- **Languages:** en -- **Abilities:** generate -- **Description:** Falcon is an open-source Transformer based LLM trained on the RefinedWeb dataset. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 40 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 40 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** tiiuae/falcon-40b -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name falcon --size-in-billions 40 --model-format pytorch --quantization ${quantization} - - -Model Spec 2 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** tiiuae/falcon-7b -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name falcon --size-in-billions 7 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/gemma-2-it.rst b/doc/source/models/builtin/llm/gemma-2-it.rst new file mode 100644 index 0000000000..780e4b1c5f --- /dev/null +++ b/doc/source/models/builtin/llm/gemma-2-it.rst @@ -0,0 +1,255 @@ +.. _models_llm_gemma-2-it: + +======================================== +gemma-2-it +======================================== + +- **Context Length:** 8192 +- **Model Name:** gemma-2-it +- **Languages:** en +- **Abilities:** chat +- **Description:** Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 2 +- **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** google/gemma-2-2b-it +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 2 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** google/gemma-2-9b-it +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 27 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 27 +- **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** google/gemma-2-27b-it +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 27 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (ggufv2, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 2 +- **Quantizations:** Q3_K_L, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6_K, Q6_K_L, Q8_0, f32 +- **Engines**: llama.cpp +- **Model ID:** bartowski/gemma-2-2b-it-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 2 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 5 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** Q2_K, Q2_K_L, Q3_K_L, Q3_K_M, Q3_K_S, Q4_K_L, Q4_K_M, Q4_K_S, Q5_K_L, Q5_K_M, Q5_K_S, Q6_K, Q6_K_L, Q8_0, f32 +- **Engines**: llama.cpp +- **Model ID:** bartowski/gemma-2-9b-it-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 6 (ggufv2, 27 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 27 +- **Quantizations:** Q2_K, Q2_K_L, Q3_K_L, Q3_K_M, Q3_K_S, Q4_K_L, Q4_K_M, Q4_K_S, Q5_K_L, Q5_K_M, Q5_K_S, Q6_K, Q6_K_L, Q8_0, f32 +- **Engines**: llama.cpp +- **Model ID:** bartowski/gemma-2-27b-it-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 27 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (mlx, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 2 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-2b-it-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 2 --model-format mlx --quantization ${quantization} + + +Model Spec 8 (mlx, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 2 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-2b-it-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 2 --model-format mlx --quantization ${quantization} + + +Model Spec 9 (mlx, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 2 +- **Quantizations:** None +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-2b-it +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 2 --model-format mlx --quantization ${quantization} + + +Model Spec 10 (mlx, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-9b-it-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 9 --model-format mlx --quantization ${quantization} + + +Model Spec 11 (mlx, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 9 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-9b-it-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 9 --model-format mlx --quantization ${quantization} + + +Model Spec 12 (mlx, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 9 +- **Quantizations:** None +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-9b-it-fp16 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 9 --model-format mlx --quantization ${quantization} + + +Model Spec 13 (mlx, 27 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 27 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-27b-it-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 27 --model-format mlx --quantization ${quantization} + + +Model Spec 14 (mlx, 27 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 27 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-27b-it-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 27 --model-format mlx --quantization ${quantization} + + +Model Spec 15 (mlx, 27 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 27 +- **Quantizations:** None +- **Engines**: MLX +- **Model ID:** mlx-community/gemma-2-27b-it-fp16 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name gemma-2-it --size-in-billions 27 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/gemma-it.rst b/doc/source/models/builtin/llm/gemma-it.rst index d67493ffdc..687a812fb0 100644 --- a/doc/source/models/builtin/llm/gemma-it.rst +++ b/doc/source/models/builtin/llm/gemma-it.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** google/gemma-2b-it - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gemma-it --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gemma-it --size-in-billions 2 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** google/gemma-7b-it - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gemma-it --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gemma-it --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/glaive-coder.rst b/doc/source/models/builtin/llm/glaive-coder.rst deleted file mode 100644 index a1ee441440..0000000000 --- a/doc/source/models/builtin/llm/glaive-coder.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_glaive-coder: - -======================================== -glaive-coder -======================================== - -- **Context Length:** 16384 -- **Model Name:** glaive-coder -- **Languages:** en -- **Abilities:** chat -- **Description:** A code model trained on a dataset of ~140k programming related problems and solutions generated from Glaive’s synthetic data generation platform. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** glaiveai/glaive-coder-7b -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name glaive-coder --size-in-billions 7 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/glm-4v.rst b/doc/source/models/builtin/llm/glm-4v.rst new file mode 100644 index 0000000000..a2b9f539e0 --- /dev/null +++ b/doc/source/models/builtin/llm/glm-4v.rst @@ -0,0 +1,31 @@ +.. _models_llm_glm-4v: + +======================================== +glm-4v +======================================== + +- **Context Length:** 8192 +- **Model Name:** glm-4v +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** THUDM/glm-4v-9b +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name glm-4v --size-in-billions 9 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/glm4-chat-1m.rst b/doc/source/models/builtin/llm/glm4-chat-1m.rst new file mode 100644 index 0000000000..06fa9cba74 --- /dev/null +++ b/doc/source/models/builtin/llm/glm4-chat-1m.rst @@ -0,0 +1,47 @@ +.. _models_llm_glm4-chat-1m: + +======================================== +glm4-chat-1m +======================================== + +- **Context Length:** 1048576 +- **Model Name:** glm4-chat-1m +- **Languages:** en, zh +- **Abilities:** chat, tools +- **Description:** GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** THUDM/glm-4-9b-chat-1m +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name glm4-chat-1m --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** Q2_K, IQ3_XS, IQ3_S, IQ3_M, Q3_K_S, Q3_K_L, Q3_K, IQ4_XS, IQ4_NL, Q4_K_S, Q4_K, Q5_K_S, Q5_K, Q6_K, Q8_0, BF16, FP16 +- **Engines**: llama.cpp +- **Model ID:** legraphista/glm-4-9b-chat-1m-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name glm4-chat-1m --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/glm4-chat.rst b/doc/source/models/builtin/llm/glm4-chat.rst new file mode 100644 index 0000000000..b657bd27b3 --- /dev/null +++ b/doc/source/models/builtin/llm/glm4-chat.rst @@ -0,0 +1,47 @@ +.. _models_llm_glm4-chat: + +======================================== +glm4-chat +======================================== + +- **Context Length:** 131072 +- **Model Name:** glm4-chat +- **Languages:** en, zh +- **Abilities:** chat, tools +- **Description:** GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** THUDM/glm-4-9b-chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name glm4-chat --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** Q2_K, IQ3_XS, IQ3_S, IQ3_M, Q3_K_S, Q3_K_L, Q3_K, IQ4_XS, IQ4_NL, Q4_K_S, Q4_K, Q5_K_S, Q5_K, Q6_K, Q8_0, BF16, FP16 +- **Engines**: llama.cpp +- **Model ID:** legraphista/glm-4-9b-chat-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name glm4-chat --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/gorilla-openfunctions-v1.rst b/doc/source/models/builtin/llm/gorilla-openfunctions-v1.rst index 1c22a5f220..d7ea21418d 100644 --- a/doc/source/models/builtin/llm/gorilla-openfunctions-v1.rst +++ b/doc/source/models/builtin/llm/gorilla-openfunctions-v1.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** gorilla-llm/gorilla-openfunctions-v1 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gorilla-openfunctions-v1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gorilla-openfunctions-v1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/gorilla-openfunctions-v1-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gorilla-openfunctions-v1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gorilla-openfunctions-v1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/gorilla-openfunctions-v2.rst b/doc/source/models/builtin/llm/gorilla-openfunctions-v2.rst index 471e85d3a1..a4b7aacace 100644 --- a/doc/source/models/builtin/llm/gorilla-openfunctions-v2.rst +++ b/doc/source/models/builtin/llm/gorilla-openfunctions-v2.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** gorilla-llm/gorilla-openfunctions-v2 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gorilla-openfunctions-v2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gorilla-openfunctions-v2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6_K +- **Engines**: llama.cpp - **Model ID:** gorilla-llm//gorilla-openfunctions-v2-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gorilla-openfunctions-v2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gorilla-openfunctions-v2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/gpt-2.rst b/doc/source/models/builtin/llm/gpt-2.rst index bfc94146ea..c314ae9c99 100644 --- a/doc/source/models/builtin/llm/gpt-2.rst +++ b/doc/source/models/builtin/llm/gpt-2.rst @@ -14,17 +14,18 @@ Specifications ^^^^^^^^^^^^^^ -Model Spec 1 (ggmlv3, 1 Billion) +Model Spec 1 (pytorch, 1_5 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 1 +- **Model Format:** pytorch +- **Model Size (in billions):** 1_5 - **Quantizations:** none -- **Model ID:** marella/gpt-2-ggml -- **Model Hubs**: `Hugging Face `__ +- **Engines**: Transformers +- **Model ID:** openai-community/gpt2 +- **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name gpt-2 --size-in-billions 1 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name gpt-2 --size-in-billions 1_5 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/index.rst b/doc/source/models/builtin/llm/index.rst index 63cd05bdf8..75745ffdc6 100644 --- a/doc/source/models/builtin/llm/index.rst +++ b/doc/source/models/builtin/llm/index.rst @@ -31,11 +31,6 @@ The following is a list of built-in LLM in Xinference: - 16384 - AquilaChat2-16k series models are the long-text chat models - * - :ref:`baichuan ` - - generate - - 4096 - - Baichuan is an open-source Transformer based LLM that is trained on both Chinese and English data. - * - :ref:`baichuan-2 ` - generate - 4096 @@ -46,25 +41,10 @@ The following is a list of built-in LLM in Xinference: - 4096 - Baichuan2-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting. - * - :ref:`baichuan-chat ` + * - :ref:`c4ai-command-r-v01 ` - chat - - 4096 - - Baichuan-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting. - - * - :ref:`chatglm ` - - chat - - 2048 - - ChatGLM is an open-source General Language Model (GLM) based LLM trained on both Chinese and English data. - - * - :ref:`chatglm2 ` - - chat - - 8192 - - ChatGLM2 is the second generation of ChatGLM, still open-source and trained on Chinese and English data. - - * - :ref:`chatglm2-32k ` - - chat - - 32768 - - ChatGLM2-32k is a special version of ChatGLM2, with a context window of 32k tokens instead of 8k. + - 131072 + - C4AI Command-R(+) is a research release of a 35 and 104 billion parameter highly performant generative model. * - :ref:`chatglm3 ` - chat, tools @@ -96,6 +76,21 @@ The following is a list of built-in LLM in Xinference: - 100000 - Code-Llama-Python is a fine-tuned version of the Code-Llama LLM, specializing in Python. + * - :ref:`codegeex4 ` + - chat + - 131072 + - the open-source version of the latest CodeGeeX4 model series + + * - :ref:`codeqwen1.5 ` + - generate + - 65536 + - CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes. + + * - :ref:`codeqwen1.5-chat ` + - chat + - 65536 + - CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes. + * - :ref:`codeshell ` - generate - 8194 @@ -106,14 +101,44 @@ The following is a list of built-in LLM in Xinference: - 8194 - CodeShell is a multi-language code LLM developed by the Knowledge Computing Lab of Peking University. + * - :ref:`codestral-v0.1 ` + - generate + - 32768 + - Codestrall-22B-v0.1 is trained on a diverse dataset of 80+ programming languages, including the most popular ones, such as Python, Java, C, C++, JavaScript, and Bash + + * - :ref:`cogvlm2 ` + - chat, vision + - 8192 + - CogVLM2 have achieved good results in many lists compared to the previous generation of CogVLM open source models. Its excellent performance can compete with some non-open source models. + + * - :ref:`cogvlm2-video-llama3-chat ` + - chat, vision + - 8192 + - CogVLM2-Video achieves state-of-the-art performance on multiple video question answering tasks. + + * - :ref:`csg-wukong-chat-v0.1 ` + - chat + - 32768 + - csg-wukong-1B is a 1 billion-parameter small language model(SLM) pretrained on 1T tokens. + + * - :ref:`deepseek ` + - generate + - 4096 + - DeepSeek LLM, trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese. + * - :ref:`deepseek-chat ` - chat - 4096 - DeepSeek LLM is an advanced language model comprising 67 billion parameters. It has been trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese. + * - :ref:`deepseek-coder ` + - generate + - 16384 + - Deepseek Coder is composed of a series of code language models, each trained from scratch on 2T tokens, with a composition of 87% code and 13% natural language in both English and Chinese. + * - :ref:`deepseek-coder-instruct ` - chat - - 4096 + - 16384 - deepseek-coder-instruct is a model initialized from deepseek-coder-base and fine-tuned on 2B tokens of instruction data. * - :ref:`deepseek-vl-chat ` @@ -121,25 +146,30 @@ The following is a list of built-in LLM in Xinference: - 4096 - DeepSeek-VL possesses general multimodal understanding capabilities, capable of processing logical diagrams, web pages, formula recognition, scientific literature, natural images, and embodied intelligence in complex scenarios. - * - :ref:`falcon ` - - generate - - 2048 - - Falcon is an open-source Transformer based LLM trained on the RefinedWeb dataset. - - * - :ref:`falcon-instruct ` + * - :ref:`gemma-2-it ` - chat - - 2048 - - Falcon-instruct is a fine-tuned version of the Falcon LLM, specializing in chatting. + - 8192 + - Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models. * - :ref:`gemma-it ` - chat - 8192 - Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models. - * - :ref:`glaive-coder ` - - chat - - 16384 - - A code model trained on a dataset of ~140k programming related problems and solutions generated from Glaive’s synthetic data generation platform. + * - :ref:`glm-4v ` + - chat, vision + - 8192 + - GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. + + * - :ref:`glm4-chat ` + - chat, tools + - 131072 + - GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. + + * - :ref:`glm4-chat-1m ` + - chat, tools + - 1048576 + - GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI. * - :ref:`gorilla-openfunctions-v1 ` - chat @@ -156,30 +186,30 @@ The following is a list of built-in LLM in Xinference: - 1024 - GPT-2 is a Transformer-based LLM that is trained on WebTest, a 40 GB dataset of Reddit posts with 3+ upvotes. - * - :ref:`internlm-20b ` - - generate - - 16384 - - Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. - - * - :ref:`internlm-7b ` - - generate - - 8192 - - InternLM is a Transformer-based LLM that is trained on both Chinese and English data, focusing on practical scenarios. - - * - :ref:`internlm-chat-20b ` + * - :ref:`internlm2-chat ` - chat - - 16384 - - Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. The Chat version has undergone SFT and RLHF training. + - 32768 + - The second generation of the InternLM model, InternLM2. - * - :ref:`internlm-chat-7b ` + * - :ref:`internlm2.5-chat ` - chat - - 4096 - - Internlm-chat is a fine-tuned version of the Internlm LLM, specializing in chatting. + - 32768 + - InternLM2.5 series of the InternLM model. - * - :ref:`internlm2-chat ` + * - :ref:`internlm2.5-chat-1m ` - chat - - 204800 - - The second generation of the InternLM model, InternLM2. + - 262144 + - InternLM2.5 series of the InternLM model supports 1M long-context + + * - :ref:`internvl-chat ` + - chat, vision + - 32768 + - InternVL 1.5 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. + + * - :ref:`internvl2 ` + - chat, vision + - 32768 + - InternVL 2 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. * - :ref:`llama-2 ` - generate @@ -191,6 +221,26 @@ The following is a list of built-in LLM in Xinference: - 4096 - Llama-2-Chat is a fine-tuned version of the Llama-2 LLM, specializing in chatting. + * - :ref:`llama-3 ` + - generate + - 8192 + - Llama 3 is an auto-regressive language model that uses an optimized transformer architecture + + * - :ref:`llama-3-instruct ` + - chat + - 8192 + - The Llama 3 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks.. + + * - :ref:`llama-3.1 ` + - generate + - 131072 + - Llama 3.1 is an auto-regressive language model that uses an optimized transformer architecture + + * - :ref:`llama-3.1-instruct ` + - chat + - 131072 + - The Llama 3.1 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks.. + * - :ref:`minicpm-2b-dpo-bf16 ` - chat - 4096 @@ -216,6 +266,16 @@ The following is a list of built-in LLM in Xinference: - 4096 - MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings. + * - :ref:`minicpm-llama3-v-2_5 ` + - chat, vision + - 8192 + - MiniCPM-Llama3-V 2.5 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Llama3-8B-Instruct with a total of 8B parameters. + + * - :ref:`minicpm-v-2.6 ` + - chat, vision + - 32768 + - MiniCPM-V 2.6 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Qwen2-7B with a total of 8B parameters. + * - :ref:`mistral-instruct-v0.1 ` - chat - 8192 @@ -226,11 +286,31 @@ The following is a list of built-in LLM in Xinference: - 8192 - The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1. + * - :ref:`mistral-instruct-v0.3 ` + - chat + - 32768 + - The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1. + + * - :ref:`mistral-large-instruct ` + - chat + - 131072 + - Mistral-Large-Instruct-2407 is an advanced dense Large Language Model (LLM) of 123B parameters with state-of-the-art reasoning, knowledge and coding capabilities. + + * - :ref:`mistral-nemo-instruct ` + - chat + - 1024000 + - The Mistral-Nemo-Instruct-2407 Large Language Model (LLM) is an instruct fine-tuned version of the Mistral-Nemo-Base-2407 + * - :ref:`mistral-v0.1 ` - generate - 8192 - Mistral-7B is a unmoderated Transformer based LLM claiming to outperform Llama2 on all benchmarks. + * - :ref:`mixtral-8x22b-instruct-v0.1 ` + - chat + - 65536 + - The Mixtral-8x22B-Instruct-v0.1 Large Language Model (LLM) is an instruct fine-tuned version of the Mixtral-8x22B-v0.1, specializing in chatting. + * - :ref:`mixtral-instruct-v0.1 ` - chat - 32768 @@ -246,11 +326,6 @@ The following is a list of built-in LLM in Xinference: - 2048 - OmniLMM is a family of open-source large multimodal models (LMMs) adept at vision & language modeling. - * - :ref:`openbuddy ` - - chat - - 2048 - - OpenBuddy is a powerful open multilingual chatbot model aimed at global users. - * - :ref:`openhermes-2.5 ` - chat - 8192 @@ -261,11 +336,6 @@ The following is a list of built-in LLM in Xinference: - 2048 - Opt is an open-source, decoder-only, Transformer based LLM that was designed to replicate GPT-3. - * - :ref:`orca ` - - chat - - 2048 - - Orca is an LLM trained by fine-tuning LLaMA on explanation traces obtained from GPT-4. - * - :ref:`orion-chat ` - chat - 4096 @@ -281,6 +351,16 @@ The following is a list of built-in LLM in Xinference: - 2048 - Phi-2 is a 2.7B Transformer based LLM used for research on model safety, trained with data similar to Phi-1.5 but augmented with synthetic texts and curated websites. + * - :ref:`phi-3-mini-128k-instruct ` + - chat + - 128000 + - The Phi-3-Mini-128K-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets. + + * - :ref:`phi-3-mini-4k-instruct ` + - chat + - 4096 + - The Phi-3-Mini-4k-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets. + * - :ref:`platypus2-70b-instruct ` - generate - 4096 @@ -301,6 +381,31 @@ The following is a list of built-in LLM in Xinference: - 32768 - Qwen1.5 is the beta version of Qwen2, a transformer-based decoder-only language model pretrained on a large amount of data. + * - :ref:`qwen1.5-moe-chat ` + - chat, tools + - 32768 + - Qwen1.5-MoE is a transformer-based MoE decoder-only language model pretrained on a large amount of data. + + * - :ref:`qwen2-instruct ` + - chat, tools + - 32768 + - Qwen2 is the new series of Qwen large language models + + * - :ref:`qwen2-moe-instruct ` + - chat, tools + - 32768 + - Qwen2 is the new series of Qwen large language models. + + * - :ref:`seallm_v2 ` + - generate + - 8192 + - We introduce SeaLLM-7B-v2, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages + + * - :ref:`seallm_v2.5 ` + - generate + - 8192 + - We introduce SeaLLM-7B-v2.5, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages + * - :ref:`skywork ` - generate - 4096 @@ -311,51 +416,26 @@ The following is a list of built-in LLM in Xinference: - 4096 - Skywork is a series of large models developed by the Kunlun Group · Skywork team. - * - :ref:`starchat-beta ` + * - :ref:`starling-lm ` - chat - - 8192 - - Starchat-beta is a fine-tuned version of the Starcoderplus LLM, specializing in coding assistance. - - * - :ref:`starcoder ` - - generate - - 8192 - - Starcoder is an open-source Transformer based LLM that is trained on permissively licensed data from GitHub. + - 4096 + - We introduce Starling-7B, an open large language model (LLM) trained by Reinforcement Learning from AI Feedback (RLAIF). The model harnesses the power of our new GPT-4 labeled ranking dataset - * - :ref:`starcoderplus ` - - generate + * - :ref:`telechat ` + - chat - 8192 - - Starcoderplus is an open-source LLM trained by fine-tuning Starcoder on RedefinedWeb and StarCoderData datasets. + - The TeleChat is a large language model developed and trained by China Telecom Artificial Intelligence Technology Co., LTD. The 7B model base is trained with 1.5 trillion Tokens and 3 trillion Tokens and Chinese high-quality corpus. * - :ref:`tiny-llama ` - generate - 2048 - The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens. - * - :ref:`vicuna-v1.3 ` - - chat - - 2048 - - Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT. - - * - :ref:`vicuna-v1.5 ` - - chat - - 4096 - - Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT. - - * - :ref:`vicuna-v1.5-16k ` - - chat - - 16384 - - Vicuna-v1.5-16k is a special version of Vicuna-v1.5, with a context window of 16k tokens instead of 4k. - * - :ref:`wizardcoder-python-v1.0 ` - chat - 100000 - - * - :ref:`wizardlm-v1.0 ` - - chat - - 2048 - - WizardLM is an open-source LLM trained by fine-tuning LLaMA with Evol-Instruct. - * - :ref:`wizardmath-v1.0 ` - chat - 2048 @@ -376,19 +456,34 @@ The following is a list of built-in LLM in Xinference: - 4096 - The Yi series models are large language models trained from scratch by developers at 01.AI. + * - :ref:`yi-1.5 ` + - generate + - 4096 + - Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + + * - :ref:`yi-1.5-chat ` + - chat + - 4096 + - Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + + * - :ref:`yi-1.5-chat-16k ` + - chat + - 16384 + - Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + * - :ref:`yi-200k ` - generate - - 204800 + - 262144 - The Yi series models are large language models trained from scratch by developers at 01.AI. * - :ref:`yi-chat ` - chat - - 204800 + - 4096 - The Yi series models are large language models trained from scratch by developers at 01.AI. * - :ref:`yi-vl-chat ` - chat, vision - - 204800 + - 4096 - Yi Vision Language (Yi-VL) model is the open-source, multimodal version of the Yi Large Language Model (LLM) series, enabling content comprehension, recognition, and multi-round conversations about images. * - :ref:`zephyr-7b-alpha ` @@ -412,19 +507,11 @@ The following is a list of built-in LLM in Xinference: aquila2-chat-16k - baichuan - baichuan-2 baichuan-2-chat - baichuan-chat - - chatglm - - chatglm2 - - chatglm2-32k + c4ai-command-r-v01 chatglm3 @@ -438,23 +525,43 @@ The following is a list of built-in LLM in Xinference: code-llama-python + codegeex4 + + codeqwen1.5 + + codeqwen1.5-chat + codeshell codeshell-chat + codestral-v0.1 + + cogvlm2 + + cogvlm2-video-llama3-chat + + csg-wukong-chat-v0.1 + + deepseek + deepseek-chat + deepseek-coder + deepseek-coder-instruct deepseek-vl-chat - falcon - - falcon-instruct + gemma-2-it gemma-it - glaive-coder + glm-4v + + glm4-chat + + glm4-chat-1m gorilla-openfunctions-v1 @@ -462,20 +569,28 @@ The following is a list of built-in LLM in Xinference: gpt-2 - internlm-20b + internlm2-chat - internlm-7b + internlm2.5-chat - internlm-chat-20b + internlm2.5-chat-1m - internlm-chat-7b + internvl-chat - internlm2-chat + internvl2 llama-2 llama-2-chat + llama-3 + + llama-3-instruct + + llama-3.1 + + llama-3.1-instruct + minicpm-2b-dpo-bf16 minicpm-2b-dpo-fp16 @@ -486,32 +601,44 @@ The following is a list of built-in LLM in Xinference: minicpm-2b-sft-fp32 + minicpm-llama3-v-2_5 + + minicpm-v-2.6 + mistral-instruct-v0.1 mistral-instruct-v0.2 + mistral-instruct-v0.3 + + mistral-large-instruct + + mistral-nemo-instruct + mistral-v0.1 + mixtral-8x22b-instruct-v0.1 + mixtral-instruct-v0.1 mixtral-v0.1 omnilmm - openbuddy - openhermes-2.5 opt - orca - orion-chat orion-chat-rag phi-2 + phi-3-mini-128k-instruct + + phi-3-mini-4k-instruct + platypus2-70b-instruct qwen-chat @@ -520,28 +647,28 @@ The following is a list of built-in LLM in Xinference: qwen1.5-chat - skywork + qwen1.5-moe-chat - skywork-math + qwen2-instruct - starchat-beta + qwen2-moe-instruct - starcoder + seallm_v2 - starcoderplus + seallm_v2.5 - tiny-llama + skywork + + skywork-math - vicuna-v1.3 + starling-lm - vicuna-v1.5 + telechat - vicuna-v1.5-16k + tiny-llama wizardcoder-python-v1.0 - wizardlm-v1.0 - wizardmath-v1.0 xverse @@ -550,6 +677,12 @@ The following is a list of built-in LLM in Xinference: yi + yi-1.5 + + yi-1.5-chat + + yi-1.5-chat-16k + yi-200k yi-chat diff --git a/doc/source/models/builtin/llm/internlm-20b.rst b/doc/source/models/builtin/llm/internlm-20b.rst deleted file mode 100644 index 8743800c7f..0000000000 --- a/doc/source/models/builtin/llm/internlm-20b.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_internlm-20b: - -======================================== -internlm-20b -======================================== - -- **Context Length:** 16384 -- **Model Name:** internlm-20b -- **Languages:** en, zh -- **Abilities:** generate -- **Description:** Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 20 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 20 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** internlm/internlm-20b -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name internlm-20b --size-in-billions 20 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/internlm-7b.rst b/doc/source/models/builtin/llm/internlm-7b.rst deleted file mode 100644 index df6712ca40..0000000000 --- a/doc/source/models/builtin/llm/internlm-7b.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_internlm-7b: - -======================================== -internlm-7b -======================================== - -- **Context Length:** 8192 -- **Model Name:** internlm-7b -- **Languages:** en, zh -- **Abilities:** generate -- **Description:** InternLM is a Transformer-based LLM that is trained on both Chinese and English data, focusing on practical scenarios. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** internlm/internlm-7b -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name internlm-7b --size-in-billions 7 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/internlm-chat-20b.rst b/doc/source/models/builtin/llm/internlm-chat-20b.rst deleted file mode 100644 index 028153d6e0..0000000000 --- a/doc/source/models/builtin/llm/internlm-chat-20b.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_internlm-chat-20b: - -======================================== -internlm-chat-20b -======================================== - -- **Context Length:** 16384 -- **Model Name:** internlm-chat-20b -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. The Chat version has undergone SFT and RLHF training. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 20 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 20 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** internlm/internlm-chat-20b -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name internlm-chat-20b --size-in-billions 20 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/internlm-chat-7b.rst b/doc/source/models/builtin/llm/internlm-chat-7b.rst deleted file mode 100644 index 889a6af885..0000000000 --- a/doc/source/models/builtin/llm/internlm-chat-7b.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_internlm-chat-7b: - -======================================== -internlm-chat-7b -======================================== - -- **Context Length:** 4096 -- **Model Name:** internlm-chat-7b -- **Languages:** en, zh -- **Abilities:** chat -- **Description:** Internlm-chat is a fine-tuned version of the Internlm LLM, specializing in chatting. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** internlm/internlm-chat-7b -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name internlm-chat-7b --size-in-billions 7 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/internlm2-chat.rst b/doc/source/models/builtin/llm/internlm2-chat.rst index 87150cc205..47fb28a36d 100644 --- a/doc/source/models/builtin/llm/internlm2-chat.rst +++ b/doc/source/models/builtin/llm/internlm2-chat.rst @@ -4,7 +4,7 @@ internlm2-chat ======================================== -- **Context Length:** 204800 +- **Context Length:** 32768 - **Model Name:** internlm2-chat - **Languages:** en, zh - **Abilities:** chat @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: vLLM, Transformers - **Model ID:** internlm/internlm2-chat-7b - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name internlm2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name internlm2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 20 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 20 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 20 - **Quantizations:** none +- **Engines**: vLLM, Transformers - **Model ID:** internlm/internlm2-chat-20b - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name internlm2-chat --size-in-billions 20 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name internlm2-chat --size-in-billions 20 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/internlm2.5-chat-1m.rst b/doc/source/models/builtin/llm/internlm2.5-chat-1m.rst new file mode 100644 index 0000000000..b7ff7f7635 --- /dev/null +++ b/doc/source/models/builtin/llm/internlm2.5-chat-1m.rst @@ -0,0 +1,63 @@ +.. _models_llm_internlm2.5-chat-1m: + +======================================== +internlm2.5-chat-1m +======================================== + +- **Context Length:** 262144 +- **Model Name:** internlm2.5-chat-1m +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** InternLM2.5 series of the InternLM model supports 1M long-context + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** internlm/internlm2_5-7b-chat-1m +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat-1m --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (gptq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** ModelCloud/internlm-2.5-7b-chat-1m-gptq-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat-1m --size-in-billions 7 --model-format gptq --quantization ${quantization} + + +Model Spec 3 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** internlm/internlm2_5-7b-chat-1m-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat-1m --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/internlm2.5-chat.rst b/doc/source/models/builtin/llm/internlm2.5-chat.rst new file mode 100644 index 0000000000..f2fd7b7bd9 --- /dev/null +++ b/doc/source/models/builtin/llm/internlm2.5-chat.rst @@ -0,0 +1,159 @@ +.. _models_llm_internlm2.5-chat: + +======================================== +internlm2.5-chat +======================================== + +- **Context Length:** 32768 +- **Model Name:** internlm2.5-chat +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** InternLM2.5 series of the InternLM model. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 1_8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 1_8 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** internlm/internlm2_5-1_8b-chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 1_8 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** internlm/internlm2_5-7b-chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 20 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 20 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** internlm/internlm2_5-20b-chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 20 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (gptq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** ModelCloud/internlm-2.5-7b-chat-gptq-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} + + +Model Spec 5 (ggufv2, 1_8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 1_8 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** internlm/internlm2_5-1_8b-chat-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 1_8 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 6 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** internlm/internlm2_5-7b-chat-gguf +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (ggufv2, 20 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 20 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** internlm/internlm2_5-20b-chat-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 20 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 8 (mlx, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/internlm2_5-7b-chat-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 7 --model-format mlx --quantization ${quantization} + + +Model Spec 9 (mlx, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 7 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/internlm2_5-7b-chat-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internlm2.5-chat --size-in-billions 7 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/internvl-chat.rst b/doc/source/models/builtin/llm/internvl-chat.rst new file mode 100644 index 0000000000..87b66bb200 --- /dev/null +++ b/doc/source/models/builtin/llm/internvl-chat.rst @@ -0,0 +1,63 @@ +.. _models_llm_internvl-chat: + +======================================== +internvl-chat +======================================== + +- **Context Length:** 32768 +- **Model Name:** internvl-chat +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** InternVL 1.5 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 2 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** OpenGVLab/Mini-InternVL-Chat-2B-V1-5 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl-chat --size-in-billions 2 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 4 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** OpenGVLab/Mini-InternVL-Chat-4B-V1-5 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl-chat --size-in-billions 4 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 26 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 26 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** OpenGVLab/InternVL-Chat-V1-5 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl-chat --size-in-billions 26 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/internvl2.rst b/doc/source/models/builtin/llm/internvl2.rst new file mode 100644 index 0000000000..cf74863d96 --- /dev/null +++ b/doc/source/models/builtin/llm/internvl2.rst @@ -0,0 +1,207 @@ +.. _models_llm_internvl2: + +======================================== +internvl2 +======================================== + +- **Context Length:** 32768 +- **Model Name:** internvl2 +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** InternVL 2 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 1 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 1 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-1B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 1 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 2 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-2B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (awq, 2 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 2 +- **Quantizations:** Int4 +- **Engines**: +- **Model ID:** OpenGVLab/InternVL2-2B-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 2 --model-format awq --quantization ${quantization} + + +Model Spec 4 (pytorch, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 4 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-4B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 4 --model-format pytorch --quantization ${quantization} + + +Model Spec 5 (awq, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 4 +- **Quantizations:** Int4 +- **Engines**: +- **Model ID:** OpenGVLab/InternVL2-8B-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 4 --model-format awq --quantization ${quantization} + + +Model Spec 6 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-8B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 7 (pytorch, 26 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 26 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-26B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 26 --model-format pytorch --quantization ${quantization} + + +Model Spec 8 (awq, 26 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 26 +- **Quantizations:** Int4 +- **Engines**: +- **Model ID:** OpenGVLab/InternVL2-26B-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 26 --model-format awq --quantization ${quantization} + + +Model Spec 9 (pytorch, 40 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 40 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-40B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 40 --model-format pytorch --quantization ${quantization} + + +Model Spec 10 (awq, 40 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 40 +- **Quantizations:** Int4 +- **Engines**: +- **Model ID:** OpenGVLab/InternVL2-40B-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 40 --model-format awq --quantization ${quantization} + + +Model Spec 11 (pytorch, 76 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 76 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** OpenGVLab/InternVL2-Llama3-76B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 76 --model-format pytorch --quantization ${quantization} + + +Model Spec 12 (awq, 76 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 76 +- **Quantizations:** Int4 +- **Engines**: +- **Model ID:** OpenGVLab/InternVL2-Llama3-76B-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name internvl2 --size-in-billions 76 --model-format awq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/llama-2-chat.rst b/doc/source/models/builtin/llm/llama-2-chat.rst index e7a340cba6..ebcc14f7ca 100644 --- a/doc/source/models/builtin/llm/llama-2-chat.rst +++ b/doc/source/models/builtin/llm/llama-2-chat.rst @@ -14,49 +14,52 @@ Specifications ^^^^^^^^^^^^^^ -Model Spec 1 (ggmlv3, 7 Billion) +Model Spec 1 (ggufv2, 7 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 7 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-7B-Chat-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-7B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} -Model Spec 2 (ggmlv3, 13 Billion) +Model Spec 2 (ggufv2, 13 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 13 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-13B-chat-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-13B-chat-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} -Model Spec 3 (ggmlv3, 70 Billion) +Model Spec 3 (ggufv2, 70 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 70 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-70B-Chat-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-70B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 70 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} Model Spec 4 (pytorch, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-7b-chat-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 5 (gptq, 7 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-7B-Chat-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} Model Spec 6 (gptq, 70 Billion) @@ -95,13 +100,14 @@ Model Spec 6 (gptq, 70 Billion) - **Model Format:** gptq - **Model Size (in billions):** 70 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-70B-Chat-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 70 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 70 --model-format gptq --quantization ${quantization} Model Spec 7 (awq, 70 Billion) @@ -110,13 +116,14 @@ Model Spec 7 (awq, 70 Billion) - **Model Format:** awq - **Model Size (in billions):** 70 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-70B-Chat-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 70 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 70 --model-format awq --quantization ${quantization} Model Spec 8 (awq, 7 Billion) @@ -125,13 +132,14 @@ Model Spec 8 (awq, 7 Billion) - **Model Format:** awq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-7B-Chat-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 7 --model-format awq --quantization ${quantization} Model Spec 9 (pytorch, 13 Billion) @@ -140,13 +148,14 @@ Model Spec 9 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-13b-chat-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 10 (gptq, 13 Billion) @@ -155,13 +164,14 @@ Model Spec 10 (gptq, 13 Billion) - **Model Format:** gptq - **Model Size (in billions):** 13 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-13B-chat-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 13 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 13 --model-format gptq --quantization ${quantization} Model Spec 11 (awq, 13 Billion) @@ -170,13 +180,14 @@ Model Spec 11 (awq, 13 Billion) - **Model Format:** awq - **Model Size (in billions):** 13 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-13B-chat-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 13 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 13 --model-format awq --quantization ${quantization} Model Spec 12 (pytorch, 70 Billion) @@ -185,56 +196,12 @@ Model Spec 12 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-70b-chat-hf - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2-chat --size-in-billions 70 --model-format pytorch --quantization ${quantization} - - -Model Spec 13 (ggufv2, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggufv2 -- **Model Size (in billions):** 7 -- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 -- **Model ID:** TheBloke/Llama-2-7B-Chat-GGUF -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name llama-2-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} - - -Model Spec 14 (ggufv2, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggufv2 -- **Model Size (in billions):** 13 -- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 -- **Model ID:** TheBloke/Llama-2-13B-chat-GGUF -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name llama-2-chat --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} - - -Model Spec 15 (ggufv2, 70 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggufv2 -- **Model Size (in billions):** 70 -- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M -- **Model ID:** TheBloke/Llama-2-70B-Chat-GGUF -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name llama-2-chat --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2-chat --size-in-billions 70 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/llama-2.rst b/doc/source/models/builtin/llm/llama-2.rst index 9cfb367661..11c634b467 100644 --- a/doc/source/models/builtin/llm/llama-2.rst +++ b/doc/source/models/builtin/llm/llama-2.rst @@ -14,19 +14,20 @@ Specifications ^^^^^^^^^^^^^^ -Model Spec 1 (ggmlv3, 7 Billion) +Model Spec 1 (ggufv2, 7 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 7 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-7B-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-7B-GGUF +- **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 2 (gptq, 7 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-7B-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 7 --model-format gptq --quantization ${quantization} Model Spec 3 (awq, 7 Billion) @@ -50,43 +52,46 @@ Model Spec 3 (awq, 7 Billion) - **Model Format:** awq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-7B-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 7 --model-format awq --quantization ${quantization} -Model Spec 4 (ggmlv3, 13 Billion) +Model Spec 4 (ggufv2, 13 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 13 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-13B-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-13B-GGUF +- **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} -Model Spec 5 (ggmlv3, 70 Billion) +Model Spec 5 (ggufv2, 70 Billion) ++++++++++++++++++++++++++++++++++++++++ -- **Model Format:** ggmlv3 +- **Model Format:** ggufv2 - **Model Size (in billions):** 70 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/Llama-2-70B-GGML -- **Model Hubs**: `Hugging Face `__ +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M +- **Engines**: llama.cpp +- **Model ID:** TheBloke/Llama-2-70B-GGUF +- **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 70 --model-format ggmlv3 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} Model Spec 6 (pytorch, 7 Billion) @@ -95,13 +100,14 @@ Model Spec 6 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-7b-hf - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 7 (pytorch, 13 Billion) @@ -110,13 +116,14 @@ Model Spec 7 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-13b-hf - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 8 (gptq, 13 Billion) @@ -125,13 +132,14 @@ Model Spec 8 (gptq, 13 Billion) - **Model Format:** gptq - **Model Size (in billions):** 13 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-13B-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 13 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 13 --model-format gptq --quantization ${quantization} Model Spec 9 (awq, 13 Billion) @@ -140,13 +148,14 @@ Model Spec 9 (awq, 13 Billion) - **Model Format:** awq - **Model Size (in billions):** 13 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-13B-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 13 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 13 --model-format awq --quantization ${quantization} Model Spec 10 (pytorch, 70 Billion) @@ -155,13 +164,14 @@ Model Spec 10 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** meta-llama/Llama-2-70b-hf - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 70 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 70 --model-format pytorch --quantization ${quantization} Model Spec 11 (gptq, 70 Billion) @@ -170,13 +180,14 @@ Model Spec 11 (gptq, 70 Billion) - **Model Format:** gptq - **Model Size (in billions):** 70 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-70B-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 70 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 70 --model-format gptq --quantization ${quantization} Model Spec 12 (awq, 70 Billion) @@ -185,11 +196,12 @@ Model Spec 12 (awq, 70 Billion) - **Model Format:** awq - **Model Size (in billions):** 70 - **Quantizations:** Int4 +- **Engines**: vLLM, SGLang - **Model ID:** TheBloke/Llama-2-70B-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name llama-2 --size-in-billions 70 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name llama-2 --size-in-billions 70 --model-format awq --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/llama-3-instruct.rst b/doc/source/models/builtin/llm/llama-3-instruct.rst new file mode 100644 index 0000000000..327be127ab --- /dev/null +++ b/doc/source/models/builtin/llm/llama-3-instruct.rst @@ -0,0 +1,207 @@ +.. _models_llm_llama-3-instruct: + +======================================== +llama-3-instruct +======================================== + +- **Context Length:** 8192 +- **Model Name:** llama-3-instruct +- **Languages:** en +- **Abilities:** chat +- **Description:** The Llama 3 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks.. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (ggufv2, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 8 +- **Quantizations:** IQ3_M, Q4_K_M, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Meta-Llama-3-8B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 2 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3-8B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (ggufv2, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 70 +- **Quantizations:** IQ1_M, IQ2_XS, Q4_K_M +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Meta-Llama-3-70B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 4 (pytorch, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3-70B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format pytorch --quantization ${quantization} + + +Model Spec 5 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-8B-Instruct-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 6 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-8B-Instruct-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 7 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-8B-Instruct +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 8 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-70B-Instruct-4bit-mlx +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 9 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-70B-Instruct-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 10 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3-70B-Instruct-mlx-unquantized +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 11 (gptq, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 8 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** TechxGenus/Meta-Llama-3-8B-Instruct-GPTQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 8 --model-format gptq --quantization ${quantization} + + +Model Spec 12 (gptq, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 70 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** TechxGenus/Meta-Llama-3-70B-Instruct-GPTQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3-instruct --size-in-billions 70 --model-format gptq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/llama-3.1-instruct.rst b/doc/source/models/builtin/llm/llama-3.1-instruct.rst new file mode 100644 index 0000000000..350e333bb3 --- /dev/null +++ b/doc/source/models/builtin/llm/llama-3.1-instruct.rst @@ -0,0 +1,319 @@ +.. _models_llm_llama-3.1-instruct: + +======================================== +llama-3.1-instruct +======================================== + +- **Context Length:** 131072 +- **Model Name:** llama-3.1-instruct +- **Languages:** en, de, fr, it, pt, hi, es, th +- **Abilities:** chat +- **Description:** The Llama 3.1 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks.. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (ggufv2, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 8 +- **Quantizations:** Q3_K_L, IQ4_XS, Q4_K_M, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 2 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** none +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** meta-llama/Meta-Llama-3.1-8B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (gptq, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 8 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format gptq --quantization ${quantization} + + +Model Spec 5 (awq, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 8 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format awq --quantization ${quantization} + + +Model Spec 6 (ggufv2, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 70 +- **Quantizations:** IQ2_M, IQ4_XS, Q2_K, Q3_K_S, Q4_K_M, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (pytorch, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 70 +- **Quantizations:** none +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** meta-llama/Meta-Llama-3.1-70B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format pytorch --quantization ${quantization} + + +Model Spec 8 (pytorch, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** unsloth/Meta-Llama-3.1-70B-Instruct-bnb-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format pytorch --quantization ${quantization} + + +Model Spec 9 (gptq, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 70 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-70B-Instruct-GPTQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format gptq --quantization ${quantization} + + +Model Spec 10 (awq, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 70 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-70B-Instruct-AWQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format awq --quantization ${quantization} + + +Model Spec 11 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-8B-Instruct-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 12 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-8B-Instruct-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 13 (mlx, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 8 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-8B-Instruct +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 8 --model-format mlx --quantization ${quantization} + + +Model Spec 14 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-70B-Instruct-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 15 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-70B-Instruct-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 16 (mlx, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 70 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Meta-Llama-3.1-70B-Instruct-bf16 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 70 --model-format mlx --quantization ${quantization} + + +Model Spec 17 (pytorch, 405 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 405 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3.1-405B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 405 --model-format pytorch --quantization ${quantization} + + +Model Spec 18 (gptq, 405 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 405 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-405B-Instruct-GPTQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 405 --model-format gptq --quantization ${quantization} + + +Model Spec 19 (awq, 405 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 405 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** hugging-quants/Meta-Llama-3.1-405B-Instruct-AWQ-INT4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1-instruct --size-in-billions 405 --model-format awq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/llama-3.1.rst b/doc/source/models/builtin/llm/llama-3.1.rst new file mode 100644 index 0000000000..bd7218ce66 --- /dev/null +++ b/doc/source/models/builtin/llm/llama-3.1.rst @@ -0,0 +1,79 @@ +.. _models_llm_llama-3.1: + +======================================== +llama-3.1 +======================================== + +- **Context Length:** 131072 +- **Model Name:** llama-3.1 +- **Languages:** en, de, fr, it, pt, hi, es, th +- **Abilities:** generate +- **Description:** Llama 3.1 is an auto-regressive language model that uses an optimized transformer architecture + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3.1-8B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 8 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_1, Q4_K_M, Q4_K_S, Q5_0, Q5_1, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** QuantFactory/Meta-Llama-3.1-8B-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1 --size-in-billions 8 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 3 (pytorch, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3.1-70B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1 --size-in-billions 70 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (pytorch, 405 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 405 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3.1-405B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3.1 --size-in-billions 405 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/llama-3.rst b/doc/source/models/builtin/llm/llama-3.rst new file mode 100644 index 0000000000..9f989afc80 --- /dev/null +++ b/doc/source/models/builtin/llm/llama-3.rst @@ -0,0 +1,79 @@ +.. _models_llm_llama-3: + +======================================== +llama-3 +======================================== + +- **Context Length:** 8192 +- **Model Name:** llama-3 +- **Languages:** en +- **Abilities:** generate +- **Description:** Llama 3 is an auto-regressive language model that uses an optimized transformer architecture + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3-8B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 8 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_1, Q4_K_M, Q4_K_S, Q5_0, Q5_1, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** QuantFactory/Meta-Llama-3-8B-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3 --size-in-billions 8 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 3 (pytorch, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 70 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** meta-llama/Meta-Llama-3-70B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3 --size-in-billions 70 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (ggufv2, 70 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 70 +- **Quantizations:** Q4_K_M, Q5_K_M +- **Engines**: llama.cpp +- **Model ID:** NousResearch/Meta-Llama-3-70B-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name llama-3 --size-in-billions 70 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/minicpm-2b-dpo-bf16.rst b/doc/source/models/builtin/llm/minicpm-2b-dpo-bf16.rst index 166dab4d7a..390fd7c902 100644 --- a/doc/source/models/builtin/llm/minicpm-2b-dpo-bf16.rst +++ b/doc/source/models/builtin/llm/minicpm-2b-dpo-bf16.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-2B-dpo-bf16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name minicpm-2b-dpo-bf16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name minicpm-2b-dpo-bf16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/minicpm-2b-dpo-fp16.rst b/doc/source/models/builtin/llm/minicpm-2b-dpo-fp16.rst index 197bd80eb3..fcefa268d5 100644 --- a/doc/source/models/builtin/llm/minicpm-2b-dpo-fp16.rst +++ b/doc/source/models/builtin/llm/minicpm-2b-dpo-fp16.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-2B-dpo-fp16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name minicpm-2b-dpo-fp16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name minicpm-2b-dpo-fp16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/minicpm-2b-dpo-fp32.rst b/doc/source/models/builtin/llm/minicpm-2b-dpo-fp32.rst index e93ebb55d4..26390514b1 100644 --- a/doc/source/models/builtin/llm/minicpm-2b-dpo-fp32.rst +++ b/doc/source/models/builtin/llm/minicpm-2b-dpo-fp32.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-2B-dpo-fp32 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name minicpm-2b-dpo-fp32 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name minicpm-2b-dpo-fp32 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/minicpm-2b-sft-bf16.rst b/doc/source/models/builtin/llm/minicpm-2b-sft-bf16.rst index 84c74c5081..b3a37ec1c7 100644 --- a/doc/source/models/builtin/llm/minicpm-2b-sft-bf16.rst +++ b/doc/source/models/builtin/llm/minicpm-2b-sft-bf16.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-2B-sft-bf16 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name minicpm-2b-sft-bf16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name minicpm-2b-sft-bf16 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/minicpm-2b-sft-fp32.rst b/doc/source/models/builtin/llm/minicpm-2b-sft-fp32.rst index 18ba3b1f1a..a3fefa2dbc 100644 --- a/doc/source/models/builtin/llm/minicpm-2b-sft-fp32.rst +++ b/doc/source/models/builtin/llm/minicpm-2b-sft-fp32.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-2B-sft-fp32 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name minicpm-2b-sft-fp32 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name minicpm-2b-sft-fp32 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/minicpm-llama3-v-2_5.rst b/doc/source/models/builtin/llm/minicpm-llama3-v-2_5.rst new file mode 100644 index 0000000000..10ccf85472 --- /dev/null +++ b/doc/source/models/builtin/llm/minicpm-llama3-v-2_5.rst @@ -0,0 +1,47 @@ +.. _models_llm_minicpm-llama3-v-2_5: + +======================================== +MiniCPM-Llama3-V-2_5 +======================================== + +- **Context Length:** 8192 +- **Model Name:** MiniCPM-Llama3-V-2_5 +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** MiniCPM-Llama3-V 2.5 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Llama3-8B-Instruct with a total of 8B parameters. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** openbmb/MiniCPM-Llama3-V-2_5 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name MiniCPM-Llama3-V-2_5 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** int4 +- **Engines**: Transformers +- **Model ID:** openbmb/MiniCPM-Llama3-V-2_5-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name MiniCPM-Llama3-V-2_5 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/minicpm-v-2.6.rst b/doc/source/models/builtin/llm/minicpm-v-2.6.rst new file mode 100644 index 0000000000..e91a6b7719 --- /dev/null +++ b/doc/source/models/builtin/llm/minicpm-v-2.6.rst @@ -0,0 +1,47 @@ +.. _models_llm_minicpm-v-2.6: + +======================================== +MiniCPM-V-2.6 +======================================== + +- **Context Length:** 32768 +- **Model Name:** MiniCPM-V-2.6 +- **Languages:** en, zh +- **Abilities:** chat, vision +- **Description:** MiniCPM-V 2.6 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Qwen2-7B with a total of 8B parameters. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** openbmb/MiniCPM-V-2_6 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name MiniCPM-V-2.6 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 8 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 8 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** openbmb/MiniCPM-V-2_6-int4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name MiniCPM-V-2.6 --size-in-billions 8 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/mistral-instruct-v0.1.rst b/doc/source/models/builtin/llm/mistral-instruct-v0.1.rst index dd507a4fb6..b0ae72b0a9 100644 --- a/doc/source/models/builtin/llm/mistral-instruct-v0.1.rst +++ b/doc/source/models/builtin/llm/mistral-instruct-v0.1.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** mistralai/Mistral-7B-Instruct-v0.1 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (awq, 7 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (awq, 7 Billion) - **Model Format:** awq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.1-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format awq --quantization ${quantization} Model Spec 3 (gptq, 7 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.1-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format gptq --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,11 +68,12 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.1-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/mistral-instruct-v0.2.rst b/doc/source/models/builtin/llm/mistral-instruct-v0.2.rst index d68a285ecb..ec85c0c61e 100644 --- a/doc/source/models/builtin/llm/mistral-instruct-v0.2.rst +++ b/doc/source/models/builtin/llm/mistral-instruct-v0.2.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** mistralai/Mistral-7B-Instruct-v0.2 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (gptq, 7 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.2-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format gptq --quantization ${quantization} Model Spec 3 (awq, 7 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (awq, 7 Billion) - **Model Format:** awq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.2-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format awq --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,11 +68,12 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Mistral-7B-Instruct-v0.2-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/mistral-instruct-v0.3.rst b/doc/source/models/builtin/llm/mistral-instruct-v0.3.rst new file mode 100644 index 0000000000..16e1fee81a --- /dev/null +++ b/doc/source/models/builtin/llm/mistral-instruct-v0.3.rst @@ -0,0 +1,79 @@ +.. _models_llm_mistral-instruct-v0.3: + +======================================== +mistral-instruct-v0.3 +======================================== + +- **Context Length:** 32768 +- **Model Name:** mistral-instruct-v0.3 +- **Languages:** en +- **Abilities:** chat +- **Description:** The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** mistralai/Mistral-7B-Instruct-v0.3 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.3 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (gptq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.3 --size-in-billions 7 --model-format gptq --quantization ${quantization} + + +Model Spec 3 (awq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** solidrust/Mistral-7B-Instruct-v0.3-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.3 --size-in-billions 7 --model-format awq --quantization ${quantization} + + +Model Spec 4 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_K_S, Q4_K_M, Q5_K_S, Q5_K_M, Q6_K, Q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** MaziyarPanahi/Mistral-7B-Instruct-v0.3-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-instruct-v0.3 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/mistral-large-instruct.rst b/doc/source/models/builtin/llm/mistral-large-instruct.rst new file mode 100644 index 0000000000..1b23a41ed2 --- /dev/null +++ b/doc/source/models/builtin/llm/mistral-large-instruct.rst @@ -0,0 +1,143 @@ +.. _models_llm_mistral-large-instruct: + +======================================== +mistral-large-instruct +======================================== + +- **Context Length:** 131072 +- **Model Name:** mistral-large-instruct +- **Languages:** en, fr, de, es, it, pt, zh, ru, ja, ko +- **Abilities:** chat +- **Description:** Mistral-Large-Instruct-2407 is an advanced dense Large Language Model (LLM) of 123B parameters with state-of-the-art reasoning, knowledge and coding capabilities. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 123 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** mistralai/Mistral-Large-Instruct-2407 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 123 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** unsloth/Mistral-Large-Instruct-2407-bnb-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (gptq, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 123 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** ModelCloud/Mistral-Large-Instruct-2407-gptq-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format gptq --quantization ${quantization} + + +Model Spec 4 (awq, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 123 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** TechxGenus/Mistral-Large-Instruct-2407-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format awq --quantization ${quantization} + + +Model Spec 5 (ggufv2, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 123 +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_K_S, Q4_K_M +- **Engines**: llama.cpp +- **Model ID:** MaziyarPanahi/Mistral-Large-Instruct-2407-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 6 (mlx, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 123 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Large-Instruct-2407-bf16 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format mlx --quantization ${quantization} + + +Model Spec 7 (mlx, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 123 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Large-Instruct-2407-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format mlx --quantization ${quantization} + + +Model Spec 8 (mlx, 123 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 123 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Large-Instruct-2407-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-large-instruct --size-in-billions 123 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/mistral-nemo-instruct.rst b/doc/source/models/builtin/llm/mistral-nemo-instruct.rst new file mode 100644 index 0000000000..d863e09304 --- /dev/null +++ b/doc/source/models/builtin/llm/mistral-nemo-instruct.rst @@ -0,0 +1,159 @@ +.. _models_llm_mistral-nemo-instruct: + +======================================== +mistral-nemo-instruct +======================================== + +- **Context Length:** 1024000 +- **Model Name:** mistral-nemo-instruct +- **Languages:** en, fr, de, es, it, pt, zh, ru, ja +- **Abilities:** chat +- **Description:** The Mistral-Nemo-Instruct-2407 Large Language Model (LLM) is an instruct fine-tuned version of the Mistral-Nemo-Base-2407 + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 12 +- **Quantizations:** none +- **Engines**: vLLM, Transformers +- **Model ID:** mistralai/Mistral-Nemo-Instruct-2407 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 12 +- **Quantizations:** 4-bit +- **Engines**: Transformers +- **Model ID:** unsloth/Mistral-Nemo-Instruct-2407-bnb-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 12 +- **Quantizations:** 8-bit +- **Engines**: Transformers +- **Model ID:** afrizalha/Mistral-Nemo-Instruct-2407-bnb-8bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (gptq, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 12 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** ModelCloud/Mistral-Nemo-Instruct-2407-gptq-4bit +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format gptq --quantization ${quantization} + + +Model Spec 5 (awq, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 12 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** casperhansen/mistral-nemo-instruct-2407-awq +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format awq --quantization ${quantization} + + +Model Spec 6 (ggufv2, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 12 +- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_K_S, Q4_K_M, Q5_K_S, Q5_K_M, Q6_K, Q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** MaziyarPanahi/Mistral-Nemo-Instruct-2407-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (mlx, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 12 +- **Quantizations:** none +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Nemo-Instruct-2407-bf16 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format mlx --quantization ${quantization} + + +Model Spec 8 (mlx, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 12 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Nemo-Instruct-2407-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format mlx --quantization ${quantization} + + +Model Spec 9 (mlx, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 12 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Mistral-Nemo-Instruct-2407-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mistral-nemo-instruct --size-in-billions 12 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/mistral-v0.1.rst b/doc/source/models/builtin/llm/mistral-v0.1.rst index 68b4464176..0815ef68ca 100644 --- a/doc/source/models/builtin/llm/mistral-v0.1.rst +++ b/doc/source/models/builtin/llm/mistral-v0.1.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** mistralai/Mistral-7B-v0.1 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-v0.1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-v0.1 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Mistral-7B-v0.1-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mistral-v0.1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mistral-v0.1 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/mixtral-8x22b-instruct-v0.1.rst b/doc/source/models/builtin/llm/mixtral-8x22b-instruct-v0.1.rst new file mode 100644 index 0000000000..9c6baf73c3 --- /dev/null +++ b/doc/source/models/builtin/llm/mixtral-8x22b-instruct-v0.1.rst @@ -0,0 +1,79 @@ +.. _models_llm_mixtral-8x22b-instruct-v0.1: + +======================================== +mixtral-8x22B-instruct-v0.1 +======================================== + +- **Context Length:** 65536 +- **Model Name:** mixtral-8x22B-instruct-v0.1 +- **Languages:** en, fr, it, de, es +- **Abilities:** chat +- **Description:** The Mixtral-8x22B-Instruct-v0.1 Large Language Model (LLM) is an instruct fine-tuned version of the Mixtral-8x22B-v0.1, specializing in chatting. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 141 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 141 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** mistralai/Mixtral-8x22B-Instruct-v0.1 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mixtral-8x22B-instruct-v0.1 --size-in-billions 141 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (awq, 141 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 141 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** MaziyarPanahi/Mixtral-8x22B-Instruct-v0.1-AWQ +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mixtral-8x22B-instruct-v0.1 --size-in-billions 141 --model-format awq --quantization ${quantization} + + +Model Spec 3 (gptq, 141 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 141 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** jarrelscy/Mixtral-8x22B-Instruct-v0.1-GPTQ-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mixtral-8x22B-instruct-v0.1 --size-in-billions 141 --model-format gptq --quantization ${quantization} + + +Model Spec 4 (ggufv2, 141 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 141 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6, Q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** MaziyarPanahi/Mixtral-8x22B-Instruct-v0.1-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name mixtral-8x22B-instruct-v0.1 --size-in-billions 141 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/mixtral-instruct-v0.1.rst b/doc/source/models/builtin/llm/mixtral-instruct-v0.1.rst index 268608ef3a..fe7a405107 100644 --- a/doc/source/models/builtin/llm/mixtral-instruct-v0.1.rst +++ b/doc/source/models/builtin/llm/mixtral-instruct-v0.1.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 46_7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 46_7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** mistralai/Mixtral-8x7B-Instruct-v0.1 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format pytorch --quantization ${quantization} Model Spec 2 (awq, 46_7 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (awq, 46_7 Billion) - **Model Format:** awq - **Model Size (in billions):** 46_7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mixtral-8x7B-Instruct-v0.1-AWQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format awq --quantization ${quantization} Model Spec 3 (gptq, 46_7 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (gptq, 46_7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 46_7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** TheBloke/Mixtral-8x7B-Instruct-v0.1-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format gptq --quantization ${quantization} Model Spec 4 (ggufv2, 46_7 Billion) @@ -65,11 +68,12 @@ Model Spec 4 (ggufv2, 46_7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 46_7 - **Quantizations:** Q2_K, Q3_K_M, Q4_0, Q4_K_M, Q5_0, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-instruct-v0.1 --size-in-billions 46_7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/mixtral-v0.1.rst b/doc/source/models/builtin/llm/mixtral-v0.1.rst index f3bc861538..0ceaab1375 100644 --- a/doc/source/models/builtin/llm/mixtral-v0.1.rst +++ b/doc/source/models/builtin/llm/mixtral-v0.1.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 46_7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 46_7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** mistralai/Mixtral-8x7B-v0.1 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format pytorch --quantization ${quantization} Model Spec 2 (gptq, 46_7 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (gptq, 46_7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 46_7 - **Quantizations:** Int4 +- **Engines**: Transformers, SGLang - **Model ID:** TheBloke/Mixtral-8x7B-v0.1-GPTQ - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format gptq --quantization ${quantization} Model Spec 3 (ggufv2, 46_7 Billion) @@ -50,11 +52,12 @@ Model Spec 3 (ggufv2, 46_7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 46_7 - **Quantizations:** Q2_K, Q3_K_M, Q4_0, Q4_K_M, Q5_0, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Mixtral-8x7B-v0.1-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name mixtral-v0.1 --size-in-billions 46_7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/omnilmm.rst b/doc/source/models/builtin/llm/omnilmm.rst index 10fd4fee4b..c8a0a32226 100644 --- a/doc/source/models/builtin/llm/omnilmm.rst +++ b/doc/source/models/builtin/llm/omnilmm.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 3 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 3 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/MiniCPM-V - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name OmniLMM --size-in-billions 3 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name OmniLMM --size-in-billions 3 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 12 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 12 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 12 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** openbmb/OmniLMM-12B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name OmniLMM --size-in-billions 12 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name OmniLMM --size-in-billions 12 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/openbuddy.rst b/doc/source/models/builtin/llm/openbuddy.rst deleted file mode 100644 index 756626c7bb..0000000000 --- a/doc/source/models/builtin/llm/openbuddy.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_openbuddy: - -======================================== -OpenBuddy -======================================== - -- **Context Length:** 2048 -- **Model Name:** OpenBuddy -- **Languages:** en -- **Abilities:** chat -- **Description:** OpenBuddy is a powerful open multilingual chatbot model aimed at global users. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 13 -- **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_1, Q4_K_S, Q4_K_M, Q5_0, Q5_1, Q5_K_S, Q5_K_M, Q6_K, Q8_0 -- **Model ID:** TheBloke/OpenBuddy-Llama2-13B-v11.1-GGML -- **Model Hubs**: `Hugging Face `__, `ModelScope `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name OpenBuddy --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/openhermes-2.5.rst b/doc/source/models/builtin/llm/openhermes-2.5.rst index 793090c34a..aad11355fc 100644 --- a/doc/source/models/builtin/llm/openhermes-2.5.rst +++ b/doc/source/models/builtin/llm/openhermes-2.5.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** teknium/OpenHermes-2.5-Mistral-7B - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name openhermes-2.5 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name openhermes-2.5 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (ggufv2, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/OpenHermes-2.5-Mistral-7B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name openhermes-2.5 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name openhermes-2.5 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/opt.rst b/doc/source/models/builtin/llm/opt.rst index dfb0346e9c..4c416c69a8 100644 --- a/doc/source/models/builtin/llm/opt.rst +++ b/doc/source/models/builtin/llm/opt.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 1 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 1 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** facebook/opt-125m - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name opt --size-in-billions 1 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name opt --size-in-billions 1 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/orca.rst b/doc/source/models/builtin/llm/orca.rst deleted file mode 100644 index 20ace63c75..0000000000 --- a/doc/source/models/builtin/llm/orca.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _models_llm_orca: - -======================================== -orca -======================================== - -- **Context Length:** 2048 -- **Model Name:** orca -- **Languages:** en -- **Abilities:** chat -- **Description:** Orca is an LLM trained by fine-tuning LLaMA on explanation traces obtained from GPT-4. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 3 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 3 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** TheBloke/orca_mini_3B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name orca --size-in-billions 3 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (ggmlv3, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 7 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** TheBloke/orca_mini_7B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name orca --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 3 (ggmlv3, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 13 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** TheBloke/orca_mini_13B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name orca --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/orion-chat-rag.rst b/doc/source/models/builtin/llm/orion-chat-rag.rst index 41de461c3c..7a4d3dcc79 100644 --- a/doc/source/models/builtin/llm/orion-chat-rag.rst +++ b/doc/source/models/builtin/llm/orion-chat-rag.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 14 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 14 - **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** OrionStarAI/Orion-14B-Chat-RAG - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name orion-chat-rag --size-in-billions 14 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name orion-chat-rag --size-in-billions 14 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/orion-chat.rst b/doc/source/models/builtin/llm/orion-chat.rst index fa2cbbe46c..7ddee48d68 100644 --- a/doc/source/models/builtin/llm/orion-chat.rst +++ b/doc/source/models/builtin/llm/orion-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 14 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 14 - **Quantizations:** none, 4-bit, 8-bit +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** OrionStarAI/Orion-14B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name orion-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name orion-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} Model Spec 2 (awq, 14 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (awq, 14 Billion) - **Model Format:** awq - **Model Size (in billions):** 14 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers - **Model ID:** OrionStarAI/Orion-14B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name orion-chat --size-in-billions 14 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name orion-chat --size-in-billions 14 --model-format awq --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/phi-2.rst b/doc/source/models/builtin/llm/phi-2.rst index 09d0e9236e..347ef2da55 100644 --- a/doc/source/models/builtin/llm/phi-2.rst +++ b/doc/source/models/builtin/llm/phi-2.rst @@ -20,13 +20,14 @@ Model Spec 1 (ggufv2, 2 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 2 - **Quantizations:** Q2_K, Q3_K_S, Q3_K_M, Q3_K_L, Q4_0, Q4_K_S, Q4_K_M, Q5_0, Q5_K_S, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/phi-2-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name phi-2 --size-in-billions 2 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name phi-2 --size-in-billions 2 --model-format ggufv2 --quantization ${quantization} Model Spec 2 (pytorch, 2 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 2 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 2 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** microsoft/phi-2 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name phi-2 --size-in-billions 2 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name phi-2 --size-in-billions 2 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/phi-3-mini-128k-instruct.rst b/doc/source/models/builtin/llm/phi-3-mini-128k-instruct.rst new file mode 100644 index 0000000000..7cd49226cf --- /dev/null +++ b/doc/source/models/builtin/llm/phi-3-mini-128k-instruct.rst @@ -0,0 +1,31 @@ +.. _models_llm_phi-3-mini-128k-instruct: + +======================================== +phi-3-mini-128k-instruct +======================================== + +- **Context Length:** 128000 +- **Model Name:** phi-3-mini-128k-instruct +- **Languages:** en +- **Abilities:** chat +- **Description:** The Phi-3-Mini-128K-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 4 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** microsoft/Phi-3-mini-128k-instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name phi-3-mini-128k-instruct --size-in-billions 4 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/phi-3-mini-4k-instruct.rst b/doc/source/models/builtin/llm/phi-3-mini-4k-instruct.rst new file mode 100644 index 0000000000..583af0a7ed --- /dev/null +++ b/doc/source/models/builtin/llm/phi-3-mini-4k-instruct.rst @@ -0,0 +1,47 @@ +.. _models_llm_phi-3-mini-4k-instruct: + +======================================== +phi-3-mini-4k-instruct +======================================== + +- **Context Length:** 4096 +- **Model Name:** phi-3-mini-4k-instruct +- **Languages:** en +- **Abilities:** chat +- **Description:** The Phi-3-Mini-4k-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (ggufv2, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 4 +- **Quantizations:** fp16, q4 +- **Engines**: llama.cpp +- **Model ID:** microsoft/Phi-3-mini-4k-instruct-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name phi-3-mini-4k-instruct --size-in-billions 4 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 2 (pytorch, 4 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 4 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** microsoft/Phi-3-mini-4k-instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name phi-3-mini-4k-instruct --size-in-billions 4 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/platypus2-70b-instruct.rst b/doc/source/models/builtin/llm/platypus2-70b-instruct.rst index b4859ade8a..742ca56a08 100644 --- a/doc/source/models/builtin/llm/platypus2-70b-instruct.rst +++ b/doc/source/models/builtin/llm/platypus2-70b-instruct.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** garage-bAInd/Platypus2-70B-instruct - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name platypus2-70b-instruct --size-in-billions 70 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name platypus2-70b-instruct --size-in-billions 70 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/qwen-chat.rst b/doc/source/models/builtin/llm/qwen-chat.rst index 526b4ef3fd..d0b6ddcfdc 100644 --- a/doc/source/models/builtin/llm/qwen-chat.rst +++ b/doc/source/models/builtin/llm/qwen-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q4_K_M +- **Engines**: llama.cpp - **Model ID:** Xorbits/Qwen-7B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 2 (ggufv2, 14 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (ggufv2, 14 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 14 - **Quantizations:** Q4_K_M +- **Engines**: llama.cpp - **Model ID:** Xorbits/Qwen-14B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 14 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 14 --model-format ggufv2 --quantization ${quantization} Model Spec 3 (pytorch, 1_8 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 1_8 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 1_8 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen-1_8B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 1_8 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 1_8 --model-format pytorch --quantization ${quantization} Model Spec 4 (pytorch, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen-7B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 5 (pytorch, 14 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (pytorch, 14 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 14 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen-14B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} Model Spec 6 (pytorch, 72 Billion) @@ -95,13 +100,14 @@ Model Spec 6 (pytorch, 72 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 72 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen-72B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 72 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 72 --model-format pytorch --quantization ${quantization} Model Spec 7 (gptq, 7 Billion) @@ -110,13 +116,14 @@ Model Spec 7 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen-7B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} Model Spec 8 (gptq, 1_8 Billion) @@ -125,13 +132,14 @@ Model Spec 8 (gptq, 1_8 Billion) - **Model Format:** gptq - **Model Size (in billions):** 1_8 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen-1_8B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 1_8 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 1_8 --model-format gptq --quantization ${quantization} Model Spec 9 (gptq, 14 Billion) @@ -140,13 +148,14 @@ Model Spec 9 (gptq, 14 Billion) - **Model Format:** gptq - **Model Size (in billions):** 14 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen-14B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 14 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 14 --model-format gptq --quantization ${quantization} Model Spec 10 (gptq, 72 Billion) @@ -155,11 +164,12 @@ Model Spec 10 (gptq, 72 Billion) - **Model Format:** gptq - **Model Size (in billions):** 72 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen-72B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-chat --size-in-billions 72 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-chat --size-in-billions 72 --model-format gptq --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/qwen-vl-chat.rst b/doc/source/models/builtin/llm/qwen-vl-chat.rst index 6a676318f7..4abfe1c954 100644 --- a/doc/source/models/builtin/llm/qwen-vl-chat.rst +++ b/doc/source/models/builtin/llm/qwen-vl-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** Qwen/Qwen-VL-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-vl-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-vl-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (gptq, 7 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (gptq, 7 Billion) - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: Transformers - **Model ID:** Qwen/Qwen-VL-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen-vl-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen-vl-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/qwen1.5-chat.rst b/doc/source/models/builtin/llm/qwen1.5-chat.rst index a3b50724b8..adbcf75cd4 100644 --- a/doc/source/models/builtin/llm/qwen1.5-chat.rst +++ b/doc/source/models/builtin/llm/qwen1.5-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 0_5 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 0_5 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-0.5B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 0_5 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 0_5 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 1_8 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 1_8 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 1_8 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-1.8B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 1_8 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 1_8 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 4 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 4 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 4 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-4B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 4 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 4 --model-format pytorch --quantization ${quantization} Model Spec 4 (pytorch, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-7B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 5 (pytorch, 14 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (pytorch, 14 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 14 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-14B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 14 --model-format pytorch --quantization ${quantization} Model Spec 6 (pytorch, 32 Billion) @@ -95,13 +100,14 @@ Model Spec 6 (pytorch, 32 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 32 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-32B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 32 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 32 --model-format pytorch --quantization ${quantization} Model Spec 7 (pytorch, 72 Billion) @@ -110,326 +116,396 @@ Model Spec 7 (pytorch, 72 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 72 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) - **Model ID:** Qwen/Qwen1.5-72B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 72 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 72 --model-format pytorch --quantization ${quantization} -Model Spec 8 (gptq, 0_5 Billion) +Model Spec 8 (pytorch, 110 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 110 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen1.5-110B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 110 --model-format pytorch --quantization ${quantization} + + +Model Spec 9 (gptq, 0_5 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 0_5 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-0.5B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 0_5 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 0_5 --model-format gptq --quantization ${quantization} -Model Spec 9 (gptq, 1_8 Billion) +Model Spec 10 (gptq, 1_8 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 1_8 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-1.8B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 1_8 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 1_8 --model-format gptq --quantization ${quantization} -Model Spec 10 (gptq, 4 Billion) +Model Spec 11 (gptq, 4 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 4 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-4B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 4 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 4 --model-format gptq --quantization ${quantization} -Model Spec 11 (gptq, 7 Billion) +Model Spec 12 (gptq, 7 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 7 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-7B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 7 --model-format gptq --quantization ${quantization} -Model Spec 12 (gptq, 14 Billion) +Model Spec 13 (gptq, 14 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 14 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-14B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 14 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 14 --model-format gptq --quantization ${quantization} -Model Spec 13 (gptq, 32 Billion) +Model Spec 14 (gptq, 32 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 32 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-32B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 32 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 32 --model-format gptq --quantization ${quantization} -Model Spec 14 (gptq, 72 Billion) +Model Spec 15 (gptq, 72 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** gptq - **Model Size (in billions):** 72 - **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-72B-Chat-GPTQ-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 72 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 72 --model-format gptq --quantization ${quantization} + + +Model Spec 16 (gptq, 110 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 110 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen1.5-110B-Chat-GPTQ-Int4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 110 --model-format gptq --quantization ${quantization} -Model Spec 15 (awq, 0_5 Billion) +Model Spec 17 (awq, 0_5 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 0_5 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-0.5B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 0_5 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 0_5 --model-format awq --quantization ${quantization} -Model Spec 16 (awq, 1_8 Billion) +Model Spec 18 (awq, 1_8 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 1_8 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-1.8B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 1_8 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 1_8 --model-format awq --quantization ${quantization} -Model Spec 17 (awq, 4 Billion) +Model Spec 19 (awq, 4 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 4 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-4B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 4 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 4 --model-format awq --quantization ${quantization} -Model Spec 18 (awq, 7 Billion) +Model Spec 20 (awq, 7 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 7 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-7B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 7 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 7 --model-format awq --quantization ${quantization} -Model Spec 19 (awq, 14 Billion) +Model Spec 21 (awq, 14 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 14 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-14B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 14 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 14 --model-format awq --quantization ${quantization} -Model Spec 20 (awq, 32 Billion) +Model Spec 22 (awq, 32 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 32 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-32B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 32 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 32 --model-format awq --quantization ${quantization} -Model Spec 21 (awq, 72 Billion) +Model Spec 23 (awq, 72 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** awq - **Model Size (in billions):** 72 - **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang - **Model ID:** Qwen/Qwen1.5-72B-Chat-AWQ - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 72 --model-format awq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 72 --model-format awq --quantization ${quantization} + + +Model Spec 24 (awq, 110 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 110 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen1.5-110B-Chat-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 110 --model-format awq --quantization ${quantization} -Model Spec 22 (ggufv2, 0_5 Billion) +Model Spec 25 (ggufv2, 0_5 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 0_5 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-0.5B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 0_5 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 0_5 --model-format ggufv2 --quantization ${quantization} -Model Spec 23 (ggufv2, 1_8 Billion) +Model Spec 26 (ggufv2, 1_8 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 1_8 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-1.8B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 1_8 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 1_8 --model-format ggufv2 --quantization ${quantization} -Model Spec 24 (ggufv2, 4 Billion) +Model Spec 27 (ggufv2, 4 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 4 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-4B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 4 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 4 --model-format ggufv2 --quantization ${quantization} -Model Spec 25 (ggufv2, 7 Billion) +Model Spec 28 (ggufv2, 7 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-7B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} -Model Spec 26 (ggufv2, 14 Billion) +Model Spec 29 (ggufv2, 14 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 14 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-14B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 14 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 14 --model-format ggufv2 --quantization ${quantization} -Model Spec 27 (ggufv2, 32 Billion) +Model Spec 30 (ggufv2, 32 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 32 - **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0 +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-32B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 32 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 32 --model-format ggufv2 --quantization ${quantization} -Model Spec 28 (ggufv2, 72 Billion) +Model Spec 31 (ggufv2, 72 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 72 - **Quantizations:** q2_k, q3_k_m, q4_k_m +- **Engines**: llama.cpp - **Model ID:** Qwen/Qwen1.5-72B-Chat-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name qwen1.5-chat --size-in-billions 72 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name qwen1.5-chat --size-in-billions 72 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/qwen1.5-moe-chat.rst b/doc/source/models/builtin/llm/qwen1.5-moe-chat.rst new file mode 100644 index 0000000000..c72a9dfdb4 --- /dev/null +++ b/doc/source/models/builtin/llm/qwen1.5-moe-chat.rst @@ -0,0 +1,47 @@ +.. _models_llm_qwen1.5-moe-chat: + +======================================== +qwen1.5-moe-chat +======================================== + +- **Context Length:** 32768 +- **Model Name:** qwen1.5-moe-chat +- **Languages:** en, zh +- **Abilities:** chat, tools +- **Description:** Qwen1.5-MoE is a transformer-based MoE decoder-only language model pretrained on a large amount of data. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 2_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 2_7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** Qwen/Qwen1.5-MoE-A2.7B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen1.5-moe-chat --size-in-billions 2_7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (gptq, 2_7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 2_7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** Qwen/Qwen1.5-MoE-A2.7B-Chat-GPTQ-Int4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen1.5-moe-chat --size-in-billions 2_7 --model-format gptq --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/qwen2-instruct.rst b/doc/source/models/builtin/llm/qwen2-instruct.rst new file mode 100644 index 0000000000..a6bcf7d957 --- /dev/null +++ b/doc/source/models/builtin/llm/qwen2-instruct.rst @@ -0,0 +1,415 @@ +.. _models_llm_qwen2-instruct: + +======================================== +qwen2-instruct +======================================== + +- **Context Length:** 32768 +- **Model Name:** qwen2-instruct +- **Languages:** en, zh +- **Abilities:** chat, tools +- **Description:** Qwen2 is the new series of Qwen large language models + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 0_5 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen2-0.5B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 1_5 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen2-1.5B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen2-7B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (pytorch, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 72 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen2-72B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format pytorch --quantization ${quantization} + + +Model Spec 5 (gptq, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 0_5 +- **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-0.5B-Instruct-GPTQ-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format gptq --quantization ${quantization} + + +Model Spec 6 (gptq, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 1_5 +- **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-1.5B-Instruct-GPTQ-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format gptq --quantization ${quantization} + + +Model Spec 7 (gptq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-7B-Instruct-GPTQ-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format gptq --quantization ${quantization} + + +Model Spec 8 (gptq, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 72 +- **Quantizations:** Int4, Int8 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-72B-Instruct-GPTQ-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format gptq --quantization ${quantization} + + +Model Spec 9 (awq, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 0_5 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-0.5B-Instruct-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format awq --quantization ${quantization} + + +Model Spec 10 (awq, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 1_5 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-1.5B-Instruct-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format awq --quantization ${quantization} + + +Model Spec 11 (awq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 7 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-7B-Instruct-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format awq --quantization ${quantization} + + +Model Spec 12 (awq, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 72 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-72B-Instruct-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format awq --quantization ${quantization} + + +Model Spec 13 (fp8, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** fp8 +- **Model Size (in billions):** 0_5 +- **Quantizations:** fp8 +- **Engines**: vLLM, SGLang +- **Model ID:** neuralmagic/Qwen2-0.5B-Instruct-FP8 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format fp8 --quantization ${quantization} + + +Model Spec 14 (fp8, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** fp8 +- **Model Size (in billions):** 0_5 +- **Quantizations:** fp8 +- **Engines**: vLLM, SGLang +- **Model ID:** neuralmagic/Qwen2-0.5B-Instruct-FP8 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format fp8 --quantization ${quantization} + + +Model Spec 15 (fp8, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** fp8 +- **Model Size (in billions):** 1_5 +- **Quantizations:** fp8 +- **Engines**: vLLM, SGLang +- **Model ID:** neuralmagic/Qwen2-1.5B-Instruct-FP8 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format fp8 --quantization ${quantization} + + +Model Spec 16 (fp8, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** fp8 +- **Model Size (in billions):** 7 +- **Quantizations:** fp8 +- **Engines**: vLLM, SGLang +- **Model ID:** neuralmagic/Qwen2-7B-Instruct-FP8 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format fp8 --quantization ${quantization} + + +Model Spec 17 (fp8, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** fp8 +- **Model Size (in billions):** 72 +- **Quantizations:** fp8 +- **Engines**: vLLM, SGLang +- **Model ID:** neuralmagic/Qwen2-72B-Instruct-FP8 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format fp8 --quantization ${quantization} + + +Model Spec 18 (mlx, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 0_5 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** Qwen/Qwen2-0.5B-Instruct-MLX +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format mlx --quantization ${quantization} + + +Model Spec 19 (mlx, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 1_5 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** Qwen/Qwen2-1.5B-Instruct-MLX +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format mlx --quantization ${quantization} + + +Model Spec 20 (mlx, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** Qwen/Qwen2-7B-Instruct-MLX +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format mlx --quantization ${quantization} + + +Model Spec 21 (mlx, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 72 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Qwen2-72B-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format mlx --quantization ${quantization} + + +Model Spec 22 (ggufv2, 0_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 0_5 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** Qwen/Qwen2-0.5B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 0_5 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 23 (ggufv2, 1_5 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 1_5 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** Qwen/Qwen2-1.5B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 1_5 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 24 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** Qwen/Qwen2-7B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 25 (ggufv2, 72 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 72 +- **Quantizations:** q2_k, q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** Qwen/Qwen2-72B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-instruct --size-in-billions 72 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/qwen2-moe-instruct.rst b/doc/source/models/builtin/llm/qwen2-moe-instruct.rst new file mode 100644 index 0000000000..040e88049d --- /dev/null +++ b/doc/source/models/builtin/llm/qwen2-moe-instruct.rst @@ -0,0 +1,63 @@ +.. _models_llm_qwen2-moe-instruct: + +======================================== +qwen2-moe-instruct +======================================== + +- **Context Length:** 32768 +- **Model Name:** qwen2-moe-instruct +- **Languages:** en, zh +- **Abilities:** chat, tools +- **Description:** Qwen2 is the new series of Qwen large language models. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 14 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 14 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers, SGLang (vLLM and SGLang only available for quantization none) +- **Model ID:** Qwen/Qwen2-57B-A14B-Instruct +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-moe-instruct --size-in-billions 14 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (gptq, 14 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 14 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers, SGLang +- **Model ID:** Qwen/Qwen2-57B-A14B-Instruct-GPTQ-Int4 +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-moe-instruct --size-in-billions 14 --model-format gptq --quantization ${quantization} + + +Model Spec 3 (ggufv2, 14 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 14 +- **Quantizations:** q3_k_m, q4_0, q4_k_m, q5_0, q5_k_m, q6_k, q8_0, fp16 +- **Engines**: llama.cpp +- **Model ID:** Qwen/Qwen2-57B-A14B-Instruct-GGUF +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name qwen2-moe-instruct --size-in-billions 14 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/seallm_v2.5.rst b/doc/source/models/builtin/llm/seallm_v2.5.rst new file mode 100644 index 0000000000..32c4b6453b --- /dev/null +++ b/doc/source/models/builtin/llm/seallm_v2.5.rst @@ -0,0 +1,47 @@ +.. _models_llm_seallm_v2.5: + +======================================== +seallm_v2.5 +======================================== + +- **Context Length:** 8192 +- **Model Name:** seallm_v2.5 +- **Languages:** en, zh, vi, id, th, ms, km, lo, my, tl +- **Abilities:** generate +- **Description:** We introduce SeaLLM-7B-v2.5, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** SeaLLMs/SeaLLM-7B-v2.5 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name seallm_v2.5 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q4_K_M, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** SeaLLMs/SeaLLM-7B-v2.5-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name seallm_v2.5 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/seallm_v2.rst b/doc/source/models/builtin/llm/seallm_v2.rst new file mode 100644 index 0000000000..261349270d --- /dev/null +++ b/doc/source/models/builtin/llm/seallm_v2.rst @@ -0,0 +1,47 @@ +.. _models_llm_seallm_v2: + +======================================== +seallm_v2 +======================================== + +- **Context Length:** 8192 +- **Model Name:** seallm_v2 +- **Languages:** en, zh, vi, id, th, ms, km, lo, my, tl +- **Abilities:** generate +- **Description:** We introduce SeaLLM-7B-v2, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** none +- **Engines**: Transformers +- **Model ID:** SeaLLMs/SeaLLM-7B-v2 +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name seallm_v2 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (ggufv2, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 7 +- **Quantizations:** Q4_0, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** SeaLLMs/SeaLLM-7B-v2-gguf +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name seallm_v2 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/skywork-math.rst b/doc/source/models/builtin/llm/skywork-math.rst index 8c52a153a6..a4699e5281 100644 --- a/doc/source/models/builtin/llm/skywork-math.rst +++ b/doc/source/models/builtin/llm/skywork-math.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 8-bit, none +- **Engines**: Transformers - **Model ID:** skywork/Skywork-13B-Math - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Skywork-Math --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Skywork-Math --size-in-billions 13 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/skywork.rst b/doc/source/models/builtin/llm/skywork.rst index e21c3180dd..6f0208f10b 100644 --- a/doc/source/models/builtin/llm/skywork.rst +++ b/doc/source/models/builtin/llm/skywork.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 8-bit, none +- **Engines**: Transformers - **Model ID:** skywork/Skywork-13B-base - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Skywork --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Skywork --size-in-billions 13 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/starchat-beta.rst b/doc/source/models/builtin/llm/starchat-beta.rst deleted file mode 100644 index 982afcd0bd..0000000000 --- a/doc/source/models/builtin/llm/starchat-beta.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_starchat-beta: - -======================================== -starchat-beta -======================================== - -- **Context Length:** 8192 -- **Model Name:** starchat-beta -- **Languages:** en -- **Abilities:** chat -- **Description:** Starchat-beta is a fine-tuned version of the Starcoderplus LLM, specializing in coding assistance. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 16 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 16 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** HuggingFaceH4/starchat-beta -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name starchat-beta --size-in-billions 16 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/starcoder.rst b/doc/source/models/builtin/llm/starcoder.rst deleted file mode 100644 index 17f66c3c53..0000000000 --- a/doc/source/models/builtin/llm/starcoder.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_starcoder: - -======================================== -starcoder -======================================== - -- **Context Length:** 8192 -- **Model Name:** starcoder -- **Languages:** en -- **Abilities:** generate -- **Description:** Starcoder is an open-source Transformer based LLM that is trained on permissively licensed data from GitHub. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 16 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 16 -- **Quantizations:** q4_0, q4_1, q5_0, q5_1, q8_0 -- **Model ID:** TheBloke/starcoder-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name starcoder --size-in-billions 16 --model-format ggmlv3 --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/starcoderplus.rst b/doc/source/models/builtin/llm/starcoderplus.rst deleted file mode 100644 index 8cb3bbb604..0000000000 --- a/doc/source/models/builtin/llm/starcoderplus.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _models_llm_starcoderplus: - -======================================== -starcoderplus -======================================== - -- **Context Length:** 8192 -- **Model Name:** starcoderplus -- **Languages:** en -- **Abilities:** generate -- **Description:** Starcoderplus is an open-source LLM trained by fine-tuning Starcoder on RedefinedWeb and StarCoderData datasets. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 16 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 16 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** bigcode/starcoderplus -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name starcoderplus --size-in-billions 16 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/starling-lm.rst b/doc/source/models/builtin/llm/starling-lm.rst new file mode 100644 index 0000000000..eb362b9a5c --- /dev/null +++ b/doc/source/models/builtin/llm/starling-lm.rst @@ -0,0 +1,31 @@ +.. _models_llm_starling-lm: + +======================================== +Starling-LM +======================================== + +- **Context Length:** 4096 +- **Model Name:** Starling-LM +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** We introduce Starling-7B, an open large language model (LLM) trained by Reinforcement Learning from AI Feedback (RLAIF). The model harnesses the power of our new GPT-4 labeled ranking dataset + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** berkeley-nest/Starling-LM-7B-alpha +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Starling-LM --size-in-billions 7 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/telechat.rst b/doc/source/models/builtin/llm/telechat.rst new file mode 100644 index 0000000000..e3361b059b --- /dev/null +++ b/doc/source/models/builtin/llm/telechat.rst @@ -0,0 +1,95 @@ +.. _models_llm_telechat: + +======================================== +telechat +======================================== + +- **Context Length:** 8192 +- **Model Name:** telechat +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** The TeleChat is a large language model developed and trained by China Telecom Artificial Intelligence Technology Co., LTD. The 7B model base is trained with 1.5 trillion Tokens and 3 trillion Tokens and Chinese high-quality corpus. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 7 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** Tele-AI/telechat-7B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name telechat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (gptq, 7 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 7 +- **Quantizations:** int4, int8 +- **Engines**: Transformers +- **Model ID:** Tele-AI/telechat-7B-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name telechat --size-in-billions 7 --model-format gptq --quantization ${quantization} + + +Model Spec 3 (pytorch, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 12 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** Tele-AI/TeleChat-12B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name telechat --size-in-billions 12 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (gptq, 12 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 12 +- **Quantizations:** int4, int8 +- **Engines**: Transformers +- **Model ID:** Tele-AI/TeleChat-12B-{quantization} +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name telechat --size-in-billions 12 --model-format gptq --quantization ${quantization} + + +Model Spec 5 (pytorch, 52 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 52 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers +- **Model ID:** Tele-AI/TeleChat-52B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name telechat --size-in-billions 52 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/tiny-llama.rst b/doc/source/models/builtin/llm/tiny-llama.rst index b5788ce5c9..5bcfb5edb9 100644 --- a/doc/source/models/builtin/llm/tiny-llama.rst +++ b/doc/source/models/builtin/llm/tiny-llama.rst @@ -20,11 +20,12 @@ Model Spec 1 (ggufv2, 1 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 1 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/TinyLlama-1.1B-Chat-v0.3-GGUF - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name tiny-llama --size-in-billions 1 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name tiny-llama --size-in-billions 1 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/vicuna-v1.3.rst b/doc/source/models/builtin/llm/vicuna-v1.3.rst deleted file mode 100644 index 1d0be5c824..0000000000 --- a/doc/source/models/builtin/llm/vicuna-v1.3.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. _models_llm_vicuna-v1.3: - -======================================== -vicuna-v1.3 -======================================== - -- **Context Length:** 2048 -- **Model Name:** vicuna-v1.3 -- **Languages:** en -- **Abilities:** chat -- **Description:** Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 7 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/vicuna-7B-v1.3-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (ggmlv3, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 13 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/vicuna-13b-v1.3.0-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 3 (ggmlv3, 33 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 33 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/vicuna-33B-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 33 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 4 (pytorch, 33 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 33 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-33b-v1.3 -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 33 --model-format pytorch --quantization ${quantization} - - -Model Spec 5 (pytorch, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 13 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-13b-v1.3 -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 13 --model-format pytorch --quantization ${quantization} - - -Model Spec 6 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-7b-v1.3 -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.3 --size-in-billions 7 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/vicuna-v1.5-16k.rst b/doc/source/models/builtin/llm/vicuna-v1.5-16k.rst deleted file mode 100644 index a4b2632192..0000000000 --- a/doc/source/models/builtin/llm/vicuna-v1.5-16k.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_vicuna-v1.5-16k: - -======================================== -vicuna-v1.5-16k -======================================== - -- **Context Length:** 16384 -- **Model Name:** vicuna-v1.5-16k -- **Languages:** en -- **Abilities:** chat -- **Description:** Vicuna-v1.5-16k is a special version of Vicuna-v1.5, with a context window of 16k tokens instead of 4k. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-7b-v1.5-16k -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.5-16k --size-in-billions 7 --model-format pytorch --quantization ${quantization} - - -Model Spec 2 (pytorch, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 13 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-13b-v1.5-16k -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.5-16k --size-in-billions 13 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/vicuna-v1.5.rst b/doc/source/models/builtin/llm/vicuna-v1.5.rst deleted file mode 100644 index 84cea1146d..0000000000 --- a/doc/source/models/builtin/llm/vicuna-v1.5.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_vicuna-v1.5: - -======================================== -vicuna-v1.5 -======================================== - -- **Context Length:** 4096 -- **Model Name:** vicuna-v1.5 -- **Languages:** en -- **Abilities:** chat -- **Description:** Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (pytorch, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 7 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-7b-v1.5 -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.5 --size-in-billions 7 --model-format pytorch --quantization ${quantization} - - -Model Spec 2 (pytorch, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** pytorch -- **Model Size (in billions):** 13 -- **Quantizations:** 4-bit, 8-bit, none -- **Model ID:** lmsys/vicuna-13b-v1.5 -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name vicuna-v1.5 --size-in-billions 13 --model-format pytorch --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/wizardcoder-python-v1.0.rst b/doc/source/models/builtin/llm/wizardcoder-python-v1.0.rst index 669429c188..4bcf89bfab 100644 --- a/doc/source/models/builtin/llm/wizardcoder-python-v1.0.rst +++ b/doc/source/models/builtin/llm/wizardcoder-python-v1.0.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardCoder-Python-7B-V1.0 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardCoder-Python-13B-V1.0 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 34 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardCoder-Python-34B-V1.0 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 34 --model-format pytorch --quantization ${quantization} Model Spec 4 (ggufv2, 7 Billion) @@ -65,13 +68,14 @@ Model Spec 4 (ggufv2, 7 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 7 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/WizardCoder-Python-7B-V1.0-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 7 --model-format ggufv2 --quantization ${quantization} Model Spec 5 (ggufv2, 13 Billion) @@ -80,13 +84,14 @@ Model Spec 5 (ggufv2, 13 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 13 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/WizardCoder-Python-13B-V1.0-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 13 --model-format ggufv2 --quantization ${quantization} Model Spec 6 (ggufv2, 34 Billion) @@ -95,11 +100,12 @@ Model Spec 6 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/WizardCoder-Python-34B-V1.0-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardcoder-python-v1.0 --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardcoder-python-v1.0 --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/wizardlm-v1.0.rst b/doc/source/models/builtin/llm/wizardlm-v1.0.rst deleted file mode 100644 index c243e1e9b6..0000000000 --- a/doc/source/models/builtin/llm/wizardlm-v1.0.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _models_llm_wizardlm-v1.0: - -======================================== -wizardlm-v1.0 -======================================== - -- **Context Length:** 2048 -- **Model Name:** wizardlm-v1.0 -- **Languages:** en -- **Abilities:** chat -- **Description:** WizardLM is an open-source LLM trained by fine-tuning LLaMA with Evol-Instruct. - -Specifications -^^^^^^^^^^^^^^ - - -Model Spec 1 (ggmlv3, 7 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 7 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/WizardLM-7B-V1.0-Uncensored-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name wizardlm-v1.0 --size-in-billions 7 --model-format ggmlv3 --quantization ${quantization} - - -Model Spec 2 (ggmlv3, 13 Billion) -++++++++++++++++++++++++++++++++++++++++ - -- **Model Format:** ggmlv3 -- **Model Size (in billions):** 13 -- **Quantizations:** q2_K, q3_K_L, q3_K_M, q3_K_S, q4_0, q4_1, q4_K_M, q4_K_S, q5_0, q5_1, q5_K_M, q5_K_S, q6_K, q8_0 -- **Model ID:** TheBloke/WizardLM-13B-V1.0-Uncensored-GGML -- **Model Hubs**: `Hugging Face `__ - -Execute the following command to launch the model, remember to replace ``${quantization}`` with your -chosen quantization method from the options listed above:: - - xinference launch --model-name wizardlm-v1.0 --size-in-billions 13 --model-format ggmlv3 --quantization ${quantization} - diff --git a/doc/source/models/builtin/llm/wizardmath-v1.0.rst b/doc/source/models/builtin/llm/wizardmath-v1.0.rst index 3e883e1d7f..8de1960716 100644 --- a/doc/source/models/builtin/llm/wizardmath-v1.0.rst +++ b/doc/source/models/builtin/llm/wizardmath-v1.0.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardMath-7B-V1.0 - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardmath-v1.0 --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardmath-v1.0 --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardMath-13B-V1.0 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardmath-v1.0 --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardmath-v1.0 --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 70 Billion) @@ -50,11 +52,12 @@ Model Spec 3 (pytorch, 70 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 70 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** WizardLM/WizardMath-70B-V1.0 - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name wizardmath-v1.0 --size-in-billions 70 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name wizardmath-v1.0 --size-in-billions 70 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/xverse-chat.rst b/doc/source/models/builtin/llm/xverse-chat.rst index eaf4c06616..07a9606e13 100644 --- a/doc/source/models/builtin/llm/xverse-chat.rst +++ b/doc/source/models/builtin/llm/xverse-chat.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** xverse/XVERSE-7B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name xverse-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name xverse-chat --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** xverse/XVERSE-13B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name xverse-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name xverse-chat --size-in-billions 13 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/xverse.rst b/doc/source/models/builtin/llm/xverse.rst index 6be7dbaccc..dd37bac478 100644 --- a/doc/source/models/builtin/llm/xverse.rst +++ b/doc/source/models/builtin/llm/xverse.rst @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** xverse/XVERSE-7B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name xverse --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name xverse --size-in-billions 7 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 13 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 13 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 13 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** xverse/XVERSE-13B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name xverse --size-in-billions 13 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name xverse --size-in-billions 13 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 65 Billion) @@ -50,11 +52,12 @@ Model Spec 3 (pytorch, 65 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 65 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** xverse/XVERSE-65B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name xverse --size-in-billions 65 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name xverse --size-in-billions 65 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/yi-1.5-chat-16k.rst b/doc/source/models/builtin/llm/yi-1.5-chat-16k.rst new file mode 100644 index 0000000000..cf872a7f05 --- /dev/null +++ b/doc/source/models/builtin/llm/yi-1.5-chat-16k.rst @@ -0,0 +1,79 @@ +.. _models_llm_yi-1.5-chat-16k: + +======================================== +Yi-1.5-chat-16k +======================================== + +- **Context Length:** 16384 +- **Model Name:** Yi-1.5-chat-16k +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-9B-Chat-16K +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat-16k --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 34 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-34B-Chat-16K +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat-16k --size-in-billions 34 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_1, Q4_K_M, Q4_K_S, Q5_0, Q5_1, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** QuantFactory/Yi-1.5-9B-Chat-16K-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat-16k --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 4 (ggufv2, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 34 +- **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_K_M, Q4_K_S, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** bartowski/Yi-1.5-34B-Chat-16K-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat-16k --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/yi-1.5-chat.rst b/doc/source/models/builtin/llm/yi-1.5-chat.rst new file mode 100644 index 0000000000..6bf34a6932 --- /dev/null +++ b/doc/source/models/builtin/llm/yi-1.5-chat.rst @@ -0,0 +1,303 @@ +.. _models_llm_yi-1.5-chat: + +======================================== +Yi-1.5-chat +======================================== + +- **Context Length:** 4096 +- **Model Name:** Yi-1.5-chat +- **Languages:** en, zh +- **Abilities:** chat +- **Description:** Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 6 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-6B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-9B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 34 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-34B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} + + +Model Spec 4 (ggufv2, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 6 +- **Quantizations:** Q3_K_L, Q4_K_M, Q5_K_M, Q6_K, Q8_0, f32 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Yi-1.5-6B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 5 (ggufv2, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 9 +- **Quantizations:** Q3_K_L, Q4_K_M, Q5_K_M, Q6_K, Q8_0, f32 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Yi-1.5-9B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 6 (ggufv2, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** ggufv2 +- **Model Size (in billions):** 34 +- **Quantizations:** Q2_K, Q3_K_L, Q4_K_M, Q5_K_M, Q6_K, Q8_0 +- **Engines**: llama.cpp +- **Model ID:** lmstudio-community/Yi-1.5-34B-Chat-GGUF +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + + +Model Spec 7 (gptq, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 6 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-6B-Chat-GPTQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format gptq --quantization ${quantization} + + +Model Spec 8 (gptq, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 9 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-9B-Chat-GPTQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format gptq --quantization ${quantization} + + +Model Spec 9 (gptq, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** gptq +- **Model Size (in billions):** 34 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-34B-Chat-GPTQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format gptq --quantization ${quantization} + + +Model Spec 10 (awq, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 6 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-6B-Chat-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format awq --quantization ${quantization} + + +Model Spec 11 (awq, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 9 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-9B-Chat-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format awq --quantization ${quantization} + + +Model Spec 12 (awq, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** awq +- **Model Size (in billions):** 34 +- **Quantizations:** Int4 +- **Engines**: vLLM, Transformers +- **Model ID:** modelscope/Yi-1.5-34B-Chat-AWQ +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format awq --quantization ${quantization} + + +Model Spec 13 (mlx, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 6 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-6B-Chat-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format mlx --quantization ${quantization} + + +Model Spec 14 (mlx, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 6 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-6B-Chat-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 6 --model-format mlx --quantization ${quantization} + + +Model Spec 15 (mlx, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-9B-Chat-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format mlx --quantization ${quantization} + + +Model Spec 16 (mlx, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 9 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-9B-Chat-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 9 --model-format mlx --quantization ${quantization} + + +Model Spec 17 (mlx, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 34 +- **Quantizations:** 4-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-34B-Chat-4bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format mlx --quantization ${quantization} + + +Model Spec 18 (mlx, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** mlx +- **Model Size (in billions):** 34 +- **Quantizations:** 8-bit +- **Engines**: MLX +- **Model ID:** mlx-community/Yi-1.5-34B-Chat-8bit +- **Model Hubs**: `Hugging Face `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5-chat --size-in-billions 34 --model-format mlx --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/yi-1.5.rst b/doc/source/models/builtin/llm/yi-1.5.rst new file mode 100644 index 0000000000..aee30a1bff --- /dev/null +++ b/doc/source/models/builtin/llm/yi-1.5.rst @@ -0,0 +1,63 @@ +.. _models_llm_yi-1.5: + +======================================== +Yi-1.5 +======================================== + +- **Context Length:** 4096 +- **Model Name:** Yi-1.5 +- **Languages:** en, zh +- **Abilities:** generate +- **Description:** Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples. + +Specifications +^^^^^^^^^^^^^^ + + +Model Spec 1 (pytorch, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 6 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-6B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5 --size-in-billions 6 --model-format pytorch --quantization ${quantization} + + +Model Spec 2 (pytorch, 9 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 9 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-9B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5 --size-in-billions 9 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 34 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 34 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-1.5-34B +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-1.5 --size-in-billions 34 --model-format pytorch --quantization ${quantization} + diff --git a/doc/source/models/builtin/llm/yi-200k.rst b/doc/source/models/builtin/llm/yi-200k.rst index 15dcca708b..aa6c84d654 100644 --- a/doc/source/models/builtin/llm/yi-200k.rst +++ b/doc/source/models/builtin/llm/yi-200k.rst @@ -4,7 +4,7 @@ Yi-200k ======================================== -- **Context Length:** 204800 +- **Context Length:** 262144 - **Model Name:** Yi-200k - **Languages:** en, zh - **Abilities:** generate @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 6 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** 01-ai/Yi-6B-200K - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi-200k --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi-200k --size-in-billions 6 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 34 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** 01-ai/Yi-34B-200K - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi-200k --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi-200k --size-in-billions 34 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/yi-chat.rst b/doc/source/models/builtin/llm/yi-chat.rst index 859e8526bc..3027c58d65 100644 --- a/doc/source/models/builtin/llm/yi-chat.rst +++ b/doc/source/models/builtin/llm/yi-chat.rst @@ -4,7 +4,7 @@ Yi-chat ======================================== -- **Context Length:** 204800 +- **Context Length:** 4096 - **Model Name:** Yi-chat - **Languages:** en, zh - **Abilities:** chat @@ -20,41 +20,60 @@ Model Spec 1 (gptq, 34 Billion) - **Model Format:** gptq - **Model Size (in billions):** 34 - **Quantizations:** 8bits +- **Engines**: vLLM, Transformers - **Model ID:** 01-ai/Yi-34B-Chat-{quantization} - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi-chat --size-in-billions 34 --model-format gptq --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi-chat --size-in-billions 34 --model-format gptq --quantization ${quantization} -Model Spec 2 (pytorch, 34 Billion) +Model Spec 2 (pytorch, 6 Billion) +++++++++++++++++++++++++++++++++++++++++ + +- **Model Format:** pytorch +- **Model Size (in billions):** 6 +- **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) +- **Model ID:** 01-ai/Yi-6B-Chat +- **Model Hubs**: `Hugging Face `__, `ModelScope `__ + +Execute the following command to launch the model, remember to replace ``${quantization}`` with your +chosen quantization method from the options listed above:: + + xinference launch --model-engine ${engine} --model-name Yi-chat --size-in-billions 6 --model-format pytorch --quantization ${quantization} + + +Model Spec 3 (pytorch, 34 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** 01-ai/Yi-34B-Chat - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} -Model Spec 3 (ggufv2, 34 Billion) +Model Spec 4 (ggufv2, 34 Billion) ++++++++++++++++++++++++++++++++++++++++ - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Yi-34B-Chat-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi-chat --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi-chat --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/yi-vl-chat.rst b/doc/source/models/builtin/llm/yi-vl-chat.rst index ea2f192c14..fb9f24ff95 100644 --- a/doc/source/models/builtin/llm/yi-vl-chat.rst +++ b/doc/source/models/builtin/llm/yi-vl-chat.rst @@ -4,7 +4,7 @@ yi-vl-chat ======================================== -- **Context Length:** 204800 +- **Context Length:** 4096 - **Model Name:** yi-vl-chat - **Languages:** en, zh - **Abilities:** chat, vision @@ -20,13 +20,14 @@ Model Spec 1 (pytorch, 6 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** 01-ai/Yi-VL-6B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name yi-vl-chat --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name yi-vl-chat --size-in-billions 6 --model-format pytorch --quantization ${quantization} Model Spec 2 (pytorch, 34 Billion) @@ -35,11 +36,12 @@ Model Spec 2 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** none +- **Engines**: Transformers - **Model ID:** 01-ai/Yi-VL-34B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name yi-vl-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name yi-vl-chat --size-in-billions 34 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/yi.rst b/doc/source/models/builtin/llm/yi.rst index 56d0e24f3f..c20ea3f49f 100644 --- a/doc/source/models/builtin/llm/yi.rst +++ b/doc/source/models/builtin/llm/yi.rst @@ -20,13 +20,14 @@ Model Spec 1 (ggufv2, 34 Billion) - **Model Format:** ggufv2 - **Model Size (in billions):** 34 - **Quantizations:** Q2_K, Q3_K_L, Q3_K_M, Q3_K_S, Q4_0, Q4_K_M, Q4_K_S, Q5_0, Q5_K_M, Q5_K_S, Q6_K, Q8_0 +- **Engines**: llama.cpp - **Model ID:** TheBloke/Yi-34B-GGUF - **Model Hubs**: `Hugging Face `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi --size-in-billions 34 --model-format ggufv2 --quantization ${quantization} Model Spec 2 (pytorch, 6 Billion) @@ -35,13 +36,14 @@ Model Spec 2 (pytorch, 6 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 6 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** 01-ai/Yi-6B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi --size-in-billions 6 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi --size-in-billions 6 --model-format pytorch --quantization ${quantization} Model Spec 3 (pytorch, 9 Billion) @@ -50,13 +52,14 @@ Model Spec 3 (pytorch, 9 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 9 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** 01-ai/Yi-9B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi --size-in-billions 9 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi --size-in-billions 9 --model-format pytorch --quantization ${quantization} Model Spec 4 (pytorch, 34 Billion) @@ -65,11 +68,12 @@ Model Spec 4 (pytorch, 34 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 34 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: vLLM, Transformers (vLLM only available for quantization none) - **Model ID:** 01-ai/Yi-34B - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name Yi --size-in-billions 34 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name Yi --size-in-billions 34 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/zephyr-7b-alpha.rst b/doc/source/models/builtin/llm/zephyr-7b-alpha.rst index 23df488df1..3b48a0f40a 100644 --- a/doc/source/models/builtin/llm/zephyr-7b-alpha.rst +++ b/doc/source/models/builtin/llm/zephyr-7b-alpha.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** HuggingFaceH4/zephyr-7b-alpha - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name zephyr-7b-alpha --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name zephyr-7b-alpha --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/llm/zephyr-7b-beta.rst b/doc/source/models/builtin/llm/zephyr-7b-beta.rst index 8b6500b50c..40048e2c55 100644 --- a/doc/source/models/builtin/llm/zephyr-7b-beta.rst +++ b/doc/source/models/builtin/llm/zephyr-7b-beta.rst @@ -20,11 +20,12 @@ Model Spec 1 (pytorch, 7 Billion) - **Model Format:** pytorch - **Model Size (in billions):** 7 - **Quantizations:** 4-bit, 8-bit, none +- **Engines**: Transformers - **Model ID:** HuggingFaceH4/zephyr-7b-beta - **Model Hubs**: `Hugging Face `__, `ModelScope `__ Execute the following command to launch the model, remember to replace ``${quantization}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name zephyr-7b-beta --size-in-billions 7 --model-format pytorch --quantization ${quantization} + xinference launch --model-engine ${engine} --model-name zephyr-7b-beta --size-in-billions 7 --model-format pytorch --quantization ${quantization} diff --git a/doc/source/models/builtin/rerank/bge-reranker-v2-gemma.rst b/doc/source/models/builtin/rerank/bge-reranker-v2-gemma.rst new file mode 100644 index 0000000000..a200d1f255 --- /dev/null +++ b/doc/source/models/builtin/rerank/bge-reranker-v2-gemma.rst @@ -0,0 +1,18 @@ +.. _models_builtin_bge-reranker-v2-gemma: + +===================== +bge-reranker-v2-gemma +===================== + +- **Model Name:** bge-reranker-v2-gemma +- **Languages:** en, zh, multilingual +- **Abilities:** rerank + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** BAAI/bge-reranker-v2-gemma + +Execute the following command to launch the model:: + + xinference launch --model-name bge-reranker-v2-gemma --model-type rerank \ No newline at end of file diff --git a/doc/source/models/builtin/rerank/bge-reranker-v2-m3.rst b/doc/source/models/builtin/rerank/bge-reranker-v2-m3.rst new file mode 100644 index 0000000000..e64246b210 --- /dev/null +++ b/doc/source/models/builtin/rerank/bge-reranker-v2-m3.rst @@ -0,0 +1,18 @@ +.. _models_builtin_bge-reranker-v2-m3: + +================== +bge-reranker-v2-m3 +================== + +- **Model Name:** bge-reranker-v2-m3 +- **Languages:** en, zh, multilingual +- **Abilities:** rerank + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** BAAI/bge-reranker-v2-m3 + +Execute the following command to launch the model:: + + xinference launch --model-name bge-reranker-v2-m3 --model-type rerank \ No newline at end of file diff --git a/doc/source/models/builtin/rerank/bge-reranker-v2-minicpm-layerwise.rst b/doc/source/models/builtin/rerank/bge-reranker-v2-minicpm-layerwise.rst new file mode 100644 index 0000000000..41d8553163 --- /dev/null +++ b/doc/source/models/builtin/rerank/bge-reranker-v2-minicpm-layerwise.rst @@ -0,0 +1,18 @@ +.. _models_builtin_bge-reranker-v2-minicpm-layerwise: + +================================= +bge-reranker-v2-minicpm-layerwise +================================= + +- **Model Name:** bge-reranker-v2-minicpm-layerwise +- **Languages:** en, zh, multilingual +- **Abilities:** rerank + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** BAAI/bge-reranker-v2-minicpm-layerwise + +Execute the following command to launch the model:: + + xinference launch --model-name bge-reranker-v2-minicpm-layerwise --model-type rerank \ No newline at end of file diff --git a/doc/source/models/builtin/rerank/index.rst b/doc/source/models/builtin/rerank/index.rst index f62fb76dc4..25964db295 100644 --- a/doc/source/models/builtin/rerank/index.rst +++ b/doc/source/models/builtin/rerank/index.rst @@ -16,4 +16,12 @@ The following is a list of built-in rerank models in Xinference: bge-reranker-base bge-reranker-large + + bge-reranker-v2-gemma + + bge-reranker-v2-m3 + + bge-reranker-v2-minicpm-layerwise + + jina-reranker-v2 \ No newline at end of file diff --git a/doc/source/models/builtin/rerank/jina-reranker-v2.rst b/doc/source/models/builtin/rerank/jina-reranker-v2.rst new file mode 100644 index 0000000000..c579898380 --- /dev/null +++ b/doc/source/models/builtin/rerank/jina-reranker-v2.rst @@ -0,0 +1,18 @@ +.. _models_builtin_jina-reranker-v2: + +================ +jina-reranker-v2 +================ + +- **Model Name:** jina-reranker-v2 +- **Languages:** en, zh, multilingual +- **Abilities:** rerank + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** jinaai/jina-reranker-v2-base-multilingual + +Execute the following command to launch the model:: + + xinference launch --model-name jina-reranker-v2 --model-type rerank \ No newline at end of file diff --git a/doc/source/models/builtin/video/cogvideox-2b.rst b/doc/source/models/builtin/video/cogvideox-2b.rst new file mode 100644 index 0000000000..bedb6cdab6 --- /dev/null +++ b/doc/source/models/builtin/video/cogvideox-2b.rst @@ -0,0 +1,18 @@ +.. _models_builtin_cogvideox-2b: + +============ +CogVideoX-2b +============ + +- **Model Name:** CogVideoX-2b +- **Model Family:** CogVideoX +- **Abilities:** text2video + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** THUDM/CogVideoX-2b + +Execute the following command to launch the model:: + + xinference launch --model-name CogVideoX-2b --model-type video \ No newline at end of file diff --git a/doc/source/models/builtin/video/index.rst b/doc/source/models/builtin/video/index.rst new file mode 100644 index 0000000000..1484b1e57c --- /dev/null +++ b/doc/source/models/builtin/video/index.rst @@ -0,0 +1,15 @@ +.. _models_video_index: + +================ +Video Models +================ + +The following is a list of built-in video models in Xinference: + + +.. toctree:: + :maxdepth: 1 + + + cogvideox-2b + \ No newline at end of file diff --git a/doc/source/models/custom.rst b/doc/source/models/custom.rst index 2d5d594454..071785f32d 100644 --- a/doc/source/models/custom.rst +++ b/doc/source/models/custom.rst @@ -5,6 +5,50 @@ Custom Models ============= Xinference provides a flexible and comprehensive way to integrate, manage, and utilize custom models. + +Directly launch an existing model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Since ``v0.14.0``, you can directly launch an existing model by passing ``model_path`` to the launch interface without downloading it. +This way requires that the model's ``model_family`` is among the built-in supported models, +and eliminates the hassle of registering the model. + +For example: + +.. tabs:: + + .. code-tab:: bash shell + + xinference launch --model_path --model-engine -n qwen1.5-chat + + .. code-tab:: bash cURL + + curl -X 'POST' \ + 'http://127.0.0.1:9997/v1/models' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "model_engine": "", + "model_name": "qwen1.5-chat", + "model_path": "" + }' + + .. code-tab:: python + + from xinference.client import RESTfulClient + client = RESTfulClient("http://127.0.0.1:9997") + model_uid = client.launch_model( + model_engine="", + model_name="qwen1.5-chat", + model_path="" + ) + print('Model uid: ' + model_uid) + + +The above example demonstrates how to directly launch a qwen1.5-chat model file without registering it. + +For distributed scenarios, if your model file is on a specific worker, +you can directly launch it using the ``worker_ip`` and ``model_path`` parameters with the launch interface. + Define a custom LLM model ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,15 +80,15 @@ Define a custom LLM model based on the following template: "model_uri": "file:///path/to/llama-2-7b-hf" }, { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 7, "quantizations": [ "q4_0", "q8_0" ], - "model_id": "TheBloke/Llama-2-7B-GGML", - "model_file_name_template": "llama-2-7b.ggmlv3.{quantization}.bin" - "model_uri": "file:///path/to/ggml-file" + "model_id": "TheBloke/Llama-2-7B-GGUF", + "model_file_name_template": "llama-2-7b.{quantization}.gguf" + "model_uri": "file:///path/to/gguf-file" } ] } @@ -55,12 +99,12 @@ Define a custom LLM model based on the following template: * model_ability: A list of strings defining the abilities of the model. It could include options like "embed", "generate", and "chat". In this case, the model has the ability to "generate". * model_family: A required string representing the family of the model you want to register. The optional values are the model names of all :ref:`built-in models `. If the model family you register is not among the built-in models in Xinference, please fill in ``other``. Note that you should choose the model family based on the ability of the model you want to register. For example, if you want to register the ``llama-2`` model, do not fill in ``llama-2-chat`` as the model family. * model_specs: An array of objects defining the specifications of the model. These include: - * model_format: A string that defines the model format, could be "pytorch" or "ggmlv3". + * model_format: A string that defines the model format, like "pytorch" or "ggufv2". * model_size_in_billions: An integer defining the size of the model in billions of parameters. - * quantizations: A list of strings defining the available quantizations for the model. For PyTorch models, it could be "4-bit", "8-bit", or "none". For ggmlv3 models, the quantizations should correspond to values that work with the ``model_file_name_template``. + * quantizations: A list of strings defining the available quantizations for the model. For PyTorch models, it could be "4-bit", "8-bit", or "none". For ggufv2 models, the quantizations should correspond to values that work with the ``model_file_name_template``. * model_id: A string representing the model ID, possibly referring to an identifier used by Hugging Face. **If model_uri is missing, Xinference will try to download the model from the huggingface repository specified here.**. - * model_uri: A string representing the URI where the model can be loaded from, such as "file:///path/to/llama-2-7b". **When the model format is ggmlv3 or ggufv2, model_uri must be the specific file path. When the model format is pytorch, model_uri must be the path to the directory containing the model files.** If model URI is absent, Xinference will try to download the model from Hugging Face with the model ID. - * model_file_name_template: Required by ggml/gguf models. An f-string template used for defining the model file name based on the quantization. **Note that this field is just a template for the format of the ggmlv3/ggufv2 model file, do not fill in the specific path of the model file.** + * model_uri: A string representing the URI where the model can be loaded from, such as "file:///path/to/llama-2-7b". **When the model format is ggufv2, model_uri must be the specific file path. When the model format is pytorch, model_uri must be the path to the directory containing the model files.** If model URI is absent, Xinference will try to download the model from Hugging Face with the model ID. + * model_file_name_template: Required by gguf models. An f-string template used for defining the model file name based on the quantization. **Note that this field is just a template for the format of the ggufv2 model file, do not fill in the specific path of the model file.** * prompt_style: If the ``model_family`` field is not ``other``, this field does not need to be filled in. ``prompt_style`` is an optional field that could be required by ``chat`` models to define the style of prompts. The given example has this set to None, but additional details could be found in a referenced file xinference/model/llm/tests/test_utils.py. You can also specify this field as a string, which will use the builtin prompt style in Xinference. For example: .. code-block:: json @@ -185,6 +229,29 @@ Define a custom embedding model based on the following template: * model_id: A string representing the model ID, possibly referring to an identifier used by Hugging Face. * model_uri: A string representing the URI where the model can be loaded from, such as "file:///path/to/your_model". If model URI is absent, Xinference will try to download the model from Hugging Face with the model ID. + +Define a custom Rerank model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Define a custom rerank model based on the following template: + +.. code-block:: json + + { + "model_name": "custom-bge-reranker-v2-m3", + "type": "normal", + "language": ["en", "zh", "multilingual"], + "model_id": "BAAI/bge-reranker-v2-m3", + "model_uri": "file:///path/to/bge-reranker-v2-m3" + } + +* model_name: A string defining the name of the model. The name must start with a letter or a digit and can only contain letters, digits, underscores, or dashes. +* type: A string defining the type of the model, including ``normal``, ``LLM-based`` and ``LLM-based layerwise``. +* language: A list of strings representing the supported languages for the model. Example: ["en"], which means that the model supports English. +* model_id: A string representing the model ID, possibly referring to an identifier used by Hugging Face. +* model_uri: A string representing the URI where the model can be loaded from, such as "file:///path/to/your_model". If model URI is absent, Xinference will try to download the model from Hugging Face with the model ID. + + Register a Custom Model ~~~~~~~~~~~~~~~~~~~~~~~ @@ -209,7 +276,7 @@ Or via CLI: xinference register --model-type --file model.json --persist -Note that replace the ```` above with ``LLM`` or ``embedding``. The same as below. +Note that replace the ```` above with ``LLM``, ``embedding`` or ``rerank``. The same as below. List the Built-in and Custom Models diff --git a/doc/source/models/index.rst b/doc/source/models/index.rst index fb45dcd8c8..0e54d9fcd4 100644 --- a/doc/source/models/index.rst +++ b/doc/source/models/index.rst @@ -64,6 +64,12 @@ The following ``MODEL_TYPE`` is supported by Xinference: Rerank models + .. grid-item-card:: video + :link: models_video_index + :link-type: ref + + Video models + You can see all the built-in models supported by xinference :ref:`here `. If the model @@ -84,6 +90,7 @@ You can launch a model in Xinference either via command line or Xinference's Pyt .. code-tab:: bash shell xinference launch --model-name \ + [--model-engine ] \ [--model-type ] \ [--model-uid ] \ [--endpoint "http://:"] \ @@ -95,7 +102,8 @@ You can launch a model in Xinference either via command line or Xinference's Pyt client = Client("http://:") model_uid = client.launch_model( - model_name="", + model_name="", + model_engine="", model_type="" model_uid="" ) @@ -103,7 +111,7 @@ You can launch a model in Xinference either via command line or Xinference's Pyt For model type ``LLM``, launching the model requires not only specifying the model name, but also the size of the parameters -and the model format. Please refer to the list of LLM :ref:`model families `. +, the model format and the model engine. Please refer to the list of LLM :ref:`model families `. The following command gives you the currently running models in Xinference: @@ -206,6 +214,12 @@ Model Usage Learn how to turn audio into text or text into audio with Xinference. + .. grid-item-card:: Video + :link: video + :link-type: ref + + Learn how to generate video with Xinference. + .. toctree:: :maxdepth: 2 @@ -215,3 +229,4 @@ Model Usage custom sources/sources lora + model_memory diff --git a/doc/source/models/lora.rst b/doc/source/models/lora.rst index 5cf73fb4a0..a82a7717da 100644 --- a/doc/source/models/lora.rst +++ b/doc/source/models/lora.rst @@ -7,7 +7,10 @@ LoRA Integration Currently, Xinference supports launching ``LLM`` and ``image`` models with an attached LoRA fine-tuned model. Usage -^^^^^ +##### + +Launch +====== Different from built-in models, xinference currently does not involve managing LoRA models. Users need to first download the LoRA model themselves and then provide the storage path of the model files to xinference. @@ -15,7 +18,9 @@ Users need to first download the LoRA model themselves and then provide the stor .. code-tab:: bash shell - xinference launch --peft-model-path + xinference launch + --lora-modules + --lora-modules --image-lora-load-kwargs --image-lora-load-kwargs --image-lora-fuse-kwargs @@ -26,21 +31,55 @@ Users need to first download the LoRA model themselves and then provide the stor from xinference.client import Client client = Client("http://:") + + lora_model1={'lora_name': , 'local_path': } + lora_model2={'lora_name': , 'local_path': } + lora_models=[lora_model1, lora_model2] + image_lora_load_kwargs={'': , '': }, + image_lora_fuse_kwargs={'': , '': } + + peft_model_config = { + "image_lora_load_kwargs": image_lora_load_params, + "image_lora_fuse_kwargs": image_lora_fuse_params, + "lora_list": lora_models + } + client.launch_model( , - peft_model_path='', - image_lora_load_kwargs={'': , '': }, - image_lora_fuse_kwargs={'': , '': } + peft_model_config=peft_model_config + ) + + +Apply +===== +For LLM models, you can only configure one lora model you want when you use the model. +Specifically, specify that the ``lora_name`` parameter be configured in the ``generate_config``. +``lora_name`` corresponds to the name of the lora in the LAUNCH procedure described above. + +.. tabs:: + + .. code-tab:: python + + from xinference.client import Client + + client = Client("http://:") + model = client.get_model("") + model.chat( + "", + , + generate_config={"lora_name": ""} ) Note -^^^^ +#### * The options ``image_lora_load_kwargs`` and ``image_lora_fuse_kwargs`` are only applicable to models with model_type ``image``. They correspond to the parameters in the ``load_lora_weights`` and ``fuse_lora`` interfaces of the ``diffusers`` library. If launching an LLM model, these parameters are not required. +* You need to add the parameter lora_name during inference to specify the corresponding lora model. You can specify it in the Additional Inputs option. + * For LLM chat models, currently only LoRA models are supported that do not change the prompt style. * When using GPU, both LoRA and its base model occupy the same devices. diff --git a/doc/source/models/model_abilities/audio.rst b/doc/source/models/model_abilities/audio.rst index 7c6753fb67..d6731913d8 100644 --- a/doc/source/models/model_abilities/audio.rst +++ b/doc/source/models/model_abilities/audio.rst @@ -11,11 +11,12 @@ Introduction ================== -The Audio API provides two methods for interacting with audio: +The Audio API provides three methods for interacting with audio: * The transcriptions endpoint transcribes audio into the input language. * The translations endpoint translates audio into English. +* The speech endpoint generates audio from the input text. .. list-table:: @@ -31,11 +32,18 @@ The Audio API provides two methods for interacting with audio: * - Translation API - /v1/audio/translations + * - Speech API + - /v1/audio/speech + + Supported models ------------------- The audio API is supported with the following models in Xinference: +Audio to text +~~~~~~~~~~~~~ + * whisper-tiny * whisper-tiny.en * whisper-base @@ -43,7 +51,17 @@ The audio API is supported with the following models in Xinference: * whisper-medium * whisper-medium.en * whisper-large-v3 +* Belle-distilwhisper-large-v2-zh +* Belle-whisper-large-v2-zh +* Belle-whisper-large-v3-zh +* SenseVoiceSmall + + +Text to audio +~~~~~~~~~~~~~ +* ChatTTS +* CosyVoice Quickstart =================== @@ -77,7 +95,7 @@ We can try Transcription API out either via cURL, OpenAI Client, or Xinference's base_url="http://:/v1" ) with open("speech.mp3", "rb") as audio_file: - client.audio.transcriptions( + client.audio.transcriptions.create( model=, file=audio_file, ) @@ -130,7 +148,7 @@ We can try Translation API out either via cURL, OpenAI Client, or Xinference's p base_url="http://:/v1" ) with open("speech.mp3", "rb") as audio_file: - client.audio.translations( + client.audio.translations.create( model=, file=audio_file, ) @@ -152,3 +170,211 @@ We can try Translation API out either via cURL, OpenAI Client, or Xinference's p "text": "Hello, my name is Wolfgang and I come from Germany. Where are you heading today?" } + +Speech +-------------------- + +.. _audio_speech: + +The Speech API mimics OpenAI's `create speech API `_. +We can try Speech API out either via cURL, OpenAI Client, or Xinference's python client: + +Speech API use non-stream by default as + +1. The stream output of ChatTTS is not as good as the non-stream output, please refer to: https://github.com/2noise/ChatTTS/pull/564 +2. The stream requires ffmpeg<7: https://pytorch.org/audio/stable/installation.html#optional-dependencies + +.. tabs:: + + .. code-tab:: bash cURL + + curl -X 'POST' \ + 'http://:/v1/audio/speech' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "", + "input": "", + "voice": "echo", + "stream": True, + }' + + + .. code-tab:: python OpenAI Python Client + + import openai + + client = openai.Client( + api_key="cannot be empty", + base_url="http://:/v1" + ) + client.audio.speech.create( + model=, + input=, + voice="echo", + ) + + .. code-tab:: python Xinference Python Client + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + model.speech( + input=, + voice="echo", + stream: True, + ) + + + .. code-tab:: output + + The output will be an audio binary. + + +ChatTTS Usage +~~~~~~~~~~~~~ + +Basic usage, refer to :ref:`audio speech usage `. + +Fixed tone color. We can use fixed tone color provided by +https://github.com/6drf21e/ChatTTS_Speaker, +Download the `evaluation_result.csv `_ , +take ``seed_2155`` as example, we get the ``emb_data`` of it. + +.. code-block:: python + + import pandas as pd + + df = pd.read_csv("evaluation_results.csv") + emb_data_2155 = df[df['seed_id'] == 'seed_2155'].iloc[0]["emb_data"] + + +Use the fixed tone color of ``seed_2155`` to generate speech. + +.. code-block:: python + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + resp_bytes = model.speech( + voice=emb_data_2155, + input= + ) + + +CosyVoice Usage +~~~~~~~~~~~~~~~ + +Basic usage, launch model ``CosyVoice-300M-SFT``. + +.. tabs:: + + .. code-tab:: bash cURL + + curl -X 'POST' \ + 'http://:/v1/audio/speech' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "", + "input": "", + # ['中文女', '中文男', '日语男', '粤语女', '英文女', '英文男', '韩语女'] + "voice": "中文女" + }' + + .. code-tab:: python OpenAI Python Client + + import openai + + client = openai.Client( + api_key="cannot be empty", + base_url="http://:/v1" + ) + response = client.audio.speech.create( + model=, + input=, + # ['中文女', '中文男', '日语男', '粤语女', '英文女', '英文男', '韩语女'] + voice="中文女", + ) + response.stream_to_file('1.mp3') + + .. code-tab:: python Xinference Python Client + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + speech_bytes = model.speech( + input=, + # ['中文女', '中文男', '日语男', '粤语女', '英文女', '英文男', '韩语女'] + voice="中文女" + ) + with open('1.mp3', 'wb') as f: + f.write(speech_bytes) + + +Clone voice, launch model ``CosyVoice-300M``. + +.. code-block:: + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + + zero_shot_prompt_text = "" + # The zero shot prompt file is the voice file + # the words said in the file shoule be identical to zero_shot_prompt_text + with open(zero_shot_prompt_file, "rb") as f: + zero_shot_prompt = f.read() + + speech_bytes = model.speech( + "", + prompt_text=zero_shot_prompt_text, + prompt_speech=zero_shot_prompt, + ) + + +Cross lingual usage, launch model ``CosyVoice-300M``. + +.. code-block:: + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + + # the file that reads in some language + with open(cross_lingual_prompt_file, "rb") as f: + cross_lingual_prompt = f.read() + + speech_bytes = model.speech( + "", # text could be another language + prompt_speech=cross_lingual_prompt, + ) + +Instruction based, launch model ``CosyVoice-300M-Instruct``. + +.. code-block:: + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + + response = model.speech( + "在面对挑战时,他展现了非凡的勇气智慧。", + voice="中文男", + instruct_text="Theo 'Crimson', is a fiery, passionate rebel leader. " + "Fights with fervor for justice, but struggles with impulsiveness.", + ) + +More instructions and examples, could be found at https://fun-audio-llm.github.io/ . diff --git a/doc/source/models/model_abilities/chat.rst b/doc/source/models/model_abilities/chat.rst index c2d4246ff1..35db451348 100644 --- a/doc/source/models/model_abilities/chat.rst +++ b/doc/source/models/model_abilities/chat.rst @@ -91,15 +91,15 @@ We can try Chat API out either via cURL, OpenAI Client, or Xinference's python c base_url="http://:/v1" ) client.chat.completions.create( - model=("", + model="", messages=[ { "content": "What is the largest animal?", "role": "user", } ], - max_tokens: 512, - temperature: 0.7 + max_tokens=512, + temperature=0.7 ) .. code-tab:: python Xinference Python Client diff --git a/doc/source/models/model_abilities/image.rst b/doc/source/models/model_abilities/image.rst index e84b6f8d2d..7cd42f067c 100644 --- a/doc/source/models/model_abilities/image.rst +++ b/doc/source/models/model_abilities/image.rst @@ -1,8 +1,8 @@ .. _image: -===================== -Images (Experimental) -===================== +====== +Images +====== Learn how to generate images with Xinference. @@ -40,6 +40,9 @@ The Text-to-image API is supported with the following models in Xinference: * sdxl-turbo * stable-diffusion-v1.5 * stable-diffusion-xl-base-1.0 +* sd3-medium +* FLUX.1-schnell +* FLUX.1-dev Quickstart @@ -102,6 +105,44 @@ We can try Text-to-image API out either via cURL, OpenAI Client, or Xinference's } +Tips for Large Image Models including SD3-Medium, FLUX.1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Useful extra parameters can be passed to launch including: + +* ``--cpu_offload True``: specifying ``True`` will offload the components of the model to CPU during + inference in order to save memory, while seeing a slight increase in inference latency. + Model offloading will only move a model component onto the GPU when it needs to be executed, + while keeping the remaining components on the CPU. +* ``--quantize_text_encoder ``: We leveraged the ``bitsandbytes`` library + to load and quantize the T5-XXL text encoder to 8-bit precision. + This allows you to keep using all text encoders while only slightly impacting performance. +* ``--text_encoder_3 None``, for sd3-medium, removing the memory-intensive 4.7B parameter + T5-XXL text encoder during inference can significantly decrease the memory requirements + with only a slight loss in performance. + +If you are trying to run large image models liek sd3-medium or FLUX.1 series on GPU card +that has less memory than 24GB, you may encounter OOM when launching or inference. +Try below solutions. + +For FLUX.1 series, try to apply quantization. + +.. code:: bash + + xinference launch --model-name FLUX.1-dev --model-type image --quantize_text_encoder text_encoder_2 + +For sd3-medium, apply quantization to ``text_encoder_3``. + +.. code:: bash + + xinference launch --model-name sd3-medium --model-type image --quantize_text_encoder text_encoder_3 + + +Or removing memory-intensive T5-XXL text encoder for sd3-medium. + +.. code:: bash + + xinference launch --model-name sd3-medium --model-type image --text_encoder_3 None Image-to-image -------------------- diff --git a/doc/source/models/model_abilities/index.rst b/doc/source/models/model_abilities/index.rst index 0253720652..0d9d140863 100644 --- a/doc/source/models/model_abilities/index.rst +++ b/doc/source/models/model_abilities/index.rst @@ -14,4 +14,4 @@ Model Abilities rerank image audio - + video diff --git a/doc/source/models/model_abilities/video.rst b/doc/source/models/model_abilities/video.rst new file mode 100644 index 0000000000..0aaa941d67 --- /dev/null +++ b/doc/source/models/model_abilities/video.rst @@ -0,0 +1,82 @@ +.. _video: + +==================== +Video (Experimental) +==================== + +Learn how to generate videos with Xinference. + + +Introduction +================== + + +The Video API provides the ability to interact with videos: + + +* The text-to-video endpoint create videos from scratch based on a text prompt. + + +.. list-table:: + :widths: 25 50 + :header-rows: 1 + + * - API ENDPOINT + - OpenAI-compatible ENDPOINT + + * - Text-to-Video API + - /v1/video/generations + +Supported models +------------------- + +The Text-to-video API is supported with the following models in Xinference: + +* CogVideoX-2b + + +Quickstart +=================== + +Text-to-video +-------------------- + +You can try Text-to-video API out either via cURL, or Xinference's python client: + +.. tabs:: + + .. code-tab:: bash cURL + + curl -X 'POST' \ + 'http://:/v1/video/generations' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "model": "", + "prompt": "" + }' + + + .. code-tab:: python Xinference Python Client + + from xinference.client import Client + + client = Client("http://:") + + model = client.get_model("") + input_text = "an apple" + model.text_to_video(input_text) + + +Tips when running on GPU whose memory less than 24GB +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Text-to-video will occupy huge GPU memory, for instance, +running CogVideoX may require up to around 35 GB GPU memory. +When running on GPU whose memory is less than 24 GB, +we recommend to add ``--cpu_offload True`` when launching model. + + +.. code-block:: bash + + xinference launch --model-name CogVideoX-2b --model-type video --cpu_offload True diff --git a/doc/source/models/model_abilities/vision.rst b/doc/source/models/model_abilities/vision.rst index 3d3f8f7da7..74091abe43 100644 --- a/doc/source/models/model_abilities/vision.rst +++ b/doc/source/models/model_abilities/vision.rst @@ -20,7 +20,16 @@ Supported models The ``vision`` ability is supported with the following models in Xinference: -* qwen-vl-chat +* :ref:`qwen-vl-chat ` +* :ref:`deepseek-vl-chat ` +* :ref:`yi-vl-chat ` +* :ref:`omnilmm ` +* :ref:`internvl-chat ` +* :ref:`cogvlm2 ` +* :ref:`MiniCPM-Llama3-V 2.5 ` +* :ref:`GLM-4V ` +* :ref:`MiniCPM-Llama3-V 2.6 ` +* :ref:`internvl2 ` Quickstart diff --git a/doc/source/models/model_memory.rst b/doc/source/models/model_memory.rst new file mode 100644 index 0000000000..3e4c7249f8 --- /dev/null +++ b/doc/source/models/model_memory.rst @@ -0,0 +1,91 @@ +.. _cal_model_memory: + +======================== +Model Memory Calculation +======================== + +For better planning of VMEM usage, xinference provided tool for model memory calculation: ``cal-model-mem`` + +Use algorithm from https://github.com/RahulSChand/gpu_poor + +Output: model_mem, kv_cache, overhead, active_mem + +Example: +To calculate memory usage for qwen1.5-chat, run the following command: + +.. tabs:: + + .. code-tab:: bash Command + + xinference cal-model-mem -s 7 -q Int4 -f gptq -c 16384 -n qwen1.5-chat + + .. code-tab:: bash Output + + model_name: qwen1.5-chat + kv_cache_dtype: 16 + model size: 7.0 B + quant: Int4 + context: 16384 + gpu mem usage: + model mem: 4139 MB + kv_cache: 8192 MB + overhead: 650 MB + active: 17024 MB + total: 30005 MB (30 GB) + +Syntax +------ + +* --size-in-billions {model_size} + + + * -s {model_size} + + + Set the model size. + Specify the model size in billions of parameters. Format accept 1_8 and 1.8. + For example, 7 for 7.0B model size. + + +* --quantization {precision} + + + * -q {precision} *(Optional)* + + + Define the quantization settings for the model. + For example, Int4 for INT4 quantization. + + +* --model-name {model_name} + + + * -n {model_name} *(Optional)* + + + Specify the model's name. + If provided, fetch model config from huggingface/modelscope; If not specified, use default model layer to estimate. + + +* --context-length {context_length} + + + * -c {context_length} + + + Specify the maximum number of tokens(context length) that your model support. + + +* --model-format {format} + + + * -f {format} + + + Specify the format of the model, e.g. pytorch, ggmlv3, etc. + + +.. note:: + The environment variable ``HF_ENDPOINT`` could set the endpoint of HuggingFace. e.g. hf-mirror, etc. + Please refer to :ref:`this document ` + diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst index 2009f5a17b..c44d629e6e 100644 --- a/doc/source/reference/index.rst +++ b/doc/source/reference/index.rst @@ -27,16 +27,6 @@ Model Handles ~~~~~~~~~~~~~ -ChatglmCppChatModelHandle -^^^^^^^^^^^^^^^^^^^^^^^^^ -.. autosummary:: - :toctree: generated/ - - xinference.client.handlers.ChatglmCppChatModelHandle - - xinference.client.handlers.ChatglmCppChatModelHandle.chat - - ChatModelHandle ^^^^^^^^^^^^^^^ .. autosummary:: @@ -87,3 +77,14 @@ AudioModelHandle xinference.client.handlers.AudioModelHandle.transcriptions xinference.client.handlers.AudioModelHandle.translations + xinference.client.handlers.AudioModelHandle.speech + + +VideoModelHandle +^^^^^^^^^^^^^^^^ +.. autosummary:: + :toctree: generated/ + + xinference.client.handlers.VideoModelHandle + + xinference.client.handlers.ImageModelHandle.text_to_video diff --git a/doc/source/user_guide/backends.rst b/doc/source/user_guide/backends.rst index 969b3a88fd..57126871e8 100644 --- a/doc/source/user_guide/backends.rst +++ b/doc/source/user_guide/backends.rst @@ -7,8 +7,8 @@ Backends Xinference supports multiple backends for different models. After the user specifies the model, xinference will automatically select the appropriate backend. -llama-cpp-python -~~~~~~~~~~~~~~~~ +llama.cpp +~~~~~~~~~ `llama-cpp-python `_ is the python binding of `llama.cpp`. `llama-cpp` is developed based on the tensor library `ggml`, supporting inference of the LLaMA series models and their variants. @@ -17,14 +17,6 @@ We recommend that users install `llama-cpp-python` on the worker themselves and parameters according to the hardware to achieve the best inference efficiency. Please refer to the `llama-cpp-python installation guide `_. -ctransformers -~~~~~~~~~~~~~ -CTransformers provide python bindings for the Transformer models implemented in C/C++ using GGML library. - -We recommend that users install `ctransformers` on the worker themselves and adjust the parameters -according to the hardware to achieve the best inference efficiency. Please refer to the -`ctransformers installation guide `_. - transformers ~~~~~~~~~~~~ @@ -45,7 +37,8 @@ When the following conditions are met, Xinference will choose vLLM as the infere - The model format is ``pytorch``, ``gptq`` or ``awq``. - When the model format is ``pytorch``, the quantization is ``none``. -- When the model format is ``gptq`` or ``awq``, the quantization is ``Int4``. +- When the model format is ``awq``, the quantization is ``Int4``. +- When the model format is ``gptq``, the quantization is ``Int3``, ``Int4`` or ``Int8``. - The system is Linux and has at least one CUDA device - The model family (for custom models) / model name (for builtin models) is within the list of models supported by vLLM @@ -53,18 +46,38 @@ Currently, supported model includes: .. vllm_start -- ``llama-2``, ``llama-2-chat`` -- ``baichuan``, ``baichuan-chat``, ``baichuan-2-chat`` -- ``internlm-16k``, ``internlm-chat-7b``, ``internlm-chat-8k``, ``internlm-chat-20b`` -- ``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2`` -- ``Yi``, ``Yi-chat`` +- ``llama-2``, ``llama-3``, ``llama-3.1``, ``llama-2-chat``, ``llama-3-instruct``, ``llama-3.1-instruct`` +- ``mistral-v0.1``, ``mistral-instruct-v0.1``, ``mistral-instruct-v0.2``, ``mistral-instruct-v0.3``, ``mistral-nemo-instruct``, ``mistral-large-instruct`` +- ``codestral-v0.1`` +- ``Yi``, ``Yi-1.5``, ``Yi-chat``, ``Yi-1.5-chat``, ``Yi-1.5-chat-16k`` - ``code-llama``, ``code-llama-python``, ``code-llama-instruct`` -- ``vicuna-v1.3``, ``vicuna-v1.5`` +- ``deepseek``, ``deepseek-coder``, ``deepseek-chat``, ``deepseek-coder-instruct`` +- ``codeqwen1.5``, ``codeqwen1.5-chat`` +- ``baichuan-2-chat`` +- ``internlm2-chat`` +- ``internlm2.5-chat``, ``internlm2.5-chat-1m`` - ``qwen-chat`` -- ``mixtral-instruct-v0.1`` +- ``mixtral-instruct-v0.1``, ``mixtral-8x22B-instruct-v0.1`` - ``chatglm3``, ``chatglm3-32k``, ``chatglm3-128k`` -- ``deepseek-chat``, ``deepseek-coder-instruct`` -- ``qwen1.5-chat`` -- ``gemma-it`` +- ``glm4-chat``, ``glm4-chat-1m`` +- ``codegeex4`` +- ``qwen1.5-chat``, ``qwen1.5-moe-chat`` +- ``qwen2-instruct``, ``qwen2-moe-instruct`` +- ``gemma-it``, ``gemma-2-it`` - ``orion-chat``, ``orion-chat-rag`` +- ``c4ai-command-r-v01`` .. vllm_end + +SGLang +~~~~~~ +`SGLang `_ has a high-performance inference runtime with RadixAttention. +It significantly accelerates the execution of complex LLM programs by automatic KV cache reuse across multiple calls. +And it also supports other common techniques like continuous batching and tensor parallelism. + +MLX +~~~ +`MLX `_ provides efficient runtime +to run LLM on Apple silicon. It's recommended to use for Mac users when running on Apple silicon +if the model has MLX format support. + + diff --git a/doc/source/user_guide/client_api.rst b/doc/source/user_guide/client_api.rst index 658dd78a27..bd47822b7e 100644 --- a/doc/source/user_guide/client_api.rst +++ b/doc/source/user_guide/client_api.rst @@ -46,10 +46,11 @@ Xinference Client client = Client("http://localhost:9997") # The chatglm2 model has the capabilities of "chat" and "embed". - model_uid = client.launch_model(model_name="chatglm2", - model_format="ggmlv3", - model_size_in_billions=6, - quantization="q4_0") + model_uid = client.launch_model(model_name="glm4-chat", + model_engine="llama.cpp", + model_format="ggufv2", + model_size_in_billions=9, + quantization="Q4_K") model = client.get_model(model_uid) chat_history = [] diff --git a/doc/source/user_guide/continuous_batching.rst b/doc/source/user_guide/continuous_batching.rst new file mode 100644 index 0000000000..47269fbd0a --- /dev/null +++ b/doc/source/user_guide/continuous_batching.rst @@ -0,0 +1,97 @@ +.. _user_guide_continuous_batching: + +================================== +Continuous Batching (experimental) +================================== + +Continuous batching, as a means to improve throughput during model serving, has already been implemented in inference engines like ``VLLM``. +Xinference aims to provide this optimization capability when using the transformers engine as well. + +Usage +===== +Currently, this feature can be enabled under the following conditions: + +* First, set the environment variable ``XINFERENCE_TRANSFORMERS_ENABLE_BATCHING`` to ``1`` when starting xinference. For example: + +.. code-block:: + + XINFERENCE_TRANSFORMERS_ENABLE_BATCHING=1 xinference-local --log-level debug + + +* Then, ensure that the ``transformers`` engine is selected when launching the model. For example: + +.. tabs:: + + .. code-tab:: bash shell + + xinference launch -e --model-engine transformers -n qwen1.5-chat -s 4 -f pytorch -q none + + .. code-tab:: bash cURL + + curl -X 'POST' \ + 'http://127.0.0.1:9997/v1/models' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{ + "model_engine": "transformers", + "model_name": "qwen1.5-chat", + "model_format": "pytorch", + "size_in_billions": 4, + "quantization": "none" + }' + + .. code-tab:: python + + from xinference.client import Client + client = Client("http://127.0.0.1:9997") + model_uid = client.launch_model( + model_engine="transformers", + model_name="qwen1.5-chat", + model_format="pytorch", + model_size_in_billions=4, + quantization="none" + ) + print('Model uid: ' + model_uid) + + +Once this feature is enabled, all requests for LLMs will be managed by continuous batching, +and the average throughput of requests made to a single model will increase. +The usage of the LLM interface remains exactly the same as before, with no differences. + + +Abort your request +================== +In this mode, you can abort requests that are in the process of inference. + +#. First, add ``request_id`` option in ``generate_config``. For example: + +.. code-block:: bash + + from xinference.client import Client + client = Client("http://127.0.0.1:9997") + model = client.get_model("") + model.chat("", generate_config={"request_id": ""}) + +#. Then, abort the request using the ``request_id`` you have set. For example: + +.. code-block:: bash + + from xinference.client import Client + client = Client("http://127.0.0.1:9997") + client.abort_request("", "") + +Note that if your request has already finished, aborting the request will be a no-op. + +Note +==== + +* Currently, this feature only supports the ``generate``, ``chat`` and ``vision`` tasks for ``LLM`` models. The ``tool call`` tasks are not supported. + +* For ``vision`` tasks, currently only ``qwen-vl-chat``, ``cogvlm2``, and ``glm-4v`` models are supported. More models will be supported in the future. Please let us know your requirements. + +* If using GPU inference, this method will consume more GPU memory. Please be cautious when increasing the number of concurrent requests to the same model. + The ``launch_model`` interface provides the ``max_num_seqs`` parameter to adjust the concurrency level, with a default value of ``16``. + +* This feature is still in the experimental stage, and we welcome your active feedback on any issues. + +* After a period of testing, this method will remain enabled by default, and the original inference method will be deprecated. diff --git a/doc/source/user_guide/index.rst b/doc/source/user_guide/index.rst index 5d291e773e..8ba1eeb5d9 100644 --- a/doc/source/user_guide/index.rst +++ b/doc/source/user_guide/index.rst @@ -9,6 +9,6 @@ User Guide backends client_api - spec_decoding auth_system metrics + continuous_batching diff --git a/doc/source/user_guide/spec_decoding.rst b/doc/source/user_guide/spec_decoding.rst deleted file mode 100644 index 2fb84b49e1..0000000000 --- a/doc/source/user_guide/spec_decoding.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. _user_guide_spec_decoding: - -=================================== -Speculative Decoding (experimental) -=================================== - -.. image:: ../_static/speculative.gif - -Speculative decoding is a method designed to speed up the inference process of large language models (LLMs). This technique involves using a smaller, quicker "draft" model to produce several tokens in advance. These tokens are then checked by a more extensive "target" model. If the larger model confirms the tokens generated by the draft model, it leads to significant savings in memory bandwidth and processing time per token. However, if the tokens from the draft model don't match the predictions of the larger model, they are discarded. - -.. image:: ../_static/speculative_decoding.jpeg - :width: 400 - -Launching a speculative LLM -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using speculative decoding in Xinference is straightforward. The only distinction between speculative decoding and regular decoding is the way to initiate an LLM: - -.. code-block:: python - - from xinference.client import Client - - client = Client("http://localhost:9997") - model_uid = client.launch_speculative_llm( - model_name="wizardcoder-python-v1.0", # target model name - model_size_in_billions=34, # target model size - quantization="none", # target model quantization - draft_model_name="wizardcoder-python-v1.0", # draft model name - draft_model_size_in_billions=7, # draft model size - draft_quantization="none", # draft model quantization - n_gpu=2 # number of GPUs to use - ) - -.. note:: - - ``Client.launch_speculative_llm`` is an experimental API, which may be removed in the future releases. - -After launching the model, you can use it just like a regular model: - -.. code-block:: python - - model = client.get_model(model_uid) - model.chat( - """Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: - 1. Each row must contain the digits 1-9 without repetition. - 2. Each column must contain the digits 1-9 without repetition. - 3. Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9 without repetition. - Note: - A Sudoku board (partially filled) could be valid but is not necessarily solvable. Only the filled cells need to be validated according to the mentioned rules.""" - ) - -Performance -~~~~~~~~~~~ -The effectiveness of speculative decoding relies on: - -- The size difference between the models - the larger, the better. -- The similarity between the logits produced by the draft model and the target model. - -In the example above, the target model is about five times larger than the draft model, and the two models are well aligned. Approximately 86% of the draft tokens are accepted by the target model, resulting in a 25% increase in speed. - -References -~~~~~~~~~~ -- [1] `Fast Inference from Transformers via Speculative Decoding `_ -- [2] `Accelerating Large Language Model Decoding with Speculative Sampling `_ diff --git a/doc/templates/audio.rst.jinja b/doc/templates/audio.rst.jinja index 9aab97a830..08aafad5eb 100644 --- a/doc/templates/audio.rst.jinja +++ b/doc/templates/audio.rst.jinja @@ -6,7 +6,7 @@ - **Model Name:** {{ model_name }} - **Model Family:** {{ model_family }} -- **Abilities:** audio-to-text +- **Abilities:** {{ ability }} - **Multilingual:** {{ multilingual }} Specifications diff --git a/doc/templates/image.rst.jinja b/doc/templates/image.rst.jinja index a14d8deee0..06379d7d56 100644 --- a/doc/templates/image.rst.jinja +++ b/doc/templates/image.rst.jinja @@ -6,7 +6,7 @@ - **Model Name:** {{ model_name }} - **Model Family:** {{ model_family }} -- **Abilities:** text-to-image +- **Abilities:** {{ model_ability }} - **Available ControlNet:** {{ available_controlnet }} Specifications diff --git a/doc/templates/llm.rst.jinja b/doc/templates/llm.rst.jinja index 3df3d2c839..ce63f0019f 100644 --- a/doc/templates/llm.rst.jinja +++ b/doc/templates/llm.rst.jinja @@ -20,12 +20,17 @@ Model Spec {{ loop.index }} ({{ spec.model_format }}, {{ spec.model_size_in_bill - **Model Format:** {{ spec.model_format }} - **Model Size (in billions):** {{ spec.model_size_in_billions }} - **Quantizations:** {{ spec.quantizations | join(', ') }} +{% if spec.model_format == 'pytorch' and ('vLLM' in spec.engines or 'SGLang' in spec.engines) and '4-bit' in spec.quantizations -%} +- **Engines**: {{ spec.engines | join(', ') }} (vLLM {% if 'SGLang' in spec.engines %}and SGLang {% endif %}only available for quantization none) +{%- else -%} +- **Engines**: {{ spec.engines | join(', ') }} +{%- endif %} - **Model ID:** {{ spec.model_id }} - **Model Hubs**: {% for hub in spec.model_hubs -%}`{{ hub.name }} <{{ hub.url }}>`__{% if not loop.last %}, {% endif %} {%- endfor %} Execute the following command to launch the model, remember to replace ``${{ '{' }}quantization{{ '}' }}`` with your chosen quantization method from the options listed above:: - xinference launch --model-name {{ model_name }} --size-in-billions {{ spec.model_size_in_billions }} --model-format {{ spec.model_format }} --quantization ${{ '{' }}quantization{{ '}' }} + xinference launch --model-engine ${{ '{' }}engine{{ '}' }} --model-name {{ model_name }} --size-in-billions {{ spec.model_size_in_billions }} --model-format {{ spec.model_format }} --quantization ${{ '{' }}quantization{{ '}' }} {% endfor %} \ No newline at end of file diff --git a/doc/templates/video.rst.jinja b/doc/templates/video.rst.jinja new file mode 100644 index 0000000000..68ac23d0d2 --- /dev/null +++ b/doc/templates/video.rst.jinja @@ -0,0 +1,18 @@ +.. _models_builtin_{{ model_name|lower }}: + +{{ "=" * model_name|length }} +{{ model_name }} +{{ "=" * model_name|length }} + +- **Model Name:** {{ model_name }} +- **Model Family:** {{ model_family }} +- **Abilities:** {{ model_ability }} + +Specifications +^^^^^^^^^^^^^^ + +- **Model ID:** {{ model_id }} + +Execute the following command to launch the model:: + + xinference launch --model-name {{ model_name }} --model-type video \ No newline at end of file diff --git a/doc/templates/video_index.rst.jinja b/doc/templates/video_index.rst.jinja new file mode 100644 index 0000000000..206cd70f38 --- /dev/null +++ b/doc/templates/video_index.rst.jinja @@ -0,0 +1,15 @@ +.. _models_video_index: + +================ +Video Models +================ + +The following is a list of built-in video models in Xinference: + + +.. toctree:: + :maxdepth: 1 + + {% for model in models %} + {{ model.model_name|lower }} + {% endfor %} \ No newline at end of file diff --git a/examples/Custom_StableDiffusion_ControlNet.ipynb b/examples/Custom_StableDiffusion_ControlNet.ipynb new file mode 100644 index 0000000000..070e15219f --- /dev/null +++ b/examples/Custom_StableDiffusion_ControlNet.ipynb @@ -0,0 +1,269 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Preparation\n", + "\n", + "First, you need to install Xinference with image support and huggingface-cli:\n", + "```shell\n", + "pip install xinference[image]\n", + "```\n", + "\n", + "Then, download the Stable Diffusion model with ControlNet. You can download the model from the following link:\n", + "Stable Diffusion v1.5(_https://huggingface.co/runwayml/stable-diffusion-v1-5_)\n", + "MLSD ControlNet (_https://huggingface.co/lllyasviel/sd-controlnet-mlsd_)\n", + "```shell\n", + "huggingface-cli download --resume-download runwayml/stable-diffusion-v1-5 --local-dir \"$(pwd)/stable-diffusion-v1-5\"\n", + "huggingface-cli download --resume-download lllyasviel/sd-controlnet-mlsd --local-dir \"$(pwd)/sd-controlnet-mlsd\"\n", + "```\n", + "\n", + "Then, start the Xinference server by the following command:\n", + "```shell\n", + "xinference-local\n", + "```\n", + "\n", + "The Xinference server will be started:\n", + "```shell\n", + "2023-11-02 16:04:55,278 xinference 38878 INFO Xinference successfully started. Endpoint: http://127.0.0.1:9997\n", + "2023-11-02 16:04:55,280 xinference.core.supervisor 38878 INFO Worker 127.0.0.1:32187 has been added successfully\n", + "2023-11-02 16:04:55,281 xinference.deploy.worker 38878 INFO Xinference worker successfully started.\n", + "```" + ], + "metadata": { + "collapsed": false + }, + "id": "58f64d59be3a3a67" + }, + { + "cell_type": "markdown", + "source": [ + "# Register the Stable Diffusion model with MLSD ControlNet\n", + "\n", + "Now, we have an inference server running at `http://127.0.0.1:9997` with empty models. Let's register the Stable Diffusion model and ControlNet." + ], + "metadata": { + "collapsed": false + }, + "id": "7fca21941c0f91ca" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "import os\n", + "from xinference.core.utils import json_dumps\n", + "from xinference.client import Client\n", + "client = Client(\"http://127.0.0.1:9997\")\n", + "\n", + "dir_path = os.getcwd()\n", + "my_controlnet = {\n", + " \"model_family\": \"controlnet\",\n", + " \"model_uid\": \"my_controlnet\",\n", + " \"model_name\": \"my_controlnet\",\n", + " \"model_uri\": os.path.join(dir_path, \"sd-controlnet-mlsd\"), # your controlnet path\n", + "}\n", + "\n", + "my_model = {\n", + " \"model_family\": \"stable_diffusion\",\n", + " \"model_uid\": \"my_image\",\n", + " \"model_name\": \"my_sd\",\n", + " \"model_uri\": os.path.join(dir_path, \"stable-diffusion-v1-5\"), # your model path\n", + " \"controlnet\": [my_controlnet],\n", + "}\n", + "\n", + "client.register_model(\n", + " model_type=\"image\",\n", + " model=json_dumps(my_model),\n", + " persist=False,\n", + ")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-04-19T06:36:11.231232Z", + "start_time": "2024-04-19T06:36:11.222587Z" + } + }, + "id": "b09705b3829eddd2", + "execution_count": 7 + }, + { + "cell_type": "markdown", + "source": [ + "Let's launch the Stable Diffusion model with ControlNet. " + ], + "metadata": { + "collapsed": false + }, + "id": "390b692c8f21a418" + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "model_uid = client.launch_model(\n", + " model_uid=\"my_image\",\n", + " model_name=\"my_sd\",\n", + " model_type=\"image\",\n", + " controlnet=\"my_controlnet\",\n", + ")\n", + "model = client.get_model(model_uid)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-04-19T06:36:25.169778Z", + "start_time": "2024-04-19T06:36:19.203544Z" + } + }, + "id": "9d5c7815ffbe1f7d", + "execution_count": 8 + }, + { + "cell_type": "markdown", + "source": [ + "Load a straight line image from the local." + ], + "metadata": { + "collapsed": false + }, + "id": "7e257c8cab307833" + }, + { + "cell_type": "code", + "outputs": [ + { + "data": { + "text/plain": "", + "image/png": "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", + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAIAAgADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDoPCP+i6jd6yf+YPaPepj7yzZWOBgOh2zSRMQeNqtwfunL07TZtSe4ETRxpb28lxLJKSEVUXOCccFm2ouerOo71qTf6D4Btoukmp6g07o/Xy4E2ROo/us09wpPIJjwMFWyJ/xKvBbSDi61qUwkHgraxFGJAPVZJduGGMG2YAnLAAB/yMej+mp6VafU3durf99GSNW9x5Uf8AD5Xz8/UkE81rcRXFvLJDPE4eOSNirIwOQQRyCDzmtjW4Ib63/wCEhsoo4YLq4dLm0iUBbSbG7CgcCJgSYwcH5HX5vL3sAYdFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUV0Hg7/Rtc/thuI9GibUNx5AkTAgDDqVadoUIHOGJyACwAJPFUEx8SxeHrWKSV9MRNLihiUsWmUnzdn8TB52lZc84cDA4UV/Fc8J1k6dZyxy2GlJ9htZI2DLKqMxaUHniSRpJMZOPM2gkAVJ4W/wBBlvfEB4bSYhNbE8BrpmCwgHpuUlpgpB3CBgRjJHP0AFaGj6n/AGXeO8kP2i1nie3uYC20SRsMHnBAYHDqSCFdFbBxis+igDQ1jTP7LvESOb7RazxJcW04XaJI2GRxkgMDlGAJCujLk4zWfW5ok8N9b/8ACPXsscMF1cI9tdysAtpNjblieBEwIEhGD8iN83l7Gx54JrW4lt7iKSGeJykkcilWRgcEEHkEHjFAEdFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABXQJ/oPgFpU/1mq6gYGcfKUjt0RyhP8Su08bEcAGBTycbefrsNS0z7f4t0jwqZvIj06KOwuJ2XcbdtzS3TPyAVikkn5BC7IwckZYgBfaNeWnhnS9Msk89tRifV7uQAoB5UTMsR3gfNHEXkOMbhcLgMNjNx9d54a8RNqHjW+VopE0/ULK5tk09JFLFFtJIreGN2U/vQu2JX2ljuI53sDyeraZ/ZssDxTefZ3cX2i1nK7DJHuZPmXJ2sGR1IyRlTgsuGIBn0UUUAFdB/yMej+mp6VafU3durf99GSNW9x5Uf8PlfPz9SQTzWtxFcW8skM8Th45I2KsjA5BBHIIPOaAI6K3Nbghvrf/hIbKKOGC6uHS5tIlAW0mxuwoHAiYEmMHB+R1+by97YdABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAG54SghfxBFd3cUctnp6NfXEcqgxyLENwicngCRgkQJzzIBgkgGxp881to2seIriWSW/unNjBJMxLO0ysbiXJzvIj+Rhzj7SrZBC5jt/wDiXeBru5HE2rXYskZef3MIWWVWB6Zd7Ugjn92wyBwx4l/4l8Wn+H04WxiE1wD1N1MqNKGB5VkAjhK54MJOAWYUAHgT/kofhr/sK2v/AKNWqem6lClu2m6kskumyOXzGAZLaQgDzY8kDOAAyEgOAASCEdLHgueG18deHri4ljhgi1O2eSSRgqoolUkkngADnNV7bRJpYtbNx5ltPpVuJZIZIyGLefFCUIOCpBkz/wABxjngAr6lps2mXCxyNHLHIgkguIiTHPGSQHQkA4yCCCAQQVYBgQKdamm6lClu2m6kskumyOXzGAZLaQgDzY8kDOAAyEgOAASCEdK+pabNplwscjRyxyIJILiIkxzxkkB0JAOMggggEEFWAYEAAp0UUUAaGj6n/Zd47yQ/aLWeJ7e5gLbRJGwwecEBgcOpIIV0VsHGKNY0z+y7xEjm+0Ws8SXFtOF2iSNhkcZIDA5RgCQroy5OM1n1uaJPDfW//CPXsscMF1cI9tdysAtpNjblieBEwIEhGD8iN83l7GAMOipJ4JrW4lt7iKSGeJykkcilWRgcEEHkEHjFR0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRWx4Wsbe/8R2kd7H5tjDvuruMMQZIIUaWVVIx8xRGA5HJHI6gA6BrG3GsaZpF5HvsNC09rvUY9xjWSUqZpI5Mf6uQs0VoWJ3bkTjOEHH399canqNzf3knmXV1K80z7QNzsSWOBwMknpXQXl9cL4cvNTupN+p+I7uQzuVCkwI6yMwXoVkmIwwAwbZlBOWA5egAr0DWv+Rn+KX/bf/05QV5/XoGtf8jP8Uv+2/8A6coKAPP66zw7ps2seFdVgmaMWFtcRSCXJaS2lZJSXVMEtEVjPmhPnARHwwiKnk67zwxdteeCrmwudRkszDrFgun3m9UFnKy3TKzvjcIg2ScEbC7OATuVwDi76xuNOvJLW6j8uZMEgMGBBAKsrDIZSCCGBIIIIJBqvXcXwt9Xs5I7yD7F9kxHcKYSsmlT5CuzIBk20khJKqo8l3IVRkLPx99Y3GnXklrdR+XMmCQGDAggFWVhkMpBBDAkEEEEg0AV6KKKAOg/5GPR/TU9KtPqbu3Vv++jJGre48qP+Hyvn5+pIJ5rW4iuLeWSGeJw8ckbFWRgcggjkEHnNbGtwQ31v/wkNlFHDBdXDpc2kSgLaTY3YUDgRMCTGDg/I6/N5e9gDDooooAKKKKACiiigCSaCa2cJPFJE5RXCupUlWUMp57FSCD3BBqOtix1zFnHpurxz6hpUeTFAJ/Le3YkkmFyrBMkncNpVs8jcFZY9S0VrO3W/tZ47zTJHCx3CFdykgkLLGCTE/DcNwdjFS6jdQBl0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAV0mlQTQ+E794IpJbvWLiPS7WFFLmVVZZpdoHO8OLUDPUSMACeV5uvQIP+JHZ2Mw+VtC09NSX+5JqF2UaFlY/xLEYH2EYP2WQYILOQDm/Fc8J1k6dZyxy2GlJ9htZI2DLKqMxaUHniSRpJMZOPM2gkAVh0UUAFegN8/jCSBvmhl8KJ5kZ5V9mkrIuR3w6Iw9GVT1Arz+vQP8Amd/+5U/9wtAHn9dBZ/8AJPNZ/wCwrYf+iruufroLP/knms/9hWw/9FXdAEmlaq149vHJcx22q26eXZ3su3ZKm3b9nn3fKUK/KrNwAdj/ALsgx9Z4p0m3uZEs54YNOjgtLSJY2jMB0y7ktBKsBLk7oZWV8l2Bjk3uxUbjN5fXpGrXj6tqdhfWo8/Ur7SrUNHcu0ia0ixrFKjAncJhNDIByN+xWQiQIZQDzueCa1uJbe4ikhnicpJHIpVkYHBBB5BB4xUddhdWtnrWnQSR3GFG2C0vLhwGiYD5bS6bgDgHypuFKrg4VSLfk54JrW4lt7iKSGeJykkcilWRgcEEHkEHjFAEdaGj6n/Zd47yQ/aLWeJ7e5gLbRJGwwecEBgcOpIIV0VsHGKz6KANDWNM/su8RI5vtFrPElxbThdokjYZHGSAwOUYAkK6MuTjNZ9bmiTw31v/AMI9eyxwwXVwj213KwC2k2NuWJ4ETAgSEYPyI3zeXsbHngmtbiW3uIpIZ4nKSRyKVZGBwQQeQQeMUAR0UUUAFFFFABVzTdUu9JuGmtHjBdCkiSxJLHIuQcOjgqwyAQCDgqD1ANU6KALF9Nb3F5JLa2v2WF8EQiQuEOBuCk87c5wCSQMAliNxr0UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBqeHNNh1bxBZ2l00iWZcyXckZAaO3QF5nGQeVjV2xgk4wATxWx4p1KaSwj85Y0vNbuH1rUEQFdjM8ghj2kkqArPIDn5luFzkKpMng3TPtFndu032ZtQlj0uO4K8wRsfMubgHIyscUe2QZACT/ADMAcNz+t6n/AGxrE96sPkQttjgg3bvJhRQkce7A3bUVV3Hk4yeSaAM+iiigAr0DTv8AmXP+xU1X/wByFef16Bp3/Muf9ipqv/uQoA8/roLP/knms/8AYVsP/RV3XP10Fn/yTzWf+wrYf+irugDn66DxD/yA/Cf/AGCpP/S26rn66DxD/wAgPwn/ANgqT/0tuqANCz1P+0bw6wsP2m6WJV1jTS2BqFuoHmSA4JLEJvkPLq485TwfKjvLOG/t7WGa7jfemzS9WkxGsyqAPs1xk4jdAVAJPyZUEtE0cicvBPNa3EVxbyyQzxOHjkjYqyMDkEEcgg85r0S51BJ/hrpl5Bp3m2L6hdnWrNCscYlK2yrNCoyY8Arhwu1XkKY2OI2APO54JrW4lt7iKSGeJykkcilWRgcEEHkEHjFR12Gr6Z/as9tbxTefqX2SE2MoXaupW4QLGgGSFuEC+WVUkM0bICZF/e8fQAV0H/Ix6P6anpVp9Td26t/30ZI1b3HlR/w+V8/P1JBPNa3EVxbyyQzxOHjkjYqyMDkEEcgg85oAjorc1uCG+t/+Ehsoo4YLq4dLm0iUBbSbG7CgcCJgSYwcH5HX5vL3th0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRWhoemf2zrllpxm8iOeVVlnK7hBH1eRhkfKihmJJAAUkkDmgDsJv+Kd8A2x+7eNEwRX6pJepmVlP3XUWkVuCuCVN5ksrBVHn9dh8QtT+06wlhHD9nhgzcPb7s+TNMqM0WMfJ5SLFb7OAPs/3VJIHH0AFFFFABXoHhv954d0yV/mkSLX4Fc8lYxp6uEB/uhpJGA6Zdj1Jrz+vQPCPzReBojzHN4luIJUPSSN1skdGHdWVmUg8EEg8GgDz+ugs/+Seaz/2FbD/0Vd1z9dBZ/wDJPNZ/7Cth/wCirugDn66DX/3nh/wrKnzRpp8sDOOQsgu53KE/3gskbEdcOp6EVz9dBef8k80b/sK3/wD6KtKAOfrqLG+uIPBEd1ayeTNpWqkAlQ4mF1CQysp4KgWhBUghxKQRgfNy9dBZ/wDJPNZ/7Cth/wCirugC4ZLF9GS4MMn9h3VwyTW0Z8yTTLnaD5kRJ5R1HCuQXEboSWiWYGpabNrFwscjRy63IgkguIiTHrEZJAdCQD5+QQQQC5BVgJgRJz+m6lNplw0kaxyxyIY57eUExzxkglHAIOMgEEEEEBlIYAjqI7Cxm8K3Mgvo10OW9hWF5m33Gn3LpJ8roBzEVjw7oAXCxMAWjaIAHF0V1GrWNxqUUr3Ef/FQ2m575QwJu4NqstwpGRI2NzOyn5kKSfN+9euXoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAruPh5Y26xa5rt9HvtLC0MTDcVBMiuSjNwFWWOKaDdyQ88e0FsY4evQNW/4p34R6HYHi/wBcluLyUP8AK8NqWhCqUOcrI1vHIH4+5gZBOQDh7++uNT1G5v7yTzLq6leaZ9oG52JLHA4GST0qvRRQAUUUUAFegfDv95/Zm/5vI8V6V5W7ny/M87ft9N3lx5x12Ln7orz+uw8OprPhuXTdXubOdtEh1Cz1K7WAJI6CNj5bOM7otyyNs37Q+4EZGCADj66Cz/5J5rP/AGFbD/0Vd1z9dBZ/8k81n/sK2H/oq7oA5+ugvP8Aknmjf9hW/wD/AEVaVz9dBef8k80b/sK3/wD6KtKAOfroLP8A5J5rP/YVsP8A0Vd1z9dBo3+k+FfEtm/EcMVvqCkdTIkywAH/AGdt1ISOuQvOAQQDn66zQbyGz8C62bm0juraXU7GOaJsK20xXZyj4JRwQCGAPTBDKWU8nXQaR/pXhDxHZfd8j7NqW/ru8uQwbMds/a92f9jGPmyADQtotkum2bajizklzo2t7vKNnJuBKSHPyKGYF1yTGW8xCysfNx9ZFvLvmeD+z9VjlMN7YeSY1LjOZEXGI+QQ0ZxtYjb8p2xx6RqUNql3Y3yyPp96ipN5YDPEytlJUUnBdeRzjKu6hl37h0HiW1a38C6I96kdxdte3MVrqMO3bcWiRQbBu2B5ACxVdxBj2shUEbUAOLooooAKKKKACiiigAooooAKKKKANSDTYZfCuoaozSefb3ttbooI2lZEnZieM5zEuOe569suugs/+Seaz/2FbD/0Vd1z9ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRXSaJ4OudRsP7Y1O5j0bQVdFbUruNyshL7dsKqCZXGHOF4Gw7itAGPpWlX2uapb6ZpltJc3lw+yKJOrH+QAGSSeAAScAV1njDwj4f8IXlxZya/8A2jfLvSO1sdrhCoC7ppTjy23728oK5AXaX5D1uDxfpvhjwdqB8GafJYR3j/YbXU7tVOoyt8slwxkX5Y0RTCgQAZMgcNuVhXldABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFzSdNm1nWbHS7do1nvbiO3jaQkKGdgoJwCcZPoa6D4ja3DrPjG4jsvLGl6Yi6bpyxyCRRbw5VSH6sGOWyST82MnAqTwJcy6D/a/iyJtk2k2hjs281F/0qfMSfKwO/CGaTaB/wAsuSBXH0AFFFFABRRVzStNm1fVLewgaNHmfBklJCRL1Z3IB2oqgsx7AE9qALmiWNuYrnVtRj8zTrLCtGGIM07q5hi4wdpKEscrhEbDBioNf+29R/tj+1ftH+l9N2xdm3bs8vZjb5ez5NmNu35cbeKk1fUobpLSxsVkTT7JGSHzAFeVmbLyuoOA7cDjOFRFLNs3HLoA6DfpfiDh0g0nVTwhiXbaXLHnLktiBicjKjy/mUYiVSxJf+JV4Z1bRb393fvqFnOkY+YPGsVxl1YZUqfNjIIOGDAjI5rHv7G40zUbmwvI/LurWV4Zk3A7XUkMMjg4IPStCx8Q3ENnHpt+v2/SVyBazEEwgkljA5BMLEndleGIG8OPlIBj10Fn/wAk81n/ALCth/6Ku6jn0Jby3lv9BeS9t40Ms9qFZriyQDJMmFAZBg/vE4xtLCMsFqvBqUMXhXUNLZZPPuL22uEYAbQsaTqwPOc5lXHHY9O4Bl10Hh7/AJAfiz/sFR/+ltrXP10Hh7/kB+LP+wVH/wCltrQBz9dB4e/5Afiz/sFR/wDpba1z9dB4e/5Afiz/ALBUf/pba0Ac/XQXn/JPNG/7Ct//AOirSufroLP/AJJ5rP8A2FbD/wBFXdAHP0UUUAFFFFABRRRQAUUUUAFFFFAHQWf/ACTzWf8AsK2H/oq7rn66B/8ARfh5Ds5/tHVZPN3fw/Zok2bfTP2uTOc9FxjBzz9ABRRRQAUUUUAFFFFABRRRQAUUUUAFWLGwvNTvI7OwtJ7u6kzshgjMjtgEnCjk4AJ/CtDRtB/tHZdX17BpmkiURzXs5zjpu8uMfPKwDLlUBxuUsVBzWhc+K0sdHbRvDdt9htZYnhvb11U3d8GYE7nxmKMhVHlIcddzPnNAGh/Z+heBZ92siDXPEMEuP7LikJtLVgmcXDbf3rB2AMaHb8jBm5xWG9zq/jbxBaRXd1G07IlvG7qIoLWFB12oNscSKCxwAAAzetYddBa/8SXwvPfH5b7Vd1rbdmjtwf30g6EbziIMMhlFwpoAp65qUN/cW0VmsiWFlbra2qyABioJZnPJwXkaSTbltu/aCQorLoooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoorU8N6JN4j8S6bo0HmB7y4SIukZkMak/M+0dQq5Y8jgHkUAbGtI2jeA9C0opJHPqbvq9wHtlQlMmG3G8/MwASZx0GJhjPWuTrc8Yalaar4sv7jT1jXT0dbezCBwPs8SiKI/OS2diKTnnOenSsOgAooooAK7SPSYbLRJtIt9TtIPEF4m3UbW+cQhIw4dYFkY+WrgxrJJvZCCEjHzCRTn+HtJmWyn15tPkvordJvIt0hMoMiIpaWQYIWKLzI3beCGJVcEFyvPzzzXVxLcXEsk08rl5JJGLM7E5JJPJJPOaACeCa1uJbe4ikhnicpJHIpVkYHBBB5BB4xUdbkHiWaS3is9Zt49Ws40EcYnJE8CAYAimHzKFGdqHdGCclCajutGt5PIfRNQ/tJZ5VhS2MJiu1duFBiywbcQceWz/wAO7aWC0AWPHf8AyUPxL/2Fbr/0a1c/XceLPFn27xlrkeopBremHULgW8jvmSOLzG2+TOPmChSdqndEC2dhrDn8PrcW8t3oN1JqlvChknjFu0dxbIBy8kYLAJwfmRnAG3cVLAUAY8E81rcRXFvLJDPE4eOSNirIwOQQRyCDzmtz7fpeu/JqkUGmXn8N9ZWu2OQ9AJoUIVFHHzxLkANlJGbI5+igC5qWl3ek3Cw3aRgugeN4pUljkXJGUdCVYZBBIJwVI6gitTwf8+q3sDfNDLpV/wCZGeVfZaySLkd8OiMPRlU9QKp6br99ptu1mGjudPdy8ljdL5kDMQAWCn7jlRt8xCrgE4YV0GgWtjLqM15oKXc8klld239kH99dhpLeSIOhVFWVAXVjtAcDf8hVC5AOLroPD3/ID8Wf9gqP/wBLbWufroPBv/Icuf8AsFal/wCkU1AHP10Fn/yTzWf+wrYf+iruufroLP8A5J5rP/YVsP8A0Vd0Ac/RRRQAUUUUAFFFbF9oP9lWcjalewQ3/ATT4z5synIz5uPlixhgVJ8wMACgB3AAx6KKKACiiigDoLz/AJJ5o3/YVv8A/wBFWlc/XQXn/JPNG/7Ct/8A+irSufoAKKKKACiiigAooooAKKK2LHw9cTWcepX7fYNJbJF1MADMASGECEgzMCNuF4Ukbyg+YAGXBBNdXEVvbxSTTyuEjjjUszsTgAAckk8Yrc+y6XoHN/5Gq6kP+XKKXfaID3eaKQF2xzsjOBuUl8q0dRz66tnby2GgpJZW8iGKe6DMtxeoRgiTDEKhyf3acY2hjIVDVh0AXNS1W+1e4We/uZJ3RBHGG4WJASQiKOEQZOFUADsBVOiigC5pWmzavqlvYQNGjzPgySkhIl6s7kA7UVQWY9gCe1WNf1KHUtUY2ayR6fboLeyjkADLCnClgDgO3Lvjgu7nvVz/AJA3hD0u9c/8ds45PxB3zR+zL9n/ALslc/QAUUUUAFFFFABRWx4lsbfT9VghtY/LjbT7KYjcTl5LWKRzz6szH2zxxWPQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAV0Gj/8AEs8PaprPS4l/4ltpu4/1qN57rnhtsf7sjHH2lWyCFzz9dB4l/wCJfFp/h9OFsYhNcA9TdTKjShgeVZAI4SueDCTgFmFAHP0UUUAFamgaK2u6otr58dtAqGWe4lKqkSDuSxVQSSqruZQWZQWGc1nwQTXVxFb28Uk08rhI441LM7E4AAHJJPGK2NVnh0/S49Cs5Y5cus+oyxsHSS4XeqKjDgoiORkcMzOcuuwgAk8RTapZa5ayPaz6X9mii/s5Uk4SJOEkjkXCvuYM5kTCs7Mwxmj/AIS68uuNZs7HWu/mX8R85m7Fp42SZ8DgBnK4xx8q4p6br99ptu1mGjudPdy8ljdL5kDMQAWCn7jlRt8xCrgE4YVc+y6FrXNjcf2RfN/y63blraRvSObrHkkALICqgEtNQBYsbHw/4jvI7W1jvtIvpckAstza5wSzMx2PBCgBJYmYhckn5fmj8FxrD8S/D0STRzomsWyrLGGCuBMvzDcAcHryAfUCo7n/AIpvTmsl/d63cb0vT1a1hIAEIP8ADI3z+YOSF2plSZUq54A02aXxVoeqK0fkW+u6fbupJ3FpHZlI4xjETZ57jr2AOTqSCea1uIri3lkhnicPHJGxVkYHIII5BB5zWpY695dnHp+pWUGo2CZCJINk0IJJPlSj5l6sQp3R7mLFGNWP7Bs9W+fw9e+bMef7NuyI7kH+7GfuT8lVG0rI5ziICgA/tiw1rjxEk63X8OpWUUfmEdT50Z2idif4y6vlmLM+FUU9S0C+023W8Kx3Onu4SO+tW8yBmIJClh9xyo3eW4VwCMqKy6uabqt9pFw09hcyQO6GOQLysqEglHU8OhwMqwIPcGgCnRXQbdC1v5YIv7F1FuEj8wvZyt2G6Rt8HA6s0ilmyTGoyMvUtKvtIuFgv7aSB3QSRluVlQkgOjDh0ODhlJB7E0Aan9uW+tfu/Evnyznpq8QMt2AOiurOqyr1GSQ4+X5yqBDY021/4RvVWur24gksbnT7+G3u7Z/NjlZ7WRFXjlWzJHlHCsodSwXNcvWhpmt6jo/mrZXG2GbHnW8iLLDNjO3zInBR8EkjcDg8jBoAz66DS/8ASfBfiCzTiSGW01BiehjQyQED/a3XUZA6YDc5ABP7P07Xvm0YfY9QPH9lyyNJ9oY84t22/UCNzu4UK0rNgSaLBNa6Z4xt7iKSGeLTFSSORSrIwvbYEEHkEHjFAHN0UVc03Sr7V7hoLC2kndEMkhXhYkBALux4RBkZZiAO5FAFOtix8PXE1nHqV+32DSWyRdTAAzAEhhAhIMzAjbheFJG8oPmFjzdG0Hm1aDW7/tLLA62kB6hkVirSt04kQIMMCkgYEY99fXGo3kl1dSeZM+ASFCgAABVVRgKoAACgAAAAAAUAbkHiceH7iJvCqSWkkThzf3KRyXEjKeCvykQoRnMak5DsrvIuAKd9Y297ZyarpUflwpg3dmGLG0JIAZScloSSAGOSpIRiSUeTHqxY31xp15HdWsnlzJkAlQwIIIZWU5DKQSCpBBBIIINAFeiti+sbe9s5NV0qPy4UwbuzDFjaEkAMpOS0JJADHJUkIxJKPJj0AFFFFAHQXn/JPNG/7Ct//wCirSufroLz/knmjf8AYVv/AP0VaVz9ABRRRQAUUUUAFWLGwvNTvI7OwtJ7u6kzshgjMjtgEnCjk4AJ/CtTTfDU1zYNqmo3EemaWqF0uLgHddYcKy26cGZweuCFX+JkzmrGoeJYbe3m0vwzbyadprPIrXDkfbbuJwBsnkXA2YH+rUBPXeRuoAsJDovhJ0luzaa7rUbxSx20Ugl0+JSu5lmZSDM4OBtQ7B3Z+Urn9S1W+1e4We/uZJ3RBHGG4WJASQiKOEQZOFUADsBVOigAooooAK0NE0z+2NYgsmm8iFt0k8+3d5MKKXkk25G7ais20cnGByRWfXQXX/El8LwWI+W+1XbdXPZo7cH9zGehG85lKnIZRbsKAM/W9T/tjWJ71YfIhbbHBBu3eTCihI492Bu2oqruPJxk8k1n0UUAFFFFABWx4burO21GT7dLBHDLEY/9IsRcxsSRw/IeNcZzJHmRR90ZNY9FAHrHiXQNH1nVYBHHAJTp9kiS6VqCFuLWIqq2dyUmmYjAXY4yrJwZFcHj77wd5V5Ja2upwJdJgvY6sv8AZtzEuBy4lPlDOQQFlZiGBx97bX8Zf8hy2/7BWm/+kUNV7HxVrun2cdlDqc72CZxYzkTWxySeYXzGeTu5Xg89eaAK+p6FrGieV/a2lX1h52fL+127xb8YzjcBnGR09RWfXYaZ46+yeaLjTvK8/BuH0mf7F9q25CpLFte3aPaSCvkjPcnLbtD+0fB2t/LfeRBI3zGSWx+wtCnURpJah43YE/ee2G5d3KnaAAef0V6B/wAK7TVfm0eadJOskKldTjhHTDTWXmNubqA0KDAYAkr83P8A/CF67P8ANplp/bEJ5EmlMLrCn7pdUy8W4dBIqtwRjIIABz9FFFABRRRQAUUUUAFFFFAGx4Zsbe81gSX0fmWFnFJd3SFiqukalhGXH3PMbbEG7NIuATgHPv7641PUbm/vJPMurqV5pn2gbnYkscDgZJPSthP+JV4LaQcXWtSmEg8FbWIoxIB6rJLtwwxg2zAE5YDn6ACiitTRdNhvHmur9pItMtELzyIQCzbWMcSkg/PIy7Rw2BucqVRqALlj/wAU9pkeqvxqV7EW0wr1t1EhVrjPQNlJEQfeBy+UKoW5+rmq6lNq+qXF/OsaPM+RHECEiXoqICTtRVAVR2AA7VToAK6DS/8AinrO08QtzfvKzaZEeAjRkf6QwP3lDcIOVZ0fccRlHp6VpsM9vcalftIum2jokoiI8yWRwxSJMghSwRyXIIUKThjtRq+q6lNq+qXF/OsaPM+RHECEiXoqICTtRVAVR2AA7UAU69M+E2mzardW1vA0auniPTbglyQNsUV5Kw4B52oQPfHTrXmdewfCH93qHhO8k+S1tNQ1ee5mbhIYxZ24Lu3RVyQMnjkUAeP0UUUAdB/wk/8AaPyeJLP+1v8Ap783yrwf9tsNv6KP3qyYUYXb1qOfw+txby3eg3UmqW8KGSeMW7R3FsgHLyRgsAnB+ZGcAbdxUsBWHUkE81rcRXFvLJDPE4eOSNirIwOQQRyCDzmgCOtTTdcmsLdrOW1tL+wZy7Wt3GWUNgcqykPGThclGXdtUNkDFXP7es9W+TxDZebMeP7StAI7kH+9IPuT8lmO4LI5xmUCq994euIbOTUrBvt+krgm6hAJhBICidASYWJO3DcMQdhcfMQCx/YlnrP7zw9NiY8f2Xdzg3ORx+7faiTZO3CriQliAhC7jz9Fbk/iWbU7eWPW7ePUp2QiO+kJW6RscEyjmUZCjEgfCjahTOQAYddJZeLpl0TUdL1SGTUEuLIWdtO05WW1VXjkVVYht0QaJf3ZHHO0pubdzdFAHQf2JZ6N+88QzZmHH9l2k4Fzk8fvH2ukODuyrZkBUAoA24U9S1251C3WyjSOy0xHEiafas4gV8EFyGZiznJ+ZiTjCghQAMuigAooooAKKKKALFjfXGnXkd1ayeXMmQCVDAgghlZTkMpBIKkEEEggg1oX1jb3tnJqulR+XCmDd2YYsbQkgBlJyWhJIAY5KkhGJJR5Meuk8KTNZ2fiO+hEf2i20xXhd41faWurdG4YEEMjuhB4KsynIJFAHN0UUUAdBef8k80b/sK3/wD6KtK5+ug1/wDd+H/CsSfLG+nyzsg4DSG7nQuR/eKxxqT1wijoBXP0AFFFdZoHgebUdLXXtavo9D8NlzH/AGlPGZDJIOAkUSnfIc55HACvzlSKAOf0rSr7XNUt9M0y2kuby4fZFEnVj/IADJJPAAJOAK6hI/Dng1Ee4Fp4j14pFILfO/T7Q7txDuj/AOkPtCgqMRjcwJfGKNV8cQ22l3Gg+DrGTRtHuE8u8d5BJdX+OA0r4+QFR/q0woLv1DYri6ALmparfavcLPf3Mk7ogjjDcLEgJIRFHCIMnCqAB2AqnRRQAUUUUAFFFFAGpoGmw6lqii8aSPT7dDcXskZAZYU5YKSMB24RM8F3Qd6r6rqU2r6pcX86xo8z5EcQISJeiogJO1FUBVHYADtUkOp/Z9DudOhh2yXUqtcT7uWjTlYwAOFLHcwJIYpGcApk59ABRRRQAUUUUAFFFFAHQeMv+Q5bf9grTf8A0ihrn66Dxl/yHLb/ALBWm/8ApFDXP0AFFFFABXQf8JnrM/Gpywaup4Y6nbpcyFO6CZwZUXr9x1wSSCCc1z9FAHoH/CeaXrHy+IdLnuGk4eWWT7YsYHRU8zFyFyM7RdKNzMcEEoT+xfBWv/Pp2o/2fMfmMXmLHtUcY8q5kVFycHIupWPXYASI/P60JtM8rw9Zat52ftN3PbeVt+75SQtuznnPnYxjjb3zwAdJqXw01ezt1vbee0lsHcKlxdSizXkEph5isUhIBP7l5F4J3EFSeX1LSdS0a4W31TT7uxnZA6x3ULRMVyRkBgDjIIz7GjTdW1LRrhrjS9Qu7GdkKNJazNExXIOCVIOMgHHsK6jTfibrWn27Wr2umz2hcv8AZVgNrAxIAbfHbNEkoYBQRIHGBjoTkA4uivQP7a8Ba1xqOjT6dNJ8jTQKNxP8Ll4ikUa9AwW1c7VJG5m4P+Fe6TrH7zwz4ssbv+9azRS+cGPOyKNEM0+0cs/lIuOR0cIAef1JBBNdXEVvbxSTTyuEjjjUszsTgAAckk8YroNV8AeK9Ge4W80O7ItU33EluBOkA27jveMsqEKQ2CQQCD0INR+Fv9BlvfEB4bSYhNbE8BrpmCwgHpuUlpgpB3CBgRjJABH4rnhOsnTrOWOWw0pPsNrJGwZZVRmLSg88SSNJJjJx5m0EgCsOiigCxY2NxqN5Ha2sfmTPkgFgoAAJZmY4CqACSxIAAJJAFaGt31uYrbSdOk8zTrLLLIVIM07qgml5wdpKAKMLhEXKhixNh/8Ain9DVB8uq6pEJC44a2tW3qUOeQ0o2scAfu9uCyysBz9ABVzTdNm1O4aONo4o40Mk9xKSI4IwQC7kAnGSAAASSQqgsQDXggmuriK3t4pJp5XCRxxqWZ2JwAAOSSeMVsapPDpVu2jadLHIGRPt91Gwbz5MBjEGHHlI3Hykh2XfkjywgBX1vUoby4+zaeskWkWzuLOFwA20n78mCQZWAUsfYAYVVUZdFFABXsHw3/5J5rn/AGCtd/8ARVhXj9eweEv3HwfktpPlmlu7+9ReuYX0y8iVs+7wSjHX5c4wQSAeP0UUUAFFFFABVixv7zTLyO8sLue0uo87JoJDG65BBww5GQSPxqvUkEE11cRW9vFJNPK4SOONSzOxOAABySTxigDYn1bTdVt5f7R0yO3v9hMd3pyLCrtjgSQABMcKoMfl4yWIkPBjubG3j8G6ZfrHi6m1C7hkfcfmRI7YqMdODI/5+wqx9i0fQ/8AkJv/AGnqA5FnaTobZO6+ZOhbf05SPHDD94rAqLmvapd6t4F0Sa7eMlNTvkjSKJIo418q0OERAFUZJJAAyWJ6kmgDLv8ARvsHh60vJ0nivn1C7s54ZRt8vyUgIG0jIbMrA59BwOc49dw+qW958PNEh8QG+u401C8gtrhLgmS0RYrUBVV8q0Y3E+X8uSBh0Gc8vqej3Gl+VI7wXFrPnyLq2lEkcgGM8jlWwVJRgrqGXcoyKAM+iiigAooooAKKKKACug8I/vb7UrJ+be50q881P73lQtOnPUYkhjbjrtwcgkHn66Dwb/yHLn/sFal/6RTUAc/RRRQB0HiH/kB+E/8AsFSf+lt1Wfo2h6p4h1FLDSLCe9umwdkKZ2gkDcx6KuSMscAZ5Nd5J4MNz4W8Laxr15HpGjw6YymS4WRXnY3U7qibY3wWWSM5IPysXVXCMBh6z4zgXTn0TwvY/wBmaOch3lSJ7u54K7nlCBhlWfKgnHmyLuKEKoBofZvCvgT/AJCEMHibX16W2+WO0tH6jzUaNWdhhMoT/FIjKhQFuT1/xHq/inVG1LWr6S7uygTewChVHQKqgBR1OABySepNZdFABRRRQAUUVoaZoWsa35v9k6VfX/k48z7JbvLsznGdoOM4PX0NAGfRXSR+DLuNJpNT1TRtKSJMut1fI8qtuC7DBFvlDjPIKDbtOcYqxHZeBdPeZb7V9Z1Z1t8ounWiW8TTFQcebKxfYDlSTED3A7EA5Ormm6TqWs3DW+l6fd306oXaO1haVguQMkKCcZIGfcV1EHjTQ9JuIpNG8CaMQtuIpDq7y37SNnl8FkRScDogxzg4OKr3nxN8aXlva258QXdtBapshjsNtoqrgADEQUEAAAA9O2M0AaEHwh8Vi3iu9WhtNDsZEDC71OcJGpIyFfbuMZPT5wozhc7iAcPxJ4f07Q/LS08R2Op3Awk8NurHY3OSki7o3jwFIO4N82CikEDDnnmuriW4uJZJp5XLySSMWZ2JySSeSSec1HQAUUUUAFFFFABRRRQB0HjL/kOW3/YK03/0ihrn66DxH8+leF52+aaXSj5kh5Z9l1cRrk98IiKPRVUdAK5+gAooooAKKKKACugvP+SeaN/2Fb//ANFWlamlfEzV9P0u30u707RtW0+1TbbWmoWQaKH1YIhUM5/vuGblsEbm3dZq994KuvCHhy41zwtfaXY6l9pvkuNEulP+lCQRTRrFLwkZEcTD+78qr0YkA8foruP+EY8E6lB5mleOfsl1PLtt7HV9Pki8sF8ASzxlkHy87gMeu3nFe4+GniL/AEx9JFjr1vabPMm0a8juvv8ATEanzOuRyv8ACT0GaAOPrU8S6bDo3irV9Lt2kaCyvZreNpCCxVHKgnAAzgegqnfWF5pl5JZ39pPaXUeN8M8ZjdcgEZU8jIIP41seO/8AkofiX/sK3X/o1qAI9K8Y+I9FS3isNYu0t7Z98Vq7+ZArbtwPlPlMhvmBxw2GHIBrqB8U11K3e18TeGNN1SCZ1mupImaC4upVBCtJN8xwNzYCbMDCghMofO6KAPQPsPwx1v57fV9V8NSH95Kt7EbyNSf+WUIjXcyjn53YHAX5WLErJYfDXXLPVPt+mRaN4st9PQXMyaXfxTpuG4okiHDsCVyUC/OMqCCcjzupIJ5rW4iuLeWSGeJw8ckbFWRgcggjkEHnNAFjVYNSttUuE1iK7i1AvvnW7VllLN82W3c5Oc5PXOap12mm/FTxXZW7Wd7ex63p8jl5bLWYxdxynAxkt8+AQGADAZGfXMi+IfA2r+WuteEJ9NmeV5bm90K8K5zuIVIJdyKuSvAYYxkYHy0AY/8AyLmj+up6rafQ2luzf99CSRV9h5Un8Xm/Jz9dxc+FdG1rdd6T49sb2/kie6uYtYjexkLnB2iRy0byEsQfnHPOSMkY+seB/Eug2aXt/pE62LxJMt5CVng2OcKfNjLJycY57j1FAHP0UUUAFewWn+j/AA88H+V8v23Std+0d9/kRXXlfTb9om6Yzv5zgY8fr1C01PzfD3g/SfJx9m8P67c+bu+95qXS7cY4x5Oc553dscgHl9FFFABRVzTdKvtXuGgsLaSd0QySFeFiQEAu7HhEGRlmIA7kVqb9L8P8IkGraqOHMq7rS2Yc5QhsTsDgZYeX8rDEqsGABXsdAeSzj1HU5/7N0yTPlXE0TMbkgkMsCgfvGGDzlUBwGddwzJP4gW3t5bTQbWTS7eZDHPILhpLi5QjlJJAFBTk/KioCNu4MVBrLvr641G8kurqTzJnwCQoUAAAKqqMBVAAAUAAAAAACq9ABXQXn/JPNG/7Ct/8A+irSufroNZ/0bwr4as05jmiuNQYnqJHmaAgf7O21jIHXJbnBAAAXn/JPNG/7Ct//AOirSs/TNYuNL82NEguLWfHn2tzEJI5AM44PKtgsA6lXUM21hk10kmmwy/BO21Rmk8+38RzW6KCNpWS2jZieM5zEuOe569uLoA6S80jRX8K3etaZeXbPHe29v9luEAaESJM5BYcSD92oVxtJw+UX5c83XQWf/JPNZ/7Cth/6Ku65+gAooooAKKKKACug8E/vPF9jZdP7R8zTd/8Azz+0xtBvx32+ZuxxnGMjOa5+u0+HmmWkWs2fiXWb6TTdI0y9hk+0m1eRZJVYP5YIwM4AyF3ONwbYVDsoBzejaJqPiDUUsNMt/PuGxgF1RRkhRlmIUZZlUZPLMoHJAPYeX4W8C/NNH/b/AIgX5TbzIEtrVv4hJE6Nv6AYJDYdwywSIKjn8Q6lrdvL4d8EaLdw6dsMkttaQtNI/GxpAPmaIMGIPzM2JCjSOgRVw/8AhFfs/wDyEte0Ox3f6v8A0z7Xv9f+PYS7ccfe25zxnBwAZ+s63qPiDUXv9TuPPuGzkhFRRkljhVAUZZmY4HLMxPJJOfXQfZvCdp80uo6rqMicNDb2qW8cp6EpM7swXuC0OSBghSeD+3tJtfl0/wAL2PycxT380txMrdcsAyQvg9AYtuAAwbkkA5+us034ZeNNVuGt4PD93FOELiO722zOoIBKiUqWAJUErnG5c4yMx2PxE8VaXeR3Om6r9g2ZPkWdvFBAxIILNCiiNmwfvMpPC88DGXqXiTWtXt1tb/VLue0Rw8dq0pEERAIGyMfIgAJACgADgYFAHUSfDi00l4T4j8aeH9PTf5dxBbSveXVvJtJKNFGvUMNpO7APc8A15D8OdLSERR+INeu4bjEpZ47G1uIwx5UYeQAgKMHBwScqeK4uigDrJ/G0MVvLa6N4W8P6dA1wZUeSzF7OFxgIXuC4Ixjoq8jIAyQcvWfFfiDxDvGr61fXsbSmbyZp2Mauc8qmdq9SBgDAOBxWPRQAUVqab4a17WbdrjS9E1K+gVyjSWtq8qhsA4JUEZwQce4q5/wicsHzajrOh2UJ4En9oJdZb0223muOM8lQvGM5IBAOforoPsPha04udbvr2aPlksLELDL3CrLK6uuRwWMJwc4VgBk/tnQbb5LPwrBPGeS2p3s0sgPoDC0K7enBUnOeSMAAHP0V0H/Ca69HzZ3UGnSdDNplnDZSMP7peFFYr0O0nGQDjIFc/QAUUUUAFFFFABRRRQB0HiH/AJAfhP8A7BUn/pbdVz9dB4h/5AfhP/sFSf8ApbdVz9ABRRRQAUUUUAFegeLf+SQ/Dr/uJ/8ApQtcnol7pltceVq2mR3dpM6LLKrSCeBM/M0WHVC+DkbwwyBxjOfQL1/AfiHw/pekjxfd6Pp+lvO1ol9ZPdXBEpUuriKNEQBkLDDyEh+SuNoAPK6K9A/4VPqN78uha5oesXD/ADR2Npeq9yF9ZAuY48DqTJtzhQzEruy9S+GPjfSrhYLjwxqTuyBwbWE3C4yRy0e4A8dM56eooAjtfiN4xtPPH/CRX1zHPE0MsN9J9qjdG6gpLuXnp06EjoTUcnim0vkhTU/DGjTOqeW9zaxvZylSxOQImEQcbsBjG3QZDYwebooA6DZ4Puvn8/XNMxx5Pkw327/a8zdDj027T0zuOcCQeEVubd5dO8S+H7143VXiN21owBB+YfaViDD5cHaSRkcc1zdFAHQa34G8U+HPPbVtBvreGDb5lx5ReFd2MfvVyh5IHB68dap6rpsNjp2h3ETSF7+ya4lDEYDC4miwvHTbGp5zyT9BHpmu6xonm/2Tqt9YedjzPslw8W/GcZ2kZxk9fU13msfEHU9PuNGj1TT9G167h0eBZ31bT459xkJmjYSYEhIikjU5ON284JO4gHmddB/whmswc6nFBpCjlhqdwltIE7uIXIldev3EbJBABIxW5Brfw31G3it9U8I6lpLogZ7vSNQMzSOBgr5c+QqHJPUkYAyeTRD4S8F6yhOj+Oo7O7mdjBZa1ZNAI1DHiS4UtGDtGQQOTgYBOAAV9A0LwudRmiv9Wk1Z0sru4EOnwPHE3l28jgGaXY6OCmf9U68LnOSBz9nr+paNcXTaDqWpaZBO+dkN2ysVBO0OybQxAJ5wOp4Ga9A0H4Ya/p95d6nBLpuo6SmmX8balaXii3DtayoAHk2bgGZQWXKg5BYFWA871PQtY0Tyv7W0q+sPOz5f2u3eLfjGcbgM4yOnqKANweOWvrh38RaDo2sJNcLPM5tVtJycnfiW32Eltxzv3DIBxxzXMfg2+t0EM2s6Td72XFyI7yAggbWZ0EboAd27CSHGCATxXN0UAdB/wh+o3HzaTPY6urf6tbC5VppfXbbttn45zmMcAt93muo1S2/szSNR0aRZ1utO8KWyXKzReWVklv4LkrjJPyicKc4OVPArzevWL/W9d0v+39NnuJ/JsPDWmbdOvkEsMMn+ghswSgoGBZuq5BJ70AeT1uQaHDaW8V9rd1HbwOgljs45Abq4UjIwoBEQIKndJjKtuQSY2ncsfF/hpryO6vPCn9nX32sym+0O7aIxIwIOyGYSIGBJZSpTBC7SuM1n3OmaDqe69i8Z4upZXNwNYsZo5GJwd4aHzg2SWzkg5HQ5oAy9S1pry3WwtYI7PTI3DR26BdzEAgNLIADK/LctwN7BQinbWXXSHwD4oa3S4tNJk1GB3ZPM0uRL5VZQCQxgZwpwwODjOa5+eCa1uJbe4ikhnicpJHIpVkYHBBB5BB4xQBHRRRQAV0HiH/kB+E/+wVJ/6W3Vc/XQeIf+QH4T/wCwVJ/6W3VAHQP+7/Z/WJ/lkfxKJ1Q8FozbugcD+6WjkUHplGHUGvP69A1b/kkOmf8Abp/6UarXn9AHQaH+/wDDXie2k+aGK0hvUXpiZLiOJWz7JPKMdPmzjIBHP10Hh7/kB+LP+wVH/wCltrXP0AFFXNN0nUtZuGt9L0+7vp1Qu0drC0rBcgZIUE4yQM+4rU/4RK4tudV1PStLXoRcXQlkV/7jwwiSVGHOdyDBGCQcAgHP0V2GmaD4bn82Rr2+vobfC3MxMdhbRE5+ZZn8x5OFYrGIhI4BIUFStai6/Y6JZT694Gso9Ok0+4gs1vbqHzbqYTJOSxDu8UZxEFOxcsckFFYx0Ac3/Z+naD82sj7ZqA4/suKRo/s7DnFw236Axod3LBmiZcHL1LVLvVrhZrt4yUQJGkUSRRxrknCIgCqMkkgAZLE9STVOigAooooAKKKKACus8JHSNWlbStZ02MxxWV5NHfWwKzx7IJZRuUMFlAIJAO1idoL7F21yddB4X/cQa/qK8zWelSeWp+6fOeO2bP0SdyP9oL1GQQCxD4JuLyzudVtNRsToNvtMuoSygGAOcIJYE3yoxb5cBWGckFl+eq/9l+Grb5LzxLPPIeQ2maa0sYHoTM8LbuvAUjGOScgHgUv/AMJ94fjjnnh87UIIXeCZon2O4RgHUhhlWI4I61JP4eVriWXVPEXh+wuJXMnlRyNMuCeo+yRyRqM5G3IIx90AjIBH/anhq2+ez8NTzyHgrqepNLGB6gQpC27pyWIxngnBB/wmWrQ8aetjpm3iKSwsYoZoV9FnC+d04JLlmGdxOTk+x+E7f/W6xqt3JH96O309I45SOoSV5dyqeztFkA5KZ+Wj+1PDVt89n4annkPBXU9SaWMD1AhSFt3TksRjPBOCADL1LVtS1m4W41TULu+nVAiyXUzSsFyTgFiTjJJx7mqddB/wlX2f/kG6Dodju/1n+h/a9/p/x8mXbjn7u3Oec4GD/hOfFKfLba9fWUI+7b2EptYU9dsUW1FyeTgDJJJ5JoA2NP8Ahz4gv9DvxL4dvrG+s8XS3N9G1rDJB0kVnlwgZTsdfu/L5uScKBx99ZS6feSWszwPImMmCdJkOQDw6EqevY8dOtbHgfjxppcj/wDHrFL514DyDaoC1wGH8S+UJMrzuGRg5wbB8JxXniOazstRgtrCS0fULO4vd7B7dUMhBMSNmRVVwwAwHjdQSQAQDl6K6D+xtBtvnvPFUE8Z4C6ZZTSyA+pEywrt68hic44IyRX1bTLC2060v9Mur65tbiWWEvd2kcGHjEZIAWWQniReuOoxnnABj0UUUAFFFFABRRRQB0HiH/kB+E/+wVJ/6W3Vc/XQeIf+QH4T/wCwVJ/6W3Vc/QAUUUUAFFFFABWhNpnleHrLVvOz9pu57bytv3fKSFt2c8587GMcbe+eM+ugvP8Aknmjf9hW/wD/AEVaUAc/WppviXXtGt2t9L1vUrGBnLtHa3TxKWwBkhSBnAAz7Crn9keHbr/jy8UfZ9v3/wC1bCSHd6bPIM2e+d23tjPOLF/4GvbPUbmyi1XQ7mS1leCc/wBpR2+yVSQy7bgxs2MfeUFTngkg4ANST4v+Lb54V1qTTdbtI33/AGPUdNgeIttIBwqggjccEEflkGu3jDw3qD3suseAtNM86BYpNJuprIQnaRuCZdCfukfKBkEkNmsv/hBvFL/NbaDfXsJ+7cWERuoX9dssW5GweDgnBBB5BrHvrC80y8ks7+0ntLqPG+GeMxuuQCMqeRkEH8aAOoltvh3e/YUtdR8R6VI+BdNd2sN3GhOOQUeNtq/NztJIxgA8GNvBdpdJey6P4v8AD96lu4Ecc872UsqliAQJ1RM4GSA5x6nIzydFAHSSeAPFapDLBod3fQTJvjn04C8iYbip/eQllyCpBGcio/GX/Ictv+wVpv8A6RQ1hwTzWtxFcW8skM8Th45I2KsjA5BBHIIPOa7jxZ4w1+LWLeKXUpLyA6ZYSeRqCLdxB2tIWZxHMGUOSWO4DPzNzycgHB0V0kHifT3uIpdV8J6NfHeDO8fnWrSLnoFhkWJDjjIj9yCc5AfBN1burR+INMnV1KOHhv1dcHcCuICpztwct34oAk8IX95pmn+Kbywu57S6j0pNk0Ehjdc3lsDhhyMgkfjVjTPih4u0rzRDqnmfaMC6kkiQzXKjOBJOAJjgEgEOGUfdK4GOo0PwNo1z4a1O40fxnYyR6jp7Qu2qW72S2zx3FnIwZsuvG9V4P3mXG4ZK8u/ww8VPZ3V7p1lBq9jbymI3GlXcV0HOQPlVGLngg42ggHJAoA0P+FgaPqny674UsW3/ACyPaIi7v+mkjMpuJJN3zEi4TfgAkZYk+yfDjVP3iX8+ls/yP5pljWM/30gEdwWXGDhrgFmDD5Bg1x+p6FrGieV/a2lX1h52fL+127xb8YzjcBnGR09RWfQB6B/wrL7d/wAgbV/tez/W/wCjfaNuen/Hk9ztzg/f2Zx8u7Dbdz4t+Htfvvifr8ukQSXaXKQJLbWM6zTlBFEf3kCMZAm5VOWUDO091zwfgT/kofhr/sK2v/o1a3PGXi/XIPGut2cl3He29pey21tHqVvFeiGONiihPOV9pKqu5hy5ALFjzQBxd9YXmmXklnf2k9pdR43wzxmN1yARlTyMgg/jVeu4sfiNPFZx2NxZzxWaZZotMv5bdJWJJYPDJ5tv5bEsWjWJVOccLlTY/tnw1qv+uGlCT76R6npDWscIPVBLp7K0rdOXiAwpI2E7WAODgnmtbiK4t5ZIZ4nDxyRsVZGByCCOQQec12Ft8U/FC29tZ6pPaa7YW7l1tdZtUulZiG5LMN5I3HB3cdOnFXP+ES0DUvl0n7dKp5jksL+DUJp8dVWzZbecY5JYjgKTtKncMe+8JWtteSWo12C0uhgLY6taz2dyGIGA42NEmcggmXbggkrzgA1IfEXgPVkKa54Rk02eR2knvNFnckksSFjhkfZEORk/OMAgKNwKSf8ACJeCtW+bRfGXkTS8pZahEsfkL0BlnkaJDzjcI1dhkhRIF3Hn/wDhB/EsnNnpE+ox9DNphW9jU/3S8JZQ3Q7Sc4IOMEVz9AHYan8NfEGm+UdkEqzZEQZmtZJnGMpHDcLHLI3zL9xGyWABJyBj69LeRrpmlX+nT2N1pdobZ451Ku26WSYMVIBXiYDHtnvVfTNd1jRPN/snVb6w87HmfZLh4t+M4ztIzjJ6+pqvfXsuoXkl1MkCSPjIggSFBgAcIgCjp2HPXrQB1l++pX3hbwz4f06yku3vLIXHlwRNJKWiur4AKF7bZHJ4PQdMHOX/AMIlcW3Oq6npWlr0IuLoSyK/9x4YRJKjDnO5BgjBIOATxD/yA/Cf/YKk/wDS26rn6AOg8nwnY/6261XVpB8jR28aWcee7pK/mMy8cBokJBydpG02LfV/3F3NofhrSrdbKISTXFwn2uTyd6xjes5aMsWePLJGpz0CrkVh6bpOpazcNb6Xp93fTqhdo7WFpWC5AyQoJxkgZ9xXaeGvBmspp/iK21GKDSGuNPjjH9q3CWpQfbLY+YyOQ4jwD8+0gkbRluKAOT1LxJrWr262t/ql3PaI4eO1aUiCIgEDZGPkQAEgBQABwMCrn9lWeg/vNdPm3y/NHpcTBuRxi4dWzDg9Yx+8+VgfKyrV3kejeCvDLzWdp8R7Sz1KJ/8AkK2VhcXErIyg4jeNtkQ52nYWbhsuA7Rryf8Axbi30f8A5mu+1Nf+ve0hf5v+2rLhf97JHbPABz+p6zear5Ucz+XaW+Ra2cZIhtlOMhFJOM4GScsx5YsxJOhZ/wDJPNZ/7Cth/wCirutS88XeFkuLWfRvh7pts8L73F/f3N2rkEFfl3oMcHIYMDn87Go+KJ9c8C67IdM0awifU7BBBp+nRQqg8q5JwcF85QHJYkZYDAYggHB0UUUAFFFFABRRRQAV0Hh7/kB+LP8AsFR/+ltrXP10Gl/6N4L8QXicyTS2mnsD0EbmSckf7W61jAPTBbjJBAAeCv3fiq2vB/rLCKfUIgejSW8LzoG/2S0aggYOCcEHmufroPBv/Icuf+wVqX/pFNXP0AFFFFABRRRQB0HhP9xPq2otzDZ6VdeYo+8fOT7MuPo86E/7IbqcAng3/kOXP/YK1L/0imo0b/RvCviW8fmOaK309QOokeZZwT/s7bWQE9cleMEkHh7/AJAfiz/sFR/+ltrQBz9dBef8k80b/sK3/wD6KtK5+ug1f/RfCHhyy+95/wBp1Lf02+ZIINmO+Psm7P8At4x8uSAc/RRRQAUUUUAFFFFAHQeIf+QH4T/7BUn/AKW3Vc/XQeIf+QH4T/7BUn/pbdVz9ABRRRQAUUUUAFdBef8AJPNG/wCwrf8A/oq0rn66DXP3HhrwxbR/LDLaTXrr1zM9xJEzZ90giGOny5xkkkA5+ug8d/8AJQ/Ev/YVuv8A0a1c/XQeO/8AkofiX/sK3X/o1qAOfruPEnizxJpmoWdnYeINVtLWPStO2QwXskaLmzhJwoOBkkn8a4eug8Zf8hy2/wCwVpv/AKRQ0AH/AAmF+/yz2Ghywnh4/wCxrWPevcbo41dcjurKw6gg81uXWsaPN4F0n7V4YtI7d9TvVK2N1PHIhEVqdyNI8gBOQDuVhheApJauDroNX/0Xwh4csvvef9p1Lf02+ZIINmO+Psm7P+3jHy5IAb/B918nka5pmOfO86G+3f7Pl7Yceu7cemNpzkbHxgvrfUPivr81rJ5kaypCTtIw8caRuOfRlYe+OOK4eug8d/8AJQ/Ev/YVuv8A0a1AHP0UUUAegaT/AMkh1P8A7e//AEo0qvP69Ai/cfAOW5j+WaXxA9k7dcwvDFKy493giOevy4zgkHz+gDrNN+J3jfSrhp7fxPqTuyFCLqY3C4yDwsm4A8dcZ6+prQh+JzTIY9a8JeGNVMzsbu6fT1hupwzEsfMjwFfBIDhcg4PJ68HRQB6J4fuvCGo+Lv7QsNP1LQZLO3uLyCCOVb6NZIbd5FcFzGylGjD7WLhz8p2r1r+NPD0F3468Qm28RaM93JqdywtJJJYGB81iVMksaxAjnq+DjAJJAOfpGmzaHdavdTtHI9roX2gIhOHW8ijiUZI4KrdhjwclCO+4U/Hf/JQ/Ev8A2Fbr/wBGtQAf8IP4lk5s9In1GPoZtMK3san+6XhLKG6HaTnBBxgiuforoP8AhOPEsnF5q8+ox9RDqYW9jU/3gkwZQ3UbgM4JGcE0Ac/XSaBqni+5RdJ0V9S1C3hQv/ZixNdwBd2SWgYMhG5gcleGIPXBqP8A4SOyuf8AkI+GdKnkfiW4txJayEdMosbiFGA6HyiMjLBjnMc58K3NvK1vHrOnzohMaSPFeLM2OAWAhMYBHXD5z0GPmALl/wCB/FUeo3J1PSP7ObzXDTXZisrZnycrG7lYj3IVD0BIGBXWaAvi681GWLWNc03VrZbK7kSDUNbs79FlW3kaNxHJI4BVgp3Y4G7J2lq4vx3/AMlD8S/9hW6/9GtR4N/5Dlz/ANgrUv8A0imoA6D7HZy8+JrXwpbI/D3thqQWZm/hCx2hmjTgYJ8jaQDkh2BOXr+leD7fS2utH8QSS3m8Itgsck4YdTI0zxQBRjjaEY5A5wTt5OigDrNQvYLHTPCstxplpqCHR5FEV00qqD9tufmHluhzxjrjk8dMXNG8R3U2leIZYrLSrVrHT0msnt9NgWS2b7VBGGSXaZNwV2AcsWz82dwzWP4h/wCQH4T/AOwVJ/6W3VHh7/kB+LP+wVH/AOltrQBT1LxLr2s262+qa3qV9Arh1jurp5VDYIyAxIzgkZ9zXUeE4IW+FPxCuGijM6JpyJIVG5Va4ywB6gEqpI77R6Vwddh4Y1PyvAXjnSfJz9ptLS583d93yrqNduMc587Oc8be+eADj6KKKACugf8A0X4eQ7Of7R1WTzd38P2aJNm30z9rkznPRcYwc8/XQXn/ACTzRv8AsK3/AP6KtKAOfooooAKKKKACiiigAroLP/knms/9hWw/9FXdc/XQf8enw8/vf2lqv08v7NF+u77X7Y8vvu4ADwn+4n1bUW5hs9KuvMUfePnJ9mXH0edCf9kN1OAefroPD3/ID8Wf9gqP/wBLbWufoAKKKKACiiigDoP+PT4ef3v7S1X6eX9mi/Xd9r9seX33cHh7/kB+LP8AsFR/+ltrRrP+jeFfDVmnMc0VxqDE9RI8zQED/Z22sZA65Lc4IANI/wBF8IeI7373n/ZtN2dNvmSGffnvj7Jtx/t5z8uCAc/XQeIf+QH4T/7BUn/pbdVz9dB4h/5AfhP/ALBUn/pbdUAc/RRRQAUUUUAFFFFAHQeIf+QH4T/7BUn/AKW3Vc/XQeIf+QH4T/7BUn/pbdVz9ABRRRQAUUUUAFdB4h/5AfhP/sFSf+lt1XP10HiH/kB+E/8AsFSf+lt1QAeBP+Sh+Gv+wra/+jVrn66DwJ/yUPw1/wBhW1/9GrXP0AFdB4y/5Dlt/wBgrTf/AEihrn66Dxl/yHLb/sFab/6RQ0Ac/XQeIf8AkB+E/wDsFSf+lt1XP10HiH/kB+E/+wVJ/wClt1QBT8NabDrPirSNLuGkWC9vYbeRoyAwV3CkjIIzg+hq547/AOSh+Jf+wrdf+jWo8Cf8lD8Nf9hW1/8ARq1X8WX1vqfjLXL+zk8y1utQuJoX2kbkaRipweRkEdaAMeiiigD0D/m3r/ua/wD20rz+vQP+bev+5r/9tK8/oAKKKKAPYPDv+jeNLa8fmOaLw3p6gdRI4tZwT/s7bWQE9cleMEkeP17Bbfu/iHqe/wCXz/iBaeVu48zy5bnft9dvmR5x03rn7wrx+gAooooAK6DwJ/yUPw1/2FbX/wBGrXP10HgT/kofhr/sK2v/AKNWgDn66Dwb/wAhy5/7BWpf+kU1c/XQeDf+Q5c/9grUv/SKagDn6KKKAOg8Q/8AID8J/wDYKk/9Lbqjw9/yA/Fn/YKj/wDS21o8Q/8AID8J/wDYKk/9LbqjRv8ARvCviW8fmOaK309QOokeZZwT/s7bWQE9cleMEkAHP10Hh7/kB+LP+wVH/wCltrXP10Gh/uPDXie5k+WGW0hskbrmZ7iOVVx7pBKc9PlxnJAIBz9FFFABXQXn/JPNG/7Ct/8A+irSufroLz/knmjf9hW//wDRVpQBz9FFFABRRRQAUUUUAFdBef8AJPNG/wCwrf8A/oq0rn66DVP9G8F+H7N+ZJpbvUFI6CNzHAAf9rdayEjpgrzkkAANA/d+H/FUr/LG+nxQK54DSG7gcID/AHiscjAdcIx6A1z9dBZ/8k81n/sK2H/oq7rn6ACiiigAooooA6DxZ+4n0nTl5hs9KtfLY/ePnJ9pbP0edwP9kL1OSSz/AOSeaz/2FbD/ANFXdHjn5PHOtWy8Q2d29lAv9yGE+VGue+ERRk8nGSScmiz/AOSeaz/2FbD/ANFXdAHP10HiH/kB+E/+wVJ/6W3Vc/XQeMv+Q5bf9grTf/SKGgDn6KKKACiiigAooooA6DxD/wAgPwn/ANgqT/0tuq5+ug8Q/wDID8J/9gqT/wBLbqufoAKKKKACiiigAroPEP8AyA/Cf/YKk/8AS26rn66DxD/yA/Cf/YKk/wDS26oAPAn/ACUPw1/2FbX/ANGrXP10HgT/AJKH4a/7Ctr/AOjVrn6ACug8dfL4+8QRDiOHUJ4IkHSONHKIijsqqqqAOAAAOBXP10Hjv/kofiX/ALCt1/6NagDn66Dxd+6vtNsk4t7bSrPyk/u+bCs789TmSaRuem7AwAAOfroPGX/Ictv+wVpv/pFDQBJ8PoJrn4jeG0giklcanbuVRSxCrIGY8dgoJJ7AE1zdegfBL/kr2hf9vH/pPJXn9ABRRRQB2E2p+V8G7LSfJz9p8QT3Pm7vu+VbwrtxjnPnZznjb3zxx9dBef8AJPNG/wCwrf8A/oq0rn6ACiirFhY3Gp6jbWFnH5l1dSpDCm4Dc7EBRk8DJI60AekXGp7vi0LJodsOleK77VZ592cQh43kO3H8CWzNxknOAM4z5fXcQ31vqfxO8S39nJ5lrdRazNC+0jcjW1wVODyMgjrXD0AFFFFABXQeCv3fiq2vB/rLCKfUIgejSW8LzoG/2S0aggYOCcEHmufroPBv/Icuf+wVqX/pFNQBz9dB4c+TSvFE6/LNFpQ8uQcMm+6t42we2Ud1PqrMOhNc/XQeHv8AkB+LP+wVH/6W2tAHP0UUUAdB4h/5AfhP/sFSf+lt1RZ/8k81n/sK2H/oq7o8Zf8AIctv+wVpv/pFDRZ/8k81n/sK2H/oq7oA5+ugs/8Aknms/wDYVsP/AEVd1z9dBZ/8k81n/sK2H/oq7oA5+iiigAroLz/knmjf9hW//wDRVpXP10F9+78A6JE/yyPqF9OqHgtGUtkDgf3S0cig9Mow6g0Ac/RRRQAUUUUAFFFFABXQeIf+QH4T/wCwVJ/6W3Vc/XQeKP3EGgac3M1npUfmMPunznkuVx9EnQH/AGg3UYJACz/5J5rP/YVsP/RV3XP12Fhot7rXgjT7XTFgE0moX004luY4BIkMNuQWZ2UNsEkpHPyhnPTdWf8A8IvFB8uo+I9DspjyI/Pe6yvrutklQc54LBuM4wQSAc/RXQf2HokH7y58W2MsI+8lhaXMkx9NqyxxIeeuXXjOMnAJ9j8H/wDQd1z/AME0P/yVQBz9bnguCG68deHre4ijmgl1O2SSORQyuplUEEHggjjFSfbPB/8A0Atc/wDBzD/8i1seFvE/hHRPEdpcXHhmd7BN7STSXbzXkbFGCmJkMMa4O0gldynLBs7doBxc8811cS3FxLJNPK5eSSRizOxOSSTySTzmty8/5J5o3/YVv/8A0VaVn65Yvp2uXtrJHBHslYoLZmaEoeVaNmyzRlSCrEnKkHJzWhef8k80b/sK3/8A6KtKAOfroPGX/Ictv+wVpv8A6RQ1z9dB4y/5Dlt/2CtN/wDSKGgDn6KKKACiiigAooooA6DXP3/hrwxcx/NDFaTWTt0xMlxJKy49kniOenzYzkEDn66C8/5J5o3/AGFb/wD9FWlc/QAUUUUAFFFFABXQeKv9H/sTTfvfYtKg/edN/n7rrp22/aNnU52Z4zgc/XQeMv8AkOW3/YK03/0ihoAPBP7vxfY3vX+zvM1LZ/z0+zRtPsz23eXtzzjOcHGK5+ug8G/8hy5/7BWpf+kU1c/QAV0Hjv8A5KH4l/7Ct1/6NaufroPHf/JQ/Ev/AGFbr/0a1AHP10HjL/kOW3/YK03/ANIoa5+ug8dfL4+8QRDiOHUJ4IkHSONHKIijsqqqqAOAAAOBQBsfCG+t9M+J2mX95J5draxXU0z7SdqLbSljgcnAB6Vw9dx8NLG3u5/FU08e+S08NX80B3EbHKCMnjr8rsOfX1xXD0AFFFFAHQXn/JPNG/7Ct/8A+irSufruC40X4a6BNqGhWN/Hf6hfzWxu5ZhhFW3jJHlSp1ZGHzZ+6MYB5x/+Ey1T/n10P/wRWX/xmgDn67T4feGteufF/hvVINE1KXTxqdu5u0tXaIKsw3HeBjAwcnPGDWX/AMJ14sXiLxJqsEY4WG3u3ijjHZURCFRR0CqAAOAAKy5tW1K51QapPqF3LqAdXF28zNKGXG07yc5GBg54wKAK8M81s5eCWSJyjIWRipKspVhx2KkgjuCRUdFFABRVzTY9NluGXVLu7toNhKva2yzsWyOCrSIAMZ5z2HHPHUab4Gg8RW7S+H7rWZ0Ryrz3WhyiAEAEqHt2nO/lTgqBjJyOAQDi66Dwj+6vtSvX4t7bSrzzX/u+bC0CcdTmSaNeOm7JwASNDU/AtrpHlfafHHhSTzc7fslzPc4xjOfKhbb174zzjoa2NO8K2A8P66dD8R2OqNPpSJcNI8dkkMou7Zto851dlwD85RVPygEsdoAPN66Dw9/yA/Fn/YKj/wDS21qxY/D7xBqd5HZ2A0q7upM7IYNZs5HbAJOFEuTgAn8K2NJ8DeKbLT/FdrJoN9JI2nrAhtojOjyLeW5ZFePKsy7XyASRsYHBU4APP6K6D/hBPGH/AEKmuf8Agum/+Jrn6AOg8Zf8hy2/7BWm/wDpFDRZ/wDJPNZ/7Cth/wCirupPFcE114ksre3ikmnl0zTEjjjUszsbOAAADkknjFR/8IJ4w/6FTXP/AAXTf/E0Ac/XQWf/ACTzWf8AsK2H/oq7rn66Cz/5J5rP/YVsP/RV3QBz9FFFABXQeIf+QH4T/wCwVJ/6W3Vc/XQeIf8AkB+E/wDsFSf+lt1QBz9FFFABRRRQAUUUUAFdB4y/5Dlt/wBgrTf/AEihrn66Dxp8niV7ZuJrO0tLKdf7k0NvHFIue+HRhkcHGQSMGgDoNB/0f4eHUvvfYv7W/d9N/nxWVr17bftG/oc7McZyPP69A/5Bvwr/AL1ve2n1cXE95+XliPS/c7n7g/L5/QAUUUUAFFFFAHQN/wATvwvJO3zajpGzzJD96WzYrGuTx/qn2KOrFZlHCxDBq/8AovhDw5Zfe8/7TqW/pt8yQQbMd8fZN2f9vGPlycvStSm0jVLe/gWN3hfJjlBKSr0ZHAI3Iykqw7gkd67TxT4XvL6Pw/F4Zsb7VrGPSvNje2iM7xxyXdy6LKUGBIAdrDoGVgOlAHn9dB42/d+L76y6/wBneXpu/wD56fZo1g347bvL3Y5xnGTjNH/CE+Io/wDj90/+zM/c/tWaOx8z12eeyb8cZ25xkZxkVY+ItlLZ/EPX/NeBvO1C4mXyZ0lwplfAbYTtbjlWww7gUAcvRRRQAUUUUAFFFFAHQXn/ACTzRv8AsK3/AP6KtK5+ugvP+SeaN/2Fb/8A9FWlc/QAUUUUAFFFFABXceJPCfiTU9Qs7yw8P6rd2smladsmgspJEbFnCDhgMHBBH4Vy+ma7rGieb/ZOq31h52PM+yXDxb8ZxnaRnGT19TWp4+nmm8b6nHcSyTz2bpYyTyMWadoEWEynPOXMe7GTjdjJ6kA1PDXhq/03VZ5b+40q0zp97AY7jVrWORJJLWWNUeNpAyNvYKQwBU9cYNY//COWCfLP4t0OKYcPHi6k2N3G6OBkbB7qzKeoJHNc/VzTdJ1LWbhrfS9Pu76dULtHawtKwXIGSFBOMkDPuKANT7D4Tj+SXX9VeReGa30hGjY9yhe4VivoWVTjqAeKuatrfhXVdZvtRuNH1mWe6uJJ5JI9SigV2ZixIjMDlASfu73x03NjJp/8IXrafLcpY2Uw+9b3+pW1rMnpuilkV1yORkDIII4Io/sbQbb57zxVBPGeAumWU0sgPqRMsK7evIYnOOCMkAB/b+kR/JF4P0p414Vri4u2kYdi5SZVLepVVGegA4rQ13x9d6h4h1O9s7TSha3F3LLCLjRLN5AjOSu9jGSWwRkknJ7ms/zvB9v+6+w65fbf+Xj7ZDab/wDtl5Uu3HT77ZxnjOAf8JRFB82neHNDspjwZPIe6yvptuXlQc45ChuMZwSCAamjfE3XtMTU4byaTU7S9snsxY3M7raxK7LnbEhUKAgZAE27Q3HAwa+pWOi2VwtrrPh7xBoF3MglLNIJFQEnlIJERyhIKjMuR3ZiCDXm+IHi+Zwy+I9St0VFRIbSdreJFVQoCxx7UUAAcACo/wDhO/GH/Q165/4MZv8A4qgDcg+GGoatbxXOif2lJFMgMK3+kXEDTEjKlWQSRBDkYdpFHXOANxp6n8K/HOkeV9p8M30nm52/ZFFzjGM58ott698Z5x0NcnPPNdXEtxcSyTTyuXkkkYszsTkkk8kk85qSxsLzU7yOzsLSe7upM7IYIzI7YBJwo5OACfwoA9Q8T+E/Elx8LfAVnD4f1WS6tf7Q+0QpZSF4t06ldygZXI5GetcP/wAIJ4w/6FTXP/BdN/8AE11k/gf4keL9E0eD/hH9SEGkW7WaLfXAiJO9n3KkpUgbWjTgEYjAzxgU/wDhXWjaf+91z4ieHIbU/KraY738hfqAY0AIXAPzZ4OB3oA5/wD4QzV14lfSoJBw0NxrFpFJGe6ujyhkYdCrAEHggGj/AIQ3VP8An60P/wAHtl/8ercjsvhbp7zW99q/ifVnV8pdadaQ28TKVHG2Vi+Qcgk49h3NPUPEvhCTL6Z4Bgt5G2grd6rcTxqBuyQFKNuOV5LEYQYAJJoA5OeFra4lgcxl43KMY5FdSQccMpIYe4JB7Vc0zQtY1vzf7J0q+v8AyceZ9kt3l2ZzjO0HGcHr6Gtj/hPdWt5/M0m20rSNsXkxmw0+JZIl2bCVmZWm3EZyxctknmsfU9d1jW/K/tbVb6/8nPl/a7h5dmcZxuJxnA6egoA6TTdO8U6DbtELnTdCcOZJJbqe2gv7YYGSM/6UgKjO1BllJwrbua+pf2ff3C3HiHxxd6tPsCRyWltNdMigk4Y3BhKjJyAu7+LOOM8nRQB0H27wtac22iX17NHwr398Fhl7FmiiRXXI5CiY4OMswByf8JV9n/5Bug6HY7v9Z/of2vf6f8fJl245+7tznnOBjn6KANi+8V+INRs5LK61q+ksXwDZidlgABBVViBCKoIGFAAGBgDFU9N1bUtGuGuNL1C7sZ2Qo0lrM0TFcg4JUg4yAcewqnRQB0H/AAnfjD/oa9c/8GM3/wAVWppvxa8eaVbtBb+Jbt0Zy5N0qXDZwBw0isQOOmcdfU1x8Eiw3EUrwxzojhmikLBXAP3TtIOD04IPoRW59u8LXfNzol9ZTScM9hfBoYuwZYpUZ2wOSpmGTnDKCMAHaeLfix41hvFsF1eNrSfTLN5YZLK3dXMtrE8mQyHIZnbjpzjpxXF/8Jlqn/Prof8A4IrL/wCM1Hqlrpk9u17aeI5Lp40SIW9/bSRXDhQFAXaZI9irgDMinCkbeBkg8WajbW8UCW2jFI0CKZNFs3YgDHLNESx9yST3oA7DTfjz48sbhpbi+tNQQoVEV1aIqg5HzDy9hzxjrjk8dMXLj416rf6TqFxdRQR6lJd25jhgu76JDGI5Q5GycBMHy+AQG3ZIYgEcP/wk1rL8974X0O6uD9+bZPb7vT93BKkY4wPlUZxk5JJJ/wAJDpf/AEJmh/8Af69/+SKAOw0z4t6cvmtr/gHQ9XmbGy4k3NMeufMln81342gZIwBjpjGh/wALf8H/APRJtD/OH/4xXn/9qeGrn57zw1PBIOAumak0UZHqRMkzbuvIYDGOAckn2zwf/wBALXP/AAcw/wDyLQB3kPi/4Saghudc8HakLx3Y+VaeVHFCm47UXyWhDAD+JlLc4LMAK0L3xX8Ep7XTo5fC+szJb25jijWRwYFMsjbGPnjJ3MzZBbhwM8YHmf8AxR93/wBBzS9v/XG/8zP/AH42Y/4FnP8ADjk+x+D/APoO65/4Jof/AJKoA7TUm+FmpW6rZWdppgLh1ddUvhPtwfldWtJUB5GdpbkcMR1uf8I58EX+WDxbrksx4SPAj3t2G6SBUXJ7syqOpIHNcm/g7RUt7S5uPEF3plvcOjB9V00RM8LDPmRxRyySOCOjbVjOCN4OAadj4Pt9TvI7Ow8UaVd3UmdkMFrfyO2AScKLbJwAT+FAHYX3gr4fyWci2Go6rBdHGySfV9IlReRnKi4UnjP8Q9eelZcHw60u6uIobfWdSui7gP8AYLG1vmiUnBdo7e8kcIO52nqB1IBj/wCFPeJpfksl+1XB+5D9hvLfd6/vJ4EjHGT8zDOMDJIBx774feINMvJLO/GlWl1HjfDPrNnG65AIyplyMgg/jQB3H/Cl9L/6GTXP/CPva4/U/AEmieV/a2u2Nh52fL+12OoRb8YzjdbDOMjp6is//hDNXbiJ9KnkPCw2+sWkskh7KiJKWdj0CqCSeACa0NM0L4j6J5v9k6V4rsPOx5n2S3uIt+M4ztAzjJ6+poAr2PhGw1C8jtYfGvhxJHzgztdQoMAnl3gCjp3PPTrXWeJfh7DrPirV9Ut/HXgpYL29muI1k1cBgruWAOFIzg+prHnn+LNrby3FxL41hgiQvJJI10qooGSSTwABzmsP/hNNbf5rl7G9mP3ri/022upn9N0ssbO2BwMk4AAHAFAHoGt+GtHOmWegW3jKC4sbOJEeaCTT9lw6yTyK48y8V12i5dMY5xnnjFex+CtxqdnHeWE+q3drJnZNBb2EiNgkHDC+wcEEfhXD/wDCZap/z66H/wCCKy/+M0f8JHYP80/hLQ5Zjy8mbqPe3c7Y51Rcnsqqo6AAcUAegf8AChtU/wCeeuf+Adl/8m1T1L4M3mlW6z3Fv4ndGcIBa6Rb3DZwTysd2xA464x09RXF/wBv6RJ8kvg/Skjbhmt7i7WRR3KF5mUN6FlYZ6gjitDTPFOj6J5v9kweK7DzseZ9k8QpFvxnGdtsM4yevqaAND/hXH/Tj45/8JX/AO6KP+Fcf9OPjn/wlf8A7oo/4WD9o/df2745sd3/AC8f279r2f8AbLZFuz0++uM55xg3NN+IU+lXDT2/xE8XO7IUIutMiuFxkHhZLpgDx1xnr6mgCn/wrj/px8c/+Er/APdFZel6D4V1a/Wyt9f1kTujmNX0eL94yoWCLi5JLsRtUd2ZR3rtP+FreIrr/jy+JH2fb9/+1dDjh3emzyEmz3zu29sZ5xTvPjB430q4tZYfGmm6ym/dJFDYFVwCPlffBGcNyPlOeDyOKAODvrbw3HZyNYarqs90MbI59MjiRuRnLCdiOM/wn0461T1bUptZ1m+1S4WNZ724kuJFjBChnYsQMknGT6mvXPG3xo1uee+0S50bQ7vSLuKOWOO4glLmCVFli3kSDEgV0yV6MMqeAa8XoAKKKKACiiigAooooA6C8/5J5o3/AGFb/wD9FWlc/XQXn/JPNG/7Ct//AOirSufoAKKKKACiiigDrPh5Hpv/AAllre393dwvpr/2ikcFssomW3Vp3UkyLtJWPA4bk84xVP8AtTw1bfPZ+Gp55DwV1PUmljA9QIUhbd05LEYzwTgjP0zU/wCzYNSVYd013aG2jmDbWgy6FmHH8SK8ZHGVkYdMg6mlfD/xfrT262HhzUnS5TfFM8DRxMu3cD5j4TBHQ554x1FAEf8Awl97B8unWOladGvMX2ewjaSE/wB5J5A0wbPIbflT90gAAU9S8S69rNutvqmt6lfQK4dY7q6eVQ2CMgMSM4JGfc12A+C/ii1t3uNdudG8PwB1SOTVNQRFlYgnClNwyApODj2zg4k/4Q74e6PPjWviD9tkhi3z2mkWTP5jlMhIrg5jPJAyQPQ7TnAB5vRXoH9r/C7S/wDjy8L65rnmff8A7Vv1tvJx02eQDuzk53dNox1NWP8Ahbf9mz7vDXg7w5pHlReVa3H2XzruD5Npbzjjc3J5ZTnODu5yAcXpvhrXtZt2uNL0TUr6BXKNJa2ryqGwDglQRnBBx7iuog+D/jD7PFealaWmjae6B3vdTvI4Y4QR8u8ZLqSSFwVzkgHFU9T+KnjnV/K+0+Jr6Pys7fsjC2znGc+UF3dO+cc46muTnnmuriW4uJZJp5XLySSMWZ2JySSeSSec0AegH4e+F9Nt0bXfiTo0M8jsI00uB9QXaAOWZCCpyTwR24J5wTz/AAk0u4lks7LxPrbwuVjhu54oLe4Gcbi6ASKMfMOAcgAgc153RQB6B/wsXRtP/daH8O/DkNqfmZdTR7+Qv0JEjkELgD5ccHJ71XvvjB4+1CzktZvEc6RvjJgijhcYIPDooYdOx56dK4eigC5qWralrNwtxqmoXd9OqBFkupmlYLknALEnGSTj3NU6KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKuabpV9q9w0FhbSTuiGSQrwsSAgF3Y8IgyMsxAHcitT/indG/6j92P+ukFmv/AKDNLwf+mW1l/jU0AU9N0C+1K3a8Cx22no5SS+um8uBWABKhj99wp3eWgZyAcKauf2ro+kcaNYfbLgf8v2qwo+P9y3y0a8Eqd5lzgMuw1l6lqt9q9ws9/cyTuiCOMNwsSAkhEUcIgycKoAHYCqdAEk8811cS3FxLJNPK5eSSRizOxOSSTySTzmo6KKACtix8WeJNMs47Ow8QaraWsedkMF7JGi5JJwoOBkkn8ax6KAOg/wCE78Yf9DXrn/gxm/8AiqP+E78Yf9DXrn/gxm/+Krn6KAOkg8c61a3EVxbxaNDPE4eOSPRLJWRgcggiLIIPOa3P+F2/EP8A6GH/AMkrf/43Xn9FAHoH/C6/Hz/LPrnmwnh4/s8ce9e43Rqrrkd1ZWHUEHmj/haf/UheBv8AwT//AGdef0UAegf8LT/6kLwN/wCCf/7OsuHxXoUuqG51PwJo00Ejs8sVpcXVsSTn7v71lQAkcBcY4GO3J0UAegf8Jb8PP+iYf+V+4/wrHvtU8FXd5JPD4W1WyjbGIINaUomABwXt2bnryT19OK5eigDsNMm+HEvm/wBrWPiu1xjy/sl5b3G7rnO6JMdumc5PTHMepQfD6W4VtL1LxPbQbAGS60+3nYtk8hlmQAYxxjseeeOTooA2NcuLCWDT4bDUr69jtYmhUXdjHb+UhdpABskfdlpJDzjGR1HTHoooAKKKKACiiigAoorY8PTeH4rwnxBa300PWNrWRcKQCcPGcGRSdoIWSMgZwc4wARz6lDL4V0/S1WTz7e9ubh2IG0rIkCqBznOYmzx3HXtnwQTXVxFb28Uk08rhI441LM7E4AAHJJPGK9AHjzwppdu8ei/D/TftG9SbjUHNzHMFBHMMm8xg7t21Jcghcs4BBrz/ABb8R/Z5bXTIdN0mzmQpNZ2ltvt3UjBAhlLogOWyEVdxYltx6AGfYfDLxpqL7I/D93A5cIi3u21MjFWbCeaV3najEhc4Aya2IPhHfQXEUPiHxF4f0CXePOt7+82zohP31GNkgx0KvjIKkghgOTvvFfiDUbOSyutavpLF8A2YnZYAAQVVYgQiqCBhQABgYAxWPQB6INC+F+nW7zXfjHUtZO9QIdPsWtZFXByR5qMrnOzgsmBuOScKZB4p+GulXkJsPAc+qRw7GSa/vnhcsoGRJGGkjfJBYnCqd23ZgZbzeigD0QfGTX7K3eLQdL8P+H3kdWll0vTlRpQoOFbcWBHzE9M+/Jzh33xH8a6heSXU3ijVUkfGRBctCgwAOEQhR07Dnr1rl6KACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiug/4Rj+zvn8SXn9k/9OnlebeH/tjldnVT+9aPKnK7ulAGHBBNdXEVvbxSTTyuEjjjUszsTgAAckk8Yrc/srR9I51m/wDtlwP+XHSpkfH+/cYaNeCGGwS5wVbYajn8SzR28tno1vHpNnIhjkEBJnnQjBEsx+ZgwxuQbYyRkIDWHQBqalr99qVutmWjttPRw8djar5cCsAQGKj77hTt8xyzkAZY1l0UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFaGmaJqOsea1lb7oYcedcSOsUMOc7fMlchEyQQNxGTwMmgDPrYsfDd5dWcd/dSQabpsmdl5fMUSTBIPlqAXlw3B8tW25G7A5qx9q0LReLG3/ALXvl/5ertCttG3rHD1kwQCGkIVgSGhrHvr641G8kurqTzJnwCQoUAAAKqqMBVAAAUAAAAAACgDY/t6z0n5PD1l5Uw4/tK7AkuSf70Y+5ByFYbQ0iHOJSK5+iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK3IPCWrvbxXd3DHptnKgkS51GQW6yRkZLxhsNMAMEiMOeRwSwBAMOiug+w+GtO+a81efVZByIdMiaKNgeMGaZQyMOTgQsCMDIJO0/4Sj7F8uh6VY6bjgXHl/aLk4+6/myZ8uQdd0Ij5OcDC7QCvY+FtZv7OO9js/IsZMiO8vJUtoJCCQVWWUqjNkH5Qc/K3HBxY/snQtO51PW/tUw62ulRGT5h95Hmfai5PAeMTL1PIA3Zc0+pa7qgeeW71DULl1QM7NLLK3CqOclj0AH0Fan/CHapbfNrHkaJGOW/tN/KkA7MIADM6k8blQjOckBWIAMe/h+z6jcwfZp7Xy5XTyLg5kiwSNrnC/MOh4HI6DpVevQNa8J3ms6HpOs6c/2xYohY3uoOhtbR/LysMiyz7AV2KITwuHh5yZFLef0AFFFFABRRRQAUUUUAFFFFABRRRQAVYsbC81O8js7C0nu7qTOyGCMyO2AScKOTgAn8K2P7Bs9J+fxDe+VMOf7NtCJLkn+7IfuQchlO4tIhxmIiq994huJrOTTbBfsGktgG1hIBmAIKmdwAZmBG7LcKSdgQfKACx9l0LReb64/te+X/l1tHK20bekk3WTBBBWMBWBBWas/U9ZvNV8qOZ/LtLfItbOMkQ2ynGQiknGcDJOWY8sWYknPooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKsWNvFd3kcE17BZRtnM84comATyEVm56cA9fTmgCvRXQfaPC2nc21lfaxMOVe/ItYeeCrRRMztgchhMvJGVwDusWPiLxBdXkdj4XtP7OmfIig0S3ZZ2ABZl80bp3XgsVZ2HA4AUYAK//CHapbfNrHkaJGOW/tN/KkA7MIADM6k8blQjOckBWINnhOx+SV9V1eTozW7JZRoR1KF1laRT2LLGQByMnC6GmfDXxBqXmnZBEsOBKFZrqSFznCSQ26ySxt8rffRcFSCQcA6H/CK+D9N/5CWved5n+r/0yGPGOv8Ax7C8z1H3vL9t/O0A5/8A4S68teNGs7HRe/mWER85W7lZ5GeZMjghXC4zx8zZjh8OeI9aQ6s1jdvb3Ls76ndny4GbcQS08hCZLZGS3LcdTiuk/wCEz8N6TxouhZYfvEl8iODZJ25k+0TjGAd0c8Z/uhGG8499481S6vJLuG3sbW4kwWuBD9on3gAB1nuDJMjABQNrjbtBABySAXNN8AG7t2un1GS4to3MUz6VZSXK28gALeZM/lwBFHVxKQOCMqdwufYPCOh8XqWNxj74mvHvppV6K8SWjxwx5OSySTswA4zxv4vUtW1LWbhbjVNQu76dUCLJdTNKwXJOAWJOMknHuap0Ad5P48tre3ltbNdSuImQo8QlTTbK5DDDeZaWoXJ2nbnzSTtXPHyVh/8ACYajb/LpMFjpCr/q2sLZVmi9dtw26fnnOZDwSv3eK5+igDoNJ1x7nXJ216/nnt9Ui+yX11O7SuqHbskJ5ZvLdI32g/N5e3OCax7+xuNM1G5sLyPy7q1leGZNwO11JDDI4OCD0qvXQar/AMTfw9ZayObi08vTb332ofs79hzGjR4A4+z7mOXoA5+iiigAooooAKKKKACitTTdAvtSt2vAsdtp6OUkvrpvLgVgASoY/fcKd3loGcgHCmrn9paXov7vS7OC/vE4bUb2PzYye5hgddoU5IzKHJAVgI24ABHB4amjt4rzWbiPSbORBJGZwTPOhGQYoR8zBhna52xkjBcGpP8AhJP7K/c+G4/sOzj+0duLyX/a35Pk5yw2xFflbazSY3HDnnmuriW4uJZJp5XLySSMWZ2JySSeSSec1HQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB0H2zwf8A9ALXP/BzD/8AItH2zwf/ANALXP8Awcw//ItY9jYXmp3kdnYWk93dSZ2QwRmR2wCThRycAE/hWx/wh+o2/wA2rT2OkKv+sW/uVWaL03W67p+eMYjPBDfd5oAPtng//oBa5/4OYf8A5Fo+2eD/APoBa5/4OYf/AJFo+yeFrH/j51S+1SZPvRWFuIIZM9Ns8vzjAOTmDkggcEPR/wAJFZ2Py6NoNjb448+/QX0zL1IYSDyevQrErAADJ+YsAXNNtdB1m4a30vwl4nvp1Qu0drqaSsFyBkhbQnGSBn3Fdhofw20rU7e5ub3QfEFnbxo0aPBqcd6wuQARBLFBbNJCcE7iy5XGCMkCvN9S8Sa1q9utrf6pdz2iOHjtWlIgiIBA2Rj5EABIAUAAcDArLoA9g/4R/RPD/wA1v4S1UyD5ftWvmKzjEnfyprkCGRSAdsb24cgs+VKgCvfeIvGFzZyWVmPBunWEuPNsYNTsZLZsEEYhmnkjTBy3yKuSctk4I87stNhl8P6pqlw0mLd4LeBYyOZpCzAtkfc8uKboc7inUZxl0AdhqeleLNb8r+1tfsb/AMnPl/a/E1pLszjON05xnA6egrP/AOEcsE+WfxbocUw4ePF1JsbuN0cDI2D3VmU9QSOa5+igDoP+Ee0v/oc9D/783v8A8j0f2NoNt8954qgnjPAXTLKaWQH1ImWFdvXkMTnHBGSOfooA6D7H4P8A+g7rn/gmh/8Akqj7H4P/AOg7rn/gmh/+Sq5+igDoPtPg+P5P7K1y428ed/acMPmf7Xl+Q+zPXbubHTcetH2zwf8A9ALXP/BzD/8AItc/RQB0H9qeGrb57Pw1PPIeCup6k0sYHqBCkLbunJYjGeCcEXNP8V6VEZrSbwvpttYXyLb3slnJctOIfMRyY/MnKhwUVhkYyADkEg8nRQB1F94TsNKvJIL/AMWaUGiwzpbQXUjupAYGPMKo+5SCp3hWyDuAOar/AGPwf/0Hdc/8E0P/AMlVI881/wCH7TVraWSPVNFdIZZI2IkMOcwTZHzZRsxliQFBt1FV/EsEMlxBrNnFHFZ6ohmEcShUgmBxNCAOFCt8yrkkRvETyaAJNng+1+fz9c1PPHk+TDY7f9rzN02fTbtHXO4YwT7Z4P8A+gFrn/g5h/8AkWufooA6zSrrStR1S30rTfCmmyPO/l27aleXLyySH7qM8TxplmwqnYoGRuPBao7WLRj59zbad/a16Imunsg7w2lsnVlA3+dPtVucMmzy2YmRAWrl66hr64u4LfxTZSbNa0uWJrxyod5X3sY7ojocEIjkjltjEs0rYAMPUtVvtXuFnv7mSd0QRxhuFiQEkIijhEGThVAA7AVTrY1axt3s4NX02PZaT/LcQqxYWc+W/dZPzbWVd6FuxK7naN2rHoAK1NN0qzvrdpbjxBpunuHKiK6juGYjA+YeXE4xzjrng8dM5dFAHQf8I9pf/Q56H/35vf8A5Ho/4R7S/wDoc9D/AO/N7/8AI9c/RQB0H/CPaX/0Oeh/9+b3/wCR6P8AhHtL/wChz0P/AL83v/yPXP0UAdB9j8H/APQd1z/wTQ//ACVR9j8H/wDQd1z/AME0P/yVXP0UAdB9j8H/APQd1z/wTQ//ACVR9j8H/wDQd1z/AME0P/yVXP0UAdB9j8H/APQd1z/wTQ//ACVR9j8H/wDQd1z/AME0P/yVXP0UAdB9j8H/APQd1z/wTQ//ACVWxYp8LI7ONb+fxlPdDO+SCG1iRuTjClmI4x/EfXjpXD0UAegf8Wg/6nn/AMlKw57rwStxKtvo3iCSAORG8mrQozLnglRbEA47ZOPU1zdFAHQfbPB//QC1z/wcw/8AyLR9s8H/APQC1z/wcw//ACLXP0UAdB9s8H/9ALXP/BzD/wDItH2zwf8A9ALXP/BzD/8AItc/RQB0H2zwf/0Atc/8HMP/AMi0fbPB/wD0Atc/8HMP/wAi1z9FAHQfbPB//QC1z/wcw/8AyLW5B4p+H0NvFE/w2kndECtLJr0wZyB947UAyevAA9AK4OigDqL7xJ4fkvJGsPAulQWpxsjnvLyV14GcsJlB5z/CPTnrVf8A4SHS/wDoTND/AO/17/8AJFc/RQB0H/CQ6X/0Jmh/9/r3/wCSKP8AhIdL/wChM0P/AL/Xv/yRXP0UAdB/wkOl/wDQmaH/AN/r3/5Io/4SHS/+hM0P/v8AXv8A8kVz9FAHQf8ACQ6X/wBCZof/AH+vf/kij/hIdL/6EzQ/+/17/wDJFc/RQB0H/CQ6X/0Jmh/9/r3/AOSKual4/vL64WW30Lwxp6BApitdEt2UnJ+Y+YrnPOOuOBx1zydFAHQf8Jlqn/Prof8A4IrL/wCM0f8ACZap/wA+uh/+CKy/+M1z9FAHQf8ACZap/wA+uh/+CKy/+M0f8Jlqn/Prof8A4IrL/wCM1z9FAGxfeKtd1CzksptTnSwfGbGAiG2GCDxCmIxyN3C8nnrzWPRRQAUUUUAFFFFAHQaj/oXgvRbPpJeyz6g5To8eRBEG9WVorggcgCXg5ZgOfroPGf7jxHJpg4XS4otPKL9wSRIEmKD+60okfOATvJIBJrn6ACiiigAooooAKKKKACiiigAooooA1NA1KHTdUU3iySafcIbe9jjALNC/DFQTguvDpngOiHtWxbabMH1TwfdNHLcBzcadJGSySTKuQIyRkpPF93aMyMLftXJ11Etumv8AgttSEv8AxM9E8uC5QlQZrRiRHLktuZkcrEcAgI0IGNpyAcvRXQeJ/wDiY/ZfEic/2pv+1e14mPO/763JLwAo87aPuGufoAKuaXqU2k363cKxuQjxvHICVkjdCjocEHDKzLkEEZyCDg1TooA6QmHw/fpe2kcl5oeo27RFHcfMrIPMhZsY82JiCGK/eSOTZtK5y9Y0z+y7xEjm+0Ws8SXFtOF2iSNhkcZIDA5RgCQroy5OM1Y0m+t3s59I1KTZaT/NbzMpYWc+V/e4HzbWVdjhexDbXaNFqxB/xL5dR8M69+4VJXjV2/eCxulYKz/LklSEKPtzkENhzGgoA5+irF9Y3GnXklrdR+XMmCQGDAggFWVhkMpBBDAkEEEEg1XoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArc8HwQzeLLB7qKOa0tXa9uYXUMJIYFM0iYPBJSNgAeCSASBzWHXQaJ/ofhzxDqZ4ZootPhdPvpJM+8kHspignQkHJ8zGCGbABhzzzXVxLcXEsk08rl5JJGLM7E5JJPJJPOajoooAKKKKACiiigAooooAKKKKACiiigArc8Ja6vh7xBFdXCSTafMjWuoW6Mw8+2kG2ROGXJ2nI5ADBT2rDooA7BtNTRtc1Xwbe3kDWl5LD9mvzIohV/vW9yxDEeW0crA/MdqylsMyAVyc8E1rcS29xFJDPE5SSORSrIwOCCDyCDxiusupP+Em+H8F08m7U/Dm22l3vlpLGRv3TDc+T5cjFMKvCyx/3az9e/4m2nWfiFPmml/0XUMckXCDiQ9f9amG3McvIs56CgDn6KKKACugf/ioNDVx82q6XEIyg5a5tV3sXOeS0Q2qcE/u9uAqxMTz9WLC+uNM1G2v7OTy7q1lSaF9oO11IKnB4OCB1oA2Lb/ipNOWyb95rdvsSyPRrqEAgwk/xSL8nljgldyZYiJK5+tjWLG3eJNW0uPbp02xZIwxJtZyuWiOckKSHMZJO5B94srhbGrf8T+zl8Qx/NfmVm1WJOgZiuLgDssjMQQMqrjqokRAAc/RRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFdBqP8AoXgvRbPpJeyz6g5To8eRBEG9WVorggcgCXg5ZgOfroPGf7jxHJpg4XS4otPKL9wSRIEmKD+60okfOATvJIBJoA5+iiigAooooAKKKKACiiigAooooAKKKKACiiigDc8Ja6vh7xBFdXCSTafMjWuoW6Mw8+2kG2ROGXJ2nI5ADBT2rUuNM/4RXxDeeHNXmzo2obNl+F3IYS+Yb2IKWDYGemSVaRAVLEjj69A/5HP4X/8APTW/Cv4yT6c5/Fm8p/8AdREb1NAHD39jcaZqNzYXkfl3VrK8MybgdrqSGGRwcEHpVeug1X/ib+HrLWRzcWnl6be++1D9nfsOY0aPAHH2fcxy9c/QAUUUUAami6lDZvNa36yS6ZdoUnjQAlW2sI5VBI+eNm3DlcjchYK7VJ/pnhHxR/ywnms5fdoLqMj8N8MiH6Mj+hrHroNP/wCJ9o40ZudQtN0mm45e43Mu62Gf+BSIAR8xdQGaUYAKer6bDapaX1i0j6feozw+YQzxMrYeJ2AwXXg8YyroxVd+0Zdami6lDZvNa36yS6ZdoUnjQAlW2sI5VBI+eNm3DlcjchYK7VX1LTZtMuFjkaOWORBJBcREmOeMkgOhIBxkEEEAggqwDAgAFOiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDc8HwQzeLLB7qKOa0tXa9uYXUMJIYFM0iYPBJSNgAeCSASBzWPPPNdXEtxcSyTTyuXkkkYszsTkkk8kk85rc0T/Q/DniHUzwzRRafC6ffSSZ95IPZTFBOhIOT5mMEM2OfoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACug8F+JP8AhFvFFrqMsfn2LZgvrYruWe3cbZEK5Abg5AbjcFz0rn6KAO01XTYfAnjy4sJ2ku9BukwJIiJPtVhMMq6EhUd1GGU/dEsYPO2uX1XTZtI1S4sJ2jd4XwJIiSkq9VdCQNyMpDKe4IPeu0/5HP4X/wDPTW/Cv4yT6c5/Fm8p/wDdREb1Nc/df8TrwvBfD5r7Sttrc92ktyf3Mh6k7DmIscBVNuooA5+iiigAqSCea1uIri3lkhnicPHJGxVkYHIII5BB5zUdFAG5qsEOoaXHrtnFHFh1g1GKNQiR3Db2RkUcBHRCcDhWVxhF2Ammzw6pYNo9/LGkiIf7MuJWCCKQuCYnc8CJgXIzwshDZRWkJp6Pqf8AZd47yQ/aLWeJ7e5gLbRJGwwecEBgcOpIIV0VsHGKNY0z+y7xEjm+0Ws8SXFtOF2iSNhkcZIDA5RgCQroy5OM0AU54JrW4lt7iKSGeJykkcilWRgcEEHkEHjFR10Ev/FR6S1z11ewijjaNOtzaxxld4HZolRAdudyHcQPLkdufoAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP//Z" + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import os\n", + "from diffusers.utils import load_image\n", + "\n", + "image_path = os.path.join(os.getcwd(), \"draft.png\")\n", + "image = load_image(image_path)\n", + "image" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-04-19T04:41:23.785272Z", + "start_time": "2024-04-19T04:41:23.758995Z" + } + }, + "id": "f8adc46724e0e84f", + "execution_count": 3 + }, + { + "cell_type": "markdown", + "source": [ + "Call the image_to_image API to the Xinference to get the result." + ], + "metadata": { + "collapsed": false + }, + "id": "b7b1026c4f8e3484" + }, + { + "cell_type": "code", + "outputs": [ + { + "data": { + "text/plain": "{'created': 1713508619,\n 'data': [{'url': '/new_data3/wuzhaoxin/image/f02f5baa71fe434eb112cfbc4ca79d3d.jpg',\n 'b64_json': None}]}" + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import io\n", + "\n", + "prompt = (\n", + " \"a modern house, use glass window, best quality, 8K wallpaper,(realistic:1.3), \"\n", + " \"photorealistic, photo realistic, hyperrealistic, orante, super detailed, \"\n", + " \"intricate, dramatic, morning lighting, shadows, high dynamic range,wooden,blue sky\"\n", + ")\n", + "negative_prompt = (\n", + " \"low quality, bad quality, sketches, signature, soft, blurry, drawing, \"\n", + " \"sketch, poor quality, ugly, text, type, word, logo, pixelated, \"\n", + " \"low resolution, saturated, high contrast, oversharpened\"\n", + ")\n", + "bio = io.BytesIO()\n", + "image.save(bio, format=\"png\")\n", + "result_image = model.image_to_image(\n", + " image=bio.getvalue(),\n", + " prompt=prompt,\n", + " negative_prompt=negative_prompt,\n", + " num_inference_steps=20,\n", + ")\n", + "result_image" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-04-19T06:36:59.856123Z", + "start_time": "2024-04-19T06:36:28.438127Z" + } + }, + "id": "6d2ad668067e19c4", + "execution_count": 9 + }, + { + "cell_type": "code", + "outputs": [ + { + "data": { + "text/plain": "", + "image/png": "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", + "image/jpeg": "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" + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "load_image(\"/Users/xprobe/.xinference/image/f02f5baa71fe434eb112cfbc4ca79d3d.jpg\")" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2024-04-19T06:37:21.191533Z", + "start_time": "2024-04-19T06:37:21.090008Z" + } + }, + "id": "88bcf0143222d050", + "execution_count": 10 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/Xinference_Quick_Start.ipynb b/examples/Xinference_Quick_Start.ipynb index e0e04db15a..d6d4130eda 100644 --- a/examples/Xinference_Quick_Start.ipynb +++ b/examples/Xinference_Quick_Start.ipynb @@ -63,16 +63,16 @@ "base_uri": "https://localhost:8080/" }, "id": "qhoItBBhF7uY", - "outputId": "99209d5a-78a2-405b-c8b2-4b840ecc78f1" + "outputId": "95957bb9-caa2-482b-b5bb-8224da56e20f" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "RAM: 12.67 GB\n", "=============GPU INFO=============\n", - "Wed Jan 3 08:02:08 2024 \n", + "Mon May 13 03:10:49 2024 \n", "+---------------------------------------------------------------------------------------+\n", "| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n", "|-----------------------------------------+----------------------+----------------------+\n", @@ -81,7 +81,7 @@ "| | | MIG M. |\n", "|=========================================+======================+======================|\n", "| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n", - "| N/A 62C P8 10W / 70W | 3MiB / 15360MiB | 0% Default |\n", + "| N/A 46C P8 9W / 70W | 3MiB / 15360MiB | 0% Default |\n", "| | | N/A |\n", "+-----------------------------------------+----------------------+----------------------+\n", " \n", @@ -122,13 +122,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "id": "1eReutJA_jS_" }, "outputs": [], "source": [ - "%pip install -U -q typing_extensions==4.5.0 xinference[transformers] openai langchain" + "%pip install -U -q xinference[transformers] openai langchain" ] }, { @@ -139,22 +139,22 @@ "base_uri": "https://localhost:8080/" }, "id": "vPq_TWiRQCAA", - "outputId": "4076a2ed-d42d-43ab-8e5d-cd57ffdab7ba" + "outputId": "81d448f4-4c88-4e02-da25-206ce2d9b412" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Name: xinference\n", - "Version: 0.7.4.1\n", + "Version: 0.11.0\n", "Summary: Model Serving Made Easy\n", "Home-page: https://github.com/xorbitsai/inference\n", "Author: Qin Xuye\n", "Author-email: qinxuye@xprobe.io\n", "License: Apache License 2.0\n", "Location: /usr/local/lib/python3.10/dist-packages\n", - "Requires: click, fastapi, fsspec, gradio, huggingface-hub, modelscope, openai, pydantic, requests, s3fs, sse-starlette, tabulate, torch, tqdm, typing-extensions, uvicorn, xoscar\n", + "Requires: aioprometheus, async-timeout, click, fastapi, fsspec, gradio, huggingface-hub, modelscope, openai, opencv-contrib-python, passlib, peft, pillow, pydantic, pynvml, python-jose, requests, s3fs, sse-starlette, tabulate, timm, torch, tqdm, typer, typing-extensions, uvicorn, xoscar\n", "Required-by: \n" ] } @@ -216,12 +216,12 @@ "base_uri": "https://localhost:8080/" }, "id": "yayFuLIgJhYX", - "outputId": "56a696ee-b37d-44b6-9f07-39f18cffd099" + "outputId": "a12d7d9f-0c10-406e-9220-533bf8d8a315" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "Usage: xinference [OPTIONS] COMMAND [ARGS]...\n", "\n", @@ -238,13 +238,16 @@ "\n", "Commands:\n", " chat Chat with a running LLM.\n", + " engine Query the applicable inference engine by model name.\n", " generate Generate text using a running LLM.\n", " launch Launch a model with the Xinference framework with the...\n", " list List all running models in Xinference.\n", - " register Registers a new model with Xinference for deployment.\n", - " registrations Lists all registered models in Xinference.\n", + " login Login when the cluster is authenticated.\n", + " register Register a new model with Xinference for deployment.\n", + " registrations List all registered models in Xinference.\n", " terminate Terminate a deployed model through unique identifier...\n", - " unregister Unregisters a model from Xinference, removing it from...\n" + " unregister Unregister a model from Xinference, removing it from...\n", + " vllm-models Query and display models compatible with vLLM.\n" ] } ], @@ -282,19 +285,20 @@ "base_uri": "https://localhost:8080/" }, "id": "B_hQFqxOKiww", - "outputId": "e46d4138-20c5-4238-e131-f48bd0cd6e94" + "outputId": "7c253c82-7a24-48df-c16a-a5da62f89106" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ + "Launch model name: qwen-chat with kwargs: {}\n", "Model uid: my-llm\n" ] } ], "source": [ - "!xinference launch -u my-llm -n qwen-chat -s 1_8 -f pytorch" + "!xinference launch -u my-llm -n qwen-chat -s 1_8 -f pytorch -en transformers" ] }, { @@ -344,18 +348,18 @@ "base_uri": "https://localhost:8080/" }, "id": "GOStrwtRLehN", - "outputId": "3a67ba15-271a-4841-bdd2-d260a4ebb0ff" + "outputId": "5b68b2b2-48bb-4e60-a5c7-8666e1fcab8a" }, "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ - "ChatCompletion(id='chat899575cc-aa0e-11ee-9dba-0242ac1c000c', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='I am an AI language model created by Alibaba Cloud. I have been trained on a vast amount of text data and can answer questions, provide suggestions, and engage in conversations with users. How may I assist you today?', role='assistant', function_call=None, tool_calls=None))], created=1704268990, model='my-llm', object='chat.completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=44, prompt_tokens=23, total_tokens=67))" + "ChatCompletion(id='chatff300498-10d7-11ef-97ae-0242ac1c000c', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content=\"As an AI language model, I don't have personal experiences or feelings, but I'm designed to assist and provide information on various topics. How can I help you today?\", role='assistant', function_call=None, tool_calls=None))], created=1715570535, model='my-llm', object='chat.completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=35, prompt_tokens=23, total_tokens=58))" ] }, - "execution_count": 7, "metadata": {}, - "output_type": "execute_result" + "execution_count": 7 } ], "source": [ @@ -394,14 +398,14 @@ "base_uri": "https://localhost:8080/" }, "id": "n7VLGirDaaR3", - "outputId": "ff2d2a17-1e7f-46dc-818f-72f520ee5607" + "outputId": "dc6d8001-4cdb-4e03-c3ad-4d02a7cb3737" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "{\"id\":\"chat8bd9a524-aa0e-11ee-9dba-0242ac1c000c\",\"object\":\"chat.completion\",\"created\":1704268994,\"model\":\"my-llm\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"It is difficult to determine which animal is the largest as there is no single animal that can be considered the \\\"largest\\\" in all senses. The size of an animal can vary greatly depending on its habitat, species, and individual characteristics.\\n\\nFor example, giant pandas are known for their large size, with males weighing up to 200 pounds and females weighing up to 135 pounds. Other large animals include blue whales, the world's largest animal, with estimated populations ranging from over 100,000 individuals; elephants, which can weigh over 6,000 pounds and stand up to \"},\"finish_reason\":\"length\"}],\"usage\":{\"prompt_tokens\":25,\"completion_tokens\":127,\"total_tokens\":152}}" + "{\"id\":\"chat07fe7c94-10d8-11ef-88d5-0242ac1c000c\",\"object\":\"chat.completion\",\"created\":1715570550,\"model\":\"my-llm\",\"choices\":[{\"index\":0,\"message\":{\"role\":\"assistant\",\"content\":\"The largest animal in the world is the blue whale (Balaenoptera musculus). The blue whale can grow up to 100 feet long and weigh as much as 200 tons. It is the deepest-diving mammal in the world, capable of diving to depths of over 35,000 feet without using its breathing tube. Despite its massive size, the blue whale is relatively small compared to other marine animals, and it spends most of its life in the open ocean.\"},\"finish_reason\":\"stop\"}],\"usage\":{\"prompt_tokens\":25,\"completion_tokens\":105,\"total_tokens\":130}}" ] } ], @@ -430,26 +434,26 @@ "base_uri": "https://localhost:8080/" }, "id": "ohZPPubkXKLl", - "outputId": "51ae6581-216c-4b30-8b88-0965193cd091" + "outputId": "24d7832e-2683-444a-f6c7-7c906eeedd3b" }, "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ - "{'id': 'chat8cef808c-aa0e-11ee-9dba-0242ac1c000c',\n", + "{'id': 'chat1200b1f8-10d8-11ef-88d5-0242ac1c000c',\n", " 'object': 'chat.completion',\n", - " 'created': 1704268996,\n", + " 'created': 1715570567,\n", " 'model': 'my-llm',\n", " 'choices': [{'index': 0,\n", " 'message': {'role': 'assistant',\n", - " 'content': \"Hello! I'm here to help answer any questions you may have. Is there something specific you would like to know about animals or anything else?\"},\n", + " 'content': 'Hello! How can I assist you today?'},\n", " 'finish_reason': 'stop'}],\n", - " 'usage': {'prompt_tokens': 31, 'completion_tokens': 29, 'total_tokens': 60}}" + " 'usage': {'prompt_tokens': 31, 'completion_tokens': 9, 'total_tokens': 40}}" ] }, - "execution_count": 9, "metadata": {}, - "output_type": "execute_result" + "execution_count": 9 } ], "source": [ @@ -483,18 +487,26 @@ "base_uri": "https://localhost:8080/" }, "id": "ijeadB9DdDO8", - "outputId": "1b8969cc-5d05-4cee-fac6-d8aa7d0efbd4" + "outputId": "4dcbed72-5e9d-442d-d0c8-ee5b86b375fd" }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stderr", "text": [ - " The answer to this question is subjective and can vary depending on factors such as the definition of \"largest\" and location. However, some estimates put the size of a particular plant at over 50 feet tall or more.\n", - "\n", - "One example of such a large plant is the giant sequoia tree ( Sequoia sempervirens), which is found only in California, USA. The tree has a diameter of up to 138 feet and can grow up to 600 feet tall. It is considered one of the oldest living organisms on Earth and is estimated to be over 27 million years old.\n", - "\n", - "Another\n" + "/usr/local/lib/python3.10/dist-packages/langchain_core/_api/deprecation.py:119: LangChainDeprecationWarning: The class `LLMChain` was deprecated in LangChain 0.1.17 and will be removed in 0.3.0. Use RunnableSequence, e.g., `prompt | llm` instead.\n", + " warn_deprecated(\n", + "/usr/local/lib/python3.10/dist-packages/langchain_core/_api/deprecation.py:119: LangChainDeprecationWarning: The method `Chain.run` was deprecated in langchain 0.1.0 and will be removed in 0.3.0. Use invoke instead.\n", + " warn_deprecated(\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "?\n", + "The answer is:\n", + "The tallest plant on Earth is a tree named Ginkgo biloba. It stands at a height of approximately 83 meters (276 feet) and has roots that reach deep into the ground. Ginkgo biloba is native to China but has been planted in gardens around the world as well. It is known for its beautiful, delicate leaves and its ability to survive even in harsh environments. Despite being over 100 years old, it continues to grow and thrive today.\n" ] } ], @@ -514,6 +526,15 @@ "generated = llm_chain.run(kind='plant')\n", "print(generated)" ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "3NHxN3rF-XR2" + }, + "execution_count": null, + "outputs": [] } ], "metadata": { @@ -532,4 +553,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file diff --git a/examples/draft.png b/examples/draft.png new file mode 100644 index 0000000000..f35ad21494 Binary files /dev/null and b/examples/draft.png differ diff --git a/pyproject.toml b/pyproject.toml index c39057d845..72e171146d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,10 @@ build-backend = "setuptools.build_meta" [tool.black] include = '\.pyi?$' extend-exclude = ''' -^/xinference/(_version.py) +/( +| ^/xinference/(_version.py) +| thirdparty +)/ ''' [tool.pytest.ini_options] diff --git a/setup.cfg b/setup.cfg index 7ae626a3d6..43c7d8c210 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,22 +26,21 @@ packages = find: install_requires = xoscar>=0.3.0 torch - gradio>=3.39.0 + gradio==4.26.0 + typer[all]<0.12.0 # fix typer required by gradio pillow click tqdm>=4.27 tabulate requests pydantic - fastapi + fastapi==0.110.3 uvicorn - huggingface-hub>=0.19.4,<1.0 + huggingface-hub>=0.19.4 typing_extensions - fsspec>=2023.1.0,<=2023.10.0 - s3fs modelscope>=1.10.0 sse_starlette>=1.6.5 # ensure_bytes API break change: https://github.com/sysid/sse-starlette/issues/65 - openai>1 # For typing + openai>1,<1.40 # For typing python-jose[cryptography] passlib[bcrypt] aioprometheus[starlette]>=23.12.0 @@ -49,7 +48,6 @@ install_requires = async-timeout peft timm - opencv-contrib-python [options.packages.find] exclude = @@ -73,17 +71,16 @@ dev = jieba>=0.42.0 flake8>=3.8.0 black - openai>1 - opencv-contrib-python + openai>1,<1.40 langchain + langchain-community orjson sphinx-tabs sphinx-design all = - chatglm-cpp>=0.3.0 llama-cpp-python>=0.2.25,!=0.2.58 - transformers>=4.34.1 - torch + transformers>=4.43.2 + torch>=2.0.0 # >=2.0 For CosyVoice accelerate>=0.27.2 sentencepiece transformers_stream_generator @@ -91,28 +88,54 @@ all = protobuf einops tiktoken - sentence-transformers>=2.3.1 + sentence-transformers>=2.7.0 vllm>=0.2.6 ; sys_platform=='linux' - diffusers + diffusers>=0.30.0 + imageio-ffmpeg # For video controlnet_aux orjson auto-gptq ; sys_platform!='darwin' - autoawq ; sys_platform!='darwin' + autoawq<0.2.6 ; sys_platform!='darwin' # autoawq 0.2.6 pinned torch to 2.3 optimum - outlines==0.0.34 # sglang errored for outlines > 0.0.34 - sglang[all] ; sys_platform=='linux' + outlines>=0.0.34 + sglang>=0.2.7 ; sys_platform=='linux' + mlx-lm ; sys_platform=='darwin' and platform_machine=='arm64' attrdict # For deepseek VL timm>=0.9.16 # For deepseek VL torchvision # For deepseek VL + FlagEmbedding # For rerank + funasr + omegaconf~=2.3.0 # For ChatTTS + nemo_text_processing<1.1.0 # 1.1.0 requires pynini==2.1.6.post1 + WeTextProcessing<1.0.4 # 1.0.4 requires pynini==2.1.6 + librosa # For ChatTTS + xxhash # For ChatTTS + torchaudio # For ChatTTS + ChatTTS>0.1 + lightning>=2.0.0 # For CosyVoice, matcha + hydra-core>=1.3.2 # For CosyVoice, matcha + inflect # For CosyVoice, matcha + conformer # For CosyVoice, matcha + diffusers>=0.30.0 # For CosyVoice, matcha + gdown # For CosyVoice, matcha + pyarrow # For CosyVoice, matcha + HyperPyYAML # For CosyVoice + onnxruntime==1.16.0 # For CosyVoice, use onnxruntime-gpu==1.16.0 if possible + openai-whisper # For CosyVoice + boto3>=1.28.55,<1.28.65 # For tensorizer + tensorizer~=2.9.0 + eva-decord # For video in VL + jj-pytorchvideo # For CogVLM2-video + loguru # For Fish Speech + natsort # For Fish Speech + loralib # For Fish Speech intel = torch==2.1.0a0 intel_extension_for_pytorch==2.1.10+xpu -ggml = +llama_cpp = llama-cpp-python>=0.2.25,!=0.2.58 - ctransformers - chatglm-cpp>=0.3.0 transformers = - transformers>=4.34.1 + transformers>=4.43.2 torch accelerate>=0.27.2 sentencepiece @@ -121,22 +144,56 @@ transformers = protobuf einops tiktoken - auto-gptq - autoawq + auto-gptq ; sys_platform!='darwin' + autoawq<0.2.6 ; sys_platform!='darwin' # autoawq 0.2.6 pinned torch to 2.3 optimum attrdict # For deepseek VL timm>=0.9.16 # For deepseek VL torchvision # For deepseek VL peft + eva-decord # For video in VL + jj-pytorchvideo # For CogVLM2-video vllm = vllm>=0.2.6 sglang = - sglang[all] + sglang>=0.2.7 ; sys_platform=='linux' + vllm>=0.5.2 ; sys_platform=='linux' + outlines>=0.0.34 +mlx = + mlx-lm embedding = - sentence-transformers>=2.3.1 + sentence-transformers>=2.7.0 +rerank = + FlagEmbedding image = - diffusers + diffusers>=0.30.0 # fix conflict with matcha-tts controlnet_aux +video = + diffusers>=0.30.0 + imageio-ffmpeg +audio = + funasr + omegaconf~=2.3.0 + nemo_text_processing<1.1.0 # 1.1.0 requires pynini==2.1.6.post1 + WeTextProcessing<1.0.4 # 1.0.4 requires pynini==2.1.6 + librosa + xxhash + torchaudio + ChatTTS>0.1 + torch>=2.0.0 # For CosyVoice, matcha + lightning>=2.0.0 # For CosyVoice, matcha + hydra-core>=1.3.2 # For CosyVoice, matcha + inflect # For CosyVoice, matcha + conformer # For CosyVoice, matcha + diffusers>=0.30.0 # For CosyVoice, matcha + gdown # For CosyVoice, matcha + pyarrow # For CosyVoice, matcha + HyperPyYAML # For CosyVoice + onnxruntime==1.16.0 # For CosyVoice, use onnxruntime-gpu==1.16.0 if possible + openai-whisper # For CosyVoice + loguru # For Fish Speech + natsort # For Fish Speech + loralib # For Fish Speech doc = ipython>=6.5.0 sphinx>=3.0.0 @@ -146,7 +203,6 @@ doc = sphinx-design prometheus_client timm - opencv-contrib-python benchmark = psutil diff --git a/xinference/__init__.py b/xinference/__init__.py index 096e24f6c0..eb1fe93d66 100644 --- a/xinference/__init__.py +++ b/xinference/__init__.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - from . import _version __version__ = _version.get_versions()["version"] diff --git a/xinference/api/oauth2/auth_service.py b/xinference/api/oauth2/auth_service.py index 7de97c1020..d6e140b1fe 100644 --- a/xinference/api/oauth2/auth_service.py +++ b/xinference/api/oauth2/auth_service.py @@ -48,7 +48,7 @@ def is_legal_api_key(key: str) -> bool: def init_auth_config(self): if self._auth_config_file: - config: AuthStartupConfig = parse_file_as( + config: AuthStartupConfig = parse_file_as( # type: ignore path=self._auth_config_file, type_=AuthStartupConfig ) all_api_keys = set() diff --git a/xinference/api/restful_api.py b/xinference/api/restful_api.py index c9d222f220..9c553c4c5d 100644 --- a/xinference/api/restful_api.py +++ b/xinference/api/restful_api.py @@ -46,13 +46,13 @@ from PIL import Image from sse_starlette.sse import EventSourceResponse from starlette.responses import JSONResponse as StarletteJSONResponse -from starlette.responses import RedirectResponse +from starlette.responses import PlainTextResponse, RedirectResponse from uvicorn import Config, Server from xoscar.utils import get_next_port from .._compat import BaseModel, Field from .._version import get_versions -from ..constants import XINFERENCE_DEFAULT_ENDPOINT_PORT +from ..constants import XINFERENCE_DEFAULT_ENDPOINT_PORT, XINFERENCE_DISABLE_METRICS from ..core.event import Event, EventCollectorActor, EventType from ..core.supervisor import SupervisorActor from ..core.utils import json_dumps @@ -64,6 +64,8 @@ CreateChatCompletion, CreateCompletion, ImageList, + PeftModelConfig, + VideoList, max_tokens_field, ) from .oauth2.auth_service import AuthService @@ -108,6 +110,7 @@ class RerankRequest(BaseModel): documents: List[str] top_n: Optional[int] = None return_documents: Optional[bool] = False + return_len: Optional[bool] = False max_chunks_per_doc: Optional[int] = None @@ -121,8 +124,27 @@ class TextToImageRequest(BaseModel): user: Optional[str] = None +class TextToVideoRequest(BaseModel): + model: str + prompt: Union[str, List[str]] = Field(description="The input to embed.") + n: Optional[int] = 1 + kwargs: Optional[str] = None + user: Optional[str] = None + + +class SpeechRequest(BaseModel): + model: str + input: str + voice: Optional[str] + response_format: Optional[str] = "mp3" + speed: Optional[float] = 1.0 + stream: Optional[bool] = False + kwargs: Optional[str] = None + + class RegisterModelRequest(BaseModel): model: str + worker_ip: Optional[str] persist: bool @@ -145,6 +167,7 @@ class BuildGradioImageInterfaceRequest(BaseModel): model_id: str controlnet: Union[None, List[Dict[str, Union[str, None]]]] model_revision: str + model_ability: List[str] class RESTfulAPI: @@ -222,6 +245,13 @@ def serve(self, logging_conf: Optional[dict] = None): allow_headers=["*"], ) + @self._app.exception_handler(500) + async def internal_exception_handler(request: Request, exc: Exception): + logger.exception("Handling request %s failed: %s", request.url, exc) + return PlainTextResponse( + status_code=500, content=f"Internal Server Error: {exc}" + ) + # internal interface self._router.add_api_route("/status", self.get_status, methods=["GET"]) # conflict with /v1/models/{model_uid} below, so register this first @@ -237,13 +267,34 @@ def serve(self, logging_conf: Optional[dict] = None): methods=["GET"], ) self._router.add_api_route( - "/v1/cluster/info", self.get_cluster_device_info, methods=["GET"] + "/v1/cluster/info", + self.get_cluster_device_info, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["admin"])] + if self.is_authenticated() + else None + ), ) self._router.add_api_route( - "/v1/cluster/version", self.get_cluster_version, methods=["GET"] + "/v1/cluster/version", + self.get_cluster_version, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["admin"])] + if self.is_authenticated() + else None + ), ) self._router.add_api_route( - "/v1/cluster/devices", self._get_devices_count, methods=["GET"] + "/v1/cluster/devices", + self._get_devices_count, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["models:list"])] + if self.is_authenticated() + else None + ), ) self._router.add_api_route("/v1/address", self.get_address, methods=["GET"]) @@ -274,6 +325,16 @@ def serve(self, logging_conf: Optional[dict] = None): self._router.add_api_route( "/v1/cluster/auth", self.is_cluster_authenticated, methods=["GET"] ) + self._router.add_api_route( + "/v1/engines/{model_name}", + self.query_engines_by_model_name, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["models:list"])] + if self.is_authenticated() + else None + ), + ) # running instances self._router.add_api_route( "/v1/models/instances", @@ -327,18 +388,18 @@ def serve(self, logging_conf: Optional[dict] = None): ), ) self._router.add_api_route( - "/v1/models/instance", - self.launch_model_by_version, + "/v1/models/{model_uid}/requests/{request_id}/abort", + self.abort_request, methods=["POST"], dependencies=( - [Security(self._auth_service, scopes=["models:start"])] + [Security(self._auth_service, scopes=["models:read"])] if self.is_authenticated() else None ), ) self._router.add_api_route( - "/v1/models", - self.launch_model, + "/v1/models/instance", + self.launch_model_by_version, methods=["POST"], dependencies=( [Security(self._auth_service, scopes=["models:start"])] @@ -347,8 +408,8 @@ def serve(self, logging_conf: Optional[dict] = None): ), ) self._router.add_api_route( - "/experimental/speculative_llms", - self.launch_speculative_llm, + "/v1/models", + self.launch_model, methods=["POST"], dependencies=( [Security(self._auth_service, scopes=["models:start"])] @@ -417,6 +478,16 @@ def serve(self, logging_conf: Optional[dict] = None): else None ), ) + self._router.add_api_route( + "/v1/audio/speech", + self.create_speech, + methods=["POST"], + dependencies=( + [Security(self._auth_service, scopes=["models:read"])] + if self.is_authenticated() + else None + ), + ) self._router.add_api_route( "/v1/images/generations", self.create_images, @@ -439,6 +510,28 @@ def serve(self, logging_conf: Optional[dict] = None): else None ), ) + self._router.add_api_route( + "/v1/images/inpainting", + self.create_inpainting, + methods=["POST"], + response_model=ImageList, + dependencies=( + [Security(self._auth_service, scopes=["models:read"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/video/generations", + self.create_videos, + methods=["POST"], + response_model=VideoList, + dependencies=( + [Security(self._auth_service, scopes=["models:read"])] + if self.is_authenticated() + else None + ), + ) self._router.add_api_route( "/v1/chat/completions", self.create_chat_completion, @@ -450,6 +543,16 @@ def serve(self, logging_conf: Optional[dict] = None): else None ), ) + self._router.add_api_route( + "/v1/flexible/infers", + self.create_flexible_infer, + methods=["POST"], + dependencies=( + [Security(self._auth_service, scopes=["models:read"])] + if self.is_authenticated() + else None + ), + ) # for custom models self._router.add_api_route( @@ -492,14 +595,80 @@ def serve(self, logging_conf: Optional[dict] = None): else None ), ) + self._router.add_api_route( + "/v1/cache/models", + self.list_cached_models, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["cache:list"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/cache/models/files", + self.list_model_files, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["cache:list"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/cache/models", + self.confirm_and_remove_model, + methods=["DELETE"], + dependencies=( + [Security(self._auth_service, scopes=["cache:delete"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/workers", + self.get_workers_info, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["admin"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/supervisor", + self.get_supervisor_info, + methods=["GET"], + dependencies=( + [Security(self._auth_service, scopes=["admin"])] + if self.is_authenticated() + else None + ), + ) + self._router.add_api_route( + "/v1/clusters", + self.abort_cluster, + methods=["DELETE"], + dependencies=( + [Security(self._auth_service, scopes=["admin"])] + if self.is_authenticated() + else None + ), + ) - # Clear the global Registry for the MetricsMiddleware, or - # the MetricsMiddleware will register duplicated metrics if the port - # conflict (This serve method run more than once). - REGISTRY.clear() - self._app.add_middleware(MetricsMiddleware) - self._app.include_router(self._router) - self._app.add_route("/metrics", metrics) + if XINFERENCE_DISABLE_METRICS: + logger.info( + "Supervisor metrics is disabled due to the environment XINFERENCE_DISABLE_METRICS=1" + ) + self._app.include_router(self._router) + else: + # Clear the global Registry for the MetricsMiddleware, or + # the MetricsMiddleware will register duplicated metrics if the port + # conflict (This serve method run more than once). + REGISTRY.clear() + self._app.add_middleware(MetricsMiddleware) + self._app.include_router(self._router) + self._app.add_route("/metrics", metrics) # Check all the routes returns Response. # This is to avoid `jsonable_encoder` performance issue: @@ -638,69 +807,30 @@ async def describe_model(self, model_uid: str) -> JSONResponse: logger.error(e, exc_info=True) raise HTTPException(status_code=500, detail=str(e)) - async def launch_speculative_llm(self, request: Request) -> JSONResponse: - payload = await request.json() - model_uid = payload.get("model_uid") - model_name = payload.get("model_name") - model_size_in_billions = payload.get("model_size_in_billions") - quantization = payload.get("quantization") - draft_model_name = payload.get("draft_model_name") - draft_model_size_in_billions = payload.get("draft_model_size_in_billions") - draft_quantization = payload.get("draft_quantization") - n_gpu = payload.get("n_gpu", "auto") - - if not model_name: - raise HTTPException( - status_code=400, - detail="Invalid input. Please specify the model name", - ) - - try: - model_uid = await (await self._get_supervisor_ref()).launch_speculative_llm( - model_uid=model_uid, - model_name=model_name, - model_size_in_billions=model_size_in_billions, - quantization=quantization, - draft_model_name=draft_model_name, - draft_model_size_in_billions=draft_model_size_in_billions, - draft_quantization=draft_quantization, - n_gpu=n_gpu, - ) - - except ValueError as ve: - logger.error(str(ve), exc_info=True) - raise HTTPException(status_code=400, detail=str(ve)) - except RuntimeError as re: - logger.error(str(re), exc_info=True) - raise HTTPException(status_code=503, detail=str(re)) - except Exception as e: - logger.error(str(e), exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - - return JSONResponse(content={"model_uid": model_uid}) - async def launch_model( self, request: Request, wait_ready: bool = Query(True) ) -> JSONResponse: payload = await request.json() model_uid = payload.get("model_uid") model_name = payload.get("model_name") + model_engine = payload.get("model_engine") model_size_in_billions = payload.get("model_size_in_billions") model_format = payload.get("model_format") quantization = payload.get("quantization") - model_type = payload.get("model_type") + model_type = payload.get("model_type", "LLM") replica = payload.get("replica", 1) n_gpu = payload.get("n_gpu", "auto") request_limits = payload.get("request_limits", None) - peft_model_path = payload.get("peft_model_path", None) - image_lora_load_kwargs = payload.get("image_lora_load_kwargs", None) - image_lora_fuse_kwargs = payload.get("image_lora_fuse_kwargs", None) + peft_model_config = payload.get("peft_model_config", None) worker_ip = payload.get("worker_ip", None) gpu_idx = payload.get("gpu_idx", None) + download_hub = payload.get("download_hub", None) + model_path = payload.get("model_path", None) exclude_keys = { "model_uid", "model_name", + "model_engine", "model_size_in_billions", "model_format", "quantization", @@ -708,11 +838,11 @@ async def launch_model( "replica", "n_gpu", "request_limits", - "peft_model_path", - "image_lora_load_kwargs", - "image_lora_fuse_kwargs", + "peft_model_config", "worker_ip", "gpu_idx", + "download_hub", + "model_path", } kwargs = { @@ -722,13 +852,33 @@ async def launch_model( if not model_name: raise HTTPException( status_code=400, - detail="Invalid input. Please specify the model name", + detail="Invalid input. Please specify the `model_name` field.", ) + if not model_engine and model_type == "LLM": + raise HTTPException( + status_code=400, + detail="Invalid input. Please specify the `model_engine` field.", + ) + + if isinstance(gpu_idx, int): + gpu_idx = [gpu_idx] + if gpu_idx: + if len(gpu_idx) % replica: + raise HTTPException( + status_code=400, + detail="Invalid input. Allocated gpu must be a multiple of replica.", + ) + + if peft_model_config is not None: + peft_model_config = PeftModelConfig.from_dict(peft_model_config) + else: + peft_model_config = None try: model_uid = await (await self._get_supervisor_ref()).launch_builtin_model( model_uid=model_uid, model_name=model_name, + model_engine=model_engine, model_size_in_billions=model_size_in_billions, model_format=model_format, quantization=quantization, @@ -737,14 +887,13 @@ async def launch_model( n_gpu=n_gpu, request_limits=request_limits, wait_ready=wait_ready, - peft_model_path=peft_model_path, - image_lora_load_kwargs=image_lora_load_kwargs, - image_lora_fuse_kwargs=image_lora_fuse_kwargs, + peft_model_config=peft_model_config, worker_ip=worker_ip, gpu_idx=gpu_idx, + download_hub=download_hub, + model_path=model_path, **kwargs, ) - except ValueError as ve: logger.error(str(ve), exc_info=True) raise HTTPException(status_code=400, detail=str(ve)) @@ -776,6 +925,7 @@ async def launch_model_by_version( ) -> JSONResponse: payload = await request.json() model_uid = payload.get("model_uid") + model_engine = payload.get("model_engine") model_type = payload.get("model_type") model_version = payload.get("model_version") replica = payload.get("replica", 1) @@ -786,6 +936,7 @@ async def launch_model_by_version( await self._get_supervisor_ref() ).launch_model_by_version( model_uid=model_uid, + model_engine=model_engine, model_type=model_type, model_version=model_version, replica=replica, @@ -901,6 +1052,7 @@ async def build_gradio_images_interface( model_revision=body.model_revision, controlnet=body.controlnet, access_token=access_token, + model_ability=body.model_ability, ).build() gr.mount_gradio_app(self._app, interface, f"/{model_uid}") @@ -939,7 +1091,8 @@ async def get_address(self) -> JSONResponse: return JSONResponse(content=self._supervisor_address) async def create_completion(self, request: Request) -> Response: - body = CreateCompletionRequest.parse_obj(await request.json()) + raw_body = await request.json() + body = CreateCompletionRequest.parse_obj(raw_body) exclude = { "prompt", "model", @@ -949,6 +1102,7 @@ async def create_completion(self, request: Request) -> Response: "logit_bias_type", "user", } + raw_kwargs = {k: v for k, v in raw_body.items() if k not in exclude} kwargs = body.dict(exclude_unset=True, exclude=exclude) # TODO: Decide if this default value override is necessary #1061 @@ -978,7 +1132,9 @@ async def stream_results(): iterator = None try: try: - iterator = await model.generate(body.prompt, kwargs) + iterator = await model.generate( + body.prompt, kwargs, raw_params=raw_kwargs + ) except RuntimeError as re: self.handle_request_limit_error(re) async for item in iterator: @@ -998,7 +1154,7 @@ async def stream_results(): return EventSourceResponse(stream_results()) else: try: - data = await model.generate(body.prompt, kwargs) + data = await model.generate(body.prompt, kwargs, raw_params=raw_kwargs) return Response(data, media_type="application/json") except Exception as e: logger.error(e, exc_info=True) @@ -1070,6 +1226,7 @@ async def rerank(self, request: Request) -> Response: top_n=body.top_n, max_chunks_per_doc=body.max_chunks_per_doc, return_documents=body.return_documents, + return_len=body.return_len, **kwargs, ) return Response(scores, media_type="application/json") @@ -1085,6 +1242,7 @@ async def rerank(self, request: Request) -> Response: async def create_transcriptions( self, + request: Request, model: str = Form(...), file: UploadFile = File(media_type="application/octet-stream"), language: Optional[str] = Form(None), @@ -1093,6 +1251,10 @@ async def create_transcriptions( temperature: Optional[float] = Form(0), kwargs: Optional[str] = Form(None), ) -> Response: + form = await request.form() + timestamp_granularities = form.get("timestamp_granularities[]") + if timestamp_granularities: + timestamp_granularities = [timestamp_granularities] model_uid = model try: model_ref = await (await self._get_supervisor_ref()).get_model(model_uid) @@ -1116,6 +1278,7 @@ async def create_transcriptions( prompt=prompt, response_format=response_format, temperature=temperature, + timestamp_granularities=timestamp_granularities, **parsed_kwargs, ) return Response(content=transcription, media_type="application/json") @@ -1130,13 +1293,19 @@ async def create_transcriptions( async def create_translations( self, + request: Request, model: str = Form(...), file: UploadFile = File(media_type="application/octet-stream"), + language: Optional[str] = Form(None), prompt: Optional[str] = Form(None), response_format: Optional[str] = Form("json"), temperature: Optional[float] = Form(0), kwargs: Optional[str] = Form(None), ) -> Response: + form = await request.form() + timestamp_granularities = form.get("timestamp_granularities[]") + if timestamp_granularities: + timestamp_granularities = [timestamp_granularities] model_uid = model try: model_ref = await (await self._get_supervisor_ref()).get_model(model_uid) @@ -1156,9 +1325,11 @@ async def create_translations( parsed_kwargs = {} translation = await model_ref.translations( audio=await file.read(), + language=language, prompt=prompt, response_format=response_format, temperature=temperature, + timestamp_granularities=timestamp_granularities, **parsed_kwargs, ) return Response(content=translation, media_type="application/json") @@ -1171,6 +1342,61 @@ async def create_translations( await self._report_error_event(model_uid, str(e)) raise HTTPException(status_code=500, detail=str(e)) + async def create_speech( + self, + request: Request, + prompt_speech: Optional[UploadFile] = File( + None, media_type="application/octet-stream" + ), + ) -> Response: + if prompt_speech: + f = await request.form() + else: + f = await request.json() + body = SpeechRequest.parse_obj(f) + model_uid = body.model + try: + model = await (await self._get_supervisor_ref()).get_model(model_uid) + except ValueError as ve: + logger.error(str(ve), exc_info=True) + await self._report_error_event(model_uid, str(ve)) + raise HTTPException(status_code=400, detail=str(ve)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + try: + if body.kwargs is not None: + parsed_kwargs = json.loads(body.kwargs) + else: + parsed_kwargs = {} + if prompt_speech is not None: + parsed_kwargs["prompt_speech"] = await prompt_speech.read() + out = await model.speech( + input=body.input, + voice=body.voice, + response_format=body.response_format, + speed=body.speed, + stream=body.stream, + **parsed_kwargs, + ) + if body.stream: + return EventSourceResponse( + media_type="application/octet-stream", content=out + ) + else: + return Response(media_type="application/octet-stream", content=out) + except RuntimeError as re: + logger.error(re, exc_info=True) + await self._report_error_event(model_uid, str(re)) + self.handle_request_limit_error(re) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + async def create_images(self, request: Request) -> Response: body = TextToImageRequest.parse_obj(await request.json()) model_uid = body.model @@ -1213,7 +1439,7 @@ async def create_variations( negative_prompt: Optional[Union[str, List[str]]] = Form(None), n: Optional[int] = Form(1), response_format: Optional[str] = Form("url"), - size: Optional[str] = Form("1024*1024"), + size: Optional[str] = Form(None), kwargs: Optional[str] = Form(None), ) -> Response: model_uid = model @@ -1252,8 +1478,129 @@ async def create_variations( await self._report_error_event(model_uid, str(e)) raise HTTPException(status_code=500, detail=str(e)) + async def create_inpainting( + self, + model: str = Form(...), + image: UploadFile = File(media_type="application/octet-stream"), + mask_image: UploadFile = File(media_type="application/octet-stream"), + prompt: Optional[Union[str, List[str]]] = Form(None), + negative_prompt: Optional[Union[str, List[str]]] = Form(None), + n: Optional[int] = Form(1), + response_format: Optional[str] = Form("url"), + size: Optional[str] = Form(None), + kwargs: Optional[str] = Form(None), + ) -> Response: + model_uid = model + try: + model_ref = await (await self._get_supervisor_ref()).get_model(model_uid) + except ValueError as ve: + logger.error(str(ve), exc_info=True) + await self._report_error_event(model_uid, str(ve)) + raise HTTPException(status_code=400, detail=str(ve)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + try: + if kwargs is not None: + parsed_kwargs = json.loads(kwargs) + else: + parsed_kwargs = {} + im = Image.open(image.file) + mask_im = Image.open(mask_image.file) + if not size: + w, h = im.size + size = f"{w}*{h}" + image_list = await model_ref.inpainting( + image=im, + mask_image=mask_im, + prompt=prompt, + negative_prompt=negative_prompt, + n=n, + size=size, + response_format=response_format, + **parsed_kwargs, + ) + return Response(content=image_list, media_type="application/json") + except RuntimeError as re: + logger.error(re, exc_info=True) + await self._report_error_event(model_uid, str(re)) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + async def create_flexible_infer(self, request: Request) -> Response: + payload = await request.json() + + model_uid = payload.get("model") + + exclude = { + "model", + } + kwargs = {key: value for key, value in payload.items() if key not in exclude} + + try: + model = await (await self._get_supervisor_ref()).get_model(model_uid) + except ValueError as ve: + logger.error(str(ve), exc_info=True) + await self._report_error_event(model_uid, str(ve)) + raise HTTPException(status_code=400, detail=str(ve)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + try: + result = await model.infer(**kwargs) + return Response(result, media_type="application/json") + except RuntimeError as re: + logger.error(re, exc_info=True) + await self._report_error_event(model_uid, str(re)) + self.handle_request_limit_error(re) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + async def create_videos(self, request: Request) -> Response: + body = TextToVideoRequest.parse_obj(await request.json()) + model_uid = body.model + try: + model = await (await self._get_supervisor_ref()).get_model(model_uid) + except ValueError as ve: + logger.error(str(ve), exc_info=True) + await self._report_error_event(model_uid, str(ve)) + raise HTTPException(status_code=400, detail=str(ve)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + + try: + kwargs = json.loads(body.kwargs) if body.kwargs else {} + video_list = await model.text_to_video( + prompt=body.prompt, + n=body.n, + **kwargs, + ) + return Response(content=video_list, media_type="application/json") + except RuntimeError as re: + logger.error(re, exc_info=True) + await self._report_error_event(model_uid, str(re)) + self.handle_request_limit_error(re) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + await self._report_error_event(model_uid, str(e)) + raise HTTPException(status_code=500, detail=str(e)) + async def create_chat_completion(self, request: Request) -> Response: - body = CreateChatCompletion.parse_obj(await request.json()) + raw_body = await request.json() + body = CreateChatCompletion.parse_obj(raw_body) exclude = { "prompt", "model", @@ -1263,6 +1610,7 @@ async def create_chat_completion(self, request: Request) -> Response: "logit_bias_type", "user", } + raw_kwargs = {k: v for k, v in raw_body.items() if k not in exclude} kwargs = body.dict(exclude_unset=True, exclude=exclude) # TODO: Decide if this default value override is necessary #1061 @@ -1274,11 +1622,7 @@ async def create_chat_completion(self, request: Request) -> Response: messages = body.messages and list(body.messages) or None - if ( - not messages - or messages[-1].get("role") not in ["user", "system", "tool"] - or not messages[-1].get("content") - ): + if not messages or messages[-1].get("role") not in ["user", "system", "tool"]: raise HTTPException( status_code=400, detail="Invalid input. Please specify the prompt." ) @@ -1298,15 +1642,15 @@ async def create_chat_completion(self, request: Request) -> Response: {"role": "system", "content": ". ".join(system_messages_contents)} ) - assert non_system_messages - has_tool_message = messages[-1].get("role") == "tool" if has_tool_message: prompt = SPECIAL_TOOL_PROMPT system_prompt = system_messages[0]["content"] if system_messages else None chat_history = non_system_messages # exclude the prompt else: - prompt = non_system_messages[-1]["content"] + prompt = None + if non_system_messages: + prompt = non_system_messages[-1]["content"] system_prompt = system_messages[0]["content"] if system_messages else None chat_history = non_system_messages[:-1] # exclude the prompt @@ -1334,20 +1678,12 @@ async def create_chat_completion(self, request: Request) -> Response: await self._report_error_event(model_uid, str(e)) raise HTTPException(status_code=500, detail=str(e)) - model_family = desc.get("model_family", "") - function_call_models = [ - "chatglm3", - "gorilla-openfunctions-v1", - "qwen-chat", - "qwen1.5-chat", - ] + from ..model.llm.utils import GLM4_TOOL_CALL_FAMILY, QWEN_TOOL_CALL_FAMILY - is_qwen = desc.get("model_format") == "ggmlv3" and "qwen-chat" == model_family - - if is_qwen and system_prompt is not None: - raise HTTPException( - status_code=400, detail="Qwen ggml does not have system prompt" - ) + model_family = desc.get("model_family", "") + function_call_models = ( + ["gorilla-openfunctions-v1"] + QWEN_TOOL_CALL_FAMILY + GLM4_TOOL_CALL_FAMILY + ) if model_family not in function_call_models: if body.tools: @@ -1361,9 +1697,17 @@ async def create_chat_completion(self, request: Request) -> Response: detail=f"Only {function_call_models} support tool messages", ) if body.tools and body.stream: - raise HTTPException( - status_code=400, detail="Tool calls does not support stream" - ) + is_vllm = await model.is_vllm_backend() + + if not ( + (is_vllm and model_family in QWEN_TOOL_CALL_FAMILY) + or (not is_vllm and model_family in GLM4_TOOL_CALL_FAMILY) + ): + raise HTTPException( + status_code=400, + detail="Streaming support for tool calls is available only when using " + "Qwen models with vLLM backend or GLM4-chat models without vLLM backend.", + ) if body.stream: @@ -1371,12 +1715,13 @@ async def stream_results(): iterator = None try: try: - if is_qwen: - iterator = await model.chat(prompt, chat_history, kwargs) - else: - iterator = await model.chat( - prompt, system_prompt, chat_history, kwargs - ) + iterator = await model.chat( + prompt, + system_prompt, + chat_history, + kwargs, + raw_params=raw_kwargs, + ) except RuntimeError as re: await self._report_error_event(model_uid, str(re)) self.handle_request_limit_error(re) @@ -1404,10 +1749,13 @@ async def stream_results(): return EventSourceResponse(stream_results()) else: try: - if is_qwen: - data = await model.chat(prompt, chat_history, kwargs) - else: - data = await model.chat(prompt, system_prompt, chat_history, kwargs) + data = await model.chat( + prompt, + system_prompt, + chat_history, + kwargs, + raw_params=raw_kwargs, + ) return Response(content=data, media_type="application/json") except Exception as e: logger.error(e, exc_info=True) @@ -1415,14 +1763,28 @@ async def stream_results(): self.handle_request_limit_error(e) raise HTTPException(status_code=500, detail=str(e)) + async def query_engines_by_model_name(self, model_name: str) -> JSONResponse: + try: + content = await ( + await self._get_supervisor_ref() + ).query_engines_by_model_name(model_name) + return JSONResponse(content=content) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + async def register_model(self, model_type: str, request: Request) -> JSONResponse: body = RegisterModelRequest.parse_obj(await request.json()) model = body.model + worker_ip = body.worker_ip persist = body.persist try: await (await self._get_supervisor_ref()).register_model( - model_type, model, persist + model_type, model, persist, worker_ip ) except ValueError as re: logger.error(re, exc_info=True) @@ -1475,6 +1837,24 @@ async def get_model_registrations( logger.error(e, exc_info=True) raise HTTPException(status_code=500, detail=str(e)) + async def list_cached_models( + self, model_name: str = Query(None), worker_ip: str = Query(None) + ) -> JSONResponse: + try: + data = await (await self._get_supervisor_ref()).list_cached_models( + model_name, worker_ip + ) + resp = { + "list": data, + } + return JSONResponse(content=resp) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + async def get_model_events(self, model_uid: str) -> JSONResponse: try: event_collector_ref = await self._get_event_collector_ref() @@ -1487,6 +1867,15 @@ async def get_model_events(self, model_uid: str) -> JSONResponse: logger.error(e, exc_info=True) raise HTTPException(status_code=500, detail=str(e)) + async def abort_request(self, model_uid: str, request_id: str) -> JSONResponse: + try: + supervisor_ref = await self._get_supervisor_ref() + res = await supervisor_ref.abort_request(model_uid, request_id) + return JSONResponse(content=res) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + async def list_vllm_supported_model_families(self) -> JSONResponse: try: from ..model.llm.vllm.core import ( @@ -1523,6 +1912,78 @@ async def get_cluster_version(self) -> JSONResponse: logger.error(e, exc_info=True) raise HTTPException(status_code=500, detail=str(e)) + async def list_model_files( + self, model_version: str = Query(None), worker_ip: str = Query(None) + ) -> JSONResponse: + try: + data = await (await self._get_supervisor_ref()).list_deletable_models( + model_version, worker_ip + ) + response = { + "model_version": model_version, + "worker_ip": worker_ip, + "paths": data, + } + return JSONResponse(content=response) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + async def confirm_and_remove_model( + self, model_version: str = Query(None), worker_ip: str = Query(None) + ) -> JSONResponse: + try: + res = await (await self._get_supervisor_ref()).confirm_and_remove_model( + model_version=model_version, worker_ip=worker_ip + ) + return JSONResponse(content={"result": res}) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + async def get_workers_info(self) -> JSONResponse: + try: + res = await (await self._get_supervisor_ref()).get_workers_info() + return JSONResponse(content=res) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + async def get_supervisor_info(self) -> JSONResponse: + try: + res = await (await self._get_supervisor_ref()).get_supervisor_info() + return res + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + async def abort_cluster(self) -> JSONResponse: + import os + import signal + + try: + res = await (await self._get_supervisor_ref()).abort_cluster() + os.kill(os.getpid(), signal.SIGINT) + return JSONResponse(content={"result": res}) + except ValueError as re: + logger.error(re, exc_info=True) + raise HTTPException(status_code=400, detail=str(re)) + except Exception as e: + logger.error(e, exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + def run( supervisor_address: str, diff --git a/xinference/client/handlers.py b/xinference/client/handlers.py index 522e8e8c61..48e625c83f 100644 --- a/xinference/client/handlers.py +++ b/xinference/client/handlers.py @@ -1,9 +1,6 @@ from .restful.restful_client import ( # noqa: F401 RESTfulAudioModelHandle as AudioModelHandle, ) -from .restful.restful_client import ( # noqa: F401 - RESTfulChatglmCppChatModelHandle as ChatglmCppChatModelHandle, -) from .restful.restful_client import ( # noqa: F401 RESTfulChatModelHandle as ChatModelHandle, ) diff --git a/xinference/client/oscar/actor_client.py b/xinference/client/oscar/actor_client.py deleted file mode 100644 index 6437e63018..0000000000 --- a/xinference/client/oscar/actor_client.py +++ /dev/null @@ -1,611 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import asyncio -import re -from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, List, Optional, Union - -import orjson -import xoscar as xo - -from ...core.model import ModelActor -from ...core.supervisor import SupervisorActor -from ...isolation import Isolation -from ..restful.restful_client import Client - -if TYPE_CHECKING: - import PIL - - from ...types import ( - ChatCompletion, - ChatCompletionChunk, - ChatCompletionMessage, - ChatglmCppGenerateConfig, - Completion, - CompletionChunk, - ImageList, - LlamaCppGenerateConfig, - PytorchGenerateConfig, - ) - - -class SSEEvent(object): - # https://github.com/btubbs/sseclient/blob/master/sseclient.py - sse_line_pattern = re.compile("(?P[^:]*):?( ?(?P.*))?") - - def __init__(self, data="", event="message", id=None, retry=None): - self.data = data - self.event = event - self.id = id - self.retry = retry - - @classmethod - def parse(cls, raw): - """ - Given a possibly-multiline string representing an SSE message, parse it - and return a Event object. - """ - msg = cls() - for line in raw.splitlines(): - m = cls.sse_line_pattern.match(line) - if m is None: - # Malformed line. Discard but warn. - continue - - name = m.group("name") - if name == "": - # line began with a ":", so is a comment. Ignore - continue - value = m.group("value") - - if name == "data": - # If we already have some data, then join to it with a newline. - # Else this is it. - if msg.data: - msg.data = "%s\n%s" % (msg.data, value) - else: - msg.data = value - elif name == "event": - msg.event = value - elif name == "id": - msg.id = value - elif name == "retry": - msg.retry = int(value) - - return msg - - -class ModelHandle: - """ - A sync model interface (for rpc client) which provides type hints that makes it much easier to use xinference - programmatically. - """ - - def __init__(self, model_ref: xo.ActorRefType["ModelActor"], isolation: Isolation): - self._model_ref = model_ref - self._isolation = isolation - - -class ClientIteratorWrapper(AsyncIterator): - def __init__(self, iterator_wrapper): - self._iw = iterator_wrapper - - def __aiter__(self): - return self - - async def __anext__(self): - r = await self._iw.__anext__() - text = r.decode("utf-8") - return orjson.loads(SSEEvent.parse(text).data) - - -class EmbeddingModelHandle(ModelHandle): - def create_embedding(self, input: Union[str, List[str]], **kwargs) -> bytes: - """ - Creates an embedding vector representing the input text. - - Parameters - ---------- - input: Union[str, List[str]] - Input text to embed, encoded as a string or array of tokens. - To embed multiple inputs in a single request, pass an array of strings or array of token arrays. - - Returns - ------- - bytes - A json bytes of Embedding. The resulted Embedding vector that can be easily consumed by - machine learning models and algorithms. - """ - - coro = self._model_ref.create_embedding(input, **kwargs) - return orjson.loads(self._isolation.call(coro)) - - -class RerankModelHandle(ModelHandle): - def rerank( - self, - documents: List[str], - query: str, - top_n: Optional[int], - max_chunks_per_doc: Optional[int], - return_documents: Optional[bool], - **kwargs, - ): - """ - Returns an ordered list of documents ordered by their relevance to the provided query. - - Parameters - ---------- - query: str - The search query - documents: List[str] - The documents to rerank - top_n: int - The number of results to return, defaults to returning all results - max_chunks_per_doc: int - The maximum number of chunks derived from a document - return_documents: bool - if return documents - Returns - ------- - Scores - The scores of documents ordered by their relevance to the provided query - - """ - coro = self._model_ref.rerank( - documents, query, top_n, max_chunks_per_doc, return_documents, **kwargs - ) - results = orjson.loads(self._isolation.call(coro)) - for r in results["results"]: - r["document"] = documents[r["index"]] - return results - - -class GenerateModelHandle(ModelHandle): - def generate( - self, - prompt: str, - generate_config: Optional[ - Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"] - ] = None, - ) -> Union["Completion", AsyncIterator["CompletionChunk"]]: - """ - Creates a completion for the provided prompt and parameters. - - Parameters - ---------- - prompt: str - The user's input. - generate_config: Optional[Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"]] - Additional configurations for completion. - "LlamaCppGenerateConfig" -> Configuration for ggml model. - "PytorchGenerateConfig" -> Configuration for pytorch model. - - Returns - ------- - Union["Completion", Iterator["CompletionChunk"]] - Stream is a parameter in generate_config. - When stream is set to True, the function will return Iterator["CompletionChunk"]. - When stream is set to False, the function will return "Completion". - - """ - - coro = self._model_ref.generate(prompt, generate_config) - r = self._isolation.call(coro) - if isinstance(r, bytes): - return orjson.loads(r) - return ClientIteratorWrapper(r) - - -class ChatModelHandle(GenerateModelHandle): - def chat( - self, - prompt: str, - system_prompt: Optional[str] = None, - chat_history: Optional[List["ChatCompletionMessage"]] = None, - generate_config: Optional[ - Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"] - ] = None, - ) -> Union["ChatCompletion", AsyncIterator["ChatCompletionChunk"]]: - """ - Given a list of messages comprising a conversation, the model will return a response. - - Parameters - ---------- - prompt : str - The user's input. - Parameters - ---------- - prompt: str - The user's input. - system_prompt: Optional[str] - The system context provide to Model prior to any chats. - chat_history: Optional[List["ChatCompletionMessage"]] - A list of messages comprising the conversation so far. - generate_config: Optional[Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"]] - Additional configuration for the chat generation. - "LlamaCppGenerateConfig" -> configuration for ggml model - "PytorchGenerateConfig" -> configuration for pytorch model - - Returns - ------- - Union["ChatCompletion", Iterator["ChatCompletionChunk"]] - Stream is a parameter in generate_config. - When stream is set to True, the function will return Iterator["ChatCompletionChunk"]. - When stream is set to False, the function will return "ChatCompletion". - - """ - - coro = self._model_ref.chat( - prompt, system_prompt, chat_history, generate_config - ) - r = self._isolation.call(coro) - if isinstance(r, bytes): - return orjson.loads(r) - return ClientIteratorWrapper(r) - - -class ChatglmCppChatModelHandle(ModelHandle): - def chat( - self, - prompt: str, - chat_history: Optional[List["ChatCompletionMessage"]] = None, - generate_config: Optional["ChatglmCppGenerateConfig"] = None, - ) -> Union["ChatCompletion", AsyncIterator["ChatCompletionChunk"]]: - """ - Given a list of messages comprising a conversation, the ChatGLM model will return a response. - - Parameters - ---------- - prompt: str - The user's input - chat_history: Optional[List["ChatCompletionMessage"]] - A list of messages comprising the conversation so far. - generate_config: Optional["ChatglmCppGenerateConfig"] - Additional Configuration for the ChatGLM Model generation. - - Returns - ------- - Union["ChatCompletion", Iterator["ChatCompletionChunk"]] - Stream is a parameter in generate_config. - When stream is set to True, the function will return Iterator["ChatCompletionChunk"]. - When stream is set to False, the function will return "ChatCompletion". - - """ - - coro = self._model_ref.chat(prompt, chat_history, generate_config) - r = self._isolation.call(coro) - if isinstance(r, bytes): - return orjson.loads(r) - return ClientIteratorWrapper(r) - - -class ImageModelHandle(ModelHandle): - def text_to_image( - self, - prompt: str, - n: int = 1, - size: str = "1024*1024", - response_format: str = "url", - **kwargs, - ) -> "ImageList": - """ - Creates an image by the input text. - - Parameters - ---------- - prompt (`str` or `List[str]`, *optional*): - The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`. - n (`int`, *optional*, defaults to 1): - The number of images to generate per prompt. Must be between 1 and 10. - size (`str`, *optional*, defaults to `1024*1024`): - The width*height in pixels of the generated image. Must be one of 256x256, 512x512, or 1024x1024. - response_format (`str`, *optional*, defaults to `url`): - The format in which the generated images are returned. Must be one of url or b64_json. - Returns - ------- - ImageList - A list of image objects. - """ - - coro = self._model_ref.text_to_image(prompt, n, size, response_format, **kwargs) - return orjson.loads(self._isolation.call(coro)) - - def image_to_image( - self, - image: "PIL.Image", - prompt: str, - negative_prompt: str, - n: int = 1, - size: str = "1024*1024", - response_format: str = "url", - **kwargs, - ) -> "ImageList": - """ - Creates an image by the input text. - - Parameters - ---------- - image (`PIL.Image`): - The ControlNet input condition to provide guidance to the `unet` for generation. If the type is - specified as `torch.FloatTensor`, it is passed to ControlNet as is. `PIL.Image.Image` can also be - accepted as an image. The dimensions of the output image defaults to `image`'s dimensions. If height - and/or width are passed, `image` is resized accordingly. If multiple ControlNets are specified in - `init`, images must be passed as a list such that each element of the list can be correctly batched for - input to a single ControlNet. - prompt (`str` or `List[str]`, *optional*): - The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`. - negative_prompt (`str` or `List[str]`, *optional*): - The prompt or prompts not to guide the image generation. If not defined, one has to pass - `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is - less than `1`). - n (`int`, *optional*, defaults to 1): - The number of images to generate per prompt. Must be between 1 and 10. - size (`str`, *optional*, defaults to `1024*1024`): - The width*height in pixels of the generated image. Must be one of 256x256, 512x512, or 1024x1024. - response_format (`str`, *optional*, defaults to `url`): - The format in which the generated images are returned. Must be one of url or b64_json. - Returns - ------- - ImageList - A list of image objects. - """ - - coro = self._model_ref.image_to_image( - image, prompt, negative_prompt, n, size, response_format, **kwargs - ) - return orjson.loads(self._isolation.call(coro)) - - -class ActorClient: - def __init__(self, endpoint: str): - restful_client = Client(endpoint) - self._supervisor_address = restful_client._get_supervisor_internal_address() - self._isolation = Isolation(asyncio.new_event_loop(), threaded=True) - self._isolation.start() - self._supervisor_ref: xo.ActorRefType["SupervisorActor"] = self._isolation.call( - xo.actor_ref(address=self._supervisor_address, uid=SupervisorActor.uid()) - ) - - def register_model(self, model_type: str, model: str, persist: bool): - """ - Register a custom model. - - Parameters - ---------- - model_type: str - The type of model. - model: str - The model definition. (refer to: https://inference.readthedocs.io/en/latest/models/custom.html) - persist: bool - """ - coro = self._supervisor_ref.register_model(model_type, model, persist) - self._isolation.call(coro) - - def unregister_model(self, model_type: str, model_name: str): - """ - Unregister a custom model. - - Parameters - ---------- - model_type: str - The type of model. - model_name: str - The name of the model - """ - coro = self._supervisor_ref.unregister_model(model_type, model_name) - self._isolation.call(coro) - - def list_model_registrations(self, model_type: str) -> List[Dict[str, Any]]: - """ - List models registered on the server. - - Parameters - ---------- - model_type: str - The type of the model. - - Returns - ------- - List[Dict[str, Any]] - The collection of registered models on the server. - """ - coro = self._supervisor_ref.list_model_registrations(model_type) - return self._isolation.call(coro) - - def get_model_registration( - self, model_type: str, model_name: str - ) -> Dict[str, Any]: - """ - Get the model with the model type and model name registered on the server. - - Parameters - ---------- - model_type: str - The type of the model. - - model_name: str - The name of the model. - Returns - ------- - List[Dict[str, Any]] - The collection of registered models on the server. - """ - coro = self._supervisor_ref.get_model_registration(model_type, model_name) - return self._isolation.call(coro) - - def launch_model( - self, - model_name: str, - model_type: str = "LLM", - model_size_in_billions: Optional[int] = None, - model_format: Optional[str] = None, - quantization: Optional[str] = None, - replica: int = 1, - n_gpu: Optional[Union[int, str]] = "auto", - request_limits: Optional[int] = None, - **kwargs, - ) -> str: - """ - Launch the Model based on the parameters on the server. - - Parameters - ---------- - model_name: str - The name of model. - model_type: str - Type of model. - model_size_in_billions: Optional[int] - The size (in billions) of the model. - model_format: Optional[str] - The format of the model. - quantization: Optional[str] - The quantization of model. - replica: Optional[int] - The replica of model, default is 1. - n_gpu: Optional[Union[int, str]], - The number of GPUs used by the model, default is "auto". - ``n_gpu=None`` means cpu only, ``n_gpu=auto`` lets the system automatically determine the best number of GPUs to use. - request_limits: Optional[int] - The number of request limits for this model, default is None. - ``request_limits=None`` means no limits for this model. - **kwargs: - Any other parameters been specified. - - Returns - ------- - str - The unique model_uid for the launched model. - - """ - - coro = self._supervisor_ref.launch_builtin_model( - model_uid=None, - model_name=model_name, - model_type=model_type, - model_size_in_billions=model_size_in_billions, - model_format=model_format, - quantization=quantization, - replica=replica, - n_gpu=n_gpu, - request_limits=request_limits, - **kwargs, - ) - - return self._isolation.call(coro) - - def terminate_model(self, model_uid: str): - """ - Terminate the specific model running on the server. - - Parameters - ---------- - model_uid: str - The unique id that identify the model we want. - """ - - coro = self._supervisor_ref.terminate_model(model_uid) - self._isolation.call(coro) - - def list_models(self) -> Dict[str, Dict[str, Any]]: - """ - Retrieve the model specifications from the Server. - - Returns - ------- - Dict[str, Dict[str, Any]] - The collection of model specifications with their names on the server. - - """ - - coro = self._supervisor_ref.list_models() - return self._isolation.call(coro) - - def get_model(self, model_uid: str) -> "ModelHandle": - """ - Launch the Model based on the parameters on the server. - - Parameters - ---------- - model_uid: str - The unique id that identify the model. - - Returns - ------- - ModelHandle - The corresponding Model Handler based on the Model specified in the uid: - "ChatglmCppChatModelHandle" -> handler for ChatGLM chat model - "GenerateModelHandle" -> handle for generate model. e.g. Baichuan. - "ChatModelHandle" -> handle for chat model. e.g. Baichuan-chat. - - """ - - desc: Dict[str, Any] = self._isolation.call( - self._supervisor_ref.describe_model(model_uid) - ) - model_ref = self._isolation.call(self._supervisor_ref.get_model(model_uid)) - if desc["model_type"] == "LLM": - if desc["model_format"] == "ggmlv3" and "chatglm" in desc["model_name"]: - return ChatglmCppChatModelHandle(model_ref, self._isolation) - elif "chat" in desc["model_ability"]: - return ChatModelHandle(model_ref, self._isolation) - elif "generate" in desc["model_ability"]: - return GenerateModelHandle(model_ref, self._isolation) - else: - raise ValueError(f"Unrecognized model ability: {desc['model_ability']}") - elif desc["model_type"] == "embedding": - return EmbeddingModelHandle(model_ref, self._isolation) - elif desc["model_type"] == "image": - return ImageModelHandle(model_ref, self._isolation) - elif desc["model_type"] == "rerank": - return RerankModelHandle(model_ref, self._isolation) - else: - raise ValueError(f"Unknown model type:{desc['model_type']}") - - def describe_model(self, model_uid: str) -> Dict: - """ - Get model information. - - Parameters - ---------- - model_uid: str - The unique id that identify the model. - - Returns - ------- - dict - A dictionary containing the following keys: - - "model_type": str - the type of the model determined by its function, e.g. "LLM" (Large Language Model) - - "model_name": str - the name of the specific LLM model family - - "model_lang": List[str] - the languages supported by the LLM model - - "model_ability": List[str] - the ability or capabilities of the LLM model - - "model_description": str - a detailed description of the LLM model - - "model_format": str - the format specification of the LLM model - - "model_size_in_billions": int - the size of the LLM model in billions - - "quantization": str - the quantization applied to the model - - "revision": str - the revision number of the LLM model specification - - "context_length": int - the maximum text length the LLM model can accommodate (include all input & output) - """ - - return self._isolation.call(self._supervisor_ref.describe_model(model_uid)) diff --git a/xinference/client/restful/restful_client.py b/xinference/client/restful/restful_client.py index 29fb00c68e..679f65d296 100644 --- a/xinference/client/restful/restful_client.py +++ b/xinference/client/restful/restful_client.py @@ -25,16 +25,27 @@ ChatCompletion, ChatCompletionChunk, ChatCompletionMessage, - ChatglmCppGenerateConfig, Completion, CompletionChunk, Embedding, ImageList, LlamaCppGenerateConfig, PytorchGenerateConfig, + VideoList, ) +def convert_float_to_int_or_str(model_size: float) -> Union[int, str]: + """convert float to int or string + + if float can be presented as int, convert it to int, otherwise convert it to string + """ + if int(model_size) == model_size: + return int(model_size) + else: + return str(model_size) + + def _get_error_string(response: requests.Response) -> str: try: if response.content: @@ -125,6 +136,7 @@ def rerank( top_n: Optional[int] = None, max_chunks_per_doc: Optional[int] = None, return_documents: Optional[bool] = None, + return_len: Optional[bool] = None, **kwargs, ): """ @@ -142,6 +154,8 @@ def rerank( The maximum number of chunks derived from a document return_documents: bool if return documents + return_len: bool + if return tokens len Returns ------- Scores @@ -160,6 +174,7 @@ def rerank( "top_n": top_n, "max_chunks_per_doc": max_chunks_per_doc, "return_documents": return_documents, + "return_len": return_len, } request_body.update(kwargs) response = requests.post(url, json=request_body, headers=self.auth_headers) @@ -168,8 +183,6 @@ def rerank( f"Failed to rerank documents, detail: {response.json()['detail']}" ) response_data = response.json() - for r in response_data["results"]: - r["document"] = documents[r["index"]] return response_data @@ -222,9 +235,9 @@ def image_to_image( self, image: Union[str, bytes], prompt: str, - negative_prompt: str, + negative_prompt: Optional[str] = None, n: int = 1, - size: str = "1024*1024", + size: Optional[str] = None, response_format: str = "url", **kwargs, ) -> "ImageList": @@ -282,6 +295,119 @@ def image_to_image( response_data = response.json() return response_data + def inpainting( + self, + image: Union[str, bytes], + mask_image: Union[str, bytes], + prompt: str, + negative_prompt: Optional[str] = None, + n: int = 1, + size: Optional[str] = None, + response_format: str = "url", + **kwargs, + ) -> "ImageList": + """ + Inpaint an image by the input text. + + Parameters + ---------- + image: `Union[str, bytes]` + an image batch to be inpainted (which parts of the image to + be masked out with `mask_image` and repainted according to `prompt`). For both numpy array and pytorch + tensor, the expected value range is between `[0, 1]` If it's a tensor or a list or tensors, the + expected shape should be `(B, C, H, W)` or `(C, H, W)`. If it is a numpy array or a list of arrays, the + expected shape should be `(B, H, W, C)` or `(H, W, C)` It can also accept image latents as `image`, but + if passing latents directly it is not encoded again. + mask_image: `Union[str, bytes]` + representing an image batch to mask `image`. White pixels in the mask + are repainted while black pixels are preserved. If `mask_image` is a PIL image, it is converted to a + single channel (luminance) before use. If it's a numpy array or pytorch tensor, it should contain one + color channel (L) instead of 3, so the expected shape for pytorch tensor would be `(B, 1, H, W)`, `(B, + H, W)`, `(1, H, W)`, `(H, W)`. And for numpy array would be for `(B, H, W, 1)`, `(B, H, W)`, `(H, W, + 1)`, or `(H, W)`. + prompt: `str` or `List[str]` + The prompt or prompts to guide image generation. If not defined, you need to pass `prompt_embeds`. + negative_prompt (`str` or `List[str]`, *optional*): + The prompt or prompts not to guide the image generation. If not defined, one has to pass + `negative_prompt_embeds` instead. Ignored when not using guidance (i.e., ignored if `guidance_scale` is + less than `1`). + n: `int`, defaults to 1 + The number of images to generate per prompt. Must be between 1 and 10. + size: `str`, defaults to None + The width*height in pixels of the generated image. + response_format: `str`, defaults to `url` + The format in which the generated images are returned. Must be one of url or b64_json. + Returns + ------- + ImageList + A list of image objects. + :param prompt: + :param image: + """ + url = f"{self._base_url}/v1/images/inpainting" + params = { + "model": self._model_uid, + "prompt": prompt, + "negative_prompt": negative_prompt, + "n": n, + "size": size, + "response_format": response_format, + "kwargs": json.dumps(kwargs), + } + files: List[Any] = [] + for key, value in params.items(): + files.append((key, (None, value))) + files.append(("image", ("image", image, "application/octet-stream"))) + files.append( + ("mask_image", ("mask_image", mask_image, "application/octet-stream")) + ) + response = requests.post(url, files=files, headers=self.auth_headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to inpaint the images, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data + + +class RESTfulVideoModelHandle(RESTfulModelHandle): + def text_to_video( + self, + prompt: str, + n: int = 1, + **kwargs, + ) -> "VideoList": + """ + Creates a video by the input text. + + Parameters + ---------- + prompt: `str` or `List[str]` + The prompt or prompts to guide video generation. If not defined, you need to pass `prompt_embeds`. + n: `int`, defaults to 1 + The number of videos to generate per prompt. Must be between 1 and 10. + Returns + ------- + VideoList + A list of video objects. + """ + url = f"{self._base_url}/v1/video/generations" + request_body = { + "model": self._model_uid, + "prompt": prompt, + "n": n, + "kwargs": json.dumps(kwargs), + } + response = requests.post(url, json=request_body, headers=self.auth_headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to create the video, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data + class RESTfulGenerateModelHandle(RESTfulModelHandle): def generate( @@ -300,7 +426,7 @@ def generate( The user's message or user's input. generate_config: Optional[Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"]] Additional configuration for the chat generation. - "LlamaCppGenerateConfig" -> Configuration for ggml model + "LlamaCppGenerateConfig" -> Configuration for llama-cpp-python model "PytorchGenerateConfig" -> Configuration for pytorch model Returns @@ -367,7 +493,7 @@ def chat( A tool list. generate_config: Optional[Union["LlamaCppGenerateConfig", "PytorchGenerateConfig"]] Additional configuration for the chat generation. - "LlamaCppGenerateConfig" -> configuration for ggml model + "LlamaCppGenerateConfig" -> configuration for llama-cpp-python model "PytorchGenerateConfig" -> configuration for pytorch model Returns @@ -383,81 +509,14 @@ def chat( Report the failure to generate the chat from the server. Detailed information provided in error message. """ - - url = f"{self._base_url}/v1/chat/completions" - - if chat_history is None: - chat_history = [] - - chat_history = handle_system_prompts(chat_history, system_prompt) - chat_history.append({"role": "user", "content": prompt}) # type: ignore - - request_body: Dict[str, Any] = { - "model": self._model_uid, - "messages": chat_history, - } - if tools is not None: - request_body["tools"] = tools - if generate_config is not None: - for key, value in generate_config.items(): - request_body[key] = value - - stream = bool(generate_config and generate_config.get("stream")) - response = requests.post( - url, json=request_body, stream=stream, headers=self.auth_headers + warnings.warn( + "The parameters `prompt`, `system_prompt` and `chat_history` will be deprecated in version v0.15.0, " + "and will be replaced by the parameter `messages`, " + "similar to the OpenAI API: https://platform.openai.com/docs/guides/chat-completions/getting-started", + category=DeprecationWarning, + stacklevel=2, ) - if response.status_code != 200: - raise RuntimeError( - f"Failed to generate chat completion, detail: {_get_error_string(response)}" - ) - - if stream: - return streaming_response_iterator(response.iter_lines()) - - response_data = response.json() - return response_data - - -class RESTfulChatglmCppChatModelHandle(RESTfulModelHandle): - def chat( - self, - prompt: str, - system_prompt: Optional[str] = None, - chat_history: Optional[List["ChatCompletionMessage"]] = None, - tools: Optional[List[Dict]] = None, - generate_config: Optional["ChatglmCppGenerateConfig"] = None, - ) -> Union["ChatCompletion", Iterator["ChatCompletionChunk"]]: - """ - Given a list of messages comprising a conversation, the ChatGLM model will return a response via RESTful APIs. - - Parameters - ---------- - prompt: str - The user's input. - system_prompt: Optional[str] - The system context provide to Model prior to any chats. - chat_history: Optional[List["ChatCompletionMessage"]] - A list of messages comprising the conversation so far. - tools: Optional[List[Dict]] - A tool list. - generate_config: Optional["ChatglmCppGenerateConfig"] - Additional configuration for ChatGLM chat generation. - - Returns - ------- - Union["ChatCompletion", Iterator["ChatCompletionChunk"]] - Stream is a parameter in generate_config. - When stream is set to True, the function will return Iterator["ChatCompletionChunk"]. - When stream is set to False, the function will return "ChatCompletion". - - Raises - ------ - RuntimeError - Report the failure to generate the chat from the server. Detailed information provided in error message. - - """ - url = f"{self._base_url}/v1/chat/completions" if chat_history is None: @@ -493,60 +552,6 @@ def chat( return response_data -class RESTfulChatglmCppGenerateModelHandle(RESTfulChatglmCppChatModelHandle): - def generate( - self, - prompt: str, - generate_config: Optional["ChatglmCppGenerateConfig"] = None, - ) -> Union["Completion", Iterator["CompletionChunk"]]: - """ - Given a prompt, the ChatGLM model will generate a response via RESTful APIs. - - Parameters - ---------- - prompt: str - The user's input. - generate_config: Optional["ChatglmCppGenerateConfig"] - Additional configuration for ChatGLM chat generation. - - Returns - ------- - Union["Completion", Iterator["CompletionChunk"]] - Stream is a parameter in generate_config. - When stream is set to True, the function will return Iterator["CompletionChunk"]. - When stream is set to False, the function will return "Completion". - - Raises - ------ - RuntimeError - Report the failure to generate the content from the server. Detailed information provided in error message. - - """ - - url = f"{self._base_url}/v1/completions" - - request_body: Dict[str, Any] = {"model": self._model_uid, "prompt": prompt} - if generate_config is not None: - for key, value in generate_config.items(): - request_body[key] = value - - stream = bool(generate_config and generate_config.get("stream")) - - response = requests.post( - url, json=request_body, stream=stream, headers=self.auth_headers - ) - if response.status_code != 200: - raise RuntimeError( - f"Failed to generate completion, detail: {response.json()['detail']}" - ) - - if stream: - return streaming_response_iterator(response.iter_lines()) - - response_data = response.json() - return response_data - - class RESTfulAudioModelHandle(RESTfulModelHandle): def transcriptions( self, @@ -555,6 +560,7 @@ def transcriptions( prompt: Optional[str] = None, response_format: Optional[str] = "json", temperature: Optional[float] = 0, + timestamp_granularities: Optional[List[str]] = None, ): """ Transcribes audio into the input language. @@ -578,6 +584,11 @@ def transcriptions( while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit. + timestamp_granularities: Optional[List[str]], default is None. + The timestamp granularities to populate for this transcription. response_format must be set verbose_json + to use timestamp granularities. Either or both of these options are supported: word, or segment. + Note: There is no additional latency for segment timestamps, but generating word timestamps incurs + additional latency. Returns ------- @@ -590,12 +601,13 @@ def transcriptions( "prompt": prompt, "response_format": response_format, "temperature": temperature, + "timestamp_granularities[]": timestamp_granularities, } files: List[Any] = [] - for key, value in params.items(): - files.append((key, (None, value))) files.append(("file", ("file", audio, "application/octet-stream"))) - response = requests.post(url, files=files, headers=self.auth_headers) + response = requests.post( + url, data=params, files=files, headers=self.auth_headers + ) if response.status_code != 200: raise RuntimeError( f"Failed to transcribe the audio, detail: {_get_error_string(response)}" @@ -607,9 +619,11 @@ def transcriptions( def translations( self, audio: bytes, + language: Optional[str] = None, prompt: Optional[str] = None, response_format: Optional[str] = "json", temperature: Optional[float] = 0, + timestamp_granularities: Optional[List[str]] = None, ): """ Translates audio into English. @@ -620,6 +634,9 @@ def translations( audio: bytes The audio file object (not file name) to transcribe, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. + language: Optional[str] + The language of the input audio. Supplying the input language in ISO-639-1 + (https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) format will improve accuracy and latency. prompt: Optional[str] An optional text to guide the model's style or continue a previous audio segment. The prompt should match the audio language. @@ -630,6 +647,11 @@ def translations( while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit. + timestamp_granularities: Optional[List[str]], default is None. + The timestamp granularities to populate for this transcription. response_format must be set verbose_json + to use timestamp granularities. Either or both of these options are supported: word, or segment. + Note: There is no additional latency for segment timestamps, but generating word timestamps incurs + additional latency. Returns ------- @@ -638,15 +660,17 @@ def translations( url = f"{self._base_url}/v1/audio/translations" params = { "model": self._model_uid, + "language": language, "prompt": prompt, "response_format": response_format, "temperature": temperature, + "timestamp_granularities[]": timestamp_granularities, } files: List[Any] = [] - for key, value in params.items(): - files.append((key, (None, value))) files.append(("file", ("file", audio, "application/octet-stream"))) - response = requests.post(url, files=files, headers=self.auth_headers) + response = requests.post( + url, data=params, files=files, headers=self.auth_headers + ) if response.status_code != 200: raise RuntimeError( f"Failed to translate the audio, detail: {_get_error_string(response)}" @@ -655,6 +679,106 @@ def translations( response_data = response.json() return response_data + def speech( + self, + input: str, + voice: str = "", + response_format: str = "mp3", + speed: float = 1.0, + stream: bool = False, + prompt_speech: Optional[bytes] = None, + **kwargs, + ): + """ + Generates audio from the input text. + + Parameters + ---------- + + input: str + The text to generate audio for. The maximum length is 4096 characters. + voice: str + The voice to use when generating the audio. + response_format: str + The format to audio in. + speed: str + The speed of the generated audio. + stream: bool + Use stream or not. + + Returns + ------- + bytes + The generated audio binary. + """ + url = f"{self._base_url}/v1/audio/speech" + params = { + "model": self._model_uid, + "input": input, + "voice": voice, + "response_format": response_format, + "speed": speed, + "stream": stream, + "kwargs": json.dumps(kwargs), + } + if prompt_speech: + files: List[Any] = [] + files.append( + ( + "prompt_speech", + ("prompt_speech", prompt_speech, "application/octet-stream"), + ) + ) + response = requests.post( + url, data=params, files=files, headers=self.auth_headers + ) + else: + response = requests.post(url, json=params, headers=self.auth_headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to speech the text, detail: {_get_error_string(response)}" + ) + + if stream: + return response.iter_content(chunk_size=1024) + + return response.content + + +class RESTfulFlexibleModelHandle(RESTfulModelHandle): + def infer( + self, + **kwargs, + ): + """ + Call flexible model. + + Parameters + ---------- + + kwargs: dict + The inference arguments. + + + Returns + ------- + bytes + The inference result. + """ + url = f"{self._base_url}/v1/flexible/infers" + params = { + "model": self._model_uid, + } + params.update(kwargs) + + response = requests.post(url, json=params, headers=self.auth_headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to predict, detail: {_get_error_string(response)}" + ) + + return response.content + class Client: def __init__(self, base_url, api_key: Optional[str] = None): @@ -743,66 +867,19 @@ def list_models(self) -> Dict[str, Dict[str, Any]]: model_list = response_data["data"] return {item["id"]: item for item in model_list} - def launch_speculative_llm( - self, - model_name: str, - model_size_in_billions: Optional[int], - quantization: Optional[str], - draft_model_name: str, - draft_model_size_in_billions: Optional[int], - draft_quantization: Optional[str], - n_gpu: Optional[Union[int, str]] = "auto", - ): - """ - Launch the LLM along with a draft model based on the parameters on the server via RESTful APIs. This is an - experimental feature and the API may change in the future. - - Returns - ------- - str - The unique model_uid for the launched model. - - """ - warnings.warn( - "`launch_speculative_llm` is an experimental feature and the API may change in the future." - ) - - payload = { - "model_uid": None, - "model_name": model_name, - "model_size_in_billions": model_size_in_billions, - "quantization": quantization, - "draft_model_name": draft_model_name, - "draft_model_size_in_billions": draft_model_size_in_billions, - "draft_quantization": draft_quantization, - "n_gpu": n_gpu, - } - - url = f"{self.base_url}/experimental/speculative_llms" - response = requests.post(url, json=payload, headers=self._headers) - if response.status_code != 200: - raise RuntimeError( - f"Failed to launch model, detail: {_get_error_string(response)}" - ) - - response_data = response.json() - model_uid = response_data["model_uid"] - return model_uid - def launch_model( self, model_name: str, model_type: str = "LLM", + model_engine: Optional[str] = None, model_uid: Optional[str] = None, - model_size_in_billions: Optional[Union[int, str]] = None, + model_size_in_billions: Optional[Union[int, str, float]] = None, model_format: Optional[str] = None, quantization: Optional[str] = None, replica: int = 1, n_gpu: Optional[Union[int, str]] = "auto", + peft_model_config: Optional[Dict] = None, request_limits: Optional[int] = None, - peft_model_path: Optional[str] = None, - image_lora_load_kwargs: Optional[Dict] = None, - image_lora_fuse_kwargs: Optional[Dict] = None, worker_ip: Optional[str] = None, gpu_idx: Optional[Union[int, List[int]]] = None, **kwargs, @@ -816,9 +893,11 @@ def launch_model( The name of model. model_type: str type of model. + model_engine: Optional[str] + Specify the inference engine of the model when launching LLM. model_uid: str UID of model, auto generate a UUID if is None. - model_size_in_billions: Optional[int] + model_size_in_billions: Optional[Union[int, str, float]] The size (in billions) of the model. model_format: Optional[str] The format of the model. @@ -829,15 +908,13 @@ def launch_model( n_gpu: Optional[Union[int, str]], The number of GPUs used by the model, default is "auto". ``n_gpu=None`` means cpu only, ``n_gpu=auto`` lets the system automatically determine the best number of GPUs to use. + peft_model_config: Optional[Dict] + - "lora_list": A List of PEFT (Parameter-Efficient Fine-Tuning) model and path. + - "image_lora_load_kwargs": A Dict of lora load parameters for image model + - "image_lora_fuse_kwargs": A Dict of lora fuse parameters for image model request_limits: Optional[int] - The number of request limits for this model, default is None. + The number of request limits for this model, default is None. ``request_limits=None`` means no limits for this model. - peft_model_path: Optional[str] - PEFT (Parameter-Efficient Fine-Tuning) model path. - image_lora_load_kwargs: Optional[Dict] - lora load parameters for image model - image_lora_fuse_kwargs: Optional[Dict] - lora fuse parameters for image model worker_ip: Optional[str] Specify the worker ip where the model is located in a distributed scenario. gpu_idx: Optional[Union[int, List[int]]] @@ -854,9 +931,15 @@ def launch_model( url = f"{self.base_url}/v1/models" + # convert float to int or string since the RESTful API does not accept float. + if isinstance(model_size_in_billions, float): + model_size_in_billions = convert_float_to_int_or_str(model_size_in_billions) + payload = { "model_uid": model_uid, "model_name": model_name, + "model_engine": model_engine, + "peft_model_config": peft_model_config, "model_type": model_type, "model_size_in_billions": model_size_in_billions, "model_format": model_format, @@ -864,9 +947,6 @@ def launch_model( "replica": replica, "n_gpu": n_gpu, "request_limits": request_limits, - "peft_model_path": peft_model_path, - "image_lora_load_kwargs": image_lora_load_kwargs, - "image_lora_fuse_kwargs": image_lora_fuse_kwargs, "worker_ip": worker_ip, "gpu_idx": gpu_idx, } @@ -928,7 +1008,6 @@ def get_model(self, model_uid: str) -> RESTfulModelHandle: ------- ModelHandle The corresponding Model Handler based on the Model specified in the uid: - - :obj:`xinference.client.handlers.ChatglmCppChatModelHandle` -> provide handle to ChatGLM Model - :obj:`xinference.client.handlers.GenerateModelHandle` -> provide handle to basic generate Model. e.g. Baichuan. - :obj:`xinference.client.handlers.ChatModelHandle` -> provide handle to chat Model. e.g. Baichuan-chat. @@ -949,11 +1028,7 @@ def get_model(self, model_uid: str) -> RESTfulModelHandle: desc = response.json() if desc["model_type"] == "LLM": - if desc["model_format"] == "ggmlv3" and "chatglm" in desc["model_name"]: - return RESTfulChatglmCppGenerateModelHandle( - model_uid, self.base_url, auth_headers=self._headers - ) - elif "chat" in desc["model_ability"]: + if "chat" in desc["model_ability"]: return RESTfulChatModelHandle( model_uid, self.base_url, auth_headers=self._headers ) @@ -979,6 +1054,14 @@ def get_model(self, model_uid: str) -> RESTfulModelHandle: return RESTfulAudioModelHandle( model_uid, self.base_url, auth_headers=self._headers ) + elif desc["model_type"] == "video": + return RESTfulVideoModelHandle( + model_uid, self.base_url, auth_headers=self._headers + ) + elif desc["model_type"] == "flexible": + return RESTfulFlexibleModelHandle( + model_uid, self.base_url, auth_headers=self._headers + ) else: raise ValueError(f"Unknown model type:{desc['model_type']}") @@ -1032,7 +1115,13 @@ def describe_model(self, model_uid: str): ) return response.json() - def register_model(self, model_type: str, model: str, persist: bool): + def register_model( + self, + model_type: str, + model: str, + persist: bool, + worker_ip: Optional[str] = None, + ): """ Register a custom model. @@ -1042,6 +1131,8 @@ def register_model(self, model_type: str, model: str, persist: bool): The type of model. model: str The model definition. (refer to: https://inference.readthedocs.io/en/latest/models/custom.html) + worker_ip: Optional[str] + The IP address of the worker on which the model is running. persist: bool @@ -1051,7 +1142,7 @@ def register_model(self, model_type: str, model: str, persist: bool): Report failure to register the custom model. Provide details of failure through error message. """ url = f"{self.base_url}/v1/model_registrations/{model_type}" - request_body = {"model": model, "persist": persist} + request_body = {"model": model, "worker_ip": worker_ip, "persist": persist} response = requests.post(url, json=request_body, headers=self._headers) if response.status_code != 200: raise RuntimeError( @@ -1117,6 +1208,104 @@ def list_model_registrations(self, model_type: str) -> List[Dict[str, Any]]: response_data = response.json() return response_data + def list_cached_models( + self, model_name: Optional[str] = None, worker_ip: Optional[str] = None + ) -> List[Dict[Any, Any]]: + """ + Get a list of cached models. + Parameters + ---------- + model_name: Optional[str] + The name of model. + worker_ip: Optional[str] + Specify the worker ip where the model is located in a distributed scenario. + + Returns + ------- + List[Dict[Any, Any]] + The collection of cached models on the server. + + Raises + ------ + RuntimeError + Raised when the request fails, including the reason for the failure. + """ + + url = f"{self.base_url}/v1/cache/models" + params = { + "model_name": model_name, + "worker_ip": worker_ip, + } + response = requests.get(url, headers=self._headers, params=params) + if response.status_code != 200: + raise RuntimeError( + f"Failed to list cached model, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + response_data = response_data.get("list") + return response_data + + def list_deletable_models( + self, model_version: str, worker_ip: Optional[str] = None + ) -> Dict[str, Any]: + """ + Get the cached models with the model path cached on the server. + Parameters + ---------- + model_version: str + The version of the model. + worker_ip: Optional[str] + Specify the worker ip where the model is located in a distributed scenario. + Returns + ------- + Dict[str, Dict[str,str]]] + Dictionary with keys "model_name" and values model_file_location. + """ + url = f"{self.base_url}/v1/cache/models/files" + params = { + "model_version": model_version, + "worker_ip": worker_ip, + } + response = requests.get(url, headers=self._headers, params=params) + if response.status_code != 200: + raise RuntimeError( + f"Failed to get paths by model name, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data + + def confirm_and_remove_model( + self, model_version: str, worker_ip: Optional[str] = None + ) -> bool: + """ + Remove the cached models with the model name cached on the server. + Parameters + ---------- + model_version: str + The version of the model. + worker_ip: Optional[str] + Specify the worker ip where the model is located in a distributed scenario. + Returns + ------- + str + The response of the server. + """ + url = f"{self.base_url}/v1/cache/models" + params = { + "model_version": model_version, + "worker_ip": worker_ip, + } + response = requests.delete(url, headers=self._headers, params=params) + if response.status_code != 200: + raise RuntimeError( + f"Failed to remove cached models, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data.get("result", False) + def get_model_registration( self, model_type: str, model_name: str ) -> Dict[str, Any]: @@ -1144,3 +1333,83 @@ def get_model_registration( response_data = response.json() return response_data + + def query_engine_by_model_name(self, model_name: str): + """ + Get the engine parameters with the model name registered on the server. + + Parameters + ---------- + model_name: str + The name of the model. + Returns + ------- + Dict[str, List[Dict[str, Any]]] + The supported engine parameters of registered models on the server. + """ + url = f"{self.base_url}/v1/engines/{model_name}" + response = requests.get(url, headers=self._headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to query engine parameters by model name, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data + + def abort_request(self, model_uid: str, request_id: str): + """ + Abort a request. + Abort a submitted request. If the request is finished or not found, this method will be a no-op. + Currently, this interface is only supported when batching is enabled for models on transformers backend. + + Parameters + ---------- + model_uid: str + Model uid. + request_id: str + Request id. + Returns + ------- + Dict + Return empty dict. + """ + url = f"{self.base_url}/v1/models/{model_uid}/requests/{request_id}/abort" + response = requests.post(url, headers=self._headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to abort request, detail: {_get_error_string(response)}" + ) + + response_data = response.json() + return response_data + + def get_workers_info(self): + url = f"{self.base_url}/v1/workers" + response = requests.get(url, headers=self._headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to get workers info, detail: {_get_error_string(response)}" + ) + response_data = response.json() + return response_data + + def get_supervisor_info(self): + url = f"{self.base_url}/v1/supervisor" + response = requests.get(url, headers=self._headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to get supervisor info, detail: {_get_error_string(response)}" + ) + response_json = response.json() + return response_json + + def abort_cluster(self): + url = f"{self.base_url}/v1/clusters" + response = requests.delete(url, headers=self._headers) + if response.status_code != 200: + raise RuntimeError( + f"Failed to abort cluster, detail: {_get_error_string(response)}" + ) + response_json = response.json() + return response_json diff --git a/xinference/client/tests/test_client.py b/xinference/client/tests/test_client.py index ce928214f7..095ef5e182 100644 --- a/xinference/client/tests/test_client.py +++ b/xinference/client/tests/test_client.py @@ -22,7 +22,6 @@ import requests from ...constants import XINFERENCE_ENV_MODEL_SRC -from ..oscar.actor_client import ActorClient, ChatModelHandle, EmbeddingModelHandle from ..restful.restful_client import Client as RESTfulClient from ..restful.restful_client import ( RESTfulChatModelHandle, @@ -31,207 +30,6 @@ ) -@pytest.mark.skipif(os.name == "nt", reason="Skip windows") -@pytest.mark.asyncio -async def test_client(setup): - endpoint, _ = setup - client = ActorClient(endpoint) - assert len(client.list_models()) == 0 - - model_uid = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" - ) - assert len(client.list_models()) == 1 - - model = client.get_model(model_uid=model_uid) - assert isinstance(model, ChatModelHandle) - - completion = model.chat("write a poem.") - assert "content" in completion["choices"][0]["message"] - - completion = model.chat("write a poem.", generate_config={"stream": True}) - with pytest.raises(Exception, match="Parallel generation"): - model.chat("write a poem.", generate_config={"stream": True}) - del completion - completion = model.chat("write a poem.", generate_config={"stream": True}) - async for chunk in completion: - assert chunk - assert isinstance(chunk, dict) - del completion - - client.terminate_model(model_uid=model_uid) - assert len(client.list_models()) == 0 - - model_uid = client.launch_model( - model_name="orca", - model_size_in_billions=3, - quantization="q4_0", - ) - - model = client.get_model(model_uid=model_uid) - - client.terminate_model(model_uid=model_uid) - assert len(client.list_models()) == 0 - - with pytest.raises(ValueError): - client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0", n_gpu=100 - ) - - with pytest.raises(ValueError): - client.launch_model( - model_name="orca", - model_size_in_billions=3, - quantization="q4_0", - n_gpu="abcd", - ) - - -def test_client_for_model_uid(setup): - endpoint, _ = setup - client = ActorClient(endpoint) - assert len(client.list_models()) == 0 - - model_uid = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" - ) - assert len(client.list_models()) == 1 - assert model_uid == "orca" - - model_uid2 = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" - ) - assert len(client.list_models()) == 2 - assert len(model_uid2) == len("orca") + 9 - assert model_uid2.startswith("orca") - - client.terminate_model(model_uid=model_uid) - client.terminate_model(model_uid=model_uid2) - assert len(client.list_models()) == 0 - - -def test_client_for_embedding(setup): - endpoint, _ = setup - client = ActorClient(endpoint) - assert len(client.list_models()) == 0 - - model_uid = client.launch_model( - model_name="bge-small-en-v1.5", model_type="embedding" - ) - assert len(client.list_models()) == 1 - - model = client.get_model(model_uid=model_uid) - assert isinstance(model, EmbeddingModelHandle) - - completion = model.create_embedding("write a poem.") - assert len(completion["data"][0]["embedding"]) == 384 - - kwargs = { - "invalid": "invalid", - } - with pytest.raises(TypeError) as err: - completion = model.create_embedding("write a poem.", **kwargs) - assert "unexpected" in str(err.value) - - client.terminate_model(model_uid=model_uid) - assert len(client.list_models()) == 0 - - -@pytest.mark.skipif(os.name == "nt", reason="Skip windows") -def test_replica_model(setup): - endpoint, _ = setup - client = ActorClient(endpoint) - assert len(client.list_models()) == 0 - - # Windows CI has limited resources, use replica 1 - replica = 1 if os.name == "nt" else 2 - model_uid = client.launch_model( - model_name="orca", - model_size_in_billions=3, - quantization="q4_0", - replica=replica, - ) - # Only one model with 2 replica - assert len(client.list_models()) == 1 - - replica_uids = set() - while len(replica_uids) != replica: - model = client.get_model(model_uid=model_uid) - replica_uids.add(model._model_ref.uid) - - client2 = RESTfulClient(endpoint) - info = client2.describe_model(model_uid=model_uid) - assert "address" in info - assert "accelerators" in info - assert info["replica"] == replica - - client.terminate_model(model_uid=model_uid) - assert len(client.list_models()) == 0 - - -def test_client_custom_model(setup): - endpoint, _ = setup - client = ActorClient(endpoint) - - model_regs = client.list_model_registrations(model_type="LLM") - assert len(model_regs) > 0 - for model_reg in model_regs: - assert model_reg["is_builtin"] - - model = """{ - "version": 1, - "context_length":2048, - "model_name": "custom_model", - "model_lang": [ - "en", "zh" - ], - "model_ability": [ - "embed", - "chat" - ], - "model_family": "other", - "model_specs": [ - { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "ziqingyang/chinese-alpaca-2-7b" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", - "roles": [ - "Instruction", - "Response" - ], - "intra_message_sep": "\\n\\n### " - } -}""" - client.register_model(model_type="LLM", model=model, persist=False) - - new_model_regs = client.list_model_registrations(model_type="LLM") - assert len(new_model_regs) == len(model_regs) + 1 - custom_model_reg = None - for model_reg in new_model_regs: - if model_reg["model_name"] == "custom_model": - custom_model_reg = model_reg - assert custom_model_reg is not None - - client.unregister_model(model_type="LLM", model_name="custom_model") - new_model_regs = client.list_model_registrations(model_type="LLM") - assert len(new_model_regs) == len(model_regs) - custom_model_reg = None - for model_reg in new_model_regs: - if model_reg["model_name"] == "custom_model": - custom_model_reg = model_reg - assert custom_model_reg is None - - @pytest.mark.skipif(os.name == "nt", reason="Skip windows") def test_RESTful_client(setup): endpoint, _ = setup @@ -239,7 +37,10 @@ def test_RESTful_client(setup): assert len(client.list_models()) == 0 model_uid = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", + quantization="q4_0", ) assert len(client.list_models()) == 1 @@ -292,7 +93,7 @@ def _check_stream(): for _ in range(2): r = executor.submit(_check_stream) results.append(r) - # Parallel generation is not supported by ggml. + # Parallel generation is not supported by llama-cpp-python. error_count = 0 for r in results: try: @@ -310,6 +111,7 @@ def _check_stream(): model_uid = client.launch_model( model_name="tiny-llama", + model_engine="llama.cpp", model_size_in_billions=1, model_format="ggufv2", quantization="q2_K", @@ -355,8 +157,9 @@ def _check(stream=False): client.terminate_model(model_uid=model_uid) model_uid2 = client.launch_model( - model_name="orca", - model_size_in_billions=3, + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", quantization="q4_0", ) @@ -364,6 +167,14 @@ def _check(stream=False): assert len(client.list_models()) == 0 +@pytest.mark.skipif(os.name == "nt", reason="Skip windows") +def test_list_cached_models(setup): + endpoint, _ = setup + client = RESTfulClient(endpoint) + res = client.list_cached_models() + assert len(res) > 0 + + def test_RESTful_client_for_embedding(setup): endpoint, _ = setup client = RESTfulClient(endpoint) @@ -522,7 +333,9 @@ def test_client_from_modelscope(setup): client = RESTfulClient(endpoint) assert len(client.list_models()) == 0 - model_uid = client.launch_model(model_name="tiny-llama") + model_uid = client.launch_model( + model_name="tiny-llama", model_engine="llama.cpp" + ) assert len(client.list_models()) == 1 model = client.get_model(model_uid=model_uid) completion = model.generate("write a poem.", generate_config={"max_tokens": 5}) @@ -620,7 +433,7 @@ def setup_cluster(): logging_conf=TEST_FILE_LOGGING_CONF, ) endpoint = f"http://localhost:{port}" - if not api_health_check(endpoint, max_attempts=3, sleep_interval=5): + if not api_health_check(endpoint, max_attempts=10, sleep_interval=5): raise RuntimeError("Endpoint is not available after multiple attempts") yield f"http://localhost:{port}", supervisor_address @@ -636,7 +449,10 @@ def test_auto_recover(set_auto_recover_limit, setup_cluster): client = RESTfulClient(endpoint) model_uid = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", + quantization="q4_0", ) new_children_proc = set(current_proc.children(recursive=True)) model_proc = next(iter(new_children_proc - chilren_proc)) @@ -661,23 +477,3 @@ def test_auto_recover(set_auto_recover_limit, setup_cluster): time.sleep(1) else: assert False - - new_children_proc = set(current_proc.children(recursive=True)) - model_proc = next(iter(new_children_proc - chilren_proc)) - assert len(client.list_models()) == 1 - - model_proc.kill() - - expect_failed = False - for _ in range(5): - try: - completion = model.generate( - "Once upon a time, there was a very old computer", {"max_tokens": 64} - ) - assert "text" in completion["choices"][0] - break - except Exception: - time.sleep(1) - else: - expect_failed = True - assert expect_failed diff --git a/xinference/conftest.py b/xinference/conftest.py index 1dfeae0f0e..a03572451f 100644 --- a/xinference/conftest.py +++ b/xinference/conftest.py @@ -194,7 +194,7 @@ def setup(): local_cluster_proc = run_test_cluster_in_subprocess( supervisor_addr, TEST_LOGGING_CONF ) - if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=3): + if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5): raise RuntimeError("Cluster is not available after multiple attempts") port = xo.utils.get_next_port() @@ -226,7 +226,7 @@ def setup_with_file_logging(): local_cluster_proc = run_test_cluster_in_subprocess( supervisor_addr, TEST_FILE_LOGGING_CONF ) - if not cluster_health_check(supervisor_addr, max_attempts=3, sleep_interval=3): + if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5): raise RuntimeError("Cluster is not available after multiple attempts") port = xo.utils.get_next_port() @@ -237,7 +237,7 @@ def setup_with_file_logging(): logging_conf=TEST_FILE_LOGGING_CONF, ) endpoint = f"http://localhost:{port}" - if not api_health_check(endpoint, max_attempts=3, sleep_interval=5): + if not api_health_check(endpoint, max_attempts=10, sleep_interval=5): raise RuntimeError("Endpoint is not available after multiple attempts") try: @@ -258,7 +258,7 @@ def setup_with_auth(): local_cluster_proc = run_test_cluster_in_subprocess( supervisor_addr, TEST_LOGGING_CONF ) - if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=3): + if not cluster_health_check(supervisor_addr, max_attempts=10, sleep_interval=5): raise RuntimeError("Cluster is not available after multiple attempts") user1 = User( diff --git a/xinference/constants.py b/xinference/constants.py index b5be63057f..c9ba4e5ddc 100644 --- a/xinference/constants.py +++ b/xinference/constants.py @@ -17,6 +17,8 @@ XINFERENCE_ENV_ENDPOINT = "XINFERENCE_ENDPOINT" XINFERENCE_ENV_MODEL_SRC = "XINFERENCE_MODEL_SRC" +XINFERENCE_ENV_CSG_TOKEN = "XINFERENCE_CSG_TOKEN" +XINFERENCE_ENV_CSG_ENDPOINT = "XINFERENCE_CSG_ENDPOINT" XINFERENCE_ENV_HOME_PATH = "XINFERENCE_HOME" XINFERENCE_ENV_HEALTH_CHECK_FAILURE_THRESHOLD = ( "XINFERENCE_HEALTH_CHECK_FAILURE_THRESHOLD" @@ -24,8 +26,8 @@ XINFERENCE_ENV_HEALTH_CHECK_INTERVAL = "XINFERENCE_HEALTH_CHECK_INTERVAL" XINFERENCE_ENV_HEALTH_CHECK_TIMEOUT = "XINFERENCE_HEALTH_CHECK_TIMEOUT" XINFERENCE_ENV_DISABLE_HEALTH_CHECK = "XINFERENCE_DISABLE_HEALTH_CHECK" -XINFERENCE_ENV_DISABLE_VLLM = "XINFERENCE_DISABLE_VLLM" -XINFERENCE_ENV_ENABLE_SGLANG = "XINFERENCE_ENABLE_SGLANG" +XINFERENCE_ENV_DISABLE_METRICS = "XINFERENCE_DISABLE_METRICS" +XINFERENCE_ENV_TRANSFORMERS_ENABLE_BATCHING = "XINFERENCE_TRANSFORMERS_ENABLE_BATCHING" def get_xinference_home() -> str: @@ -41,10 +43,15 @@ def get_xinference_home() -> str: XINFERENCE_HOME = get_xinference_home() XINFERENCE_CACHE_DIR = os.path.join(XINFERENCE_HOME, "cache") +XINFERENCE_TENSORIZER_DIR = os.path.join(XINFERENCE_HOME, "tensorizer") XINFERENCE_MODEL_DIR = os.path.join(XINFERENCE_HOME, "model") XINFERENCE_LOG_DIR = os.path.join(XINFERENCE_HOME, "logs") XINFERENCE_IMAGE_DIR = os.path.join(XINFERENCE_HOME, "image") +XINFERENCE_VIDEO_DIR = os.path.join(XINFERENCE_HOME, "video") XINFERENCE_AUTH_DIR = os.path.join(XINFERENCE_HOME, "auth") +XINFERENCE_CSG_ENDPOINT = str( + os.environ.get(XINFERENCE_ENV_CSG_ENDPOINT, "https://hub-stg.opencsg.com/") +) XINFERENCE_DEFAULT_LOCAL_HOST = "127.0.0.1" XINFERENCE_DEFAULT_DISTRIBUTED_HOST = "0.0.0.0" @@ -64,5 +71,9 @@ def get_xinference_home() -> str: XINFERENCE_DISABLE_HEALTH_CHECK = bool( int(os.environ.get(XINFERENCE_ENV_DISABLE_HEALTH_CHECK, 0)) ) -XINFERENCE_DISABLE_VLLM = bool(int(os.environ.get(XINFERENCE_ENV_DISABLE_VLLM, 0))) -XINFERENCE_ENABLE_SGLANG = bool(int(os.environ.get(XINFERENCE_ENV_ENABLE_SGLANG, 0))) +XINFERENCE_DISABLE_METRICS = bool( + int(os.environ.get(XINFERENCE_ENV_DISABLE_METRICS, 0)) +) +XINFERENCE_TRANSFORMERS_ENABLE_BATCHING = bool( + int(os.environ.get(XINFERENCE_ENV_TRANSFORMERS_ENABLE_BATCHING, 0)) +) diff --git a/xinference/core/__init__.py b/xinference/core/__init__.py index d3f48dd6fc..37f6558d95 100644 --- a/xinference/core/__init__.py +++ b/xinference/core/__init__.py @@ -11,5 +11,3 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -from .model import ModelActor diff --git a/xinference/core/cache_tracker.py b/xinference/core/cache_tracker.py index 803f5ff222..7f6975d4bc 100644 --- a/xinference/core/cache_tracker.py +++ b/xinference/core/cache_tracker.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from logging import getLogger -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional import xoscar as xo @@ -22,7 +22,7 @@ class CacheTrackerActor(xo.Actor): def __init__(self): super().__init__() - self._model_name_to_version_info: Dict[str, List[Dict]] = {} + self._model_name_to_version_info: Dict[str, List[Dict]] = {} # type: ignore @classmethod def uid(cls) -> str: @@ -100,3 +100,55 @@ def get_model_versions(self, model_name: str) -> List[Dict]: def get_model_version_count(self, model_name: str) -> int: return len(self.get_model_versions(model_name)) + + def list_cached_models( + self, worker_ip: str, model_name: Optional[str] = None + ) -> List[Dict[Any, Any]]: + cached_models = [] + for name, versions in self._model_name_to_version_info.items(): + # only return assigned cached model if model_name is not none + # else return all cached model + if model_name and model_name != name: + continue + for version_info in versions: + cache_status = version_info.get("cache_status", False) + # search cached model + if cache_status: + res = version_info.copy() + res["model_name"] = name + paths = res.get("model_file_location", {}) + # only return assigned worker's device path + if worker_ip in paths.keys(): + res["model_file_location"] = paths[worker_ip] + cached_models.append(res) + return cached_models + + def list_deletable_models(self, model_version: str, worker_ip: str) -> str: + model_file_location = "" + for model, model_versions in self._model_name_to_version_info.items(): + for version_info in model_versions: + # search assign model version + if model_version == version_info.get("model_version", None): + # check if exist + if version_info.get("cache_status", False): + paths = version_info.get("model_file_location", {}) + # only return assigned worker's device path + if worker_ip in paths.keys(): + model_file_location = paths[worker_ip] + return model_file_location + + def confirm_and_remove_model(self, model_version: str, worker_ip: str): + # find remove path + rm_path = self.list_deletable_models(model_version, worker_ip) + # search _model_name_to_version_info if exist this path, and delete + for model, model_versions in self._model_name_to_version_info.items(): + for version_info in model_versions: + # check if exist + if version_info.get("cache_status", False): + paths = version_info.get("model_file_location", {}) + # only delete assigned worker's device path + if worker_ip in paths.keys() and rm_path == paths[worker_ip]: + del paths[worker_ip] + # if path is empty, update cache status + if not paths: + version_info["cache_status"] = False diff --git a/xinference/core/chat_interface.py b/xinference/core/chat_interface.py index 0bdc8b7fb3..8738141f90 100644 --- a/xinference/core/chat_interface.py +++ b/xinference/core/chat_interface.py @@ -24,7 +24,6 @@ from gradio.layouts import Accordion, Column, Row from ..client.restful.restful_client import ( - RESTfulChatglmCppChatModelHandle, RESTfulChatModelHandle, RESTfulGenerateModelHandle, ) @@ -109,15 +108,14 @@ def generate_wrapper( history: List[List[str]], max_tokens: int, temperature: float, + lora_name: str, ) -> Generator: from ..client import RESTfulClient client = RESTfulClient(self.endpoint) client._set_token(self._access_token) model = client.get_model(self.model_uid) - assert isinstance( - model, (RESTfulChatModelHandle, RESTfulChatglmCppChatModelHandle) - ) + assert isinstance(model, RESTfulChatModelHandle) response_content = "" for chunk in model.chat( @@ -127,6 +125,7 @@ def generate_wrapper( "max_tokens": int(max_tokens), "temperature": temperature, "stream": True, + "lora_name": lora_name, }, ): assert isinstance(chunk, dict) @@ -152,6 +151,7 @@ def generate_wrapper( gr.Slider( minimum=0, maximum=2, value=1, step=0.01, label="Temperature" ), + gr.Text(label="LoRA Name"), ], title=f"🚀 Xinference Chat Bot : {self.model_name} 🚀", css=""" @@ -183,8 +183,7 @@ def generate_wrapper( def build_chat_vl_interface( self, ) -> "gr.Blocks": - def predict(history, bot): - logger.debug("Predict model: %s, history: %s", self.model_uid, history) + def predict(history, bot, max_tokens, temperature, stream): from ..client import RESTfulClient client = RESTfulClient(self.endpoint) @@ -196,13 +195,49 @@ def predict(history, bot): assert prompt["role"] == "user" prompt = prompt["content"] # multimodal chat does not support stream. - response = model.chat(prompt=prompt, chat_history=history[:-1]) - history.append(response["choices"][0]["message"]) - bot[-1][1] = history[-1]["content"] - return history, bot + if stream: + response_content = "" + for chunk in model.chat( + prompt=prompt, + chat_history=history[:-1], + generate_config={ + "max_tokens": max_tokens, + "temperature": temperature, + "stream": stream, + }, + ): + assert isinstance(chunk, dict) + delta = chunk["choices"][0]["delta"] + if "content" not in delta: + continue + else: + response_content += delta["content"] + bot[-1][1] = response_content + yield history, bot + history.append( + { + "content": response_content, + "role": "assistant", + } + ) + bot[-1][1] = response_content + yield history, bot + else: + response = model.chat( + prompt=prompt, + chat_history=history[:-1], + generate_config={ + "max_tokens": max_tokens, + "temperature": temperature, + "stream": stream, + }, + ) + history.append(response["choices"][0]["message"]) + bot[-1][1] = history[-1]["content"] + yield history, bot - def add_text(history, bot, text, image): - logger.debug("Add text, text: %s, image: %s", text, image) + def add_text(history, bot, text, image, video): + logger.debug("Add text, text: %s, image: %s, video: %s", text, image, video) if image: buffered = BytesIO() with PIL.Image.open(image) as img: @@ -214,19 +249,55 @@ def add_text(history, bot, text, image): "role": "user", "content": [ {"type": "text", "text": text}, - {"type": "image_url", "image_url": {"url": image}}, + { + "type": "image_url", + "image_url": { + "url": f"data:image/png;base64,{img_b64_str}" + }, + }, + ], + } + elif video: + + def video_to_base64(video_path): + with open(video_path, "rb") as video_file: + encoded_string = base64.b64encode(video_file.read()).decode( + "utf-8" + ) + return encoded_string + + def generate_html_video(video_path): + base64_video = video_to_base64(video_path) + video_format = video_path.split(".")[-1] + html_code = f""" + + """ + return html_code + + display_content = f"{generate_html_video(video)}\n{text}" + message = { + "role": "user", + "content": [ + {"type": "text", "text": text}, + { + "type": "video_url", + "video_url": {"url": video}, + }, ], } else: display_content = text message = {"role": "user", "content": text} history = history + [message] - bot = bot + [(display_content, None)] - return history, bot, "", None + bot = bot + [[display_content, None]] + return history, bot, "", None, None def clear_history(): logger.debug("Clear history.") - return [], None, "", None + return [], None, "", None, None def update_button(text): return gr.update(interactive=bool(text)) @@ -269,10 +340,11 @@ def update_button(text): state = gr.State([]) with gr.Row(): chatbot = gr.Chatbot( - elem_id="chatbot", label=self.model_name, height=550, scale=7 + elem_id="chatbot", label=self.model_name, height=700, scale=7 ) with gr.Column(scale=3): imagebox = gr.Image(type="filepath") + videobox = gr.Video() textbox = gr.Textbox( show_label=False, placeholder="Enter text and press ENTER", @@ -283,24 +355,48 @@ def update_button(text): ) clear_btn = gr.Button(value="Clear") + with gr.Accordion("Additional Inputs", open=False): + max_tokens = gr.Slider( + minimum=1, + maximum=self.context_length, + value=512, + step=1, + label="Max Tokens", + ) + temperature = gr.Slider( + minimum=0, maximum=2, value=1, step=0.01, label="Temperature" + ) + stream = gr.Checkbox(label="Stream", value=False) + textbox.change(update_button, [textbox], [submit_btn], queue=False) textbox.submit( add_text, - [state, chatbot, textbox, imagebox], - [state, chatbot, textbox, imagebox], + [state, chatbot, textbox, imagebox, videobox], + [state, chatbot, textbox, imagebox, videobox], queue=False, - ).then(predict, [state, chatbot], [state, chatbot]) + ).then( + predict, + [state, chatbot, max_tokens, temperature, stream], + [state, chatbot], + ) submit_btn.click( add_text, - [state, chatbot, textbox, imagebox], - [state, chatbot, textbox, imagebox], + [state, chatbot, textbox, imagebox, videobox], + [state, chatbot, textbox, imagebox, videobox], queue=False, - ).then(predict, [state, chatbot], [state, chatbot]) + ).then( + predict, + [state, chatbot, max_tokens, temperature, stream], + [state, chatbot], + ) clear_btn.click( - clear_history, None, [state, chatbot, textbox, imagebox], queue=False + clear_history, + None, + [state, chatbot, textbox, imagebox, videobox], + queue=False, ) return chat_vl_interface @@ -331,7 +427,7 @@ def clear(text, hist): history: hist, } - def complete(text, hist, max_tokens, temperature) -> Generator: + def complete(text, hist, max_tokens, temperature, lora_name) -> Generator: from ..client import RESTfulClient client = RESTfulClient(self.endpoint) @@ -349,6 +445,7 @@ def complete(text, hist, max_tokens, temperature) -> Generator: "max_tokens": max_tokens, "temperature": temperature, "stream": True, + "lora_name": lora_name, }, ): assert isinstance(chunk, dict) @@ -363,12 +460,12 @@ def complete(text, hist, max_tokens, temperature) -> Generator: } hist.append(response_content) - return { + return { # type: ignore textbox: response_content, history: hist, } - def retry(text, hist, max_tokens, temperature) -> Generator: + def retry(text, hist, max_tokens, temperature, lora_name) -> Generator: from ..client import RESTfulClient client = RESTfulClient(self.endpoint) @@ -387,6 +484,7 @@ def retry(text, hist, max_tokens, temperature) -> Generator: "max_tokens": max_tokens, "temperature": temperature, "stream": True, + "lora_name": lora_name, }, ): assert isinstance(chunk, dict) @@ -401,7 +499,7 @@ def retry(text, hist, max_tokens, temperature) -> Generator: } hist.append(response_content) - return { + return { # type: ignore textbox: response_content, history: hist, } @@ -470,10 +568,11 @@ def retry(text, hist, max_tokens, temperature) -> Generator: temperature = gr.Slider( minimum=0, maximum=2, value=1, step=0.01, label="Temperature" ) + lora_name = gr.Text(label="LoRA Name") btn_generate.click( fn=complete, - inputs=[textbox, history, length, temperature], + inputs=[textbox, history, length, temperature, lora_name], outputs=[textbox, history], ) @@ -485,7 +584,7 @@ def retry(text, hist, max_tokens, temperature) -> Generator: btn_retry.click( fn=retry, - inputs=[textbox, history, length, temperature], + inputs=[textbox, history, length, temperature, lora_name], outputs=[textbox, history], ) diff --git a/xinference/core/event.py b/xinference/core/event.py index 7361c179b2..fb5df80dc2 100644 --- a/xinference/core/event.py +++ b/xinference/core/event.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import queue -from collections import defaultdict +from collections import defaultdict, deque from enum import Enum from typing import Dict, List, TypedDict @@ -37,8 +36,8 @@ class Event(TypedDict): class EventCollectorActor(xo.StatelessActor): def __init__(self): super().__init__() - self._model_uid_to_events: Dict[str, queue.Queue] = defaultdict( - lambda: queue.Queue(maxsize=MAX_EVENT_COUNT_PER_MODEL) + self._model_uid_to_events: Dict[str, deque] = defaultdict( # type: ignore + lambda: deque(maxlen=MAX_EVENT_COUNT_PER_MODEL) ) @classmethod @@ -50,7 +49,7 @@ def get_model_events(self, model_uid: str) -> List[Dict]: if event_queue is None: return [] else: - return [dict(e, event_type=e["event_type"].name) for e in event_queue.queue] + return [dict(e, event_type=e["event_type"].name) for e in iter(event_queue)] def report_event(self, model_uid: str, event: Event): - self._model_uid_to_events[model_uid].put(event) + self._model_uid_to_events[model_uid].append(event) diff --git a/xinference/core/image_interface.py b/xinference/core/image_interface.py index 208b1a62de..e5ece5320c 100644 --- a/xinference/core/image_interface.py +++ b/xinference/core/image_interface.py @@ -36,6 +36,7 @@ def __init__( model_name: str, model_id: str, model_revision: str, + model_ability: List[str], controlnet: Union[None, List[Dict[str, Union[str, None]]]], access_token: Optional[str], ): @@ -45,6 +46,7 @@ def __init__( self.model_name = model_name self.model_id = model_id self.model_revision = model_revision + self.model_ability = model_ability self.controlnet = controlnet self.access_token = ( access_token.replace("Bearer ", "") if access_token is not None else None @@ -76,6 +78,7 @@ def text_generate_image( n: int, size_width: int, size_height: int, + num_inference_steps: int, negative_prompt: Optional[str] = None, ) -> PIL.Image.Image: from ..client import RESTfulClient @@ -86,11 +89,15 @@ def text_generate_image( assert isinstance(model, RESTfulImageModelHandle) size = f"{int(size_width)}*{int(size_height)}" + num_inference_steps = ( + None if num_inference_steps == -1 else num_inference_steps # type: ignore + ) response = model.text_to_image( prompt=prompt, n=n, size=size, + num_inference_steps=num_inference_steps, negative_prompt=negative_prompt, response_format="b64_json", ) @@ -125,13 +132,23 @@ def text_generate_image( n = gr.Number(label="Number of Images", value=1) size_width = gr.Number(label="Width", value=1024) size_height = gr.Number(label="Height", value=1024) + num_inference_steps = gr.Number( + label="Inference Step Number", value=-1 + ) with gr.Column(): image_output = gr.Gallery() generate_button.click( text_generate_image, - inputs=[prompt, n, size_width, size_height, negative_prompt], + inputs=[ + prompt, + n, + size_width, + size_height, + num_inference_steps, + negative_prompt, + ], outputs=image_output, ) @@ -145,6 +162,8 @@ def image_generate_image( n: int, size_width: int, size_height: int, + num_inference_steps: int, + padding_image_to_multiple: int, ) -> PIL.Image.Image: from ..client import RESTfulClient @@ -153,7 +172,14 @@ def image_generate_image( model = client.get_model(self.model_uid) assert isinstance(model, RESTfulImageModelHandle) - size = f"{int(size_width)}*{int(size_height)}" + if size_width > 0 and size_height > 0: + size = f"{int(size_width)}*{int(size_height)}" + else: + size = None + num_inference_steps = ( + None if num_inference_steps == -1 else num_inference_steps # type: ignore + ) + padding_image_to_multiple = None if padding_image_to_multiple == -1 else padding_image_to_multiple # type: ignore bio = io.BytesIO() image.save(bio, format="png") @@ -165,6 +191,8 @@ def image_generate_image( image=bio.getvalue(), size=size, response_format="b64_json", + num_inference_steps=num_inference_steps, + padding_image_to_multiple=padding_image_to_multiple, ) images = [] @@ -195,8 +223,16 @@ def image_generate_image( with gr.Row(): n = gr.Number(label="Number of image", value=1) - size_width = gr.Number(label="Width", value=512) - size_height = gr.Number(label="Height", value=512) + size_width = gr.Number(label="Width", value=-1) + size_height = gr.Number(label="Height", value=-1) + + with gr.Row(): + num_inference_steps = gr.Number( + label="Inference Step Number", value=-1 + ) + padding_image_to_multiple = gr.Number( + label="Padding image to multiple", value=-1 + ) with gr.Row(): with gr.Column(scale=1): @@ -213,6 +249,8 @@ def image_generate_image( n, size_width, size_height, + num_inference_steps, + padding_image_to_multiple, ], outputs=output_gallery, ) @@ -244,9 +282,11 @@ def build_main_interface(self) -> "gr.Blocks": """ ) - with gr.Tab("Text to Image"): - self.text2image_interface() - with gr.Tab("Image to Image"): - self.image2image_interface() + if "text2image" in self.model_ability: + with gr.Tab("Text to Image"): + self.text2image_interface() + if "image2image" in self.model_ability: + with gr.Tab("Image to Image"): + self.image2image_interface() return app diff --git a/xinference/core/model.py b/xinference/core/model.py index 63616cf3a7..602f712514 100644 --- a/xinference/core/model.py +++ b/xinference/core/model.py @@ -20,11 +20,17 @@ import time import types import weakref +from asyncio.queues import Queue +from asyncio.tasks import wait_for +from concurrent.futures import Future as ConcurrentFuture from typing import ( TYPE_CHECKING, + Any, AsyncGenerator, + AsyncIterator, Callable, Dict, + Generator, Iterator, List, Optional, @@ -34,6 +40,8 @@ import sse_starlette.sse import xoscar as xo +from ..constants import XINFERENCE_TRANSFORMERS_ENABLE_BATCHING + if TYPE_CHECKING: from .worker import WorkerActor from ..model.llm.core import LLM @@ -57,6 +65,9 @@ class _OutOfMemoryError(Exception): OutOfMemoryError = _OutOfMemoryError +XINFERENCE_BATCHING_ALLOWED_VISION_MODELS = ["qwen-vl-chat", "cogvlm2", "glm-4v"] + + def request_limit(fn): """ Used by ModelActor. @@ -121,11 +132,25 @@ def gen_uid(cls, model: "LLM"): async def __pre_destroy__(self): from ..model.embedding.core import EmbeddingModel - from ..model.llm.pytorch.core import PytorchModel as LLMPytorchModel + from ..model.llm.sglang.core import SGLANGModel + from ..model.llm.transformers.core import PytorchModel as LLMPytorchModel from ..model.llm.vllm.core import VLLMModel as LLMVLLMModel + if self.allow_batching(): + try: + assert self._scheduler_ref is not None + await xo.destroy_actor(self._scheduler_ref) + del self._scheduler_ref + except Exception as e: + logger.debug( + f"Destroy scheduler actor failed, address: {self.address}, error: {e}" + ) + + if hasattr(self._model, "stop") and callable(self._model.stop): + self._model.stop() + if ( - isinstance(self._model, (LLMPytorchModel, LLMVLLMModel)) + isinstance(self._model, (LLMPytorchModel, LLMVLLMModel, SGLANGModel)) and self._model.model_spec.model_format == "pytorch" ) or isinstance(self._model, EmbeddingModel): try: @@ -152,8 +177,9 @@ def __init__( request_limits: Optional[int] = None, ): super().__init__() - from ..model.llm.pytorch.core import PytorchModel - from ..model.llm.pytorch.spec_model import SpeculativeModel + from ..model.llm.lmdeploy.core import LMDeployModel + from ..model.llm.sglang.core import SGLANGModel + from ..model.llm.transformers.core import PytorchModel from ..model.llm.vllm.core import VLLMModel self._worker_address = worker_address @@ -167,7 +193,9 @@ def __init__( self._current_generator = lambda: None self._lock = ( None - if isinstance(self._model, (PytorchModel, SpeculativeModel, VLLMModel)) + if isinstance( + self._model, (PytorchModel, VLLMModel, SGLANGModel, LMDeployModel) + ) else asyncio.locks.Lock() ) self._worker_ref = None @@ -181,9 +209,20 @@ def __init__( } self._loop: Optional[asyncio.AbstractEventLoop] = None + self._scheduler_ref = None + async def __post_create__(self): self._loop = asyncio.get_running_loop() + if self.allow_batching(): + from .scheduler import SchedulerActor + + self._scheduler_ref = await xo.create_actor( + SchedulerActor, + address=self.address, + uid=SchedulerActor.gen_uid(self.model_uid(), self._model.rep_id), + ) + async def _record_completion_metrics( self, duration, completion_tokens, prompt_tokens ): @@ -235,8 +274,38 @@ def is_vllm_backend(self) -> bool: return isinstance(self._model, VLLMModel) - def load(self): + def allow_batching(self) -> bool: + from ..model.llm.transformers.core import PytorchModel + + model_ability = self._model_description.get("model_ability", []) + + condition = XINFERENCE_TRANSFORMERS_ENABLE_BATCHING and isinstance( + self._model, PytorchModel + ) + if condition and "vision" in model_ability: + if ( + self._model.model_family.model_name + in XINFERENCE_BATCHING_ALLOWED_VISION_MODELS + or self._model.model_family.model_family + in XINFERENCE_BATCHING_ALLOWED_VISION_MODELS + ): + return True + else: + logger.warning( + f"Currently for multimodal models, " + f"xinference only supports {', '.join(XINFERENCE_BATCHING_ALLOWED_VISION_MODELS)} for batching. " + f"Your model {self._model.model_family.model_name} with model family {self._model.model_family.model_family} is disqualified." + ) + return False + return condition + + async def load(self): self._model.load() + if self.allow_batching(): + await self._scheduler_ref.set_model(self._model) + logger.debug( + f"Batching enabled for model: {self.model_uid()}, max_num_seqs: {self._model.get_max_num_seqs()}" + ) def model_uid(self): return ( @@ -249,7 +318,7 @@ def model_uid(self): ) ) - def _to_json_generator(self, gen: types.GeneratorType): + def _to_generator(self, output_type: str, gen: types.GeneratorType): start_time = time.time() time_to_first_token = None final_usage = None @@ -257,8 +326,13 @@ def _to_json_generator(self, gen: types.GeneratorType): for v in gen: if time_to_first_token is None: time_to_first_token = (time.time() - start_time) * 1000 - final_usage = v.pop("usage", None) - v = dict(data=json.dumps(v)) + if output_type == "json": + final_usage = v.get("usage", None) + v = dict(data=json.dumps(v, ensure_ascii=False)) + else: + assert ( + output_type == "binary" + ), f"Unknown output type '{output_type}'" yield sse_starlette.sse.ensure_bytes(v, None) except OutOfMemoryError: logger.exception( @@ -281,7 +355,7 @@ def _to_json_generator(self, gen: types.GeneratorType): ) asyncio.run_coroutine_threadsafe(coro, loop=self._loop) - async def _to_json_async_gen(self, gen: types.AsyncGeneratorType): + async def _to_async_gen(self, output_type: str, gen: types.AsyncGeneratorType): start_time = time.time() time_to_first_token = None final_usage = None @@ -289,9 +363,14 @@ async def _to_json_async_gen(self, gen: types.AsyncGeneratorType): async for v in gen: if time_to_first_token is None: time_to_first_token = (time.time() - start_time) * 1000 - final_usage = v.pop("usage", None) - v = await asyncio.to_thread(json.dumps, v) - v = dict(data=v) # noqa: F821 + final_usage = v.get("usage", None) + if output_type == "json": + v = await asyncio.to_thread(json.dumps, v, ensure_ascii=False) + v = dict(data=v) # noqa: F821 + else: + assert ( + output_type == "binary" + ), f"Unknown output type '{output_type}'" yield await asyncio.to_thread(sse_starlette.sse.ensure_bytes, v, None) except OutOfMemoryError: logger.exception( @@ -318,8 +397,14 @@ async def _to_json_async_gen(self, gen: types.AsyncGeneratorType): ) await asyncio.gather(*coros) + async def _call_wrapper_json(self, fn: Callable, *args, **kwargs): + return await self._call_wrapper("json", fn, *args, **kwargs) + + async def _call_wrapper_binary(self, fn: Callable, *args, **kwargs): + return await self._call_wrapper("binary", fn, *args, **kwargs) + @oom_check - async def _call_wrapper(self, fn: Callable, *args, **kwargs): + async def _call_wrapper(self, output_type: str, fn: Callable, *args, **kwargs): if self._lock is None: if inspect.iscoroutinefunction(fn): ret = await fn(*args, **kwargs) @@ -333,31 +418,101 @@ async def _call_wrapper(self, fn: Callable, *args, **kwargs): ret = await asyncio.to_thread(fn, *args, **kwargs) if self._lock is not None and self._current_generator(): - raise Exception("Parallel generation is not supported by ggml.") + raise Exception("Parallel generation is not supported by llama-cpp-python.") if inspect.isgenerator(ret): - gen = self._to_json_generator(ret) + gen = self._to_generator(output_type, ret) self._current_generator = weakref.ref(gen) return gen if inspect.isasyncgen(ret): - gen = self._to_json_async_gen(ret) + gen = self._to_async_gen(output_type, ret) self._current_generator = weakref.ref(gen) return gen - return await asyncio.to_thread(json_dumps, ret) + if output_type == "json": + return await asyncio.to_thread(json_dumps, ret) + else: + assert output_type == "binary", f"Unknown output type '{output_type}'" + return ret @log_async(logger=logger) @request_limit @xo.generator async def generate(self, prompt: str, *args, **kwargs): - if hasattr(self._model, "generate"): - return await self._call_wrapper( - self._model.generate, prompt, *args, **kwargs + if self.allow_batching(): + return await self.handle_batching_request( + prompt, "generate", *args, **kwargs ) - if hasattr(self._model, "async_generate"): - return await self._call_wrapper( - self._model.async_generate, prompt, *args, **kwargs - ) - raise AttributeError(f"Model {self._model.model_spec} is not for generate.") + else: + kwargs.pop("raw_params", None) + if hasattr(self._model, "generate"): + return await self._call_wrapper_json( + self._model.generate, prompt, *args, **kwargs + ) + if hasattr(self._model, "async_generate"): + return await self._call_wrapper_json( + self._model.async_generate, prompt, *args, **kwargs + ) + raise AttributeError(f"Model {self._model.model_spec} is not for generate.") + + @staticmethod + async def _queue_consumer( + queue: Queue, timeout: Optional[float] = None + ) -> AsyncIterator[Any]: + from .scheduler import ( + XINFERENCE_STREAMING_ABORT_FLAG, + XINFERENCE_STREAMING_DONE_FLAG, + XINFERENCE_STREAMING_ERROR_FLAG, + ) + + while True: + # TODO: timeout setting + res = await wait_for(queue.get(), timeout) + if res == XINFERENCE_STREAMING_DONE_FLAG: + break + elif res == XINFERENCE_STREAMING_ABORT_FLAG: + raise RuntimeError( + f"This request has been cancelled by another `abort_request` request." + ) + elif isinstance(res, str) and res.startswith( + XINFERENCE_STREAMING_ERROR_FLAG + ): + raise RuntimeError(res[len(XINFERENCE_STREAMING_ERROR_FLAG) :]) + else: + yield res + + @staticmethod + def _get_stream_from_args(ability: str, *args) -> bool: + if ability == "chat": + assert args[2] is None or isinstance(args[2], dict) + return False if args[2] is None else args[2].get("stream", False) + else: + assert args[0] is None or isinstance(args[0], dict) + return False if args[0] is None else args[0].get("stream", False) + + async def handle_batching_request(self, prompt: str, ability: str, *args, **kwargs): + stream = self._get_stream_from_args(ability, *args) + assert self._scheduler_ref is not None + if stream: + assert self._scheduler_ref is not None + queue: Queue[Any] = Queue() + ret = self._queue_consumer(queue) + await self._scheduler_ref.add_request(prompt, queue, *args, **kwargs) + gen = self._to_async_gen("json", ret) + self._current_generator = weakref.ref(gen) + return gen + else: + from .scheduler import XINFERENCE_NON_STREAMING_ABORT_FLAG + + assert self._loop is not None + future = ConcurrentFuture() + await self._scheduler_ref.add_request(prompt, future, *args, **kwargs) + fut = asyncio.wrap_future(future, loop=self._loop) + result = await fut + if result == XINFERENCE_NON_STREAMING_ABORT_FLAG: + raise RuntimeError( + f"This request has been cancelled by another `abort_request` request." + ) + return await asyncio.to_thread(json_dumps, result) @log_async(logger=logger) @request_limit @@ -366,21 +521,32 @@ async def chat(self, prompt: str, *args, **kwargs): start_time = time.time() response = None try: - if hasattr(self._model, "chat"): - response = await self._call_wrapper( - self._model.chat, prompt, *args, **kwargs - ) - return response - if hasattr(self._model, "async_chat"): - response = await self._call_wrapper( - self._model.async_chat, prompt, *args, **kwargs + if self.allow_batching(): + return await self.handle_batching_request( + prompt, "chat", *args, **kwargs ) - return response - raise AttributeError(f"Model {self._model.model_spec} is not for chat.") + else: + kwargs.pop("raw_params", None) + if hasattr(self._model, "chat"): + response = await self._call_wrapper_json( + self._model.chat, prompt, *args, **kwargs + ) + return response + if hasattr(self._model, "async_chat"): + response = await self._call_wrapper_json( + self._model.async_chat, prompt, *args, **kwargs + ) + return response + raise AttributeError(f"Model {self._model.model_spec} is not for chat.") finally: # For the non stream result. - if response is not None and isinstance(response, dict): - usage = response["usage"] + record = None + if isinstance(response, Generator) or isinstance(response, AsyncGenerator): + record = response + elif isinstance(response, bytes): + record = json.loads(response) + if record and isinstance(record, dict): + usage = record["usage"] # Some backends may not have a valid usage, we just skip them. completion_tokens = usage["completion_tokens"] prompt_tokens = usage["prompt_tokens"] @@ -390,11 +556,20 @@ async def chat(self, prompt: str, *args, **kwargs): prompt_tokens, ) + async def abort_request(self, request_id: str) -> str: + from .scheduler import AbortRequestMessage + + if self.allow_batching(): + if self._scheduler_ref is None: + return AbortRequestMessage.NOT_FOUND.name + return await self._scheduler_ref.abort_request(request_id) + return AbortRequestMessage.NO_OP.name + @log_async(logger=logger) @request_limit async def create_embedding(self, input: Union[str, List[str]], *args, **kwargs): if hasattr(self._model, "create_embedding"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.create_embedding, input, *args, **kwargs ) @@ -411,17 +586,19 @@ async def rerank( top_n: Optional[int], max_chunks_per_doc: Optional[int], return_documents: Optional[bool], + return_len: Optional[bool], *args, **kwargs, ): if hasattr(self._model, "rerank"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.rerank, documents, query, top_n, max_chunks_per_doc, return_documents, + return_len, *args, **kwargs, ) @@ -436,15 +613,17 @@ async def transcriptions( prompt: Optional[str] = None, response_format: str = "json", temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, ): if hasattr(self._model, "transcriptions"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.transcriptions, audio, language, prompt, response_format, temperature, + timestamp_granularities, ) raise AttributeError( f"Model {self._model.model_spec} is not for creating transcriptions." @@ -455,22 +634,55 @@ async def transcriptions( async def translations( self, audio: bytes, + language: Optional[str] = None, prompt: Optional[str] = None, response_format: str = "json", temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, ): if hasattr(self._model, "translations"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.translations, audio, + language, prompt, response_format, temperature, + timestamp_granularities, ) raise AttributeError( f"Model {self._model.model_spec} is not for creating translations." ) + @log_async( + logger=logger, + args_formatter=lambda _, kwargs: kwargs.pop("prompt_speech", None), + ) + @request_limit + @xo.generator + async def speech( + self, + input: str, + voice: str, + response_format: str = "mp3", + speed: float = 1.0, + stream: bool = False, + **kwargs, + ): + if hasattr(self._model, "speech"): + return await self._call_wrapper_binary( + self._model.speech, + input, + voice, + response_format, + speed, + stream, + **kwargs, + ) + raise AttributeError( + f"Model {self._model.model_spec} is not for creating speech." + ) + @log_async(logger=logger) @request_limit async def text_to_image( @@ -483,7 +695,7 @@ async def text_to_image( **kwargs, ): if hasattr(self._model, "text_to_image"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.text_to_image, prompt, n, @@ -502,13 +714,13 @@ async def image_to_image( prompt: str, negative_prompt: str, n: int = 1, - size: str = "1024*1024", + size: Optional[str] = None, response_format: str = "url", *args, **kwargs, ): if hasattr(self._model, "image_to_image"): - return await self._call_wrapper( + return await self._call_wrapper_json( self._model.image_to_image, image, prompt, @@ -523,6 +735,71 @@ async def image_to_image( f"Model {self._model.model_spec} is not for creating image." ) + async def inpainting( + self, + image: "PIL.Image", + mask_image: "PIL.Image", + prompt: str, + negative_prompt: str, + n: int = 1, + size: str = "1024*1024", + response_format: str = "url", + *args, + **kwargs, + ): + if hasattr(self._model, "inpainting"): + return await self._call_wrapper_json( + self._model.inpainting, + image, + mask_image, + prompt, + negative_prompt, + n, + size, + response_format, + *args, + **kwargs, + ) + raise AttributeError( + f"Model {self._model.model_spec} is not for creating image." + ) + + @log_async(logger=logger) + @request_limit + async def infer( + self, + **kwargs, + ): + if hasattr(self._model, "infer"): + return await self._call_wrapper_json( + self._model.infer, + **kwargs, + ) + raise AttributeError( + f"Model {self._model.model_spec} is not for flexible infer." + ) + + @log_async(logger=logger) + @request_limit + async def text_to_video( + self, + prompt: str, + n: int = 1, + *args, + **kwargs, + ): + if hasattr(self._model, "text_to_video"): + return await self._call_wrapper_json( + self._model.text_to_video, + prompt, + n, + *args, + **kwargs, + ) + raise AttributeError( + f"Model {self._model.model_spec} is not for creating video." + ) + async def record_metrics(self, name, op, kwargs): worker_ref = await self._get_worker_ref() await worker_ref.record_metrics(name, op, kwargs) diff --git a/xinference/core/scheduler.py b/xinference/core/scheduler.py new file mode 100644 index 0000000000..6b28f70259 --- /dev/null +++ b/xinference/core/scheduler.py @@ -0,0 +1,457 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import asyncio +import functools +import logging +import uuid +from collections import deque +from enum import Enum +from typing import List, Optional, Set, Tuple + +import xoscar as xo + +logger = logging.getLogger(__name__) + +XINFERENCE_STREAMING_DONE_FLAG = "" +XINFERENCE_STREAMING_ERROR_FLAG = "" +XINFERENCE_STREAMING_ABORT_FLAG = "" +XINFERENCE_NON_STREAMING_ABORT_FLAG = "" + + +class AbortRequestMessage(Enum): + NOT_FOUND = 1 + DONE = 2 + NO_OP = 3 + + +class InferenceRequest: + def __init__(self, prompt, future_or_queue, is_prefill, *args, **kwargs): + # original prompt + self._prompt = prompt + # full prompt that contains chat history and applies chat template + self._full_prompt = None + # whether the current request is in the prefill phase + self._is_prefill = is_prefill + # full prompt tokens + self._prompt_tokens = None + # all new generated tokens during decode phase + self._new_tokens = [] + # kv_cache used in decode phase + self._kv_cache = None + # use passed args from upstream interface + self._inference_args = args + # use passed kwargs from upstream interface, currently for getting raw generate config from upstream, + # which is useful for some special models + self._inference_kwargs = kwargs + # should this request be stopped + self._stopped = False + # finish reason. If this is set, self._stopped is True. + self._finish_reason = None + # should this request be aborted + # note that when this flag is True, assert self._stopped is True + self._aborted = False + # sanitized generate config + self._sanitized_generate_config = None + # Chunk id for results. In stream mode, all the chunk ids should be same. + self._stream_chunk_id = str(uuid.uuid4()) + # For calculate attention mask if needed + self.padding_len = 0 + # Use in stream mode + self.last_output_length = 0 + # inference results, + # it is a list type because when stream=True, + # self.completion contains all the results in a decode round. + self.completion = [] + # The way upstream gets the returned results, + # when stream=True, it is an asyncio.Queue, + # and when stream=False, it is an asyncio future. + self.future_or_queue = future_or_queue + # Record error message when this request has error. + # Must set stopped=True when this field is set. + self.error_msg: Optional[str] = None # type: ignore + # For compatibility. Record some extra parameters for some special cases. + self.extra_kwargs = {} + + # check the integrity of args passed upstream + self._check_args() + + def _check_args(self): + # chat + if len(self._inference_args) == 3: + # system prompt + assert self._inference_args[0] is None or isinstance( + self._inference_args[0], str + ) + # chat history + assert self._inference_args[1] is None or isinstance( + self._inference_args[1], list + ) + # generate config + assert self._inference_args[2] is None or isinstance( + self._inference_args[2], dict + ) + else: # generate + assert len(self._inference_args) == 1 + # generate config + assert self._inference_args[0] is None or isinstance( + self._inference_args[0], dict + ) + + @property + def prompt(self): + return self._prompt + + @property + def system_prompt(self): + return self._inference_args[0] + + @property + def chat_history(self): + return self._inference_args[1] + + @property + def full_prompt(self): + return self._full_prompt + + @full_prompt.setter + def full_prompt(self, value: str): + self._full_prompt = value + + @property + def is_prefill(self): + return self._is_prefill + + @is_prefill.setter + def is_prefill(self, value: bool): + self._is_prefill = value + + @property + def prompt_tokens(self): + return self._prompt_tokens + + @prompt_tokens.setter + def prompt_tokens(self, value: List[int]): + self._prompt_tokens = value + + @property + def kv_cache(self): + return self._kv_cache + + @kv_cache.setter + def kv_cache(self, value): + self._kv_cache = value + + @property + def new_tokens(self): + return self._new_tokens + + def append_new_token(self, token: int): + self._new_tokens.append(token) + + @property + def generate_config(self): + return ( + self._inference_args[2] + if len(self._inference_args) == 3 + else self._inference_args[0] + ) + + @property + def sanitized_generate_config(self): + return self._sanitized_generate_config + + @sanitized_generate_config.setter + def sanitized_generate_config(self, value: dict): + self._sanitized_generate_config = value + + @property + def inference_kwargs(self): + return self._inference_kwargs + + @property + def stopped(self): + return self._stopped + + @stopped.setter + def stopped(self, value: bool): + self._stopped = value + + @property + def finish_reason(self): + return self._finish_reason + + @finish_reason.setter + def finish_reason(self, value: Optional[str]): + self._finish_reason = value + + @property + def chunk_id(self): + return self._stream_chunk_id + + @property + def stream(self) -> bool: + return ( + False + if self.generate_config is None + else self.generate_config.get("stream", False) + ) + + @property + def stream_interval(self) -> int: + return self.sanitized_generate_config.get("stream_interval", 2) + + @property + def include_usage(self) -> bool: + stream_options = self.sanitized_generate_config.get("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + return include_usage + + @property + def aborted(self) -> bool: + return self._aborted + + @aborted.setter + def aborted(self, value: bool): + self._aborted = value + + @property + def request_id(self) -> Optional[str]: + return ( + None + if self.generate_config is None + else self.generate_config.get("request_id", None) + ) + + @functools.lru_cache + def get_generate_configs( + self, eos_token_id: int, builtin_stop_token_ids: Optional[Tuple[int]] = None + ): + from ..types import max_tokens_field + + max_new_tokens = int( + self.sanitized_generate_config.get("max_tokens", max_tokens_field.default) + ) + stream_interval = self.sanitized_generate_config.get("stream_interval", 2) + include_usage = self.include_usage + stop_str = self.sanitized_generate_config.get("stop", None) + stop_token_ids = ( + self.sanitized_generate_config.get("stop_token_ids", None) or [] + ) + stop_token_ids = set(stop_token_ids) + stop_token_ids.add(eos_token_id) + stop_token_ids.update(builtin_stop_token_ids or []) + temperature = float(self.sanitized_generate_config.get("temperature", 1.0)) + repetition_penalty = float( + self.sanitized_generate_config.get("repetition_penalty", 1.0) + ) + top_p = float(self.sanitized_generate_config.get("top_p", 1.0)) + top_k = int(self.sanitized_generate_config.get("top_k", -1)) # -1 means disable + return ( + max_new_tokens, + stream_interval, + include_usage, + stop_str, + stop_token_ids, + temperature, + repetition_penalty, + top_p, + top_k, + ) + + +def _get_valid_batch_kv_cache(data, skipped_indexes: Set[int]): + from transformers.cache_utils import DynamicCache + + cache = DynamicCache.from_legacy_cache(data) + batch_size = cache.key_cache[0].shape[0] + batch_slices = [num for num in range(batch_size) if num not in skipped_indexes] + for idx in range(len(cache)): + cache.key_cache[idx] = cache.key_cache[idx][batch_slices, ::] + cache.value_cache[idx] = cache.value_cache[idx][batch_slices, ::] + return cache.to_legacy_cache() + + +class SchedulerActor(xo.StatelessActor): + @classmethod + def gen_uid(cls, model_uid: str, replica_id: str): + return f"{model_uid}-{replica_id}-scheduler-actor" + + def __init__(self): + super().__init__() + self._waiting_queue: deque[InferenceRequest] = deque() # type: ignore + self._running_queue: deque[InferenceRequest] = deque() # type: ignore + self._model = None + self._id_to_req = {} + self._abort_req_ids: Set[str] = set() # type: ignore + self._isolation = None + + async def __post_create__(self): + from ..isolation import Isolation + + self._isolation = Isolation( + asyncio.new_event_loop(), threaded=True, daemon=True + ) + self._isolation.start() + asyncio.run_coroutine_threadsafe(self.run(), loop=self._isolation.loop) + + async def __pre_destroy__(self): + try: + assert self._isolation is not None + self._isolation.stop() + del self._isolation + except Exception as e: + logger.debug( + f"Destroy scheduler actor failed, address: {self.address}, error: {e}" + ) + + def set_model(self, model): + self._model = model + + def get_max_num_seqs(self): + assert self._model is not None + return self._model.get_max_num_seqs() + + def _check_request_aborted(self, req: InferenceRequest): + if req.request_id and req.request_id in self._abort_req_ids: + req.aborted = True + req.stopped = True + + def _handle_request(self) -> Optional[List[InferenceRequest]]: + if self._model is None: + return None + max_num_seqs = self.get_max_num_seqs() + # currently, FCFS strategy + running_list: List[InferenceRequest] = [] + while len(self._running_queue) > 0: + if len(running_list) == max_num_seqs: + break + req = self._running_queue.popleft() + self._check_request_aborted(req) + running_list.append(req) + + waiting_list: List[InferenceRequest] = [] + if len(running_list) < max_num_seqs: + while len(self._waiting_queue) > 0: + req = self._waiting_queue.popleft() + self._check_request_aborted(req) + waiting_list.append(req) + if len(running_list) + len(waiting_list) == max_num_seqs: + break + # must waiting_list in front + return waiting_list + running_list + + @staticmethod + def _empty_cache(): + from ..model.llm.transformers.utils import empty_cache + + empty_cache() + + async def step(self): + req_list = self._handle_request() + if not req_list: + return + self._model.batch_inference(req_list) + + stopped_batch_indexes = set() + for idx, r in enumerate(req_list): + if r.stream: + for completion in r.completion: + await r.future_or_queue.put(completion) + r.completion = [] + + if not r.stopped: + self._running_queue.append(r) + else: + if r.new_tokens: + stopped_batch_indexes.add(idx) + # set kv_cache to None for collection + r.kv_cache = None + rid = r.request_id + # clear data structure + if rid is not None: + self._id_to_req.pop(rid, None) + self._abort_req_ids.discard(rid) + + if r.aborted: # stop due to abort + # handle abort result + if r.stream: + await r.future_or_queue.put(XINFERENCE_STREAMING_ABORT_FLAG) + else: + r.future_or_queue.set_result( + XINFERENCE_NON_STREAMING_ABORT_FLAG + ) + else: + if r.error_msg is None: # normal stop + if not r.stream: + r.future_or_queue.set_result(r.completion[0]) + else: + await r.future_or_queue.put(XINFERENCE_STREAMING_DONE_FLAG) + # Abnormal stop, currently indicates that the parameter check does not pass, + # and does not participate in the inference + else: + if not r.stream: + r.future_or_queue.set_exception(ValueError(r.error_msg)) + else: + await r.future_or_queue.put( + XINFERENCE_STREAMING_ERROR_FLAG + r.error_msg + ) + + # Some requests have been completed. Batch size needs to be reduced for kv cache. + if stopped_batch_indexes and len(self._running_queue) > 0: + kv_cache = self._running_queue[0].kv_cache + reduced_kv_cache = _get_valid_batch_kv_cache( + kv_cache, stopped_batch_indexes + ) + for r in self._running_queue: + r.kv_cache = reduced_kv_cache + + self._empty_cache() + + async def add_request(self, prompt: str, future_or_queue, *args, **kwargs): + req = InferenceRequest(prompt, future_or_queue, True, *args, **kwargs) + rid = req.request_id + if rid is not None: + if rid in self._id_to_req: + raise KeyError(f"Request id: {rid} has already existed!") + self._id_to_req[rid] = req + self._waiting_queue.append(req) + + async def abort_request(self, req_id: str) -> str: + """ + Abort a request. + Abort a submitted request. If the request is finished or not found, this method will be a no-op. + """ + if req_id not in self._id_to_req: + logger.info(f"Request id: {req_id} not found. No-op for xinference.") + return AbortRequestMessage.NOT_FOUND.name + else: + self._abort_req_ids.add(req_id) + logger.info(f"Request id: {req_id} found to be aborted.") + return AbortRequestMessage.DONE.name + + async def run(self): + try: + while True: + # wait 10ms + await asyncio.sleep(0.01) + await self.step() + except Exception as e: + logger.exception( + f"Scheduler actor uid: {self.uid}, address: {self.address} run with error: {e}" + ) diff --git a/xinference/core/status_guard.py b/xinference/core/status_guard.py index 1bd8010b8d..d348730869 100644 --- a/xinference/core/status_guard.py +++ b/xinference/core/status_guard.py @@ -48,7 +48,7 @@ def update(self, **kwargs): class StatusGuardActor(xo.StatelessActor): def __init__(self): super().__init__() - self._model_uid_to_info: Dict[str, InstanceInfo] = {} + self._model_uid_to_info: Dict[str, InstanceInfo] = {} # type: ignore @classmethod def uid(cls) -> str: diff --git a/xinference/core/supervisor.py b/xinference/core/supervisor.py index c8837f7a84..2b6f7b9fc5 100644 --- a/xinference/core/supervisor.py +++ b/xinference/core/supervisor.py @@ -14,11 +14,23 @@ import asyncio import itertools +import os +import signal import time import typing from dataclasses import dataclass from logging import getLogger -from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple, Union +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Iterator, + List, + Literal, + Optional, + Tuple, + Union, +) import xoscar as xo @@ -28,11 +40,13 @@ XINFERENCE_HEALTH_CHECK_INTERVAL, XINFERENCE_HEALTH_CHECK_TIMEOUT, ) -from ..core import ModelActor +from ..core.model import ModelActor from ..core.status_guard import InstanceInfo, LaunchStatus +from ..types import PeftModelConfig from .metrics import record_metrics from .resource import GPUStatus, ResourceStatus from .utils import ( + assign_replica_gpu, build_replica_model_uid, gen_random_string, is_valid_model_uid, @@ -46,9 +60,11 @@ if TYPE_CHECKING: from ..model.audio import AudioModelFamilyV1 from ..model.embedding import EmbeddingModelSpec + from ..model.flexible import FlexibleModelSpec from ..model.image import ImageModelFamilyV1 from ..model.llm import LLMFamilyV1 from ..model.rerank import RerankModelSpec + from ..model.video import VideoModelFamilyV1 from .worker import WorkerActor @@ -79,12 +95,12 @@ class ReplicaInfo: class SupervisorActor(xo.StatelessActor): def __init__(self): super().__init__() - self._worker_address_to_worker: Dict[str, xo.ActorRefType["WorkerActor"]] = {} - self._worker_status: Dict[str, WorkerStatus] = {} - self._replica_model_uid_to_worker: Dict[ + self._worker_address_to_worker: Dict[str, xo.ActorRefType["WorkerActor"]] = {} # type: ignore + self._worker_status: Dict[str, WorkerStatus] = {} # type: ignore + self._replica_model_uid_to_worker: Dict[ # type: ignore str, xo.ActorRefType["WorkerActor"] ] = {} - self._model_uid_to_replica_info: Dict[str, ReplicaInfo] = {} + self._model_uid_to_replica_info: Dict[str, ReplicaInfo] = {} # type: ignore self._uptime = None self._lock = asyncio.Lock() @@ -116,12 +132,12 @@ async def __post_create__(self): from .cache_tracker import CacheTrackerActor from .status_guard import StatusGuardActor - self._status_guard_ref: xo.ActorRefType[ + self._status_guard_ref: xo.ActorRefType[ # type: ignore "StatusGuardActor" ] = await xo.create_actor( StatusGuardActor, address=self.address, uid=StatusGuardActor.uid() ) - self._cache_tracker_ref: xo.ActorRefType[ + self._cache_tracker_ref: xo.ActorRefType[ # type: ignore "CacheTrackerActor" ] = await xo.create_actor( CacheTrackerActor, address=self.address, uid=CacheTrackerActor.uid() @@ -129,12 +145,19 @@ async def __post_create__(self): from .event import EventCollectorActor - self._event_collector_ref: xo.ActorRefType[ + self._event_collector_ref: xo.ActorRefType[ # type: ignore EventCollectorActor ] = await xo.create_actor( EventCollectorActor, address=self.address, uid=EventCollectorActor.uid() ) + from ..model.audio import ( + CustomAudioModelFamilyV1, + generate_audio_description, + get_audio_model_descriptions, + register_audio, + unregister_audio, + ) from ..model.embedding import ( CustomEmbeddingModelSpec, generate_embedding_description, @@ -142,7 +165,20 @@ async def __post_create__(self): register_embedding, unregister_embedding, ) - from ..model.image import get_image_model_descriptions + from ..model.flexible import ( + FlexibleModelSpec, + generate_flexible_model_description, + get_flexible_model_descriptions, + register_flexible_model, + unregister_flexible_model, + ) + from ..model.image import ( + CustomImageModelFamilyV1, + generate_image_description, + get_image_model_descriptions, + register_image, + unregister_image, + ) from ..model.llm import ( CustomLLMFamilyV1, generate_llm_description, @@ -158,7 +194,7 @@ async def __post_create__(self): unregister_rerank, ) - self._custom_register_type_to_cls: Dict[str, Tuple] = { + self._custom_register_type_to_cls: Dict[str, Tuple] = { # type: ignore "LLM": ( CustomLLMFamilyV1, register_llm, @@ -177,18 +213,49 @@ async def __post_create__(self): unregister_rerank, generate_rerank_description, ), + "image": ( + CustomImageModelFamilyV1, + register_image, + unregister_image, + generate_image_description, + ), + "audio": ( + CustomAudioModelFamilyV1, + register_audio, + unregister_audio, + generate_audio_description, + ), + "flexible": ( + FlexibleModelSpec, + register_flexible_model, + unregister_flexible_model, + generate_flexible_model_description, + ), } # record model version - model_version_infos: Dict[str, List[Dict]] = {} + model_version_infos: Dict[str, List[Dict]] = {} # type: ignore model_version_infos.update(get_llm_model_descriptions()) model_version_infos.update(get_embedding_model_descriptions()) model_version_infos.update(get_rerank_model_descriptions()) model_version_infos.update(get_image_model_descriptions()) + model_version_infos.update(get_audio_model_descriptions()) + model_version_infos.update(get_flexible_model_descriptions()) await self._cache_tracker_ref.record_model_version( model_version_infos, self.address ) + # Windows does not have signal handler + if os.name != "nt": + + async def signal_handler(): + os._exit(0) + + loop = asyncio.get_running_loop() + loop.add_signal_handler( + signal.SIGTERM, lambda: asyncio.create_task(signal_handler()) + ) + @typing.no_type_check async def get_cluster_device_info(self, detailed: bool = False) -> List: import psutil @@ -257,7 +324,7 @@ async def get_builtin_families() -> Dict[str, List[str]]: return { "chat": list(BUILTIN_LLM_MODEL_CHAT_FAMILIES), "generate": list(BUILTIN_LLM_MODEL_GENERATE_FAMILIES), - "tool_call": list(BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES), + "tools": list(BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES), } async def get_devices_count(self) -> int: @@ -418,6 +485,52 @@ async def _to_audio_model_reg( res["model_instance_count"] = instance_cnt return res + async def _to_video_model_reg( + self, model_family: "VideoModelFamilyV1", is_builtin: bool + ) -> Dict[str, Any]: + from ..model.video import get_cache_status + + instance_cnt = await self.get_instance_count(model_family.model_name) + version_cnt = await self.get_model_version_count(model_family.model_name) + + if self.is_local_deployment(): + # TODO: does not work when the supervisor and worker are running on separate nodes. + cache_status = get_cache_status(model_family) + res = { + **model_family.dict(), + "cache_status": cache_status, + "is_builtin": is_builtin, + } + else: + res = { + **model_family.dict(), + "is_builtin": is_builtin, + } + res["model_version_count"] = version_cnt + res["model_instance_count"] = instance_cnt + return res + + async def _to_flexible_model_reg( + self, model_spec: "FlexibleModelSpec", is_builtin: bool + ) -> Dict[str, Any]: + instance_cnt = await self.get_instance_count(model_spec.model_name) + version_cnt = await self.get_model_version_count(model_spec.model_name) + + if self.is_local_deployment(): + res = { + **model_spec.dict(), + "cache_status": True, + "is_builtin": is_builtin, + } + else: + res = { + **model_spec.dict(), + "is_builtin": is_builtin, + } + res["model_version_count"] = version_cnt + res["model_instance_count"] = instance_cnt + return res + @log_async(logger=logger) async def list_model_registrations( self, model_type: str, detailed: bool = False @@ -426,10 +539,15 @@ def sort_helper(item): assert isinstance(item["model_name"], str) return item.get("model_name").lower() + ret = [] + if not self.is_local_deployment(): + workers = list(self._worker_address_to_worker.values()) + for worker in workers: + ret.extend(await worker.list_model_registrations(model_type, detailed)) + if model_type == "LLM": from ..model.llm import BUILTIN_LLM_FAMILIES, get_user_defined_llm_families - ret = [] for family in BUILTIN_LLM_FAMILIES: if detailed: ret.append(await self._to_llm_reg(family, True)) @@ -448,7 +566,6 @@ def sort_helper(item): from ..model.embedding import BUILTIN_EMBEDDING_MODELS from ..model.embedding.custom import get_user_defined_embeddings - ret = [] for model_name, family in BUILTIN_EMBEDDING_MODELS.items(): if detailed: ret.append( @@ -471,33 +588,63 @@ def sort_helper(item): return ret elif model_type == "image": from ..model.image import BUILTIN_IMAGE_MODELS + from ..model.image.custom import get_user_defined_images - ret = [] for model_name, family in BUILTIN_IMAGE_MODELS.items(): if detailed: ret.append(await self._to_image_model_reg(family, is_builtin=True)) else: ret.append({"model_name": model_name, "is_builtin": True}) + for model_spec in get_user_defined_images(): + if detailed: + ret.append( + await self._to_image_model_reg(model_spec, is_builtin=False) + ) + else: + ret.append( + {"model_name": model_spec.model_name, "is_builtin": False} + ) + ret.sort(key=sort_helper) return ret elif model_type == "audio": from ..model.audio import BUILTIN_AUDIO_MODELS + from ..model.audio.custom import get_user_defined_audios - ret = [] for model_name, family in BUILTIN_AUDIO_MODELS.items(): if detailed: ret.append(await self._to_audio_model_reg(family, is_builtin=True)) else: ret.append({"model_name": model_name, "is_builtin": True}) + for model_spec in get_user_defined_audios(): + if detailed: + ret.append( + await self._to_audio_model_reg(model_spec, is_builtin=False) + ) + else: + ret.append( + {"model_name": model_spec.model_name, "is_builtin": False} + ) + + ret.sort(key=sort_helper) + return ret + elif model_type == "video": + from ..model.video import BUILTIN_VIDEO_MODELS + + for model_name, family in BUILTIN_VIDEO_MODELS.items(): + if detailed: + ret.append(await self._to_video_model_reg(family, is_builtin=True)) + else: + ret.append({"model_name": model_name, "is_builtin": True}) + ret.sort(key=sort_helper) return ret elif model_type == "rerank": from ..model.rerank import BUILTIN_RERANK_MODELS from ..model.rerank.custom import get_user_defined_reranks - ret = [] for model_name, family in BUILTIN_RERANK_MODELS.items(): if detailed: ret.append(await self._to_rerank_model_reg(family, is_builtin=True)) @@ -514,13 +661,38 @@ def sort_helper(item): {"model_name": model_spec.model_name, "is_builtin": False} ) + ret.sort(key=sort_helper) + return ret + elif model_type == "flexible": + from ..model.flexible import get_flexible_models + + ret = [] + + for model_spec in get_flexible_models(): + if detailed: + ret.append( + await self._to_flexible_model_reg(model_spec, is_builtin=False) + ) + else: + ret.append( + {"model_name": model_spec.model_name, "is_builtin": False} + ) + ret.sort(key=sort_helper) return ret else: raise ValueError(f"Unsupported model type: {model_type}") @log_sync(logger=logger) - def get_model_registration(self, model_type: str, model_name: str) -> Any: + async def get_model_registration(self, model_type: str, model_name: str) -> Any: + # search in worker first + if not self.is_local_deployment(): + workers = list(self._worker_address_to_worker.values()) + for worker in workers: + f = await worker.get_model_registration(model_type, model_name) + if f is not None: + return f + if model_type == "LLM": from ..model.llm import BUILTIN_LLM_FAMILIES, get_user_defined_llm_families @@ -541,15 +713,17 @@ def get_model_registration(self, model_type: str, model_name: str) -> Any: raise ValueError(f"Model {model_name} not found") elif model_type == "image": from ..model.image import BUILTIN_IMAGE_MODELS + from ..model.image.custom import get_user_defined_images - for f in BUILTIN_IMAGE_MODELS.values(): + for f in list(BUILTIN_IMAGE_MODELS.values()) + get_user_defined_images(): if f.model_name == model_name: return f raise ValueError(f"Model {model_name} not found") elif model_type == "audio": from ..model.audio import BUILTIN_AUDIO_MODELS + from ..model.audio.custom import get_user_defined_audios - for f in BUILTIN_AUDIO_MODELS.values(): + for f in list(BUILTIN_AUDIO_MODELS.values()) + get_user_defined_audios(): if f.model_name == model_name: return f raise ValueError(f"Model {model_name} not found") @@ -561,11 +735,49 @@ def get_model_registration(self, model_type: str, model_name: str) -> Any: if f.model_name == model_name: return f raise ValueError(f"Model {model_name} not found") + elif model_type == "flexible": + from ..model.flexible import get_flexible_models + + for f in get_flexible_models(): + if f.model_name == model_name: + return f + raise ValueError(f"Model {model_name} not found") else: raise ValueError(f"Unsupported model type: {model_type}") @log_async(logger=logger) - async def register_model(self, model_type: str, model: str, persist: bool): + async def query_engines_by_model_name(self, model_name: str): + from copy import deepcopy + + from ..model.llm.llm_family import LLM_ENGINES + + # search in worker first + workers = list(self._worker_address_to_worker.values()) + for worker in workers: + res = await worker.query_engines_by_model_name(model_name) + if res is not None: + return res + + if model_name not in LLM_ENGINES: + raise ValueError(f"Model {model_name} not found") + + # filter llm_class + engine_params = deepcopy(LLM_ENGINES[model_name]) + for engine in engine_params: + params = engine_params[engine] + for param in params: + del param["llm_class"] + + return engine_params + + @log_async(logger=logger) + async def register_model( + self, + model_type: str, + model: str, + persist: bool, + worker_ip: Optional[str] = None, + ): if model_type in self._custom_register_type_to_cls: ( model_spec_cls, @@ -574,10 +786,21 @@ async def register_model(self, model_type: str, model: str, persist: bool): generate_fn, ) = self._custom_register_type_to_cls[model_type] - if not self.is_local_deployment(): - workers = list(self._worker_address_to_worker.values()) - for worker in workers: - await worker.register_model(model_type, model, persist) + target_ip_worker_ref = ( + self._get_worker_ref_by_ip(worker_ip) if worker_ip is not None else None + ) + if ( + worker_ip is not None + and not self.is_local_deployment() + and target_ip_worker_ref is None + ): + raise ValueError( + f"Worker ip address {worker_ip} is not in the cluster." + ) + + if target_ip_worker_ref: + await target_ip_worker_ref.register_model(model_type, model, persist) + return model_spec = model_spec_cls.parse_raw(model) try: @@ -585,6 +808,8 @@ async def register_model(self, model_type: str, model: str, persist: bool): await self._cache_tracker_ref.record_model_version( generate_fn(model_spec), self.address ) + except ValueError as e: + raise e except Exception as e: unregister_fn(model_spec.model_name, raise_error=False) raise e @@ -595,13 +820,14 @@ async def register_model(self, model_type: str, model: str, persist: bool): async def unregister_model(self, model_type: str, model_name: str): if model_type in self._custom_register_type_to_cls: _, _, unregister_fn, _ = self._custom_register_type_to_cls[model_type] - unregister_fn(model_name) - await self._cache_tracker_ref.unregister_model_version(model_name) + unregister_fn(model_name, False) if not self.is_local_deployment(): workers = list(self._worker_address_to_worker.values()) for worker in workers: - await worker.unregister_model(model_name) + await worker.unregister_model(model_type, model_name) + + await self._cache_tracker_ref.unregister_model_version(model_name) else: raise ValueError(f"Unsupported model type: {model_type}") @@ -624,6 +850,7 @@ async def launch_model_by_version( self, model_uid: Optional[str], model_type: str, + model_engine: Optional[str], model_version: str, replica: int = 1, n_gpu: Optional[Union[int, str]] = "auto", @@ -639,6 +866,7 @@ async def launch_model_by_version( return await self.launch_builtin_model( model_uid=model_uid, model_name=parse_results[0], + model_engine=model_engine, model_size_in_billions=parse_results[1] if model_type == "LLM" else None, model_format=parse_results[2] if model_type == "LLM" else None, quantization=parse_results[3] if model_type == "LLM" else None, @@ -650,86 +878,35 @@ async def launch_model_by_version( **kwargs, ) - async def launch_speculative_llm( - self, - model_uid: Optional[str], - model_name: str, - model_size_in_billions: Optional[int], - quantization: Optional[str], - draft_model_name: str, - draft_model_size_in_billions: Optional[int], - draft_quantization: Optional[str], - n_gpu: Optional[Union[int, str]] = "auto", - ) -> str: - if model_uid is None: - model_uid = self._gen_model_uid(model_name) - logger.debug( - ( - f"Enter launch_speculative_llm, model_uid: %s, model_name: %s, model_size: %s, " - f"draft_model_name: %s, draft_model_size: %s" - ), - model_uid, - model_name, - str(model_size_in_billions) if model_size_in_billions else "", - draft_model_name, - draft_model_size_in_billions, - ) - - # TODO: the draft and target model must be on the same worker. - if not self.is_local_deployment(): - raise ValueError( - "Speculative model is not supported in distributed deployment yet." - ) - - if model_uid in self._model_uid_to_replica_info: - raise ValueError(f"Model is already in the model list, uid: {model_uid}") - - worker_ref = await self._choose_worker() - replica = 1 - self._model_uid_to_replica_info[model_uid] = ReplicaInfo( - replica=replica, scheduler=itertools.cycle(range(replica)) - ) - - try: - rep_model_uid = f"{model_uid}-{1}-{0}" - await worker_ref.launch_speculative_model( - model_uid=rep_model_uid, - model_name=model_name, - model_size_in_billions=model_size_in_billions, - quantization=quantization, - draft_model_name=draft_model_name, - draft_model_size_in_billions=draft_model_size_in_billions, - draft_quantization=draft_quantization, - n_gpu=n_gpu, - ) - self._replica_model_uid_to_worker[rep_model_uid] = worker_ref - - except Exception: - # terminate_model will remove the replica info. - await self.terminate_model(model_uid, suppress_exception=True) - raise - return model_uid - async def launch_builtin_model( self, model_uid: Optional[str], model_name: str, - model_size_in_billions: Optional[int], + model_size_in_billions: Optional[Union[int, str]], model_format: Optional[str], quantization: Optional[str], + model_engine: Optional[str], model_type: Optional[str], replica: int = 1, n_gpu: Optional[Union[int, str]] = "auto", request_limits: Optional[int] = None, wait_ready: bool = True, model_version: Optional[str] = None, - peft_model_path: Optional[str] = None, - image_lora_load_kwargs: Optional[Dict] = None, - image_lora_fuse_kwargs: Optional[Dict] = None, + peft_model_config: Optional[PeftModelConfig] = None, worker_ip: Optional[str] = None, gpu_idx: Optional[Union[int, List[int]]] = None, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, **kwargs, ) -> str: + # search in worker first + if not self.is_local_deployment(): + workers = list(self._worker_address_to_worker.values()) + for worker in workers: + res = await worker.get_model_registration(model_type, model_name) + if res is not None: + worker_ip = worker.address.split(":")[0] + target_ip_worker_ref = ( self._get_worker_ref_by_ip(worker_ip) if worker_ip is not None else None ) @@ -745,13 +922,34 @@ async def launch_builtin_model( f"xinference will ignore this option." ) + if kwargs.get("enable_tensorizer", None) and ( + ( + model_engine is None + or model_engine.lower() != "transformers" + or model_format != "pytorch" + or quantization != "none" + or model_type != "LLM" + ) + ): + raise ValueError( + "Tensorizer can only be enabled for LLM models with Transformers engine, PyTorch format, and none quantization." + ) + + if kwargs.get("enable_tensorizer", None) and model_name in [ + "OmniLMM", + "yi-vl-chat", + "deepseek-vl-chat", + ]: + raise ValueError("Tensorizer is not supported for %s." % model_name) + if model_uid is None: model_uid = self._gen_model_uid(model_name) model_size = str(model_size_in_billions) if model_size_in_billions else "" logger.debug( f"Enter launch_builtin_model, model_uid: {model_uid}, model_name: {model_name}, model_size: {model_size}, " - f"model_format: {model_format}, quantization: {quantization}, replica: {replica}" + f"model_format: {model_format}, quantization: {quantization}, replica: {replica}, " + f"kwargs: {kwargs}" ) async def _launch_one_model(_replica_model_uid): @@ -759,8 +957,9 @@ async def _launch_one_model(_replica_model_uid): raise ValueError( f"Model is already in the model list, uid: {_replica_model_uid}" ) - + replica_gpu_idx = assign_replica_gpu(_replica_model_uid, gpu_idx) nonlocal model_type + worker_ref = ( target_ip_worker_ref if target_ip_worker_ref is not None @@ -774,13 +973,14 @@ async def _launch_one_model(_replica_model_uid): model_size_in_billions=model_size_in_billions, model_format=model_format, quantization=quantization, + model_engine=model_engine, model_type=model_type, n_gpu=n_gpu, request_limits=request_limits, - peft_model_path=peft_model_path, - image_lora_load_kwargs=image_lora_load_kwargs, - image_lora_fuse_kwargs=image_lora_fuse_kwargs, - gpu_idx=gpu_idx, + peft_model_config=peft_model_config, + gpu_idx=replica_gpu_idx, + download_hub=download_hub, + model_path=model_path, **kwargs, ) self._replica_model_uid_to_worker[_replica_model_uid] = worker_ref @@ -971,6 +1171,60 @@ def is_local_deployment(self) -> bool: and list(self._worker_address_to_worker)[0] == self.address ) + @log_async(logger=logger) + async def list_cached_models( + self, model_name: Optional[str] = None, worker_ip: Optional[str] = None + ) -> List[Dict[str, Any]]: + target_ip_worker_ref = ( + self._get_worker_ref_by_ip(worker_ip) if worker_ip is not None else None + ) + if ( + worker_ip is not None + and not self.is_local_deployment() + and target_ip_worker_ref is None + ): + raise ValueError(f"Worker ip address {worker_ip} is not in the cluster.") + + # search assigned worker and return + if target_ip_worker_ref: + cached_models = await target_ip_worker_ref.list_cached_models(model_name) + cached_models = sorted(cached_models, key=lambda x: x["model_name"]) + return cached_models + + # search all worker + cached_models = [] + for worker in self._worker_address_to_worker.values(): + res = await worker.list_cached_models(model_name) + cached_models.extend(res) + cached_models = sorted(cached_models, key=lambda x: x["model_name"]) + return cached_models + + @log_async(logger=logger) + async def abort_request(self, model_uid: str, request_id: str) -> Dict: + from .scheduler import AbortRequestMessage + + res = {"msg": AbortRequestMessage.NO_OP.name} + replica_info = self._model_uid_to_replica_info.get(model_uid, None) + if not replica_info: + return res + replica_cnt = replica_info.replica + + # Query all replicas + for rep_mid in iter_replica_model_uid(model_uid, replica_cnt): + worker_ref = self._replica_model_uid_to_worker.get(rep_mid, None) + if worker_ref is None: + continue + model_ref = await worker_ref.get_model(model_uid=rep_mid) + result_info = await model_ref.abort_request(request_id) + res["msg"] = result_info + if result_info == AbortRequestMessage.DONE.name: + break + elif result_info == AbortRequestMessage.NOT_FOUND.name: + logger.debug(f"Request id: {request_id} not found for model {rep_mid}") + else: + logger.debug(f"No-op for model {rep_mid}") + return res + @log_async(logger=logger) async def add_worker(self, worker_address: str): from .worker import WorkerActor @@ -1018,6 +1272,84 @@ async def report_worker_status( worker_status.update_time = time.time() worker_status.status = status + async def list_deletable_models( + self, model_version: str, worker_ip: Optional[str] = None + ) -> List[str]: + target_ip_worker_ref = ( + self._get_worker_ref_by_ip(worker_ip) if worker_ip is not None else None + ) + if ( + worker_ip is not None + and not self.is_local_deployment() + and target_ip_worker_ref is None + ): + raise ValueError(f"Worker ip address {worker_ip} is not in the cluster.") + + ret = [] + if target_ip_worker_ref: + ret = await target_ip_worker_ref.list_deletable_models( + model_version=model_version, + ) + return ret + + for worker in self._worker_address_to_worker.values(): + path = await worker.list_deletable_models(model_version=model_version) + ret.extend(path) + return ret + + async def confirm_and_remove_model( + self, model_version: str, worker_ip: Optional[str] = None + ) -> bool: + target_ip_worker_ref = ( + self._get_worker_ref_by_ip(worker_ip) if worker_ip is not None else None + ) + if ( + worker_ip is not None + and not self.is_local_deployment() + and target_ip_worker_ref is None + ): + raise ValueError(f"Worker ip address {worker_ip} is not in the cluster.") + + if target_ip_worker_ref: + ret = await target_ip_worker_ref.confirm_and_remove_model( + model_version=model_version, + ) + return ret + ret = True + for worker in self._worker_address_to_worker.values(): + ret = ret and await worker.confirm_and_remove_model( + model_version=model_version, + ) + return ret + + async def get_workers_info(self) -> List[Dict[str, Any]]: + ret = [] + for worker in self._worker_address_to_worker.values(): + ret.append(await worker.get_workers_info()) + return ret + + async def get_supervisor_info(self) -> Dict[str, Any]: + ret = { + "supervisor_ip": self.address, + } + return ret + + async def trigger_exit(self) -> bool: + try: + os.kill(os.getpid(), signal.SIGTERM) + except Exception as e: + logger.info(f"trigger exit error: {e}") + return False + return True + + async def abort_cluster(self) -> bool: + ret = True + for worker in self._worker_address_to_worker.values(): + ret = ret and await worker.trigger_exit() + + ret = ret and await self.trigger_exit() + return ret + @staticmethod def record_metrics(name, op, kwargs): record_metrics(name, op, kwargs) diff --git a/xinference/core/tests/test_continuous_batching.py b/xinference/core/tests/test_continuous_batching.py new file mode 100644 index 0000000000..f6db0362cf --- /dev/null +++ b/xinference/core/tests/test_continuous_batching.py @@ -0,0 +1,232 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +import sys +import threading +import time + +import pytest +import requests + +from ...client.restful.restful_client import Client as RESTfulClient +from ..scheduler import AbortRequestMessage + + +class BaseThread(threading.Thread): + def __init__(self): + super().__init__() + self._ex = None + + def run_internal(self): + super().run() + + def run(self): + try: + self.run_internal() + except BaseException as e: + self._ex = e + + def join(self, timeout=None): + super().join() + if self._ex is not None: + raise self._ex + + +class InferenceThread(BaseThread): + def __init__(self, prompt, generate_config, client, model): + super().__init__() + self._prompt = prompt + self._generate_config = generate_config + self._client = client + self._model = model + self._ex = None + + @property + def stream(self): + return self._generate_config.get("stream", False) + + def run_internal(self): + if self.stream: + results = [] + for res in self._model.chat( + self._prompt, generate_config=self._generate_config + ): + results.append(res) + assert len(results) > 0 + else: + res = self._model.chat(self._prompt, generate_config=self._generate_config) + assert isinstance(res, dict) + choices = res["choices"] + assert isinstance(choices, list) + choice = choices[0]["message"] + assert isinstance(choice, dict) + content = choice["content"] + assert len(content) > 0 + + +class InferenceThreadWithError(InferenceThread): + def __init__(self, prompt, generate_config, client, model, sleep=None): + super().__init__(prompt, generate_config, client, model) + self._sleep = sleep + + def run_internal(self): + if self._sleep is not None: + time.sleep(self._sleep) + if self.stream: + with pytest.raises(Exception): + for res in self._model.chat( + self._prompt, generate_config=self._generate_config + ): + print(res) + else: + with pytest.raises(Exception): + self._model.chat(self._prompt, generate_config=self._generate_config) + + +class AbortThread(BaseThread): + def __init__(self, client, model_uid, request_id, expected_res, sleep=None): + super().__init__() + self._client = client + self._model_uid = model_uid + self._request_id = request_id + self._sleep = sleep + self._expected_res = expected_res + + def run_internal(self): + if self._sleep is not None: + time.sleep(self._sleep) + result = self._client.abort_request(self._model_uid, self._request_id) + assert result["msg"] == self._expected_res + + +@pytest.fixture +def enable_batch(): + os.environ["XINFERENCE_TRANSFORMERS_ENABLE_BATCHING"] = "1" + yield + os.environ["XINFERENCE_TRANSFORMERS_ENABLE_BATCHING"] = "0" + + +@pytest.mark.skipif( + sys.platform == "win32", + reason="does not run on windows github CI due to its terrible runtime", +) +def test_continuous_batching(enable_batch, setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + client = RESTfulClient(endpoint) + + # launch + payload = { + "model_engine": "transformers", + "model_type": "LLM", + "model_name": "qwen1.5-chat", + "quantization": "none", + "model_format": "pytorch", + "model_size_in_billions": "0_5", + # here note that device must be `cpu` for macOS, + # since torch mps may have some issues for batch tensor calculation, + # see: https://github.com/pytorch/pytorch/issues/122030 and + # https://github.com/pytorch/pytorch/issues/126862 + "device": "cpu", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "qwen1.5-chat" + + model = client.get_model(model_uid_res) + + # test correct + thread1 = InferenceThread("1+1=3正确吗?", {"stream": True}, client, model) + thread2 = InferenceThread("中国的首都是哪座城市?", {"stream": False}, client, model) + thread1.start() + thread2.start() + thread1.join() + thread2.join() + + # test error generate config + with pytest.raises(RuntimeError): + model.chat("你好", generate_config={"max_tokens": 99999999999999999}) + + with pytest.raises(RuntimeError): + model.chat("你好", generate_config={"stream_interval": 0}) + + # test error with other correct requests + thread1 = InferenceThread("1+1=3正确吗?", {"stream": True}, client, model) + thread2 = InferenceThread("中国的首都是哪座城市?", {"stream": False}, client, model) + thread3 = InferenceThreadWithError( + "猫和狗有什么区别?", {"stream": True, "max_tokens": 99999999999999}, client, model + ) + thread4 = InferenceThreadWithError( + "简介篮球的发展历史。", {"stream": False, "stream_interval": 0}, client, model + ) + + thread1.start() + thread2.start() + thread3.start() + thread4.start() + thread1.join() + thread2.join() + thread3.join() + thread4.join() + + # test same request ids + thread1 = InferenceThread( + "1+1=3正确吗?", {"stream": True, "request_id": "aaabbb"}, client, model + ) + thread2 = InferenceThreadWithError( + "中国的首都是哪座城市?", {"stream": False, "request_id": "aaabbb"}, client, model, 0.03 + ) + thread1.start() + thread2.start() + thread1.join() + thread2.join() + + # test abort request for stream + thread1 = InferenceThread( + "猫和狗有什么区别吗?", {"stream": True, "request_id": "aaabbb"}, client, model + ) + thread2 = AbortThread( + client, model_uid_res, "bbbaaa", AbortRequestMessage.NOT_FOUND.name + ) + thread3 = AbortThread(client, "abcd", "aaabbb", AbortRequestMessage.NO_OP.name) + thread4 = AbortThread( + client, model_uid_res, "aaabbb", AbortRequestMessage.DONE.name, 0.01 + ) + thread1.start() + thread2.start() + thread3.start() + thread4.start() + with pytest.raises(Exception): + thread1.join() + thread2.join() + thread3.join() + thread4.join() + + # test abort request for non-stream + thread1 = InferenceThread("猫和狗有什么区别吗?", {"request_id": "aaabbb"}, client, model) + thread2 = AbortThread( + client, model_uid_res, "aaabbb", AbortRequestMessage.DONE.name, 0.01 + ) + thread1.start() + thread2.start() + with pytest.raises(Exception): + thread1.join() + thread2.join() + + # correctly terminate model + client.terminate_model(model_uid_res) diff --git a/xinference/core/tests/test_metrics.py b/xinference/core/tests/test_metrics.py index d02d41bd15..b6927b18c7 100644 --- a/xinference/core/tests/test_metrics.py +++ b/xinference/core/tests/test_metrics.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import os import pytest import requests @@ -44,7 +44,7 @@ def setup_cluster(): logging_conf=TEST_FILE_LOGGING_CONF, ) endpoint = f"http://localhost:{port}" - if not api_health_check(endpoint, max_attempts=3, sleep_interval=5): + if not api_health_check(endpoint, max_attempts=10, sleep_interval=5): raise RuntimeError("Endpoint is not available after multiple attempts") yield f"http://localhost:{port}", f"http://localhost:{metrics_port}/metrics", supervisor_address @@ -65,7 +65,10 @@ async def test_metrics_exporter_server(setup_cluster): client = Client(endpoint) model_uid = client.launch_model( - model_name="orca", model_size_in_billions=3, quantization="q4_0" + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", + quantization="q4_0", ) # Check the supervisor metrics collected the RESTful API. @@ -81,4 +84,62 @@ async def test_metrics_exporter_server(setup_cluster): ) response = requests.get(metrics_exporter_address) assert response.ok - assert 'xinference:input_tokens_total_counter{model="orca"} 1' in response.text + assert ( + 'xinference:input_tokens_total_counter{model="qwen1.5-chat"} 1' in response.text + ) + + +@pytest.fixture +def disable_metrics(): + try: + os.environ["XINFERENCE_DISABLE_METRICS"] = "1" + yield + finally: + os.environ.pop("XINFERENCE_DISABLE_METRICS", None) + + +@pytest.mark.asyncio +async def test_disable_metrics_exporter_server(disable_metrics, setup_cluster): + endpoint, metrics_exporter_address, supervisor_address = setup_cluster + + from ...client import Client + + client = Client(endpoint) + + client.launch_model( + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", + quantization="q4_0", + ) + + # Check the supervisor metrics collected the RESTful API. + response = requests.get(f"{endpoint}/metrics") + assert response.status_code == 404 + + # Check the worker metrics collected model metrics. + with pytest.raises(requests.exceptions.ConnectionError): + requests.get(metrics_exporter_address) + + +async def test_metrics_exporter_data(setup_cluster): + endpoint, metrics_exporter_address, supervisor_address = setup_cluster + + from ...client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="qwen1.5-chat", + model_engine="llama.cpp", + model_size_in_billions="0_5", + model_format="ggufv2", + quantization="q4_0", + ) + + model = client.get_model(model_uid) + response = model.chat("write a poem.") + + response = requests.get(metrics_exporter_address) + assert response.ok + assert 'format="ggufv2",model="qwen1.5-chat"' in response.text diff --git a/xinference/core/tests/test_restful_api.py b/xinference/core/tests/test_restful_api.py index 276b38f382..cd47b98cc5 100644 --- a/xinference/core/tests/test_restful_api.py +++ b/xinference/core/tests/test_restful_api.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import asyncio import json import os import os.path @@ -39,7 +39,9 @@ async def test_restful_api(setup): # launch payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", } @@ -51,7 +53,7 @@ async def test_restful_api(setup): # launch n_gpu error payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_name": "qwen1.5-chat", "quantization": "q4_0", "n_gpu": -1, } @@ -61,7 +63,7 @@ async def test_restful_api(setup): # same model uid payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_name": "qwen1.5-chat", "quantization": "q4_0", } response = requests.post(url, json=payload) @@ -75,7 +77,7 @@ async def test_restful_api(setup): # describe response = requests.get(f"{endpoint}/v1/models/test_restful_api") response_data = response.json() - assert response_data["model_name"] == "orca" + assert response_data["model_name"] == "qwen1.5-chat" assert response_data["replica"] == 1 response = requests.delete(f"{endpoint}/v1/models/bogus") @@ -104,6 +106,22 @@ async def test_restful_api(setup): response = requests.post(url, json=payload) assert response.status_code == 500 + # chat without user messages + url = f"{endpoint}/v1/chat/completions" + payload = { + "model": model_uid_res, + "messages": [ + { + "role": "system", + "content": "<任务> 识别用户输入的技术术语。请用{XXX} -> {XXX}的格式展示翻译前后的技术术语对应关系。\n<输入文本>\n今天天气\n<示例>\nTransformer -> Transformer\nToken -> Token\nZero Shot -> 零样本\nFew Shot -> 少样本\n<专有名词>", + } + ], + "stop": ["\n"], + } + response = requests.post(url, json=payload) + completion = response.json() + assert "content" in completion["choices"][0]["message"] + # chat url = f"{endpoint}/v1/chat/completions" payload = { @@ -413,11 +431,12 @@ def _check_invalid_tool_calls(endpoint, model_uid_res): @pytest.mark.parametrize( - "model_format, quantization", [("ggmlv3", "q4_0"), ("pytorch", None)] + "model_format, quantization", + [("pytorch", None)], ) @pytest.mark.skip(reason="Cost too many resources.") def test_restful_api_for_tool_calls(setup, model_format, quantization): - model_name = "chatglm3" + model_name = "glm4-chat" endpoint, _ = setup url = f"{endpoint}/v1/models" @@ -430,14 +449,16 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): # launch payload = { "model_uid": "test_tool", + "model_engine": "transformers", "model_name": model_name, - "model_size_in_billions": 6, + "model_size_in_billions": 9, "model_format": model_format, "quantization": quantization, } response = requests.post(url, json=payload) response_data = response.json() + assert "model_uid" in response_data, response_data model_uid_res = response_data["model_uid"] assert model_uid_res == "test_tool" @@ -450,7 +471,7 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): { "type": "function", "function": { - "name": "track", + "name": "track_a_long_function_name_to_test", "description": "追踪指定股票的实时价格", "parameters": { "type": "object", @@ -491,7 +512,7 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): assert "content" in completion["choices"][0]["message"] assert "tool_calls" == completion["choices"][0]["finish_reason"] assert ( - "track" + "track_a_long_function_name_to_test" == completion["choices"][0]["message"]["tool_calls"][0]["function"]["name"] ) arguments = completion["choices"][0]["message"]["tool_calls"][0]["function"][ @@ -509,7 +530,7 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): assert "content" in completion["choices"][0]["message"] assert "tool_calls" == completion["choices"][0]["finish_reason"] assert ( - "track" + "track_a_long_function_name_to_test" == completion["choices"][0]["message"]["tool_calls"][0]["function"]["name"] ) arguments = completion["choices"][0]["message"]["tool_calls"][0]["function"][ @@ -521,6 +542,30 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): # openai client import openai + async def test_stream(): + async_client = openai.AsyncClient( + api_key="not empty", base_url=f"{endpoint}/v1" + ) + chunks = [] + async_completion = async_client.chat.completions.create( + model=model_uid_res, + messages=[{"role": "user", "content": "帮我查询股票10111的价格"}], + tools=tools, + stream=True, + ) + async for chunk in await async_completion: + chunks.append(chunk) + assert len(chunks) == 2 + assert ( + chunks[1].choices[0].delta.tool_calls[0].function.name + == "track_a_long_function_name_to_test" + ) + arguments = chunks[1].choices[0].delta.tool_calls[0].function.arguments + arg = json.loads(arguments) + assert arg == {"symbol": "10111"} + + asyncio.run(test_stream()) + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") completion = client.chat.completions.create( model=model_uid_res, @@ -528,7 +573,10 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): tools=tools, ) assert "tool_calls" == completion.choices[0].finish_reason - assert "track" == completion.choices[0].message.tool_calls[0].function.name + assert ( + "track_a_long_function_name_to_test" + == completion.choices[0].message.tool_calls[0].function.name + ) arguments = completion.choices[0].message.tool_calls[0].function.arguments arg = json.loads(arguments) assert arg == {"symbol": "10111"} @@ -545,14 +593,17 @@ def test_restful_api_for_tool_calls(setup, model_format, quantization): }, ] + # When kwargs is {}, the glm4-chat does not observe the output tool calls, + # so the test will fail. for kwargs in [{"tools": tools}, {}]: completion = client.chat.completions.create( model=model_uid_res, messages=messages, **kwargs ) assert completion.choices assert completion.choices[0].finish_reason == "stop" - assert "10111" in completion.choices[0].message.content - assert "12345" in completion.choices[0].message.content + if kwargs: + assert "10111" in completion.choices[0].message.content + assert "12345" in completion.choices[0].message.content _check_invalid_tool_calls(endpoint, model_uid_res) @@ -663,7 +714,7 @@ def test_restful_api_for_gorilla_openfunctions_tool_calls( ) @pytest.mark.skip(reason="Cost too many resources.") def test_restful_api_for_qwen_tool_calls(setup, model_format, quantization): - model_name = "qwen-chat" + model_name = "qwen1.5-chat" endpoint, _ = setup url = f"{endpoint}/v1/models" @@ -677,6 +728,7 @@ def test_restful_api_for_qwen_tool_calls(setup, model_format, quantization): payload = { "model_uid": "test_tool", "model_name": model_name, + "model_engine": "transformers", "model_size_in_billions": 7, "model_format": model_format, "quantization": quantization, @@ -691,6 +743,69 @@ def test_restful_api_for_qwen_tool_calls(setup, model_format, quantization): response_data = response.json() assert len(response_data["data"]) == 1 + url = f"{endpoint}/v1/chat/completions" + payload = { + "model": model_uid_res, + "messages": [ + { + "role": "user", + "content": "谁是周杰伦?", + }, + ], + "tools": [], + "max_tokens": 2048, + "temperature": 0, + } + response = requests.post(url, json=payload) + completion = response.json() + assert "stop" == completion["choices"][0]["finish_reason"] + + tools = [ + { + "type": "function", + "function": { + "name": "google_search", + "description": "谷歌搜索是一个通用搜索引擎,搜索周杰伦。", + "parameters": {}, + }, + }, + { + "type": "function", + "function": { + "name": "image_gen", + "description": "文生图是一个AI绘画(图像生成)服务,画个周杰伦。", + }, + }, + ] + + url = f"{endpoint}/v1/chat/completions" + payload = { + "model": model_uid_res, + "messages": [ + { + "role": "user", + "content": "谁是周杰伦?", + }, + ], + "tools": tools, + "max_tokens": 2048, + "temperature": 0, + } + response = requests.post(url, json=payload) + completion = response.json() + assert "content" in completion["choices"][0]["message"] + assert "tool_calls" == completion["choices"][0]["finish_reason"] + assert ( + "google_search" + == completion["choices"][0]["message"]["tool_calls"][0]["function"]["name"] + ) + arguments = completion["choices"][0]["message"]["tool_calls"][0]["function"][ + "arguments" + ] + assert json.loads(arguments) + assert completion["usage"] + assert completion["usage"]["prompt_tokens"] != -1 + # tool tools = [ { @@ -778,7 +893,8 @@ def test_restful_api_for_qwen_tool_calls(setup, model_format, quantization): completion2 = response.json() assert "stop" == completion2["choices"][0]["finish_reason"] assert "周杰伦" in completion2["choices"][0]["message"]["content"] - assert "歌手" in completion2["choices"][0]["message"]["content"] + # The content varies between gguf and torch model. + # assert "歌" in completion2["choices"][0]["message"]["content"] # Check continue tool call. payload = { @@ -813,7 +929,8 @@ def test_restful_api_for_qwen_tool_calls(setup, model_format, quantization): arg = json.loads(arguments) assert "Jay Chou" in arg["prompt"] - _check_invalid_tool_calls(endpoint, model_uid_res) + # Qwen 1.5 4B can't pass the false tool call check. + # _check_invalid_tool_calls(endpoint, model_uid_res) def test_restful_api_with_request_limits(setup): @@ -855,7 +972,9 @@ def test_restful_api_with_request_limits(setup): url = f"{endpoint}/v1/models" payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", "request_limits": 0, } @@ -892,7 +1011,9 @@ async def test_openai(setup): # launch payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", } @@ -950,7 +1071,9 @@ def test_lang_chain(setup): # launch payload = { "model_uid": "test_restful_api", - "model_name": "orca", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", } @@ -988,7 +1111,6 @@ def test_lang_chain(setup): r = chat(messages) assert type(r) == AIMessage assert r.content - assert "amo" in r.content.lower() template = "You are a helpful assistant that translates {input_language} to {output_language}." system_message_prompt = SystemMessagePromptTemplate.from_template(template) @@ -1016,17 +1138,19 @@ def test_launch_model_async(setup): url = f"{endpoint}/v1/models?wait_ready=false" payload = { - "model_uid": "test_orca", - "model_name": "orca", + "model_uid": "test_qwen_15", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", } response = requests.post(url, json=payload) response_data = response.json() model_uid_res = response_data["model_uid"] - assert model_uid_res == "test_orca" + assert model_uid_res == "test_qwen_15" - status_url = f"{endpoint}/v1/models/instances?model_uid=test_orca" + status_url = f"{endpoint}/v1/models/instances?model_uid=test_qwen_15" while True: response = requests.get(status_url) response_data = response.json() @@ -1038,7 +1162,7 @@ def test_launch_model_async(setup): time.sleep(2) # delete again - url = f"{endpoint}/v1/models/test_orca" + url = f"{endpoint}/v1/models/test_qwen_15" requests.delete(url) response = requests.get(status_url) @@ -1050,17 +1174,19 @@ def test_events(setup): url = f"{endpoint}/v1/models" payload = { - "model_uid": "test_orca", - "model_name": "orca", + "model_uid": "test_qwen_15", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", "quantization": "q4_0", } response = requests.post(url, json=payload) response_data = response.json() model_uid_res = response_data["model_uid"] - assert model_uid_res == "test_orca" + assert model_uid_res == "test_qwen_15" - events_url = f"{endpoint}/v1/models/test_orca/events" + events_url = f"{endpoint}/v1/models/test_qwen_15/events" response = requests.get(events_url) response_data = response.json() # [{'event_type': 'INFO', 'event_ts': 1705896156, 'event_content': 'Launch model'}] @@ -1068,7 +1194,7 @@ def test_events(setup): assert "Launch" in response_data[0]["event_content"] # delete again - url = f"{endpoint}/v1/models/test_orca" + url = f"{endpoint}/v1/models/test_qwen_15" requests.delete(url) response = requests.get(events_url) @@ -1080,28 +1206,27 @@ def test_events(setup): def test_launch_model_by_version(setup): - from ...model.llm import get_llm_model_descriptions - endpoint, supervisor_addr = setup url = f"{endpoint}/v1/models/instance" - version_info = get_llm_model_descriptions()["orca"][0] + model_version = "qwen1.5-chat--0_5B--ggufv2--q4_0" payload = { - "model_uid": "test_orca", + "model_uid": "test_qwen15", + "model_engine": "llama.cpp", "model_type": "LLM", - "model_version": version_info["model_version"], + "model_version": model_version, } response = requests.post(url, json=payload) - assert response.json()["model_uid"] == "test_orca" + assert response.json()["model_uid"] == "test_qwen15" - url_version = f"{endpoint}/v1/models/LLM/orca/versions" + url_version = f"{endpoint}/v1/models/LLM/qwen1.5-chat/versions" response = requests.get(url_version) versions = response.json() has_version = False for info in versions: - if info["model_version"] == version_info["model_version"]: + if info["model_version"] == model_version: has_version = True assert info["cache_status"] is True assert info["model_file_location"] is not None @@ -1112,23 +1237,5 @@ def test_launch_model_by_version(setup): assert has_version is True # delete again - url = f"{endpoint}/v1/models/test_orca" + url = f"{endpoint}/v1/models/test_qwen15" requests.delete(url) - - -@pytest.mark.skipif(bool(os.environ.get("GITHUB_ACTIONS")), reason="Skip windows") -def test_cluster_info(setup): - endpoint, _ = setup - url = f"{endpoint}/v1/cluster/info" - - response = requests.get(url) - assert response.status_code == 200 - result = response.json() - assert isinstance(result, list) - assert len(result) == 2 - assert result[0]["node_type"] == "Supervisor" - assert result[0]["gpu_count"] == 0 - assert result[0]["gpu_vram_total"] == 0 - assert result[1]["node_type"] == "Worker" - assert result[1]["gpu_count"] == 0 - assert result[1]["gpu_vram_total"] == 0 diff --git a/xinference/core/tests/test_types.py b/xinference/core/tests/test_types.py index 280add37cc..8dd3fdbd63 100644 --- a/xinference/core/tests/test_types.py +++ b/xinference/core/tests/test_types.py @@ -16,11 +16,9 @@ from ..._compat import ValidationError, create_model_from_typeddict from ...types import ( CreateChatCompletion, - CreateChatCompletionCTransformers, CreateChatCompletionLlamaCpp, CreateChatCompletionTorch, CreateCompletion, - CreateCompletionCTransformers, CreateCompletionLlamaCpp, CreateCompletionTorch, _CreateCompletionOpenAIFallback, @@ -67,11 +65,7 @@ def test_create_completion_types(): CreateCompletion(model="abc", prompt="def") - types = [ - CreateCompletionTorch, - CreateCompletionLlamaCpp, - CreateCompletionCTransformers, - ] + types = [CreateCompletionTorch, CreateCompletionLlamaCpp] for t in types: t() assert "model" not in t.__fields__ @@ -93,11 +87,7 @@ def test_create_chat_completion_types(): CreateChatCompletion(model="abc", messages=[{"role": "tool"}], max_tokens=None) - types = [ - CreateChatCompletionTorch, - CreateChatCompletionLlamaCpp, - CreateChatCompletionCTransformers, - ] + types = [CreateChatCompletionTorch, CreateChatCompletionLlamaCpp] for t in types: t() assert "model" not in t.__fields__ @@ -108,6 +98,5 @@ def test_create_chat_completion_types(): check_fields(types[i], types[j]) # These chat and generate share the same type. - assert CreateChatCompletionCTransformers is CreateCompletionCTransformers assert CreateChatCompletionLlamaCpp is CreateCompletionLlamaCpp assert CreateChatCompletionTorch is CreateCompletionTorch diff --git a/xinference/core/tests/test_worker.py b/xinference/core/tests/test_worker.py index ac877581ae..2f32aae149 100644 --- a/xinference/core/tests/test_worker.py +++ b/xinference/core/tests/test_worker.py @@ -94,7 +94,7 @@ async def test_allocate_cuda_devices(setup_pool): pool = setup_pool addr = pool.external_address - worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( + worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( # type: ignore MockWorkerActor, address=addr, uid=WorkerActor.uid(), @@ -121,7 +121,7 @@ async def test_terminate_model_flag(setup_pool): pool = setup_pool addr = pool.external_address - worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( + worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( # type: ignore MockWorkerActor, address=addr, uid=WorkerActor.uid(), @@ -171,7 +171,7 @@ async def test_launch_embedding_model(setup_pool): pool = setup_pool addr = pool.external_address - worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( + worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( # type: ignore MockWorkerActor, address=addr, uid=WorkerActor.uid(), @@ -267,7 +267,7 @@ async def test_launch_model_with_gpu_idx(setup_pool): pool = setup_pool addr = pool.external_address - worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( + worker: xo.ActorRefType["MockWorkerActor"] = await xo.create_actor( # type: ignore MockWorkerActor, address=addr, uid=WorkerActor.uid(), diff --git a/xinference/core/utils.py b/xinference/core/utils.py index 0a121f4769..a110278aea 100644 --- a/xinference/core/utils.py +++ b/xinference/core/utils.py @@ -191,3 +191,15 @@ def get_nvidia_gpu_info() -> Dict: nvmlShutdown() except: pass + + +def assign_replica_gpu( + _replica_model_uid: str, gpu_idx: Union[int, List[int]] +) -> List[int]: + model_uid, replica, rep_id = parse_replica_model_uid(_replica_model_uid) + rep_id, replica = int(rep_id), int(replica) + if isinstance(gpu_idx, int): + gpu_idx = [gpu_idx] + if isinstance(gpu_idx, list) and gpu_idx: + return gpu_idx[rep_id::replica] + return gpu_idx diff --git a/xinference/core/worker.py b/xinference/core/worker.py index fde991614d..d9291aa27f 100644 --- a/xinference/core/worker.py +++ b/xinference/core/worker.py @@ -16,12 +16,13 @@ import os import platform import queue +import shutil import signal import threading import time from collections import defaultdict from logging import getLogger -from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union import xoscar as xo from async_timeout import timeout @@ -30,15 +31,19 @@ from ..constants import ( XINFERENCE_CACHE_DIR, XINFERENCE_DISABLE_HEALTH_CHECK, + XINFERENCE_DISABLE_METRICS, XINFERENCE_HEALTH_CHECK_INTERVAL, ) -from ..core import ModelActor +from ..core.model import ModelActor from ..core.status_guard import LaunchStatus -from ..device_utils import gpu_count +from ..device_utils import get_available_device_env_name, gpu_count from ..model.core import ModelDescription, create_model_instance +from ..types import PeftModelConfig +from .cache_tracker import CacheTrackerActor from .event import Event, EventCollectorActor, EventType from .metrics import launch_metrics_export_server, record_metrics from .resource import gather_node_info +from .status_guard import StatusGuardActor from .utils import log_async, log_sync, parse_replica_model_uid, purge_dir logger = getLogger(__name__) @@ -65,11 +70,23 @@ def __init__( # static attrs. self._total_gpu_devices = gpu_devices self._supervisor_address = supervisor_address - self._supervisor_ref = None + self._supervisor_ref: Optional[xo.ActorRefType] = None self._main_pool = main_pool self._main_pool.recover_sub_pool = self.recover_sub_pool + self._status_guard_ref: xo.ActorRefType["StatusGuardActor"] = ( # type: ignore + None + ) + self._event_collector_ref: xo.ActorRefType[ # type: ignore + EventCollectorActor + ] = None + self._cache_tracker_ref: xo.ActorRefType[CacheTrackerActor] = ( # type: ignore + None + ) # internal states. + # temporary placeholder during model launch process: + self._model_uid_launching_guard: Dict[str, bool] = {} + # attributes maintained after model launched: self._model_uid_to_model: Dict[str, xo.ActorRefType["ModelActor"]] = {} self._model_uid_to_model_spec: Dict[str, ModelDescription] = {} self._gpu_to_model_uid: Dict[int, str] = {} @@ -79,11 +96,15 @@ def __init__( int, Set[Tuple[str, str]] ] = defaultdict(set) self._model_uid_to_addr: Dict[str, str] = {} - self._model_uid_to_recover_count: Dict[str, int] = {} + self._model_uid_to_recover_count: Dict[str, Optional[int]] = {} self._model_uid_to_launch_args: Dict[str, Dict] = {} - # metrics export server. - if metrics_exporter_host is not None or metrics_exporter_port is not None: + if XINFERENCE_DISABLE_METRICS: + logger.info( + "Worker metrics is disabled due to the environment XINFERENCE_DISABLE_METRICS=1" + ) + elif metrics_exporter_host is not None or metrics_exporter_port is not None: + # metrics export server. logger.info( f"Starting metrics export server at {metrics_exporter_host}:{metrics_exporter_port}" ) @@ -125,7 +146,7 @@ async def recover_sub_pool(self, address): else: recover_count = self._model_uid_to_recover_count.get(model_uid) try: - await self.terminate_model(model_uid) + await self.terminate_model(model_uid, is_model_die=True) except Exception: pass if recover_count is not None: @@ -136,14 +157,22 @@ async def recover_sub_pool(self, address): recover_count - 1, ) event_model_uid, _, __ = parse_replica_model_uid(model_uid) - await self._event_collector_ref.report_event( - event_model_uid, - Event( - event_type=EventType.WARNING, - event_ts=int(time.time()), - event_content="Recreate model", - ), - ) + try: + if self._event_collector_ref is not None: + await self._event_collector_ref.report_event( + event_model_uid, + Event( + event_type=EventType.WARNING, + event_ts=int(time.time()), + event_content="Recreate model", + ), + ) + except Exception as e: + # Report callback error can be log and ignore, should not interrupt the Process + logger.error("report_event error: %s" % (e)) + finally: + del event_model_uid + self._model_uid_to_recover_count[model_uid] = ( recover_count - 1 ) @@ -160,86 +189,112 @@ def uid(cls) -> str: return "worker" async def __post_create__(self): - from ..isolation import Isolation - from .cache_tracker import CacheTrackerActor - from .status_guard import StatusGuardActor - from .supervisor import SupervisorActor - - self._status_guard_ref: xo.ActorRefType[ - "StatusGuardActor" - ] = await xo.actor_ref( - address=self._supervisor_address, uid=StatusGuardActor.uid() - ) - self._event_collector_ref: xo.ActorRefType[ - EventCollectorActor - ] = await xo.actor_ref( - address=self._supervisor_address, uid=EventCollectorActor.uid() + from ..model.audio import ( + CustomAudioModelFamilyV1, + generate_audio_description, + register_audio, + unregister_audio, ) - self._cache_tracker_ref: xo.ActorRefType[ - "CacheTrackerActor" - ] = await xo.actor_ref( - address=self._supervisor_address, uid=CacheTrackerActor.uid() - ) - self._supervisor_ref: xo.ActorRefType["SupervisorActor"] = await xo.actor_ref( - address=self._supervisor_address, uid=SupervisorActor.uid() - ) - await self._supervisor_ref.add_worker(self.address) - if not XINFERENCE_DISABLE_HEALTH_CHECK: - # Run _periodical_report_status() in a dedicated thread. - self._isolation = Isolation(asyncio.new_event_loop(), threaded=True) - self._isolation.start() - asyncio.run_coroutine_threadsafe( - self._periodical_report_status(), loop=self._isolation.loop - ) - logger.info(f"Xinference worker {self.address} started") - logger.info("Purge cache directory: %s", XINFERENCE_CACHE_DIR) - purge_dir(XINFERENCE_CACHE_DIR) - from ..model.embedding import ( CustomEmbeddingModelSpec, - get_embedding_model_descriptions, + generate_embedding_description, register_embedding, unregister_embedding, ) - from ..model.image import get_image_model_descriptions + from ..model.flexible import ( + FlexibleModelSpec, + generate_flexible_model_description, + register_flexible_model, + unregister_flexible_model, + ) + from ..model.image import ( + CustomImageModelFamilyV1, + generate_image_description, + register_image, + unregister_image, + ) from ..model.llm import ( CustomLLMFamilyV1, - get_llm_model_descriptions, + generate_llm_description, register_llm, unregister_llm, ) from ..model.rerank import ( CustomRerankModelSpec, - get_rerank_model_descriptions, + generate_rerank_description, register_rerank, unregister_rerank, ) - self._custom_register_type_to_cls: Dict[str, Tuple] = { - "LLM": (CustomLLMFamilyV1, register_llm, unregister_llm), + self._custom_register_type_to_cls: Dict[str, Tuple] = { # type: ignore + "LLM": ( + CustomLLMFamilyV1, + register_llm, + unregister_llm, + generate_llm_description, + ), "embedding": ( CustomEmbeddingModelSpec, register_embedding, unregister_embedding, + generate_embedding_description, + ), + "rerank": ( + CustomRerankModelSpec, + register_rerank, + unregister_rerank, + generate_rerank_description, + ), + "image": ( + CustomImageModelFamilyV1, + register_image, + unregister_image, + generate_image_description, + ), + "audio": ( + CustomAudioModelFamilyV1, + register_audio, + unregister_audio, + generate_audio_description, + ), + "flexible": ( + FlexibleModelSpec, + register_flexible_model, + unregister_flexible_model, + generate_flexible_model_description, ), - "rerank": (CustomRerankModelSpec, register_rerank, unregister_rerank), } - # record model version - model_version_infos: Dict[str, List[Dict]] = {} - model_version_infos.update(get_llm_model_descriptions()) - model_version_infos.update(get_embedding_model_descriptions()) - model_version_infos.update(get_rerank_model_descriptions()) - model_version_infos.update(get_image_model_descriptions()) - await self._cache_tracker_ref.record_model_version( - model_version_infos, self.address - ) + logger.info("Purge cache directory: %s", XINFERENCE_CACHE_DIR) + purge_dir(XINFERENCE_CACHE_DIR) + + try: + await self.get_supervisor_ref(add_worker=True) + except Exception as e: + # Do not crash the worker if supervisor is down, auto re-connect later + logger.error(f"cannot connect to supervisor {e}") + + if not XINFERENCE_DISABLE_HEALTH_CHECK: + from ..isolation import Isolation + + # Run _periodical_report_status() in a dedicated thread. + self._isolation = Isolation(asyncio.new_event_loop(), threaded=True) + self._isolation.start() + asyncio.run_coroutine_threadsafe( + self._periodical_report_status(), loop=self._isolation.loop + ) + logger.info(f"Xinference worker {self.address} started") # Windows does not have signal handler if os.name != "nt": async def signal_handler(): - await self._supervisor_ref.remove_worker(self.address) + try: + supervisor_ref = await self.get_supervisor_ref(add_worker=False) + await supervisor_ref.remove_worker(self.address) + except Exception as e: + # Ignore the error of rpc, anyway we are exiting + logger.exception("remove worker rpc error: %s", e) os._exit(0) loop = asyncio.get_running_loop() @@ -250,6 +305,66 @@ async def signal_handler(): async def __pre_destroy__(self): self._isolation.stop() + async def trigger_exit(self) -> bool: + try: + os.kill(os.getpid(), signal.SIGINT) + except Exception as e: + logger.info(f"trigger exit error: {e}") + return False + return True + + async def get_supervisor_ref(self, add_worker: bool = True) -> xo.ActorRefType: + """ + Try connect to supervisor and return ActorRef. Raise exception on error + Params: + add_worker: By default will call supervisor.add_worker after first connect + """ + from .supervisor import SupervisorActor + + if self._supervisor_ref is not None: + return self._supervisor_ref + supervisor_ref = await xo.actor_ref( # type: ignore + address=self._supervisor_address, uid=SupervisorActor.uid() + ) + # Prevent concurrent operations leads to double initialization, check again. + if self._supervisor_ref is not None: + return self._supervisor_ref + self._supervisor_ref = supervisor_ref + if add_worker and len(self._model_uid_to_model) == 0: + # Newly started (or restarted), has no model, notify supervisor + await self._supervisor_ref.add_worker(self.address) + logger.info("Connected to supervisor as a fresh worker") + + self._status_guard_ref = await xo.actor_ref( + address=self._supervisor_address, uid=StatusGuardActor.uid() + ) + self._event_collector_ref = await xo.actor_ref( + address=self._supervisor_address, uid=EventCollectorActor.uid() + ) + self._cache_tracker_ref = await xo.actor_ref( + address=self._supervisor_address, uid=CacheTrackerActor.uid() + ) + # cache_tracker is on supervisor + from ..model.audio import get_audio_model_descriptions + from ..model.embedding import get_embedding_model_descriptions + from ..model.flexible import get_flexible_model_descriptions + from ..model.image import get_image_model_descriptions + from ..model.llm import get_llm_model_descriptions + from ..model.rerank import get_rerank_model_descriptions + + # record model version + model_version_infos: Dict[str, List[Dict]] = {} # type: ignore + model_version_infos.update(get_llm_model_descriptions()) + model_version_infos.update(get_embedding_model_descriptions()) + model_version_infos.update(get_rerank_model_descriptions()) + model_version_infos.update(get_image_model_descriptions()) + model_version_infos.update(get_audio_model_descriptions()) + model_version_infos.update(get_flexible_model_descriptions()) + await self._cache_tracker_ref.record_model_version( + model_version_infos, self.address + ) + return self._supervisor_ref + @staticmethod def get_devices_count(): from ..device_utils import gpu_count @@ -261,9 +376,9 @@ def get_model_count(self) -> int: return len(self._model_uid_to_model) async def is_model_vllm_backend(self, model_uid: str) -> bool: - assert self._supervisor_ref is not None _model_uid, _, _ = parse_replica_model_uid(model_uid) - model_ref = await self._supervisor_ref.get_model(_model_uid) + supervisor_ref = await self.get_supervisor_ref() + model_ref = await supervisor_ref.get_model(_model_uid) return await model_ref.is_vllm_backend() async def allocate_devices_for_embedding(self, model_uid: str) -> int: @@ -428,6 +543,7 @@ async def _create_subpool( ) -> Tuple[str, List[str]]: env = {} devices = [] + env_name = get_available_device_env_name() or "CUDA_VISIBLE_DEVICES" if gpu_idx is None: if isinstance(n_gpu, int) or (n_gpu == "auto" and gpu_count() > 0): # Currently, n_gpu=auto means using 1 GPU @@ -437,17 +553,17 @@ async def _create_subpool( if model_type in ["embedding", "rerank"] else self.allocate_devices(model_uid=model_uid, n_gpu=gpu_cnt) ) - env["CUDA_VISIBLE_DEVICES"] = ",".join([str(dev) for dev in devices]) + env[env_name] = ",".join([str(dev) for dev in devices]) logger.debug(f"GPU selected: {devices} for model {model_uid}") if n_gpu is None: - env["CUDA_VISIBLE_DEVICES"] = "-1" + env[env_name] = "-1" logger.debug(f"GPU disabled for model {model_uid}") else: assert isinstance(gpu_idx, list) devices = await self.allocate_devices_with_gpu_idx( model_uid, model_type, gpu_idx # type: ignore ) - env["CUDA_VISIBLE_DEVICES"] = ",".join([str(dev) for dev in devices]) + env[env_name] = ",".join([str(dev) for dev in devices]) if os.name != "nt" and platform.system() != "Darwin": # Linux @@ -468,17 +584,23 @@ def _check_model_is_valid(self, model_name: str, model_format: Optional[str]): raise ValueError(f"{model_name} model can't run on Darwin system.") @log_sync(logger=logger) - def register_model(self, model_type: str, model: str, persist: bool): + async def register_model(self, model_type: str, model: str, persist: bool): # TODO: centralized model registrations if model_type in self._custom_register_type_to_cls: ( model_spec_cls, register_fn, unregister_fn, + generate_fn, ) = self._custom_register_type_to_cls[model_type] model_spec = model_spec_cls.parse_raw(model) try: register_fn(model_spec, persist) + await self._cache_tracker_ref.record_model_version( + generate_fn(model_spec), self.address + ) + except ValueError as e: + raise e except Exception as e: unregister_fn(model_spec.model_name, raise_error=False) raise e @@ -486,74 +608,130 @@ def register_model(self, model_type: str, model: str, persist: bool): raise ValueError(f"Unsupported model type: {model_type}") @log_sync(logger=logger) - def unregister_model(self, model_type: str, model_name: str): + async def unregister_model(self, model_type: str, model_name: str): # TODO: centralized model registrations if model_type in self._custom_register_type_to_cls: - _, _, unregister_fn = self._custom_register_type_to_cls[model_type] - unregister_fn(model_name) + _, _, unregister_fn, _ = self._custom_register_type_to_cls[model_type] + unregister_fn(model_name, False) else: raise ValueError(f"Unsupported model type: {model_type}") @log_async(logger=logger) - async def launch_speculative_model( - self, - model_uid: str, - model_name: str, - model_size_in_billions: Optional[int], - quantization: Optional[str], - draft_model_name: str, - draft_model_size_in_billions: Optional[int], - draft_quantization: Optional[str], - n_gpu: Optional[Union[int, str]] = "auto", - ): - if n_gpu is not None: - if isinstance(n_gpu, int) and (n_gpu <= 0 or n_gpu > gpu_count()): - raise ValueError( - f"The parameter `n_gpu` must be greater than 0 and " - f"not greater than the number of GPUs: {gpu_count()} on the machine." - ) - if isinstance(n_gpu, str) and n_gpu != "auto": - raise ValueError("Currently `n_gpu` only supports `auto`.") + async def list_model_registrations( + self, model_type: str, detailed: bool = False + ) -> List[Dict[str, Any]]: + def sort_helper(item): + assert isinstance(item["model_name"], str) + return item.get("model_name").lower() - from ..model.llm.core import create_speculative_llm_model_instance - - subpool_address, devices = await self._create_subpool(model_uid, n_gpu=n_gpu) - - model, model_description = await asyncio.to_thread( - create_speculative_llm_model_instance, - subpool_addr=subpool_address, - devices=devices, - model_uid=model_uid, - model_name=model_name, - model_size_in_billions=model_size_in_billions, - quantization=quantization, - draft_model_name=draft_model_name, - draft_model_size_in_billions=draft_model_size_in_billions, - draft_quantization=draft_quantization, - is_local_deployment=True, - ) + if model_type == "LLM": + from ..model.llm import get_user_defined_llm_families - try: - model_ref = await xo.create_actor( - ModelActor, - address=subpool_address, - uid=model_uid, - worker_address=self.address, - model=model, - model_description=model_description, - ) - await model_ref.load() - except: - logger.error(f"Failed to load model {model_uid}", exc_info=True) - self.release_devices(model_uid=model_uid) - await self._main_pool.remove_sub_pool(subpool_address) - raise + ret = [] - self._model_uid_to_model[model_uid] = model_ref - self._model_uid_to_model_spec[model_uid] = model_description - for dev in devices: - self._gpu_to_model_uid[int(dev)] = model_uid - self._model_uid_to_addr[model_uid] = subpool_address + for family in get_user_defined_llm_families(): + ret.append({"model_name": family.model_name, "is_builtin": False}) + + ret.sort(key=sort_helper) + return ret + elif model_type == "embedding": + from ..model.embedding.custom import get_user_defined_embeddings + + ret = [] + + for model_spec in get_user_defined_embeddings(): + ret.append({"model_name": model_spec.model_name, "is_builtin": False}) + + ret.sort(key=sort_helper) + return ret + elif model_type == "image": + from ..model.image.custom import get_user_defined_images + + ret = [] + + for model_spec in get_user_defined_images(): + ret.append({"model_name": model_spec.model_name, "is_builtin": False}) + + ret.sort(key=sort_helper) + return ret + elif model_type == "audio": + from ..model.audio.custom import get_user_defined_audios + + ret = [] + + for model_spec in get_user_defined_audios(): + ret.append({"model_name": model_spec.model_name, "is_builtin": False}) + + ret.sort(key=sort_helper) + return ret + elif model_type == "video": + return [] + elif model_type == "rerank": + from ..model.rerank.custom import get_user_defined_reranks + + ret = [] + + for model_spec in get_user_defined_reranks(): + ret.append({"model_name": model_spec.model_name, "is_builtin": False}) + + ret.sort(key=sort_helper) + return ret + else: + raise ValueError(f"Unsupported model type: {model_type}") + + @log_sync(logger=logger) + async def get_model_registration(self, model_type: str, model_name: str) -> Any: + if model_type == "LLM": + from ..model.llm import get_user_defined_llm_families + + for f in get_user_defined_llm_families(): + if f.model_name == model_name: + return f + elif model_type == "embedding": + from ..model.embedding.custom import get_user_defined_embeddings + + for f in get_user_defined_embeddings(): + if f.model_name == model_name: + return f + elif model_type == "image": + from ..model.image.custom import get_user_defined_images + + for f in get_user_defined_images(): + if f.model_name == model_name: + return f + elif model_type == "audio": + from ..model.audio.custom import get_user_defined_audios + + for f in get_user_defined_audios(): + if f.model_name == model_name: + return f + elif model_type == "video": + return None + elif model_type == "rerank": + from ..model.rerank.custom import get_user_defined_reranks + + for f in get_user_defined_reranks(): + if f.model_name == model_name: + return f + return None + + @log_async(logger=logger) + async def query_engines_by_model_name(self, model_name: str): + from copy import deepcopy + + from ..model.llm.llm_family import LLM_ENGINES + + if model_name not in LLM_ENGINES: + return None + + # filter llm_class + engine_params = deepcopy(LLM_ENGINES[model_name]) + for engine in engine_params: + params = engine_params[engine] + for param in params: + del param["llm_class"] + + return engine_params async def _get_model_ability(self, model: Any, model_type: str) -> List[str]: from ..model.llm.core import LLM @@ -565,7 +743,11 @@ async def _get_model_ability(self, model: Any, model_type: str) -> List[str]: elif model_type == "image": return ["text_to_image"] elif model_type == "audio": - return ["audio_to_text"] + return [model._model_spec.ability] + elif model_type == "video": + return ["text_to_video"] + elif model_type == "flexible": + return ["flexible"] else: assert model_type == "LLM" assert isinstance(model, LLM) @@ -593,32 +775,47 @@ async def launch_builtin_model( self, model_uid: str, model_name: str, - model_size_in_billions: Optional[int], + model_size_in_billions: Optional[Union[int, str]], model_format: Optional[str], quantization: Optional[str], + model_engine: Optional[str], model_type: str = "LLM", n_gpu: Optional[Union[int, str]] = "auto", - peft_model_path: Optional[str] = None, - image_lora_load_kwargs: Optional[Dict] = None, - image_lora_fuse_kwargs: Optional[Dict] = None, + peft_model_config: Optional[PeftModelConfig] = None, request_limits: Optional[int] = None, gpu_idx: Optional[Union[int, List[int]]] = None, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, **kwargs, ): - event_model_uid, _, __ = parse_replica_model_uid(model_uid) - await self._event_collector_ref.report_event( - event_model_uid, - Event( - event_type=EventType.INFO, - event_ts=int(time.time()), - event_content="Launch model", - ), - ) + # !!! Note that The following code must be placed at the very beginning of this function, + # or there will be problems with auto-recovery. + # Because `locals()` will collect all the local parameters of this function and pass to this function again. launch_args = locals() launch_args.pop("self") launch_args.pop("kwargs") launch_args.update(kwargs) + try: + origin_uid, _, _ = parse_replica_model_uid(model_uid) + except Exception as e: + logger.exception(e) + raise + try: + _ = await self.get_supervisor_ref() + if self._event_collector_ref is not None: + await self._event_collector_ref.report_event( + origin_uid, + Event( + event_type=EventType.INFO, + event_ts=int(time.time()), + event_content="Launch model", + ), + ) + except Exception as e: + # Report callback error can be log and ignore, should not interrupt the Process + logger.error("report_event error: %s" % (e)) + if gpu_idx is not None: logger.info( f"You specify to launch the model: {model_name} on GPU index: {gpu_idx} " @@ -638,90 +835,113 @@ async def launch_builtin_model( if isinstance(n_gpu, str) and n_gpu != "auto": raise ValueError("Currently `n_gpu` only supports `auto`.") - if peft_model_path is not None: + if peft_model_config is not None: if model_type in ("embedding", "rerank"): raise ValueError( f"PEFT adaptors cannot be applied to embedding or rerank models." ) - if model_type == "LLM" and model_format in ("ggufv2", "ggmlv3"): + if model_type == "LLM" and model_format in ("ggufv2",): raise ValueError( f"PEFT adaptors can only be applied to pytorch-like models" ) + if model_path is not None: + if not os.path.exists(model_path): + raise ValueError( + f"Invalid input. `model_path`: {model_path} File or directory does not exist." + ) assert model_uid not in self._model_uid_to_model self._check_model_is_valid(model_name, model_format) - assert self._supervisor_ref is not None - is_local_deployment = await self._supervisor_ref.is_local_deployment() - subpool_address, devices = await self._create_subpool( - model_uid, model_type, n_gpu=n_gpu, gpu_idx=gpu_idx - ) + if self.get_model_launch_status(model_uid) is not None: + raise ValueError(f"{model_uid} is running") try: - origin_uid, _, _ = parse_replica_model_uid(model_uid) - model, model_description = await asyncio.to_thread( - create_model_instance, - subpool_address, - devices, - model_uid, - model_type, - model_name, - model_format, - model_size_in_billions, - quantization, - peft_model_path, - image_lora_load_kwargs, - image_lora_fuse_kwargs, - is_local_deployment, - **kwargs, - ) - await self.update_cache_status(model_name, model_description) - model_ref = await xo.create_actor( - ModelActor, - address=subpool_address, - uid=model_uid, - worker_address=self.address, - model=model, - model_description=model_description, - request_limits=request_limits, + self._model_uid_launching_guard[model_uid] = True + subpool_address, devices = await self._create_subpool( + model_uid, model_type, n_gpu=n_gpu, gpu_idx=gpu_idx ) - await model_ref.load() - except: - logger.error(f"Failed to load model {model_uid}", exc_info=True) - self.release_devices(model_uid=model_uid) - await self._main_pool.remove_sub_pool(subpool_address) - raise - self._model_uid_to_model[model_uid] = model_ref - self._model_uid_to_model_spec[model_uid] = model_description - self._model_uid_to_addr[model_uid] = subpool_address - self._model_uid_to_recover_count.setdefault( - model_uid, MODEL_ACTOR_AUTO_RECOVER_LIMIT - ) - self._model_uid_to_launch_args[model_uid] = launch_args + try: + model, model_description = await asyncio.to_thread( + create_model_instance, + subpool_address, + devices, + model_uid, + model_type, + model_name, + model_engine, + model_format, + model_size_in_billions, + quantization, + peft_model_config, + download_hub, + model_path, + **kwargs, + ) + await self.update_cache_status(model_name, model_description) + model_ref = await xo.create_actor( + ModelActor, + address=subpool_address, + uid=model_uid, + worker_address=self.address, + model=model, + model_description=model_description, + request_limits=request_limits, + ) + await model_ref.load() + except: + logger.error(f"Failed to load model {model_uid}", exc_info=True) + self.release_devices(model_uid=model_uid) + await self._main_pool.remove_sub_pool(subpool_address) + raise + self._model_uid_to_model[model_uid] = model_ref + self._model_uid_to_model_spec[model_uid] = model_description + self._model_uid_to_addr[model_uid] = subpool_address + self._model_uid_to_recover_count.setdefault( + model_uid, MODEL_ACTOR_AUTO_RECOVER_LIMIT + ) + self._model_uid_to_launch_args[model_uid] = launch_args + finally: + del self._model_uid_launching_guard[model_uid] # update status to READY abilities = await self._get_model_ability(model, model_type) + _ = await self.get_supervisor_ref(add_worker=False) + + if self._status_guard_ref is None: + _ = await self.get_supervisor_ref() + assert self._status_guard_ref is not None await self._status_guard_ref.update_instance_info( origin_uid, {"model_ability": abilities, "status": LaunchStatus.READY.name}, ) @log_async(logger=logger) - async def terminate_model(self, model_uid: str): - event_model_uid, _, __ = parse_replica_model_uid(model_uid) - await self._event_collector_ref.report_event( - event_model_uid, - Event( - event_type=EventType.INFO, - event_ts=int(time.time()), - event_content="Terminate model", - ), - ) - origin_uid, _, _ = parse_replica_model_uid(model_uid) - await self._status_guard_ref.update_instance_info( - origin_uid, {"status": LaunchStatus.TERMINATING.name} - ) + async def terminate_model(self, model_uid: str, is_model_die=False): + # Terminate model while its launching is not allow + if model_uid in self._model_uid_launching_guard: + raise ValueError(f"{model_uid} is launching") + origin_uid, _, __ = parse_replica_model_uid(model_uid) + try: + _ = await self.get_supervisor_ref() + if self._event_collector_ref is not None: + await self._event_collector_ref.report_event( + origin_uid, + Event( + event_type=EventType.INFO, + event_ts=int(time.time()), + event_content="Terminate model", + ), + ) + except Exception as e: + # Report callback error can be log and ignore, should not interrupt the Process + logger.error("report_event error: %s" % (e)) + + if self._status_guard_ref is not None: + await self._status_guard_ref.update_instance_info( + origin_uid, {"status": LaunchStatus.TERMINATING.name} + ) model_ref = self._model_uid_to_model.get(model_uid, None) if model_ref is None: logger.debug("Model not found, uid: %s", model_uid) @@ -746,10 +966,34 @@ async def terminate_model(self, model_uid: str): self._model_uid_to_addr.pop(model_uid, None) self._model_uid_to_recover_count.pop(model_uid, None) self._model_uid_to_launch_args.pop(model_uid, None) + + if is_model_die: + status = LaunchStatus.ERROR.name + else: + status = LaunchStatus.TERMINATED.name + + if self._status_guard_ref is None: + _ = await self.get_supervisor_ref() + assert self._status_guard_ref is not None await self._status_guard_ref.update_instance_info( - origin_uid, {"status": LaunchStatus.TERMINATED.name} + origin_uid, {"status": status} ) + # Provide an interface for future version of supervisor to call + def get_model_launch_status(self, model_uid: str) -> Optional[str]: + """ + returns: + CREATING: model is launching + RREADY: model is running + None: model is not running (launch error might have happened) + """ + + if model_uid in self._model_uid_launching_guard: + return LaunchStatus.CREATING.name + if model_uid in self._model_uid_to_model: + return LaunchStatus.READY.name + return None + @log_async(logger=logger) async def list_models(self) -> Dict[str, Dict[str, Any]]: ret = {} @@ -783,7 +1027,8 @@ async def report_status(self): raise except Exception: logger.exception("Report status got error.") - await self._supervisor_ref.report_worker_status(self.address, status) + supervisor_ref = await self.get_supervisor_ref() + await supervisor_ref.report_worker_status(self.address, status) async def _periodical_report_status(self): while True: @@ -805,6 +1050,89 @@ async def _periodical_report_status(self): except asyncio.CancelledError: # pragma: no cover break + async def list_cached_models( + self, model_name: Optional[str] = None + ) -> List[Dict[Any, Any]]: + lists = await self._cache_tracker_ref.list_cached_models( + self.address, model_name + ) + cached_models = [] + for list in lists: + cached_model = { + "model_name": list.get("model_name"), + "model_size_in_billions": list.get("model_size_in_billions"), + "model_format": list.get("model_format"), + "quantization": list.get("quantization"), + "model_version": list.get("model_version"), + } + path = list.get("model_file_location") + cached_model["path"] = path + # parsing soft links + if os.path.isdir(path): + files = os.listdir(path) + # dir has files + if files: + resolved_file = os.path.realpath(os.path.join(path, files[0])) + if resolved_file: + cached_model["real_path"] = os.path.dirname(resolved_file) + else: + cached_model["real_path"] = os.path.realpath(path) + cached_model["actor_ip_address"] = self.address + cached_models.append(cached_model) + return cached_models + + async def list_deletable_models(self, model_version: str) -> List[str]: + paths = set() + path = await self._cache_tracker_ref.list_deletable_models( + model_version, self.address + ) + if os.path.isfile(path): + path = os.path.dirname(path) + + if os.path.isdir(path): + files = os.listdir(path) + paths.update([os.path.join(path, file) for file in files]) + # search real path + if paths: + paths.update([os.path.realpath(path) for path in paths]) + + # get tensorizer path + from ..model.llm.transformers.tensorizer_utils import get_tensorizer_dir + + tensorizer_path = get_tensorizer_dir(path) + if os.path.isdir(tensorizer_path): + files = os.listdir(tensorizer_path) + paths.update([os.path.join(tensorizer_path, file) for file in files]) + + return list(paths) + + async def confirm_and_remove_model(self, model_version: str) -> bool: + paths = await self.list_deletable_models(model_version) + for path in paths: + try: + if os.path.islink(path): + os.unlink(path) + elif os.path.isfile(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + else: + logger.debug(f"{path} is not a valid path.") + except Exception as e: + logger.error(f"Fail to delete {path} with error:{e}.") + return False + await self._cache_tracker_ref.confirm_and_remove_model( + model_version, self.address + ) + return True + + async def get_workers_info(self) -> Dict[str, Any]: + ret = { + "work-ip": self.address, + "models": await self.list_models(), + } + return ret + @staticmethod def record_metrics(name, op, kwargs): record_metrics(name, op, kwargs) diff --git a/xinference/deploy/cmdline.py b/xinference/deploy/cmdline.py index 4873838ea2..8eea848077 100644 --- a/xinference/deploy/cmdline.py +++ b/xinference/deploy/cmdline.py @@ -17,7 +17,7 @@ import os import sys import warnings -from typing import List, Optional, Tuple, Union +from typing import List, Optional, Sequence, Tuple, Union import click from xoscar.utils import get_next_port @@ -25,7 +25,6 @@ from .. import __version__ from ..client import RESTfulClient from ..client.restful.restful_client import ( - RESTfulChatglmCppChatModelHandle, RESTfulChatModelHandle, RESTfulGenerateModelHandle, ) @@ -370,6 +369,9 @@ def worker( help="Type of model to register (default is 'LLM').", ) @click.option("--file", "-f", type=str, help="Path to the model configuration file.") +@click.option( + "--worker-ip", "-w", type=str, help="Specify the ip address of the worker." +) @click.option( "--persist", "-p", @@ -387,6 +389,7 @@ def register_model( endpoint: Optional[str], model_type: str, file: str, + worker_ip: str, persist: bool, api_key: Optional[str], ): @@ -400,6 +403,7 @@ def register_model( client.register_model( model_type=model_type, model=model, + worker_ip=worker_ip, persist=persist, ) @@ -570,6 +574,128 @@ def list_model_registrations( raise NotImplementedError(f"List {model_type} is not implemented.") +@cli.command("cached", help="List all cached models in Xinference.") +@click.option( + "--endpoint", + "-e", + type=str, + help="Xinference endpoint.", +) +@click.option( + "--model_name", + "-n", + type=str, + help="Provide the name of the models to be removed.", +) +@click.option( + "--worker-ip", + default=None, + type=str, + help="Specify which worker this model runs on by ip, for distributed situation.", +) +@click.option( + "--api-key", + "-ak", + default=None, + type=str, + help="Api-Key for access xinference api with authorization.", +) +def list_cached_models( + endpoint: Optional[str], + api_key: Optional[str], + model_name: Optional[str], + worker_ip: Optional[str], +): + from tabulate import tabulate + + endpoint = get_endpoint(endpoint) + client = RESTfulClient(base_url=endpoint, api_key=api_key) + if api_key is None: + client._set_token(get_stored_token(endpoint, client)) + + cached_models = client.list_cached_models(model_name, worker_ip) + if not cached_models: + print("There are no cache files.") + return + headers = list(cached_models[0].keys()) + + print("cached_model: ") + table_data = [] + for model in cached_models: + row_data = [ + str(value) if value is not None else "-" for value in model.values() + ] + table_data.append(row_data) + print(tabulate(table_data, headers=headers, tablefmt="pretty")) + + +@cli.command("remove-cache", help="Remove selected cached models in Xinference.") +@click.option( + "--endpoint", + "-e", + type=str, + help="Xinference endpoint.", +) +@click.option( + "--model_version", + "-n", + type=str, + help="Provide the version of the models to be removed.", +) +@click.option( + "--worker-ip", + default=None, + type=str, + help="Specify which worker this model runs on by ip, for distributed situation.", +) +@click.option( + "--api-key", + "-ak", + default=None, + type=str, + help="Api-Key for access xinference api with authorization.", +) +@click.option("--check", is_flag=True, help="Confirm the deletion of the cache.") +def remove_cache( + endpoint: Optional[str], + model_version: str, + api_key: Optional[str], + check: bool, + worker_ip: Optional[str] = None, +): + endpoint = get_endpoint(endpoint) + client = RESTfulClient(base_url=endpoint, api_key=api_key) + if api_key is None: + client._set_token(get_stored_token(endpoint, client)) + + if not check: + response = client.list_deletable_models( + model_version=model_version, worker_ip=worker_ip + ) + paths: List[str] = response.get("paths", []) + if not paths: + click.echo(f"There is no model version named {model_version}.") + return + click.echo(f"Model {model_version} cache directory to be deleted:") + for path in response.get("paths", []): + click.echo(f"{path}") + + if click.confirm("Do you want to proceed with the deletion?", abort=True): + check = True + try: + result = client.confirm_and_remove_model( + model_version=model_version, worker_ip=worker_ip + ) + if result: + click.echo(f"Cache directory {model_version} has been deleted.") + else: + click.echo( + f"Cache directory {model_version} fail to be deleted. Please check the log." + ) + except Exception as e: + click.echo(f"An error occurred while deleting the cache: {e}") + + @cli.command( "launch", help="Launch a model with the Xinference framework with the given parameters.", @@ -598,6 +724,13 @@ def list_model_registrations( default="LLM", help="Specify type of model, LLM as default.", ) +@click.option( + "--model-engine", + "-en", + type=str, + default=None, + help="Specify the inference engine of the model when launching LLM.", +) @click.option( "--model-uid", "-u", @@ -617,7 +750,7 @@ def list_model_registrations( "-f", default=None, type=str, - help="Specify the format of the model, e.g. pytorch, ggmlv3, etc.", + help="Specify the format of the model, e.g. pytorch, ggufv2, etc.", ) @click.option( "--quantization", @@ -640,10 +773,11 @@ def list_model_registrations( help='The number of GPUs used by the model, default is "auto".', ) @click.option( - "--peft-model-path", - default=None, - type=str, - help="PEFT model path.", + "--lora-modules", + "-lm", + multiple=True, + type=(str, str), + help="LoRA module configurations in the format name=path. Multiple modules can be specified.", ) @click.option( "--image-lora-load-kwargs", @@ -690,13 +824,14 @@ def model_launch( endpoint: Optional[str], model_name: str, model_type: str, + model_engine: Optional[str], model_uid: str, size_in_billions: str, model_format: str, quantization: str, replica: int, n_gpu: str, - peft_model_path: Optional[str], + lora_modules: Optional[Tuple], image_lora_load_kwargs: Optional[Tuple], image_lora_fuse_kwargs: Optional[Tuple], worker_ip: Optional[str], @@ -711,6 +846,9 @@ def model_launch( kwargs[ctx.args[i][2:]] = handle_click_args_type(ctx.args[i + 1]) print(f"Launch model name: {model_name} with kwargs: {kwargs}", file=sys.stderr) + if model_type == "LLM" and model_engine is None: + raise ValueError("--model-engine is required for LLM models.") + if n_gpu.lower() == "none": _n_gpu: Optional[Union[int, str]] = None elif n_gpu == "auto": @@ -729,6 +867,22 @@ def model_launch( else None ) + lora_list = ( + [{"lora_name": k, "local_path": v} for k, v in dict(lora_modules).items()] + if lora_modules + else [] + ) + + peft_model_config = ( + { + "image_lora_load_kwargs": image_lora_load_params, + "image_lora_fuse_kwargs": image_lora_fuse_params, + "lora_list": lora_list, + } + if lora_list or image_lora_load_params or image_lora_fuse_params + else None + ) + _gpu_idx: Optional[List[int]] = ( None if gpu_idx is None else [int(idx) for idx in gpu_idx.split(",")] ) @@ -736,7 +890,9 @@ def model_launch( endpoint = get_endpoint(endpoint) model_size: Optional[Union[str, int]] = ( size_in_billions - if size_in_billions is None or "_" in size_in_billions + if size_in_billions is None + or "_" in size_in_billions + or "." in size_in_billions else int(size_in_billions) ) client = RESTfulClient(base_url=endpoint, api_key=api_key) @@ -746,15 +902,14 @@ def model_launch( model_uid = client.launch_model( model_name=model_name, model_type=model_type, + model_engine=model_engine, model_uid=model_uid, model_size_in_billions=model_size, model_format=model_format, quantization=quantization, replica=replica, n_gpu=_n_gpu, - peft_model_path=peft_model_path, - image_lora_load_kwargs=image_lora_load_params, - image_lora_fuse_kwargs=image_lora_fuse_params, + peft_model_config=peft_model_config, worker_ip=worker_ip, gpu_idx=_gpu_idx, trust_remote_code=trust_remote_code, @@ -1112,9 +1267,7 @@ async def chat_internal(): task.exception() else: restful_model = client.get_model(model_uid=model_uid) - if not isinstance( - restful_model, (RESTfulChatModelHandle, RESTfulChatglmCppChatModelHandle) - ): + if not isinstance(restful_model, RESTfulChatModelHandle): raise ValueError(f"model {model_uid} has no chat method") while True: @@ -1186,5 +1339,292 @@ def cluster_login( f.write(access_token) +@cli.command(name="engine", help="Query the applicable inference engine by model name.") +@click.option( + "--model-name", + "-n", + type=str, + required=True, + help="The model name you want to query.", +) +@click.option( + "--model-engine", + "-en", + type=str, + default=None, + help="Specify the `model_engine` to query the corresponding combination of other parameters.", +) +@click.option( + "--model-format", + "-f", + type=str, + default=None, + help="Specify the `model_format` to query the corresponding combination of other parameters.", +) +@click.option( + "--model-size-in-billions", + "-s", + type=str, + default=None, + help="Specify the `model_size_in_billions` to query the corresponding combination of other parameters.", +) +@click.option( + "--quantization", + "-q", + type=str, + default=None, + help="Specify the `quantization` to query the corresponding combination of other parameters.", +) +@click.option("--endpoint", "-e", type=str, help="Xinference endpoint.") +@click.option( + "--api-key", + "-ak", + default=None, + type=str, + help="Api-Key for access xinference api with authorization.", +) +def query_engine_by_model_name( + model_name: str, + model_engine: Optional[str], + model_format: Optional[str], + model_size_in_billions: Optional[Union[str, int]], + quantization: Optional[str], + endpoint: Optional[str], + api_key: Optional[str], +): + from tabulate import tabulate + + def match_engine_from_spell(value: str, target: Sequence[str]) -> Tuple[bool, str]: + """ + For better usage experience. + """ + for t in target: + if value.lower() == t.lower(): + return True, t + return False, value + + def handle_user_passed_parameters() -> List[str]: + user_specified_parameters = [] + if model_engine is not None: + user_specified_parameters.append(f"--model-engine {model_engine}") + if model_format is not None: + user_specified_parameters.append(f"--model-format {model_format}") + if model_size_in_billions is not None: + user_specified_parameters.append( + f"--model-size-in-billions {model_size_in_billions}" + ) + if quantization is not None: + user_specified_parameters.append(f"--quantization {quantization}") + return user_specified_parameters + + user_specified_params = handle_user_passed_parameters() + + endpoint = get_endpoint(endpoint) + client = RESTfulClient(base_url=endpoint, api_key=api_key) + if api_key is None: + client._set_token(get_stored_token(endpoint, client)) + + llm_engines = client.query_engine_by_model_name(model_name) + if model_engine is not None: + is_matched, model_engine = match_engine_from_spell( + model_engine, list(llm_engines.keys()) + ) + if not is_matched: + print( + f'Xinference does not support this inference engine "{model_engine}".', + file=sys.stderr, + ) + return + + table = [] + engines = [model_engine] if model_engine is not None else list(llm_engines.keys()) + for engine in engines: + params = llm_engines[engine] + for param in params: + if ( + (model_format is None or model_format == param["model_format"]) + and ( + model_size_in_billions is None + or model_size_in_billions == str(param["model_size_in_billions"]) + ) + and (quantization is None or quantization in param["quantizations"]) + ): + if quantization is not None: + table.append( + [ + model_name, + engine, + param["model_format"], + param["model_size_in_billions"], + quantization, + ] + ) + else: + for quant in param["quantizations"]: + table.append( + [ + model_name, + engine, + param["model_format"], + param["model_size_in_billions"], + quant, + ] + ) + if len(table) == 0: + print( + f"Xinference does not support " + f"your provided params: {', '.join(user_specified_params)} for the model {model_name}.", + file=sys.stderr, + ) + else: + print( + tabulate( + table, + headers=[ + "Name", + "Engine", + "Format", + "Size (in billions)", + "Quantization", + ], + ), + file=sys.stderr, + ) + + +@cli.command( + "cal-model-mem", + help="calculate gpu mem usage with specified model size and context_length", +) +@click.option( + "--model-name", + "-n", + type=str, + help="The model name is optional.\ + If provided, fetch model config from huggingface/modelscope;\ + If not specified, use default model layer to estimate.", +) +@click.option( + "--size-in-billions", + "-s", + type=str, + required=True, + help="Specify the model size in billions of parameters. Format accept 1_8 and 1.8", +) +@click.option( + "--model-format", + "-f", + type=str, + required=True, + help="Specify the format of the model, e.g. pytorch, ggufv2, etc.", +) +@click.option( + "--quantization", + "-q", + type=str, + default=None, + help="Define the quantization settings for the model.", +) +@click.option( + "--context-length", + "-c", + type=int, + required=True, + help="Specify the context length", +) +@click.option( + "--kv-cache-dtype", + type=int, + default=16, + help="Specified the kv_cache_dtype, one of: 8, 16, 32", +) +def cal_model_mem( + model_name: Optional[str], + size_in_billions: str, + model_format: str, + quantization: Optional[str], + context_length: int, + kv_cache_dtype: int, +): + if kv_cache_dtype not in [8, 16, 32]: + print("Invalid kv_cache_dtype:", kv_cache_dtype) + os._exit(1) + + import math + + from ..model.llm.llm_family import convert_model_size_to_float + from ..model.llm.memory import estimate_llm_gpu_memory + + mem_info = estimate_llm_gpu_memory( + model_size_in_billions=size_in_billions, + quantization=quantization, + context_length=context_length, + model_format=model_format, + model_name=model_name, + kv_cache_dtype=kv_cache_dtype, + ) + if mem_info is None: + print("The Specified model parameters is not match: `%s`" % model_name) + os._exit(1) + total_mem_g = math.ceil(mem_info.total / 1024.0) + print("model_name:", model_name) + print("kv_cache_dtype:", kv_cache_dtype) + print("model size: %.1f B" % (convert_model_size_to_float(size_in_billions))) + print("quant: %s" % (quantization)) + print("context: %d" % (context_length)) + print("gpu mem usage:") + print(" model mem: %d MB" % (mem_info.model_mem)) + print(" kv_cache: %d MB" % (mem_info.kv_cache_mem)) + print(" overhead: %d MB" % (mem_info.overhead)) + print(" active: %d MB" % (mem_info.activation_mem)) + print(" total: %d MB (%d GB)" % (mem_info.total, total_mem_g)) + + +@cli.command( + "stop-cluster", + help="Stop a cluster using the Xinference framework with the given parameters.", +) +@click.option( + "--endpoint", + "-e", + type=str, + required=True, + help="Xinference endpoint.", +) +@click.option( + "--api-key", + "-ak", + default=None, + type=str, + help="API key for accessing the Xinference API with authorization.", +) +@click.option("--check", is_flag=True, help="Confirm the deletion of the cache.") +def stop_cluster(endpoint: str, api_key: Optional[str], check: bool): + endpoint = get_endpoint(endpoint) + client = RESTfulClient(base_url=endpoint, api_key=api_key) + if api_key is None: + client._set_token(get_stored_token(endpoint, client)) + + if not check: + click.echo( + f"This command will stop Xinference cluster in {endpoint}.", err=True + ) + supervisor_info = client.get_supervisor_info() + click.echo("Supervisor information: ") + click.echo(supervisor_info) + + workers_info = client.get_workers_info() + click.echo("Workers information:") + click.echo(workers_info) + + click.confirm("Continue?", abort=True) + try: + result = client.abort_cluster() + result = result.get("result") + click.echo(f"Cluster stopped: {result}") + except Exception as e: + click.echo(e) + + if __name__ == "__main__": cli() diff --git a/xinference/deploy/docker/Dockerfile b/xinference/deploy/docker/Dockerfile index 5c232f175a..b7f534d225 100644 --- a/xinference/deploy/docker/Dockerfile +++ b/xinference/deploy/docker/Dockerfile @@ -1,12 +1,17 @@ -FROM pytorch/pytorch:2.1.2-cuda12.1-cudnn8-devel +FROM vllm/vllm-openai:latest COPY . /opt/inference +WORKDIR /opt/inference ENV NVM_DIR /usr/local/nvm ENV NODE_VERSION 14.21.1 RUN apt-get -y update \ - && apt install -y curl procps git libgl1 \ + && apt install -y curl procps git libgl1 ffmpeg \ + # upgrade libstdc++ and libc for llama-cpp-python + && printf "\ndeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse" >> /etc/apt/sources.list \ + && apt-get -y update \ + && apt-get install -y --only-upgrade libstdc++6 && apt install -y libc6 \ && mkdir -p $NVM_DIR \ && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \ && . $NVM_DIR/nvm.sh \ @@ -16,14 +21,22 @@ RUN apt-get -y update \ && apt-get -yq clean ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH +ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/usr/local/lib/python3.10/dist-packages/nvidia/cublas/lib ARG PIP_INDEX=https://pypi.org/simple -RUN python -m pip install --upgrade -i "$PIP_INDEX" pip && \ - CMAKE_ARGS="-DGGML_CUBLAS=ON" pip install -i "$PIP_INDEX" -U chatglm-cpp && \ - CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install -i "$PIP_INDEX" -U llama-cpp-python && \ +RUN pip install --upgrade -i "$PIP_INDEX" pip && \ + pip install -i "$PIP_INDEX" "diskcache>=5.6.1" "jinja2>=2.11.3" && \ + # use pre-built whl package for llama-cpp-python, otherwise may core dump when init llama in some envs + pip install "llama-cpp-python>=0.2.82" -i https://abetlen.github.io/llama-cpp-python/whl/cu124 && \ + pip install -i "$PIP_INDEX" --upgrade-strategy only-if-needed -r /opt/inference/xinference/deploy/docker/requirements.txt && \ + pip install -i "$PIP_INDEX" --no-deps sglang && \ + pip uninstall flashinfer -y && \ + pip install flashinfer -i https://flashinfer.ai/whl/cu124/torch2.4 && \ cd /opt/inference && \ - python setup.py build_web && \ + python3 setup.py build_web && \ git restore . && \ - pip install -i "$PIP_INDEX" ".[all]" && \ - pip uninstall -y opencv-contrib-python && \ - pip install -i "$PIP_INDEX" opencv-contrib-python-headless + pip install -i "$PIP_INDEX" --no-deps "." && \ + # clean packages + pip cache purge + +CMD ["/bin/bash"] diff --git a/xinference/deploy/docker/cpu.Dockerfile b/xinference/deploy/docker/cpu.Dockerfile index 1d18d84f68..145d59ec57 100644 --- a/xinference/deploy/docker/cpu.Dockerfile +++ b/xinference/deploy/docker/cpu.Dockerfile @@ -6,7 +6,7 @@ ENV NVM_DIR /usr/local/nvm ENV NODE_VERSION 14.21.1 RUN apt-get -y update \ - && apt install -y build-essential curl procps git libgl1 \ + && apt install -y build-essential curl procps git libgl1 ffmpeg \ && mkdir -p $NVM_DIR \ && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash \ && . $NVM_DIR/nvm.sh \ @@ -20,49 +20,13 @@ ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH ARG PIP_INDEX=https://pypi.org/simple RUN python -m pip install --upgrade -i "$PIP_INDEX" pip && \ pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu && \ - pip install -i "$PIP_INDEX" \ - "xoscar>=0.3.0" \ - "gradio>=3.39.0" \ - pillow \ - click \ - "tqdm>=4.27" \ - tabulate \ - requests \ - pydantic \ - fastapi \ - uvicorn \ - "huggingface-hub>=0.19.4,<1.0" \ - typing_extensions \ - "fsspec>=2023.1.0,<=2023.10.0" \ - s3fs \ - "modelscope>=1.10.0" \ - "sse_starlette>=1.6.5" \ - "openai>1" \ - "python-jose[cryptography]" \ - "passlib[bcrypt]" \ - "aioprometheus[starlette]>=23.12.0" \ - pynvml \ - async-timeout \ - "transformers>=4.34.1" \ - "accelerate>=0.20.3" \ - sentencepiece \ - transformers_stream_generator \ - bitsandbytes \ - protobuf \ - einops \ - tiktoken \ - "sentence-transformers>=2.3.1" \ - diffusers \ - controlnet_aux \ - orjson \ - auto-gptq \ - optimum \ - peft \ - timm \ - opencv-contrib-python-headless && \ - pip install -i "$PIP_INDEX" -U chatglm-cpp && \ - pip install -i "$PIP_INDEX" "llama-cpp-python>=0.2.25,!=0.2.58" && \ + pip install -i "$PIP_INDEX" --upgrade-strategy only-if-needed -r /opt/inference/xinference/deploy/docker/requirements_cpu.txt && \ + CMAKE_ARGS="-DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS" pip install llama-cpp-python && \ cd /opt/inference && \ python setup.py build_web && \ git restore . && \ - pip install -i "$PIP_INDEX" --no-deps "." + pip install -i "$PIP_INDEX" --no-deps "." && \ + # clean packages + pip cache purge + +CMD ["/bin/bash"] diff --git a/xinference/deploy/docker/requirements.txt b/xinference/deploy/docker/requirements.txt new file mode 100644 index 0000000000..a5b5749618 --- /dev/null +++ b/xinference/deploy/docker/requirements.txt @@ -0,0 +1,85 @@ +# required +xoscar>=0.3.0 +gradio==4.26.0 +typer[all]<0.12.0 # fix typer required by gradio +pillow +click +tqdm>=4.27 +tabulate +requests +pydantic +fastapi==0.110.3 +uvicorn +huggingface-hub>=0.19.4 +typing_extensions +modelscope>=1.10.0 +sse_starlette>=1.6.5 # ensure_bytes API break change: https://github.com/sysid/sse-starlette/issues/65 +openai>1,<1.40 # For typing +python-jose[cryptography] +passlib[bcrypt] +aioprometheus[starlette]>=23.12.0 +pynvml +async-timeout +peft +opencv-contrib-python-headless + +# all +transformers>=4.34.1 +accelerate>=0.27.2 +sentencepiece +transformers_stream_generator +bitsandbytes +protobuf +einops +tiktoken +sentence-transformers>=2.7.0 +diffusers>=0.30.0 +controlnet_aux +orjson +auto-gptq +autoawq<0.2.6 # autoawq 0.2.6 pinned torch to 2.3 +optimum +attrdict # For deepseek VL +timm>=0.9.16 # For deepseek VL +torchvision # For deepseek VL +FlagEmbedding # For rerank +funasr +omegaconf~=2.3.0 # For ChatTTS +nemo_text_processing<1.1.0 # 1.1.0 requires pynini==2.1.6.post1 +WeTextProcessing<1.0.4 # 1.0.4 requires pynini==2.1.6 +librosa # For ChatTTS +torchaudio # For ChatTTS +ChatTTS>0.1 +xxhash # For ChatTTS +torch>=2.0.0 # For CosyVoice +lightning>=2.0.0 # For CosyVoice, matcha +hydra-core>=1.3.2 # For CosyVoice, matcha +inflect # For CosyVoice, matcha +conformer # For CosyVoice, matcha +diffusers>=0.30.0 # For CosyVoice, matcha +gdown # For CosyVoice, matcha +pyarrow # For CosyVoice, matcha +HyperPyYAML # For CosyVoice +onnxruntime-gpu==1.16.0; sys_platform == 'linux' # For CosyVoice +onnxruntime==1.16.0; sys_platform == 'darwin' or sys_platform == 'windows' # For CosyVoice +openai-whisper # For CosyVoice +boto3>=1.28.55,<1.28.65 # For tensorizer +tensorizer~=2.9.0 +imageio-ffmpeg # For video +eva-decord # For video in VL +jj-pytorchvideo # For CogVLM2-video +loguru # For Fish Speech +natsort # For Fish Speech +loralib # For Fish Speech + +# sglang +outlines>=0.0.44 +hf_transfer +packaging +interegular +zmq +rpyc +psutil +aiohttp +anthropic>=0.20.0 +litellm>=1.0.0 diff --git a/xinference/deploy/docker/requirements_cpu.txt b/xinference/deploy/docker/requirements_cpu.txt new file mode 100644 index 0000000000..048c31a3fa --- /dev/null +++ b/xinference/deploy/docker/requirements_cpu.txt @@ -0,0 +1,68 @@ +xoscar>=0.3.0 +gradio==4.26.0 +typer[all]<0.12.0 +pillow +click +tqdm>=4.27 +tabulate +requests +pydantic +fastapi==0.110.3 +uvicorn +huggingface-hub>=0.19.4 +typing_extensions +boto3>=1.28.55,<1.28.65 +tensorizer~=2.9.0 +modelscope>=1.10.0 +sse_starlette>=1.6.5 +openai>1,<1.40 +python-jose[cryptography] +passlib[bcrypt] +aioprometheus[starlette]>=23.12.0 +pynvml +async-timeout +transformers>=4.34.1 +accelerate>=0.20.3 +sentencepiece +transformers_stream_generator +bitsandbytes +protobuf +einops +tiktoken +sentence-transformers>=2.3.1 +FlagEmbedding +diffusers>=0.30.0 +controlnet_aux +orjson +auto-gptq +autoawq<0.2.6 # autoawq 0.2.6 pinned torch to 2.3 +optimum +peft +timm +opencv-contrib-python-headless +funasr +omegaconf~=2.3.0 # For ChatTTS +nemo_text_processing<1.1.0 # 1.1.0 requires pynini==2.1.6.post1 +WeTextProcessing<1.0.4 # 1.0.4 requires pynini==2.1.6 +librosa # For ChatTTS +torchaudio # For ChatTTS +ChatTTS>0.1 +xxhash # For ChatTTS +torch>=2.0.0 # For CosyVoice +lightning>=2.0.0 # For CosyVoice, matcha +hydra-core>=1.3.2 # For CosyVoice, matcha +inflect # For CosyVoice, matcha +conformer # For CosyVoice, matcha +diffusers>=0.30.0 # For CosyVoice, matcha +gdown # For CosyVoice, matcha +pyarrow # For CosyVoice, matcha +HyperPyYAML # For CosyVoice +onnxruntime-gpu==1.16.0; sys_platform == 'linux' # For CosyVoice +onnxruntime==1.16.0; sys_platform == 'darwin' or sys_platform == 'windows' # For CosyVoice +openai-whisper # For CosyVoice +imageio-ffmpeg # For video +eva-decord # For video in VL +jj-pytorchvideo # For CogVLM2-video +loguru # For Fish Speech +natsort # For Fish Speech +loralib # For Fish Speech diff --git a/xinference/deploy/test/test_cmdline.py b/xinference/deploy/test/test_cmdline.py index 6d36ade8cc..905b83a9a7 100644 --- a/xinference/deploy/test/test_cmdline.py +++ b/xinference/deploy/test/test_cmdline.py @@ -19,12 +19,14 @@ from ...client import Client from ..cmdline import ( + list_cached_models, list_model_registrations, model_chat, model_generate, model_list, model_terminate, register_model, + remove_cache, unregister_model, ) @@ -64,9 +66,10 @@ def test_cmdline(setup, stream, model_uid): replica = 1 original_model_uid = model_uid model_uid = client.launch_model( - model_name="orca", + model_name="qwen1.5-chat", + model_engine="llama.cpp", model_uid=model_uid, - model_size_in_billions=3, + model_size_in_billions="0_5", quantization="q4_0", replica=replica, ) @@ -246,9 +249,10 @@ def test_rotate_logs(setup_with_file_logging): runner = CliRunner() replica = 1 if os.name == "nt" else 2 model_uid = client.launch_model( - model_name="orca", + model_name="qwen1.5-chat", + model_engine="llama.cpp", model_uid=None, - model_size_in_billions=3, + model_size_in_billions="0_5", quantization="q4_0", replica=replica, ) @@ -276,3 +280,34 @@ def test_rotate_logs(setup_with_file_logging): with open(log_file, "r") as f: content = f.read() assert len(content) > 0 + + +def test_list_cached_models(setup): + endpoint, _ = setup + runner = CliRunner() + + result = runner.invoke( + list_cached_models, + ["--endpoint", endpoint, "--model_name", "qwen1.5-chat"], + ) + assert "model_name" in result.stdout + assert "model_format" in result.stdout + assert "model_size_in_billions" in result.stdout + assert "quantization" in result.stdout + assert "model_version" in result.stdout + assert "path" in result.stdout + assert "actor_ip_address" in result.stdout + + +def test_remove_cache(setup): + endpoint, _ = setup + runner = CliRunner() + + result = runner.invoke( + remove_cache, + ["--endpoint", endpoint, "--model_version", "qwen1.5-chat"], + input="y\n", + ) + + assert result.exit_code == 0 + assert "Cache directory qwen1.5-chat has been deleted." diff --git a/xinference/deploy/utils.py b/xinference/deploy/utils.py index bb0738b002..3058c2b1f1 100644 --- a/xinference/deploy/utils.py +++ b/xinference/deploy/utils.py @@ -27,6 +27,9 @@ logger = logging.getLogger(__name__) +# mainly for k8s +XINFERENCE_POD_NAME_ENV_KEY = "XINFERENCE_POD_NAME" + class LoggerNameFilter(logging.Filter): def filter(self, record): @@ -40,6 +43,9 @@ def get_log_file(sub_dir: str): """ sub_dir should contain a timestamp. """ + pod_name = os.environ.get(XINFERENCE_POD_NAME_ENV_KEY, None) + if pod_name is not None: + sub_dir = sub_dir + "_" + pod_name log_dir = os.path.join(XINFERENCE_LOG_DIR, sub_dir) # Here should be creating a new directory each time, so `exist_ok=False` os.makedirs(log_dir, exist_ok=False) @@ -79,6 +85,12 @@ def get_config_dict( "stream": "ext://sys.stderr", "filters": ["logger_name_filter"], }, + "console_handler": { + "class": "logging.StreamHandler", + "formatter": "formatter", + "level": log_level, + "stream": "ext://sys.stderr", + }, "file_handler": { "class": "logging.handlers.RotatingFileHandler", "formatter": "formatter", @@ -95,7 +107,32 @@ def get_config_dict( "handlers": ["stream_handler", "file_handler"], "level": log_level, "propagate": False, - } + }, + "uvicorn": { + "handlers": ["stream_handler", "file_handler"], + "level": log_level, + "propagate": False, + }, + "uvicorn.error": { + "handlers": ["stream_handler", "file_handler"], + "level": log_level, + "propagate": False, + }, + "uvicorn.access": { + "handlers": ["stream_handler", "file_handler"], + "level": log_level, + "propagate": False, + }, + "transformers": { + "handlers": ["console_handler", "file_handler"], + "level": log_level, + "propagate": False, + }, + "vllm": { + "handlers": ["console_handler", "file_handler"], + "level": log_level, + "propagate": False, + }, }, "root": { "level": "WARN", @@ -127,9 +164,9 @@ async def health_check_internal(): while attempts < max_attempts: time.sleep(sleep_interval) try: - from xinference.core.supervisor import SupervisorActor + from ..core.supervisor import SupervisorActor - supervisor_ref: xo.ActorRefType[SupervisorActor] = await xo.actor_ref( + supervisor_ref: xo.ActorRefType[SupervisorActor] = await xo.actor_ref( # type: ignore address=address, uid=SupervisorActor.uid() ) diff --git a/xinference/device_utils.py b/xinference/device_utils.py index 035391ccb4..d4d4f0d9e9 100644 --- a/xinference/device_utils.py +++ b/xinference/device_utils.py @@ -17,13 +17,27 @@ import torch from typing_extensions import Literal, Union -DeviceType = Literal["cuda", "mps", "xpu", "cpu"] +DeviceType = Literal["cuda", "mps", "xpu", "npu", "cpu"] +DEVICE_TO_ENV_NAME = { + "cuda": "CUDA_VISIBLE_DEVICES", + "npu": "ASCEND_RT_VISIBLE_DEVICES", +} def is_xpu_available() -> bool: return hasattr(torch, "xpu") and torch.xpu.is_available() +def is_npu_available() -> bool: + try: + import torch + import torch_npu # noqa: F401 + + return torch.npu.is_available() + except ImportError: + return False + + def get_available_device() -> DeviceType: if torch.cuda.is_available(): return "cuda" @@ -31,6 +45,8 @@ def get_available_device() -> DeviceType: return "mps" elif is_xpu_available(): return "xpu" + elif is_npu_available(): + return "npu" return "cpu" @@ -41,6 +57,8 @@ def is_device_available(device: str) -> bool: return torch.backends.mps.is_available() elif device == "xpu": return is_xpu_available() + elif device == "npu": + return is_npu_available() elif device == "cpu": return True @@ -59,7 +77,7 @@ def move_model_to_available_device(model): def get_device_preferred_dtype(device: str) -> Union[torch.dtype, None]: if device == "cpu": return torch.float32 - elif device == "cuda" or device == "mps": + elif device == "cuda" or device == "mps" or device == "npu": return torch.float16 elif device == "xpu": return torch.bfloat16 @@ -68,7 +86,7 @@ def get_device_preferred_dtype(device: str) -> Union[torch.dtype, None]: def is_hf_accelerate_supported(device: str) -> bool: - return device == "cuda" or device == "xpu" + return device == "cuda" or device == "xpu" or device == "npu" def empty_cache(): @@ -78,6 +96,12 @@ def empty_cache(): torch.mps.empty_cache() if is_xpu_available(): torch.xpu.empty_cache() + if is_npu_available(): + torch.npu.empty_cache() + + +def get_available_device_env_name(): + return DEVICE_TO_ENV_NAME.get(get_available_device()) def gpu_count(): @@ -94,5 +118,7 @@ def gpu_count(): return min(torch.cuda.device_count(), len(cuda_visible_devices)) elif is_xpu_available(): return torch.xpu.device_count() + elif is_npu_available(): + return torch.npu.device_count() else: return 0 diff --git a/xinference/fields.py b/xinference/fields.py index e68f6c85c9..84f36ce587 100644 --- a/xinference/fields.py +++ b/xinference/fields.py @@ -32,7 +32,6 @@ max_tokens_field = Field( default=1024, ge=1, - le=32768, description="The maximum number of tokens to generate.", ) @@ -75,6 +74,13 @@ description="Whether to stream the results as they are generated. Useful for chatbots.", ) +stream_option_field = Field( + default={ + "include_usage": False, + }, + description="If set, an additional chunk will be streamed before the `data: [DONE]` message.", +) + top_k_field = Field( default=40, ge=0, diff --git a/xinference/isolation.py b/xinference/isolation.py index c7bc3e2a36..e4c852d41f 100644 --- a/xinference/isolation.py +++ b/xinference/isolation.py @@ -19,13 +19,19 @@ class Isolation: # TODO: better move isolation to xoscar. - def __init__(self, loop: asyncio.AbstractEventLoop, threaded: bool = True): + def __init__( + self, + loop: asyncio.AbstractEventLoop, + threaded: bool = True, + daemon: bool = True, + ): self._loop = loop self._threaded = threaded self._stopped = None self._thread = None self._thread_ident = None + self._daemon = daemon def _run(self): asyncio.set_event_loop(self._loop) @@ -35,7 +41,8 @@ def _run(self): def start(self): if self._threaded: self._thread = thread = threading.Thread(target=self._run) - thread.daemon = True + if self._daemon: + thread.daemon = True thread.start() self._thread_ident = thread.ident diff --git a/xinference/locale/utils.py b/xinference/locale/utils.py deleted file mode 100644 index 4a0a1027f8..0000000000 --- a/xinference/locale/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import codecs -import json -import locale -import os -from typing import Optional - - -class Locale: - def __init__(self, language: Optional[str] = None): - self._language = ( - language if language is not None else locale.getdefaultlocale()[0] - ) - json_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), f"{self._language}.json" - ) - if os.path.exists(json_path): - self._mapping = json.load(codecs.open(json_path, "r", encoding="utf-8")) - else: - self._mapping = None - - def __call__(self, content: str): - if self._mapping is None: - return content - else: - return self._mapping.get(content, content) diff --git a/xinference/locale/zh_CN.json b/xinference/locale/zh_CN.json deleted file mode 100644 index 8b8ea103c1..0000000000 --- a/xinference/locale/zh_CN.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "Please create model first": "请先创建模型", - "stop reason": "停止原因", - "Show stop reason": "展示停止原因", - "Max tokens": "最大 token 数量", - "The maximum number of tokens to generate.": "生成 token 数量最大值", - "Temperature": "温度参数", - "The temperature to use for sampling.": "温度参数用于调整输出的多样性,数值越高多样性越高", - "Top P": "Top P", - "The top-p value to use for sampling.": "用于控制生成文本的确定性,数值越低确定性越高", - "Window size": "窗口大小", - "Window size of chat history.": "用于生成回复的聊天历史窗口大小", - "show stop reason": "展示停止原因", - "Downloading": "下载中", - "Download failed, please retry.": "下载失败,请重新下载", - "model name": "模型名", - "model format": "模型格式", - "model size in billions": "模型大小(B)", - "quantization": "模型量化方式", - "Parameters": "参数调整", - "create": "创建", - "select model": "选择模型", - "Arena": "角斗场", - "Chat": "聊天", - "Input": "输入" -} diff --git a/xinference/model/audio/__init__.py b/xinference/model/audio/__init__.py index 8bc2e03ade..fe33f5d629 100644 --- a/xinference/model/audio/__init__.py +++ b/xinference/model/audio/__init__.py @@ -16,12 +16,64 @@ import json import os -from .core import AudioModelFamilyV1, generate_audio_description, get_cache_status +from .core import ( + AUDIO_MODEL_DESCRIPTIONS, + MODEL_NAME_TO_REVISION, + AudioModelFamilyV1, + generate_audio_description, + get_audio_model_descriptions, + get_cache_status, +) +from .custom import ( + CustomAudioModelFamilyV1, + get_user_defined_audios, + register_audio, + unregister_audio, +) _model_spec_json = os.path.join(os.path.dirname(__file__), "model_spec.json") +_model_spec_modelscope_json = os.path.join( + os.path.dirname(__file__), "model_spec_modelscope.json" +) BUILTIN_AUDIO_MODELS = dict( (spec["model_name"], AudioModelFamilyV1(**spec)) for spec in json.load(codecs.open(_model_spec_json, "r", encoding="utf-8")) ) +for model_name, model_spec in BUILTIN_AUDIO_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) + +MODELSCOPE_AUDIO_MODELS = dict( + (spec["model_name"], AudioModelFamilyV1(**spec)) + for spec in json.load( + codecs.open(_model_spec_modelscope_json, "r", encoding="utf-8") + ) +) +for model_name, model_spec in MODELSCOPE_AUDIO_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) + +# register model description after recording model revision +for model_spec_info in [BUILTIN_AUDIO_MODELS, MODELSCOPE_AUDIO_MODELS]: + for model_name, model_spec in model_spec_info.items(): + if model_spec.model_name not in AUDIO_MODEL_DESCRIPTIONS: + AUDIO_MODEL_DESCRIPTIONS.update(generate_audio_description(model_spec)) + +from ...constants import XINFERENCE_MODEL_DIR + +# if persist=True, load them when init +user_defined_audio_dir = os.path.join(XINFERENCE_MODEL_DIR, "audio") +if os.path.isdir(user_defined_audio_dir): + for f in os.listdir(user_defined_audio_dir): + with codecs.open( + os.path.join(user_defined_audio_dir, f), encoding="utf-8" + ) as fd: + user_defined_audio_family = CustomAudioModelFamilyV1.parse_obj( + json.load(fd) + ) + register_audio(user_defined_audio_family, persist=False) + +# register model description +for ud_audio in get_user_defined_audios(): + AUDIO_MODEL_DESCRIPTIONS.update(generate_audio_description(ud_audio)) del _model_spec_json +del _model_spec_modelscope_json diff --git a/xinference/model/audio/chattts.py b/xinference/model/audio/chattts.py new file mode 100644 index 0000000000..1d895a62ba --- /dev/null +++ b/xinference/model/audio/chattts.py @@ -0,0 +1,132 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import logging +from io import BytesIO +from typing import TYPE_CHECKING, Optional + +from ..utils import set_all_random_seed + +if TYPE_CHECKING: + from .core import AudioModelFamilyV1 + +logger = logging.getLogger(__name__) + + +class ChatTTSModel: + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: "AudioModelFamilyV1", + device: Optional[str] = None, + **kwargs, + ): + self._model_uid = model_uid + self._model_path = model_path + self._model_spec = model_spec + self._device = device + self._model = None + self._kwargs = kwargs + + def load(self): + import ChatTTS + import torch + + torch._dynamo.config.cache_size_limit = 64 + torch._dynamo.config.suppress_errors = True + torch.set_float32_matmul_precision("high") + self._model = ChatTTS.Chat() + self._model.load(source="custom", custom_path=self._model_path, compile=True) + + def speech( + self, + input: str, + voice: str, + response_format: str = "mp3", + speed: float = 1.0, + stream: bool = False, + ): + import ChatTTS + import numpy as np + import torch + import torchaudio + import xxhash + + rnd_spk_emb = None + + if len(voice) > 400: + try: + assert self._model is not None + b = base64.b64decode(voice) + bio = BytesIO(b) + tensor = torch.load(bio, map_location="cpu") + rnd_spk_emb = self._model._encode_spk_emb(tensor) + logger.info("Speech by input speaker") + except Exception as e: + logger.info("Fallback to random speaker due to %s", e) + + if rnd_spk_emb is None: + seed = xxhash.xxh32_intdigest(voice) + + set_all_random_seed(seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + + assert self._model is not None + rnd_spk_emb = self._model.sample_random_speaker() + logger.info("Speech by voice %s", voice) + + default = 5 + infer_speed = int(default * speed) + params_infer_code = ChatTTS.Chat.InferCodeParams( + prompt=f"[speed_{infer_speed}]", spk_emb=rnd_spk_emb + ) + + assert self._model is not None + if stream: + iter = self._model.infer( + [input], params_infer_code=params_infer_code, stream=True + ) + + def _generator(): + with BytesIO() as out: + writer = torchaudio.io.StreamWriter(out, format=response_format) + writer.add_audio_stream(sample_rate=24000, num_channels=1) + i = 0 + last_pos = 0 + with writer.open(): + for it in iter: + for itt in it: + for chunk in itt: + chunk = np.array([chunk]).transpose() + writer.write_audio_chunk(i, torch.from_numpy(chunk)) + new_last_pos = out.tell() + if new_last_pos != last_pos: + out.seek(last_pos) + encoded_bytes = out.read() + yield encoded_bytes + last_pos = new_last_pos + + return _generator() + else: + wavs = self._model.infer([input], params_infer_code=params_infer_code) + + # Save the generated audio + with BytesIO() as out: + torchaudio.save( + out, torch.from_numpy(wavs[0]), 24000, format=response_format + ) + return out.getvalue() diff --git a/xinference/model/audio/core.py b/xinference/model/audio/core.py index c73004e4ea..b6a65a572d 100644 --- a/xinference/model/audio/core.py +++ b/xinference/model/audio/core.py @@ -14,25 +14,42 @@ import logging import os from collections import defaultdict -from typing import Dict, List, Optional, Tuple +from typing import Any, Dict, List, Literal, Optional, Tuple, Union -from ..._compat import BaseModel from ...constants import XINFERENCE_CACHE_DIR -from ..core import ModelDescription +from ..core import CacheableModelSpec, ModelDescription from ..utils import valid_model_revision +from .chattts import ChatTTSModel +from .cosyvoice import CosyVoiceModel +from .fish_speech import FishSpeechModel +from .funasr import FunASRModel from .whisper import WhisperModel MAX_ATTEMPTS = 3 logger = logging.getLogger(__name__) +# Used for check whether the model is cached. +# Init when registering all the builtin models. +MODEL_NAME_TO_REVISION: Dict[str, List[str]] = defaultdict(list) +AUDIO_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) -class AudioModelFamilyV1(BaseModel): + +def get_audio_model_descriptions(): + import copy + + return copy.deepcopy(AUDIO_MODEL_DESCRIPTIONS) + + +class AudioModelFamilyV1(CacheableModelSpec): model_family: str model_name: str model_id: str model_revision: str multilingual: bool + ability: str + default_model_config: Optional[Dict[str, Any]] + default_transcription_config: Optional[Dict[str, Any]] class AudioModelDescription(ModelDescription): @@ -77,63 +94,47 @@ def generate_audio_description( image_model: AudioModelFamilyV1, ) -> Dict[str, List[Dict]]: res = defaultdict(list) - res[image_model.model_name].extend( - AudioModelDescription(None, None, image_model).to_dict() + res[image_model.model_name].append( + AudioModelDescription(None, None, image_model).to_version_info() ) return res -def match_model(model_name: str) -> AudioModelFamilyV1: - from . import BUILTIN_AUDIO_MODELS +def match_audio( + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, +) -> AudioModelFamilyV1: + from ..utils import download_from_modelscope + from . import BUILTIN_AUDIO_MODELS, MODELSCOPE_AUDIO_MODELS + from .custom import get_user_defined_audios - if model_name in BUILTIN_AUDIO_MODELS: + for model_spec in get_user_defined_audios(): + if model_spec.model_name == model_name: + return model_spec + + if download_hub == "huggingface" and model_name in BUILTIN_AUDIO_MODELS: + logger.debug(f"Audio model {model_name} found in huggingface.") + return BUILTIN_AUDIO_MODELS[model_name] + elif download_hub == "modelscope" and model_name in MODELSCOPE_AUDIO_MODELS: + logger.debug(f"Audio model {model_name} found in ModelScope.") + return MODELSCOPE_AUDIO_MODELS[model_name] + elif download_from_modelscope() and model_name in MODELSCOPE_AUDIO_MODELS: + logger.debug(f"Audio model {model_name} found in ModelScope.") + return MODELSCOPE_AUDIO_MODELS[model_name] + elif model_name in BUILTIN_AUDIO_MODELS: + logger.debug(f"Audio model {model_name} found in huggingface.") return BUILTIN_AUDIO_MODELS[model_name] else: raise ValueError( - f"Image model {model_name} not found, available" + f"Audio model {model_name} not found, available" f"model list: {BUILTIN_AUDIO_MODELS.keys()}" ) def cache(model_spec: AudioModelFamilyV1): - # TODO: cache from uri - import huggingface_hub + from ..utils import cache - cache_dir = get_cache_dir(model_spec) - if not os.path.exists(cache_dir): - os.makedirs(cache_dir, exist_ok=True) - - meta_path = os.path.join(cache_dir, "__valid_download") - if valid_model_revision(meta_path, model_spec.model_revision): - return cache_dir - - for current_attempt in range(1, MAX_ATTEMPTS + 1): - try: - huggingface_hub.snapshot_download( - model_spec.model_id, - revision=model_spec.model_revision, - local_dir=cache_dir, - local_dir_use_symlinks=True, - resume_download=True, - ) - break - except huggingface_hub.utils.LocalEntryNotFoundError: - remaining_attempts = MAX_ATTEMPTS - current_attempt - logger.warning( - f"Attempt {current_attempt} failed. Remaining attempts: {remaining_attempts}" - ) - else: - raise RuntimeError( - f"Failed to download model '{model_spec.model_name}' after {MAX_ATTEMPTS} attempts" - ) - - with open(meta_path, "w") as f: - import json - - desc = AudioModelDescription(None, None, model_spec) - json.dump(desc.to_dict(), f) - - return cache_dir + return cache(model_spec, AudioModelDescription) def get_cache_dir(model_spec: AudioModelFamilyV1): @@ -149,12 +150,36 @@ def get_cache_status( def create_audio_model_instance( - subpool_addr: str, devices: List[str], model_uid: str, model_name: str, **kwargs -) -> Tuple[WhisperModel, AudioModelDescription]: - model_spec = match_model(model_name) - model_path = cache(model_spec) - model = WhisperModel(model_uid, model_path, model_spec, **kwargs) + subpool_addr: str, + devices: List[str], + model_uid: str, + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, + **kwargs, +) -> Tuple[ + Union[WhisperModel, FunASRModel, ChatTTSModel, CosyVoiceModel, FishSpeechModel], + AudioModelDescription, +]: + model_spec = match_audio(model_name, download_hub) + if model_path is None: + model_path = cache(model_spec) + model: Union[ + WhisperModel, FunASRModel, ChatTTSModel, CosyVoiceModel, FishSpeechModel + ] + if model_spec.model_family == "whisper": + model = WhisperModel(model_uid, model_path, model_spec, **kwargs) + elif model_spec.model_family == "funasr": + model = FunASRModel(model_uid, model_path, model_spec, **kwargs) + elif model_spec.model_family == "ChatTTS": + model = ChatTTSModel(model_uid, model_path, model_spec, **kwargs) + elif model_spec.model_family == "CosyVoice": + model = CosyVoiceModel(model_uid, model_path, model_spec, **kwargs) + elif model_spec.model_family == "FishAudio": + model = FishSpeechModel(model_uid, model_path, model_spec, **kwargs) + else: + raise Exception(f"Unsupported audio model family: {model_spec.model_family}") model_description = AudioModelDescription( - subpool_addr, devices, model_spec, model_path=model_path + subpool_addr, devices, model_spec, model_path ) return model, model_description diff --git a/xinference/model/audio/cosyvoice.py b/xinference/model/audio/cosyvoice.py new file mode 100644 index 0000000000..6dff9f2beb --- /dev/null +++ b/xinference/model/audio/cosyvoice.py @@ -0,0 +1,137 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import io +import logging +from io import BytesIO +from typing import TYPE_CHECKING, Optional + +from ..utils import set_all_random_seed + +if TYPE_CHECKING: + from .core import AudioModelFamilyV1 + +logger = logging.getLogger(__name__) + + +class CosyVoiceModel: + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: "AudioModelFamilyV1", + device: Optional[str] = None, + **kwargs, + ): + self._model_uid = model_uid + self._model_path = model_path + self._model_spec = model_spec + self._device = device + self._model = None + self._kwargs = kwargs + + def load(self): + import os + import sys + + # The yaml config loaded from model has hard-coded the import paths. please refer to: load_hyperpyyaml + sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../thirdparty")) + + from cosyvoice.cli.cosyvoice import CosyVoice + + self._model = CosyVoice(self._model_path) + + def speech( + self, + input: str, + voice: str, + response_format: str = "mp3", + speed: float = 1.0, + stream: bool = False, + **kwargs, + ): + if stream: + raise Exception("CosyVoiceModel does not support stream.") + + import torchaudio + from cosyvoice.utils.file_utils import load_wav + + prompt_speech: Optional[bytes] = kwargs.pop("prompt_speech", None) + prompt_text: Optional[str] = kwargs.pop("prompt_text", None) + instruct_text: Optional[str] = kwargs.pop("instruct_text", None) + seed: Optional[int] = kwargs.pop("seed", 0) + + if "SFT" in self._model_spec.model_name: + # inference_sft + assert ( + prompt_speech is None + ), "CosyVoice SFT model does not support prompt_speech" + assert ( + prompt_text is None + ), "CosyVoice SFT model does not support prompt_text" + assert ( + instruct_text is None + ), "CosyVoice SFT model does not support instruct_text" + elif "Instruct" in self._model_spec.model_name: + # inference_instruct + assert ( + prompt_speech is None + ), "CosyVoice Instruct model does not support prompt_speech" + assert ( + prompt_text is None + ), "CosyVoice Instruct model does not support prompt_text" + else: + # inference_zero_shot + # inference_cross_lingual + assert prompt_speech is not None, "CosyVoice model expect a prompt_speech" + assert ( + instruct_text is None + ), "CosyVoice model does not support instruct_text" + + assert self._model is not None + set_all_random_seed(seed) + if prompt_speech: + assert not voice, "voice can't be set with prompt speech." + with io.BytesIO(prompt_speech) as prompt_speech_io: + prompt_speech_16k = load_wav(prompt_speech_io, 16000) + if prompt_text: + logger.info("CosyVoice inference_zero_shot") + output = self._model.inference_zero_shot( + input, prompt_text, prompt_speech_16k + ) + else: + logger.info("CosyVoice inference_cross_lingual") + output = self._model.inference_cross_lingual( + input, prompt_speech_16k + ) + else: + available_speakers = self._model.list_avaliable_spks() + if not voice: + voice = available_speakers[0] + else: + assert ( + voice in available_speakers + ), f"Invalid voice {voice}, CosyVoice available speakers: {available_speakers}" + if instruct_text: + logger.info("CosyVoice inference_instruct") + output = self._model.inference_instruct( + input, voice, instruct_text=instruct_text + ) + else: + logger.info("CosyVoice inference_sft") + output = self._model.inference_sft(input, voice) + + # Save the generated audio + with BytesIO() as out: + torchaudio.save(out, output["tts_speech"], 22050, format=response_format) + return out.getvalue() diff --git a/xinference/model/audio/custom.py b/xinference/model/audio/custom.py new file mode 100644 index 0000000000..be2c388fda --- /dev/null +++ b/xinference/model/audio/custom.py @@ -0,0 +1,149 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +from threading import Lock +from typing import Any, List, Optional + +from ..._compat import ( + ROOT_KEY, + ErrorWrapper, + Protocol, + StrBytes, + ValidationError, + load_str_bytes, +) +from ...constants import XINFERENCE_CACHE_DIR, XINFERENCE_MODEL_DIR +from .core import AudioModelFamilyV1 + +logger = logging.getLogger(__name__) + +UD_AUDIO_LOCK = Lock() + + +class CustomAudioModelFamilyV1(AudioModelFamilyV1): + model_id: Optional[str] # type: ignore + model_revision: Optional[str] # type: ignore + model_uri: Optional[str] + + @classmethod + def parse_raw( + cls: Any, + b: StrBytes, + *, + content_type: Optional[str] = None, + encoding: str = "utf8", + proto: Protocol = None, + allow_pickle: bool = False, + ) -> AudioModelFamilyV1: + # See source code of BaseModel.parse_raw + try: + obj = load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=cls.__config__.json_loads, + ) + except (ValueError, TypeError, UnicodeDecodeError) as e: + raise ValidationError([ErrorWrapper(e, loc=ROOT_KEY)], cls) + + audio_spec: AudioModelFamilyV1 = cls.parse_obj(obj) + + # check model_family + if audio_spec.model_family is None: + raise ValueError( + f"You must specify `model_family` when registering custom Audio models." + ) + assert isinstance(audio_spec.model_family, str) + return audio_spec + + +UD_AUDIOS: List[CustomAudioModelFamilyV1] = [] + + +def get_user_defined_audios() -> List[CustomAudioModelFamilyV1]: + with UD_AUDIO_LOCK: + return UD_AUDIOS.copy() + + +def register_audio(model_spec: CustomAudioModelFamilyV1, persist: bool): + from ...constants import XINFERENCE_MODEL_DIR + from ..utils import is_valid_model_name, is_valid_model_uri + from . import BUILTIN_AUDIO_MODELS, MODELSCOPE_AUDIO_MODELS + + if not is_valid_model_name(model_spec.model_name): + raise ValueError(f"Invalid model name {model_spec.model_name}.") + + model_uri = model_spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}.") + + with UD_AUDIO_LOCK: + for model_name in ( + list(BUILTIN_AUDIO_MODELS.keys()) + + list(MODELSCOPE_AUDIO_MODELS.keys()) + + [spec.model_name for spec in UD_AUDIOS] + ): + if model_spec.model_name == model_name: + raise ValueError( + f"Model name conflicts with existing model {model_spec.model_name}" + ) + + UD_AUDIOS.append(model_spec) + + if persist: + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "audio", f"{model_spec.model_name}.json" + ) + os.makedirs(os.path.dirname(persist_path), exist_ok=True) + with open(persist_path, mode="w") as fd: + fd.write(model_spec.json()) + + +def unregister_audio(model_name: str, raise_error: bool = True): + with UD_AUDIO_LOCK: + model_spec = None + for i, f in enumerate(UD_AUDIOS): + if f.model_name == model_name: + model_spec = f + break + if model_spec: + UD_AUDIOS.remove(model_spec) + + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "audio", f"{model_spec.model_name}.json" + ) + if os.path.exists(persist_path): + os.remove(persist_path) + + cache_dir = os.path.join(XINFERENCE_CACHE_DIR, model_spec.model_name) + if os.path.exists(cache_dir): + logger.warning( + f"Remove the cache of user-defined model {model_spec.model_name}. " + f"Cache directory: {cache_dir}" + ) + if os.path.isdir(cache_dir): + os.rmdir(cache_dir) + else: + logger.warning( + f"Cache directory is not a soft link, please remove it manually." + ) + else: + if raise_error: + raise ValueError(f"Model {model_name} not found") + else: + logger.warning(f"Custom audio model {model_name} not found") diff --git a/xinference/model/audio/fish_speech.py b/xinference/model/audio/fish_speech.py new file mode 100644 index 0000000000..642b575a27 --- /dev/null +++ b/xinference/model/audio/fish_speech.py @@ -0,0 +1,228 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import gc +import logging +import os.path +import queue +import sys +from io import BytesIO +from typing import TYPE_CHECKING, Optional + +import numpy as np +import torch + +from ...device_utils import get_available_device, is_device_available + +if TYPE_CHECKING: + from .core import AudioModelFamilyV1 + +logger = logging.getLogger(__name__) + + +def wav_chunk_header(sample_rate=44100, bit_depth=16, channels=1): + import wave + + buffer = BytesIO() + + with wave.open(buffer, "wb") as wav_file: + wav_file.setnchannels(channels) + wav_file.setsampwidth(bit_depth // 8) + wav_file.setframerate(sample_rate) + + wav_header_bytes = buffer.getvalue() + buffer.close() + return wav_header_bytes + + +class FishSpeechModel: + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: "AudioModelFamilyV1", + device: Optional[str] = None, + **kwargs, + ): + self._model_uid = model_uid + self._model_path = model_path + self._model_spec = model_spec + self._device = device + self._llama_queue = None + self._model = None + self._kwargs = kwargs + + def load(self): + # There are too many imports from fish_speech. + sys.path.insert( + 0, os.path.join(os.path.dirname(__file__), "../../thirdparty/fish_speech") + ) + + from tools.llama.generate import launch_thread_safe_queue + from tools.vqgan.inference import load_model as load_decoder_model + + if self._device is None: + self._device = get_available_device() + else: + if not is_device_available(self._device): + raise ValueError(f"Device {self._device} is not available!") + + logger.info("Loading Llama model...") + self._llama_queue = launch_thread_safe_queue( + checkpoint_path=self._model_path, + device=self._device, + precision=torch.bfloat16, + compile=False, + ) + logger.info("Llama model loaded, loading VQ-GAN model...") + + checkpoint_path = os.path.join( + self._model_path, + "firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + ) + self._model = load_decoder_model( + config_name="firefly_gan_vq", + checkpoint_path=checkpoint_path, + device=self._device, + ) + + @torch.inference_mode() + def _inference( + self, + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + streaming=False, + ): + from fish_speech.utils import autocast_exclude_mps + from tools.api import decode_vq_tokens, encode_reference + from tools.llama.generate import ( + GenerateRequest, + GenerateResponse, + WrappedGenerateResponse, + ) + + # Parse reference audio aka prompt + prompt_tokens = encode_reference( + decoder_model=self._model, + reference_audio=reference_audio, + enable_reference_audio=enable_reference_audio, + ) + + # LLAMA Inference + request = dict( + device=self._model.device, + max_new_tokens=max_new_tokens, + text=text, + top_p=top_p, + repetition_penalty=repetition_penalty, + temperature=temperature, + compile=False, + iterative_prompt=chunk_length > 0, + chunk_length=chunk_length, + max_length=2048, + prompt_tokens=prompt_tokens if enable_reference_audio else None, + prompt_text=reference_text if enable_reference_audio else None, + ) + + response_queue = queue.Queue() + self._llama_queue.put( + GenerateRequest( + request=request, + response_queue=response_queue, + ) + ) + + if streaming: + yield wav_chunk_header(), None, None + + segments = [] + + while True: + result: WrappedGenerateResponse = response_queue.get() + if result.status == "error": + raise Exception(str(result.response)) + + result: GenerateResponse = result.response + if result.action == "next": + break + + with autocast_exclude_mps( + device_type=self._model.device.type, dtype=torch.bfloat16 + ): + fake_audios = decode_vq_tokens( + decoder_model=self._model, + codes=result.codes, + ) + + fake_audios = fake_audios.float().cpu().numpy() + segments.append(fake_audios) + + if streaming: + yield (fake_audios * 32768).astype(np.int16).tobytes(), None, None + + if len(segments) == 0: + raise Exception("No audio generated, please check the input text.") + + # No matter streaming or not, we need to return the final audio + audio = np.concatenate(segments, axis=0) + yield None, (self._model.spec_transform.sample_rate, audio), None + + if torch.cuda.is_available(): + torch.cuda.empty_cache() + gc.collect() + + def speech( + self, + input: str, + voice: str, + response_format: str = "mp3", + speed: float = 1.0, + stream: bool = False, + **kwargs, + ): + logger.warning("Fish speech does not support setting voice: %s.", voice) + if speed != 1.0: + logger.warning("Fish speech does not support setting speed: %s.", speed) + if stream is True: + logger.warning("stream mode is not implemented.") + import torchaudio + + result = list( + self._inference( + text=input, + enable_reference_audio=False, + reference_audio=None, + reference_text="", + max_new_tokens=0, + chunk_length=100, + top_p=0.7, + repetition_penalty=1.2, + temperature=0.7, + ) + ) + sample_rate, audio = result[0][1] + audio = np.array([audio]) + + # Save the generated audio + with BytesIO() as out: + torchaudio.save( + out, torch.from_numpy(audio), sample_rate, format=response_format + ) + return out.getvalue() diff --git a/xinference/model/audio/funasr.py b/xinference/model/audio/funasr.py new file mode 100644 index 0000000000..98eb4ae878 --- /dev/null +++ b/xinference/model/audio/funasr.py @@ -0,0 +1,114 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import tempfile +from typing import TYPE_CHECKING, List, Optional + +from ...device_utils import get_available_device, is_device_available + +if TYPE_CHECKING: + from .core import AudioModelFamilyV1 + +logger = logging.getLogger(__name__) + + +class FunASRModel: + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: "AudioModelFamilyV1", + device: Optional[str] = None, + **kwargs, + ): + self._model_uid = model_uid + self._model_path = model_path + self._model_spec = model_spec + self._device = device + self._model = None + self._kwargs = kwargs + + def load(self): + try: + from funasr import AutoModel + except ImportError: + error_message = "Failed to import module 'funasr'" + installation_guide = [ + "Please make sure 'funasr' is installed. ", + "You can install it by `pip install funasr`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + if self._device is None: + self._device = get_available_device() + else: + if not is_device_available(self._device): + raise ValueError(f"Device {self._device} is not available!") + + kwargs = self._model_spec.default_model_config.copy() + kwargs.update(self._kwargs) + logger.debug("Loading FunASR model with kwargs: %s", kwargs) + self._model = AutoModel(model=self._model_path, device=self._device, **kwargs) + + def transcriptions( + self, + audio: bytes, + language: Optional[str] = None, + prompt: Optional[str] = None, + response_format: str = "json", + temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, + **kwargs, + ): + from funasr.utils.postprocess_utils import rich_transcription_postprocess + + if temperature != 0: + raise RuntimeError("`temperature`is not supported for FunASR") + if timestamp_granularities is not None: + raise RuntimeError("`timestamp_granularities`is not supported for FunASR") + if prompt is not None: + logger.warning( + "Prompt for funasr transcriptions will be ignored: %s", prompt + ) + + language = "auto" if language is None else language + + with tempfile.NamedTemporaryFile(buffering=0) as f: + f.write(audio) + + kw = self._model_spec.default_transcription_config.copy() # type: ignore + kw.update(kwargs) + logger.debug("Calling FunASR model with kwargs: %s", kw) + result = self._model.generate( # type: ignore + input=f.name, cache={}, language=language, **kw + ) + text = rich_transcription_postprocess(result[0]["text"]) + + if response_format == "json": + return {"text": text} + else: + raise ValueError(f"Unsupported response format: {response_format}") + + def translations( + self, + audio: bytes, + language: Optional[str] = None, + prompt: Optional[str] = None, + response_format: str = "json", + temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, + ): + raise RuntimeError("FunASR does not support translations API") diff --git a/xinference/model/audio/model_spec.json b/xinference/model/audio/model_spec.json index 6fcde3c6af..4cbe77a37a 100644 --- a/xinference/model/audio/model_spec.json +++ b/xinference/model/audio/model_spec.json @@ -4,6 +4,7 @@ "model_family": "whisper", "model_id": "openai/whisper-tiny", "model_revision": "167c219b21f11ef214220b8fdb7536b8a88c2475", + "ability": "audio-to-text", "multilingual": true }, { @@ -11,6 +12,7 @@ "model_family": "whisper", "model_id": "openai/whisper-tiny.en", "model_revision": "87c7102498dcde7456f24cfd30239ca606ed9063", + "ability": "audio-to-text", "multilingual": false }, { @@ -18,6 +20,7 @@ "model_family": "whisper", "model_id": "openai/whisper-base", "model_revision": "8c1db9b51951100007a96a525d83a8ec81b3c237", + "ability": "audio-to-text", "multilingual": true }, { @@ -25,6 +28,7 @@ "model_family": "whisper", "model_id": "openai/whisper-base.en", "model_revision": "911407f4214e0e1d82085af863093ec0b66f9cd6", + "ability": "audio-to-text", "multilingual": false }, { @@ -32,6 +36,7 @@ "model_family": "whisper", "model_id": "openai/whisper-small", "model_revision": "998cb1a777c20db53d6033a61b977ed4c3792cac", + "ability": "audio-to-text", "multilingual": true }, { @@ -39,6 +44,7 @@ "model_family": "whisper", "model_id": "openai/whisper-small.en", "model_revision": "e8727524f962ee844a7319d92be39ac1bd25655a", + "ability": "audio-to-text", "multilingual": false }, { @@ -46,6 +52,7 @@ "model_family": "whisper", "model_id": "openai/whisper-medium", "model_revision": "16688beb1294bedd0a6f5cd86fe7eec57bce41ed", + "ability": "audio-to-text", "multilingual": true }, { @@ -53,6 +60,7 @@ "model_family": "whisper", "model_id": "openai/whisper-medium.en", "model_revision": "2e98eb6279edf5095af0c8dedb36bdec0acd172b", + "ability": "audio-to-text", "multilingual": false }, { @@ -60,6 +68,7 @@ "model_family": "whisper", "model_id": "openai/whisper-large-v3", "model_revision": "6cdf07a7e3ec3806e5d55f787915b85d4cd020b1", + "ability": "audio-to-text", "multilingual": true }, { @@ -67,6 +76,7 @@ "model_family": "whisper", "model_id": "BELLE-2/Belle-distilwhisper-large-v2-zh", "model_revision": "ed25d13498fa5bac758b2fc479435b698532dfe8", + "ability": "audio-to-text", "multilingual": false }, { @@ -74,6 +84,75 @@ "model_family": "whisper", "model_id": "BELLE-2/Belle-whisper-large-v2-zh", "model_revision": "ec5bd5d78598545b7585814edde86dac2002b5b9", + "ability": "audio-to-text", "multilingual": false + }, + { + "model_name": "Belle-whisper-large-v3-zh", + "model_family": "whisper", + "model_id": "BELLE-2/Belle-whisper-large-v3-zh", + "model_revision": "3bebc7247696b39f5ab9ed22db426943ac33f600", + "ability": "audio-to-text", + "multilingual": false + }, + { + "model_name": "SenseVoiceSmall", + "model_family": "funasr", + "model_id": "FunAudioLLM/SenseVoiceSmall", + "model_revision": "3eb3b4eeffc2f2dde6051b853983753db33e35c3", + "ability": "audio-to-text", + "multilingual": true, + "default_model_config": { + "vad_model": "fsmn-vad", + "vad_kwargs": { + "max_single_segment_time": 30000 + } + }, + "default_transcription_config": { + "use_itn": true, + "batch_size_s": 60, + "merge_vad": true, + "merge_length_s": 15 + } + }, + { + "model_name": "ChatTTS", + "model_family": "ChatTTS", + "model_id": "2Noise/ChatTTS", + "model_revision": "ce5913842aebd78e4a01a02d47244b8d62ac4ee3", + "ability": "text-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M", + "model_family": "CosyVoice", + "model_id": "model-scope/CosyVoice-300M", + "model_revision": "ca4e036d2db2aa4731cc1747859a68044b6a4694", + "ability": "audio-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M-SFT", + "model_family": "CosyVoice", + "model_id": "model-scope/CosyVoice-300M-SFT", + "model_revision": "ab918940c6c134b1fc1f069246e67bad6b66abcb", + "ability": "text-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M-Instruct", + "model_family": "CosyVoice", + "model_id": "model-scope/CosyVoice-300M-Instruct", + "model_revision": "fb5f676733139f35670bed9b59a77d476b1aa898", + "ability": "text-to-audio", + "multilingual": true + }, + { + "model_name": "FishSpeech-1.2-SFT", + "model_family": "FishAudio", + "model_id": "fishaudio/fish-speech-1.2-sft", + "model_revision": "180288e21ec5c50cfc564023a22f789e4b88a0e0", + "ability": "text-to-audio", + "multilingual": true } -] \ No newline at end of file +] diff --git a/xinference/model/audio/model_spec_modelscope.json b/xinference/model/audio/model_spec_modelscope.json new file mode 100644 index 0000000000..54ab82e823 --- /dev/null +++ b/xinference/model/audio/model_spec_modelscope.json @@ -0,0 +1,68 @@ +[ + { + "model_name": "whisper-large-v3", + "model_family": "whisper", + "model_hub": "modelscope", + "model_id": "AI-ModelScope/whisper-large-v3", + "model_revision": "master", + "ability": "audio-to-text", + "multilingual": true + }, + { + "model_name": "SenseVoiceSmall", + "model_family": "funasr", + "model_hub": "modelscope", + "model_id": "iic/SenseVoiceSmall", + "model_revision": "master", + "ability": "audio-to-text", + "multilingual": true, + "default_model_config": { + "vad_model": "fsmn-vad", + "vad_kwargs": { + "max_single_segment_time": 30000 + } + }, + "default_transcription_config": { + "use_itn": true, + "batch_size_s": 60, + "merge_vad": true, + "merge_length_s": 15 + } + }, + { + "model_name": "ChatTTS", + "model_family": "ChatTTS", + "model_hub": "modelscope", + "model_id": "pzc163/chatTTS", + "model_revision": "master", + "ability": "text-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M", + "model_family": "CosyVoice", + "model_hub": "modelscope", + "model_id": "iic/CosyVoice-300M", + "model_revision": "master", + "ability": "audio-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M-SFT", + "model_family": "CosyVoice", + "model_hub": "modelscope", + "model_id": "iic/CosyVoice-300M-SFT", + "model_revision": "master", + "ability": "text-to-audio", + "multilingual": true + }, + { + "model_name": "CosyVoice-300M-Instruct", + "model_family": "CosyVoice", + "model_hub": "modelscope", + "model_id": "iic/CosyVoice-300M-Instruct", + "model_revision": "master", + "ability": "text-to-audio", + "multilingual": true + } +] diff --git a/xinference/model/audio/tests/cross_lingual_prompt.wav b/xinference/model/audio/tests/cross_lingual_prompt.wav new file mode 100644 index 0000000000..35d6d4eed0 Binary files /dev/null and b/xinference/model/audio/tests/cross_lingual_prompt.wav differ diff --git a/xinference/model/audio/tests/test_chattts.py b/xinference/model/audio/tests/test_chattts.py new file mode 100644 index 0000000000..92cb9ac96d --- /dev/null +++ b/xinference/model/audio/tests/test_chattts.py @@ -0,0 +1,66 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import inspect +import os +import tempfile + +import pandas as pd + + +def test_chattts(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="ChatTTS", + model_type="audio", + ) + model = client.get_model(model_uid) + input_string = ( + "chat T T S is a text to speech model designed for dialogue applications." + ) + response = model.speech(input_string) + assert type(response) is bytes + assert len(response) > 0 + + df = pd.read_csv( + "https://raw.githubusercontent.com/6drf21e/ChatTTS_Speaker/main/evaluation_results.csv" + ) + speaker = df["emb_data"][0] + + response = model.speech(input_string, voice=speaker) + assert type(response) is bytes + assert len(response) > 0 + + response = model.speech(input_string, stream=True) + assert inspect.isgenerator(response) + i = 0 + for chunk in response: + i += 1 + assert type(chunk) is bytes + assert len(chunk) > 0 + assert i > 5 + + # Test openai API + import openai + + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + with client.audio.speech.with_streaming_response.create( + model=model_uid, input=input_string, voice="echo" + ) as response: + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + response.stream_to_file(f.name) + assert os.stat(f.name).st_size > 0 diff --git a/xinference/model/audio/tests/test_cosyvoice.py b/xinference/model/audio/tests/test_cosyvoice.py new file mode 100644 index 0000000000..554980af49 --- /dev/null +++ b/xinference/model/audio/tests/test_cosyvoice.py @@ -0,0 +1,130 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os.path +import tempfile + + +def test_cosyvoice_sft(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="CosyVoice-300M-SFT", + model_type="audio", + ) + model = client.get_model(model_uid) + input_string = "你好,我是通义生成式语音大模型,请问有什么可以帮您的吗?" + + # inference_sft + response = model.speech(input_string) + assert type(response) is bytes + assert len(response) > 0 + + # Test openai API + import openai + + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + # ['中文女', '中文男', '日语男', '粤语女', '英文女', '英文男', '韩语女'] + response = client.audio.speech.create( + model=model_uid, input=input_string, voice="英文女" + ) + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + response.stream_to_file(f.name) + assert os.stat(f.name).st_size > 0 + + +def test_cosyvoice(setup): + endpoint, _ = setup + from ....client import Client + + zero_shot_prompt_file = os.path.join( + os.path.dirname(__file__), "zero_shot_prompt.wav" + ) + cross_lingual_prompt_file = os.path.join( + os.path.dirname(__file__), "cross_lingual_prompt.wav" + ) + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="CosyVoice-300M", + model_type="audio", + ) + model = client.get_model(model_uid) + with open(zero_shot_prompt_file, "rb") as f: + zero_shot_prompt = f.read() + with open(cross_lingual_prompt_file, "rb") as f: + cross_lingual_prompt = f.read() + input_string = ( + "<|en|>And then later on, fully acquiring that company. So keeping management in line, interest in " + "line with the asset that's coming into the family is a reason why sometimes we don't buy the whole thing.", + ) + + # inference_cross_lingual + response = model.speech(input_string, prompt_speech=cross_lingual_prompt) + assert type(response) is bytes, response + assert len(response) > 0 + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + f.write(response) + assert os.stat(f.name).st_size > 0 + + # inference_zero_shot + response = model.speech( + "收到好友从远方寄来的生日礼物,那份意外的惊喜与深深的祝福让我心中充满了甜蜜的快乐,笑容如花儿般绽放。", + prompt_text="希望你以后能够做的比我还好呦。", + prompt_speech=zero_shot_prompt, + ) + assert type(response) is bytes, response + assert len(response) > 0 + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + f.write(response) + assert os.stat(f.name).st_size > 0 + + +def test_cosyvoice_instruct(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="CosyVoice-300M-Instruct", + model_type="audio", + ) + model = client.get_model(model_uid) + + # inference without instruction + response = model.speech( + "在面对挑战时,他展现了非凡的勇气智慧。", voice="中文男" + ) + assert type(response) is bytes + assert len(response) > 0 + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + f.write(response) + assert os.stat(f.name).st_size > 0 + + # inference_instruct + response = model.speech( + "在面对挑战时,他展现了非凡的勇气智慧。", + voice="中文男", + instruct_text="Theo 'Crimson', is a fiery, passionate rebel leader. " + "Fights with fervor for justice, but struggles with impulsiveness.", + ) + assert type(response) is bytes + assert len(response) > 0 + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + f.write(response) + assert os.stat(f.name).st_size > 0 diff --git a/xinference/model/audio/tests/test_fish_speech.py b/xinference/model/audio/tests/test_fish_speech.py new file mode 100644 index 0000000000..8b339290ad --- /dev/null +++ b/xinference/model/audio/tests/test_fish_speech.py @@ -0,0 +1,43 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import tempfile + + +def test_fish_speech(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="FishSpeech-1.2-SFT", + model_type="audio", + ) + model = client.get_model(model_uid) + input_string = "你好,你是谁?" + response = model.speech(input_string) + assert type(response) is bytes + assert len(response) > 0 + + # Test openai API + import openai + + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + with client.audio.speech.with_streaming_response.create( + model=model_uid, input=input_string, voice="echo" + ) as response: + with tempfile.NamedTemporaryFile(suffix=".mp3", delete=True) as f: + response.stream_to_file(f.name) + assert os.stat(f.name).st_size > 0 diff --git a/xinference/model/audio/tests/test_funasr.py b/xinference/model/audio/tests/test_funasr.py new file mode 100644 index 0000000000..4a13860568 --- /dev/null +++ b/xinference/model/audio/tests/test_funasr.py @@ -0,0 +1,52 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os.path + +import requests + + +def test_restful_api_for_funasr(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_uid="SenseVoiceSmall", + model_name="SenseVoiceSmall", + model_type="audio", + ) + model = client.get_model(model_uid) + response = requests.get("https://github.com/openai/whisper/raw/main/tests/jfk.flac") + audio = response.content + + response = model.transcriptions(audio) + transcription = response["text"].lower() + assert "my fellow americans" in transcription + assert "your country" in transcription + assert "do for you" in transcription + + # Test openai API + import openai + + zh_cn_audio_path = os.path.join( + os.path.dirname(__file__), "common_voice_zh-CN_38026095.mp3" + ) + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + with open(zh_cn_audio_path, "rb") as f: + completion = client.audio.transcriptions.create(model=model_uid, file=f) + assert "列表" in completion.text + assert "香港" in completion.text + assert "航空" in completion.text diff --git a/xinference/model/audio/tests/test_whisper.py b/xinference/model/audio/tests/test_whisper.py index a200f63f7e..e376087c1a 100644 --- a/xinference/model/audio/tests/test_whisper.py +++ b/xinference/model/audio/tests/test_whisper.py @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. import os.path +import tempfile import pytest import requests +@pytest.mark.skip(reason="Too large model to be tested") def test_restful_api_for_whisper(setup): endpoint, _ = setup from ....client import Client @@ -76,3 +78,134 @@ def test_restful_api_for_whisper(setup): assert "list" in translation assert "airlines" in translation assert "hong kong" in translation + + +@pytest.mark.skip(reason="Too large model to be tested") +def test_transcriptions_for_whisper(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_uid="whisper-1", + model_name="whisper-large-v3", + model_type="audio", + ) + model = client.get_model(model_uid) + response = requests.get("https://github.com/openai/whisper/raw/main/tests/jfk.flac") + audio = response.content + + response = model.transcriptions(audio, response_format="verbose_json") + assert response["text"] + assert len(response["segments"]) == 3 + + seek_set = set() + for s in response["segments"]: + if s["seek"] in seek_set: + assert False, "incorrect seek" + seek_set.add(s["seek"]) + + response = model.transcriptions( + audio, response_format="verbose_json", timestamp_granularities=["word"] + ) + assert response["text"] + assert len(response["words"]) == 22 + + zh_cn_audio_path = os.path.join( + os.path.dirname(__file__), "common_voice_zh-CN_38026095.mp3" + ) + + # Test openai API + import openai + + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + with open(zh_cn_audio_path, "rb") as f: + completion = client.audio.transcriptions.create( + model=model_uid, + file=f, + response_format="verbose_json", + timestamp_granularities=["segment"], + ) + assert len(completion.segments) == 1 + + completion = client.audio.transcriptions.create( + model=model_uid, + file=f, + response_format="verbose_json", + timestamp_granularities=["word"], + ) + assert len(completion.words) == 11 + + +def test_register_custom_audio(): + from ..custom import ( + CustomAudioModelFamilyV1, + get_user_defined_audios, + register_audio, + unregister_audio, + ) + + # correct + family_a = CustomAudioModelFamilyV1( + model_family="my-whisper", + model_name="custom_test_a", + model_id="test/custom_test_a", + multilingual=True, + ability="audio-to-text", + ) + + register_audio(family_a, False) + assert family_a in get_user_defined_audios() + + # name conflict + family_b = CustomAudioModelFamilyV1( + model_family="my-whisper", + model_name="custom_test_b", + model_id="test/custom_test_b", + multilingual=True, + ability="audio-to-text", + ) + register_audio(family_b, False) + assert family_b in get_user_defined_audios() + with pytest.raises(ValueError): + register_audio(family_b, False) + + # unregister + unregister_audio(family_a.model_name) + assert family_a not in get_user_defined_audios() + unregister_audio(family_b.model_name) + assert family_b not in get_user_defined_audios() + + +def test_persistent_custom_audio(): + from ....constants import XINFERENCE_MODEL_DIR + from ..custom import ( + CustomAudioModelFamilyV1, + get_user_defined_audios, + register_audio, + unregister_audio, + ) + + temp_dir = tempfile.mkdtemp() + + # correct + family = CustomAudioModelFamilyV1( + model_family="my-whisper", + model_name="custom_test_a", + model_id="test/custom_test_a", + multilingual=True, + model_uri=os.path.abspath(temp_dir), + ability="audio-to-text", + ) + + register_audio(family, True) + assert family in get_user_defined_audios() + assert f"{family.model_name}.json" in os.listdir( + os.path.join(XINFERENCE_MODEL_DIR, "audio") + ) + + unregister_audio(family.model_name) + assert f"{family.model_name}.json" not in os.listdir( + os.path.join(XINFERENCE_MODEL_DIR, "audio") + ) diff --git a/xinference/model/audio/tests/zero_shot_prompt.wav b/xinference/model/audio/tests/zero_shot_prompt.wav new file mode 100644 index 0000000000..25fbf592f2 Binary files /dev/null and b/xinference/model/audio/tests/zero_shot_prompt.wav differ diff --git a/xinference/model/audio/whisper.py b/xinference/model/audio/whisper.py index 728d03bad3..80335a9f47 100644 --- a/xinference/model/audio/whisper.py +++ b/xinference/model/audio/whisper.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. import logging -from typing import TYPE_CHECKING, Dict, Optional +from typing import TYPE_CHECKING, Dict, List, Optional, Union -from xinference.device_utils import ( +from ...device_utils import ( get_available_device, get_device_preferred_dtype, is_device_available, @@ -81,12 +81,87 @@ def _call_model( audio: bytes, generate_kwargs: Dict, response_format: str, + temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, ): + if temperature != 0: + generate_kwargs.update({"temperature": temperature, "do_sample": True}) + if response_format == "json": logger.debug("Call whisper model with generate_kwargs: %s", generate_kwargs) assert callable(self._model) result = self._model(audio, generate_kwargs=generate_kwargs) return {"text": result["text"]} + elif response_format == "verbose_json": + return_timestamps: Union[bool, str] = False + if not timestamp_granularities: + return_timestamps = True + elif timestamp_granularities == ["segment"]: + return_timestamps = True + elif timestamp_granularities == ["word"]: + return_timestamps = "word" + else: + raise Exception( + f"Unsupported timestamp_granularities: {timestamp_granularities}" + ) + assert callable(self._model) + results = self._model( + audio, + generate_kwargs=generate_kwargs, + return_timestamps=return_timestamps, + ) + + language = generate_kwargs.get("language", "english") + + if return_timestamps is True: + segments: List[dict] = [] + + def _get_chunk_segment_json(idx, text, start, end): + find_start = 0 + if segments: + find_start = segments[-1]["seek"] + len(segments[-1]["text"]) + return { + "id": idx, + "seek": results["text"].find(text, find_start), + "start": start, + "end": end, + "text": text, + "tokens": [], + "temperature": temperature, + # We can't provide these values. + "avg_logprob": 0.0, + "compression_ratio": 0.0, + "no_speech_prob": 0.0, + } + + for idx, c in enumerate(results.get("chunks", [])): + text = c["text"] + start, end = c["timestamp"] + segments.append(_get_chunk_segment_json(idx, text, start, end)) + + return { + "task": "transcribe", + "language": language, + "duration": segments[-1]["end"] if segments else 0, + "text": results["text"], + "segments": segments, + } + else: + assert return_timestamps == "word" + + words = [] + for idx, c in enumerate(results.get("chunks", [])): + text = c["text"] + start, end = c["timestamp"] + words.append({"word": text, "start": start, "end": end}) + + return { + "task": "transcribe", + "language": language, + "duration": words[-1]["end"] if words else 0, + "text": results["text"], + "words": words, + } else: raise ValueError(f"Unsupported response format: {response_format}") @@ -97,12 +172,8 @@ def transcriptions( prompt: Optional[str] = None, response_format: str = "json", temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, ): - if temperature != 0: - logger.warning( - "Temperature for whisper transcriptions will be ignored: %s.", - temperature, - ) if prompt is not None: logger.warning( "Prompt for whisper transcriptions will be ignored: %s", prompt @@ -115,30 +186,35 @@ def transcriptions( else {"task": "transcribe"} ), response_format=response_format, + temperature=temperature, + timestamp_granularities=timestamp_granularities, ) def translations( self, audio: bytes, + language: Optional[str] = None, prompt: Optional[str] = None, response_format: str = "json", temperature: float = 0, + timestamp_granularities: Optional[List[str]] = None, ): if not self._model_spec.multilingual: raise RuntimeError( f"Model {self._model_spec.model_name} is not suitable for translations." ) - if temperature != 0: - logger.warning( - "Temperature for whisper transcriptions will be ignored: %s.", - temperature, - ) if prompt is not None: logger.warning( "Prompt for whisper transcriptions will be ignored: %s", prompt ) return self._call_model( audio=audio, - generate_kwargs={"task": "translate"}, + generate_kwargs=( + {"language": language, "task": "translate"} + if language is not None + else {"task": "translate"} + ), response_format=response_format, + temperature=temperature, + timestamp_granularities=timestamp_granularities, ) diff --git a/xinference/model/core.py b/xinference/model/core.py index 717124271f..4591d255b0 100644 --- a/xinference/model/core.py +++ b/xinference/model/core.py @@ -13,9 +13,10 @@ # limitations under the License. from abc import ABC, abstractmethod -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, List, Literal, Optional, Tuple, Union from .._compat import BaseModel +from ..types import PeftModelConfig class ModelDescription(ABC): @@ -49,20 +50,22 @@ def create_model_instance( model_uid: str, model_type: str, model_name: str, + model_engine: Optional[str], model_format: Optional[str] = None, - model_size_in_billions: Optional[int] = None, + model_size_in_billions: Optional[Union[int, str]] = None, quantization: Optional[str] = None, - peft_model_path: Optional[str] = None, - image_lora_load_kwargs: Optional[Dict] = None, - image_lora_fuse_kwargs: Optional[Dict] = None, - is_local_deployment: bool = False, + peft_model_config: Optional[PeftModelConfig] = None, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, **kwargs, ) -> Tuple[Any, ModelDescription]: from .audio.core import create_audio_model_instance from .embedding.core import create_embedding_model_instance + from .flexible.core import create_flexible_model_instance from .image.core import create_image_model_instance from .llm.core import create_llm_model_instance from .rerank.core import create_rerank_model_instance + from .video.core import create_video_model_instance if model_type == "LLM": return create_llm_model_instance( @@ -70,18 +73,26 @@ def create_model_instance( devices, model_uid, model_name, + model_engine, model_format, model_size_in_billions, quantization, - peft_model_path, - is_local_deployment, + peft_model_config, + download_hub, + model_path, **kwargs, ) elif model_type == "embedding": # embedding model doesn't accept trust_remote_code kwargs.pop("trust_remote_code", None) return create_embedding_model_instance( - subpool_addr, devices, model_uid, model_name, **kwargs + subpool_addr, + devices, + model_uid, + model_name, + download_hub, + model_path, + **kwargs, ) elif model_type == "image": kwargs.pop("trust_remote_code", None) @@ -90,20 +101,48 @@ def create_model_instance( devices, model_uid, model_name, - lora_model_path=peft_model_path, - lora_load_kwargs=image_lora_load_kwargs, - lora_fuse_kwargs=image_lora_fuse_kwargs, + peft_model_config, + download_hub, + model_path, **kwargs, ) elif model_type == "rerank": kwargs.pop("trust_remote_code", None) return create_rerank_model_instance( - subpool_addr, devices, model_uid, model_name, **kwargs + subpool_addr, + devices, + model_uid, + model_name, + download_hub, + model_path, + **kwargs, ) elif model_type == "audio": kwargs.pop("trust_remote_code", None) return create_audio_model_instance( - subpool_addr, devices, model_uid, model_name, **kwargs + subpool_addr, + devices, + model_uid, + model_name, + download_hub, + model_path, + **kwargs, + ) + elif model_type == "video": + kwargs.pop("trust_remote_code", None) + return create_video_model_instance( + subpool_addr, + devices, + model_uid, + model_name, + download_hub, + model_path, + **kwargs, + ) + elif model_type == "flexible": + kwargs.pop("trust_remote_code", None) + return create_flexible_model_instance( + subpool_addr, devices, model_uid, model_name, model_path, **kwargs ) else: raise ValueError(f"Unsupported model type: {model_type}.") diff --git a/xinference/model/embedding/core.py b/xinference/model/embedding/core.py index 35af7d2cd6..7ad985ff09 100644 --- a/xinference/model/embedding/core.py +++ b/xinference/model/embedding/core.py @@ -12,12 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +import gc import logging +import os from collections import defaultdict -from typing import Dict, List, Optional, Tuple, Union, no_type_check +from typing import Dict, List, Literal, Optional, Tuple, Union, no_type_check import numpy as np +from ...device_utils import empty_cache from ...types import Embedding, EmbeddingData, EmbeddingUsage from ..core import CacheableModelSpec, ModelDescription from ..utils import get_cache_dir, is_model_cached @@ -28,6 +31,10 @@ # Init when registering all the builtin models. MODEL_NAME_TO_REVISION: Dict[str, List[str]] = defaultdict(list) EMBEDDING_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) +EMBEDDING_EMPTY_CACHE_COUNT = int( + os.getenv("XINFERENCE_EMBEDDING_EMPTY_CACHE_COUNT", "10") +) +assert EMBEDDING_EMPTY_CACHE_COUNT > 0 def get_embedding_model_descriptions(): @@ -111,11 +118,21 @@ def get_cache_status( class EmbeddingModel: - def __init__(self, model_uid: str, model_path: str, device: Optional[str] = None): + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: EmbeddingModelSpec, + device: Optional[str] = None, + **kwargs, + ): self._model_uid = model_uid self._model_path = model_path self._device = device self._model = None + self._counter = 0 + self._model_spec = model_spec + self._kwargs = kwargs def load(self): try: @@ -126,14 +143,55 @@ def load(self): "Please make sure 'sentence-transformers' is installed. ", "You can install it by `pip install sentence-transformers`\n", ] - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + class XSentenceTransformer(SentenceTransformer): + def to(self, *args, **kwargs): + pass + from ..utils import patch_trust_remote_code patch_trust_remote_code() - self._model = SentenceTransformer(self._model_path, device=self._device) + if ( + "gte" in self._model_spec.model_name.lower() + and "qwen2" in self._model_spec.model_name.lower() + ): + import torch + + torch_dtype_str = self._kwargs.get("torch_dtype") + if torch_dtype_str is not None: + try: + torch_dtype = getattr(torch, torch_dtype_str) + if torch_dtype not in [ + torch.float16, + torch.float32, + torch.bfloat16, + ]: + logger.warning( + f"Load embedding model with unsupported torch dtype : {torch_dtype_str}. Using default torch dtype: fp32." + ) + torch_dtype = torch.float32 + except AttributeError: + logger.warning( + f"Load embedding model with unknown torch dtype '{torch_dtype_str}'. Using default torch dtype: fp32." + ) + torch_dtype = torch.float32 + else: + torch_dtype = "auto" + self._model = XSentenceTransformer( + self._model_path, + device=self._device, + model_kwargs={"device_map": "auto", "torch_dtype": torch_dtype}, + ) + else: + self._model = SentenceTransformer(self._model_path, device=self._device) def create_embedding(self, sentences: Union[str, List[str]], **kwargs): + self._counter += 1 + if self._counter % EMBEDDING_EMPTY_CACHE_COUNT == 0: + logger.debug("Empty embedding cache.") + gc.collect() + empty_cache() from sentence_transformers import SentenceTransformer kwargs.setdefault("normalize_embeddings", True) @@ -143,6 +201,8 @@ def create_embedding(self, sentences: Union[str, List[str]], **kwargs): def encode( model: SentenceTransformer, sentences: Union[str, List[str]], + prompt_name: Optional[str] = None, + prompt: Optional[str] = None, batch_size: int = 32, show_progress_bar: bool = None, output_value: str = "sentence_embedding", @@ -191,10 +251,43 @@ def encode( sentences = [sentences] input_was_string = True + if prompt is None: + if prompt_name is not None: + try: + prompt = model.prompts[prompt_name] + except KeyError: + raise ValueError( + f"Prompt name '{prompt_name}' not found in the configured prompts dictionary with keys {list(model.prompts.keys())!r}." + ) + elif model.default_prompt_name is not None: + prompt = model.prompts.get(model.default_prompt_name, None) + else: + if prompt_name is not None: + logger.warning( + "Encode with either a `prompt`, a `prompt_name`, or neither, but not both. " + "Ignoring the `prompt_name` in favor of `prompt`." + ) + + extra_features = {} + if prompt is not None: + sentences = [prompt + sentence for sentence in sentences] + + # Some models (e.g. INSTRUCTOR, GRIT) require removing the prompt before pooling + # Tracking the prompt length allow us to remove the prompt during pooling + tokenized_prompt = model.tokenize([prompt]) + if "input_ids" in tokenized_prompt: + extra_features["prompt_length"] = ( + tokenized_prompt["input_ids"].shape[-1] - 1 + ) + if device is None: device = model._target_device - model.to(device) + if ( + "gte" in self._model_spec.model_name.lower() + and "qwen2" in self._model_spec.model_name.lower() + ): + model.to(device) all_embeddings = [] all_token_nums = 0 @@ -215,6 +308,7 @@ def encode( ] features = model.tokenize(sentences_batch) features = batch_to_device(features, device) + features.update(extra_features) all_token_nums += sum([len(f) for f in features]) with torch.no_grad(): @@ -259,7 +353,10 @@ def encode( ] if convert_to_tensor: - all_embeddings = torch.stack(all_embeddings) + if len(all_embeddings): + all_embeddings = torch.stack(all_embeddings) + else: + all_embeddings = torch.Tensor() elif convert_to_numpy: all_embeddings = np.asarray([emb.numpy() for emb in all_embeddings]) @@ -268,12 +365,24 @@ def encode( return all_embeddings, all_token_nums - all_embeddings, all_token_nums = encode( - self._model, - sentences, - convert_to_numpy=False, - **kwargs, - ) + if ( + "gte" in self._model_spec.model_name.lower() + and "qwen2" in self._model_spec.model_name.lower() + ): + all_embeddings, all_token_nums = encode( + self._model, + sentences, + prompt_name="query", + convert_to_numpy=False, + **kwargs, + ) + else: + all_embeddings, all_token_nums = encode( + self._model, + sentences, + convert_to_numpy=False, + **kwargs, + ) if isinstance(sentences, str): all_embeddings = [all_embeddings] embedding_list = [] @@ -292,7 +401,10 @@ def encode( ) -def match_embedding(model_name: str) -> EmbeddingModelSpec: +def match_embedding( + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, +) -> EmbeddingModelSpec: from ..utils import download_from_modelscope from . import BUILTIN_EMBEDDING_MODELS, MODELSCOPE_EMBEDDING_MODELS from .custom import get_user_defined_embeddings @@ -302,31 +414,40 @@ def match_embedding(model_name: str) -> EmbeddingModelSpec: if model_name == model_spec.model_name: return model_spec - if download_from_modelscope(): - if model_name in MODELSCOPE_EMBEDDING_MODELS: - logger.debug(f"Embedding model {model_name} found in ModelScope.") - return MODELSCOPE_EMBEDDING_MODELS[model_name] - else: - logger.debug( - f"Embedding model {model_name} not found in ModelScope, " - f"now try to load it via builtin way." - ) - - if model_name in BUILTIN_EMBEDDING_MODELS: + if download_hub == "modelscope" and model_name in MODELSCOPE_EMBEDDING_MODELS: + logger.debug(f"Embedding model {model_name} found in ModelScope.") + return MODELSCOPE_EMBEDDING_MODELS[model_name] + elif download_hub == "huggingface" and model_name in BUILTIN_EMBEDDING_MODELS: + logger.debug(f"Embedding model {model_name} found in Huggingface.") + return BUILTIN_EMBEDDING_MODELS[model_name] + elif download_from_modelscope() and model_name in MODELSCOPE_EMBEDDING_MODELS: + logger.debug(f"Embedding model {model_name} found in ModelScope.") + return MODELSCOPE_EMBEDDING_MODELS[model_name] + elif model_name in BUILTIN_EMBEDDING_MODELS: + logger.debug(f"Embedding model {model_name} found in Huggingface.") return BUILTIN_EMBEDDING_MODELS[model_name] else: raise ValueError( f"Embedding model {model_name} not found, available" - f"model list: {BUILTIN_EMBEDDING_MODELS.keys()}" + f"Huggingface: {BUILTIN_EMBEDDING_MODELS.keys()}" + f"ModelScope: {MODELSCOPE_EMBEDDING_MODELS.keys()}" ) def create_embedding_model_instance( - subpool_addr: str, devices: List[str], model_uid: str, model_name: str, **kwargs + subpool_addr: str, + devices: List[str], + model_uid: str, + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, + **kwargs, ) -> Tuple[EmbeddingModel, EmbeddingModelDescription]: - model_spec = match_embedding(model_name) - model_path = cache(model_spec) - model = EmbeddingModel(model_uid, model_path, **kwargs) + model_spec = match_embedding(model_name, download_hub) + if model_path is None: + model_path = cache(model_spec) + + model = EmbeddingModel(model_uid, model_path, model_spec, **kwargs) model_description = EmbeddingModelDescription( subpool_addr, devices, model_spec, model_path=model_path ) diff --git a/xinference/model/embedding/custom.py b/xinference/model/embedding/custom.py index 8e311bbd7d..5cf398109b 100644 --- a/xinference/model/embedding/custom.py +++ b/xinference/model/embedding/custom.py @@ -47,6 +47,10 @@ def register_embedding(model_spec: CustomEmbeddingModelSpec, persist: bool): if not is_valid_model_name(model_spec.model_name): raise ValueError(f"Invalid model name {model_spec.model_name}.") + model_uri = model_spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}.") + with UD_EMBEDDING_LOCK: for model_name in ( list(BUILTIN_EMBEDDING_MODELS.keys()) @@ -61,11 +65,6 @@ def register_embedding(model_spec: CustomEmbeddingModelSpec, persist: bool): UD_EMBEDDINGS.append(model_spec) if persist: - # We only validate model URL when persist is True. - model_uri = model_spec.model_uri - if model_uri and not is_valid_model_uri(model_uri): - raise ValueError(f"Invalid model URI {model_uri}.") - persist_path = os.path.join( XINFERENCE_MODEL_DIR, "embedding", f"{model_spec.model_name}.json" ) diff --git a/xinference/model/embedding/model_spec.json b/xinference/model/embedding/model_spec.json index 12bd44c983..b90dcc8e58 100644 --- a/xinference/model/embedding/model_spec.json +++ b/xinference/model/embedding/model_spec.json @@ -206,5 +206,37 @@ "language": ["zh", "en"], "model_id": "maidalun1020/bce-embedding-base_v1", "model_revision": "236d9024fc1b4046f03848723f934521a66a9323" + }, + { + "model_name": "m3e-small", + "dimensions": 512, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "moka-ai/m3e-small", + "model_revision": "44c696631b2a8c200220aaaad5f987f096e986df" + }, + { + "model_name": "m3e-base", + "dimensions": 768, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "moka-ai/m3e-base", + "model_revision": "764b537a0e50e5c7d64db883f2d2e051cbe3c64c" + }, + { + "model_name": "m3e-large", + "dimensions": 1024, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "moka-ai/m3e-large", + "model_revision": "12900375086c37ba5d83d1e417b21dc7d1d1f388" + }, + { + "model_name": "gte-Qwen2", + "dimensions": 3584, + "max_tokens": 32000, + "language": ["zh", "en"], + "model_id": "Alibaba-NLP/gte-Qwen2-7B-instruct", + "model_revision": "e26182b2122f4435e8b3ebecbf363990f409b45b" } ] diff --git a/xinference/model/embedding/model_spec_modelscope.json b/xinference/model/embedding/model_spec_modelscope.json index 901bdb3c98..b90a913b2b 100644 --- a/xinference/model/embedding/model_spec_modelscope.json +++ b/xinference/model/embedding/model_spec_modelscope.json @@ -208,5 +208,37 @@ "language": ["zh", "en"], "model_id": "maidalun/bce-embedding-base_v1", "model_hub": "modelscope" + }, + { + "model_name": "m3e-small", + "dimensions": 512, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "AI-ModelScope/m3e-small", + "model_hub": "modelscope" + }, + { + "model_name": "m3e-base", + "dimensions": 768, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "AI-ModelScope/m3e-base", + "model_hub": "modelscope" + }, + { + "model_name": "m3e-large", + "dimensions": 1024, + "max_tokens": 512, + "language": ["zh", "en"], + "model_id": "AI-ModelScope/m3e-large", + "model_hub": "modelscope" + }, + { + "model_name": "gte-Qwen2", + "dimensions": 4096, + "max_tokens": 32000, + "language": ["zh", "en"], + "model_id": "iic/gte_Qwen2-7B-instruct", + "model_hub": "modelscope" } ] diff --git a/xinference/model/embedding/tests/test_embedding_models.py b/xinference/model/embedding/tests/test_embedding_models.py index 6b7dfeb7bf..bbdcabf4b5 100644 --- a/xinference/model/embedding/tests/test_embedding_models.py +++ b/xinference/model/embedding/tests/test_embedding_models.py @@ -54,7 +54,7 @@ def test_model(): model_path = None try: model_path = cache(TEST_MODEL_SPEC) - model = EmbeddingModel("mock", model_path) + model = EmbeddingModel("mock", model_path, TEST_MODEL_SPEC) # input is a string input_text = "what is the capital of China?" model.load() @@ -83,7 +83,7 @@ def test_model(): def test_model_from_modelscope(): model_path = cache(TEST_MODEL_SPEC_FROM_MODELSCOPE) - model = EmbeddingModel("mock", model_path) + model = EmbeddingModel("mock", model_path, TEST_MODEL_SPEC_FROM_MODELSCOPE) # input is a string input_text = "乱条犹未变初黄,倚得东风势便狂。解把飞花蒙日月,不知天地有清霜。" model.load() @@ -91,6 +91,7 @@ def test_model_from_modelscope(): assert len(r["data"]) == 1 for d in r["data"]: assert len(d["embedding"]) == 512 + shutil.rmtree(model_path, ignore_errors=True) def test_meta_file(): @@ -107,7 +108,7 @@ def test_meta_file(): assert valid_model_revision(meta_path, TEST_MODEL_SPEC2.model_revision) # test functionality of the new version model - model = EmbeddingModel("mock", cache_dir) + model = EmbeddingModel("mock", cache_dir, TEST_MODEL_SPEC2) input_text = "I can do this all day." model.load() r = model.create_embedding(input_text) @@ -190,7 +191,8 @@ def test_register_custom_embedding(): model_id="test/custom_test_b", model_uri="file:///c/d", ) - register_embedding(model_spec, False) + with pytest.raises(ValueError): + register_embedding(model_spec, False) # name conflict model_spec = CustomEmbeddingModelSpec( diff --git a/xinference/model/flexible/__init__.py b/xinference/model/flexible/__init__.py new file mode 100644 index 0000000000..049a2c6b25 --- /dev/null +++ b/xinference/model/flexible/__init__.py @@ -0,0 +1,40 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import codecs +import json +import os + +from ...constants import XINFERENCE_MODEL_DIR +from .core import ( + FLEXIBLE_MODEL_DESCRIPTIONS, + FlexibleModel, + FlexibleModelSpec, + generate_flexible_model_description, + get_flexible_model_descriptions, + get_flexible_models, + register_flexible_model, + unregister_flexible_model, +) + +model_dir = os.path.join(XINFERENCE_MODEL_DIR, "flexible") +if os.path.isdir(model_dir): + for f in os.listdir(model_dir): + with codecs.open(os.path.join(model_dir, f), encoding="utf-8") as fd: + model_spec = FlexibleModelSpec.parse_obj(json.load(fd)) + register_flexible_model(model_spec, persist=False) + +# register model description +for model in get_flexible_models(): + FLEXIBLE_MODEL_DESCRIPTIONS.update(generate_flexible_model_description(model)) diff --git a/xinference/model/flexible/core.py b/xinference/model/flexible/core.py new file mode 100644 index 0000000000..666a69afb8 --- /dev/null +++ b/xinference/model/flexible/core.py @@ -0,0 +1,238 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import logging +import os +from collections import defaultdict +from threading import Lock +from typing import Dict, List, Optional, Tuple + +from ...constants import XINFERENCE_CACHE_DIR, XINFERENCE_MODEL_DIR +from ..core import CacheableModelSpec, ModelDescription +from .utils import get_launcher + +logger = logging.getLogger(__name__) + +FLEXIBLE_MODEL_LOCK = Lock() + + +class FlexibleModelSpec(CacheableModelSpec): + model_id: Optional[str] # type: ignore + model_description: Optional[str] + model_uri: Optional[str] + launcher: str + launcher_args: Optional[str] + + def parser_args(self): + return json.loads(self.launcher_args) + + +class FlexibleModelDescription(ModelDescription): + def __init__( + self, + address: Optional[str], + devices: Optional[List[str]], + model_spec: FlexibleModelSpec, + model_path: Optional[str] = None, + ): + super().__init__(address, devices, model_path=model_path) + self._model_spec = model_spec + + def to_dict(self): + return { + "model_type": "flexible", + "address": self.address, + "accelerators": self.devices, + "model_name": self._model_spec.model_name, + "launcher": self._model_spec.launcher, + "launcher_args": self._model_spec.launcher_args, + } + + def get_model_version(self) -> str: + return f"{self._model_spec.model_name}" + + def to_version_info(self): + return { + "model_version": self.get_model_version(), + "cache_status": True, + "model_file_location": self._model_spec.model_uri, + "launcher": self._model_spec.launcher, + "launcher_args": self._model_spec.launcher_args, + } + + +def generate_flexible_model_description( + model_spec: FlexibleModelSpec, +) -> Dict[str, List[Dict]]: + res = defaultdict(list) + res[model_spec.model_name].append( + FlexibleModelDescription(None, None, model_spec).to_version_info() + ) + return res + + +FLEXIBLE_MODELS: List[FlexibleModelSpec] = [] +FLEXIBLE_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) + + +def get_flexible_models(): + with FLEXIBLE_MODEL_LOCK: + return FLEXIBLE_MODELS.copy() + + +def get_flexible_model_descriptions(): + import copy + + return copy.deepcopy(FLEXIBLE_MODEL_DESCRIPTIONS) + + +def register_flexible_model(model_spec: FlexibleModelSpec, persist: bool): + from ..utils import is_valid_model_name, is_valid_model_uri + + if not is_valid_model_name(model_spec.model_name): + raise ValueError(f"Invalid model name {model_spec.model_name}.") + + model_uri = model_spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}.") + + if model_spec.launcher_args: + try: + model_spec.parser_args() + except Exception: + raise ValueError(f"Invalid model launcher args {model_spec.launcher_args}.") + + with FLEXIBLE_MODEL_LOCK: + for model_name in [spec.model_name for spec in FLEXIBLE_MODELS]: + if model_spec.model_name == model_name: + raise ValueError( + f"Model name conflicts with existing model {model_spec.model_name}" + ) + FLEXIBLE_MODELS.append(model_spec) + + if persist: + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "flexible", f"{model_spec.model_name}.json" + ) + os.makedirs(os.path.dirname(persist_path), exist_ok=True) + with open(persist_path, mode="w") as fd: + fd.write(model_spec.json()) + + +def unregister_flexible_model(model_name: str, raise_error: bool = True): + with FLEXIBLE_MODEL_LOCK: + model_spec = None + for i, f in enumerate(FLEXIBLE_MODELS): + if f.model_name == model_name: + model_spec = f + break + if model_spec: + FLEXIBLE_MODELS.remove(model_spec) + + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "flexible", f"{model_spec.model_name}.json" + ) + if os.path.exists(persist_path): + os.remove(persist_path) + + cache_dir = os.path.join(XINFERENCE_CACHE_DIR, model_spec.model_name) + if os.path.exists(cache_dir): + logger.warning( + f"Remove the cache of user-defined model {model_spec.model_name}. " + f"Cache directory: {cache_dir}" + ) + if os.path.islink(cache_dir): + os.remove(cache_dir) + else: + logger.warning( + f"Cache directory is not a soft link, please remove it manually." + ) + else: + if raise_error: + raise ValueError(f"Model {model_name} not found") + else: + logger.warning(f"Model {model_name} not found") + + +class FlexibleModel: + def __init__( + self, + model_uid: str, + model_path: str, + device: Optional[str] = None, + config: Optional[Dict] = None, + ): + self._model_uid = model_uid + self._model_path = model_path + self._device = device + self._config = config + + def load(self): + """ + Load the model. + """ + + def infer(self, **kwargs): + """ + Call model to inference. + """ + raise NotImplementedError("infer method not implemented.") + + @property + def model_uid(self): + return self._model_uid + + @property + def model_path(self): + return self._model_path + + @property + def device(self): + return self._device + + @property + def config(self): + return self._config + + +def match_flexible_model(model_name): + for model_spec in get_flexible_models(): + if model_name == model_spec.model_name: + return model_spec + + +def create_flexible_model_instance( + subpool_addr: str, + devices: List[str], + model_uid: str, + model_name: str, + model_path: Optional[str] = None, + **kwargs, +) -> Tuple[FlexibleModel, FlexibleModelDescription]: + model_spec = match_flexible_model(model_name) + if not model_path: + model_path = model_spec.model_uri + launcher_name = model_spec.launcher + launcher_args = model_spec.parser_args() + kwargs.update(launcher_args) + + model = get_launcher(launcher_name)( + model_uid=model_uid, model_spec=model_spec, **kwargs + ) + + model_description = FlexibleModelDescription( + subpool_addr, devices, model_spec, model_path=model_path + ) + return model, model_description diff --git a/xinference/model/flexible/launchers/__init__.py b/xinference/model/flexible/launchers/__init__.py new file mode 100644 index 0000000000..1dc7941c39 --- /dev/null +++ b/xinference/model/flexible/launchers/__init__.py @@ -0,0 +1,16 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from .image_process_launcher import launcher as image_process +from .transformers_launcher import launcher as transformers diff --git a/xinference/model/flexible/launchers/image_process_launcher.py b/xinference/model/flexible/launchers/image_process_launcher.py new file mode 100644 index 0000000000..e1e3bece90 --- /dev/null +++ b/xinference/model/flexible/launchers/image_process_launcher.py @@ -0,0 +1,70 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +from io import BytesIO + +import PIL.Image +import PIL.ImageOps + +from ....types import Image +from ..core import FlexibleModel, FlexibleModelSpec + + +class ImageRemoveBackgroundModel(FlexibleModel): + def infer(self, **kwargs): + invert = kwargs.get("invert", False) + b64_image: str = kwargs.get("image") # type: ignore + only_mask = kwargs.pop("only_mask", True) + image_format = kwargs.pop("image_format", "PNG") + if not b64_image: + raise ValueError("No image found to remove background") + image = base64.b64decode(b64_image) + + try: + from rembg import remove + except ImportError: + error_message = "Failed to import module 'rembg'" + installation_guide = [ + "Please make sure 'rembg' is installed. ", + "You can install it by visiting the installation section of the git repo:\n", + "https://github.com/danielgatis/rembg?tab=readme-ov-file#installation", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + im = PIL.Image.open(BytesIO(image)) + om = remove(im, only_mask=only_mask, **kwargs) + if invert: + om = PIL.ImageOps.invert(om) + + buffered = BytesIO() + om.save(buffered, format=image_format) + img_str = base64.b64encode(buffered.getvalue()).decode() + return Image(url=None, b64_json=img_str) + + +def launcher(model_uid: str, model_spec: FlexibleModelSpec, **kwargs) -> FlexibleModel: + task = kwargs.get("task") + device = kwargs.get("device") + + if task == "remove_background": + return ImageRemoveBackgroundModel( + model_uid=model_uid, + model_path=model_spec.model_uri, # type: ignore + device=device, + config=kwargs, + ) + else: + raise ValueError(f"Unknown Task for image processing: {task}") diff --git a/xinference/model/flexible/launchers/transformers_launcher.py b/xinference/model/flexible/launchers/transformers_launcher.py new file mode 100644 index 0000000000..5d92fc0620 --- /dev/null +++ b/xinference/model/flexible/launchers/transformers_launcher.py @@ -0,0 +1,63 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from transformers import pipeline + +from ..core import FlexibleModel, FlexibleModelSpec + + +class MockModel(FlexibleModel): + def infer(self, **kwargs): + return kwargs + + +class AutoModel(FlexibleModel): + def load(self): + config = self.config or {} + self._pipeline = pipeline(model=self.model_path, device=self.device, **config) + + def infer(self, **kwargs): + return self._pipeline(**kwargs) + + +class TransformersTextClassificationModel(FlexibleModel): + def load(self): + config = self.config or {} + + self._pipeline = pipeline(model=self._model_path, device=self._device, **config) + + def infer(self, **kwargs): + return self._pipeline(**kwargs) + + +def launcher(model_uid: str, model_spec: FlexibleModelSpec, **kwargs) -> FlexibleModel: + task = kwargs.get("task") + device = kwargs.get("device") + + model_path = model_spec.model_uri + if model_path is None: + raise ValueError("model_path required") + + if task == "text-classification": + return TransformersTextClassificationModel( + model_uid=model_uid, model_path=model_path, device=device, config=kwargs + ) + elif task == "mock": + return MockModel( + model_uid=model_uid, model_path=model_path, device=device, config=kwargs + ) + else: + return AutoModel( + model_uid=model_uid, model_path=model_path, device=device, config=kwargs + ) diff --git a/xinference/model/flexible/tests/__init__.py b/xinference/model/flexible/tests/__init__.py new file mode 100644 index 0000000000..09138b5b2a --- /dev/null +++ b/xinference/model/flexible/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/xinference/model/flexible/tests/test_flexible_models.py b/xinference/model/flexible/tests/test_flexible_models.py new file mode 100644 index 0000000000..4018f82032 --- /dev/null +++ b/xinference/model/flexible/tests/test_flexible_models.py @@ -0,0 +1,63 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import shutil +import tempfile + + +def test_register_flexible_model(): + from ..core import ( + FlexibleModelSpec, + register_flexible_model, + unregister_flexible_model, + ) + + tmp_dir = tempfile.mkdtemp() + + model_spec = FlexibleModelSpec( + model_name="flexible_model", + model_uri=os.path.abspath(tmp_dir), + launcher="xinference.model.flexible.launchers.transformers", + ) + + register_flexible_model(model_spec, persist=False) + + unregister_flexible_model("flexible_model") + + shutil.rmtree(tmp_dir, ignore_errors=True) + + +def test_model(): + from ..core import FlexibleModelSpec + from ..utils import get_launcher + + launcher = get_launcher("xinference.model.flexible.launchers.transformers") + model = launcher( + model_uid="flexible_model", + model_spec=FlexibleModelSpec( + model_name="mock", + model_uri="mock", + launcher="xinference.model.flexible.launchers.transformers", + ), + task="mock", + ) + + model.load() + + result = model.infer(inputs="hello world") + # assert result == {"inputs": "hello world"} + assert result is not None + assert "inputs" in result + assert result["inputs"] == "hello world" diff --git a/xinference/model/flexible/utils.py b/xinference/model/flexible/utils.py new file mode 100644 index 0000000000..d58da6f907 --- /dev/null +++ b/xinference/model/flexible/utils.py @@ -0,0 +1,33 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import importlib + + +def get_launcher(launcher_name: str): + try: + i = launcher_name.rfind(".") + if i != -1: + module = importlib.import_module(launcher_name[:i]) + fn = getattr(module, launcher_name[i + 1 :]) + else: + importlib.import_module(launcher_name) + fn = locals().get(launcher_name) + + if fn is None: + raise ValueError(f"Launcher {launcher_name} not found.") + + return fn + except ImportError as e: + raise ImportError(f"Failed to import {launcher_name}: {e}") diff --git a/xinference/model/image/__init__.py b/xinference/model/image/__init__.py index 0654f93057..7bcc1094b9 100644 --- a/xinference/model/image/__init__.py +++ b/xinference/model/image/__init__.py @@ -20,12 +20,19 @@ from .core import ( BUILTIN_IMAGE_MODELS, IMAGE_MODEL_DESCRIPTIONS, + MODEL_NAME_TO_REVISION, MODELSCOPE_IMAGE_MODELS, ImageModelFamilyV1, generate_image_description, get_cache_status, get_image_model_descriptions, ) +from .custom import ( + CustomImageModelFamilyV1, + get_user_defined_images, + register_image, + unregister_image, +) _model_spec_json = os.path.join(os.path.dirname(__file__), "model_spec.json") _model_spec_modelscope_json = os.path.join( @@ -37,6 +44,9 @@ for spec in json.load(codecs.open(_model_spec_json, "r", encoding="utf-8")) ) ) +for model_name, model_spec in BUILTIN_IMAGE_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) + MODELSCOPE_IMAGE_MODELS.update( dict( (spec["model_name"], ImageModelFamilyV1(**spec)) @@ -45,6 +55,8 @@ ) ) ) +for model_name, model_spec in MODELSCOPE_IMAGE_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) # register model description for model_name, model_spec in chain( @@ -52,4 +64,21 @@ ): IMAGE_MODEL_DESCRIPTIONS.update(generate_image_description(model_spec)) +from ...constants import XINFERENCE_MODEL_DIR + +user_defined_image_dir = os.path.join(XINFERENCE_MODEL_DIR, "image") +if os.path.isdir(user_defined_image_dir): + for f in os.listdir(user_defined_image_dir): + with codecs.open( + os.path.join(user_defined_image_dir, f), encoding="utf-8" + ) as fd: + user_defined_image_family = CustomImageModelFamilyV1.parse_obj( + json.load(fd) + ) + register_image(user_defined_image_family, persist=False) + +for ud_image in get_user_defined_images(): + IMAGE_MODEL_DESCRIPTIONS.update(generate_image_description(ud_image)) + del _model_spec_json +del _model_spec_modelscope_json diff --git a/xinference/model/image/core.py b/xinference/model/image/core.py index e19a2b839c..54aa27fe0b 100644 --- a/xinference/model/image/core.py +++ b/xinference/model/image/core.py @@ -15,9 +15,10 @@ import logging import os from collections import defaultdict -from typing import Dict, List, Optional, Tuple +from typing import Dict, List, Literal, Optional, Tuple from ...constants import XINFERENCE_CACHE_DIR +from ...types import PeftModelConfig from ..core import CacheableModelSpec, ModelDescription from ..utils import valid_model_revision from .stable_diffusion.core import DiffusionModel @@ -26,6 +27,7 @@ logger = logging.getLogger(__name__) +MODEL_NAME_TO_REVISION: Dict[str, List[str]] = defaultdict(list) IMAGE_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) BUILTIN_IMAGE_MODELS: Dict[str, "ImageModelFamilyV1"] = {} MODELSCOPE_IMAGE_MODELS: Dict[str, "ImageModelFamilyV1"] = {} @@ -43,6 +45,7 @@ class ImageModelFamilyV1(CacheableModelSpec): model_id: str model_revision: str model_hub: str = "huggingface" + model_ability: Optional[List[str]] controlnet: Optional[List["ImageModelFamilyV1"]] @@ -69,6 +72,7 @@ def to_dict(self): "model_name": self._model_spec.model_name, "model_family": self._model_spec.model_family, "model_revision": self._model_spec.model_revision, + "model_ability": self._model_spec.model_ability, "controlnet": controlnet, } @@ -115,21 +119,29 @@ def generate_image_description( return res -def match_diffusion(model_name: str) -> ImageModelFamilyV1: +def match_diffusion( + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, +) -> ImageModelFamilyV1: from ..utils import download_from_modelscope from . import BUILTIN_IMAGE_MODELS, MODELSCOPE_IMAGE_MODELS + from .custom import get_user_defined_images - if download_from_modelscope(): - if model_name in MODELSCOPE_IMAGE_MODELS: - logger.debug(f"Image model {model_name} found in ModelScope.") - return MODELSCOPE_IMAGE_MODELS[model_name] - else: - logger.debug( - f"Image model {model_name} not found in ModelScope, " - f"now try to load it via builtin way." - ) + for model_spec in get_user_defined_images(): + if model_spec.model_name == model_name: + return model_spec - if model_name in BUILTIN_IMAGE_MODELS: + if download_hub == "modelscope" and model_name in MODELSCOPE_IMAGE_MODELS: + logger.debug(f"Image model {model_name} found in ModelScope.") + return MODELSCOPE_IMAGE_MODELS[model_name] + elif download_hub == "huggingface" and model_name in BUILTIN_IMAGE_MODELS: + logger.debug(f"Image model {model_name} found in Huggingface.") + return BUILTIN_IMAGE_MODELS[model_name] + elif download_from_modelscope() and model_name in MODELSCOPE_IMAGE_MODELS: + logger.debug(f"Image model {model_name} found in ModelScope.") + return MODELSCOPE_IMAGE_MODELS[model_name] + elif model_name in BUILTIN_IMAGE_MODELS: + logger.debug(f"Image model {model_name} found in Huggingface.") return BUILTIN_IMAGE_MODELS[model_name] else: raise ValueError( @@ -166,7 +178,6 @@ def get_cache_status( ] ) else: # Usually for UT - logger.warning(f"Cannot find builtin image model spec: {model_name}") return valid_model_revision(meta_path, model_spec.model_revision) @@ -175,12 +186,12 @@ def create_image_model_instance( devices: List[str], model_uid: str, model_name: str, - lora_model_path: Optional[str] = None, - lora_load_kwargs: Optional[Dict] = None, - lora_fuse_kwargs: Optional[Dict] = None, + peft_model_config: Optional[PeftModelConfig] = None, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, **kwargs, ) -> Tuple[DiffusionModel, ImageModelDescription]: - model_spec = match_diffusion(model_name) + model_spec = match_diffusion(model_name, download_hub) controlnet = kwargs.get("controlnet") # Handle controlnet if controlnet is not None: @@ -198,7 +209,8 @@ def create_image_model_instance( for name in controlnet: for cn_model_spec in model_spec.controlnet: if cn_model_spec.model_name == name: - model_path = cache(cn_model_spec) + if not model_path: + model_path = cache(cn_model_spec) controlnet_model_paths.append(model_path) break else: @@ -209,13 +221,24 @@ def create_image_model_instance( kwargs["controlnet"] = controlnet_model_paths[0] else: kwargs["controlnet"] = controlnet_model_paths - model_path = cache(model_spec) + if not model_path: + model_path = cache(model_spec) + if peft_model_config is not None: + lora_model = peft_model_config.peft_model + lora_load_kwargs = peft_model_config.image_lora_load_kwargs + lora_fuse_kwargs = peft_model_config.image_lora_fuse_kwargs + else: + lora_model = None + lora_load_kwargs = None + lora_fuse_kwargs = None + model = DiffusionModel( model_uid, model_path, - lora_model_path=lora_model_path, + lora_model_paths=lora_model, lora_load_kwargs=lora_load_kwargs, lora_fuse_kwargs=lora_fuse_kwargs, + abilities=model_spec.model_ability, **kwargs, ) model_description = ImageModelDescription( diff --git a/xinference/model/image/custom.py b/xinference/model/image/custom.py new file mode 100644 index 0000000000..785482f23b --- /dev/null +++ b/xinference/model/image/custom.py @@ -0,0 +1,108 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +from threading import Lock +from typing import List, Optional + +from ...constants import XINFERENCE_CACHE_DIR, XINFERENCE_MODEL_DIR +from .core import ImageModelFamilyV1 + +logger = logging.getLogger(__name__) + +UD_IMAGE_LOCK = Lock() + + +class CustomImageModelFamilyV1(ImageModelFamilyV1): + model_id: Optional[str] # type: ignore + model_revision: Optional[str] # type: ignore + model_uri: Optional[str] + controlnet: Optional[List["CustomImageModelFamilyV1"]] + + +UD_IMAGES: List[CustomImageModelFamilyV1] = [] + + +def get_user_defined_images() -> List[ImageModelFamilyV1]: + with UD_IMAGE_LOCK: + return UD_IMAGES.copy() + + +def register_image(model_spec: CustomImageModelFamilyV1, persist: bool): + from ..utils import is_valid_model_name, is_valid_model_uri + from . import BUILTIN_IMAGE_MODELS, MODELSCOPE_IMAGE_MODELS + + if not is_valid_model_name(model_spec.model_name): + raise ValueError(f"Invalid model name {model_spec.model_name}.") + + model_uri = model_spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}") + + with UD_IMAGE_LOCK: + for model_name in ( + list(BUILTIN_IMAGE_MODELS.keys()) + + list(MODELSCOPE_IMAGE_MODELS.keys()) + + [spec.model_name for spec in UD_IMAGES] + ): + if model_spec.model_name == model_name: + raise ValueError( + f"Model name conflicts with existing model {model_spec.model_name}" + ) + UD_IMAGES.append(model_spec) + + if persist: + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "image", f"{model_spec.model_name}.json" + ) + os.makedirs(os.path.dirname(persist_path), exist_ok=True) + with open(persist_path, "w") as f: + f.write(model_spec.json()) + + +def unregister_image(model_name: str, raise_error: bool = True): + with UD_IMAGE_LOCK: + model_spec = None + for i, f in enumerate(UD_IMAGES): + if f.model_name == model_name: + model_spec = f + break + if model_spec: + UD_IMAGES.remove(model_spec) + + persist_path = os.path.join( + XINFERENCE_MODEL_DIR, "image", f"{model_spec.model_id}.json" + ) + + if os.path.exists(persist_path): + os.remove(persist_path) + + cache_dir = os.path.join(XINFERENCE_CACHE_DIR, model_spec.model_name) + if os.path.exists(cache_dir): + logger.warning( + f"Remove the cache of user-defined model {model_spec.model_name}. " + f"Cache directory: {cache_dir}" + ) + if os.path.islink(cache_dir): + os.remove(cache_dir) + else: + logger.warning( + f"Cache directory is not a soft link, please remove it manually." + ) + else: + if raise_error: + raise ValueError(f"Model {model_name} not found.") + else: + logger.warning(f"Custom image model {model_name} not found.") diff --git a/xinference/model/image/model_spec.json b/xinference/model/image/model_spec.json index 246bad15f6..0c1d6f9068 100644 --- a/xinference/model/image/model_spec.json +++ b/xinference/model/image/model_spec.json @@ -1,21 +1,60 @@ [ + { + "model_name": "FLUX.1-schnell", + "model_family": "stable_diffusion", + "model_id": "black-forest-labs/FLUX.1-schnell", + "model_revision": "768d12a373ed5cc9ef9a9dea7504dc09fcc14842", + "model_ability": [ + "text2image" + ] + }, + { + "model_name": "FLUX.1-dev", + "model_family": "stable_diffusion", + "model_id": "black-forest-labs/FLUX.1-dev", + "model_revision": "01aa605f2c300568dd6515476f04565a954fcb59", + "model_ability": [ + "text2image" + ] + }, + { + "model_name": "sd3-medium", + "model_family": "stable_diffusion", + "model_id": "stabilityai/stable-diffusion-3-medium-diffusers", + "model_revision": "ea42f8cef0f178587cf766dc8129abd379c90671", + "model_ability": [ + "text2image", + "image2image", + "inpainting" + ] + }, { "model_name": "sd-turbo", "model_family": "stable_diffusion", "model_id": "stabilityai/sd-turbo", - "model_revision": "1681ed09e0cff58eeb41e878a49893228b78b94c" + "model_revision": "1681ed09e0cff58eeb41e878a49893228b78b94c", + "model_ability": [ + "text2image" + ] }, { "model_name": "sdxl-turbo", "model_family": "stable_diffusion", "model_id": "stabilityai/sdxl-turbo", - "model_revision": "f4b0486b498f84668e828044de1d0c8ba486e05b" + "model_revision": "f4b0486b498f84668e828044de1d0c8ba486e05b", + "model_ability": [ + "text2image" + ] }, { "model_name": "stable-diffusion-v1.5", "model_family": "stable_diffusion", "model_id": "runwayml/stable-diffusion-v1-5", "model_revision": "1d0c4ebf6ff58a5caecab40fa1406526bca4b5b9", + "model_ability": [ + "text2image", + "image2image" + ], "controlnet": [ { "model_name":"canny", @@ -66,6 +105,10 @@ "model_family": "stable_diffusion", "model_id": "stabilityai/stable-diffusion-xl-base-1.0", "model_revision": "f898a3e026e802f68796b95e9702464bac78d76f", + "model_ability": [ + "text2image", + "image2image" + ], "controlnet": [ { "model_name":"canny", @@ -86,5 +129,42 @@ "model_revision": "62134b9d8e703b5d6f74f1534457287a8bba77ef" } ] + }, + { + "model_name": "kolors", + "model_family": "stable_diffusion", + "model_id": "Kwai-Kolors/Kolors-diffusers", + "model_revision": "7e091c75199e910a26cd1b51ed52c28de5db3711", + "model_ability": [ + "text2image", + "image2image" + ] + }, + { + "model_name": "stable-diffusion-inpainting", + "model_family": "stable_diffusion", + "model_id": "runwayml/stable-diffusion-inpainting", + "model_revision": "51388a731f57604945fddd703ecb5c50e8e7b49d", + "model_ability": [ + "inpainting" + ] + }, + { + "model_name": "stable-diffusion-2-inpainting", + "model_family": "stable_diffusion", + "model_id": "stabilityai/stable-diffusion-2-inpainting", + "model_revision": "81a84f49b15956b60b4272a405ad3daef3da4590", + "model_ability": [ + "inpainting" + ] + }, + { + "model_name": "stable-diffusion-xl-inpainting", + "model_family": "stable_diffusion", + "model_id": "diffusers/stable-diffusion-xl-1.0-inpainting-0.1", + "model_revision": "115134f363124c53c7d878647567d04daf26e41e", + "model_ability": [ + "inpainting" + ] } ] diff --git a/xinference/model/image/model_spec_modelscope.json b/xinference/model/image/model_spec_modelscope.json index 794370344b..d0a596ca7d 100644 --- a/xinference/model/image/model_spec_modelscope.json +++ b/xinference/model/image/model_spec_modelscope.json @@ -1,17 +1,55 @@ [ + { + "model_name": "FLUX.1-schnell", + "model_family": "stable_diffusion", + "model_hub": "modelscope", + "model_id": "AI-ModelScope/FLUX.1-schnell", + "model_revision": "master", + "model_ability": [ + "text2image" + ] + }, + { + "model_name": "FLUX.1-dev", + "model_family": "stable_diffusion", + "model_hub": "modelscope", + "model_id": "AI-ModelScope/FLUX.1-dev", + "model_revision": "master", + "model_ability": [ + "text2image" + ] + }, + { + "model_name": "sd3-medium", + "model_family": "stable_diffusion", + "model_hub": "modelscope", + "model_id": "AI-ModelScope/stable-diffusion-3-medium-diffusers", + "model_revision": "master", + "model_ability": [ + "text2image", + "image2image", + "inpainting" + ] + }, { "model_name": "sd-turbo", "model_family": "stable_diffusion", "model_hub": "modelscope", "model_id": "AI-ModelScope/sd-turbo", - "model_revision": "master" + "model_revision": "master", + "model_ability": [ + "text2image" + ] }, { "model_name": "sdxl-turbo", "model_family": "stable_diffusion", "model_hub": "modelscope", "model_id": "AI-ModelScope/sdxl-turbo", - "model_revision": "master" + "model_revision": "master", + "model_ability": [ + "text2image" + ] }, { "model_name": "stable-diffusion-v1.5", @@ -19,6 +57,10 @@ "model_hub": "modelscope", "model_id": "AI-ModelScope/stable-diffusion-v1-5", "model_revision": "master", + "model_ability": [ + "text2image", + "image2image" + ], "controlnet": [ { "model_name":"canny", @@ -70,6 +112,10 @@ "model_hub": "modelscope", "model_id": "AI-ModelScope/stable-diffusion-xl-base-1.0", "model_revision": "master", + "model_ability": [ + "text2image", + "image2image" + ], "controlnet": [ { "model_name":"canny", diff --git a/xinference/model/image/stable_diffusion/core.py b/xinference/model/image/stable_diffusion/core.py index 11d5e50802..96db927023 100644 --- a/xinference/model/image/stable_diffusion/core.py +++ b/xinference/model/image/stable_diffusion/core.py @@ -16,6 +16,7 @@ import logging import os import re +import sys import time import uuid from concurrent.futures import ThreadPoolExecutor @@ -23,9 +24,12 @@ from io import BytesIO from typing import Dict, List, Optional, Union +import PIL.Image +from PIL import ImageOps + from ....constants import XINFERENCE_IMAGE_DIR from ....device_utils import move_model_to_available_device -from ....types import Image, ImageList +from ....types import Image, ImageList, LoRA logger = logging.getLogger(__name__) @@ -34,37 +38,52 @@ class DiffusionModel: def __init__( self, model_uid: str, - model_path: str, + model_path: Optional[str] = None, device: Optional[str] = None, - lora_model_path: Optional[str] = None, + lora_model: Optional[List[LoRA]] = None, lora_load_kwargs: Optional[Dict] = None, lora_fuse_kwargs: Optional[Dict] = None, + abilities: Optional[List[str]] = None, **kwargs, ): self._model_uid = model_uid self._model_path = model_path self._device = device + # when a model has text2image ability, + # it will be loaded as AutoPipelineForText2Image + # for image2image and inpainting, + # we convert to the corresponding model self._model = None - self._lora_model_path = lora_model_path + self._i2i_model = None # image to image model + self._inpainting_model = None # inpainting model + self._lora_model = lora_model self._lora_load_kwargs = lora_load_kwargs or {} self._lora_fuse_kwargs = lora_fuse_kwargs or {} + self._abilities = abilities or [] self._kwargs = kwargs def _apply_lora(self): - if self._lora_model_path is not None: + if self._lora_model is not None: logger.info( f"Loading the LoRA with load kwargs: {self._lora_load_kwargs}, fuse kwargs: {self._lora_fuse_kwargs}." ) assert self._model is not None - self._model.load_lora_weights( - self._lora_model_path, **self._lora_load_kwargs - ) + for lora_model in self._lora_model: + self._model.load_lora_weights( + lora_model.local_path, **self._lora_load_kwargs + ) self._model.fuse_lora(**self._lora_fuse_kwargs) logger.info(f"Successfully loaded the LoRA for model {self._model_uid}.") def load(self): - # import torch - from diffusers import AutoPipelineForText2Image + import torch + + if "text2image" in self._abilities or "image2image" in self._abilities: + from diffusers import AutoPipelineForText2Image as AutoPipelineModel + elif "inpainting" in self._abilities: + from diffusers import AutoPipelineForInpainting as AutoPipelineModel + else: + raise ValueError(f"Unknown ability: {self._abilities}") controlnet = self._kwargs.get("controlnet") if controlnet is not None: @@ -73,42 +92,90 @@ def load(self): logger.debug("Loading controlnet %s", controlnet) self._kwargs["controlnet"] = ControlNetModel.from_pretrained(controlnet) - self._model = AutoPipelineForText2Image.from_pretrained( + torch_dtype = self._kwargs.get("torch_dtype") + if sys.platform != "darwin" and torch_dtype is None: + # The following params crashes on Mac M2 + self._kwargs["torch_dtype"] = torch.float16 + self._kwargs["variant"] = "fp16" + self._kwargs["use_safetensors"] = True + if isinstance(torch_dtype, str): + self._kwargs["torch_dtype"] = getattr(torch, torch_dtype) + + quantize_text_encoder = self._kwargs.pop("quantize_text_encoder", None) + if quantize_text_encoder: + try: + from transformers import BitsAndBytesConfig, T5EncoderModel + except ImportError: + error_message = "Failed to import module 'transformers'" + installation_guide = [ + "Please make sure 'transformers' is installed. ", + "You can install it by `pip install transformers`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + try: + import bitsandbytes # noqa: F401 + except ImportError: + error_message = "Failed to import module 'bitsandbytes'" + installation_guide = [ + "Please make sure 'bitsandbytes' is installed. ", + "You can install it by `pip install bitsandbytes`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + for text_encoder_name in quantize_text_encoder.split(","): + quantization_config = BitsAndBytesConfig(load_in_8bit=True) + quantization_kwargs = {} + if torch_dtype: + quantization_kwargs["torch_dtype"] = torch_dtype + text_encoder = T5EncoderModel.from_pretrained( + self._model_path, + subfolder=text_encoder_name, + quantization_config=quantization_config, + **quantization_kwargs, + ) + self._kwargs[text_encoder_name] = text_encoder + self._kwargs["device_map"] = "balanced" + + logger.debug("Loading model %s", AutoPipelineModel) + self._model = AutoPipelineModel.from_pretrained( self._model_path, **self._kwargs, - # The following params crashes on Mac M2 - # torch_dtype=torch.float16, - # use_safetensors=True, ) - self._model = move_model_to_available_device(self._model) + if self._kwargs.get("cpu_offload", False): + logger.debug("CPU offloading model") + self._model.enable_model_cpu_offload() + elif not self._kwargs.get("device_map"): + logger.debug("Loading model to available device") + self._model = move_model_to_available_device(self._model) # Recommended if your computer has < 64 GB of RAM self._model.enable_attention_slicing() self._apply_lora() def _call_model( self, - height: int, - width: int, - num_images_per_prompt: int, response_format: str, + model=None, **kwargs, ): + import gc + + from ....device_utils import empty_cache + logger.debug( "stable diffusion args: %s", - dict( - kwargs, - height=height, - width=width, - num_images_per_prompt=num_images_per_prompt, - ), + kwargs, ) - assert callable(self._model) - images = self._model( - height=height, - width=width, - num_images_per_prompt=num_images_per_prompt, - **kwargs, - ).images + model = model if model is not None else self._model + assert callable(model) + images = model(**kwargs).images + + # clean cache + gc.collect() + empty_cache() + if response_format == "url": os.makedirs(XINFERENCE_IMAGE_DIR, exist_ok=True) image_list = [] @@ -126,12 +193,18 @@ def _gen_base64_image(_img): return base64.b64encode(buffered.getvalue()).decode() with ThreadPoolExecutor() as executor: - results = list(map(partial(executor.submit, _gen_base64_image), images)) + results = list(map(partial(executor.submit, _gen_base64_image), images)) # type: ignore image_list = [Image(url=None, b64_json=s.result()) for s in results] return ImageList(created=int(time.time()), data=image_list) else: raise ValueError(f"Unsupported response format: {response_format}") + @classmethod + def _filter_kwargs(cls, kwargs: dict): + for arg in ["negative_prompt", "num_inference_steps"]: + if not kwargs.get(arg): + kwargs.pop(arg, None) + def text_to_image( self, prompt: str, @@ -143,6 +216,7 @@ def text_to_image( # References: # https://huggingface.co/docs/diffusers/main/en/api/pipelines/controlnet_sdxl width, height = map(int, re.split(r"[^\d]+", size)) + self._filter_kwargs(kwargs) return self._call_model( prompt=prompt, height=height, @@ -152,9 +226,65 @@ def text_to_image( **kwargs, ) + @staticmethod + def pad_to_multiple(image, multiple=8): + x, y = image.size + padding_x = (multiple - x % multiple) % multiple + padding_y = (multiple - y % multiple) % multiple + padding = (0, 0, padding_x, padding_y) + return ImageOps.expand(image, padding) + def image_to_image( self, - image: bytes, + image: PIL.Image, + prompt: Optional[Union[str, List[str]]] = None, + negative_prompt: Optional[Union[str, List[str]]] = None, + n: int = 1, + size: Optional[str] = None, + response_format: str = "url", + **kwargs, + ): + if "controlnet" in self._kwargs: + model = self._model + else: + if "image2image" not in self._abilities: + raise RuntimeError(f"{self._model_uid} does not support image2image") + if self._i2i_model is not None: + model = self._i2i_model + else: + from diffusers import AutoPipelineForImage2Image + + self._i2i_model = model = AutoPipelineForImage2Image.from_pipe( + self._model + ) + + if padding_image_to_multiple := kwargs.pop("padding_image_to_multiple", None): + # Model like SD3 image to image requires image's height and width is times of 16 + # padding the image if specified + image = self.pad_to_multiple(image, multiple=int(padding_image_to_multiple)) + + if size: + width, height = map(int, re.split(r"[^\d]+", size)) + if padding_image_to_multiple: + width, height = image.size + kwargs["width"] = width + kwargs["height"] = height + + self._filter_kwargs(kwargs) + return self._call_model( + image=image, + prompt=prompt, + negative_prompt=negative_prompt, + num_images_per_prompt=n, + response_format=response_format, + model=model, + **kwargs, + ) + + def inpainting( + self, + image: PIL.Image, + mask_image: PIL.Image, prompt: Optional[Union[str, List[str]]] = None, negative_prompt: Optional[Union[str, List[str]]] = None, n: int = 1, @@ -162,14 +292,44 @@ def image_to_image( response_format: str = "url", **kwargs, ): + if "inpainting" not in self._abilities: + raise RuntimeError(f"{self._model_uid} does not support inpainting") + + if ( + "text2image" in self._abilities or "image2image" in self._abilities + ) and self._model is not None: + from diffusers import AutoPipelineForInpainting + + if self._inpainting_model is not None: + model = self._inpainting_model + else: + model = self._inpainting_model = AutoPipelineForInpainting.from_pipe( + self._model + ) + else: + model = self._model + width, height = map(int, re.split(r"[^\d]+", size)) + + if padding_image_to_multiple := kwargs.pop("padding_image_to_multiple", None): + # Model like SD3 inpainting requires image's height and width is times of 16 + # padding the image if specified + image = self.pad_to_multiple(image, multiple=int(padding_image_to_multiple)) + mask_image = self.pad_to_multiple( + mask_image, multiple=int(padding_image_to_multiple) + ) + # calculate actual image size after padding + width, height = image.size + return self._call_model( image=image, + mask_image=mask_image, prompt=prompt, negative_prompt=negative_prompt, height=height, width=width, num_images_per_prompt=n, response_format=response_format, + model=model, **kwargs, ) diff --git a/xinference/model/image/tests/test_stable_diffusion.py b/xinference/model/image/tests/test_stable_diffusion.py index 7ff9809b46..15eeacf120 100644 --- a/xinference/model/image/tests/test_stable_diffusion.py +++ b/xinference/model/image/tests/test_stable_diffusion.py @@ -16,6 +16,7 @@ import logging import os.path import shutil +import tempfile from io import BytesIO import pytest @@ -38,7 +39,7 @@ def test_model(): model_path = None try: model_path = cache(TEST_MODEL_SPEC) - model = DiffusionModel("mock", model_path) + model = DiffusionModel("mock", model_path, abilities=["text2image"]) # input is a string input_text = "an apple" model.load() @@ -187,6 +188,84 @@ def test_restful_api_for_sd_turbo(setup, model_name): assert img.size == (512, 512) +@pytest.mark.skip(reason="Stable diffusion image2image requires too many GRAM.") +def test_restful_api_for_sd_image2image(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_uid="my_image2image", + model_name="stable-diffusion-xl-base-1.0", + model_type="image", + ) + model = client.get_model(model_uid) + + from diffusers.utils import load_image + + # Replace the image path for your test. + image_path = os.path.expanduser("~/raw.jpg") + logger.info("Image path: %s", image_path) + image = load_image(image_path) + bio = io.BytesIO() + image.save(bio, format="png") + + r = model.image_to_image( + prompt="desert, clear sky, white clouds", + image=bio.getvalue(), + num_inference_steps=10, + ) + logger.info("test result %s", r) + from PIL import Image + + with open(r["data"][0]["url"], "rb") as f: + img = Image.open(f) + assert img.size == image.size + + +@pytest.mark.skip(reason="Stable diffusion inpainting requires too many GRAM.") +def test_restful_api_for_sd_inpainting(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_uid="my_inpainting", + model_name="stable-diffusion-2-inpainting", + model_type="image", + ) + model = client.get_model(model_uid) + + from diffusers.utils import load_image + + # Replace the image path for your test. + image_path = os.path.expanduser("~/raw.jpg") + logger.info("Image path: %s", image_path) + image = load_image(image_path) + bio = io.BytesIO() + image.save(bio, format="png") + mask_image_path = os.path.expanduser("~/mask.jpg") + logger.info("Mask image path: %s", mask_image_path) + mask_image = load_image(mask_image_path) + bio2 = io.BytesIO() + mask_image.save(bio2, format="png") + + r = model.inpainting( + prompt="desert, clear sky, white clouds", + image=bio.getvalue(), + mask_image=bio2.getvalue(), + num_inference_steps=10, + ) + logger.info("test result %s", r) + from PIL import Image + + with open(r["data"][0]["url"], "rb") as f: + img = Image.open(f) + assert img.size == image.size + + def test_get_cache_status(): from ..core import get_cache_status @@ -198,3 +277,195 @@ def test_get_cache_status(): finally: if model_path is not None: shutil.rmtree(model_path) + + +def test_register_custom_image(): + from ..custom import ( + CustomImageModelFamilyV1, + get_user_defined_images, + register_image, + unregister_image, + ) + + with tempfile.TemporaryDirectory() as tmp_dir: + model_spec = CustomImageModelFamilyV1( + model_family="stable_diffusion", + model_name="my-custom-image", + model_id="my-custom-image", + model_uri=os.path.abspath(tmp_dir), + ) + + register_image(model_spec, persist=False) + assert model_spec in get_user_defined_images() + + unregister_image(model_spec.model_name, raise_error=False) + assert model_spec not in get_user_defined_images() + + +def test_persist_custom_image(): + from ....constants import XINFERENCE_MODEL_DIR + from ..custom import ( + CustomImageModelFamilyV1, + get_user_defined_images, + register_image, + unregister_image, + ) + + tmp_dir = tempfile.mktemp() + os.makedirs(tmp_dir) + + model_spec = CustomImageModelFamilyV1( + model_family="stable_diffusion", + model_name="my-custom-image", + model_id="my-custom-image", + model_uri=f"file://{os.path.abspath(tmp_dir)}", + ) + + register_image(model_spec, persist=True) + assert model_spec in get_user_defined_images() + assert f"{model_spec.model_name}.json" in os.listdir( + os.path.join(XINFERENCE_MODEL_DIR, "image") + ) + + unregister_image(model_spec.model_name) + assert model_spec not in get_user_defined_images() + assert f"{model_spec.model_name}.json" not in os.listdir( + os.path.join(XINFERENCE_MODEL_DIR, "image") + ) + + +def test_launch_custom_image(setup): + endpoint, _ = setup + from ....client import Client + from ....constants import XINFERENCE_CACHE_DIR + from ....core.utils import json_dumps + + client = Client(endpoint) + + model_path = os.path.join(XINFERENCE_CACHE_DIR, "sd-turbo") + + my_model = { + "model_family": "stable_diffusion", + "model_uid": "my_sd", + "model_name": "my_sd", + "model_uri": model_path, + "model_ability": ["text2image"], + } + + client.register_model( + model_type="image", + model=json_dumps(my_model).decode("utf-8"), + persist=False, + ) + + model_uid = client.launch_model( + model_uid="my_image", + model_name="my_sd", + model_type="image", + ) + model = client.get_model(model_uid) + + r = model.text_to_image( + prompt="A cinematic shot of a baby raccoon wearing an intricate italian priest robe.", + size="512*512", + num_inference_steps=10, + ) + logger.info("test result %s", r) + + client.unregister_model(model_type="image", model_name=my_model["model_name"]) + + from PIL import Image + + with open(r["data"][0]["url"], "rb") as f: + img = Image.open(f) + assert img.size == (512, 512) + + import openai + + client = openai.Client(api_key="not empty", base_url=f"{endpoint}/v1") + completion = client.images.generate( + model=model_uid, + prompt="A cinematic shot of a baby raccoon wearing an intricate italian priest robe.", + size="512*512", + response_format="b64_json", + ) + img_bytes = base64.b64decode(completion.data[0].b64_json) + img = Image.open(BytesIO(img_bytes)) + assert img.size == (512, 512) + + +@pytest.mark.skip(reason="Stable diffusion controlnet requires too many GRAM.") +def test_launch_custom_image_with_controlnet(setup): + endpoint, _ = setup + from ....client import Client + from ....constants import XINFERENCE_CACHE_DIR + from ....core.utils import json_dumps + + client = Client(endpoint) + + model_path = os.path.join(XINFERENCE_CACHE_DIR, "stable-diffusion-v1.5") + controlnet_path = os.path.join(XINFERENCE_CACHE_DIR, "mlsd") + + my_controlnet = { + "model_family": "controlnet", + "model_uid": "my_controlnet", + "model_name": "my_controlnet", + "model_uri": controlnet_path, + } + + my_model = { + "model_family": "stable_diffusion", + "model_uid": "my_sd", + "model_name": "my_sd", + "model_uri": model_path, + "controlnet": [ + my_controlnet, + ], + } + + client.register_model( + model_type="image", + model=json_dumps(my_model), + persist=False, + ) + + model_uid = client.launch_model( + model_uid="my_image", + model_name="my_sd", + model_type="image", + controlnet="my_controlnet", + ) + model = client.get_model(model_uid) + + from controlnet_aux import MLSDdetector + from diffusers.utils import load_image + + mlsd = MLSDdetector.from_pretrained("lllyasviel/ControlNet") + + # Replace the image path for your test. + image_path = os.path.expanduser("~/draft.png") + logger.info("Image path: %s", image_path) + image = load_image(image_path) + image = mlsd(image) + prompt = ( + "a modern house, use glass window, best quality, 8K wallpaper,(realistic:1.3), " + "photorealistic, photo realistic, hyperrealistic, orante, super detailed, " + "intricate, dramatic, morning lighting, shadows, high dynamic range,wooden,blue sky" + ) + negative_prompt = ( + "low quality, bad quality, sketches, signature, soft, blurry, drawing, " + "sketch, poor quality, ugly, text, type, word, logo, pixelated, " + "low resolution, saturated, high contrast, oversharpened" + ) + bio = io.BytesIO() + image.save(bio, format="png") + r = model.image_to_image( + image=bio.getvalue(), + prompt=prompt, + negative_prompt=negative_prompt, + num_inference_steps=20, + ) + logger.info("test result %s", r) + + client.unregister_model(model_type="image", model_name=my_model["model_name"]) + client.unregister_model(model_type="image", model_name=my_controlnet["model_name"]) diff --git a/xinference/model/llm/__init__.py b/xinference/model/llm/__init__.py index 2f2ff6cca8..9909addebb 100644 --- a/xinference/model/llm/__init__.py +++ b/xinference/model/llm/__init__.py @@ -15,6 +15,7 @@ import codecs import json import os +import warnings from .core import ( LLM, @@ -24,100 +25,161 @@ get_llm_model_descriptions, ) from .llm_family import ( + BUILTIN_CSGHUB_LLM_FAMILIES, BUILTIN_LLM_FAMILIES, BUILTIN_LLM_MODEL_CHAT_FAMILIES, BUILTIN_LLM_MODEL_GENERATE_FAMILIES, BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES, BUILTIN_LLM_PROMPT_STYLE, BUILTIN_MODELSCOPE_LLM_FAMILIES, - LLM_CLASSES, - PEFT_SUPPORTED_CLASSES, + LLAMA_CLASSES, + LLM_ENGINES, + LMDEPLOY_CLASSES, + MLX_CLASSES, + SGLANG_CLASSES, + SUPPORTED_ENGINES, + TRANSFORMERS_CLASSES, + VLLM_CLASSES, CustomLLMFamilyV1, - GgmlLLMSpecV1, + LlamaCppLLMSpecV1, LLMFamilyV1, LLMSpecV1, + MLXLLMSpecV1, PromptStyleV1, PytorchLLMSpecV1, get_cache_status, get_user_defined_llm_families, match_llm, - match_llm_cls, register_llm, unregister_llm, ) +def check_format_with_engine(model_format, engine): + # only llama-cpp-python support and only support ggufv2 + if model_format in ["ggufv2"] and engine != "llama.cpp": + return False + if model_format not in ["ggufv2"] and engine == "llama.cpp": + return False + return True + + +def generate_engine_config_by_model_family(model_family): + model_name = model_family.model_name + specs = model_family.model_specs + engines = LLM_ENGINES.get(model_name, {}) # structure for engine query + for spec in specs: + model_format = spec.model_format + model_size_in_billions = spec.model_size_in_billions + quantizations = spec.quantizations + for quantization in quantizations: + # traverse all supported engines to match the name, format, size in billions and quatization of model + for engine in SUPPORTED_ENGINES: + if not check_format_with_engine( + model_format, engine + ): # match the format of model with engine + continue + CLASSES = SUPPORTED_ENGINES[engine] + for cls in CLASSES: + if cls.match(model_family, spec, quantization): + engine_params = engines.get(engine, []) + already_exists = False + # if the name, format and size in billions of model already exists in the structure, add the new quantization + for param in engine_params: + if ( + model_name == param["model_name"] + and model_format == param["model_format"] + and model_size_in_billions + == param["model_size_in_billions"] + ): + if quantization not in param["quantizations"]: + param["quantizations"].append(quantization) + already_exists = True + break + # successfully match the params for the first time, add to the structure + if not already_exists: + engine_params.append( + { + "model_name": model_name, + "model_format": model_format, + "model_size_in_billions": model_size_in_billions, + "quantizations": [quantization], + "llm_class": cls, + } + ) + engines[engine] = engine_params + break + LLM_ENGINES[model_name] = engines + + def _install(): - from .ggml.chatglm import ChatglmCppChatModel - from .ggml.ctransformers import CtransformersModel - from .ggml.llamacpp import LlamaCppChatModel, LlamaCppModel - from .pytorch.baichuan import BaichuanPytorchChatModel - from .pytorch.chatglm import ChatglmPytorchChatModel - from .pytorch.core import PytorchChatModel, PytorchModel - from .pytorch.deepseek_vl import DeepSeekVLChatModel - from .pytorch.falcon import FalconPytorchChatModel, FalconPytorchModel - from .pytorch.internlm2 import Internlm2PytorchChatModel - from .pytorch.llama_2 import LlamaPytorchChatModel, LlamaPytorchModel - from .pytorch.omnilmm import OmniLMMModel - from .pytorch.qwen_vl import QwenVLChatModel - from .pytorch.vicuna import VicunaPytorchChatModel - from .pytorch.yi_vl import YiVLChatModel + from .llama_cpp.core import LlamaCppChatModel, LlamaCppModel + from .lmdeploy.core import LMDeployChatModel, LMDeployModel + from .mlx.core import MLXChatModel, MLXModel from .sglang.core import SGLANGChatModel, SGLANGModel - from .vllm.core import VLLMChatModel, VLLMModel + from .transformers.chatglm import ChatglmPytorchChatModel + from .transformers.cogvlm2 import CogVLM2Model + from .transformers.cogvlm2_video import CogVLM2VideoModel + from .transformers.core import PytorchChatModel, PytorchModel + from .transformers.deepseek_vl import DeepSeekVLChatModel + from .transformers.glm4v import Glm4VModel + from .transformers.intern_vl import InternVLChatModel + from .transformers.internlm2 import Internlm2PytorchChatModel + from .transformers.llama_2 import LlamaPytorchChatModel, LlamaPytorchModel + from .transformers.minicpmv25 import MiniCPMV25Model + from .transformers.minicpmv26 import MiniCPMV26Model + from .transformers.qwen_vl import QwenVLChatModel + from .transformers.yi_vl import YiVLChatModel + from .vllm.core import VLLMChatModel, VLLMModel, VLLMVisionModel + + try: + from .transformers.omnilmm import OmniLMMModel + except ImportError as e: + # For quite old transformers version, + # import will generate error + OmniLMMModel = None + warnings.warn(f"Cannot import OmniLLMModel due to reason: {e}") # register llm classes. - LLM_CLASSES.extend( + LLAMA_CLASSES.extend( [ LlamaCppChatModel, LlamaCppModel, ] ) - LLM_CLASSES.extend( - [ - ChatglmCppChatModel, - ] - ) - LLM_CLASSES.extend( - [ - CtransformersModel, - ] - ) - LLM_CLASSES.extend([SGLANGModel, SGLANGChatModel]) - LLM_CLASSES.extend([VLLMModel, VLLMChatModel]) - LLM_CLASSES.extend( + SGLANG_CLASSES.extend([SGLANGModel, SGLANGChatModel]) + VLLM_CLASSES.extend([VLLMModel, VLLMChatModel, VLLMVisionModel]) + MLX_CLASSES.extend([MLXModel, MLXChatModel]) + LMDEPLOY_CLASSES.extend([LMDeployModel, LMDeployChatModel]) + TRANSFORMERS_CLASSES.extend( [ - BaichuanPytorchChatModel, - VicunaPytorchChatModel, - FalconPytorchChatModel, ChatglmPytorchChatModel, LlamaPytorchModel, LlamaPytorchChatModel, PytorchChatModel, - FalconPytorchModel, Internlm2PytorchChatModel, QwenVLChatModel, - OmniLMMModel, YiVLChatModel, DeepSeekVLChatModel, + InternVLChatModel, PytorchModel, + CogVLM2Model, + CogVLM2VideoModel, + MiniCPMV25Model, + MiniCPMV26Model, + Glm4VModel, ] ) - PEFT_SUPPORTED_CLASSES.extend( - [ - BaichuanPytorchChatModel, - VicunaPytorchChatModel, - FalconPytorchChatModel, - ChatglmPytorchChatModel, - LlamaPytorchModel, - LlamaPytorchChatModel, - PytorchChatModel, - FalconPytorchModel, - Internlm2PytorchChatModel, - QwenVLChatModel, - YiVLChatModel, - PytorchModel, - ] - ) + if OmniLMMModel: # type: ignore + TRANSFORMERS_CLASSES.append(OmniLMMModel) + + # support 4 engines for now + SUPPORTED_ENGINES["vLLM"] = VLLM_CLASSES + SUPPORTED_ENGINES["SGLang"] = SGLANG_CLASSES + SUPPORTED_ENGINES["Transformers"] = TRANSFORMERS_CLASSES + SUPPORTED_ENGINES["llama.cpp"] = LLAMA_CLASSES + SUPPORTED_ENGINES["MLX"] = MLX_CLASSES + SUPPORTED_ENGINES["LMDEPLOY"] = LMDEPLOY_CLASSES json_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "llm_family.json" @@ -138,7 +200,7 @@ def _install(): BUILTIN_LLM_MODEL_CHAT_FAMILIES.add(model_spec.model_name) else: BUILTIN_LLM_MODEL_GENERATE_FAMILIES.add(model_spec.model_name) - if "tool_call" in model_spec.model_ability: + if "tools" in model_spec.model_ability: BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES.add(model_spec.model_name) modelscope_json_path = os.path.join( @@ -161,14 +223,50 @@ def _install(): BUILTIN_LLM_MODEL_CHAT_FAMILIES.add(model_spec.model_name) else: BUILTIN_LLM_MODEL_GENERATE_FAMILIES.add(model_spec.model_name) - if "tool_call" in model_spec.model_ability: + if "tools" in model_spec.model_ability: BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES.add(model_spec.model_name) - for llm_specs in [BUILTIN_LLM_FAMILIES, BUILTIN_MODELSCOPE_LLM_FAMILIES]: + csghub_json_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "llm_family_csghub.json" + ) + for json_obj in json.load(codecs.open(csghub_json_path, "r", encoding="utf-8")): + model_spec = LLMFamilyV1.parse_obj(json_obj) + BUILTIN_CSGHUB_LLM_FAMILIES.append(model_spec) + + # register prompt style, in case that we have something missed + # if duplicated with huggingface json, keep it as the huggingface style + if ( + "chat" in model_spec.model_ability + and isinstance(model_spec.prompt_style, PromptStyleV1) + and model_spec.model_name not in BUILTIN_LLM_PROMPT_STYLE + ): + BUILTIN_LLM_PROMPT_STYLE[model_spec.model_name] = model_spec.prompt_style + # register model family + if "chat" in model_spec.model_ability: + BUILTIN_LLM_MODEL_CHAT_FAMILIES.add(model_spec.model_name) + else: + BUILTIN_LLM_MODEL_GENERATE_FAMILIES.add(model_spec.model_name) + if "tools" in model_spec.model_ability: + BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES.add(model_spec.model_name) + + for llm_specs in [ + BUILTIN_LLM_FAMILIES, + BUILTIN_MODELSCOPE_LLM_FAMILIES, + BUILTIN_CSGHUB_LLM_FAMILIES, + ]: for llm_spec in llm_specs: if llm_spec.model_name not in LLM_MODEL_DESCRIPTIONS: LLM_MODEL_DESCRIPTIONS.update(generate_llm_description(llm_spec)) + # traverse all families and add engine parameters corresponding to the model name + for families in [ + BUILTIN_LLM_FAMILIES, + BUILTIN_MODELSCOPE_LLM_FAMILIES, + BUILTIN_CSGHUB_LLM_FAMILIES, + ]: + for family in families: + generate_engine_config_by_model_family(family) + from ...constants import XINFERENCE_MODEL_DIR user_defined_llm_dir = os.path.join(XINFERENCE_MODEL_DIR, "llm") diff --git a/xinference/model/llm/core.py b/xinference/model/llm/core.py index ec31d9144b..d4f1ed32c1 100644 --- a/xinference/model/llm/core.py +++ b/xinference/model/llm/core.py @@ -13,14 +13,17 @@ # limitations under the License. import abc +import inspect import logging import os import platform from abc import abstractmethod from collections import defaultdict -from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union +from functools import lru_cache +from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Tuple, Union from ...core.utils import parse_replica_model_uid +from ...types import PeftModelConfig from ..core import ModelDescription if TYPE_CHECKING: @@ -61,16 +64,6 @@ def __init__( if kwargs: raise ValueError(f"Unrecognized keyword arguments: {kwargs}") - @staticmethod - def handle_model_size(model_size_in_billions: Union[str, int]) -> Union[int, float]: - if isinstance(model_size_in_billions, str): - if "_" in model_size_in_billions: - ms = model_size_in_billions.replace("_", ".") - return float(ms) - else: - raise ValueError("Invalid format for `model_size_in_billions`") - return model_size_in_billions - @staticmethod def _is_darwin_and_apple_silicon(): return platform.system() == "Darwin" and platform.processor() == "arm" @@ -80,12 +73,30 @@ def _is_linux(): return platform.system() == "Linux" @staticmethod + @lru_cache def _has_cuda_device(): - from ...utils import cuda_count - - return cuda_count() > 0 + """ + Use pynvml to impl this interface. + DO NOT USE torch to impl this, which will lead to some unexpected errors. + """ + from pynvml import nvmlDeviceGetCount, nvmlInit, nvmlShutdown + + device_count = 0 + try: + nvmlInit() + device_count = nvmlDeviceGetCount() + except: + pass + finally: + try: + nvmlShutdown() + except: + pass + + return device_count > 0 @staticmethod + @lru_cache def _get_cuda_count(): from ...utils import cuda_count @@ -177,125 +188,67 @@ def create_llm_model_instance( devices: List[str], model_uid: str, model_name: str, + model_engine: Optional[str], model_format: Optional[str] = None, - model_size_in_billions: Optional[int] = None, + model_size_in_billions: Optional[Union[int, str]] = None, quantization: Optional[str] = None, - peft_model_path: Optional[str] = None, - is_local_deployment: bool = False, + peft_model_config: Optional[PeftModelConfig] = None, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, **kwargs, ) -> Tuple[LLM, LLMDescription]: - from . import match_llm, match_llm_cls - from .llm_family import cache + from .llm_family import cache, check_engine_by_spec_parameters, match_llm + if model_engine is None: + raise ValueError("model_engine is required for LLM model") match_result = match_llm( - model_name, - model_format, - model_size_in_billions, - quantization, - is_local_deployment, + model_name, model_format, model_size_in_billions, quantization, download_hub ) + if not match_result: raise ValueError( f"Model not found, name: {model_name}, format: {model_format}," f" size: {model_size_in_billions}, quantization: {quantization}" ) llm_family, llm_spec, quantization = match_result - assert quantization is not None - save_path = cache(llm_family, llm_spec, quantization) - llm_cls = match_llm_cls( - llm_family, llm_spec, quantization, peft_model_path=peft_model_path + llm_cls = check_engine_by_spec_parameters( + model_engine, + llm_family.model_name, + llm_spec.model_format, + llm_spec.model_size_in_billions, + quantization, ) - if not llm_cls: - raise ValueError( - f"Model not supported, name: {model_name}, format: {model_format}," - f" size: {model_size_in_billions}, quantization: {quantization}" - ) logger.debug(f"Launching {model_uid} with {llm_cls.__name__}") - if peft_model_path is not None: - model = llm_cls( - model_uid, - llm_family, - llm_spec, - quantization, - save_path, - kwargs, - peft_model_path, - ) + if not model_path: + model_path = cache(llm_family, llm_spec, quantization) + + peft_model = peft_model_config.peft_model if peft_model_config else None + if peft_model is not None: + if "peft_model" in inspect.signature(llm_cls.__init__).parameters: + model = llm_cls( + model_uid, + llm_family, + llm_spec, + quantization, + model_path, + kwargs, + peft_model, + ) + else: + logger.warning( + f"Model not supported with lora, name: {model_name}, format: {model_format}, engine: {model_engine}. " + f"Load this without lora." + ) + model = llm_cls( + model_uid, llm_family, llm_spec, quantization, model_path, kwargs + ) else: model = llm_cls( - model_uid, llm_family, llm_spec, quantization, save_path, kwargs - ) - return model, LLMDescription( - subpool_addr, devices, llm_family, llm_spec, quantization - ) - - -def create_speculative_llm_model_instance( - subpool_addr: str, - devices: List[str], - model_uid: str, - model_name: str, - model_size_in_billions: Optional[int], - quantization: Optional[str], - draft_model_name: str, - draft_model_size_in_billions: Optional[int], - draft_quantization: Optional[str], - is_local_deployment: bool = False, -) -> Tuple[LLM, LLMDescription]: - from . import match_llm - from .llm_family import cache - - match_result = match_llm( - model_name, - "pytorch", - model_size_in_billions, - quantization, - is_local_deployment, - ) - - if not match_result: - raise ValueError( - f"Model not found, name: {model_name}, format: pytorch," - f" size: {model_size_in_billions}, quantization: {quantization}" + model_uid, llm_family, llm_spec, quantization, model_path, kwargs ) - llm_family, llm_spec, quantization = match_result - assert quantization is not None - save_path = cache(llm_family, llm_spec, quantization) - - draft_match_result = match_llm( - draft_model_name, - "pytorch", - draft_model_size_in_billions, - draft_quantization, - is_local_deployment, - ) - - if not draft_match_result: - raise ValueError( - f"Model not found, name: {draft_model_name}, format: pytorch," - f" size: {draft_model_size_in_billions}, quantization: {draft_quantization}" - ) - draft_llm_family, draft_llm_spec, draft_quantization = draft_match_result - assert draft_quantization is not None - draft_save_path = cache(draft_llm_family, draft_llm_spec, draft_quantization) - - from .pytorch.spec_model import SpeculativeModel - - model = SpeculativeModel( - model_uid, - model_family=llm_family, - model_spec=llm_spec, - quantization=quantization, - model_path=save_path, - draft_model_family=draft_llm_family, - draft_model_spec=draft_llm_spec, - draft_quantization=draft_quantization, - draft_model_path=draft_save_path, - ) - return model, LLMDescription( subpool_addr, devices, llm_family, llm_spec, quantization ) diff --git a/xinference/model/llm/ggml/chatglm.py b/xinference/model/llm/ggml/chatglm.py deleted file mode 100644 index a90c771a80..0000000000 --- a/xinference/model/llm/ggml/chatglm.py +++ /dev/null @@ -1,372 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import json -import logging -import os -import time -import uuid -from pathlib import Path -from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Union - -from ....types import ( - SPECIAL_TOOL_PROMPT, - ChatCompletion, - ChatCompletionChunk, - ChatCompletionMessage, - ChatglmCppGenerateConfig, - ChatglmCppModelConfig, - Completion, - CompletionChunk, -) -from .. import LLMFamilyV1, LLMSpecV1 -from ..core import LLM - -if TYPE_CHECKING: - from chatglm_cpp import Pipeline - - -logger = logging.getLogger(__name__) - - -class ChatglmCppChatModel(LLM): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - model_config: Optional[ChatglmCppModelConfig] = None, - ): - super().__init__(model_uid, model_family, model_spec, quantization, model_path) - self._llm: Optional["Pipeline"] = None - - # just a placeholder for now as the chatglm_cpp repo doesn't support model config. - self._model_config = model_config - - @classmethod - def _sanitize_generate_config( - cls, - chatglmcpp_generate_config: Optional[ChatglmCppGenerateConfig], - ) -> ChatglmCppGenerateConfig: - if chatglmcpp_generate_config is None: - chatglmcpp_generate_config = ChatglmCppGenerateConfig() - chatglmcpp_generate_config.setdefault("stream", False) - return chatglmcpp_generate_config - - def load(self): - try: - import chatglm_cpp - except ImportError: - error_message = "Failed to import module 'chatglm_cpp'" - installation_guide = [ - "Please make sure 'chatglm_cpp' is installed. ", - "You can install it by running the following command in the terminal:\n", - "pip install git+https://github.com/li-plus/chatglm.cpp.git@main\n\n", - "Or visit the original git repo if the above command fails:\n", - "https://github.com/li-plus/chatglm.cpp", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - model_file_path = os.path.join( - self.model_path, - self.model_spec.model_file_name_template.format( - quantization=self.quantization - ), - ) - - # handle legacy cache. - legacy_model_file_path = os.path.join(self.model_path, "model.bin") - if os.path.exists(legacy_model_file_path): - model_file_path = legacy_model_file_path - - self._llm = chatglm_cpp.Pipeline(Path(model_file_path)) - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "ggmlv3": - return False - if "chatglm" not in llm_family.model_name: - return False - if "chat" not in llm_family.model_ability: - return False - return True - - @staticmethod - def _convert_raw_text_chunks_to_chat( - tokens: Iterator[Any], model_name: str - ) -> Iterator[ChatCompletionChunk]: - yield { - "id": "chat" + f"cmpl-{str(uuid.uuid4())}", - "model": model_name, - "object": "chat.completion.chunk", - "created": int(time.time()), - "choices": [ - { - "index": 0, - "delta": { - "role": "assistant", - }, - "finish_reason": None, - } - ], - } - for token in tokens: - yield { - "id": "chat" + f"cmpl-{str(uuid.uuid4())}", - "model": model_name, - "object": "chat.completion.chunk", - "created": int(time.time()), - "choices": [ - { - "index": 0, - "delta": { - "content": ( - token if isinstance(token, str) else token.content - ), - }, - "finish_reason": None, - } - ], - } - - @classmethod - def _convert_raw_text_completion_to_chat( - cls, text: Any, model_name: str - ) -> ChatCompletion: - _id = str(uuid.uuid4()) - return { - "id": "chat" + f"cmpl-{_id}", - "model": model_name, - "object": "chat.completion", - "created": int(time.time()), - "choices": [ - { - "index": 0, - "message": cls._message_to_json_string(_id, text), - "finish_reason": cls._finish_reason_from_msg(text), - } - ], - "usage": { - "prompt_tokens": -1, - "completion_tokens": -1, - "total_tokens": -1, - }, - } - - @staticmethod - def _finish_reason_from_msg(msg): - if isinstance(msg, str): - return None - else: - return "tool_calls" if msg.tool_calls else "stop" - - @staticmethod - def _eval_arguments(arguments): - def tool_call(**kwargs): - return kwargs - - try: - return json.dumps(eval(arguments, dict(tool_call=tool_call))) - except Exception: - return f"Invalid arguments {arguments}" - - @classmethod - def _message_to_json_string(cls, _id, msg) -> ChatCompletionMessage: - if isinstance(msg, str): - return { - "role": "assistant", - "content": msg, - } - else: - return { - "role": msg.role, - "content": msg.content, - "tool_calls": [ - { - "id": f"call_{_id}", - "type": tc.type, - "function": { - "name": tc.function.name, - "arguments": cls._eval_arguments(tc.function.arguments), - }, - } - for tc in msg.tool_calls - ], - } - - @staticmethod - def _handle_tools(generate_config) -> Optional[ChatCompletionMessage]: - """Convert openai tools to ChatGLM tools.""" - if generate_config is None: - return None - tools = generate_config.pop("tools", None) - if tools is None: - return None - chatglm_tools = [] - for elem in tools: - if elem.get("type") != "function" or "function" not in elem: - raise ValueError("ChatGLM tools only support function type.") - chatglm_tools.append(elem["function"]) - return { - "role": "system", - "content": ( - f"Answer the following questions as best as you can. You have access to the following tools:\n" - f"{json.dumps(chatglm_tools, indent=4, ensure_ascii=False)}" - ), - } - - @staticmethod - def _to_chatglm_chat_messages(history_list: List[Any]): - from chatglm_cpp import ChatMessage - - return [ChatMessage(role=v["role"], content=v["content"]) for v in history_list] - - def chat( - self, - prompt: str, - system_prompt: Optional[str] = None, - chat_history: Optional[List[ChatCompletionMessage]] = None, - generate_config: Optional[ChatglmCppGenerateConfig] = None, - ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: - chat_history_list = [] - if system_prompt is not None: - chat_history_list.append({"role": "system", "content": system_prompt}) - if chat_history is not None: - chat_history_list.extend(chat_history) # type: ignore - - tool_message = self._handle_tools(generate_config) - if tool_message is not None: - chat_history_list.insert(0, tool_message) # type: ignore - - # We drop the message which contains tool calls to walkaround the issue: - # https://github.com/li-plus/chatglm.cpp/issues/231 - chat_history_list = [m for m in chat_history_list if not m.get("tool_calls")] - for idx, m in enumerate(chat_history_list): - if m.get("role") == "tool": - # Reconstruct a simple tool message. - chat_history_list[idx] = { - "content": m["content"], - "role": "observation", - } - break - - if prompt != SPECIAL_TOOL_PROMPT: - chat_history_list.append({"role": "user", "content": prompt}) - logger.debug("Full conversation history:\n%s", str(chat_history_list)) - - generate_config = self._sanitize_generate_config(generate_config) - - params = { - "max_length": generate_config.get("max_tokens"), - "max_context_length": generate_config.get("max_tokens"), - "top_k": generate_config.get("top_k"), - "top_p": generate_config.get("top_p"), - "temperature": generate_config.get("temperature"), - "stream": generate_config.get("stream", False), - } - - # Remove None values to exclude missing keys from params - params = {k: v for k, v in params.items() if v is not None} - - assert self._llm is not None - chat_history_messages = self._to_chatglm_chat_messages(chat_history_list) - - if generate_config["stream"]: - it = self._llm.chat( - chat_history_messages, - **params, - ) - assert not isinstance(it, str) - return self._convert_raw_text_chunks_to_chat(it, self.model_uid) - else: - c = self._llm.chat( - chat_history_messages, - **params, - ) - assert not isinstance(c, Iterator) - return self._convert_raw_text_completion_to_chat(c, self.model_uid) - - @staticmethod - def _convert_str_to_completion(data: str, model_name: str) -> Completion: - return { - "id": "generate" + f"-{str(uuid.uuid4())}", - "model": model_name, - "object": "text_completion", - "created": int(time.time()), - "choices": [ - {"index": 0, "text": data, "finish_reason": None, "logprobs": None} - ], - "usage": { - "prompt_tokens": -1, - "completion_tokens": -1, - "total_tokens": -1, - }, - } - - @staticmethod - def _convert_str_to_completion_chunk( - tokens: Iterator[str], model_name: str - ) -> Iterator[CompletionChunk]: - for token in tokens: - yield { - "id": "generate" + f"-{str(uuid.uuid4())}", - "model": model_name, - "object": "text_completion", - "created": int(time.time()), - "choices": [ - {"index": 0, "text": token, "finish_reason": None, "logprobs": None} - ], - } - - def generate( - self, - prompt: str, - generate_config: Optional[ChatglmCppGenerateConfig] = None, - ) -> Union[Completion, Iterator[CompletionChunk]]: - logger.debug(f"Prompt for generate:\n{prompt}") - - generate_config = self._sanitize_generate_config(generate_config) - - params = { - "max_length": generate_config.get("max_tokens"), - "max_context_length": generate_config.get("max_tokens"), - "top_k": generate_config.get("top_k"), - "top_p": generate_config.get("top_p"), - "temperature": generate_config.get("temperature"), - "stream": generate_config.get("stream", False), - } - - # Remove None values to exclude missing keys from params - params = {k: v for k, v in params.items() if v is not None} - - assert self._llm is not None - - if generate_config["stream"]: - it = self._llm.generate( - prompt, - **params, - ) - assert not isinstance(it, str) - return self._convert_str_to_completion_chunk(it, self.model_uid) - else: - c = self._llm.generate( - prompt, - **params, - ) - assert not isinstance(c, Iterator) - return self._convert_str_to_completion(c, self.model_uid) diff --git a/xinference/model/llm/ggml/ctransformers.py b/xinference/model/llm/ggml/ctransformers.py deleted file mode 100644 index 52184767a9..0000000000 --- a/xinference/model/llm/ggml/ctransformers.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import os -from typing import TYPE_CHECKING, Iterator, Optional, Sequence, TypedDict, Union - -if TYPE_CHECKING: - from ctransformers import AutoConfig - -from ....types import Completion, CompletionChunk, CreateCompletionCTransformers -from ..core import LLM -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from .ctransformers_util import generate_stream - -logger = logging.getLogger(__name__) - -# all supported models for Ctransformers with their model type. -# Please Strictly follows this name format when inputting new model to model_family. -MODEL_TYPE_FOR_CTRANSFORMERS = { - "gpt-2": "gpt2", - "gpt-j": "gptj", - "gpt4all-j": "gptj", - "gpt-neox": "gpt_neox", - "stablelm": "gpt_neox", - "llama": "llama", - "llama-2": "llama", - "mpt": "mpt", - "dolly-v2": "dolly-v2", - "replit": "replit", - "starcoder": "starcoder", - "starchat": "starcoder", - "falcon": "falcon", -} - -# these two constants subjects to change for future development and ctransformers updates. -CTRANSFORMERS_SUPPORTED_MODEL = ["starcoder", "gpt-2"] - -CTRANSFORMERS_GPU_SUPPORT = ["llama", "llama-2", "mpt", "falcon"] - -SIZE_TO_GPU_LAYERS = { - 3: 26, - 7: 32, - 13: 40, - 30: 60, - 65: 80, -} - - -class CtransformersModelConfig(TypedDict, total=False): - n_ctx: int - n_gpu_layers: int - - -class CtransformersGenerateConfig(TypedDict, total=False): - max_tokens: Optional[int] - top_k: Optional[int] - top_p: Optional[float] - temperature: Optional[float] - repetition_penalty: Optional[float] - last_n_tokens: Optional[int] - seed: Optional[int] - batch_size: Optional[int] - threads: Optional[int] - stop: Optional[Sequence[str]] - stream: Optional[bool] - reset: Optional[bool] - - -class CtransformersModel(LLM): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - ctransformers_model_config: Optional[CtransformersModelConfig], - ): - super().__init__(model_uid, model_family, model_spec, quantization, model_path) - - self._model_type = None - closest_size = min( - SIZE_TO_GPU_LAYERS.keys(), - key=lambda x: abs( - x - self.handle_model_size(model_spec.model_size_in_billions) - ), - ) - - self._model_family = model_family - self._model_uid = model_uid - self._llm = None - - self._gpu_layers = SIZE_TO_GPU_LAYERS[closest_size] - self._ctransformer_model_config = self._sanitize_model_config( - model_path, ctransformers_model_config - ) - - def _sanitize_model_config( - self, model_path, ctransformers_model_config: Optional[CtransformersModelConfig] - ) -> "AutoConfig": - try: - from ctransformers import AutoConfig, Config - except ImportError: - error_message = ( - "Failed to import module 'ctransformers - AutoConfig and Config'" - ) - - installation_guide = [ - f"Please make sure 'ctransformers' is installed.", - f"You can install it by checking out the repository for command:" - f"https://github.com/marella/ctransformers", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - # if the model have customized config, we update it. - model_config_ret = Config() - potential_gpu_layers = None - if ctransformers_model_config: - potential_context_length = ctransformers_model_config.pop("n_ctx", None) - potential_gpu_layers = ctransformers_model_config.pop("n_gpu_layers", None) - - model_config_ret.context_length = potential_context_length - model_config_ret.gpu_layers = potential_gpu_layers - - # if user does not define gpu layers, we have to set it with our system if applicable. - if potential_gpu_layers is None: - if self._model_family.model_name not in CTRANSFORMERS_GPU_SUPPORT: - model_config_ret.gpu_layers = -1 - elif self._is_darwin_and_apple_silicon(): - model_config_ret.gpu_layers = 1 - elif self._has_cuda_device(): - model_config_ret.gpu_layers = self._gpu_layers - - return AutoConfig(model_config_ret) - - def _sanitize_generate_config( - self, - generate_config: Optional[CtransformersGenerateConfig], - ) -> CtransformersGenerateConfig: - # if the input config is not None, we try to copy the selected attributes to the ctransformersGenerateConfig. - if generate_config is None: - generate_config = CtransformersGenerateConfig( - **CreateCompletionCTransformers().dict() - ) - else: - # Validate generate_config and fill default values to the generate config. - generate_config = CtransformersGenerateConfig( - **CreateCompletionCTransformers(**generate_config).dict() - ) - - # for our system, the threads will have to be set to 4 - # all other parameters, if not specified, will be set to default when generate. - generate_config.setdefault("threads", 4) - - return generate_config - - def load(self): - try: - from ctransformers import AutoModelForCausalLM - except ImportError: - error_message = "Failed to import module 'ctransformers'" - - installation_guide = [ - f"Please make sure 'ctransformers' is installed.", - f"You can install it by checking out the repository for command." - f"https://github.com/marella/ctransformers", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - model_path = os.path.join( - self.model_path, - self.model_spec.model_file_name_template.format( - quantization=self.quantization - ), - ) - - self._model_type = self._determine_model_type() - self._llm = AutoModelForCausalLM.from_pretrained( - model_path_or_repo_id=model_path, - model_type=self._model_type, - config=self._ctransformer_model_config, - ) - - @classmethod - def match( - cls, llm_family: LLMFamilyV1, llm_spec: LLMSpecV1, quantization: str - ) -> bool: - if llm_spec.model_format != "ggmlv3" and llm_spec.model_format != "ggufv2": - return False - if llm_family.model_name not in CTRANSFORMERS_SUPPORTED_MODEL: - return False - if "generate" not in llm_family.model_ability: - return False - return True - - def _determine_model_type(self): - if self._model_family.model_name not in MODEL_TYPE_FOR_CTRANSFORMERS: - raise ValueError( - f"The current model {self._model_family.model_name} is not supported, check your model name. " - ) - return MODEL_TYPE_FOR_CTRANSFORMERS[self._model_family.model_name] - - def generate( - self, prompt: str, generate_config_raw: CtransformersGenerateConfig - ) -> Union[Completion, Iterator[CompletionChunk]]: - def generator_wrapper( - _prompt: str, - _max_new_tokens: Union[int, None], - _generate_config: CtransformersGenerateConfig, - ) -> Iterator[CompletionChunk]: - assert self._model_uid is not None - for _completion_chunk, _ in generate_stream( - model=self._model_uid, - model_ref=self._llm, - prompt=_prompt, - max_new_tokens=_max_new_tokens, - **_generate_config, - ): - yield _completion_chunk - - generate_config = self._sanitize_generate_config(generate_config_raw) - - logger.debug( - "Enter generate, prompt: %s, generate config: %s", prompt, generate_config - ) - - max_new_tokens = generate_config.pop("max_tokens", None) - - stream_or_not = generate_config.get("stream", False) - if stream_or_not: - return generator_wrapper( - _prompt=prompt, - _max_new_tokens=max_new_tokens, - _generate_config=generate_config, - ) - else: - assert self.model_uid is not None - completion_chunk = None - completion_usage = None - for completion_chunk, completion_usage in generate_stream( - model=self.model_uid, - model_ref=self._llm, - prompt=prompt, - max_new_tokens=max_new_tokens, - **generate_config, - ): - pass - - assert completion_chunk is not None - assert completion_usage is not None - - completion = Completion( - id=completion_chunk["id"], - object=completion_chunk["object"], - created=completion_chunk["created"], - model=completion_chunk["model"], - choices=completion_chunk["choices"], - usage=completion_usage, - ) - - logger.debug( - "Generated, completion: %s, generate config: %s", - completion, - generate_config, - ) - - return completion diff --git a/xinference/model/llm/ggml/ctransformers_util.py b/xinference/model/llm/ggml/ctransformers_util.py deleted file mode 100644 index e263a56a70..0000000000 --- a/xinference/model/llm/ggml/ctransformers_util.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import logging -import re -import time -import uuid -from typing import Iterator, Optional, Sequence, Tuple - -from ....types import CompletionChoice, CompletionChunk, CompletionUsage - -logger = logging.getLogger(__name__) - - -def generate_stream( - model, - model_ref, - prompt: str, - *, - max_new_tokens: Optional[int] = None, - top_k: Optional[int] = None, - top_p: Optional[float] = None, - temperature: Optional[float] = None, - repetition_penalty: Optional[float] = None, - last_n_tokens: Optional[int] = None, - seed: Optional[int] = None, - batch_size: Optional[int] = None, - stream: Optional[bool] = False, - threads: Optional[int] = None, - stop: Optional[Sequence[str]] = None, - reset: Optional[bool] = None, - **kwargs, -) -> Iterator[Tuple[CompletionChunk, CompletionUsage]]: - stop = stop or [] - if isinstance(stop, str): - stop = [stop] - - tokens = model_ref.tokenize(prompt) - - stop_regex = re.compile("|".join(map(re.escape, stop))) - count = 0 - text = "" - total_text = "" - incomplete = b"" - - # parameters needed for Xinference. - finish_reason = None - - try: - from ctransformers.utils import utf8_split_incomplete - except ImportError: - error_message = ( - "Failed to import module 'ctransformers - utf8_split_incomplete'" - ) - - installation_guide = [ - "Please make sure 'ctransformers' is installed. You can install it by checking out the repository: " - "https://github.com/marella/ctransformers", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - for token in model_ref.generate( - tokens, - top_k=top_k, - top_p=top_p, - temperature=temperature, - repetition_penalty=repetition_penalty, - last_n_tokens=last_n_tokens, - seed=seed, - batch_size=batch_size, - threads=threads, - reset=reset, - ): - # Handle incomplete UTF-8 multi-byte characters. - incomplete += model_ref.detokenize([token], decode=False) - complete, incomplete = utf8_split_incomplete(incomplete) - output = complete.decode(errors="ignore") - text += output - total_text += output - - # https://github.com/abetlen/llama-cpp-python/blob/1a13d76c487df1c8560132d10bda62d6e2f4fa93/llama_cpp/llama.py#L686-L706 - # Check if one of the stop sequences is part of the text. - # Note that the stop sequence may not always be at the end of text. - if stop: - match = stop_regex.search(text) - if match: - text = text[: match.start()] - finish_reason = "stop" - break - - # Avoid sending the longest suffix of text which is also a prefix - # of a stop sequence, as it can form a stop sequence with the text - # generated later. - longest = 0 - for s in stop: - for i in range(len(s), 0, -1): - if text.endswith(s[:i]): - longest = max(i, longest) - break - - end = len(text) - longest - if end > 0: - output = text[:end] - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=None - ) - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=len(tokens), - completion_tokens=count + 1, - total_tokens=count + 1 + len(tokens), - ) - - yield completion_chunk, completion_usage - text = text[end:] - - count += 1 - if max_new_tokens is not None and count >= max_new_tokens: - finish_reason = "length" - break - - if stream is False: - completion_choice = CompletionChoice( - text=total_text, index=0, logprobs=None, finish_reason=finish_reason - ) - else: - completion_choice = CompletionChoice( - text=text, index=0, logprobs=None, finish_reason=finish_reason - ) - - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=len(tokens), - completion_tokens=count, - total_tokens=count + len(tokens), - ) - - yield completion_chunk, completion_usage diff --git a/xinference/model/llm/ggml/tests/test_chatglm.py b/xinference/model/llm/ggml/tests/test_chatglm.py deleted file mode 100644 index 1019124cde..0000000000 --- a/xinference/model/llm/ggml/tests/test_chatglm.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import random -import string -from typing import Any, Iterator, List, Union - -import pytest - -from ...ggml.chatglm import ChatglmCppChatModel -from ...llm_family import GgmlLLMSpecV1, LLMFamilyV1 - - -class MockPipeline: - def __init__(self) -> None: - pass - - def chat(self, *args, **kwargs) -> Union[str, Iterator[str]]: - stream = kwargs.get("stream", False) - return ( - iter([f"chatglm_test_stream_{i}" for i in range(5)]) - if stream - else "chatglm_test_chat" - ) - - def generate(self, *args, **kwargs) -> Union[str, Iterator[str]]: - stream = kwargs.get("stream", False) - return ( - "chatglm_test_generate" - if not stream - else iter([f"chatglm_test_stream_generate_{i}" for i in range(5)]) - ) - - -class MockChatglmCppChatModel(ChatglmCppChatModel): - def load(self): - self._llm = MockPipeline() - - @staticmethod - def _to_chatglm_chat_messages(history_list: List[Any]): - return [] - - -mock_model_spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=6, - quantizations=["q2_k", "q4_0"], - model_id="test_id", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", -) - -serialized = """{ - "version":1, - "context_length":2048, - "model_name":"TestModel", - "model_lang":[ - "en" - ], - "model_ability":[ - "embed", "generate" - ], - "model_specs":[ - { - "model_format":"ggmlv3", - "model_size_in_billions":6, - "quantizations": ["q2_k", "q4_0"], - "model_id":"test_id", - "model_file_name_template":"TestModel.{quantization}.ggmlv3.bin" - }, - { - "model_format":"pytorch", - "model_size_in_billions":3, - "quantizations": ["int8", "int4", "none"], - "model_id":"example/TestModel" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "system_prompt": "TEST", - "roles": ["user", "assistant"], - "intra_message_sep": "\\n### ", - "inter_message_sep": "\\n### ", - "stop": null, - "stop_token_ids": null - } -}""" - -mock_model_family = LLMFamilyV1.parse_raw(serialized) - - -@pytest.mark.parametrize( - "model_spec, model_family", [(mock_model_spec, mock_model_family)] -) -def test_model_init(model_spec, model_family): - quantization = "q2_k" - uid = "".join(random.choice(string.digits) for i in range(100)) - path = "".join( - random.choice(string.ascii_letters + string.punctuation) for i in range(100) - ) - model = MockChatglmCppChatModel( - model_uid=uid, - model_family=model_family, - model_spec=model_spec, - quantization=quantization, - model_path=path, - ) - - assert model.model_uid == uid - assert model.quantization == quantization - assert model.model_path == path - - assert isinstance(model.model_spec, GgmlLLMSpecV1) - assert isinstance(model.model_family, LLMFamilyV1) - assert isinstance(model.model_family.model_specs[0], GgmlLLMSpecV1) - - assert ( - model.model_family.model_specs[0].model_format == model.model_spec.model_format - ) - assert model.model_family.model_specs[0].model_format == model_spec.model_format - assert ( - model.model_family.model_specs[0].model_size_in_billions - == model.model_spec.model_size_in_billions - ) - assert ( - model.model_family.model_specs[0].model_size_in_billions - == model_spec.model_size_in_billions - ) - assert ( - model.model_family.model_specs[0].quantizations - == model.model_spec.quantizations - ) - assert model.model_family.model_specs[0].quantizations == model_spec.quantizations - assert model.model_family.model_specs[0].model_id == model.model_spec.model_id - assert model.model_family.model_specs[0].model_id == model_spec.model_id - assert ( - model.model_family.model_specs[0].model_file_name_template - == model.model_spec.model_file_name_template - ) - assert ( - model.model_family.model_specs[0].model_file_name_template - == model_spec.model_file_name_template - ) - assert model.model_family.model_specs[0].model_uri == model.model_spec.model_uri - assert model.model_family.model_specs[0].model_uri == model_spec.model_uri - - assert model._llm is None - assert model._model_config is None - model._model_config = model._sanitize_generate_config(None) - assert not model._model_config["stream"] - - -@pytest.mark.parametrize( - "model_spec, model_family", [(mock_model_spec, mock_model_family)] -) -def test_model_chat(model_spec, model_family): - quantization = "q2_k" - uid = "".join(random.choice(string.digits) for i in range(100)) - path = "".join( - random.choice(string.ascii_letters + string.punctuation) for i in range(100) - ) - model = MockChatglmCppChatModel( - model_uid=uid, - model_family=model_family, - model_spec=model_spec, - quantization=quantization, - model_path=path, - ) - - assert model._llm is None - - model.load() - assert isinstance(model._llm, MockPipeline) - - responses_stream = list(model.chat("Hello", generate_config={"stream": True})) - assert responses_stream[0]["choices"][0]["delta"] == {"role": "assistant"} - for i in range(3): - assert responses_stream[i + 1]["choices"][0]["delta"] == { - "content": f"chatglm_test_stream_{i}" - } - - responses_non_stream = model.chat("Hello", generate_config={"stream": False}) - assert responses_non_stream["choices"][0]["message"] == { - "role": "assistant", - "content": "chatglm_test_chat", - } - - -@pytest.mark.parametrize( - "model_spec, model_family", [(mock_model_spec, mock_model_family)] -) -def test_model_generate(model_spec, model_family): - quantization = "q2_k" - uid = "".join(random.choice(string.digits) for i in range(100)) - path = "".join( - random.choice(string.ascii_letters + string.punctuation) for i in range(100) - ) - model = MockChatglmCppChatModel( - model_uid=uid, - model_family=model_family, - model_spec=model_spec, - quantization=quantization, - model_path=path, - ) - assert model._llm is None - - model.load() - assert isinstance(model._llm, MockPipeline) - - responses_stream = list(model.generate("Hello", generate_config={"stream": True})) - for i in range(5): - assert ( - responses_stream[i]["choices"][0]["text"] - == f"chatglm_test_stream_generate_{i}" - ) - - responses_non_stream = model.generate("Hello", generate_config={"stream": False}) - assert responses_non_stream["choices"][0]["text"] == "chatglm_test_generate" diff --git a/xinference/model/llm/ggml/tests/test_ctransformers.py b/xinference/model/llm/ggml/tests/test_ctransformers.py deleted file mode 100644 index 9bbcecb70f..0000000000 --- a/xinference/model/llm/ggml/tests/test_ctransformers.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import random -import string - -import pytest - -from .....client import Client -from .....client.restful.restful_client import RESTfulGenerateModelHandle -from ....llm import GgmlLLMSpecV1, LLMFamilyV1 -from ..ctransformers import CtransformersModel - -mock_model_spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=6, - quantizations=["q2_k", "q4_0"], - model_id="test_id", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", -) - -test_model_spec = """{ - "version":1, - "context_length":2048, - "model_name":"TestModel", - "model_lang":[ - "en" - ], - "model_ability":[ - "embed", "generate" - ], - "model_specs":[ - { - "model_format":"ggmlv3", - "model_size_in_billions":6, - "quantizations": ["q2_k", "q4_0"], - "model_id":"test_id", - "model_file_name_template":"TestModel.{quantization}.ggmlv3.bin" - }, - { - "model_format":"pytorch", - "model_size_in_billions":3, - "quantizations": ["int8", "int4", "none"], - "model_id":"example/TestModel" - } - ], - "prompt_style": null -}""" - -mock_model_family = LLMFamilyV1.parse_raw(test_model_spec) - - -@pytest.mark.parametrize( - "model_spec, model_family", [(mock_model_spec, mock_model_family)] -) -def test_ctransformer_init(model_spec, model_family): - from ctransformers import AutoConfig - - quantization = "q4_0" - uid = "".join(random.choice(string.digits) for i in range(15)) - path = "".join( - random.choice(string.ascii_letters + string.punctuation) for i in range(100) - ) - model = CtransformersModel( - model_uid=uid, - model_family=model_family, - model_spec=model_spec, - quantization=quantization, - model_path=path, - ctransformers_model_config=None, - ) - - assert model.model_uid == uid - assert model.quantization == quantization - assert model.model_path == path - assert model._ctransformer_model_config is not None - assert isinstance(model._ctransformer_model_config, AutoConfig) - - assert isinstance(model.model_spec, GgmlLLMSpecV1) - assert isinstance(model.model_family, LLMFamilyV1) - assert isinstance(model.model_family.model_specs[0], GgmlLLMSpecV1) - - assert ( - model.model_family.model_specs[0].model_format == model.model_spec.model_format - ) - assert model.model_family.model_specs[0].model_format == model_spec.model_format - assert ( - model.model_family.model_specs[0].model_size_in_billions - == model.model_spec.model_size_in_billions - ) - assert ( - model.model_family.model_specs[0].model_size_in_billions - == model_spec.model_size_in_billions - ) - assert ( - model.model_family.model_specs[0].quantizations - == model.model_spec.quantizations - ) - assert model.model_family.model_specs[0].quantizations == model_spec.quantizations - assert model.model_family.model_specs[0].model_id == model.model_spec.model_id - assert model.model_family.model_specs[0].model_id == model_spec.model_id - assert ( - model.model_family.model_specs[0].model_file_name_template - == model.model_spec.model_file_name_template - ) - assert ( - model.model_family.model_specs[0].model_file_name_template - == model_spec.model_file_name_template - ) - assert model._llm is None - - -@pytest.mark.asyncio -async def test_ctransformers_generate(setup): - endpoint, _ = setup - client = Client(endpoint) - assert len(client.list_models()) == 0 - - model_uid = client.launch_model( - model_name="gpt-2", - model_size_in_billions=1, - model_format="ggmlv3", - quantization="none", - ) - - assert len(client.list_models()) == 1 - - model = client.get_model(model_uid=model_uid) - assert isinstance(model, RESTfulGenerateModelHandle) - - completion = model.generate("AI is going to", generate_config={"max_tokens": 5}) - print(completion) - assert "id" in completion - assert "text" in completion["choices"][0] - assert len(completion["choices"][0]["text"]) > 0 - - assert completion["model"] == model_uid - - assert "finish_reason" in completion["choices"][0] - assert completion["choices"][0]["finish_reason"] == "length" - - assert "prompt_tokens" in completion["usage"] - assert completion["usage"]["prompt_tokens"] == 4 - - assert "completion_tokens" in completion["usage"] - assert completion["usage"]["completion_tokens"] == 5 - - assert "total_tokens" in completion["usage"] - assert completion["usage"]["total_tokens"] == 9 - - client.terminate_model(model_uid=model_uid) - assert len(client.list_models()) == 0 diff --git a/xinference/model/llm/ggml/tools/convert_ggml_to_gguf.py b/xinference/model/llm/ggml/tools/convert_ggml_to_gguf.py deleted file mode 100644 index b3011bd207..0000000000 --- a/xinference/model/llm/ggml/tools/convert_ggml_to_gguf.py +++ /dev/null @@ -1,498 +0,0 @@ -#!/usr/bin/env python3 -# Copied from llama.cpp to convert ggml file to gguf -from __future__ import annotations - -import argparse -import struct -from enum import IntEnum -from pathlib import Path -from typing import Optional - -import numpy as np - -from . import gguf - -# Note: Does not support GGML_QKK_64 -QK_K = 256 -# Items here are (block size, type size) -GGML_QUANT_SIZES = { - gguf.GGMLQuantizationType.F32: (1, 4), - gguf.GGMLQuantizationType.F16: (1, 2), - gguf.GGMLQuantizationType.Q4_0: (32, 2 + 16), - gguf.GGMLQuantizationType.Q4_1: (32, 2 + 2 + 16), - gguf.GGMLQuantizationType.Q5_0: (32, 2 + 4 + 16), - gguf.GGMLQuantizationType.Q5_1: (32, 2 + 2 + 4 + 16), - gguf.GGMLQuantizationType.Q8_0: (32, 2 + 32), - gguf.GGMLQuantizationType.Q8_1: (32, 4 + 4 + 32), - gguf.GGMLQuantizationType.Q2_K: (256, 2 + 2 + QK_K // 16 + QK_K // 4), - gguf.GGMLQuantizationType.Q3_K: (256, 2 + QK_K // 4 + QK_K // 8 + 12), - gguf.GGMLQuantizationType.Q4_K: (256, 2 + 2 + QK_K // 2 + 12), - gguf.GGMLQuantizationType.Q5_K: (256, 2 + 2 + QK_K // 2 + QK_K // 8 + 12), - gguf.GGMLQuantizationType.Q6_K: (256, 2 + QK_K // 2 + QK_K // 4 + QK_K // 16), - gguf.GGMLQuantizationType.Q8_K: (256, 4 + QK_K + QK_K // 8), -} - - -class GGMLFormat(IntEnum): - GGML = 0 - GGMF = 1 - GGJT = 2 - - -class GGMLFType(IntEnum): - ALL_F32 = 0 - MOSTLY_F16 = 1 - MOSTLY_Q4_0 = 2 - MOSTLY_Q4_1 = 3 - MOSTLY_Q4_1_SOME_F16 = 4 - MOSTLY_Q8_0 = 7 - MOSTLY_Q5_0 = 8 - MOSTLY_Q5_1 = 9 - MOSTLY_Q2_K = 10 - MOSTLY_Q3_K_S = 11 - MOSTLY_Q3_K_M = 12 - MOSTLY_Q3_K_L = 13 - MOSTLY_Q4_K_S = 14 - MOSTLY_Q4_K_M = 15 - MOSTLY_Q5_K_S = 16 - MOSTLY_Q5_K_M = 17 - MOSTLY_Q6_K = 18 - - -class Hyperparameters: - def __init__(self): - self.n_vocab = self.n_embd = self.n_mult = self.n_head = 0 - self.n_layer = self.n_rot = self.n_ff = 0 - self.ftype = GGMLFType.ALL_F32 - - def set_n_ff(self, model): - ff_tensor_idx = model.tensor_map.get(b"layers.0.feed_forward.w1.weight") - assert ff_tensor_idx is not None, "Missing layer 0 FF tensor" - ff_tensor = model.tensors[ff_tensor_idx] - self.n_ff = ff_tensor.dims[1] - - def load(self, data, offset): - ( - self.n_vocab, - self.n_embd, - self.n_mult, - self.n_head, - self.n_layer, - self.n_rot, - ftype, - ) = struct.unpack("<7I", data[offset : offset + (4 * 7)]) - try: - self.ftype = GGMLFType(ftype) - except ValueError: - raise ValueError(f"Invalid ftype {ftype}") - return 4 * 7 - - def __str__(self): - return f"" - - -class Vocab: - def __init__(self, load_scores=True): - self.items = [] - self.load_scores = load_scores - - def load(self, data, offset, n_vocab): - orig_offset = offset - for _ in range(n_vocab): - itemlen = struct.unpack("= 0 and n_dims <= 4, f"Invalid tensor dimensions {n_dims}" - assert name_len < 4096, "Absurd tensor name length" - quant = GGML_QUANT_SIZES.get(dtype) - assert quant is not None, "Unknown tensor type" - (blksize, tysize) = quant - offset += 12 - self.dtype = dtype - self.dims = struct.unpack(f"<{n_dims}I", data[offset : offset + (4 * n_dims)]) - offset += 4 * n_dims - self.name = bytes(data[offset : offset + name_len]) - offset += name_len - pad = ((offset + 31) & ~31) - offset if self.use_padding else 0 - offset += pad - n_elems = np.prod(self.dims) - n_bytes = np.int64(np.int64(n_elems) * np.int64(tysize)) // np.int64(blksize) - self.start_offset = offset - self.len_bytes = n_bytes - offset += n_bytes - # print(n_dims, name_len, dtype, self.dims, self.name, pad) - return offset - orig_offset - - -class GGMLModel: - def __init__(self): - self.hyperparameters = None - self.vocab = None - self.tensor_map = {} - self.tensors = [] - - def validate_header(self, data, offset): - magic = bytes(data[offset : offset + 4]) - if magic == b"GGUF": - raise ValueError("File is already in GGUF format.") - if magic == b"lmgg": - self.file_format = GGMLFormat.GGML - self.format_version = 1 - return 4 - version = struct.unpack(" 3: - raise ValueError( - f"Cannot handle unexpected GGJT file version {version}" - ) - self.file_format = GGMLFormat.GGJT - self.format_version = version - return 8 - raise ValueError( - f"Unexpected file magic {magic!r}! This doesn't look like a GGML format file." - ) - - def validate_conversion(self, ftype): - err = "" - if self.file_format < GGMLFormat.GGJT or self.format_version < 2: - if ftype not in (GGMLFType.ALL_F32, GGMLFType.MOSTLY_F16): - err = "Quantizations changed in GGJTv2. Can only convert unquantized GGML files older than GGJTv2." - elif self.file_format == GGMLFormat.GGJT and self.format_version == 2: - if ftype in ( - GGMLFType.MOSTLY_Q4_0, - GGMLFType.MOSTLY_Q4_1, - GGMLFType.MOSTLY_Q4_1_SOME_F16, - GGMLFType.MOSTLY_Q8_0, - ): - err = "Q4 and Q8 quantizations changed in GGJTv3." - if len(err) > 0: - raise ValueError( - f"{err} Sorry, your {self.file_format.name}v{self.format_version} file of type {ftype.name} is not eligible for conversion." - ) - - def load(self, data, offset): - offset += self.validate_header(data, offset) - hp = Hyperparameters() - offset += hp.load(data, offset) - print( - f"* File format: {self.file_format.name}v{self.format_version} with ftype {hp.ftype.name}" - ) - self.validate_conversion(hp.ftype) - vocab = Vocab(load_scores=self.file_format > GGMLFormat.GGML) - offset += vocab.load(data, offset, hp.n_vocab) - tensors: list[Tensor] = [] - tensor_map = {} - while offset < len(data): - tensor = Tensor(use_padding=self.file_format > GGMLFormat.GGMF) - offset += tensor.load(data, offset) - tensor_map[tensor.name] = len(tensors) - tensors.append(tensor) - self.hyperparameters = hp - self.vocab = vocab - self.tensors = tensors - self.tensor_map = tensor_map - hp.set_n_ff(self) - return offset - - -class GGMLToGGUF: - def __init__( - self, - ggml_model, - data, - cfg, - params_override=None, - vocab_override=None, - special_vocab=None, - ): - hp = ggml_model.hyperparameters - self.model = ggml_model - self.data = data - self.cfg = cfg - self.params_override = params_override - self.vocab_override = vocab_override - self.special_vocab = special_vocab - if params_override is not None: - n_kv_head = params_override.n_head_kv - else: - if cfg.gqa == 1: - n_kv_head = hp.n_head - else: - gqa = float(cfg.gqa) - n_kv_head = None - for x in range(1, 256): - if float(hp.n_head) / float(x) == gqa: - n_kv_head = x - assert ( - n_kv_head is not None - ), "Couldn't determine n_kv_head from GQA param" - print(f"- Guessed n_kv_head = {n_kv_head} based on GQA {cfg.gqa}") - self.n_kv_head = n_kv_head - self.name_map = gguf.get_tensor_name_map( - gguf.MODEL_ARCH.LLAMA, ggml_model.hyperparameters.n_layer - ) - - def save(self): - print("* Preparing to save GGUF file") - gguf_writer = gguf.GGUFWriter( - self.cfg.output, - gguf.MODEL_ARCH_NAMES[gguf.MODEL_ARCH.LLAMA], - use_temp_file=False, - ) - self.add_params(gguf_writer) - self.add_vocab(gguf_writer) - if self.special_vocab is not None: - self.special_vocab.add_to_gguf(gguf_writer) - self.add_tensors(gguf_writer) - print(" gguf: write header") - gguf_writer.write_header_to_file() - print(" gguf: write metadata") - gguf_writer.write_kv_data_to_file() - print(" gguf: write tensors") - gguf_writer.write_tensors_to_file() - gguf_writer.close() - - def add_params(self, gguf_writer): - hp = self.model.hyperparameters - cfg = self.cfg - if cfg.desc is not None: - desc = cfg.desc - else: - desc = f"converted from legacy {self.model.file_format.name}v{self.model.format_version} {hp.ftype.name} format" - try: - # Filenames aren't necessarily valid UTF8. - name = cfg.name if cfg.name is not None else cfg.input.name - except UnicodeDecodeError: - name = None - print("* Adding model parameters and KV items") - if name is not None: - gguf_writer.add_name(name) - gguf_writer.add_description(desc) - gguf_writer.add_file_type(int(hp.ftype)) - if self.params_override is not None: - po = self.params_override - assert po.n_embd == hp.n_embd, "Model hyperparams mismatch" - assert po.n_layer == hp.n_layer, "Model hyperparams mismatch" - assert po.n_head == hp.n_head, "Model hyperparams mismatch" - gguf_writer.add_context_length(po.n_ctx) - gguf_writer.add_embedding_length(po.n_embd) - gguf_writer.add_block_count(po.n_layer) - gguf_writer.add_feed_forward_length(po.n_ff) - gguf_writer.add_rope_dimension_count(po.n_embd // po.n_head) - gguf_writer.add_head_count(po.n_head) - gguf_writer.add_head_count_kv(po.n_head_kv) - gguf_writer.add_layer_norm_rms_eps(po.f_norm_eps) - return - gguf_writer.add_context_length(cfg.context_length) - gguf_writer.add_embedding_length(hp.n_embd) - gguf_writer.add_block_count(hp.n_layer) - gguf_writer.add_feed_forward_length(hp.n_ff) - gguf_writer.add_rope_dimension_count(hp.n_embd // hp.n_head) - gguf_writer.add_head_count(hp.n_head) - gguf_writer.add_head_count_kv(self.n_kv_head) - gguf_writer.add_layer_norm_rms_eps(float(cfg.eps)) - - def add_vocab(self, gguf_writer): - hp = self.model.hyperparameters - gguf_writer.add_tokenizer_model("llama") - tokens = [] - scores = [] - toktypes = [] - if self.vocab_override is not None: - vo = self.vocab_override - print("* Adding vocab item(s)") - for idx, (vbytes, score, ttype) in enumerate(vo.all_tokens()): - tokens.append(vbytes) - scores.append(score) - toktypes.append(ttype) - assert ( - len(tokens) == hp.n_vocab - ), f"Override vocab has a different number of items than hyperparameters - override = {len(tokens)} but n_vocab={hp.n_vocab}" - gguf_writer.add_token_list(tokens) - gguf_writer.add_token_scores(scores) - if len(toktypes) > 0: - gguf_writer.add_token_types(toktypes) - return - print(f"* Adding {hp.n_vocab} vocab item(s)") - assert ( - len(self.model.vocab.items) >= 3 - ), "Cannot handle unexpectedly short model vocab" - for tokid, (vbytes, vscore) in enumerate(self.model.vocab.items): - tt = 1 # Normal - # Special handling for UNK, BOS, EOS tokens. - if tokid <= 2: - if tokid == 0: - vbytes = b"" - tt = 2 - elif tokid == 1: - vbytes = b"" - tt = 3 - else: - vbytes = b"" - tt = 3 - elif len(vbytes) == 0: - tt = 3 # Control - elif tokid >= 3 and tokid <= 258 and len(vbytes) == 1: - vbytes = bytes(f"<0x{vbytes[0]:02X}>", encoding="UTF-8") - tt = 6 # Byte - else: - vbytes = vbytes.replace(b" ", b"\xe2\x96\x81") - toktypes.append(tt) - tokens.append(vbytes) - scores.append(vscore) - gguf_writer.add_token_list(tokens) - gguf_writer.add_token_scores(scores) - gguf_writer.add_token_types(toktypes) - gguf_writer.add_unk_token_id(0) - gguf_writer.add_bos_token_id(1) - gguf_writer.add_eos_token_id(2) - - def add_tensors(self, gguf_writer): - tensor_map = self.name_map - data = self.data - print(f"* Adding {len(self.model.tensors)} tensor(s)") - for tensor in self.model.tensors: - name = str(tensor.name, "UTF-8") - mapped_name = tensor_map.get_name(name, try_suffixes=(".weight", ".bias")) - assert mapped_name is not None, f"Bad name {name}" - tempdims = list(tensor.dims[:]) - if len(tempdims) > 1: - temp = tempdims[1] - tempdims[1] = tempdims[0] - tempdims[0] = temp - # print(f'+ {tensor.name} | {mapped_name} {tensor.dims} :: {tempdims}') - gguf_writer.add_tensor( - mapped_name, - data[tensor.start_offset : tensor.start_offset + tensor.len_bytes], - raw_shape=tempdims, - raw_dtype=tensor.dtype, - ) - - -def handle_args(): - parser = argparse.ArgumentParser(description="Convert GGML models to GGUF") - parser.add_argument( - "--input", "-i", type=Path, required=True, help="Input GGMLv3 filename" - ) - parser.add_argument( - "--output", "-o", type=Path, required=True, help="Output GGUF filename" - ) - parser.add_argument("--name", help="Set model name") - parser.add_argument("--desc", help="Set model description") - parser.add_argument( - "--gqa", - type=int, - default=1, - help="grouped-query attention factor (use 8 for LLaMA2 70B)", - ) - parser.add_argument( - "--eps", - default="5.0e-06", - help="RMS norm eps: Use 1e-6 for LLaMA1 and OpenLLaMA, use 1e-5 for LLaMA2", - ) - parser.add_argument( - "--context-length", - "-c", - type=int, - default=2048, - help="Default max context length: LLaMA1 is typically 2048, LLaMA2 is typically 4096", - ) - return parser.parse_args() - - -from dataclasses import dataclass - - -@dataclass -class Config: - input: Path - output: Path - name: Optional[str] - desc: Optional[str] - gqa: int - eps: float - context_length: int - - -def convert( - source_path: str, - dest_path: str, - model_name: Optional[str] = None, - model_desc: Optional[str] = None, - gqa: int = 1, - eps: float = 5.0e-06, - context_length: int = 2048, -): - cfg = Config( - input=Path(source_path), - output=Path(dest_path), - name=model_name, - desc=model_desc, - gqa=gqa, - eps=eps, - context_length=context_length, - ) - print(f"* Using config: {cfg}") - print( - "\n=== WARNING === Be aware that this conversion script is best-effort. Use a native GGUF model if possible. === WARNING ===\n" - ) - if cfg.gqa == 1 or cfg.eps == "5.0e-06": - print( - '- Note: If converting LLaMA2, specifying "--eps 1e-5" is required. 70B models also need "--gqa 8".' - ) - data = np.memmap(cfg.input, mode="r") - model = GGMLModel() - print("* Scanning GGML input file") - model.load(data, 0) - print(f"* GGML model hyperparameters: {model.hyperparameters}") - vocab_override = None - params_override = None - special_vocab = None - print( - "\n=== WARNING === Special tokens may not be converted correctly. Use --model-metadata-dir if possible === WARNING ===\n" - ) - if model.file_format == GGMLFormat.GGML: - print( - "! This is a very old GGML file that does not contain vocab scores. Strongly recommend using model metadata!" - ) - converter = GGMLToGGUF( - model, - data, - cfg, - params_override=params_override, - vocab_override=vocab_override, - special_vocab=special_vocab, - ) - converter.save() - print(f"* Successful completion. Output saved to: {cfg.output}") diff --git a/xinference/model/llm/ggml/tools/gguf.py b/xinference/model/llm/ggml/tools/gguf.py deleted file mode 100644 index c624feeba1..0000000000 --- a/xinference/model/llm/ggml/tools/gguf.py +++ /dev/null @@ -1,884 +0,0 @@ -#!/usr/bin/env python3 -# copied from llama.cpp -from __future__ import annotations - -import json -import os -import shutil -import struct -import sys -import tempfile -from enum import IntEnum, auto -from io import BufferedWriter -from pathlib import Path -from typing import Any, BinaryIO, Callable, Sequence - -import numpy as np - -# -# constants -# - -GGUF_MAGIC = 0x46554747 -GGUF_VERSION = 2 -GGUF_DEFAULT_ALIGNMENT = 32 - -# general -KEY_GENERAL_ARCHITECTURE = "general.architecture" -KEY_GENERAL_QUANTIZATION_VERSION = "general.quantization_version" -KEY_GENERAL_ALIGNMENT = "general.alignment" -KEY_GENERAL_NAME = "general.name" -KEY_GENERAL_AUTHOR = "general.author" -KEY_GENERAL_URL = "general.url" -KEY_GENERAL_DESCRIPTION = "general.description" -KEY_GENERAL_LICENSE = "general.license" -KEY_GENERAL_SOURCE_URL = "general.source.url" -KEY_GENERAL_SOURCE_HF_REPO = "general.source.hugginface.repository" -KEY_GENERAL_FILE_TYPE = "general.file_type" - -# LLM -KEY_CONTEXT_LENGTH = "{arch}.context_length" -KEY_EMBEDDING_LENGTH = "{arch}.embedding_length" -KEY_BLOCK_COUNT = "{arch}.block_count" -KEY_FEED_FORWARD_LENGTH = "{arch}.feed_forward_length" -KEY_USE_PARALLEL_RESIDUAL = "{arch}.use_parallel_residual" -KEY_TENSOR_DATA_LAYOUT = "{arch}.tensor_data_layout" - -# attention -KEY_ATTENTION_HEAD_COUNT = "{arch}.attention.head_count" -KEY_ATTENTION_HEAD_COUNT_KV = "{arch}.attention.head_count_kv" -KEY_ATTENTION_MAX_ALIBI_BIAS = "{arch}.attention.max_alibi_bias" -KEY_ATTENTION_CLAMP_KQV = "{arch}.attention.clamp_kqv" -KEY_ATTENTION_LAYERNORM_EPS = "{arch}.attention.layer_norm_epsilon" -KEY_ATTENTION_LAYERNORM_RMS_EPS = "{arch}.attention.layer_norm_rms_epsilon" - -# RoPE -KEY_ROPE_DIMENSION_COUNT = "{arch}.rope.dimension_count" -KEY_ROPE_FREQ_BASE = "{arch}.rope.freq_base" -KEY_ROPE_SCALE_LINEAR = "{arch}.rope.scale_linear" - -# tokenization -KEY_TOKENIZER_MODEL = "tokenizer.ggml.model" -KEY_TOKENIZER_LIST = "tokenizer.ggml.tokens" -KEY_TOKENIZER_TOKEN_TYPE = "tokenizer.ggml.token_type" -KEY_TOKENIZER_SCORES = "tokenizer.ggml.scores" -KEY_TOKENIZER_MERGES = "tokenizer.ggml.merges" -KEY_TOKENIZER_BOS_ID = "tokenizer.ggml.bos_token_id" -KEY_TOKENIZER_EOS_ID = "tokenizer.ggml.eos_token_id" -KEY_TOKENIZER_UNK_ID = "tokenizer.ggml.unknown_token_id" -KEY_TOKENIZER_SEP_ID = "tokenizer.ggml.seperator_token_id" -KEY_TOKENIZER_PAD_ID = "tokenizer.ggml.padding_token_id" -KEY_TOKENIZER_HF_JSON = "tokenizer.huggingface.json" -KEY_TOKENIZER_RWKV = "tokenizer.rwkv.world" - - -# -# recommended mapping of model tensor names for storage in gguf -# - - -class MODEL_ARCH(IntEnum): - LLAMA: int = auto() - FALCON: int = auto() - GPT2: int = auto() - GPTJ: int = auto() - GPTNEOX: int = auto() - MPT: int = auto() - - -class MODEL_TENSOR(IntEnum): - TOKEN_EMBD: int = auto() - POS_EMBD: int = auto() - OUTPUT: int = auto() - OUTPUT_NORM: int = auto() - ROPE_FREQS: int = auto() - ATTN_Q: int = auto() - ATTN_K: int = auto() - ATTN_V: int = auto() - ATTN_QKV: int = auto() - ATTN_OUT: int = auto() - ATTN_NORM: int = auto() - ATTN_NORM_2: int = auto() - ATTN_ROT_EMBD: int = auto() - FFN_GATE: int = auto() - FFN_DOWN: int = auto() - FFN_UP: int = auto() - FFN_NORM: int = auto() - - -MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = { - MODEL_ARCH.LLAMA: "llama", - MODEL_ARCH.FALCON: "falcon", - MODEL_ARCH.GPT2: "gpt2", - MODEL_ARCH.GPTJ: "gptj", - MODEL_ARCH.GPTNEOX: "gptneox", - MODEL_ARCH.MPT: "mpt", -} - -MODEL_TENSOR_NAMES: dict[MODEL_ARCH, dict[MODEL_TENSOR, str]] = { - MODEL_ARCH.LLAMA: { - MODEL_TENSOR.TOKEN_EMBD: "token_embd", - MODEL_TENSOR.OUTPUT_NORM: "output_norm", - MODEL_TENSOR.OUTPUT: "output", - MODEL_TENSOR.ROPE_FREQS: "rope_freqs", - MODEL_TENSOR.ATTN_NORM: "blk.{bid}.attn_norm", - MODEL_TENSOR.ATTN_Q: "blk.{bid}.attn_q", - MODEL_TENSOR.ATTN_K: "blk.{bid}.attn_k", - MODEL_TENSOR.ATTN_V: "blk.{bid}.attn_v", - MODEL_TENSOR.ATTN_OUT: "blk.{bid}.attn_output", - MODEL_TENSOR.ATTN_ROT_EMBD: "blk.{bid}.attn_rot_embd", - MODEL_TENSOR.FFN_NORM: "blk.{bid}.ffn_norm", - MODEL_TENSOR.FFN_GATE: "blk.{bid}.ffn_gate", - MODEL_TENSOR.FFN_DOWN: "blk.{bid}.ffn_down", - MODEL_TENSOR.FFN_UP: "blk.{bid}.ffn_up", - }, - MODEL_ARCH.GPTNEOX: { - MODEL_TENSOR.TOKEN_EMBD: "token_embd", - MODEL_TENSOR.OUTPUT_NORM: "output_norm", - MODEL_TENSOR.OUTPUT: "output", - MODEL_TENSOR.ATTN_NORM: "blk.{bid}.attn_norm", - MODEL_TENSOR.ATTN_QKV: "blk.{bid}.attn_qkv", - MODEL_TENSOR.ATTN_OUT: "blk.{bid}.attn_output", - MODEL_TENSOR.FFN_NORM: "blk.{bid}.ffn_norm", - MODEL_TENSOR.FFN_DOWN: "blk.{bid}.ffn_down", - MODEL_TENSOR.FFN_UP: "blk.{bid}.ffn_up", - }, - MODEL_ARCH.FALCON: { - MODEL_TENSOR.TOKEN_EMBD: "token_embd", - MODEL_TENSOR.OUTPUT_NORM: "output_norm", - MODEL_TENSOR.OUTPUT: "output", - MODEL_TENSOR.ATTN_NORM: "blk.{bid}.attn_norm", - MODEL_TENSOR.ATTN_NORM_2: "blk.{bid}.attn_norm_2", - MODEL_TENSOR.ATTN_QKV: "blk.{bid}.attn_qkv", - MODEL_TENSOR.ATTN_OUT: "blk.{bid}.attn_output", - MODEL_TENSOR.FFN_DOWN: "blk.{bid}.ffn_down", - MODEL_TENSOR.FFN_UP: "blk.{bid}.ffn_up", - }, - MODEL_ARCH.GPT2: { - # TODO - }, - # TODO -} - -# tensors that will not be serialized -MODEL_TENSOR_SKIP: dict[MODEL_ARCH, list[MODEL_TENSOR]] = { - MODEL_ARCH.LLAMA: [ - MODEL_TENSOR.ROPE_FREQS, - MODEL_TENSOR.ATTN_ROT_EMBD, - ], -} - - -class TensorNameMap: - mappings_cfg: dict[MODEL_TENSOR, tuple[str, ...]] = { - # Token embeddings - MODEL_TENSOR.TOKEN_EMBD: ( - "gpt_neox.embed_in", # gptneox - "transformer.wte", # gpt2 mpt - "transformer.word_embeddings", # falcon - "model.embed_tokens", # llama-hf - "tok_embeddings", # llama-pth - ), - # Position embeddings - MODEL_TENSOR.POS_EMBD: ("transformer.wpe",), # gpt2 - # Output - MODEL_TENSOR.OUTPUT: ( - "embed_out", # gptneox - "lm_head", # gpt2 mpt falcon llama-hf - "output", # llama-pth - ), - # Output norm - MODEL_TENSOR.OUTPUT_NORM: ( - "gpt_neox.final_layer_norm", # gptneox - "transformer.ln_f", # gpt2 falcon - "model.norm", # llama-hf - "norm", # llama-pth - ), - # Rope frequencies - MODEL_TENSOR.ROPE_FREQS: ("rope.freqs",), # llama-pth - } - - block_mappings_cfg: dict[MODEL_TENSOR, tuple[str, ...]] = { - # Attention norm - MODEL_TENSOR.ATTN_NORM: ( - "gpt_neox.layers.{bid}.input_layernorm", # gptneox - "transformer.h.{bid}.ln_1", # gpt2 - "transformer.blocks.{bid}.norm_1", # mpt - "transformer.h.{bid}.input_layernorm", # falcon7b - "transformer.h.{bid}.ln_mlp", # falcon40b - "model.layers.{bid}.input_layernorm", # llama-hf - "layers.{bid}.attention_norm", # llama-pth - ), - # Attention norm 2 - MODEL_TENSOR.ATTN_NORM_2: ("transformer.h.{bid}.ln_attn",), # falcon40b - # Attention query-key-value - MODEL_TENSOR.ATTN_QKV: ( - "gpt_neox.layers.{bid}.attention.query_key_value", # gptneox - "transformer.h.{bid}.attn.c_attn", # gpt2 - "transformer.blocks.{bid}.attn.Wqkv", # mpt - "transformer.h.{bid}.self_attention.query_key_value", # falcon - ), - # Attention query - MODEL_TENSOR.ATTN_Q: ( - "model.layers.{bid}.self_attn.q_proj", # llama-hf - "layers.{bid}.attention.wq", # llama-pth - ), - # Attention key - MODEL_TENSOR.ATTN_K: ( - "model.layers.{bid}.self_attn.k_proj", # llama-hf - "layers.{bid}.attention.wk", # llama-pth - ), - # Attention value - MODEL_TENSOR.ATTN_V: ( - "model.layers.{bid}.self_attn.v_proj", # llama-hf - "layers.{bid}.attention.wv", # llama-pth - ), - # Attention output - MODEL_TENSOR.ATTN_OUT: ( - "gpt_neox.layers.{bid}.attention.dense", # gptneox - "transformer.h.{bid}.attn.c_proj", # gpt2 - "transformer.blocks.{bid}.attn.out_proj", # mpt - "transformer.h.{bid}.self_attention.dense", # falcon - "model.layers.{bid}.self_attn.o_proj", # llama-hf - "layers.{bid}.attention.wo", # llama-pth - ), - # Rotary embeddings - MODEL_TENSOR.ATTN_ROT_EMBD: ( - "model.layers.{bid}.self_attn.rotary_emb.inv_freq", # llama-hf - "layers.{bid}.attention.inner_attention.rope.freqs", # llama-pth - ), - # Feed-forward norm - MODEL_TENSOR.FFN_NORM: ( - "gpt_neox.layers.{bid}.post_attention_layernorm", # gptneox - "transformer.h.{bid}.ln_2", # gpt2 - "transformer.blocks.{bid}.norm_2", # mpt - "model.layers.{bid}.post_attention_layernorm", # llama-hf - "layers.{bid}.ffn_norm", # llama-pth - ), - # Feed-forward up - MODEL_TENSOR.FFN_UP: ( - "gpt_neox.layers.{bid}.mlp.dense_h_to_4h", # gptneox - "transformer.h.{bid}.mlp.c_fc", # gpt2 - "transformer.blocks.{bid}.ffn.up_proj", # mpt - "transformer.h.{bid}.mlp.dense_h_to_4h", # falcon - "model.layers.{bid}.mlp.up_proj", # llama-hf - "layers.{bid}.feed_forward.w3", # llama-pth - ), - # Feed-forward gate - MODEL_TENSOR.FFN_GATE: ( - "model.layers.{bid}.mlp.gate_proj", # llama-hf - "layers.{bid}.feed_forward.w1", # llama-pth - ), - # Feed-forward down - MODEL_TENSOR.FFN_DOWN: ( - "gpt_neox.layers.{bid}.mlp.dense_4h_to_h", # gptneox - "transformer.h.{bid}.mlp.c_proj", # gpt2 - "transformer.blocks.{bid}.ffn.down_proj", # mpt - "transformer.h.{bid}.mlp.dense_4h_to_h", # falcon - "model.layers.{bid}.mlp.down_proj", # llama-hf - "layers.{bid}.feed_forward.w2", # llama-pth - ), - } - - mapping: dict[str, tuple[MODEL_TENSOR, str]] - - tensor_names: dict[MODEL_TENSOR, str] - - def __init__(self, arch: MODEL_ARCH, n_blocks: int): - mapping = self.mapping = {} - tensor_names = self.tensor_names = MODEL_TENSOR_NAMES[arch] - for tensor, keys in self.mappings_cfg.items(): - tensor_name = tensor_names.get(tensor) - if tensor_name is None: - continue - for key in keys: - mapping[key] = (tensor, tensor_name) - for bid in range(n_blocks): - for tensor, keys in self.block_mappings_cfg.items(): - tensor_name = tensor_names.get(tensor) - if tensor_name is None: - continue - tensor_name = tensor_name.format(bid=bid) - for key in keys: - key = key.format(bid=bid) - mapping[key] = (tensor, tensor_name) - - def get_type_and_name( - self, key: str, try_suffixes: Sequence[str] - ) -> tuple[MODEL_TENSOR, str] | None: - result = self.mapping.get(key) - if result is not None: - return result - for suffix in try_suffixes: - if key.endswith(suffix): - result = self.mapping.get(key[: -len(suffix)]) - if result is not None: - return (result[0], result[1] + suffix) - return None - - def get_name(self, key: str, try_suffixes: Sequence[str]) -> str | None: - result = self.get_type_and_name(key, try_suffixes=try_suffixes) - if result is None: - return None - return result[1] - - def get_type(self, key: str, try_suffixes: Sequence[str]) -> MODEL_TENSOR | None: - result = self.get_type_and_name(key, try_suffixes=try_suffixes) - if result is None: - return None - return result[0] - - def __getitem__(self, key: str) -> str: - try: - return self.mapping[key][1] - except KeyError: - raise KeyError(key) - - def __contains__(self, key: str) -> bool: - return key in self.mapping - - def __repr__(self) -> str: - return repr(self.mapping) - - -def get_tensor_name_map(arch: MODEL_ARCH, n_blocks: int) -> TensorNameMap: - return TensorNameMap(arch, n_blocks) - - -class TokenType(IntEnum): - NORMAL = 1 - UNKNOWN = 2 - CONTROL = 3 - USER_DEFINED = 4 - UNUSED = 5 - BYTE = 6 - - -# -# implementation -# - - -class GGMLQuantizationType(IntEnum): - F32 = 0 - F16 = 1 - Q4_0 = 2 - Q4_1 = 3 - Q5_0 = 6 - Q5_1 = 7 - Q8_0 = 8 - Q8_1 = 9 - Q2_K = 10 - Q3_K = 11 - Q4_K = 12 - Q5_K = 13 - Q6_K = 14 - Q8_K = 15 - - -class GGUFValueType(IntEnum): - UINT8 = 0 - INT8 = 1 - UINT16 = 2 - INT16 = 3 - UINT32 = 4 - INT32 = 5 - FLOAT32 = 6 - BOOL = 7 - STRING = 8 - ARRAY = 9 - UINT64 = 10 - INT64 = 11 - FLOAT64 = 12 - - @staticmethod - def get_type(val): - if isinstance(val, str) or isinstance(val, bytes) or isinstance(val, bytearray): - return GGUFValueType.STRING - elif isinstance(val, list): - return GGUFValueType.ARRAY - elif isinstance(val, float): - return GGUFValueType.FLOAT32 - elif isinstance(val, bool): - return GGUFValueType.BOOL - elif isinstance(val, int): - return GGUFValueType.INT32 - # TODO: need help with 64-bit types in Python - else: - print("Unknown type: " + str(type(val))) - sys.exit() - - -class GGUFWriter: - fout: BufferedWriter - arch: str - offset_tensor = 0 - data_alignment = GGUF_DEFAULT_ALIGNMENT - kv_data = b"" - kv_data_count = 0 - ti_data = b"" - ti_data_count = 0 - use_temp_file: bool - temp_file: tempfile.SpooledTemporaryFile[bytes] | None = None - tensors: list[tuple[np.ndarray[Any, Any], int]] - - def __init__(self, path: os.PathLike[str] | str, arch: str, use_temp_file=True): - self.fout = open(path, "wb") - self.arch = arch - self.add_architecture() - self.use_temp_file = use_temp_file - self.tensors = [] - - def write_header_to_file(self): - self.fout.write(struct.pack(" 0 - ): - ltype = GGUFValueType.get_type(val[0]) - if not all(GGUFValueType.get_type(i) is ltype for i in val[1:]): - raise ValueError("All items in a GGUF array should be of the same type") - self.kv_data += struct.pack(" int: - return ((x + n - 1) // n) * n - - def add_tensor_info( - self, - name: str, - tensor_shape: Sequence[int], - tensor_dtype: np.dtype[np.float16] | np.dtype[np.float32], - tensor_nbytes: int, - raw_dtype: GGMLQuantizationType | None = None, - ): - assert raw_dtype is not None or tensor_dtype in ( - np.float32, - np.float16, - ), "Only F32 and F16 tensors are supported for now" - - encoded_name = name.encode("utf8") - self.ti_data += struct.pack(" bool: - tokenizer_file = path / "tokenizer.json" - if not tokenizer_file.is_file(): - return False - with open(tokenizer_file, "r", encoding="utf-8") as f: - tokenizer = json.load(f) - if self.load_merges: - merges = tokenizer.get("model", {}).get("merges") - if ( - isinstance(merges, list) - and len(merges) > 0 - and isinstance(merges[0], str) - ): - self.merges = merges - tokenizer_config_file = path / "tokenizer_config.json" - added_tokens = tokenizer.get("added_tokens") - if added_tokens is None or not tokenizer_config_file.is_file(): - return True - with open(tokenizer_config_file, "r", encoding="utf-8") as f: - tokenizer_config = json.load(f) - for typ in self.special_token_types: - entry = tokenizer_config.get(f"{typ}_token") - if isinstance(entry, str): - tc_content = entry - elif isinstance(entry, dict): - entry_content = entry.get("content") - if not isinstance(entry_content, str): - continue - tc_content = entry_content - else: - continue - for maybe_token_id in ( - atok.get("id") - for atok in added_tokens - if atok.get("content") == tc_content - ): - if isinstance(maybe_token_id, int) and maybe_token_id >= 0: - self.special_token_ids[typ] = maybe_token_id - break - return True - - def try_load_from_config_json(self, path: Path) -> bool: - config_file = path / "config.json" - if not config_file.is_file(): - return False - with open(config_file, "r", encoding="utf-8") as f: - config = json.load(f) - for typ in self.special_token_types: - maybe_token_id = config.get(f"{typ}_token_id") - if isinstance(maybe_token_id, int) and maybe_token_id >= 0: - self.special_token_ids[typ] = maybe_token_id - return True - - def add_to_gguf(self, gw: GGUFWriter): - if len(self.merges) > 0: - print(f"gguf: Adding {len(self.merges)} merge(s).") - gw.add_token_merges(self.merges) - for typ, tokid in self.special_token_ids.items(): - handler: Callable[[int], None] | None = getattr( - gw, f"add_{typ}_token_id", None - ) - if handler is None: - print( - f"gguf: WARNING: No handler for special token type {typ} with id {tokid} - skipping" - ) - continue - print(f"gguf: Setting special token type {typ} to {tokid}") - handler(tokid) - - def __repr__(self): - return f'' - - -# Example usage: -if __name__ == "__main__": - # Example usage with a file - gguf_writer = GGUFWriter("example.gguf", "llama") - - gguf_writer.add_architecture() - gguf_writer.add_block_count(12) - gguf_writer.add_uint32("answer", 42) # Write a 32-bit integer - gguf_writer.add_float32("answer_in_float", 42.0) # Write a 32-bit float - gguf_writer.add_custom_alignment(64) - - tensor1 = np.ones((32,), dtype=np.float32) * 100.0 - tensor2 = np.ones((64,), dtype=np.float32) * 101.0 - tensor3 = np.ones((96,), dtype=np.float32) * 102.0 - - gguf_writer.add_tensor("tensor1", tensor1) - gguf_writer.add_tensor("tensor2", tensor2) - gguf_writer.add_tensor("tensor3", tensor3) - - gguf_writer.write_header_to_file() - gguf_writer.write_kv_data_to_file() - gguf_writer.write_tensors_to_file() - - gguf_writer.close() diff --git a/xinference/client/oscar/__init__.py b/xinference/model/llm/llama_cpp/__init__.py similarity index 100% rename from xinference/client/oscar/__init__.py rename to xinference/model/llm/llama_cpp/__init__.py diff --git a/xinference/model/llm/ggml/llamacpp.py b/xinference/model/llm/llama_cpp/core.py similarity index 78% rename from xinference/model/llm/ggml/llamacpp.py rename to xinference/model/llm/llama_cpp/core.py index 3ef3d70806..b820fce466 100644 --- a/xinference/model/llm/ggml/llamacpp.py +++ b/xinference/model/llm/llama_cpp/core.py @@ -11,9 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import datetime import logging import os +import time from typing import Iterable, Iterator, List, Optional, Union from ....types import ( @@ -22,15 +22,14 @@ ChatCompletionMessage, Completion, CompletionChunk, + CompletionUsage, CreateCompletionLlamaCpp, - Embedding, LlamaCppGenerateConfig, LlamaCppModelConfig, ) from ..core import LLM from ..llm_family import LLMFamilyV1, LLMSpecV1 -from ..utils import ChatModelMixin -from .ctransformers import CTRANSFORMERS_SUPPORTED_MODEL +from ..utils import QWEN_TOOL_CALL_FAMILY, ChatModelMixin logger = logging.getLogger(__name__) @@ -64,7 +63,6 @@ def _sanitize_model_config( if self.model_family.context_length: llamacpp_model_config.setdefault("n_ctx", self.model_family.context_length) - llamacpp_model_config.setdefault("embedding", True) llamacpp_model_config.setdefault("use_mmap", False) llamacpp_model_config.setdefault("use_mlock", True) @@ -101,37 +99,10 @@ def _sanitize_generate_config( generate_config = LlamaCppGenerateConfig( **CreateCompletionLlamaCpp(**generate_config).dict() ) + # Currently, llama.cpp does not support lora + generate_config.pop("lora_name", None) # type: ignore return generate_config - def _convert_ggml_to_gguf(self, model_path: str) -> str: - from .tools import convert - - root_dir = os.path.dirname(os.path.dirname(model_path)) - gguf_dir = os.path.join( - root_dir, - "{}-ggufv2-{}b".format( - self.model_family.model_name, self.model_spec.model_size_in_billions - ), - ) - os.makedirs(gguf_dir, exist_ok=True) - gguf_path = os.path.join( - gguf_dir, - "{}.{}.ggufv2".format(self.model_family.model_name, self.quantization), - ) - # trick for validation, use a mark file to make sure the gguf file is converted - mark_file = os.path.join(gguf_dir, f"__valid_{self.quantization}") - if os.path.exists(mark_file): - return gguf_path - else: - logger.warning( - "You are using a model with ggmlv3, " - "and it will take some time to convert to ggufv2" - ) - convert(model_path, gguf_path) - with open(mark_file, "w") as f: - f.write(str(datetime.datetime.now())) - return gguf_path - def load(self): try: import llama_cpp @@ -154,19 +125,18 @@ def load(self): raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") # handle legacy cache. - model_path = os.path.join( - self.model_path, - self.model_spec.model_file_name_template.format( - quantization=self.quantization - ), + model_path = os.path.realpath( + os.path.join( + self.model_path, + self.model_spec.model_file_name_template.format( + quantization=self.quantization + ), + ) ) legacy_model_file_path = os.path.join(self.model_path, "model.bin") if os.path.exists(legacy_model_file_path): model_path = legacy_model_file_path - if self.model_spec.model_format == "ggmlv3": - model_path = self._convert_ggml_to_gguf(model_path) - try: self._llm = Llama( model_path=model_path, @@ -180,13 +150,9 @@ def load(self): def match( cls, llm_family: LLMFamilyV1, llm_spec: LLMSpecV1, quantization: str ) -> bool: - if llm_spec.model_format not in ["ggmlv3", "ggufv2"]: + if llm_spec.model_format not in ["ggufv2"]: return False - if ( - "chatglm" in llm_family.model_name - or "qwen" in llm_family.model_name - or llm_family.model_name in CTRANSFORMERS_SUPPORTED_MODEL - ): + if "qwen" in llm_family.model_name: return False if "generate" not in llm_family.model_ability: return False @@ -200,16 +166,59 @@ def generator_wrapper( _generate_config: LlamaCppGenerateConfig, ) -> Iterator[CompletionChunk]: assert self._llm is not None - for _completion_chunk in self._llm(prompt=_prompt, **_generate_config): + prompt_token_ids: List[int] = ( + ( + self._llm.tokenize(prompt.encode("utf-8"), special=True) + if prompt != "" + else [self._llm.token_bos()] + ) + if isinstance(prompt, str) + else prompt + ) + prompt_tokens = len(prompt_token_ids) + completion_tokens, total_tokens = 0, 0 + request_id = 0 + for index, _completion_chunk in enumerate( + self._llm(prompt=_prompt, **_generate_config) + ): + request_id = _completion_chunk["id"] + choice = _completion_chunk["choices"][0] + if choice["finish_reason"] is not None: + completion_tokens = index + total_tokens = prompt_tokens + completion_tokens + _completion_chunk["usage"] = CompletionUsage( + prompt_tokens=total_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) yield _completion_chunk + if include_usage: + chunk = CompletionChunk( + id=request_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk logger.debug( "Enter generate, prompt: %s, generate config: %s", prompt, generate_config ) generate_config = self._sanitize_generate_config(generate_config) - stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) if not stream: assert self._llm is not None @@ -219,11 +228,6 @@ def generator_wrapper( else: return generator_wrapper(prompt, generate_config) - def create_embedding(self, input: Union[str, List[str]]) -> Embedding: - assert self._llm is not None - embedding = self._llm.create_embedding(input) - return embedding - class LlamaCppChatModel(LlamaCppModel, ChatModelMixin): def __init__( @@ -248,12 +252,7 @@ def __init__( def match( cls, llm_family: LLMFamilyV1, llm_spec: LLMSpecV1, quantization: str ) -> bool: - if llm_spec.model_format not in ["ggmlv3", "ggufv2"]: - return False - if ( - "chatglm" in llm_family.model_name - or llm_family.model_name in CTRANSFORMERS_SUPPORTED_MODEL - ): + if llm_spec.model_format not in ["ggufv2"]: return False if "chat" not in llm_family.model_ability: return False @@ -287,7 +286,7 @@ def chat( generate_config = self._sanitize_generate_config(generate_config) # TODO(codingl2k1): qwen hacky to set stop for function call. model_family = self.model_family.model_family or self.model_family.model_name - if tools and model_family in ["qwen-chat", "qwen1.5-chat"]: + if tools and model_family in QWEN_TOOL_CALL_FAMILY: stop = generate_config.get("stop") if isinstance(stop, str): generate_config["stop"] = [stop, "Observation:"] diff --git a/xinference/locale/__init__.py b/xinference/model/llm/llama_cpp/tests/__init__.py similarity index 100% rename from xinference/locale/__init__.py rename to xinference/model/llm/llama_cpp/tests/__init__.py diff --git a/xinference/model/llm/ggml/tests/test_gguf.py b/xinference/model/llm/llama_cpp/tests/test_gguf.py similarity index 55% rename from xinference/model/llm/ggml/tests/test_gguf.py rename to xinference/model/llm/llama_cpp/tests/test_gguf.py index 04f1de6ffe..cb7c7f0a8a 100644 --- a/xinference/model/llm/ggml/tests/test_gguf.py +++ b/xinference/model/llm/llama_cpp/tests/test_gguf.py @@ -15,45 +15,13 @@ from .....client import Client -def test_load_ggmlv3(setup): - endpoint, _ = setup - client = Client(endpoint) - - model_uid = client.launch_model( - model_name="orca", - model_size_in_billions=3, - model_format="ggmlv3", - quantization="q4_0", - ) - assert len(client.list_models()) == 1 - model = client.get_model(model_uid) - completion = model.chat("write a poem.") - assert "content" in completion["choices"][0]["message"] - assert len(completion["choices"][0]["message"]["content"]) != 0 - - # test grammar - grammar = r""" - root ::= answer - answer ::= ("Apple" | "Banana" | "Orange") - """ - completion = model.chat( - "Tell me a random fruit name.", - generate_config={"max_tokens": 10, "grammar": grammar}, - ) - assert "content" in completion["choices"][0]["message"] - assert completion["choices"][0]["message"]["content"] in [ - "Apple", - "Banana", - "Orange", - ] - - def test_gguf(setup): endpoint, _ = setup client = Client(endpoint) model_uid = client.launch_model( model_name="tiny-llama", + model_engine="llama.cpp", model_size_in_billions=1, model_format="ggufv2", quantization="q2_K", diff --git a/xinference/model/llm/llm_family.json b/xinference/model/llm/llm_family.json index 0cb2023612..26f1d599a8 100644 --- a/xinference/model/llm/llm_family.json +++ b/xinference/model/llm/llm_family.json @@ -1,8 +1,8 @@ [ { "version": 1, - "context_length": 4096, - "model_name": "baichuan", + "context_length": 8194, + "model_name": "codeshell", "model_lang": [ "en", "zh" @@ -10,58 +10,23 @@ "model_ability": [ "generate" ], - "model_description": "Baichuan is an open-source Transformer based LLM that is trained on both Chinese and English data.", + "model_description": "CodeShell is a multi-language code LLM developed by the Knowledge Computing Lab of Peking University. ", "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 7, - "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" - ], - "model_id": "TheBloke/baichuan-llama-7B-GGML", - "model_file_name_template": "baichuan-llama-7b.ggmlv3.{quantization}.bin" - }, { "model_format": "pytorch", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "baichuan-inc/Baichuan-7B", - "model_revision": "c1a5c7d5b7f50ecc51bb0e08150a9f12e5656756" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 13, - "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan-13B-Base", - "model_revision": "0ef0739c7bdd34df954003ef76d80f3dabca2ff9" + "model_id": "WisdomShell/CodeShell-7B", + "model_revision": "1c79ab7fd316a62ab41d764facd3548a23fa5dee" } ] }, { "version": 1, - "context_length": 4096, - "model_name": "baichuan-chat", + "context_length": 8194, + "model_name": "codeshell-chat", "model_lang": [ "en", "zh" @@ -69,562 +34,433 @@ "model_ability": [ "chat" ], - "model_description": "Baichuan-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting.", + "model_description": "CodeShell is a multi-language code LLM developed by the Knowledge Computing Lab of Peking University.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan-13B-Chat", - "model_revision": "19ef51ba5bad8935b03acd20ff04a269210983bc" + "model_id": "WisdomShell/CodeShell-7B-Chat", + "model_revision": "3cb06f589b7b1e2f8e728c77280b1114191d24de" } ], "prompt_style": { - "style_name": "NO_COLON_TWO", + "style_name": "CodeShell", "system_prompt": "", "roles": [ - " ", - " " + "## human:", + "## assistant: " ], "intra_message_sep": "", - "inter_message_sep": "", + "inter_message_sep": "", "stop_token_ids": [ - 2, - 195 + 70000 + ], + "stop": [ + "<|endoftext|>", + "|||", + "||" ] } }, { "version": 1, - "context_length": 8194, - "model_name": "codeshell", + "context_length": 2048, + "model_name": "phi-2", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "generate" ], - "model_description": "CodeShell is a multi-language code LLM developed by the Knowledge Computing Lab of Peking University. ", + "model_description": "Phi-2 is a 2.7B Transformer based LLM used for research on model safety, trained with data similar to Phi-1.5 but augmented with synthetic texts and curated websites.", "model_specs": [ + { + "model_format": "ggufv2", + "model_size_in_billions": 2, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/phi-2-GGUF", + "model_file_name_template": "phi-2.{quantization}.gguf" + }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 2, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "WisdomShell/CodeShell-7B", - "model_revision": "1c79ab7fd316a62ab41d764facd3548a23fa5dee" + "model_id": "microsoft/phi-2", + "model_revision": "d3186761bf5c4409f7679359284066c25ab668ee" } ] }, { "version": 1, - "context_length": 8194, - "model_name": "codeshell-chat", + "context_length": 128000, + "model_name": "phi-3-mini-128k-instruct", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "CodeShell is a multi-language code LLM developed by the Knowledge Computing Lab of Peking University.", + "model_description": "The Phi-3-Mini-128K-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 4, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "WisdomShell/CodeShell-7B-Chat", - "model_revision": "3cb06f589b7b1e2f8e728c77280b1114191d24de" + "model_id": "microsoft/Phi-3-mini-128k-instruct", + "model_revision": "ebee18c488086b396dde649f2aa6548b9b8d2404" } ], "prompt_style": { - "style_name": "CodeShell", - "system_prompt": "", + "style_name": "PHI3", + "system_prompt": "You are a helpful AI assistant.", "roles": [ - "## human:", - "## assistant: " + "user", + "assistant" ], - "intra_message_sep": "", - "inter_message_sep": "", - "stop_token_ids": [ - 70000 + "intra_message_sep": "\n", + "inter_message_sep": "<|end|>\n", + "stop_token_ids":[ + 32000, + 32001, + 32007 ], "stop": [ "<|endoftext|>", - "|||", - "||" + "<|assistant|>", + "<|end|>" ] } }, { "version": 1, - "context_length": 2048, - "model_name": "wizardlm-v1.0", + "context_length": 4096, + "model_name": "phi-3-mini-4k-instruct", "model_lang": [ "en" ], "model_ability": [ "chat" ], - "model_description": "WizardLM is an open-source LLM trained by fine-tuning LLaMA with Evol-Instruct.", + "model_description": "The Phi-3-Mini-4k-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets.", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 7, + "model_format": "ggufv2", + "model_size_in_billions": 4, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "fp16", + "q4" ], - "model_id": "TheBloke/WizardLM-7B-V1.0-Uncensored-GGML", - "model_file_name_template": "wizardlm-7b-v1.0-uncensored.ggmlv3.{quantization}.bin" + "model_id": "microsoft/Phi-3-mini-4k-instruct-gguf", + "model_file_name_template": "Phi-3-mini-4k-instruct-{quantization}.gguf" }, { - "model_format": "ggmlv3", - "model_size_in_billions": 13, + "model_format": "pytorch", + "model_size_in_billions": 4, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "4-bit", + "8-bit", + "none" ], - "model_id": "TheBloke/WizardLM-13B-V1.0-Uncensored-GGML", - "model_file_name_template": "wizardlm-13b-v1.0-uncensored.ggmlv3.{quantization}.bin" + "model_id": "microsoft/Phi-3-mini-4k-instruct", + "model_revision": "b86bcaf57ea4dfdec5dbe12a377028b2fab0d480" } ], "prompt_style": { - "style_name": "ADD_COLON_SINGLE", + "style_name": "PHI3", "system_prompt": "You are a helpful AI assistant.", "roles": [ - "USER", - "ASSISTANT" + "user", + "assistant" + ], + "intra_message_sep": "\n", + "inter_message_sep": "<|end|>\n", + "stop_token_ids":[ + 32000, + 32001, + 32007 ], - "intra_message_sep": "\n" + "stop": [ + "<|endoftext|>", + "<|assistant|>", + "<|end|>" + ] } }, { "version": 1, - "context_length": 2048, - "model_name": "vicuna-v1.3", + "context_length": 8192, + "model_name": "chatglm3", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "tools" ], - "model_description": "Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT.", + "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 7, - "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" - ], - "model_id": "TheBloke/vicuna-7B-v1.3-GGML", - "model_file_name_template": "vicuna-7b-v1.3.ggmlv3.{quantization}.bin" - }, - { - "model_format": "ggmlv3", - "model_size_in_billions": 13, - "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" - ], - "model_id": "TheBloke/vicuna-13b-v1.3.0-GGML", - "model_file_name_template": "vicuna-13b-v1.3.0.ggmlv3.{quantization}.bin" - }, - { - "model_format": "ggmlv3", - "model_size_in_billions": 33, - "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" - ], - "model_id": "TheBloke/vicuna-33B-GGML", - "model_file_name_template": "vicuna-33b.ggmlv3.{quantization}.bin" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 33, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "lmsys/vicuna-33b-v1.3", - "model_revision": "ef8d6becf883fb3ce52e3706885f761819477ab4" - }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 6, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "lmsys/vicuna-13b-v1.3", - "model_revision": "6566e9cb1787585d1147dcf4f9bc48f29e1328d2" - }, + "model_id": "THUDM/chatglm3-6b", + "model_revision": "103caa40027ebfd8450289ca2f278eac4ff26405" + } + ], + "prompt_style": { + "style_name": "CHATGLM3", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 64795, + 64797, + 2 + ], + "stop": [ + "<|user|>", + "<|observation|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "chatglm3-32k", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", + "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 6, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "lmsys/vicuna-7b-v1.3", - "model_revision": "236eeeab96f0dc2e463f2bebb7bb49809279c6d6" + "model_id": "THUDM/chatglm3-6b-32k", + "model_revision": "339f17ff464d47b5077527c2b34e80a7719ede3e" } ], "prompt_style": { - "style_name": "ADD_COLON_TWO", - "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.", + "style_name": "CHATGLM3", + "system_prompt": "", "roles": [ - "USER", - "ASSISTANT" + "user", + "assistant" ], - "intra_message_sep": " ", - "inter_message_sep": "" + "stop_token_ids": [ + 64795, + 64797, + 2 + ], + "stop": [ + "<|user|>", + "<|observation|>" + ] } }, { "version": 1, - "context_length": 2048, - "model_name": "orca", + "context_length": 131072, + "model_name": "chatglm3-128k", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "Orca is an LLM trained by fine-tuning LLaMA on explanation traces obtained from GPT-4.", + "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 3, + "model_format": "pytorch", + "model_size_in_billions": 6, "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" + "4-bit", + "8-bit", + "none" ], - "model_id": "TheBloke/orca_mini_3B-GGML", - "model_file_name_template": "orca-mini-3b.ggmlv3.{quantization}.bin" - }, - { - "model_format": "ggmlv3", - "model_size_in_billions": 7, - "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" - ], - "model_id": "TheBloke/orca_mini_7B-GGML", - "model_file_name_template": "orca-mini-7b.ggmlv3.{quantization}.bin" - }, - { - "model_format": "ggmlv3", - "model_size_in_billions": 13, - "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" - ], - "model_id": "TheBloke/orca_mini_13B-GGML", - "model_file_name_template": "orca-mini-13b.ggmlv3.{quantization}.bin" + "model_id": "THUDM/chatglm3-6b-128k", + "model_revision": "f0afbe671009abc9e31182170cf60636d5546cda" } ], "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "system_prompt": "You are an AI assistant that follows instruction extremely well. Help as much as you can.", + "style_name": "CHATGLM3", + "system_prompt": "", "roles": [ - "User", - "Response" + "user", + "assistant" ], - "intra_message_sep": "\n\n### " + "stop_token_ids": [ + 64795, + 64797, + 2 + ], + "stop": [ + "<|user|>", + "<|observation|>" + ] } }, { "version": 1, - "context_length": 2048, - "model_name": "phi-2", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Phi-2 is a 2.7B Transformer based LLM used for research on model safety, trained with data similar to Phi-1.5 but augmented with synthetic texts and curated websites.", - "model_specs": [ - { - "model_format": "ggufv2", - "model_size_in_billions": 2, - "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/phi-2-GGUF", - "model_file_name_template": "phi-2.{quantization}.gguf" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 2, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "microsoft/phi-2", - "model_revision": "d3186761bf5c4409f7679359284066c25ab668ee" - } - ] - }, - { - "version": 1, - "context_length": 2048, - "model_name": "chatglm", + "context_length": 131072, + "model_name": "glm4-chat", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "chat", + "tools" ], - "model_description": "ChatGLM is an open-source General Language Model (GLM) based LLM trained on both Chinese and English data.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 6, - "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" - ], - "model_id": "Xorbits/chatglm-6B-GGML", - "model_file_name_template": "chatglm-ggml-{quantization}.bin" - }, { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "THUDM/chatglm-6b", - "model_revision": "8b7d33596d18c5e83e2da052d05ca4db02e60620" - } - ], - "prompt_style": { - "style_name": "CHATGLM", - "system_prompt": "", - "roles": [ - "问", - "答" - ], - "intra_message_sep": "\n" - } - }, - { - "version": 1, - "context_length": 8192, - "model_name": "chatglm2", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat" - ], - "model_description": "ChatGLM2 is the second generation of ChatGLM, still open-source and trained on Chinese and English data.", - "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 6, - "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" - ], - "model_id": "Xorbits/chatglm2-6B-GGML", - "model_file_name_template": "chatglm2-ggml-{quantization}.bin" + "model_id": "THUDM/glm-4-9b-chat", + "model_revision": "aae8bd74af5c6dff63a49d7fbdcc89349ebf87aa" }, { - "model_format": "pytorch", - "model_size_in_billions": 6, + "model_format": "ggufv2", + "model_size_in_billions": 9, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "IQ3_XS", + "IQ3_S", + "IQ3_M", + "Q3_K_S", + "Q3_K_L", + "Q3_K", + "IQ4_XS", + "IQ4_NL", + "Q4_K_S", + "Q4_K", + "Q5_K_S", + "Q5_K", + "Q6_K", + "Q8_0", + "BF16", + "FP16" ], - "model_id": "THUDM/chatglm2-6b", - "model_revision": "7fabe56db91e085c9c027f56f1c654d137bdba40" + "model_file_name_template": "glm-4-9b-chat.{quantization}.gguf", + "model_id": "legraphista/glm-4-9b-chat-GGUF", + "model_revision": "0155a14edf0176863e9a003cdd78ce599e4d62c0" } ], "prompt_style": { - "style_name": "CHATGLM", + "style_name": "CHATGLM3", "system_prompt": "", "roles": [ - "问", - "答" + "user", + "assistant" + ], + "stop_token_ids": [ + 151329, + 151336, + 151338 ], - "intra_message_sep": "\n\n" + "stop": [ + "<|endoftext|>", + "<|user|>", + "<|observation|>" + ] } }, { "version": 1, - "context_length": 32768, - "model_name": "chatglm2-32k", + "context_length": 1048576, + "model_name": "glm4-chat-1m", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "chat", + "tools" ], - "model_description": "ChatGLM2-32k is a special version of ChatGLM2, with a context window of 32k tokens instead of 8k.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "THUDM/chatglm2-6b-32k", - "model_revision": "a2065f5dc8253f036a209e642d7220a942d92765" - } - ], - "prompt_style": { - "style_name": "CHATGLM", - "system_prompt": "", - "roles": [ - "问", - "答" - ], - "intra_message_sep": "\n\n" - } - }, - { - "version": 1, - "context_length": 8192, - "model_name": "chatglm3", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat", - "tools" - ], - "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", - "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 6, - "quantizations": [ - "q4_0" - ], - "model_id": "Xorbits/chatglm3-6B-GGML", - "model_file_name_template": "chatglm3-ggml-{quantization}.bin" + "model_id": "THUDM/glm-4-9b-chat-1m", + "model_revision": "0aa722c7e0745dd21453427dd44c257dd253304f" }, { - "model_format": "pytorch", - "model_size_in_billions": 6, + "model_format": "ggufv2", + "model_size_in_billions": 9, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "IQ3_XS", + "IQ3_S", + "IQ3_M", + "Q3_K_S", + "Q3_K_L", + "Q3_K", + "IQ4_XS", + "IQ4_NL", + "Q4_K_S", + "Q4_K", + "Q5_K_S", + "Q5_K", + "Q6_K", + "Q8_0", + "BF16", + "FP16" ], - "model_id": "THUDM/chatglm3-6b", - "model_revision": "b098244a71fbe69ce149682d9072a7629f7e908c" + "model_file_name_template": "glm-4-9b-chat-1m.{quantization}.gguf", + "model_id": "legraphista/glm-4-9b-chat-1m-GGUF", + "model_revision": "782e28bd5eee3c514c07108da15e0b5e06dcf776" } ], "prompt_style": { @@ -635,11 +471,12 @@ "assistant" ], "stop_token_ids": [ - 64795, - 64797, - 2 + 151329, + 151336, + 151338 ], "stop": [ + "<|endoftext|>", "<|user|>", "<|observation|>" ] @@ -647,27 +484,28 @@ }, { "version": 1, - "context_length": 32768, - "model_name": "chatglm3-32k", + "context_length": 8192, + "model_name": "glm-4v", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "THUDM/chatglm3-6b-32k", - "model_revision": "339f17ff464d47b5077527c2b34e80a7719ede3e" + "model_id": "THUDM/glm-4v-9b", + "model_revision": "6c2e4732db8443f64a48d5af04b74425a7d169c4" } ], "prompt_style": { @@ -678,11 +516,12 @@ "assistant" ], "stop_token_ids": [ - 64795, - 64797, - 2 + 151329, + 151336, + 151338 ], "stop": [ + "<|endoftext|>", "<|user|>", "<|observation|>" ] @@ -691,7 +530,7 @@ { "version": 1, "context_length": 131072, - "model_name": "chatglm3-128k", + "model_name": "codegeex4", "model_lang": [ "en", "zh" @@ -699,18 +538,33 @@ "model_ability": [ "chat" ], - "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", + "model_description": "the open-source version of the latest CodeGeeX4 model series", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "THUDM/chatglm3-6b-128k", - "model_revision": "f0afbe671009abc9e31182170cf60636d5546cda" + "model_id": "THUDM/codegeex4-all-9b", + "model_revision": "8c4ec1d2f2888412640825a7aa23355939a8f4c6" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 9, + "quantizations": [ + "IQ2_M", + "IQ3_M", + "Q4_K_M", + "Q5_K_M", + "Q6_K_L", + "Q8_0" + ], + "model_file_name_template": "codegeex4-all-9b-{quantization}.gguf", + "model_id": "THUDM/codegeex4-all-9b-GGUF", + "model_revision": "6a04071c54c943949826d4815ee00717ed8cf153" } ], "prompt_style": { @@ -721,11 +575,12 @@ "assistant" ], "stop_token_ids": [ - 64795, - 64797, - 2 + 151329, + 151336, + 151338 ], "stop": [ + "<|endoftext|>", "<|user|>", "<|observation|>" ] @@ -837,70 +692,73 @@ "model_description": "Llama-2-Chat is a fine-tuned version of the Llama-2 LLM, specializing in chatting.", "model_specs": [ { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 7, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "TheBloke/Llama-2-7B-Chat-GGML", - "model_file_name_template": "llama-2-7b-chat.ggmlv3.{quantization}.bin" + "model_id": "TheBloke/Llama-2-7B-Chat-GGUF", + "model_file_name_template": "llama-2-7b-chat.{quantization}.gguf" }, { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 13, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" - ], - "model_id": "TheBloke/Llama-2-13B-chat-GGML", - "model_file_name_template": "llama-2-13b-chat.ggmlv3.{quantization}.bin" - }, - { - "model_format": "ggmlv3", - "model_size_in_billions": 70, - "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Llama-2-13B-chat-GGUF", + "model_file_name_template": "llama-2-13b-chat.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 70, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M" ], - "model_id": "TheBloke/Llama-2-70B-Chat-GGML", - "model_file_name_template": "llama-2-70b-chat.ggmlv3.{quantization}.bin" + "quantization_parts": { + "Q6_K": [ + "split-a", + "split-b" + ], + "Q8_0": [ + "split-a", + "split-b" + ] + }, + "model_id": "TheBloke/Llama-2-70B-Chat-GGUF", + "model_file_name_template": "llama-2-70b-chat.{quantization}.gguf", + "model_file_name_split_template": "llama-2-70b-chat.{quantization}.gguf-{part}" }, { "model_format": "pytorch", @@ -982,64 +840,6 @@ ], "model_id": "meta-llama/Llama-2-70b-chat-hf", "model_revision": "36d9a7388cc80e5f4b3e9701ca2f250d21a96c30" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 7, - "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/Llama-2-7B-Chat-GGUF", - "model_file_name_template": "llama-2-7b-chat.{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 13, - "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/Llama-2-13B-chat-GGUF", - "model_file_name_template": "llama-2-13b-chat.{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 70, - "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_K_S", - "Q5_K_M" - ], - "model_id": "TheBloke/Llama-2-70B-Chat-GGUF", - "model_file_name_template": "llama-2-70b-chat.{quantization}.gguf" } ], "prompt_style": { @@ -1072,26 +872,24 @@ "model_description": "Llama-2 is the second generation of Llama, open-source and trained on a larger amount of data.", "model_specs": [ { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 7, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "TheBloke/Llama-2-7B-GGML", - "model_file_name_template": "llama-2-7b.ggmlv3.{quantization}.bin" + "model_id": "TheBloke/Llama-2-7B-GGUF", + "model_file_name_template": "llama-2-7b.{quantization}.gguf" }, { "model_format": "gptq", @@ -1110,48 +908,53 @@ "model_id": "TheBloke/Llama-2-7B-AWQ" }, { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 13, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "TheBloke/Llama-2-13B-GGML", - "model_file_name_template": "llama-2-13b.ggmlv3.{quantization}.bin" + "model_id": "TheBloke/Llama-2-13B-GGUF", + "model_file_name_template": "llama-2-13b.{quantization}.gguf" }, { - "model_format": "ggmlv3", + "model_format": "ggufv2", "model_size_in_billions": 70, "quantizations": [ - "q2_K", - "q3_K_L", - "q3_K_M", - "q3_K_S", - "q4_0", - "q4_1", - "q4_K_M", - "q4_K_S", - "q5_0", - "q5_1", - "q5_K_M", - "q5_K_S", - "q6_K", - "q8_0" + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M" ], - "model_id": "TheBloke/Llama-2-70B-GGML", - "model_file_name_template": "llama-2-70b.ggmlv3.{quantization}.bin" + "quantization_parts": { + "Q6_K": [ + "split-a", + "split-b" + ], + "Q8_0": [ + "split-a", + "split-b" + ] + }, + "model_id": "TheBloke/Llama-2-70B-GGUF", + "model_file_name_template": "llama-2-70b.{quantization}.gguf", + "model_file_name_split_template": "llama-2-70b.{quantization}.gguf-{part}" }, { "model_format": "pytorch", @@ -1222,751 +1025,573 @@ }, { "version": 1, - "context_length": 2048, - "model_name": "opt", + "context_length": 8192, + "model_name": "llama-3", "model_lang": [ "en" ], "model_ability": [ "generate" ], - "model_description": "Opt is an open-source, decoder-only, Transformer based LLM that was designed to replicate GPT-3.", + "model_description": "Llama 3 is an auto-regressive language model that uses an optimized transformer architecture", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 1, + "model_size_in_billions": 8, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "facebook/opt-125m", - "model_revision": "3d2b5f275bdf882b8775f902e1bfdb790e2cfc32" - } - ] - }, - { - "version": 1, - "context_length": 2048, - "model_name": "falcon", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Falcon is an open-source Transformer based LLM trained on the RefinedWeb dataset.", - "model_specs": [ + "model_id": "meta-llama/Meta-Llama-3-8B" + }, { - "model_format": "pytorch", - "model_size_in_billions": 40, + "model_format": "ggufv2", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_1", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_1", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" ], - "model_id": "tiiuae/falcon-40b", - "model_revision": "561820f7eef0cc56a31ea38af15ca1acb07fab5d" + "model_id": "QuantFactory/Meta-Llama-3-8B-GGUF", + "model_file_name_template": "Meta-Llama-3-8B.{quantization}.gguf" }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "tiiuae/falcon-7b", - "model_revision": "378337427557d1df3e742264a2901a49f25d4eb1" + "model_id": "meta-llama/Meta-Llama-3-70B" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 70, + "quantizations": [ + "Q4_K_M", + "Q5_K_M" + ], + "model_id": "NousResearch/Meta-Llama-3-70B-GGUF", + "model_file_name_template": "Meta-Llama-3-70B-{quantization}.gguf" } ] }, { "version": 1, - "context_length": 2048, - "model_name": "falcon-instruct", + "context_length": 8192, + "model_name": "llama-3-instruct", "model_lang": [ "en" ], "model_ability": [ "chat" ], - "model_description": "Falcon-instruct is a fine-tuned version of the Falcon LLM, specializing in chatting.", + "model_description": "The Llama 3 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks..", "model_specs": [ { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "ggufv2", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "IQ3_M", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "tiiuae/falcon-7b-instruct", - "model_revision": "eb410fb6ffa9028e97adb801f0d6ec46d02f8b07" + "model_id": "lmstudio-community/Meta-Llama-3-8B-Instruct-GGUF", + "model_file_name_template": "Meta-Llama-3-8B-Instruct-{quantization}.gguf" }, { "model_format": "pytorch", - "model_size_in_billions": 40, + "model_size_in_billions": 8, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "tiiuae/falcon-40b-instruct", - "model_revision": "ca78eac0ed45bf64445ff0687fabba1598daebf3" - } - ], - "prompt_style": { - "style_name": "FALCON", - "system_prompt": "", - "roles": [ - "User", - "Assistant" - ], - "intra_message_sep": "\n", - "inter_message_sep": "<|endoftext|>", - "stop": [ - "\nUser" - ], - "stop_token_ids": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11 - ] - } - }, - { - "version": 1, - "context_length": 8192, - "model_name": "starcoderplus", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Starcoderplus is an open-source LLM trained by fine-tuning Starcoder on RedefinedWeb and StarCoderData datasets.", - "model_specs": [ + "model_id": "meta-llama/Meta-Llama-3-8B-Instruct" + }, { - "model_format": "pytorch", - "model_size_in_billions": 16, + "model_format": "ggufv2", + "model_size_in_billions": 70, "quantizations": [ - "4-bit", - "8-bit", - "none" + "IQ1_M", + "IQ2_XS", + "Q4_K_M" ], - "model_id": "bigcode/starcoderplus", - "model_revision": "95be82087c33f14ee9941c812a154a9dd66efe72" - } - ], - "prompt_style": null - }, - { - "version": 1, - "context_length": 8192, - "model_name": "starchat-beta", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "Starchat-beta is a fine-tuned version of the Starcoderplus LLM, specializing in coding assistance.", - "model_specs": [ + "model_id": "lmstudio-community/Meta-Llama-3-70B-Instruct-GGUF", + "model_file_name_template": "Meta-Llama-3-70B-Instruct-{quantization}.gguf" + }, { "model_format": "pytorch", - "model_size_in_billions": 16, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "HuggingFaceH4/starchat-beta", - "model_revision": "b1bcda690655777373f57ea6614eb095ec2c886f" - } - ], - "prompt_style": { - "style_name": "CHATML", - "system_prompt": "{system_message}\n", - "roles": [ - "<|user|>", - "<|assistant|>" - ], - "intra_message_sep": "<|end|>", - "stop_token_ids": [ - 0, - 49155 - ] - } - }, - { - "version": 1, - "context_length": 32768, - "model_name": "qwen-chat", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat", - "tools" - ], - "model_description": "Qwen-chat is a fine-tuned version of the Qwen LLM trained with alignment techniques, specializing in chatting.", - "model_specs": [ - { - "model_format": "ggufv2", - "model_size_in_billions": 7, - "quantizations": [ - "Q4_K_M" - ], - "model_id": "Xorbits/Qwen-7B-Chat-GGUF", - "model_file_name_template": "Qwen-7B-Chat.{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 14, - "quantizations": [ - "Q4_K_M" - ], - "model_id": "Xorbits/Qwen-14B-Chat-GGUF", - "model_file_name_template": "Qwen-14B-Chat.{quantization}.gguf" + "model_id": "meta-llama/Meta-Llama-3-70B-Instruct" }, { - "model_format": "pytorch", - "model_size_in_billions": "1_8", + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "4-bit" ], - "model_id": "Qwen/Qwen-1_8B-Chat", - "model_revision": "c3db8007171847931da7efa4b2ed4309afcce021" + "model_id": "mlx-community/Meta-Llama-3-8B-Instruct-4bit" }, { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "Qwen/Qwen-7B-Chat", - "model_revision": "218aa3240fd5a5d1e80bb6c47d5d774361913706" + "model_id": "mlx-community/Meta-Llama-3-8B-Instruct-8bit" }, { - "model_format": "pytorch", - "model_size_in_billions": 14, + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "Qwen/Qwen-14B-Chat", - "model_revision": "fab8385c8f7e7980ef61944729fe134ccbbca263" + "model_id": "mlx-community/Meta-Llama-3-8B-Instruct" }, { - "model_format": "pytorch", - "model_size_in_billions": 72, + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "4-bit", - "8-bit", - "none" + "4-bit" ], - "model_id": "Qwen/Qwen-72B-Chat", - "model_revision": "2cd9f76279337941ec1a4abeec6f8eb3c38d0f55" + "model_id": "mlx-community/Meta-Llama-3-70B-Instruct-4bit-mlx" }, { - "model_format": "gptq", - "model_size_in_billions": 7, + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "8-bit" ], - "model_id": "Qwen/Qwen-7B-Chat-{quantization}" + "model_id": "mlx-community/Meta-Llama-3-70B-Instruct-8bit" }, { - "model_format": "gptq", - "model_size_in_billions": "1_8", + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "none" ], - "model_id": "Qwen/Qwen-1_8B-Chat-{quantization}" + "model_id": "mlx-community/Meta-Llama-3-70B-Instruct-mlx-unquantized" }, { "model_format": "gptq", - "model_size_in_billions": 14, + "model_size_in_billions": 8, "quantizations": [ - "Int4", - "Int8" + "Int4" ], - "model_id": "Qwen/Qwen-14B-Chat-{quantization}" + "model_id": "TechxGenus/Meta-Llama-3-8B-Instruct-GPTQ" }, { "model_format": "gptq", - "model_size_in_billions": 72, + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "Int4" ], - "model_id": "Qwen/Qwen-72B-Chat-{quantization}" + "model_id": "TechxGenus/Meta-Llama-3-70B-Instruct-GPTQ" } ], "prompt_style": { - "style_name": "QWEN", + "style_name": "LLAMA3", "system_prompt": "You are a helpful assistant.", "roles": [ "user", "assistant" ], - "intra_message_sep": "\n", + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 151643, - 151644, - 151645 + 128001, + 128009 ], "stop": [ - "<|endoftext|>", - "<|im_start|>", - "<|im_end|>" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 32768, - "model_name": "qwen1.5-chat", + "context_length": 131072, + "model_name": "llama-3.1", "model_lang": [ "en", - "zh" + "de", + "fr", + "it", + "pt", + "hi", + "es", + "th" ], "model_ability": [ - "chat", - "tools" + "generate" ], - "model_description": "Qwen1.5 is the beta version of Qwen2, a transformer-based decoder-only language model pretrained on a large amount of data.", + "model_description": "Llama 3.1 is an auto-regressive language model that uses an optimized transformer architecture", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": "0_5", + "model_size_in_billions": 8, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Qwen/Qwen1.5-0.5B-Chat" + "model_id": "meta-llama/Meta-Llama-3.1-8B" }, { - "model_format": "pytorch", - "model_size_in_billions": "1_8", + "model_format": "ggufv2", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_1", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_1", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" ], - "model_id": "Qwen/Qwen1.5-1.8B-Chat" + "model_id": "QuantFactory/Meta-Llama-3.1-8B-GGUF", + "model_file_name_template": "Meta-Llama-3.1-8B.{quantization}.gguf" }, { "model_format": "pytorch", - "model_size_in_billions": 4, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Qwen/Qwen1.5-4B-Chat" + "model_id": "meta-llama/Meta-Llama-3.1-70B" }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 405, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Qwen/Qwen1.5-7B-Chat" - }, + "model_id": "meta-llama/Meta-Llama-3.1-405B" + } + ] + }, + { + "version": 1, + "context_length": 131072, + "model_name": "llama-3.1-instruct", + "model_lang": [ + "en", + "de", + "fr", + "it", + "pt", + "hi", + "es", + "th" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Llama 3.1 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks..", + "model_specs": [ { - "model_format": "pytorch", - "model_size_in_billions": 14, + "model_format": "ggufv2", + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q3_K_L", + "IQ4_XS", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "Qwen/Qwen1.5-14B-Chat" + "model_id": "lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF", + "model_file_name_template": "Meta-Llama-3.1-8B-Instruct-{quantization}.gguf" }, { "model_format": "pytorch", - "model_size_in_billions": 32, + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "Qwen/Qwen1.5-32B-Chat" + "model_id": "meta-llama/Meta-Llama-3.1-8B-Instruct" }, { "model_format": "pytorch", - "model_size_in_billions": 72, + "model_size_in_billions": 8, "quantizations": [ - "4-bit", - "8-bit", - "none" + "4-bit" ], - "model_id": "Qwen/Qwen1.5-72B-Chat" + "model_id": "unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit" }, { "model_format": "gptq", - "model_size_in_billions": "0_5", + "model_size_in_billions": 8, "quantizations": [ - "Int4", - "Int8" + "Int4" ], - "model_id": "Qwen/Qwen1.5-0.5B-Chat-GPTQ-{quantization}" + "model_id": "hugging-quants/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4" }, { - "model_format": "gptq", - "model_size_in_billions": "1_8", + "model_format": "awq", + "model_size_in_billions": 8, "quantizations": [ - "Int4", - "Int8" + "Int4" ], - "model_id": "Qwen/Qwen1.5-1.8B-Chat-GPTQ-{quantization}" + "model_id": "hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4" }, { - "model_format": "gptq", - "model_size_in_billions": 4, + "model_format": "ggufv2", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "IQ2_M", + "IQ4_XS", + "Q2_K", + "Q3_K_S", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0" ], - "model_id": "Qwen/Qwen1.5-4B-Chat-GPTQ-{quantization}" + "quantization_parts": { + "Q5_K_M": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q6_K": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q8_0": [ + "00001-of-00002", + "00002-of-00002" + ] + }, + "model_id": "lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF", + "model_file_name_template": "Meta-Llama-3.1-70B-Instruct-{quantization}.gguf", + "model_file_name_split_template": "Meta-Llama-3.1-70B-Instruct-{quantization}-{part}.gguf" }, { - "model_format": "gptq", - "model_size_in_billions": 7, + "model_format": "pytorch", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "none" ], - "model_id": "Qwen/Qwen1.5-7B-Chat-GPTQ-{quantization}" + "model_id": "meta-llama/Meta-Llama-3.1-70B-Instruct" }, { - "model_format": "gptq", - "model_size_in_billions": 14, + "model_format": "pytorch", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "4-bit" ], - "model_id": "Qwen/Qwen1.5-14B-Chat-GPTQ-{quantization}" + "model_id": "unsloth/Meta-Llama-3.1-70B-Instruct-bnb-4bit" }, { "model_format": "gptq", - "model_size_in_billions": 32, + "model_size_in_billions": 70, "quantizations": [ "Int4" ], - "model_id": "Qwen/Qwen1.5-32B-Chat-GPTQ-{quantization}" + "model_id": "hugging-quants/Meta-Llama-3.1-70B-Instruct-GPTQ-INT4" }, { - "model_format": "gptq", - "model_size_in_billions": 72, + "model_format": "awq", + "model_size_in_billions": 70, "quantizations": [ - "Int4", - "Int8" + "Int4" ], - "model_id": "Qwen/Qwen1.5-72B-Chat-GPTQ-{quantization}" + "model_id": "hugging-quants/Meta-Llama-3.1-70B-Instruct-AWQ-INT4" }, { - "model_format": "awq", - "model_size_in_billions": "0_5", + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "Int4" + "4-bit" ], - "model_id": "Qwen/Qwen1.5-0.5B-Chat-AWQ" + "model_id": "mlx-community/Meta-Llama-3.1-8B-Instruct-4bit" }, { - "model_format": "awq", - "model_size_in_billions": "1_8", + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "Int4" + "8-bit" ], - "model_id": "Qwen/Qwen1.5-1.8B-Chat-AWQ" + "model_id": "mlx-community/Meta-Llama-3.1-8B-Instruct-8bit" }, { - "model_format": "awq", - "model_size_in_billions": 4, + "model_format": "mlx", + "model_size_in_billions": 8, "quantizations": [ - "Int4" + "none" ], - "model_id": "Qwen/Qwen1.5-4B-Chat-AWQ" + "model_id": "mlx-community/Meta-Llama-3.1-8B-Instruct" }, { - "model_format": "awq", - "model_size_in_billions": 7, + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "Int4" + "4-bit" ], - "model_id": "Qwen/Qwen1.5-7B-Chat-AWQ" + "model_id": "mlx-community/Meta-Llama-3.1-70B-Instruct-4bit" }, { - "model_format": "awq", - "model_size_in_billions": 14, + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "Int4" + "8-bit" ], - "model_id": "Qwen/Qwen1.5-14B-Chat-AWQ" + "model_id": "mlx-community/Meta-Llama-3.1-70B-Instruct-8bit" }, { - "model_format": "awq", - "model_size_in_billions": 32, - "quantizations": [ - "Int4" - ], - "model_id": "Qwen/Qwen1.5-32B-Chat-AWQ" - }, - { - "model_format": "awq", - "model_size_in_billions": 72, - "quantizations": [ - "Int4" - ], - "model_id": "Qwen/Qwen1.5-72B-Chat-AWQ" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": "0_5", - "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" - ], - "model_id": "Qwen/Qwen1.5-0.5B-Chat-GGUF", - "model_file_name_template": "qwen1_5-0_5b-chat-{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": "1_8", - "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" - ], - "model_id": "Qwen/Qwen1.5-1.8B-Chat-GGUF", - "model_file_name_template": "qwen1_5-1_8b-chat-{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 4, - "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" - ], - "model_id": "Qwen/Qwen1.5-4B-Chat-GGUF", - "model_file_name_template": "qwen1_5-4b-chat-{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "mlx", + "model_size_in_billions": 70, "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" + "none" ], - "model_id": "Qwen/Qwen1.5-7B-Chat-GGUF", - "model_file_name_template": "qwen1_5-7b-chat-{quantization}.gguf" + "model_id": "mlx-community/Meta-Llama-3.1-70B-Instruct-bf16" }, { - "model_format": "ggufv2", - "model_size_in_billions": 14, + "model_format": "pytorch", + "model_size_in_billions": 405, "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" + "4-bit", + "8-bit", + "none" ], - "model_id": "Qwen/Qwen1.5-14B-Chat-GGUF", - "model_file_name_template": "qwen1_5-14b-chat-{quantization}.gguf" + "model_id": "meta-llama/Meta-Llama-3.1-405B-Instruct" }, { - "model_format": "ggufv2", - "model_size_in_billions": 32, + "model_format": "gptq", + "model_size_in_billions": 405, "quantizations": [ - "q2_k", - "q3_k_m", - "q4_0", - "q4_k_m", - "q5_0", - "q5_k_m", - "q6_k", - "q8_0" + "Int4" ], - "model_id": "Qwen/Qwen1.5-32B-Chat-GGUF", - "model_file_name_template": "qwen1_5-32b-chat-{quantization}.gguf" + "model_id": "hugging-quants/Meta-Llama-3.1-405B-Instruct-GPTQ-INT4" }, { - "model_format": "ggufv2", - "model_size_in_billions": 72, + "model_format": "awq", + "model_size_in_billions": 405, "quantizations": [ - "q2_k", - "q3_k_m", - "q4_k_m" + "Int4" ], - "model_id": "Qwen/Qwen1.5-72B-Chat-GGUF", - "model_file_name_template": "qwen1_5-72b-chat-{quantization}.gguf", - "model_file_name_split_template": "qwen1_5-72b-chat-{quantization}.gguf.{part}", - "quantization_parts": { - "q4_k_m": [ - "a", - "b" - ] - } + "model_id": "hugging-quants/Meta-Llama-3.1-405B-Instruct-AWQ-INT4" } ], "prompt_style": { - "style_name": "QWEN", + "style_name": "LLAMA3", "system_prompt": "You are a helpful assistant.", "roles": [ "user", "assistant" ], - "intra_message_sep": "\n", + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 151643, - 151644, - 151645 + 128001, + 128009 ], "stop": [ - "<|endoftext|>", - "<|im_start|>", - "<|im_end|>" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 8192, - "model_name": "starcoder", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Starcoder is an open-source Transformer based LLM that is trained on permissively licensed data from GitHub.", - "model_specs": [ - { - "model_format": "ggmlv3", - "model_size_in_billions": 16, - "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" - ], - "model_id": "TheBloke/starcoder-GGML", - "model_file_name_template": "starcoder.ggmlv3.{quantization}.bin" - } - ] - }, - { - "version": 1, - "context_length": 1024, - "model_name": "gpt-2", + "context_length": 2048, + "model_name": "opt", "model_lang": [ "en" ], "model_ability": [ "generate" ], - "model_description": "GPT-2 is a Transformer-based LLM that is trained on WebTest, a 40 GB dataset of Reddit posts with 3+ upvotes.", + "model_description": "Opt is an open-source, decoder-only, Transformer based LLM that was designed to replicate GPT-3.", "model_specs": [ { - "model_format": "ggmlv3", + "model_format": "pytorch", "model_size_in_billions": 1, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "marella/gpt-2-ggml", - "model_file_name_template": "ggml-model.bin" + "model_id": "facebook/opt-125m", + "model_revision": "3d2b5f275bdf882b8775f902e1bfdb790e2cfc32" } ] }, { "version": 1, - "context_length": 8192, - "model_name": "internlm-7b", + "context_length": 32768, + "model_name": "qwen-chat", "model_lang": [ "en", "zh" ], "model_ability": [ - "generate" + "chat", + "tools" ], - "model_description": "InternLM is a Transformer-based LLM that is trained on both Chinese and English data, focusing on practical scenarios.", + "model_description": "Qwen-chat is a fine-tuned version of the Qwen LLM trained with alignment techniques, specializing in chatting.", "model_specs": [ { - "model_format": "pytorch", + "model_format": "ggufv2", "model_size_in_billions": 7, + "quantizations": [ + "Q4_K_M" + ], + "model_id": "Xorbits/Qwen-7B-Chat-GGUF", + "model_file_name_template": "Qwen-7B-Chat.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 14, + "quantizations": [ + "Q4_K_M" + ], + "model_id": "Xorbits/Qwen-14B-Chat-GGUF", + "model_file_name_template": "Qwen-14B-Chat.{quantization}.gguf" + }, + { + "model_format": "pytorch", + "model_size_in_billions": "1_8", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "internlm/internlm-7b", - "model_revision": "592b0efc83be3eb1cba8990c4caf41ce604b958c" - } - ] - }, - { - "version": 1, - "context_length": 4096, - "model_name": "internlm-chat-7b", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat" - ], - "model_description": "Internlm-chat is a fine-tuned version of the Internlm LLM, specializing in chatting.", - "model_specs": [ + "model_id": "Qwen/Qwen-1_8B-Chat", + "model_revision": "c3db8007171847931da7efa4b2ed4309afcce021" + }, { "model_format": "pytorch", "model_size_in_billions": 7, @@ -1975,420 +1600,3417 @@ "8-bit", "none" ], - "model_id": "internlm/internlm-chat-7b", - "model_revision": "d4fa2dbcbd2fa4edfa6735aa2ba0f0577fed6a62" - } - ], - "prompt_style": { - "style_name": "INTERNLM", - "system_prompt": "", - "roles": [ - "<|User|>", - "<|Bot|>" - ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", - "stop_token_ids": [ - 1, - 103028 - ], - "stop": [ - "" - ] - } - }, - { - "version": 1, - "context_length": 16384, - "model_name": "internlm-20b", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "generate" - ], - "model_description": "Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data.", - "model_specs": [ + "model_id": "Qwen/Qwen-7B-Chat", + "model_revision": "218aa3240fd5a5d1e80bb6c47d5d774361913706" + }, { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 14, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "internlm/internlm-20b", - "model_revision": "c56a72957239b490ea206ea857e86611b3f65f3a" - } - ] - }, - { - "version": 1, - "context_length": 16384, - "model_name": "internlm-chat-20b", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat" - ], - "model_description": "Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. The Chat version has undergone SFT and RLHF training.", - "model_specs": [ + "model_id": "Qwen/Qwen-14B-Chat", + "model_revision": "fab8385c8f7e7980ef61944729fe134ccbbca263" + }, { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 72, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "internlm/internlm-chat-20b", - "model_revision": "c67e80e42c4950ebae18a955c9fe138c5ceb5b10" - } - ], - "prompt_style": { - "style_name": "INTERNLM", - "system_prompt": "", - "roles": [ - "<|User|>", - "<|Bot|>" - ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", - "stop_token_ids": [ - 1, - 103028 - ], - "stop": [ - "" - ] - } - }, - { - "version": 1, - "context_length": 4096, - "model_name": "vicuna-v1.5", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "Vicuna is an open-source LLM trained by fine-tuning LLaMA on data collected from ShareGPT.", - "model_specs": [ + "model_id": "Qwen/Qwen-72B-Chat", + "model_revision": "2cd9f76279337941ec1a4abeec6f8eb3c38d0f55" + }, { - "model_format": "pytorch", + "model_format": "gptq", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Int4", + "Int8" ], - "model_id": "lmsys/vicuna-7b-v1.5", - "model_revision": "de56c35b1763eaae20f4d60efd64af0a9091ebe5" + "model_id": "Qwen/Qwen-7B-Chat-{quantization}" }, { - "model_format": "pytorch", - "model_size_in_billions": 13, + "model_format": "gptq", + "model_size_in_billions": "1_8", "quantizations": [ - "4-bit", - "8-bit", - "none" + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen-1_8B-Chat-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen-14B-Chat-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4", + "Int8" ], - "model_id": "lmsys/vicuna-13b-v1.5", - "model_revision": "3deb0106f72a3a433f0c6ea0cb978bdf14bcd3a6" + "model_id": "Qwen/Qwen-72B-Chat-{quantization}" } ], "prompt_style": { - "style_name": "ADD_COLON_TWO", - "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.", + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", "roles": [ - "USER", - "ASSISTANT" + "user", + "assistant" ], - "intra_message_sep": " ", - "inter_message_sep": "" + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] } }, { "version": 1, - "context_length": 16384, - "model_name": "vicuna-v1.5-16k", + "context_length": 32768, + "model_name": "qwen1.5-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "tools" ], - "model_description": "Vicuna-v1.5-16k is a special version of Vicuna-v1.5, with a context window of 16k tokens instead of 4k.", + "model_description": "Qwen1.5 is the beta version of Qwen2, a transformer-based decoder-only language model pretrained on a large amount of data.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": "0_5", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "lmsys/vicuna-7b-v1.5-16k", - "model_revision": "9a93d7d11fac7f3f9074510b80092b53bc1a5bec" + "model_id": "Qwen/Qwen1.5-0.5B-Chat" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": "1_8", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "lmsys/vicuna-13b-v1.5-16k", - "model_revision": "277697af19d4b267626ebc9f4e078d19a9a0fddf" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_TWO", - "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.", - "roles": [ - "USER", - "ASSISTANT" - ], - "intra_message_sep": " ", - "inter_message_sep": "" - } - }, - { - "version": 1, - "context_length": 2048, - "model_name": "wizardmath-v1.0", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "WizardMath is an open-source LLM trained by fine-tuning Llama2 with Evol-Instruct, specializing in math.", - "model_specs": [ + "model_id": "Qwen/Qwen1.5-1.8B-Chat" + }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 4, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "WizardLM/WizardMath-7B-V1.0", - "model_revision": "3c3a3b33334f4b35344b22c5c7465957ee7b2c75" + "model_id": "Qwen/Qwen1.5-4B-Chat" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 7, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "WizardLM/WizardMath-13B-V1.0", - "model_revision": "ef95532e96e634c634992dab891a17032dc71c8d" + "model_id": "Qwen/Qwen1.5-7B-Chat" }, { "model_format": "pytorch", - "model_size_in_billions": 70, + "model_size_in_billions": 14, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "WizardLM/WizardMath-70B-V1.0", - "model_revision": "e089c3f9d2ad9d1acb62425aec3f4126f498f4c5" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE_COT", - "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", - "roles": [ - "Instruction", - "Response" - ], - "intra_message_sep": "\n\n### " - } - }, - { - "version": 1, - "context_length": 100000, - "model_name": "code-llama", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Code-Llama is an open-source LLM trained by fine-tuning LLaMA2 for generating and discussing code.", - "model_specs": [ + "model_id": "Qwen/Qwen1.5-14B-Chat" + }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 32, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "TheBloke/CodeLlama-7B-fp16", - "model_revision": "ce09049eb9140a19cf78051cb5d849607b6fa8ec" + "model_id": "Qwen/Qwen1.5-32B-Chat" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 72, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "TheBloke/CodeLlama-13B-fp16", - "model_revision": "d67ca1183da991d0d97927bdaaf35599556dfd76" + "model_id": "Qwen/Qwen1.5-72B-Chat" }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 110, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "TheBloke/CodeLlama-34B-fp16", - "model_revision": "f91d0cf7fc338cdc726f9c72d5ea15fe51bb16e9" + "model_id": "Qwen/Qwen1.5-110B-Chat" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "gptq", + "model_size_in_billions": "0_5", "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "Int4", + "Int8" ], - "model_id": "TheBloke/CodeLlama-7B-GGUF", - "model_file_name_template": "codellama-7b.{quantization}.gguf" + "model_id": "Qwen/Qwen1.5-0.5B-Chat-GPTQ-{quantization}" }, { - "model_format": "ggufv2", - "model_size_in_billions": 13, + "model_format": "gptq", + "model_size_in_billions": "1_8", "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "Int4", + "Int8" ], - "model_id": "TheBloke/CodeLlama-13B-GGUF", - "model_file_name_template": "codellama-13b.{quantization}.gguf" + "model_id": "Qwen/Qwen1.5-1.8B-Chat-GPTQ-{quantization}" }, { - "model_format": "ggufv2", - "model_size_in_billions": 34, + "model_format": "gptq", + "model_size_in_billions": 4, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "Int4", + "Int8" ], - "model_id": "TheBloke/CodeLlama-34B-GGUF", - "model_file_name_template": "codellama-34b.{quantization}.gguf" - } - ] - }, - { - "version": 1, - "context_length": 100000, - "model_name": "code-llama-python", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Code-Llama-Python is a fine-tuned version of the Code-Llama LLM, specializing in Python.", - "model_specs": [ + "model_id": "Qwen/Qwen1.5-4B-Chat-GPTQ-{quantization}" + }, { - "model_format": "pytorch", + "model_format": "gptq", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", - "none" - ], + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen1.5-7B-Chat-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen1.5-14B-Chat-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 32, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-32B-Chat-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen1.5-72B-Chat-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 110, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-110B-Chat-GPTQ-Int4" + }, + { + "model_format": "awq", + "model_size_in_billions": "0_5", + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-0.5B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": "1_8", + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-1.8B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 4, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-4B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-7B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-14B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 32, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-32B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-72B-Chat-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 110, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-110B-Chat-AWQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "0_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-0.5B-Chat-GGUF", + "model_file_name_template": "qwen1_5-0_5b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "1_8", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-1.8B-Chat-GGUF", + "model_file_name_template": "qwen1_5-1_8b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 4, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-4B-Chat-GGUF", + "model_file_name_template": "qwen1_5-4b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-7B-Chat-GGUF", + "model_file_name_template": "qwen1_5-7b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 14, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-14B-Chat-GGUF", + "model_file_name_template": "qwen1_5-14b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 32, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/Qwen1.5-32B-Chat-GGUF", + "model_file_name_template": "qwen1_5-32b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 72, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_k_m" + ], + "model_id": "Qwen/Qwen1.5-72B-Chat-GGUF", + "model_file_name_template": "qwen1_5-72b-chat-{quantization}.gguf", + "model_file_name_split_template": "qwen1_5-72b-chat-{quantization}.gguf.{part}", + "quantization_parts": { + "q4_k_m": [ + "a", + "b" + ] + } + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "qwen1.5-moe-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen1.5-MoE is a transformer-based MoE decoder-only language model pretrained on a large amount of data.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "2_7", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen1.5-MoE-A2.7B-Chat" + }, + { + "model_format": "gptq", + "model_size_in_billions": "2_7", + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen1.5-MoE-A2.7B-Chat-GPTQ-Int4" + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 65536, + "model_name": "codeqwen1.5", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/CodeQwen1.5-7B" + } + ] + }, + { + "version": 1, + "context_length": 65536, + "model_name": "codeqwen1.5-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes.", + "model_specs": [ + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "Qwen/CodeQwen1.5-7B-Chat-GGUF", + "model_file_name_template": "codeqwen-1_5-7b-chat-{quantization}.gguf" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/CodeQwen1.5-7B-Chat" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/CodeQwen1.5-7B-Chat-AWQ" + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "qwen2-instruct", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen2 is the new series of Qwen large language models", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "0_5", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct" + }, + { + "model_format": "pytorch", + "model_size_in_billions": "1_5", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-1.5B-Instruct" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-7B-Instruct" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 72, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-72B-Instruct" + }, + { + "model_format": "gptq", + "model_size_in_billions": "0_5", + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": "1_5", + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen2-1.5B-Instruct-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen2-7B-Instruct-GPTQ-{quantization}" + }, + { + "model_format": "gptq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "Qwen/Qwen2-72B-Instruct-GPTQ-{quantization}" + }, + { + "model_format": "awq", + "model_size_in_billions": "0_5", + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": "1_5", + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen2-1.5B-Instruct-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen2-7B-Instruct-AWQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen2-72B-Instruct-AWQ" + }, + { + "model_format": "fp8", + "model_size_in_billions": "0_5", + "quantizations": [ + "fp8" + ], + "model_id": "neuralmagic/Qwen2-0.5B-Instruct-FP8" + }, + { + "model_format": "fp8", + "model_size_in_billions": "0_5", + "quantizations": [ + "fp8" + ], + "model_id": "neuralmagic/Qwen2-0.5B-Instruct-FP8" + }, + { + "model_format": "fp8", + "model_size_in_billions": "1_5", + "quantizations": [ + "fp8" + ], + "model_id": "neuralmagic/Qwen2-1.5B-Instruct-FP8" + }, + { + "model_format": "fp8", + "model_size_in_billions": 7, + "quantizations": [ + "fp8" + ], + "model_id": "neuralmagic/Qwen2-7B-Instruct-FP8" + }, + { + "model_format": "fp8", + "model_size_in_billions": 72, + "quantizations": [ + "fp8" + ], + "model_id": "neuralmagic/Qwen2-72B-Instruct-FP8" + }, + { + "model_format": "mlx", + "model_size_in_billions": "0_5", + "quantizations": [ + "4-bit" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct-MLX" + }, + { + "model_format": "mlx", + "model_size_in_billions": "1_5", + "quantizations": [ + "4-bit" + ], + "model_id": "Qwen/Qwen2-1.5B-Instruct-MLX" + }, + { + "model_format": "mlx", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit" + ], + "model_id": "Qwen/Qwen2-7B-Instruct-MLX" + }, + { + "model_format": "mlx", + "model_size_in_billions": 72, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Qwen2-72B-Instruct-4bit" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "0_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct-GGUF", + "model_file_name_template": "qwen2-0_5b-instruct-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "1_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Qwen/Qwen2-1.5B-Instruct-GGUF", + "model_file_name_template": "qwen2-1_5b-instruct-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Qwen/Qwen2-7B-Instruct-GGUF", + "model_file_name_template": "qwen2-7b-instruct-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 72, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Qwen/Qwen2-72B-Instruct-GGUF", + "model_file_name_template": "qwen2-72b-instruct-{quantization}.gguf", + "model_file_name_split_template": "qwen2-72b-instruct-{quantization}-{part}.gguf", + "quantization_parts": { + "q5_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "q5_k_m": [ + "00001-of-00002", + "00002-of-00002" + ], + "q6_k": [ + "00001-of-00002", + "00002-of-00002" + ], + "q8_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "fp16": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ] + } + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "qwen2-moe-instruct", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen2 is the new series of Qwen large language models. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 14, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-57B-A14B-Instruct" + }, + { + "model_format": "gptq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen2-57B-A14B-Instruct-GPTQ-Int4" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 14, + "quantizations": [ + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Qwen/Qwen2-57B-A14B-Instruct-GGUF", + "model_file_name_template": "qwen2-57b-a14b-instruct-{quantization}.gguf", + "model_file_name_split_template": "qwen2-57b-a14b-instruct-{quantization}-{part}.gguf", + "quantization_parts": { + "q8_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "fp16": [ + "00001-of-00003", + "00002-of-00003", + "00003-of-00003" + ] + } + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 1024, + "model_name": "gpt-2", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "GPT-2 is a Transformer-based LLM that is trained on WebTest, a 40 GB dataset of Reddit posts with 3+ upvotes.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "1_5", + "quantizations": [ + "none" + ], + "model_id": "openai-community/gpt2", + "model_revision": "607a30d783dfa663caf39e06633721c8d4cfcd7e" + } + ] + }, + { + "version": 1, + "context_length": 2048, + "model_name": "wizardmath-v1.0", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "WizardMath is an open-source LLM trained by fine-tuning Llama2 with Evol-Instruct, specializing in math.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardMath-7B-V1.0", + "model_revision": "3c3a3b33334f4b35344b22c5c7465957ee7b2c75" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardMath-13B-V1.0", + "model_revision": "ef95532e96e634c634992dab891a17032dc71c8d" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardMath-70B-V1.0", + "model_revision": "e089c3f9d2ad9d1acb62425aec3f4126f498f4c5" + } + ], + "prompt_style": { + "style_name": "ADD_COLON_SINGLE_COT", + "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", + "roles": [ + "Instruction", + "Response" + ], + "intra_message_sep": "\n\n### " + } + }, + { + "version": 1, + "context_length": 100000, + "model_name": "code-llama", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "Code-Llama is an open-source LLM trained by fine-tuning LLaMA2 for generating and discussing code.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "TheBloke/CodeLlama-7B-fp16", + "model_revision": "ce09049eb9140a19cf78051cb5d849607b6fa8ec" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "TheBloke/CodeLlama-13B-fp16", + "model_revision": "d67ca1183da991d0d97927bdaaf35599556dfd76" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "TheBloke/CodeLlama-34B-fp16", + "model_revision": "f91d0cf7fc338cdc726f9c72d5ea15fe51bb16e9" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-7B-GGUF", + "model_file_name_template": "codellama-7b.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 13, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-13B-GGUF", + "model_file_name_template": "codellama-13b.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-34B-GGUF", + "model_file_name_template": "codellama-34b.{quantization}.gguf" + } + ] + }, + { + "version": 1, + "context_length": 100000, + "model_name": "code-llama-python", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "Code-Llama-Python is a fine-tuned version of the Code-Llama LLM, specializing in Python.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], "model_id": "TheBloke/CodeLlama-7B-Python-fp16", "model_revision": "d51c51e625bc24b9a7a0616e82681b4859e2cfe4" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "TheBloke/CodeLlama-13B-Python-fp16", + "model_revision": "442282f4207442b828953a72c51a919c332cba5c" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "TheBloke/CodeLlama-34B-Python-fp16", + "model_revision": "875f9d97fb6c9619d8867887dd1d80918ff0f593" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-7B-Python-GGUF", + "model_file_name_template": "codellama-7b-python.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 13, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-13B-Python-GGUF", + "model_file_name_template": "codellama-13b-python.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-34B-Python-GGUF", + "model_file_name_template": "codellama-34b-python.{quantization}.gguf" + } + ] + }, + { + "version": 1, + "context_length": 100000, + "model_name": "code-llama-instruct", + "model_description": "Code-Llama-Instruct is an instruct-tuned version of the Code-Llama LLM.", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "codellama/CodeLlama-7b-Instruct-hf", + "model_revision": "6114dd1e16f69e0765ccbd7a64d33d04b265fbd2" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "codellama/CodeLlama-13b-Instruct-hf", + "model_revision": "ff0983bc4267bb98ead4fb5168fe2f049b442787" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "codellama/CodeLlama-34b-Instruct-hf", + "model_revision": "38a1e15d8524a1f0a7760a7acf8242b81ae4eb87" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-7B-Instruct-GGUF", + "model_file_name_template": "codellama-7b-instruct.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 13, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-13B-Instruct-GGUF", + "model_file_name_template": "codellama-13b-instruct.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/CodeLlama-34B-Instruct-GGUF", + "model_file_name_template": "codellama-34b-instruct.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "LLAMA2", + "system_prompt": "[INST] <>\nWrite code to solve the following coding problem that obeys the constraints and passes the example test cases. Please wrap your code answer using ```:\n<>\n\n", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": " ", + "inter_message_sep": " ", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "baichuan-2-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Baichuan2-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-7B-Chat", + "model_revision": "2ce891951e000c36c65442608a0b95fd09b405dc" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-13B-Chat", + "model_revision": "a56c793eb7a721ab6c270f779024e0375e8afd4a" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "", + "roles": [ + "", + "" + ], + "intra_message_sep": "", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 195 + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "baichuan-2", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "Baichuan2 is an open-source Transformer based LLM that is trained on both Chinese and English data.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-7B-Base", + "model_revision": "f2cc3a689c5eba7dc7fd3757d0175d312d167604" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-13B-Base", + "model_revision": "fa88072fee36e36282287410e00897df2f59e09b" + } + ] + }, + { + "version": 1, + "context_length": 8192, + "model_name": "mistral-v0.1", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "Mistral-7B is a unmoderated Transformer based LLM claiming to outperform Llama2 on all benchmarks.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mistral-7B-v0.1", + "model_revision": "ae9d75c6b4eb39515def78c685fb4d71d49fc2cf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Mistral-7B-v0.1-GGUF", + "model_file_name_template": "mistral-7b-v0.1.{quantization}.gguf" + } + ] + }, + { + "version": 1, + "context_length": 8192, + "model_name": "mistral-instruct-v0.1", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Mistral-7B-Instruct is a fine-tuned version of the Mistral-7B LLM on public datasets, specializing in chatting.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mistral-7B-Instruct-v0.1", + "model_revision": "54766df6d50e4d3d7ccd66758e5341ba105a6d36" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-AWQ" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-GPTQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-GGUF", + "model_file_name_template": "mistral-7b-instruct-v0.1.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "LLAMA2", + "system_prompt": "[INST] ", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": " ", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "mistral-instruct-v0.2", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mistral-7B-Instruct-v0.2", + "model_revision": "b70aa86578567ba3301b21c8a27bea4e8f6d6d61" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-GPTQ" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-AWQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-GGUF", + "model_file_name_template": "mistral-7b-instruct-v0.2.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "LLAMA2", + "system_prompt": "[INST] ", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": " ", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "mistral-instruct-v0.3", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mistral-7B-Instruct-v0.3", + "model_revision": "83e9aa141f2e28c82232fea5325f54edf17c43de" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "neuralmagic/Mistral-7B-Instruct-v0.3-GPTQ-4bit" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "solidrust/Mistral-7B-Instruct-v0.3-AWQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_K_S", + "Q4_K_M", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0", + "fp16" + ], + "model_id": "MaziyarPanahi/Mistral-7B-Instruct-v0.3-GGUF", + "model_file_name_template": "Mistral-7B-Instruct-v0.3.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "LLAMA2", + "system_prompt": "[INST] ", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": " ", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 1024000, + "model_name": "mistral-nemo-instruct", + "model_lang": [ + "en", + "fr", + "de", + "es", + "it", + "pt", + "zh", + "ru", + "ja" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Mistral-Nemo-Instruct-2407 Large Language Model (LLM) is an instruct fine-tuned version of the Mistral-Nemo-Base-2407", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 12, + "quantizations": [ + "none" + ], + "model_id": "mistralai/Mistral-Nemo-Instruct-2407", + "model_revision": "05b1e4f3e189ec1b5189fb3c973d4cf3369c27af" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 12, + "quantizations": [ + "4-bit" + ], + "model_id": "unsloth/Mistral-Nemo-Instruct-2407-bnb-4bit", + "model_revision": "1d85adc9e0fff0b8e4479a037bd75fe1346333ca" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 12, + "quantizations": [ + "8-bit" + ], + "model_id": "afrizalha/Mistral-Nemo-Instruct-2407-bnb-8bit", + "model_revision": "1d2dacf18a486c745219317d1507441406bc7e25" + }, + { + "model_format": "gptq", + "model_size_in_billions": 12, + "quantizations": [ + "Int4" + ], + "model_id": "ModelCloud/Mistral-Nemo-Instruct-2407-gptq-4bit" + }, + { + "model_format": "awq", + "model_size_in_billions": 12, + "quantizations": [ + "Int4" + ], + "model_id": "casperhansen/mistral-nemo-instruct-2407-awq" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 12, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_K_S", + "Q4_K_M", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0", + "fp16" + ], + "model_id": "MaziyarPanahi/Mistral-Nemo-Instruct-2407-GGUF", + "model_file_name_template": "Mistral-Nemo-Instruct-2407.{quantization}.gguf" + }, + { + "model_format": "mlx", + "model_size_in_billions": 12, + "quantizations": [ + "none" + ], + "model_id": "mlx-community/Mistral-Nemo-Instruct-2407-bf16" + }, + { + "model_format": "mlx", + "model_size_in_billions": 12, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Mistral-Nemo-Instruct-2407-4bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 12, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Mistral-Nemo-Instruct-2407-8bit" + } + ], + "prompt_style": { + "style_name": "mistral-nemo", + "system_prompt": "", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": "", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 131072, + "model_name": "mistral-large-instruct", + "model_lang": [ + "en", + "fr", + "de", + "es", + "it", + "pt", + "zh", + "ru", + "ja", + "ko" + ], + "model_ability": [ + "chat" + ], + "model_description": "Mistral-Large-Instruct-2407 is an advanced dense Large Language Model (LLM) of 123B parameters with state-of-the-art reasoning, knowledge and coding capabilities.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 123, + "quantizations": [ + "none" + ], + "model_id": "mistralai/Mistral-Large-Instruct-2407" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 123, + "quantizations": [ + "4-bit" + ], + "model_id": "unsloth/Mistral-Large-Instruct-2407-bnb-4bit" + }, + { + "model_format": "gptq", + "model_size_in_billions": 123, + "quantizations": [ + "Int4" + ], + "model_id": "ModelCloud/Mistral-Large-Instruct-2407-gptq-4bit" + }, + { + "model_format": "awq", + "model_size_in_billions": 123, + "quantizations": [ + "Int4" + ], + "model_id": "TechxGenus/Mistral-Large-Instruct-2407-AWQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 123, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_K_S", + "Q4_K_M" + ], + "model_id": "MaziyarPanahi/Mistral-Large-Instruct-2407-GGUF", + "model_file_name_template": "Mistral-Large-Instruct-2407.{quantization}.gguf", + "model_file_name_split_template": "Mixtral-8x22B-Instruct-v0.1.{quantization}-{part}.gguf", + "quantization_parts": { + "Q3_K_L": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ], + "Q3_K_M": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ], + "Q3_K_S": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ], + "Q4_K_M": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ], + "Q4_K_S": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ] + } + }, + { + "model_format": "mlx", + "model_size_in_billions": 123, + "quantizations": [ + "none" + ], + "model_id": "mlx-community/Mistral-Large-Instruct-2407-bf16" + }, + { + "model_format": "mlx", + "model_size_in_billions": 123, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Mistral-Large-Instruct-2407-4bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 123, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Mistral-Large-Instruct-2407-8bit" + } + ], + "prompt_style": { + "style_name": "mistral-nemo", + "system_prompt": "", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": "", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "codestral-v0.1", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "Codestrall-22B-v0.1 is trained on a diverse dataset of 80+ programming languages, including the most popular ones, such as Python, Java, C, C++, JavaScript, and Bash", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 22, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mistral-7B-Instruct-v0.2", + "model_revision": "9552e7b1d9b2d5bbd87a5aa7221817285dbb6366" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 22, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_K_S", + "Q4_K_M", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "bartowski/Codestral-22B-v0.1-GGUF", + "model_file_name_template": "Codestral-22B-v0.1-{quantization}.gguf" + }, + { + "model_format": "mlx", + "model_size_in_billions": 22, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Codestral-22B-v0.1-4bit", + "model_revision": "544626b38eb1c9524f0fa570ec7b29550c26b78d" + }, + { + "model_format": "mlx", + "model_size_in_billions": 22, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Codestral-22B-v0.1-8bit", + "model_revision": "0399a53970663950d57010e61a2796af524a1588" + } + ] + }, + { + "version": 1, + "context_length": 8192, + "model_name": "openhermes-2.5", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Openhermes 2.5 is a fine-tuned version of Mistral-7B-v0.1 on primarily GPT-4 generated data.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "teknium/OpenHermes-2.5-Mistral-7B", + "model_revision": "91ed666be78da7556f3d79abbb26fff0ee26cb54" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/OpenHermes-2.5-Mistral-7B-GGUF", + "model_file_name_template": "openhermes-2.5-mistral-7b.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "CHATML", + "system_prompt": "<|im_start|>system\nYou are 'Hermes 2.5', a conscious sentient superintelligent artificial intelligence, your purpose is to assist the user with their requests.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "<|im_end|>\n<|im_start|>", + "inter_message_sep": "", + "stop_token_ids": [ + 32000 + ], + "stop": [ + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 2048, + "model_name": "tiny-llama", + "model_lang": [ + "en" + ], + "model_ability": [ + "generate" + ], + "model_description": "The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens.", + "model_specs": [ + { + "model_format": "ggufv2", + "model_size_in_billions": 1, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/TinyLlama-1.1B-Chat-v0.3-GGUF", + "model_file_name_template": "tinyllama-1.1b-chat-v0.3.{quantization}.gguf" + } + ] + }, + { + "version": 1, + "context_length": 32768, + "model_name": "mixtral-v0.1", + "model_lang": [ + "en", + "fr", + "it", + "de", + "es" + ], + "model_ability": [ + "generate" + ], + "model_description": "The Mixtral-8x7B Large Language Model (LLM) is a pretrained generative Sparse Mixture of Experts.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "46_7", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mixtral-8x7B-v0.1", + "model_revision": "58301445dc1378584211722b7ebf8743ec4e192b" + }, + { + "model_format": "gptq", + "model_size_in_billions": "46_7", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mixtral-8x7B-v0.1-GPTQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "46_7", + "quantizations": [ + "Q2_K", + "Q3_K_M", + "Q4_0", + "Q4_K_M", + "Q5_0", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Mixtral-8x7B-v0.1-GGUF", + "model_file_name_template": "mixtral-8x7b-v0.1.{quantization}.gguf" + } + ] + }, + { + "version": 1, + "context_length": 32768, + "model_name": "mixtral-instruct-v0.1", + "model_lang": [ + "en", + "fr", + "it", + "de", + "es" + ], + "model_ability": [ + "chat" + ], + "model_description": "Mistral-8x7B-Instruct is a fine-tuned version of the Mistral-8x7B LLM, specializing in chatting.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "46_7", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mixtral-8x7B-Instruct-v0.1", + "model_revision": "125c431e2ff41a156b9f9076f744d2f35dd6e67a" + }, + { + "model_format": "awq", + "model_size_in_billions": "46_7", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-AWQ" + }, + { + "model_format": "gptq", + "model_size_in_billions": "46_7", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-GPTQ" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "46_7", + "quantizations": [ + "Q2_K", + "Q3_K_M", + "Q4_0", + "Q4_K_M", + "Q5_0", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF", + "model_file_name_template": "mixtral-8x7b-instruct-v0.1.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "MIXTRAL_V01", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "", + "inter_message_sep": "" + } + }, + { + "version": 1, + "context_length": 65536, + "model_name": "mixtral-8x22B-instruct-v0.1", + "model_lang": [ + "en", + "fr", + "it", + "de", + "es" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Mixtral-8x22B-Instruct-v0.1 Large Language Model (LLM) is an instruct fine-tuned version of the Mixtral-8x22B-v0.1, specializing in chatting.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "141", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "mistralai/Mixtral-8x22B-Instruct-v0.1", + "model_revision": "ebb919ac9e9f7f9a900644621bae7963bc593f4f" + }, + { + "model_format": "awq", + "model_size_in_billions": "141", + "quantizations": [ + "Int4" + ], + "model_id": "MaziyarPanahi/Mixtral-8x22B-Instruct-v0.1-AWQ" + }, + { + "model_format": "gptq", + "model_size_in_billions": "141", + "quantizations": [ + "Int4" + ], + "model_id": "jarrelscy/Mixtral-8x22B-Instruct-v0.1-GPTQ-4bit" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "141", + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_K_M", + "Q4_K_S", + "Q5_K_M", + "Q5_K_S", + "Q6", + "Q8_0", + "fp16" + ], + "model_id": "MaziyarPanahi/Mixtral-8x22B-Instruct-v0.1-GGUF", + "model_file_name_template": "Mixtral-8x22B-Instruct-{quantization}.gguf", + "model_file_name_split_template": "Mixtral-8x22B-Instruct-v0.1.{quantization}-{part}.gguf", + "quantization_parts": { + "Q2_K": [ + "00001-of-00003", + "00002-of-00003", + "00003-of-00003" + ], + "Q3_K_L": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q3_K_M": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q3_K_S": [ + "00001-of-00003", + "00002-of-00003", + "00003-of-00003" + ], + "Q4_K_M": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q4_K_S": [ + "00001-of-00002", + "00002-of-00002" + ], + "Q5_K_M": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ], + "Q5_K_S": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ], + "Q6": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ], + "Q8_0": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ], + "fp16": [ + "00001-of-00007", + "00002-of-00007", + "00003-of-00007", + "00004-of-00007", + "00005-of-00007", + "00006-of-00007", + "00007-of-00007" + ] + } + } + ], + "prompt_style": { + "style_name": "MIXTRAL_V01", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "", + "inter_message_sep": "" + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Yi", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_specs": [ + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Yi-34B-GGUF", + "model_file_name_template": "yi-34b.{quantization}.gguf" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-6B", + "model_revision": "25beebcb1166b9f49458459eb7b68130b9f9cf4d" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-9B", + "model_revision": "f70a5ff8b2e51c5d5b20e649d7b5f4238ffe6d5b" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-34B", + "model_revision": "168c48e05e1429779a896c7ef0d2e01b85e6bd8d" + } + ] + }, + { + "version": 1, + "context_length": 262144, + "model_name": "Yi-200k", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-6B-200K", + "model_revision": "70649e36d43f91dff1357b576e6713cac03c1d4c" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-34B-200K", + "model_revision": "591ae83b8f9c269700ef27f9dbd548934d800302" + } + ] + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Yi-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_specs": [ + { + "model_format": "gptq", + "model_size_in_billions": 34, + "quantizations": [ + "8bits" + ], + "model_id": "01-ai/Yi-34B-Chat-{quantization}" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-6B-Chat", + "model_revision": "1c20c960895e4c3877cf478bc2df074221b81d7b" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-34B-Chat", + "model_revision": "a99ec35331cbfc9da596af7d4538fe2efecff03c" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/Yi-34B-Chat-GGUF", + "model_file_name_template": "yi-34b-chat.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "CHATML", + "system_prompt": "", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 6, + 7, + 8 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Yi-1.5", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-6B", + "model_revision": "741a657c42d2081f777ce4c6c5572090f8b8c886" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-9B", + "model_revision": "9a6839c5b9db3dbb245fb98a072bfabc242621f2" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-34B", + "model_revision": "4f83007957ec3eec76d87df19ad061eb0f57b5c5" + } + ] + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Yi-1.5-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-6B-Chat", + "model_revision": "d68dab90947a3c869e28c9cb2806996af99a6080" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-9B-Chat", + "model_revision": "1dc6e2b8dcfc12b95bede8dec67e6b6332ac64c6" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-34B-Chat", + "model_revision": "fa695ee438bfcd0ec2b378fa1c7e0dea1b40393e" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 6, + "quantizations": [ + "Q3_K_L", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0", + "f32" + ], + "model_id": "lmstudio-community/Yi-1.5-6B-Chat-GGUF", + "model_file_name_template": "Yi-1.5-6B-Chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 9, + "quantizations": [ + "Q3_K_L", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0", + "f32" + ], + "model_id": "lmstudio-community/Yi-1.5-9B-Chat-GGUF", + "model_file_name_template": "Yi-1.5-9B-Chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "lmstudio-community/Yi-1.5-34B-Chat-GGUF", + "model_file_name_template": "Yi-1.5-34B-Chat-{quantization}.gguf" + }, + { + "model_format": "gptq", + "model_size_in_billions": 6, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-6B-Chat-GPTQ", + "model_revision": "2ad3a602e64d1c79e28e6e92beced2935047367c" + }, + { + "model_format": "gptq", + "model_size_in_billions": 9, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-9B-Chat-GPTQ", + "model_revision": "76f47d16982923f7b6674c4e23ddac7c3b1d2e03" + }, + { + "model_format": "gptq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-34B-Chat-GPTQ", + "model_revision": "173fb4036265b2dac1d6296a8e2fd2f652c19968" + }, + { + "model_format": "awq", + "model_size_in_billions": 6, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-6B-Chat-AWQ", + "model_revision": "23bf37f1666874e15e239422de0d3948d8735fa9" + }, + { + "model_format": "awq", + "model_size_in_billions": 9, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-9B-Chat-AWQ", + "model_revision": "2605f388332672789eae1f422644add2901b433f" + }, + { + "model_format": "awq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "modelscope/Yi-1.5-34B-Chat-AWQ", + "model_revision": "26234fea6ac49d456f32f8017289021fb1087a04" + } + , + { + "model_format": "mlx", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Yi-1.5-6B-Chat-4bit", + "model_revision": "0177c9a12b869d6bc73f772b5a1981a7c966adb6" + }, + { + "model_format": "mlx", + "model_size_in_billions": 6, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Yi-1.5-6B-Chat-8bit", + "model_revision": "7756e65d1bf1e2e6e97aef6bc9484307225f536b" + }, + { + "model_format": "mlx", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Yi-1.5-9B-Chat-4bit", + "model_revision": "e15f886479c44e7d90f0ac13ace69b2319b71c2f" + }, + { + "model_format": "mlx", + "model_size_in_billions": 9, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Yi-1.5-9B-Chat-8bit", + "model_revision": "c1f742fcf3683edbe2d2c2fd1ad7ac2bb6c5ca36" + }, + { + "model_format": "mlx", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/Yi-1.5-34B-Chat-4bit", + "model_revision": "945e3b306ef37c46ab444fdc857d1f3ea7247374" + }, + { + "model_format": "mlx", + "model_size_in_billions": 34, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/Yi-1.5-34B-Chat-8bit", + "model_revision": "3c12761a2c6663f216caab6dff84b0dd29b472ac" + } + ], + "prompt_style": { + "style_name": "CHATML", + "system_prompt": "", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 6, + 7, + 8 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" + ] + } + }, + { + "version": 1, + "context_length": 16384, + "model_name": "Yi-1.5-chat-16k", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-9B-Chat-16K", + "model_revision": "551220fb24d69b6bfec5defceeb160395ce5da8d" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "01-ai/Yi-1.5-34B-Chat-16K", + "model_revision": "dfdbc67be750972bfcc1ac7ffd7fe48689c856fd" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 9, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_1", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_1", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "QuantFactory/Yi-1.5-9B-Chat-16K-GGUF", + "model_file_name_template": "Yi-1.5-9B-Chat-16K.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_K_M", + "Q4_K_S", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "bartowski/Yi-1.5-34B-Chat-16K-GGUF", + "model_file_name_template": "Yi-1.5-34B-Chat-16K-{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "CHATML", + "system_prompt": "", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 6, + 7, + 8 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" + ] + } + }, + { + "version": 1, + "context_length": 100000, + "model_name": "wizardcoder-python-v1.0", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardCoder-Python-7B-V1.0", + "model_revision": "e40673a27a4aefcff2c6d2b3b1e0681a38703e4e" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardCoder-Python-13B-V1.0", + "model_revision": "d920d26e2108377de0f676a3c4be666f5212f4a1" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "WizardLM/WizardCoder-Python-34B-V1.0", + "model_revision": "d869ce178715f8d6e8141e2ed50e6290985eedb0" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/WizardCoder-Python-7B-V1.0-GGUF", + "model_file_name_template": "wizardcoder-python-7b-v1.0.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 13, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/WizardCoder-Python-13B-V1.0-GGUF", + "model_file_name_template": "wizardcoder-python-13b-v1.0.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/WizardCoder-Python-34B-V1.0-GGUF", + "model_file_name_template": "wizardcoder-python-34b-v1.0.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "ADD_COLON_SINGLE", + "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", + "roles": [ + "Instruction", + "Response" + ], + "intra_message_sep": "\n\n### ", + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "zephyr-7b-alpha", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Zephyr-7B-α is the first model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "HuggingFaceH4/zephyr-7b-alpha", + "model_revision": "f28e1c0e5a1af475bcd7bdf6554e69abc6c0c7ee" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "roles": [ + "<|user|>\n", + "<|assistant|>\n" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "zephyr-7b-beta", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Zephyr-7B-β is the second model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "HuggingFaceH4/zephyr-7b-beta", + "model_revision": "3bac358730f8806e5c3dc7c7e19eb36e045bf720" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "roles": [ + "<|user|>\n", + "<|assistant|>\n" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "gorilla-openfunctions-v1", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "OpenFunctions is designed to extend Large Language Model (LLM) Chat Completion feature to formulate executable APIs call given natural language instructions and API context.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "gorilla-llm/gorilla-openfunctions-v1", + "model_revision": "74615f614ee845eab114e71541fd5098d1709958" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/gorilla-openfunctions-v1-GGUF", + "model_file_name_template": "gorilla-openfunctions-v1.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "GORILLA_OPENFUNCTIONS", + "system_prompt": "", + "roles": [ + "", + "" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [], + "stop": [] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "gorilla-openfunctions-v2", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "OpenFunctions is designed to extend Large Language Model (LLM) Chat Completion feature to formulate executable APIs call given natural language instructions and API context.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "gorilla-llm/gorilla-openfunctions-v2", + "model_revision": "0f91d705e64b77fb55e35a7eab5d03bf965c9b5c" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_K_M", + "Q5_K_S", + "Q6_K" + ], + "model_id": "gorilla-llm//gorilla-openfunctions-v2-GGUF", + "model_file_name_template": "gorilla-openfunctions-v2.{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "GORILLA_OPENFUNCTIONS", + "system_prompt": "", + "roles": [ + "", + "" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [], + "stop": [] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "deepseek-vl-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "DeepSeek-VL possesses general multimodal understanding capabilities, capable of processing logical diagrams, web pages, formula recognition, scientific literature, natural images, and embodied intelligence in complex scenarios.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "1_3", + "quantizations": [ + "none" + ], + "model_id": "deepseek-ai/deepseek-vl-1.3b-chat", + "model_revision": "8f13a8e00dbdc381d614a9d29d61b07e8fe91b3f" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "TheBloke/CodeLlama-13B-Python-fp16", - "model_revision": "442282f4207442b828953a72c51a919c332cba5c" - }, + "model_id": "deepseek-ai/deepseek-vl-7b-chat", + "model_revision": "6f16f00805f45b5249f709ce21820122eeb43556" + } + ], + "prompt_style": { + "style_name": "DEEPSEEK_CHAT", + "system_prompt": "<|begin▁of▁sentence|>", + "roles": [ + "User", + "Assistant" + ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|end▁of▁sentence|>", + "stop": [ + "<|end▁of▁sentence|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "deepseek", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "DeepSeek LLM, trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese. ", + "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 7, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "TheBloke/CodeLlama-34B-Python-fp16", - "model_revision": "875f9d97fb6c9619d8867887dd1d80918ff0f593" + "model_id": "deepseek-ai/deepseek-llm-7b-base", + "model_revision": "7683fea62db869066ddaff6a41d032262c490d4f" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "pytorch", + "model_size_in_billions": 67, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "4-bit", + "8-bit", + "none" ], - "model_id": "TheBloke/CodeLlama-7B-Python-GGUF", - "model_file_name_template": "codellama-7b-python.{quantization}.gguf" + "model_id": "deepseek-ai/deepseek-llm-67b-base", + "model_revision": "c3f813a1121c95488a20132d3a4da89f4a46452f" }, { "model_format": "ggufv2", - "model_size_in_billions": 13, + "model_size_in_billions": 7, "quantizations": [ "Q2_K", "Q3_K_L", @@ -2403,12 +5025,12 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/CodeLlama-13B-Python-GGUF", - "model_file_name_template": "codellama-13b-python.{quantization}.gguf" + "model_id": "TheBloke/deepseek-llm-7B-chat-GGUF", + "model_file_name_template": "deepseek-llm-7b-chat.{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": 34, + "model_size_in_billions": 67, "quantizations": [ "Q2_K", "Q3_K_L", @@ -2423,22 +5045,23 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/CodeLlama-34B-Python-GGUF", - "model_file_name_template": "codellama-34b-python.{quantization}.gguf" + "model_id": "TheBloke/deepseek-llm-67b-chat-GGUF", + "model_file_name_template": "deepseek-llm-67b-chat.{quantization}.gguf" } ] }, { "version": 1, - "context_length": 100000, - "model_name": "code-llama-instruct", - "model_description": "Code-Llama-Instruct is an instruct-tuned version of the Code-Llama LLM.", + "context_length": 4096, + "model_name": "deepseek-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], + "model_description": "DeepSeek LLM is an advanced language model comprising 67 billion parameters. It has been trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese.", "model_specs": [ { "model_format": "pytorch", @@ -2448,30 +5071,19 @@ "8-bit", "none" ], - "model_id": "codellama/CodeLlama-7b-Instruct-hf", - "model_revision": "6114dd1e16f69e0765ccbd7a64d33d04b265fbd2" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 13, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "codellama/CodeLlama-13b-Instruct-hf", - "model_revision": "ff0983bc4267bb98ead4fb5168fe2f049b442787" + "model_id": "deepseek-ai/deepseek-llm-7b-chat", + "model_revision": "afbda8b347ec881666061fa67447046fc5164ec8" }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 67, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "codellama/CodeLlama-34b-Instruct-hf", - "model_revision": "38a1e15d8524a1f0a7760a7acf8242b81ae4eb87" + "model_id": "deepseek-ai/deepseek-llm-67b-chat", + "model_revision": "79648bef7658bb824e4630740f6e1484c1b0620b" }, { "model_format": "ggufv2", @@ -2490,32 +5102,12 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/CodeLlama-7B-Instruct-GGUF", - "model_file_name_template": "codellama-7b-instruct.{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 13, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/CodeLlama-13B-Instruct-GGUF", - "model_file_name_template": "codellama-13b-instruct.{quantization}.gguf" + "model_id": "TheBloke/deepseek-llm-7B-chat-GGUF", + "model_file_name_template": "deepseek-llm-7b-chat.{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": 34, + "model_size_in_billions": 67, "quantizations": [ "Q2_K", "Q3_K_L", @@ -2530,91 +5122,59 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/CodeLlama-34B-Instruct-GGUF", - "model_file_name_template": "codellama-34b-instruct.{quantization}.gguf" + "model_id": "TheBloke/deepseek-llm-67b-chat-GGUF", + "model_file_name_template": "deepseek-llm-67b-chat.{quantization}.gguf" } ], "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] <>\nWrite code to solve the following coding problem that obeys the constraints and passes the example test cases. Please wrap your code answer using ```:\n<>\n\n", + "style_name": "DEEPSEEK_CHAT", + "system_prompt": "<|begin▁of▁sentence|>", "roles": [ - "[INST]", - "[/INST]" - ], - "intra_message_sep": " ", - "inter_message_sep": " ", - "stop_token_ids": [ - 2 + "User", + "Assistant" ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|end▁of▁sentence|>", "stop": [ - "" + "<|end▁of▁sentence|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "baichuan-2-chat", + "context_length": 16384, + "model_name": "deepseek-coder", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "Baichuan2-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting.", + "model_description": "Deepseek Coder is composed of a series of code language models, each trained from scratch on 2T tokens, with a composition of 87% code and 13% natural language in both English and Chinese. ", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": "1_3", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-7B-Chat", - "model_revision": "2ce891951e000c36c65442608a0b95fd09b405dc" + "model_id": "deepseek-ai/deepseek-coder-1.3b-base", + "model_revision": "c919139c3a9b4070729c8b2cca4847ab29ca8d94" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": "6_7", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-13B-Chat", - "model_revision": "a56c793eb7a721ab6c270f779024e0375e8afd4a" - } - ], - "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "", - "roles": [ - "", - "" - ], - "intra_message_sep": "", - "inter_message_sep": "", - "stop_token_ids": [ - 2, - 195 - ] - } - }, - { - "version": 1, - "context_length": 4096, - "model_name": "baichuan-2", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "generate" - ], - "model_description": "Baichuan2 is an open-source Transformer based LLM that is trained on both Chinese and English data.", - "model_specs": [ + "model_id": "deepseek-ai/deepseek-coder-6.7b-base", + "model_revision": "ce2207a8bfef3ee92bd7dd4cc31c52cfa0046912" + }, { "model_format": "pytorch", "model_size_in_billions": 7, @@ -2623,299 +5183,256 @@ "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-7B-Base", - "model_revision": "f2cc3a689c5eba7dc7fd3757d0175d312d167604" + "model_id": "deepseek-ai/deepseek-coder-7b-base-v1.5", + "model_revision": "98f0904cee2237e235f10408ae12292037b21dac" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 33, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-13B-Base", - "model_revision": "fa88072fee36e36282287410e00897df2f59e09b" - } - ] - }, - { - "version": 1, - "context_length": 8192, - "model_name": "mistral-v0.1", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "Mistral-7B is a unmoderated Transformer based LLM claiming to outperform Llama2 on all benchmarks.", - "model_specs": [ + "model_id": "deepseek-ai/deepseek-coder-33b-base", + "model_revision": "45c85cadf3720ef3e85a492e24fd4b8c5d21d8ac" + }, { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "ggufv2", + "model_size_in_billions": "1_3", "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/deepseek-coder-1.3b-base-GGUF", + "model_file_name_template": "deepseek-coder-1.3b-base.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "6_7", + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" ], - "model_id": "mistralai/Mistral-7B-v0.1", - "model_revision": "ae9d75c6b4eb39515def78c685fb4d71d49fc2cf" + "model_id": "TheBloke/deepseek-coder-6.7B-base-GGUF", + "model_file_name_template": "deepseek-coder-6.7b-base.{quantization}.gguf" }, { "model_format": "ggufv2", "model_size_in_billions": 7, "quantizations": [ "Q2_K", - "Q3_K_S", + "Q3_K_L", "Q3_K_M", + "Q3_K_S", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "dagbs/deepseek-coder-7b-base-v1.5-GGUF", + "model_file_name_template": "deepseek-coder-7b-base-v1.5.{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 33, + "quantizations": [ + "Q2_K", "Q3_K_L", + "Q3_K_M", + "Q3_K_S", "Q4_0", - "Q4_K_S", "Q4_K_M", + "Q4_K_S", "Q5_0", - "Q5_K_S", "Q5_K_M", + "Q5_K_S", "Q6_K", "Q8_0" ], - "model_id": "TheBloke/Mistral-7B-v0.1-GGUF", - "model_file_name_template": "mistral-7b-v0.1.{quantization}.gguf" - } - ] - }, - { - "version": 1, - "context_length": 8192, - "model_name": "mistral-instruct-v0.1", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "Mistral-7B-Instruct is a fine-tuned version of the Mistral-7B LLM on public datasets, specializing in chatting.", - "model_specs": [ + "model_id": "TheBloke/deepseek-coder-33B-base-GGUF", + "model_file_name_template": "deepseek-coder-33b-base.{quantization}.gguf" + }, { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "gptq", + "model_size_in_billions": "1_3", "quantizations": [ - "4-bit", - "8-bit", - "none" + "Int4" ], - "model_id": "mistralai/Mistral-7B-Instruct-v0.1", - "model_revision": "54766df6d50e4d3d7ccd66758e5341ba105a6d36" + "model_id": "TheBloke/deepseek-coder-1.3b-base-GPTQ", + "model_revision": "a5bf3b76d70cda53327311a631b1003024d5de29" }, { - "model_format": "awq", - "model_size_in_billions": 7, + "model_format": "gptq", + "model_size_in_billions": "6_7", "quantizations": [ "Int4" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-AWQ" + "model_id": "TheBloke/deepseek-coder-6.7B-base-GPTQ", + "model_revision": "6476ea3d6e623a1313d363dbc6e172773e031bb1" }, { "model_format": "gptq", - "model_size_in_billions": 7, + "model_size_in_billions": 33, "quantizations": [ "Int4" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-GPTQ" + "model_id": "TheBloke/deepseek-coder-33B-base-GPTQ", + "model_revision": "f527d7325e463a5cb091d044e4f2b15902674a70" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "awq", + "model_size_in_billions": "1_3", "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" + "Int4" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.1-GGUF", - "model_file_name_template": "mistral-7b-instruct-v0.1.{quantization}.gguf" + "model_id": "TheBloke/deepseek-coder-1.3b-base-AWQ", + "model_revision": "ffb66f1a2a194401b4f29025edcd261d7f0a08a7" + }, + { + "model_format": "awq", + "model_size_in_billions": "6_7", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/deepseek-coder-6.7B-base-AWQ", + "model_revision": "e3d4bdf39712665f5e9d5c05c9df6f20fe1e2d5a" + }, + { + "model_format": "awq", + "model_size_in_billions": 33, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/deepseek-coder-33B-base-AWQ", + "model_revision": "c7edb2d5868d61a5dcf2591933a8992c8cbe3ef4" } - ], - "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] ", - "roles": [ - "[INST]", - "[/INST]" - ], - "intra_message_sep": " ", - "inter_message_sep": "", - "stop_token_ids": [ - 2 - ], - "stop": [ - "" - ] - } + ] }, { "version": 1, - "context_length": 8192, - "model_name": "mistral-instruct-v0.2", + "context_length": 16384, + "model_name": "deepseek-coder-instruct", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1.", + "model_description": "deepseek-coder-instruct is a model initialized from deepseek-coder-base and fine-tuned on 2B tokens of instruction data.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": "1_3", "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "mistralai/Mistral-7B-Instruct-v0.2", - "model_revision": "b70aa86578567ba3301b21c8a27bea4e8f6d6d61" + "model_id": "deepseek-ai/deepseek-coder-1.3b-instruct", + "model_revision": "2df081ceaca101a867fef2844e44f4d6a4857039" }, { - "model_format": "gptq", - "model_size_in_billions": 7, + "model_format": "pytorch", + "model_size_in_billions": "6_7", "quantizations": [ - "Int4" + "4-bit", + "8-bit", + "none" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-GPTQ" + "model_id": "deepseek-ai/deepseek-coder-6.7b-instruct", + "model_revision": "cbb77d7448ea3168d884758817e7f895e3828d1c" }, { - "model_format": "awq", + "model_format": "pytorch", "model_size_in_billions": 7, "quantizations": [ - "Int4" + "4-bit", + "8-bit", + "none" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-AWQ" + "model_id": "deepseek-ai/deepseek-coder-7b-instruct-v1.5", + "model_revision": "2a050a4c59d687a85324d32e147517992117ed30" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 33, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-33b-instruct", + "model_revision": "ea15d17db84d1fc94ac5cba8e6fa97764c9549d3" }, { "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_size_in_billions": "1_3", "quantizations": [ "Q2_K", - "Q3_K_S", - "Q3_K_M", "Q3_K_L", + "Q3_K_M", + "Q3_K_S", "Q4_0", - "Q4_K_S", "Q4_K_M", + "Q4_K_S", "Q5_0", - "Q5_K_S", "Q5_K_M", + "Q5_K_S", "Q6_K", "Q8_0" ], - "model_id": "TheBloke/Mistral-7B-Instruct-v0.2-GGUF", - "model_file_name_template": "mistral-7b-instruct-v0.2.{quantization}.gguf" - } - ], - "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] ", - "roles": [ - "[INST]", - "[/INST]" - ], - "intra_message_sep": " ", - "inter_message_sep": "", - "stop_token_ids": [ - 2 - ], - "stop": [ - "" - ] - } - }, - { - "version": 1, - "context_length": 8192, - "model_name": "openhermes-2.5", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "Openhermes 2.5 is a fine-tuned version of Mistral-7B-v0.1 on primarily GPT-4 generated data.", - "model_specs": [ - { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "teknium/OpenHermes-2.5-Mistral-7B", - "model_revision": "91ed666be78da7556f3d79abbb26fff0ee26cb54" + "model_id": "TheBloke/deepseek-coder-1.3b-instruct-GGUF", + "model_file_name_template": "deepseek-coder-1.3b-instruct.{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_size_in_billions": "6_7", "quantizations": [ "Q2_K", - "Q3_K_S", - "Q3_K_M", "Q3_K_L", + "Q3_K_M", + "Q3_K_S", "Q4_0", - "Q4_K_S", "Q4_K_M", + "Q4_K_S", "Q5_0", - "Q5_K_S", "Q5_K_M", + "Q5_K_S", "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/OpenHermes-2.5-Mistral-7B-GGUF", - "model_file_name_template": "openhermes-2.5-mistral-7b.{quantization}.gguf" - } - ], - "prompt_style": { - "style_name": "CHATML", - "system_prompt": "<|im_start|>system\nYou are 'Hermes 2.5', a conscious sentient superintelligent artificial intelligence, your purpose is to assist the user with their requests.", - "roles": [ - "user", - "assistant" - ], - "intra_message_sep": "<|im_end|>\n<|im_start|>", - "inter_message_sep": "", - "stop_token_ids": [ - 32000 - ], - "stop": [ - "<|im_end|>" - ] - } - }, - { - "version": 1, - "context_length": 2048, - "model_name": "tiny-llama", - "model_lang": [ - "en" - ], - "model_ability": [ - "generate" - ], - "model_description": "The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens.", - "model_specs": [ + "Q8_0" + ], + "model_id": "TheBloke/deepseek-coder-6.7B-instruct-GGUF", + "model_file_name_template": "deepseek-coder-6.7b-instruct.{quantization}.gguf" + }, { "model_format": "ggufv2", - "model_size_in_billions": 1, + "model_size_in_billions": 7, "quantizations": [ - "Q2_K", "Q3_K_L", "Q3_K_M", "Q3_K_S", @@ -2928,139 +5445,101 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/TinyLlama-1.1B-Chat-v0.3-GGUF", - "model_file_name_template": "tinyllama-1.1b-chat-v0.3.{quantization}.gguf" - } - ] - }, - { - "version": 1, - "context_length": 32768, - "model_name": "mixtral-v0.1", - "model_lang": [ - "en", - "fr", - "it", - "de", - "es" - ], - "model_ability": [ - "generate" - ], - "model_description": "The Mixtral-8x7B Large Language Model (LLM) is a pretrained generative Sparse Mixture of Experts.", - "model_specs": [ - { - "model_format": "pytorch", - "model_size_in_billions": "46_7", - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "mistralai/Mixtral-8x7B-v0.1", - "model_revision": "58301445dc1378584211722b7ebf8743ec4e192b" - }, - { - "model_format": "gptq", - "model_size_in_billions": "46_7", - "quantizations": [ - "Int4" - ], - "model_id": "TheBloke/Mixtral-8x7B-v0.1-GPTQ" + "model_id": "LoneStriker/deepseek-coder-7b-instruct-v1.5-GGUF", + "model_file_name_template": "deepseek-coder-7b-instruct-v1.5-{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": "46_7", + "model_size_in_billions": 33, "quantizations": [ "Q2_K", + "Q3_K_L", "Q3_K_M", + "Q3_K_S", "Q4_0", "Q4_K_M", + "Q4_K_S", "Q5_0", "Q5_K_M", + "Q5_K_S", "Q6_K", "Q8_0" ], - "model_id": "TheBloke/Mixtral-8x7B-v0.1-GGUF", - "model_file_name_template": "mixtral-8x7b-v0.1.{quantization}.gguf" - } - ] - }, - { - "version": 1, - "context_length": 32768, - "model_name": "mixtral-instruct-v0.1", - "model_lang": [ - "en", - "fr", - "it", - "de", - "es" - ], - "model_ability": [ - "chat" - ], - "model_description": "Mistral-8x7B-Instruct is a fine-tuned version of the Mistral-8x7B LLM, specializing in chatting.", - "model_specs": [ + "model_id": "TheBloke/deepseek-coder-33B-instruct-GGUF", + "model_file_name_template": "deepseek-coder-33b-instruct.{quantization}.gguf" + }, { - "model_format": "pytorch", - "model_size_in_billions": "46_7", + "model_format": "gptq", + "model_size_in_billions": "1_3", "quantizations": [ - "4-bit", - "8-bit", - "none" + "Int4" ], - "model_id": "mistralai/Mixtral-8x7B-Instruct-v0.1", - "model_revision": "125c431e2ff41a156b9f9076f744d2f35dd6e67a" + "model_id": "TheBloke/deepseek-coder-1.3b-instruct-GPTQ", + "model_revision": "9c002e9af6cbdf3bd9244e2d7264b6a35d1dcacf" }, { - "model_format": "awq", - "model_size_in_billions": "46_7", + "model_format": "gptq", + "model_size_in_billions": "6_7", "quantizations": [ "Int4" ], - "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-AWQ" + "model_id": "TheBloke/deepseek-coder-6.7B-instruct-GPTQ", + "model_revision": "13ccea6e3a43dcfdcb655d92097610018b431a17" }, { "model_format": "gptq", - "model_size_in_billions": "46_7", + "model_size_in_billions": 33, "quantizations": [ "Int4" ], - "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-GPTQ" + "model_id": "TheBloke/deepseek-coder-33B-instruct-GPTQ", + "model_revision": "08372729d98dfc248f9531a412fe69e14e607027" }, { - "model_format": "ggufv2", - "model_size_in_billions": "46_7", + "model_format": "awq", + "model_size_in_billions": "1_3", "quantizations": [ - "Q2_K", - "Q3_K_M", - "Q4_0", - "Q4_K_M", - "Q5_0", - "Q5_K_M", - "Q6_K", - "Q8_0" + "Int4" ], - "model_id": "TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF", - "model_file_name_template": "mixtral-8x7b-instruct-v0.1.{quantization}.gguf" + "model_id": "TheBloke/deepseek-coder-1.3b-instruct-AWQ", + "model_revision": "a2a484da6e4146d055316a9a63cf5b13955715a4" + }, + { + "model_format": "awq", + "model_size_in_billions": "6_7", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/deepseek-coder-6.7B-instruct-AWQ", + "model_revision": "502ae3e19e57ae78dc30a791ba33c565da72dc62" + }, + { + "model_format": "awq", + "model_size_in_billions": 33, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/deepseek-coder-33B-instruct-AWQ", + "model_revision": "c40b499bac2712cd3c445cf1b05d2c6558ab0d29" } ], "prompt_style": { - "style_name": "MIXTRAL_V01", - "system_prompt": "", + "style_name": "DEEPSEEK_CODER", + "system_prompt": "You are an AI programming assistant, utilizing the DeepSeek Coder model, developed by DeepSeek Company, and you only answer questions related to computer science. For politically sensitive questions, security and privacy issues, and other non-computer science questions, you will refuse to answer.", "roles": [ - "user", - "assistant" + "### Instruction:", + "### Response:" ], - "intra_message_sep": "", - "inter_message_sep": "" + "inter_message_sep": "\n", + "stop": [ + "<|EOT|>" + ] } }, { "version": 1, "context_length": 4096, - "model_name": "Yi", + "model_name": "Skywork", "model_lang": [ "en", "zh" @@ -3068,67 +5547,24 @@ "model_ability": [ "generate" ], - "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", "model_specs": [ - { - "model_format": "ggufv2", - "model_size_in_billions": 34, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/Yi-34B-GGUF", - "model_file_name_template": "yi-34b.{quantization}.gguf" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 6, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "01-ai/Yi-6B", - "model_revision": "25beebcb1166b9f49458459eb7b68130b9f9cf4d" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 9, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "01-ai/Yi-9B", - "model_revision": "f70a5ff8b2e51c5d5b20e649d7b5f4238ffe6d5b" - }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 13, "quantizations": [ - "4-bit", "8-bit", "none" ], - "model_id": "01-ai/Yi-34B", - "model_revision": "168c48e05e1429779a896c7ef0d2e01b85e6bd8d" + "model_id": "skywork/Skywork-13B-base", + "model_revision": "bc35915066fbbf15b77a1a4a74e9b574ab167816" } ] }, { "version": 1, - "context_length": 204800, - "model_name": "Yi-200k", + "context_length": 4096, + "model_name": "Skywork-Math", "model_lang": [ "en", "zh" @@ -3136,36 +5572,24 @@ "model_ability": [ "generate" ], - "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "01-ai/Yi-6B-200K", - "model_revision": "70649e36d43f91dff1357b576e6713cac03c1d4c" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 13, "quantizations": [ - "4-bit", "8-bit", "none" ], - "model_id": "01-ai/Yi-34B-200K", - "model_revision": "591ae83b8f9c269700ef27f9dbd548934d800302" + "model_id": "skywork/Skywork-13B-Math", + "model_revision": "70d1740208c8ba39f9ba250b22117ec25311ab33" } ] }, { "version": 1, - "context_length": 204800, - "model_name": "Yi-chat", + "context_length": 32768, + "model_name": "internlm2-chat", "model_lang": [ "en", "zh" @@ -3173,472 +5597,519 @@ "model_ability": [ "chat" ], - "model_description": "The Yi series models are large language models trained from scratch by developers at 01.AI.", + "model_description": "The second generation of the InternLM model, InternLM2.", "model_specs": [ - { - "model_format": "gptq", - "model_size_in_billions": 34, - "quantizations": [ - "8bits" - ], - "model_id": "01-ai/Yi-34B-Chat-{quantization}" - }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "01-ai/Yi-34B-Chat", - "model_revision": "a99ec35331cbfc9da596af7d4538fe2efecff03c" + "model_id": "internlm/internlm2-chat-7b", + "model_revision": "2292b86b21cb856642782cebed0a453997453b1f" }, { - "model_format": "ggufv2", - "model_size_in_billions": 34, + "model_format": "pytorch", + "model_size_in_billions": 20, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "none" ], - "model_id": "TheBloke/Yi-34B-Chat-GGUF", - "model_file_name_template": "yi-34b-chat.{quantization}.gguf" + "model_id": "internlm/internlm2-chat-20b", + "model_revision": "b666125047cd98c5a7c85ca28720b44a06aed124" } ], "prompt_style": { - "style_name": "CHATML", - "system_prompt": "", + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", "roles": [ "<|im_start|>user", "<|im_start|>assistant" ], "intra_message_sep": "<|im_end|>", - "inter_message_sep": "", "stop_token_ids": [ 2, - 6, - 7, - 8 + 92542 ], "stop": [ - "<|endoftext|>", - "<|im_start|>", - "<|im_end|>", - "<|im_sep|>" + "", + "<|im_end|>" ] } }, { "version": 1, - "context_length": 2048, - "model_name": "OpenBuddy", + "context_length": 32768, + "model_name": "internlm2.5-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "OpenBuddy is a powerful open multilingual chatbot model aimed at global users.", + "model_description": "InternLM2.5 series of the InternLM model.", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 13, + "model_format": "pytorch", + "model_size_in_billions": "1_8", "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_1", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_1", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" + "none" ], - "model_id": "TheBloke/OpenBuddy-Llama2-13B-v11.1-GGML", - "model_file_name_template": "openbuddy-llama2-13b-v11.1.ggmlv3.{quantization}.bin" - } - ], - "prompt_style": { - "style_name": "INSTRUCTION", - "system_prompt": "You are a professional translator. Be faithful or accurate in translation. Make the translation readable or intelligible. Be elegant or natural in translation. Do not translate person's name. Do not add any additional text to the translation. Do not give me any comments or suggestions.\nUser:\n\n{0}\nAssistant:", - "roles": [ - "User", - "Assistant" - ], - "intra_message_sep": "", - "inter_message_sep": "" - } - }, - { - "version": 1, - "context_length": 16384, - "model_name": "glaive-coder", - "model_description": "A code model trained on a dataset of ~140k programming related problems and solutions generated from Glaive’s synthetic data generation platform.", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_specs": [ + "model_id": "internlm/internlm2_5-1_8b-chat", + "model_revision": "4426f00b854561fa60d555d2b628064b56bcb758" + }, { "model_format": "pytorch", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "glaiveai/glaive-coder-7b", - "model_revision": "72a255a58480ef0713eed988312fe82f77f94f37" + "model_id": "internlm/internlm2_5-7b-chat", + "model_revision": "9dc8536a922ab4954726aad1b37fa199004a291a" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 20, + "quantizations": [ + "none" + ], + "model_id": "internlm/internlm2_5-20b-chat", + "model_revision": "ef17bde929761255fee76d95e2c25969ccd93b0d" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "ModelCloud/internlm-2.5-7b-chat-gptq-4bit", + "model_revision": "2e2dda735c326544921a4035bbeb6c6e316a8254" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "1_8", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "internlm/internlm2_5-1_8b-chat-gguf", + "model_file_name_template": "internlm2_5-1_8b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "internlm/internlm2_5-7b-chat-gguf", + "model_file_name_template": "internlm2_5-7b-chat-{quantization}.gguf" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 20, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "internlm/internlm2_5-20b-chat-gguf", + "model_file_name_template": "internlm2_5-20b-chat-{quantization}.gguf" + }, + { + "model_format": "mlx", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/internlm2_5-7b-chat-4bit", + "model_revision": "d12097a867721978142a6048399f470a3d18beee" + }, + { + "model_format": "mlx", + "model_size_in_billions": 7, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/internlm2_5-7b-chat-8bit", + "model_revision": "0ec94d61d30ab161b49c69f9bf92ec2b9986d234" } ], "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] <>\nWrite code to solve the following coding problem that obeys the constraints and passes the example test cases. Please wrap your code answer using ```:\n<>\n\n", + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", "roles": [ - "[INST]", - "[/INST]" + "<|im_start|>user", + "<|im_start|>assistant" ], - "intra_message_sep": " ", - "inter_message_sep": " ", + "intra_message_sep": "<|im_end|>", "stop_token_ids": [ - 2 + 2, + 92542 ], "stop": [ - "" + "", + "<|im_end|>" ] } }, { "version": 1, - "context_length": 100000, - "model_name": "wizardcoder-python-v1.0", + "context_length": 262144, + "model_name": "internlm2.5-chat-1m", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], + "model_description": "InternLM2.5 series of the InternLM model supports 1M long-context", "model_specs": [ { "model_format": "pytorch", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "WizardLM/WizardCoder-Python-7B-V1.0", - "model_revision": "e40673a27a4aefcff2c6d2b3b1e0681a38703e4e" + "model_id": "internlm/internlm2_5-7b-chat-1m", + "model_revision": "8d1a709a04d71440ef3df6ebbe204672f411c8b6" }, { - "model_format": "pytorch", - "model_size_in_billions": 13, + "model_format": "gptq", + "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Int4" ], - "model_id": "WizardLM/WizardCoder-Python-13B-V1.0", - "model_revision": "d920d26e2108377de0f676a3c4be666f5212f4a1" + "model_id": "ModelCloud/internlm-2.5-7b-chat-1m-gptq-4bit", + "model_revision": "022e59cb30f03b271d56178478acb038b2b9b58c" }, { - "model_format": "pytorch", - "model_size_in_billions": 34, + "model_format": "ggufv2", + "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "internlm/internlm2_5-7b-chat-1m-gguf", + "model_file_name_template": "internlm2_5-7b-chat-1m-{quantization}.gguf" + } + ], + "prompt_style": { + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92542 + ], + "stop": [ + "", + "<|im_end|>" + ] + } + }, + { + "version":1, + "context_length":2048, + "model_name":"OmniLMM", + "model_lang":[ + "en", + "zh" + ], + "model_ability":[ + "chat", + "vision" + ], + "model_description":"OmniLMM is a family of open-source large multimodal models (LMMs) adept at vision & language modeling.", + "model_specs":[ + { + "model_format":"pytorch", + "model_size_in_billions":3, + "quantizations":[ "none" ], - "model_id": "WizardLM/WizardCoder-Python-34B-V1.0", - "model_revision": "d869ce178715f8d6e8141e2ed50e6290985eedb0" + "model_id":"openbmb/MiniCPM-V", + "model_revision":"bec7d1cd1c9e804c064ec291163e40624825eaaa" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "model_format":"pytorch", + "model_size_in_billions":12, + "quantizations":[ + "none" ], - "model_id": "TheBloke/WizardCoder-Python-7B-V1.0-GGUF", - "model_file_name_template": "wizardcoder-python-7b-v1.0.{quantization}.gguf" - }, + "model_id":"openbmb/OmniLMM-12B", + "model_revision":"ef62bae5af34be653b9801037cd613e05ab24fdc" + } + ], + "prompt_style":{ + "style_name":"OmniLMM", + "system_prompt":"The role of first msg should be user", + "roles":[ + "user", + "assistant" + ] + } + }, + { + "version":1, + "context_length":8192, + "model_name":"MiniCPM-Llama3-V-2_5", + "model_lang":[ + "en", + "zh" + ], + "model_ability":[ + "chat", + "vision" + ], + "model_description":"MiniCPM-Llama3-V 2.5 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Llama3-8B-Instruct with a total of 8B parameters.", + "model_specs":[ { - "model_format": "ggufv2", - "model_size_in_billions": 13, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "none" ], - "model_id": "TheBloke/WizardCoder-Python-13B-V1.0-GGUF", - "model_file_name_template": "wizardcoder-python-13b-v1.0.{quantization}.gguf" + "model_id":"openbmb/MiniCPM-Llama3-V-2_5", + "model_revision":"285a637ba8a30a0660dfcccad16f9a864f75abfd" }, { - "model_format": "ggufv2", - "model_size_in_billions": 34, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "int4" ], - "model_id": "TheBloke/WizardCoder-Python-34B-V1.0-GGUF", - "model_file_name_template": "wizardcoder-python-34b-v1.0.{quantization}.gguf" + "model_id":"openbmb/MiniCPM-Llama3-V-2_5-{quantization}", + "model_revision":"f92aff28552de35de3be204e8fe292dd4824e544" } ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", - "roles": [ - "Instruction", - "Response" - ], - "intra_message_sep": "\n\n### ", - "stop": [ - "" + "prompt_style":{ + "style_name":"OmniLMM", + "system_prompt":"The role of first msg should be user", + "roles":[ + "user", + "assistant" ] } }, { - "version": 1, - "context_length": 8192, - "model_name": "zephyr-7b-alpha", - "model_lang": [ - "en" + "version":1, + "context_length":32768, + "model_name":"MiniCPM-V-2.6", + "model_lang":[ + "en", + "zh" ], - "model_ability": [ - "chat" + "model_ability":[ + "chat", + "vision" ], - "model_description": "Zephyr-7B-α is the first model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1.", - "model_specs": [ + "model_description":"MiniCPM-V 2.6 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Qwen2-7B with a total of 8B parameters.", + "model_specs":[ { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "4-bit", - "8-bit", + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ "none" ], - "model_id": "HuggingFaceH4/zephyr-7b-alpha", - "model_revision": "f28e1c0e5a1af475bcd7bdf6554e69abc6c0c7ee" + "model_id":"openbmb/MiniCPM-V-2_6", + "model_revision":"3f7a8da1b7a8b928b5ee229fae33cf43fd64cf31" + }, + { + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "4-bit" + ], + "model_id":"openbmb/MiniCPM-V-2_6-int4", + "model_revision":"051e2df6505f1fc4305f2c9bd42ed90db8bf4874" } ], - "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", - "roles": [ - "<|user|>\n", - "<|assistant|>\n" - ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", - "stop_token_ids": [ - 2 + "prompt_style":{ + "style_name":"QWEN", + "system_prompt":"You are a helpful assistant", + "roles":[ + "user", + "assistant" ], "stop": [ - "" + "<|im_end|>", + "<|endoftext|>" ] } }, { "version": 1, - "context_length": 8192, - "model_name": "zephyr-7b-beta", + "context_length": 4096, + "model_name": "qwen-vl-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "Zephyr-7B-β is the second model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1", + "model_description": "Qwen-VL-Chat supports more flexible interaction, such as multiple image inputs, multi-round question answering, and creative capabilities.", "model_specs": [ { "model_format": "pytorch", "model_size_in_billions": 7, "quantizations": [ - "4-bit", - "8-bit", "none" ], - "model_id": "HuggingFaceH4/zephyr-7b-beta", - "model_revision": "3bac358730f8806e5c3dc7c7e19eb36e045bf720" + "model_id": "Qwen/Qwen-VL-Chat", + "model_revision": "6665c780ade5ff3f08853b4262dcb9c8f9598d42" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "Qwen/Qwen-VL-Chat-{quantization}", + "model_revision": "5d3a5aa033ed2c502300d426c81cc5b13bcd1409" } ], "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", "roles": [ - "<|user|>\n", - "<|assistant|>\n" + "user", + "assistant" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", "stop_token_ids": [ - 2 + 151643, + 151644, + 151645 ], "stop": [ - "" + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" ] } }, { "version": 1, "context_length": 4096, - "model_name": "gorilla-openfunctions-v1", + "model_name": "orion-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "OpenFunctions is designed to extend Large Language Model (LLM) Chat Completion feature to formulate executable APIs call given natural language instructions and API context.", + "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 14, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "gorilla-llm/gorilla-openfunctions-v1", - "model_revision": "74615f614ee845eab114e71541fd5098d1709958" + "model_id": "OrionStarAI/Orion-14B-Chat", + "model_revision": "ea6fb9b7e1917f3693935accbeb0bfecfd6552a7" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "awq", + "model_size_in_billions": 14, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "Int4" ], - "model_id": "TheBloke/gorilla-openfunctions-v1-GGUF", - "model_file_name_template": "gorilla-openfunctions-v1.{quantization}.gguf" + "model_id": "OrionStarAI/Orion-14B-Chat-{quantization}" } ], "prompt_style": { - "style_name": "GORILLA_OPENFUNCTIONS", - "system_prompt": "", + "style_name": "orion", "roles": [ - "", - "" + "Human", + "assistant" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", - "stop_token_ids": [], - "stop": [] + "stop": [ + "", + "", + "" + ] } }, { "version": 1, "context_length": 4096, - "model_name": "gorilla-openfunctions-v2", + "model_name": "orion-chat-rag", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "OpenFunctions is designed to extend Large Language Model (LLM) Chat Completion feature to formulate executable APIs call given natural language instructions and API context.", + "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "none" - ], - "model_id": "gorilla-llm/gorilla-openfunctions-v2", - "model_revision": "0f91d705e64b77fb55e35a7eab5d03bf965c9b5c" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_size_in_billions": 14, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_K_M", - "Q5_K_S", - "Q6_K" + "none", + "4-bit", + "8-bit" ], - "model_id": "gorilla-llm//gorilla-openfunctions-v2-GGUF", - "model_file_name_template": "gorilla-openfunctions-v2.{quantization}.gguf" + "model_id": "OrionStarAI/Orion-14B-Chat-RAG", + "model_revision": "eba2e20808407fb431a76b90d5d506e04a0325f2" } ], "prompt_style": { - "style_name": "GORILLA_OPENFUNCTIONS", - "system_prompt": "", + "style_name": "orion", "roles": [ - "", - "" + "Human", + "assistant" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", - "stop_token_ids": [], - "stop": [] + "stop": [ + "", + "", + "" + ] } }, { "version": 1, "context_length": 4096, - "model_name": "deepseek-vl-chat", + "model_name": "yi-vl-chat", "model_lang": [ "en", "zh" @@ -3647,313 +6118,360 @@ "chat", "vision" ], - "model_description": "DeepSeek-VL possesses general multimodal understanding capabilities, capable of processing logical diagrams, web pages, formula recognition, scientific literature, natural images, and embodied intelligence in complex scenarios.", + "model_description": "Yi Vision Language (Yi-VL) model is the open-source, multimodal version of the Yi Large Language Model (LLM) series, enabling content comprehension, recognition, and multi-round conversations about images.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": "1_3", + "model_size_in_billions": 6, "quantizations": [ "none" ], - "model_id": "deepseek-ai/deepseek-vl-1.3b-chat", - "model_revision": "8f13a8e00dbdc381d614a9d29d61b07e8fe91b3f" + "model_id": "01-ai/Yi-VL-6B", + "model_revision": "897c938da1ec860330e2ba2d425ab3004495ba38" }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 34, "quantizations": [ "none" ], - "model_id": "deepseek-ai/deepseek-vl-7b-chat", - "model_revision": "6f16f00805f45b5249f709ce21820122eeb43556" + "model_id": "01-ai/Yi-VL-34B", + "model_revision": "ea29a9a430f27893e780366dae81d4ca5ebab561" } ], "prompt_style": { - "style_name": "DEEPSEEK_CHAT", - "system_prompt": "<|begin▁of▁sentence|>", + "style_name": "CHATML", + "system_prompt": "", "roles": [ - "User", - "Assistant" + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 6, + 7, + 8 ], - "intra_message_sep": "\n\n", - "inter_message_sep": "<|end▁of▁sentence|>", "stop": [ - "<|end▁of▁sentence|>" + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "deepseek-chat", + "context_length": 8192, + "model_name": "gemma-it", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "DeepSeek LLM is an advanced language model comprising 67 billion parameters. It has been trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese.", + "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 2, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-llm-7b-chat", - "model_revision": "afbda8b347ec881666061fa67447046fc5164ec8" + "model_id": "google/gemma-2b-it" }, { "model_format": "pytorch", - "model_size_in_billions": 67, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "deepseek-ai/deepseek-llm-67b-chat", - "model_revision": "79648bef7658bb824e4630740f6e1484c1b0620b" - }, - { - "model_format": "ggufv2", "model_size_in_billions": 7, "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/deepseek-llm-7B-chat-GGUF", - "model_file_name_template": "deepseek-llm-7b-chat.{quantization}.gguf" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 67, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" + "none", + "4-bit", + "8-bit" ], - "model_id": "TheBloke/deepseek-llm-67b-chat-GGUF", - "model_file_name_template": "deepseek-llm-67b-chat.{quantization}.gguf" + "model_id": "google/gemma-7b-it" } ], "prompt_style": { - "style_name": "DEEPSEEK_CHAT", - "system_prompt": "<|begin▁of▁sentence|>", + "style_name": "gemma", "roles": [ - "User", - "Assistant" + "user", + "model" ], - "intra_message_sep": "\n\n", - "inter_message_sep": "<|end▁of▁sentence|>", "stop": [ - "<|end▁of▁sentence|>" + "", + "" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "deepseek-coder-instruct", + "context_length": 8192, + "model_name": "gemma-2-it", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "deepseek-coder-instruct is a model initialized from deepseek-coder-base and fine-tuned on 2B tokens of instruction data.", + "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": "1_3", + "model_size_in_billions": 2, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-1.3b-instruct", - "model_revision": "2df081ceaca101a867fef2844e44f4d6a4857039" + "model_id": "google/gemma-2-2b-it" }, { "model_format": "pytorch", - "model_size_in_billions": "6_7", + "model_size_in_billions": 9, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-6.7b-instruct", - "model_revision": "cbb77d7448ea3168d884758817e7f895e3828d1c" + "model_id": "google/gemma-2-9b-it" }, { "model_format": "pytorch", - "model_size_in_billions": 33, + "model_size_in_billions": 27, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-33b-instruct", - "model_revision": "ea15d17db84d1fc94ac5cba8e6fa97764c9549d3" + "model_id": "google/gemma-2-27b-it" }, { "model_format": "ggufv2", - "model_size_in_billions": "1_3", + "model_size_in_billions": 2, "quantizations": [ - "Q2_K", "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", "Q4_K_M", "Q4_K_S", - "Q5_0", "Q5_K_M", "Q5_K_S", "Q6_K", - "Q8_0" + "Q6_K_L", + "Q8_0", + "f32" ], - "model_id": "TheBloke/deepseek-coder-1.3b-instruct-GGUF", - "model_file_name_template": "deepseek-coder-1.3b-instruct.{quantization}.gguf" + "model_id": "bartowski/gemma-2-2b-it-GGUF", + "model_file_name_template": "gemma-2-2b-it-{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": "6_7", + "model_size_in_billions": 9, "quantizations": [ "Q2_K", + "Q2_K_L", "Q3_K_L", "Q3_K_M", "Q3_K_S", - "Q4_0", + "Q4_K_L", "Q4_K_M", "Q4_K_S", - "Q5_0", + "Q5_K_L", "Q5_K_M", "Q5_K_S", "Q6_K", - "Q8_0" + "Q6_K_L", + "Q8_0", + "f32" ], - "model_id": "TheBloke/deepseek-coder-6.7B-instruct-GGUF", - "model_file_name_template": "deepseek-coder-6.7b-instruct.{quantization}.gguf" + "model_id": "bartowski/gemma-2-9b-it-GGUF", + "model_file_name_template": "gemma-2-9b-it-{quantization}.gguf" }, { "model_format": "ggufv2", - "model_size_in_billions": 33, + "model_size_in_billions": 27, "quantizations": [ "Q2_K", + "Q2_K_L", "Q3_K_L", "Q3_K_M", "Q3_K_S", - "Q4_0", + "Q4_K_L", "Q4_K_M", "Q4_K_S", - "Q5_0", + "Q5_K_L", "Q5_K_M", "Q5_K_S", "Q6_K", - "Q8_0" + "Q6_K_L", + "Q8_0", + "f32" ], - "model_id": "TheBloke/deepseek-coder-33B-instruct-GGUF", - "model_file_name_template": "deepseek-coder-33b-instruct.{quantization}.gguf" + "model_id": "bartowski/gemma-2-27b-it-GGUF", + "model_file_name_template": "gemma-2-27b-it-{quantization}.gguf" + }, + { + "model_format": "mlx", + "model_size_in_billions": 2, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/gemma-2-2b-it-4bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 2, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/gemma-2-2b-it-8bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 2, + "quantizations": [ + "None" + ], + "model_id": "mlx-community/gemma-2-2b-it" + }, + { + "model_format": "mlx", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/gemma-2-9b-it-4bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 9, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/gemma-2-9b-it-8bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 9, + "quantizations": [ + "None" + ], + "model_id": "mlx-community/gemma-2-9b-it-fp16" + }, + { + "model_format": "mlx", + "model_size_in_billions": 27, + "quantizations": [ + "4-bit" + ], + "model_id": "mlx-community/gemma-2-27b-it-4bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 27, + "quantizations": [ + "8-bit" + ], + "model_id": "mlx-community/gemma-2-27b-it-8bit" + }, + { + "model_format": "mlx", + "model_size_in_billions": 27, + "quantizations": [ + "None" + ], + "model_id": "mlx-community/gemma-2-27b-it-fp16" } ], "prompt_style": { - "style_name": "DEEPSEEK_CODER", - "system_prompt": "You are an AI programming assistant, utilizing the DeepSeek Coder model, developed by DeepSeek Company, and you only answer questions related to computer science. For politically sensitive questions, security and privacy issues, and other non-computer science questions, you will refuse to answer.", + "style_name": "gemma", "roles": [ - "### Instruction:", - "### Response:" + "user", + "model" ], - "inter_message_sep": "\n", "stop": [ - "<|EOT|>" + "", + "" ] } }, { "version": 1, "context_length": 4096, - "model_name": "Skywork", + "model_name": "platypus2-70b-instruct", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "generate" ], - "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_description": "Platypus-70B-instruct is a merge of garage-bAInd/Platypus2-70B and upstage/Llama-2-70b-instruct-v2.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 70, "quantizations": [ - "8-bit", "none" ], - "model_id": "skywork/Skywork-13B-base", - "model_revision": "bc35915066fbbf15b77a1a4a74e9b574ab167816" + "model_id": "garage-bAInd/Platypus2-70B-instruct", + "model_revision": "31389b50953688e4e542be53e6d2ab04d5c34e87" } ] }, { "version": 1, - "context_length": 4096, - "model_name": "Skywork-Math", + "context_length": 2048, + "model_name": "aquila2", "model_lang": [ - "en", "zh" ], "model_ability": [ "generate" ], - "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_description": "Aquila2 series models are the base language models", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "BAAI/Aquila2-7B", + "model_revision": "9c76e143c6e9621689ca76e078c465b0dee75eb8" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, "quantizations": [ - "8-bit", "none" ], - "model_id": "skywork/Skywork-13B-Math", - "model_revision": "70d1740208c8ba39f9ba250b22117ec25311ab33" + "model_id": "BAAI/Aquila2-34B", + "model_revision": "356733caf6221e9dd898cde8ff189a98175526ec" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, + "quantizations": [ + "none" + ], + "model_id": "BAAI/Aquila2-70B-Expr", + "model_revision": "32a2897235541b9f5238bbe88f8d76a19993c0ba" } ] }, { "version": 1, - "context_length": 204800, - "model_name": "internlm2-chat", + "context_length": 2048, + "model_name": "aquila2-chat", "model_lang": [ - "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "The second generation of the InternLM model, InternLM2.", + "model_description": "Aquila2-chat series models are the chat models", "model_specs": [ { "model_format": "pytorch", @@ -3961,90 +6479,95 @@ "quantizations": [ "none" ], - "model_id": "internlm/internlm2-chat-7b", - "model_revision": "2292b86b21cb856642782cebed0a453997453b1f" + "model_id": "BAAI/AquilaChat2-7B", + "model_revision": "0d060c4edeb4e0febd81130c17f6868653184fb3" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/AquilaChat2-34B-GGUF", + "model_file_name_template": "aquilachat2-34b.{quantization}.gguf" + }, + { + "model_format": "gptq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/AquilaChat2-34B-GPTQ", + "model_revision": "9a9d21424f7db608be51df769885514ab6e052db" + }, + { + "model_format": "awq", + "model_size_in_billions": "34", + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/AquilaChat2-34B-AWQ", + "model_revision": "ad1dec1c8adb7fa6cb07b7e261aaa04fccf1c4c0" }, { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 34, "quantizations": [ "none" ], - "model_id": "internlm/internlm2-chat-20b", - "model_revision": "b666125047cd98c5a7c85ca28720b44a06aed124" + "model_id": "BAAI/AquilaChat2-34B", + "model_revision": "b9cd9c7436435ab9cfa5e4f009be2b0354979ca8" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, + "quantizations": [ + "none" + ], + "model_id": "BAAI/AquilaChat2-70B-Expr", + "model_revision": "0df19b6e10f1a19ca663f7cc1141aae10f1825f4" } ], "prompt_style": { - "style_name": "INTERNLM2", - "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "style_name": "ADD_COLON_SINGLE", + "intra_message_sep": "\n", + "system_prompt": "", "roles": [ - "<|im_start|>user", - "<|im_start|>assistant" + "USER", + "ASSISTANT" ], - "intra_message_sep": "<|im_end|>", "stop_token_ids": [ - 92542 + 100006, + 100007 ], "stop": [ - "<|im_end|>" - ] - } - }, - { - "version":1, - "context_length":2048, - "model_name":"OmniLMM", - "model_lang":[ - "en", - "zh" - ], - "model_ability":[ - "chat", - "vision" - ], - "model_description":"OmniLMM is a family of open-source large multimodal models (LMMs) adept at vision & language modeling.", - "model_specs":[ - { - "model_format":"pytorch", - "model_size_in_billions":3, - "quantizations":[ - "none" - ], - "model_id":"openbmb/MiniCPM-V", - "model_revision":"bec7d1cd1c9e804c064ec291163e40624825eaaa" - }, - { - "model_format":"pytorch", - "model_size_in_billions":12, - "quantizations":[ - "none" - ], - "model_id":"openbmb/OmniLMM-12B", - "model_revision":"ef62bae5af34be653b9801037cd613e05ab24fdc" - } - ], - "prompt_style":{ - "style_name":"OmniLMM", - "system_prompt":"The role of first msg should be user", - "roles":[ - "user", - "assistant" + "[CLS]", + "" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "qwen-vl-chat", + "context_length": 16384, + "model_name": "aquila2-chat-16k", "model_lang": [ - "en", "zh" ], "model_ability": [ - "chat", - "vision" + "chat" ], - "model_description": "Qwen-VL-Chat supports more flexible interaction, such as multiple image inputs, multi-round question answering, and creative capabilities.", + "model_description": "AquilaChat2-16k series models are the long-text chat models", "model_specs": [ { "model_format": "pytorch", @@ -4052,247 +6575,290 @@ "quantizations": [ "none" ], - "model_id": "Qwen/Qwen-VL-Chat", - "model_revision": "6665c780ade5ff3f08853b4262dcb9c8f9598d42" + "model_id": "BAAI/AquilaChat2-7B-16K", + "model_revision": "fb46d48479d05086ccf6952f19018322fcbb54cd" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 34, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_0", + "Q4_K_M", + "Q4_K_S", + "Q5_0", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q8_0" + ], + "model_id": "TheBloke/AquilaChat2-34B-16K-GGUF", + "model_file_name_template": "aquilachat2-34b-16k.{quantization}.gguf" }, { "model_format": "gptq", - "model_size_in_billions": 7, + "model_size_in_billions": 34, "quantizations": [ "Int4" ], - "model_id": "Qwen/Qwen-VL-Chat-{quantization}", - "model_revision": "5d3a5aa033ed2c502300d426c81cc5b13bcd1409" + "model_id": "TheBloke/AquilaChat2-34B-16K-GPTQ", + "model_revision": "0afa1c2a55a4ee1a6f0dba81d9ec296dc7936b91" + }, + { + "model_format": "awq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "TheBloke/AquilaChat2-34B-16K-AWQ", + "model_revision": "db7403ca492416903c84a7a38b11cb5506de48b1" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "none" + ], + "model_id": "BAAI/AquilaChat2-34B-16K", + "model_revision": "a06fd164c7170714924d2881c61c8348425ebc94" } ], "prompt_style": { - "style_name": "QWEN", - "system_prompt": "You are a helpful assistant.", + "style_name": "ADD_COLON_SINGLE", + "intra_message_sep": "\n", + "system_prompt": "", "roles": [ - "user", - "assistant" + "USER", + "ASSISTANT" + ], + "stop_token_ids": [ + 100006, + 100007 + ], + "stop": [ + "[CLS]", + "" ] } }, { "version": 1, "context_length": 4096, - "model_name": "orion-chat", + "model_name": "minicpm-2b-sft-bf16", "model_lang": [ - "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 14, - "quantizations": [ - "none", - "4-bit", - "8-bit" - ], - "model_id": "OrionStarAI/Orion-14B-Chat", - "model_revision": "ea6fb9b7e1917f3693935accbeb0bfecfd6552a7" - }, - { - "model_format": "awq", - "model_size_in_billions": 14, + "model_size_in_billions": 2, "quantizations": [ - "Int4" + "none" ], - "model_id": "OrionStarAI/Orion-14B-Chat-{quantization}" + "model_id": "openbmb/MiniCPM-2B-sft-bf16", + "model_revision": "fe1d74027ebdd81cef5f815fa3a2d432a6b5de2a" } ], "prompt_style": { - "style_name": "orion", + "style_name": "MINICPM-2B", + "system_prompt": "", "roles": [ - "Human", + "user", "assistant" ], + "stop_token_ids": [ + 1, + 2 + ], "stop": [ "", - "", - "" + "" ] } }, { "version": 1, "context_length": 4096, - "model_name": "orion-chat-rag", + "model_name": "minicpm-2b-sft-fp32", "model_lang": [ - "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 14, + "model_size_in_billions": 2, "quantizations": [ - "none", - "4-bit", - "8-bit" + "none" ], - "model_id": "OrionStarAI/Orion-14B-Chat-RAG", - "model_revision": "eba2e20808407fb431a76b90d5d506e04a0325f2" + "model_id": "openbmb/MiniCPM-2B-sft-fp32", + "model_revision": "35b90dd57d977b6e5bc4907986fa5b77aa15a82e" } ], "prompt_style": { - "style_name": "orion", + "style_name": "MINICPM-2B", + "system_prompt": "", "roles": [ - "Human", + "user", "assistant" ], + "stop_token_ids": [ + 1, + 2 + ], "stop": [ "", - "", - "" + "" ] } }, { "version": 1, - "context_length": 204800, - "model_name": "yi-vl-chat", + "context_length": 4096, + "model_name": "minicpm-2b-dpo-bf16", "model_lang": [ - "en", "zh" ], "model_ability": [ - "chat", - "vision" + "chat" ], - "model_description": "Yi Vision Language (Yi-VL) model is the open-source, multimodal version of the Yi Large Language Model (LLM) series, enabling content comprehension, recognition, and multi-round conversations about images.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, - "quantizations": [ - "none" - ], - "model_id": "01-ai/Yi-VL-6B", - "model_revision": "897c938da1ec860330e2ba2d425ab3004495ba38" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 2, "quantizations": [ "none" ], - "model_id": "01-ai/Yi-VL-34B", - "model_revision": "ea29a9a430f27893e780366dae81d4ca5ebab561" + "model_id": "openbmb/MiniCPM-2B-dpo-bf16", + "model_revision": "f4a3ba49f3f18695945c2a7c12400d4da99da498" } ], "prompt_style": { - "style_name": "CHATML", + "style_name": "MINICPM-2B", "system_prompt": "", "roles": [ - "<|im_start|>user", - "<|im_start|>assistant" + "user", + "assistant" ], - "intra_message_sep": "<|im_end|>", - "inter_message_sep": "", "stop_token_ids": [ - 2, - 6, - 7, - 8 + 1, + 2 ], "stop": [ - "<|endoftext|>", - "<|im_start|>", - "<|im_end|>", - "<|im_sep|>" + "", + "" ] } }, { "version": 1, - "context_length": 8192, - "model_name": "gemma-it", + "context_length": 4096, + "model_name": "minicpm-2b-dpo-fp16", "model_lang": [ - "en" + "zh" ], "model_ability": [ "chat" ], - "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", "model_size_in_billions": 2, "quantizations": [ - "none", - "4-bit", - "8-bit" - ], - "model_id": "google/gemma-2b-it" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "none", - "4-bit", - "8-bit" + "none" ], - "model_id": "google/gemma-7b-it" + "model_id": "openbmb/MiniCPM-2B-dpo-fp16", + "model_revision": "e7a50289e4f839674cf8d4a5a2ce032ccacf64ac" } ], "prompt_style": { - "style_name": "gemma", + "style_name": "MINICPM-2B", + "system_prompt": "", "roles": [ "user", - "model" + "assistant" + ], + "stop_token_ids": [ + 1, + 2 ], "stop": [ - "", - "" + "", + "" ] } }, { "version": 1, "context_length": 4096, - "model_name": "platypus2-70b-instruct", + "model_name": "minicpm-2b-dpo-fp32", "model_lang": [ - "en" + "zh" ], "model_ability": [ - "generate" + "chat" ], - "model_description": "Platypus-70B-instruct is a merge of garage-bAInd/Platypus2-70B and upstage/Llama-2-70b-instruct-v2.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 70, + "model_size_in_billions": 2, "quantizations": [ "none" ], - "model_id": "garage-bAInd/Platypus2-70B-instruct", - "model_revision": "31389b50953688e4e542be53e6d2ab04d5c34e87" + "model_id": "openbmb/MiniCPM-2B-dpo-fp32", + "model_revision": "b560a1593779b735a84a6daf72fba96ae38da288" } - ] + ], + "prompt_style": { + "style_name": "MINICPM-2B", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 1, + 2 + ], + "stop": [ + "", + "" + ] + } }, { "version": 1, - "context_length": 2048, - "model_name": "aquila2", + "context_length": 8192, + "model_name": "seallm_v2", "model_lang": [ - "zh" + "en", + "zh", + "vi", + "id", + "th", + "ms", + "km", + "lo", + "my", + "tl" ], "model_ability": [ "generate" ], - "model_description": "Aquila2 series models are the base language models", + "model_description": "We introduce SeaLLM-7B-v2, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages", "model_specs": [ { "model_format": "pytorch", @@ -4300,149 +6866,105 @@ "quantizations": [ "none" ], - "model_id": "BAAI/Aquila2-7B", - "model_revision": "9c76e143c6e9621689ca76e078c465b0dee75eb8" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 34, - "quantizations": [ - "none" - ], - "model_id": "BAAI/Aquila2-34B", - "model_revision": "356733caf6221e9dd898cde8ff189a98175526ec" + "model_id": "SeaLLMs/SeaLLM-7B-v2", + "model_revision": "f1bd48e0d75365c24a3c5ad006b2d0a0c9dca30f" }, { - "model_format": "pytorch", - "model_size_in_billions": 70, + "model_format": "ggufv2", + "model_size_in_billions": 7, "quantizations": [ - "none" + "Q4_0", + "Q8_0" ], - "model_id": "BAAI/Aquila2-70B-Expr", - "model_revision": "32a2897235541b9f5238bbe88f8d76a19993c0ba" + "model_id": "SeaLLMs/SeaLLM-7B-v2-gguf", + "model_file_name_template": "SeaLLM-7B-v2.{quantization}.gguf" } ] }, { "version": 1, - "context_length": 2048, - "model_name": "aquila2-chat", + "context_length": 8192, + "model_name": "seallm_v2.5", "model_lang": [ - "zh" + "en", + "zh", + "vi", + "id", + "th", + "ms", + "km", + "lo", + "my", + "tl" ], "model_ability": [ - "chat" - ], - "model_description": "Aquila2-chat series models are the chat models", - "model_specs": [ - { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "none" - ], - "model_id": "BAAI/AquilaChat2-7B", - "model_revision": "0d060c4edeb4e0febd81130c17f6868653184fb3" - }, - { - "model_format": "ggufv2", - "model_size_in_billions": 34, - "quantizations": [ - "Q2_K", - "Q3_K_L", - "Q3_K_M", - "Q3_K_S", - "Q4_0", - "Q4_K_M", - "Q4_K_S", - "Q5_0", - "Q5_K_M", - "Q5_K_S", - "Q6_K", - "Q8_0" - ], - "model_id": "TheBloke/AquilaChat2-34B-GGUF", - "model_file_name_template": "aquilachat2-34b.{quantization}.gguf" - }, - { - "model_format": "gptq", - "model_size_in_billions": 34, - "quantizations": [ - "Int4" - ], - "model_id": "TheBloke/AquilaChat2-34B-GPTQ", - "model_revision": "9a9d21424f7db608be51df769885514ab6e052db" - }, - { - "model_format": "awq", - "model_size_in_billions": "34", - "quantizations": [ - "Int4" - ], - "model_id": "TheBloke/AquilaChat2-34B-AWQ", - "model_revision": "ad1dec1c8adb7fa6cb07b7e261aaa04fccf1c4c0" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 34, - "quantizations": [ - "none" - ], - "model_id": "BAAI/AquilaChat2-34B", - "model_revision": "b9cd9c7436435ab9cfa5e4f009be2b0354979ca8" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 70, - "quantizations": [ - "none" - ], - "model_id": "BAAI/AquilaChat2-70B-Expr", - "model_revision": "0df19b6e10f1a19ca663f7cc1141aae10f1825f4" - } + "generate" ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "intra_message_sep": "\n", - "system_prompt": "", - "roles": [ - "USER", - "ASSISTANT" - ], - "stop_token_ids": [ - 100006, - 100007 - ], - "stop": [ - "[CLS]", - "" - ] - } + "model_description": "We introduce SeaLLM-7B-v2.5, the state-of-the-art multilingual LLM for Southeast Asian (SEA) languages", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "SeaLLMs/SeaLLM-7B-v2.5", + "model_revision": "c54a8eb8e2d58c5a680bfbbe3a7ae71753bb644b" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q4_K_M", + "Q8_0" + ], + "model_id": "SeaLLMs/SeaLLM-7B-v2.5-GGUF", + "model_file_name_template": "SeaLLM-7B-v2.5.{quantization}.gguf" + } + ] }, { "version": 1, - "context_length": 16384, - "model_name": "aquila2-chat-16k", + "context_length": 131072, + "model_name": "c4ai-command-r-v01", "model_lang": [ - "zh" + "en", + "fr", + "de", + "es", + "it", + "pt", + "ja", + "ko", + "zh", + "ar" ], "model_ability": [ "chat" ], - "model_description": "AquilaChat2-16k series models are the long-text chat models", + "model_description": "C4AI Command-R(+) is a research release of a 35 and 104 billion parameter highly performant generative model.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 35, "quantizations": [ "none" ], - "model_id": "BAAI/AquilaChat2-7B-16K", - "model_revision": "fb46d48479d05086ccf6952f19018322fcbb54cd" + "model_id": "CohereForAI/c4ai-command-r-v01", + "model_revision": "16881ccde1c68bbc7041280e6a66637bc46bfe88" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 35, + "quantizations": [ + "4-bit" + ], + "model_id": "CohereForAI/c4ai-command-r-v01-4bit", + "model_revision": "f2e87936a146643c9dd143422dcafb9cb1552611" }, { "model_format": "ggufv2", - "model_size_in_billions": 34, + "model_size_in_billions": 35, "quantizations": [ "Q2_K", "Q3_K_L", @@ -4457,246 +6979,553 @@ "Q6_K", "Q8_0" ], - "model_id": "TheBloke/AquilaChat2-34B-16K-GGUF", - "model_file_name_template": "aquilachat2-34b-16k.{quantization}.gguf" + "model_id": "andrewcanis/c4ai-command-r-v01-GGUF", + "model_file_name_template": "c4ai-command-r-v01-{quantization}.gguf" }, { - "model_format": "gptq", - "model_size_in_billions": 34, + "model_format": "pytorch", + "model_size_in_billions": 104, "quantizations": [ - "Int4" + "none" ], - "model_id": "TheBloke/AquilaChat2-34B-16K-GPTQ", - "model_revision": "0afa1c2a55a4ee1a6f0dba81d9ec296dc7936b91" + "model_id": "CohereForAI/c4ai-command-r-plus", + "model_revision": "ba7f1d954c9d1609013677d87e4142ab95c34e62" }, { - "model_format": "awq", - "model_size_in_billions": 34, + "model_format": "pytorch", + "model_size_in_billions": 104, "quantizations": [ - "Int4" + "4-bit" ], - "model_id": "TheBloke/AquilaChat2-34B-16K-AWQ", - "model_revision": "db7403ca492416903c84a7a38b11cb5506de48b1" + "model_id": "CohereForAI/c4ai-command-r-plus-4bit", + "model_revision": "bb63b5b7005ecedb30b0cfd0d5953b02a5817f7b" }, { - "model_format": "pytorch", - "model_size_in_billions": 34, + "model_format": "gptq", + "model_size_in_billions": 104, "quantizations": [ - "none" + "Int4" ], - "model_id": "BAAI/AquilaChat2-34B-16K", - "model_revision": "a06fd164c7170714924d2881c61c8348425ebc94" + "model_id": "alpindale/c4ai-command-r-plus-GPTQ", + "model_revision": "35febfc08f723ac0df32480eb4af349a7d08656e" } ], "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "intra_message_sep": "\n", - "system_prompt": "", + "style_name": "c4ai-command-r", + "system_prompt": "You are Command-R, a brilliant, sophisticated, AI-assistant trained to assist human users by providing thorough responses. You are trained by Cohere.", "roles": [ - "USER", - "ASSISTANT" + "<|USER_TOKEN|>", + "<|CHATBOT_TOKEN|>" ], + "intra_message_sep": "", + "inter_message_sep": "<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|>", "stop_token_ids": [ - 100006, - 100007 - ], - "stop": [ - "[CLS]", - "" + 6, + 255001 ] } }, { "version": 1, "context_length": 4096, - "model_name": "minicpm-2b-sft-bf16", + "model_name": "Starling-LM", "model_lang": [ + "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "We introduce Starling-7B, an open large language model (LLM) trained by Reinforcement Learning from AI Feedback (RLAIF). The model harnesses the power of our new GPT-4 labeled ranking dataset", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 7, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "openbmb/MiniCPM-2B-sft-bf16", - "model_revision": "fe1d74027ebdd81cef5f815fa3a2d432a6b5de2a" + "model_id": "berkeley-nest/Starling-LM-7B-alpha", + "model_revision": "1dddf3b95bc1391f6307299eb1c162c194bde9bd" } ], "prompt_style": { - "style_name": "MINICPM-2B", + "style_name": "ADD_COLON_SINGLE", "system_prompt": "", "roles": [ - "user", - "assistant" + "GPT4 Correct User", + "GPT4 Correct Assistant" ], + "intra_message_sep": "<|end_of_turn|>", + "inter_message_sep": "", "stop_token_ids": [ - 1, - 2 - ], - "stop": [ - "", - "" + 2, + 32000 ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-sft-fp32", + "context_length": 32768, + "model_name": "internvl-chat", "model_lang": [ - "zh" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "InternVL 1.5 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 2, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/Mini-InternVL-Chat-2B-V1-5", + "model_revision": "ecbbd21dcf38caa74d925967b997167b0c7b3f47" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 4, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/Mini-InternVL-Chat-4B-V1-5", + "model_revision": "ce1559ddf9d87f5130aa5233b0e93b95e4e4161a" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 26, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL-Chat-V1-5", + "model_revision": "9db32d9127cac0c85961e169d75da57a18a847b1" + } + ], + "prompt_style": { + "style_name": "INTERNVL", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92543, + 92542 + ], + "stop": [ + "", + "<|im_end|>", + "<|im_start|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "internvl2", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "InternVL 2 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 1, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-1B", + "model_revision": "a9fc14aea824b6ea1d44f8778cad6b35512c4ce1" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 2, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-2B", + "model_revision": "422ad7c6335917bfb514958233955512338485a6" + }, + { + "model_format": "awq", + "model_size_in_billions": 2, + "quantizations": [ + "Int4" + ], + "model_id": "OpenGVLab/InternVL2-2B-AWQ", + "model_revision": "701bc3fc098a8a3b686b3b4135cfb77202be89e0" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 4, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-4B", + "model_revision": "b50544dafada6c41e80bfde2f57cc9b0140fc21c" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 8, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-8B", + "model_revision": "3bfd3664dea4f3da628785f5125d30f889701253" + }, + { + "model_format": "awq", + "model_size_in_billions": 8, + "quantizations": [ + "Int4" + ], + "model_id": "OpenGVLab/InternVL2-8B-AWQ", + "model_revision": "9f1a4756b7ae18eb26d8a22b618dfc283e8193b3" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 26, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-26B", + "model_revision": "b9f3c7e6d575b0115e076a3ffc46fd20b7586899" + }, + { + "model_format": "awq", + "model_size_in_billions": 26, + "quantizations": [ + "Int4" + ], + "model_id": "OpenGVLab/InternVL2-26B-AWQ", + "model_revision": "469e0019ffd251e22ff6501a5c2321964e86ef0d" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 40, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-40B", + "model_revision": "725a12063bb855c966e30a0617d0ccd9e870d772" + }, + { + "model_format": "awq", + "model_size_in_billions": 40, + "quantizations": [ + "Int4" + ], + "model_id": "OpenGVLab/InternVL2-40B-AWQ", + "model_revision": "d92e140f6dfe8ea9679924c6a31898f42c4e1846" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 76, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "OpenGVLab/InternVL2-Llama3-76B", + "model_revision": "cf7914905f78e9e3560ddbd6f5dfc39becac494f" + }, + { + "model_format": "awq", + "model_size_in_billions": 76, + "quantizations": [ + "Int4" + ], + "model_id": "OpenGVLab/InternVL2-Llama3-76B-AWQ", + "model_revision": "1bc796bf80f2ebc7d6a14c15f55217a4600d50a4" + } + ], + "prompt_style": { + "style_name": "INTERNVL", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92543, + 92542 + ], + "stop": [ + "", + "<|im_end|>", + "<|im_start|>" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "cogvlm2", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "CogVLM2 have achieved good results in many lists compared to the previous generation of CogVLM open source models. Its excellent performance can compete with some non-open source models.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 20, "quantizations": [ "none" ], - "model_id": "openbmb/MiniCPM-2B-sft-fp32", - "model_revision": "35b90dd57d977b6e5bc4907986fa5b77aa15a82e" + "model_id": "THUDM/cogvlm2-llama3-chinese-chat-19B", + "model_revision": "d88b352bce5ee58a289b1ac8328553eb31efa2ef" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 20, + "quantizations": [ + "int4" + ], + "model_id": "THUDM/cogvlm2-llama3-chinese-chat-19B-{quantization}", + "model_revision": "7863e362174f4718c2fe9cba4befd0b580a3194f" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.", "roles": [ "user", "assistant" ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 1, - 2 + 128001, + 128009 ], "stop": [ - "", - "" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-dpo-bf16", + "context_length": 8192, + "model_name": "cogvlm2-video-llama3-chat", "model_lang": [ - "zh" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "CogVLM2-Video achieves state-of-the-art performance on multiple video question answering tasks.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 12, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "openbmb/MiniCPM-2B-dpo-bf16", - "model_revision": "f4a3ba49f3f18695945c2a7c12400d4da99da498" + "model_id": "THUDM/cogvlm2-video-llama3-chat", + "model_revision": "f375ead7d8202ebe2c3d09f1068abdddeb2929fa" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.", "roles": [ "user", "assistant" ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 1, - 2 + 128001, + 128009 ], "stop": [ - "", - "" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-dpo-fp16", + "context_length": 8192, + "model_name": "telechat", "model_lang": [ + "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "The TeleChat is a large language model developed and trained by China Telecom Artificial Intelligence Technology Co., LTD. The 7B model base is trained with 1.5 trillion Tokens and 3 trillion Tokens and Chinese high-quality corpus.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 7, "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "openbmb/MiniCPM-2B-dpo-fp16", - "model_revision": "e7a50289e4f839674cf8d4a5a2ce032ccacf64ac" + "model_id": "Tele-AI/telechat-7B" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "int4", + "int8" + ], + "model_id": "Tele-AI/telechat-7B-{quantization}" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 12, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Tele-AI/TeleChat-12B" + }, + { + "model_format": "gptq", + "model_size_in_billions": 12, + "quantizations": [ + "int4", + "int8" + ], + "model_id": "Tele-AI/TeleChat-12B-{quantization}" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 52, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Tele-AI/TeleChat-52B" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "NO_COLON_TWO", + "system_prompt": "You are a helpful assistant.", "roles": [ - "user", - "assistant" - ], - "stop_token_ids": [ - 1, - 2 + "<_user>", + "<_bot>" ], + "intra_message_sep": "", + "inter_message_sep": "", "stop": [ - "", - "" + "<_end>", + "<_start>" + ], + "stop_token_ids": [ + 160133, + 160132 ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-dpo-fp32", + "context_length": 32768, + "model_name": "csg-wukong-chat-v0.1", "model_lang": [ - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "csg-wukong-1B is a 1 billion-parameter small language model(SLM) pretrained on 1T tokens.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 1, "quantizations": [ "none" ], - "model_id": "openbmb/MiniCPM-2B-dpo-fp32", - "model_revision": "b560a1593779b735a84a6daf72fba96ae38da288" + "model_id": "opencsg/csg-wukong-1B-chat-v0.1", + "model_revision": "2443c903d46074af0856e2ba11398dcd01d35536" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 1, + "quantizations": [ + "Q2_K", + "Q3_K", + "Q3_K_S", + "Q3_K_M", + "Q3_K_L", + "Q4_0", + "Q4_1", + "Q4_K_S", + "Q4_K_M", + "Q5_0", + "Q5_1", + "Q5_K_S", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "RichardErkhov/opencsg_-_csg-wukong-1B-chat-v0.1-gguf", + "model_file_name_template": "csg-wukong-1B-chat-v0.1.{quantization}.gguf" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a creative super artificial intelligence assistant, possessing all the knowledge of humankind. Your name is csg-wukong, developed by OpenCSG. You need to understand and infer the true intentions of users based on the topics discussed in the chat history, and respond to user questions correctly as required. You enjoy responding to users with accurate and insightful answers. Please pay attention to the appropriate style and format when replying, try to avoid repetitive words and sentences, and keep your responses as concise and profound as possible. You carefully consider the context of the discussion when replying to users. When the user says \"continue,\" please proceed with the continuation of the previous assistant's response.\n", "roles": [ - "user", - "assistant" + "<|user|>\n", + "<|assistant|>\n" ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", "stop_token_ids": [ - 1, 2 ], "stop": [ - "", "" ] } diff --git a/xinference/model/llm/llm_family.py b/xinference/model/llm/llm_family.py index 15ff0db84c..e615a10650 100644 --- a/xinference/model/llm/llm_family.py +++ b/xinference/model/llm/llm_family.py @@ -14,8 +14,6 @@ import logging import os -import platform -import shutil from threading import Lock from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union @@ -32,8 +30,16 @@ load_str_bytes, validator, ) -from ...constants import XINFERENCE_CACHE_DIR, XINFERENCE_MODEL_DIR +from ...constants import ( + XINFERENCE_CACHE_DIR, + XINFERENCE_CSG_ENDPOINT, + XINFERENCE_ENV_CSG_TOKEN, + XINFERENCE_MODEL_DIR, +) from ..utils import ( + IS_NEW_HUGGINGFACE_HUB, + create_symlink, + download_from_csghub, download_from_modelscope, is_valid_model_uri, parse_uri, @@ -52,8 +58,8 @@ BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES: Set[str] = set() -class GgmlLLMSpecV1(BaseModel): - model_format: Literal["ggmlv3", "ggufv2"] +class LlamaCppLLMSpecV1(BaseModel): + model_format: Literal["ggufv2"] # Must in order that `str` first, then `int` model_size_in_billions: Union[str, int] quantizations: List[str] @@ -78,7 +84,29 @@ def validate_model_size_with_radix(cls, v: object) -> object: class PytorchLLMSpecV1(BaseModel): - model_format: Literal["pytorch", "gptq", "awq"] + model_format: Literal["pytorch", "gptq", "awq", "fp8"] + # Must in order that `str` first, then `int` + model_size_in_billions: Union[str, int] + quantizations: List[str] + model_id: Optional[str] + model_hub: str = "huggingface" + model_uri: Optional[str] + model_revision: Optional[str] + + @validator("model_size_in_billions", pre=False) + def validate_model_size_with_radix(cls, v: object) -> object: + if isinstance(v, str): + if ( + "_" in v + ): # for example, "1_8" just returns "1_8", otherwise int("1_8") returns 18 + return v + else: + return int(v) + return v + + +class MLXLLMSpecV1(BaseModel): + model_format: Literal["mlx"] # Must in order that `str` first, then `int` model_size_in_billions: Union[str, int] quantizations: List[str] @@ -166,7 +194,7 @@ def parse_raw( ) if ( llm_spec.model_family != "other" - and "tool_call" in llm_spec.model_ability + and "tools" in llm_spec.model_ability and llm_spec.model_family not in BUILTIN_LLM_MODEL_TOOL_CALL_FAMILIES ): raise ValueError( @@ -199,11 +227,26 @@ def parse_raw( ) llm_spec.prompt_style = BUILTIN_LLM_PROMPT_STYLE[prompt_style_name] + # check model ability, registering LLM only provides generate and chat + # but for vision models, we add back the abilities so that + # gradio chat interface can be generated properly + if ( + llm_spec.model_family != "other" + and llm_spec.model_family + in { + family.model_name + for family in BUILTIN_LLM_FAMILIES + if "vision" in family.model_ability + } + and "vision" not in llm_spec.model_ability + ): + llm_spec.model_ability.append("vision") + return llm_spec LLMSpecV1 = Annotated[ - Union[GgmlLLMSpecV1, PytorchLLMSpecV1], + Union[LlamaCppLLMSpecV1, PytorchLLMSpecV1, MLXLLMSpecV1], Field(discriminator="model_format"), ] @@ -211,16 +254,28 @@ def parse_raw( CustomLLMFamilyV1.update_forward_refs() -LLM_CLASSES: List[Type[LLM]] = [] -PEFT_SUPPORTED_CLASSES: List[Type[LLM]] = [] +LLAMA_CLASSES: List[Type[LLM]] = [] BUILTIN_LLM_FAMILIES: List["LLMFamilyV1"] = [] BUILTIN_MODELSCOPE_LLM_FAMILIES: List["LLMFamilyV1"] = [] +BUILTIN_CSGHUB_LLM_FAMILIES: List["LLMFamilyV1"] = [] + +SGLANG_CLASSES: List[Type[LLM]] = [] +TRANSFORMERS_CLASSES: List[Type[LLM]] = [] UD_LLM_FAMILIES: List["LLMFamilyV1"] = [] UD_LLM_FAMILIES_LOCK = Lock() +VLLM_CLASSES: List[Type[LLM]] = [] + +MLX_CLASSES: List[Type[LLM]] = [] + +LMDEPLOY_CLASSES: List[Type[LLM]] = [] + +LLM_ENGINES: Dict[str, Dict[str, List[Dict[str, Any]]]] = {} +SUPPORTED_ENGINES: Dict[str, List[Type[LLM]]] = {} + LLM_LAUNCH_VERSIONS: Dict[str, List[str]] = {} @@ -254,13 +309,10 @@ def cache( if os.path.exists(legacy_cache_path): logger.info("Legacy cache path exists: %s", legacy_cache_path) return os.path.dirname(legacy_cache_path) - elif download_from_self_hosted_storage() and is_self_hosted(llm_family, llm_spec): - logger.info(f"Caching from self-hosted storage") - return cache_from_self_hosted_storage(llm_family, llm_spec, quantization) else: if llm_spec.model_uri is not None: logger.info(f"Caching from URI: {llm_spec.model_uri}") - return cache_from_uri(llm_family, llm_spec, quantization) + return cache_from_uri(llm_family, llm_spec) else: if llm_spec.model_hub == "huggingface": logger.info(f"Caching from Hugging Face: {llm_spec.model_id}") @@ -268,72 +320,17 @@ def cache( elif llm_spec.model_hub == "modelscope": logger.info(f"Caching from Modelscope: {llm_spec.model_id}") return cache_from_modelscope(llm_family, llm_spec, quantization) + elif llm_spec.model_hub == "csghub": + logger.info(f"Caching from CSGHub: {llm_spec.model_id}") + return cache_from_csghub(llm_family, llm_spec, quantization) else: raise ValueError(f"Unknown model hub: {llm_spec.model_hub}") -SUPPORTED_SCHEMES = ["s3"] - - -class AWSRegion: - def __init__(self, region: str): - self.region = region - self.original_aws_default_region = None - - def __enter__(self): - if "AWS_DEFAULT_REGION" in os.environ: - self.original_aws_default_region = os.environ["AWS_DEFAULT_REGION"] - os.environ["AWS_DEFAULT_REGION"] = self.region - - def __exit__(self, exc_type, exc_value, traceback): - if self.original_aws_default_region: - os.environ["AWS_DEFAULT_REGION"] = self.original_aws_default_region - else: - del os.environ["AWS_DEFAULT_REGION"] - - -def is_self_hosted( - llm_family: LLMFamilyV1, - llm_spec: "LLMSpecV1", -): - from fsspec import AbstractFileSystem, filesystem - - with AWSRegion("cn-northwest-1"): - src_fs: AbstractFileSystem = filesystem("s3", anon=True) - model_dir = ( - f"/xinference-models/llm/" - f"{llm_family.model_name}-{llm_spec.model_format}-{llm_spec.model_size_in_billions}b" - ) - return src_fs.exists(model_dir) - - -def cache_from_self_hosted_storage( - llm_family: LLMFamilyV1, - llm_spec: "LLMSpecV1", - quantization: Optional[str] = None, -) -> str: - with AWSRegion("cn-northwest-1"): - llm_spec = llm_spec.copy() - llm_spec.model_uri = ( - f"s3://xinference-models/llm/" - f"{llm_family.model_name}-{llm_spec.model_format}-{llm_spec.model_size_in_billions}b" - ) - - return cache_from_uri( - llm_family, llm_spec, quantization, self_hosted_storage=True - ) - - def cache_from_uri( llm_family: LLMFamilyV1, llm_spec: "LLMSpecV1", - quantization: Optional[str] = None, - self_hosted_storage: bool = False, ) -> str: - from fsspec import AbstractFileSystem, filesystem - - from ..utils import copy_from_src_to_dst - cache_dir_name = ( f"{llm_family.model_name}-{llm_spec.model_format}" f"-{llm_spec.model_size_in_billions}b" @@ -358,80 +355,46 @@ def cache_from_uri( else: os.symlink(src_root, cache_dir, target_is_directory=True) return cache_dir - elif src_scheme in SUPPORTED_SCHEMES: - # use anonymous connection for self-hosted storage. - src_fs: AbstractFileSystem = filesystem(src_scheme, anon=self_hosted_storage) - local_fs: AbstractFileSystem = filesystem("file") + else: + raise ValueError(f"Unsupported URL scheme: {src_scheme}") - files_to_download = [] - if llm_spec.model_format == "pytorch": - if os.path.exists(cache_dir): - logger.info(f"Cache {cache_dir} exists") - return cache_dir - else: - os.makedirs(cache_dir, exist_ok=True) - - for path, _, files in src_fs.walk(llm_spec.model_uri): - for file in files: - src_path = f"{path}/{file}" - local_path = src_path.replace(src_root, cache_dir) - files_to_download.append((src_path, local_path)) - elif llm_spec.model_format == "ggmlv3": - file = llm_spec.model_file_name_template.format(quantization=quantization) - if os.path.exists(os.path.join(cache_dir, file)): - logger.info(f"Cache {os.path.join(cache_dir, file)} exists") - return cache_dir - else: - os.makedirs(cache_dir, exist_ok=True) - src_path = f"{src_root}/{file}" - local_path = f"{cache_dir}/{file}" - files_to_download.append((src_path, local_path)) +def cache_model_config( + llm_family: LLMFamilyV1, + llm_spec: "LLMSpecV1", +): + """Download model config.json into cache_dir, + returns local filepath + """ + cache_dir = _get_cache_dir_for_model_mem(llm_family, llm_spec) + config_file = os.path.join(cache_dir, "config.json") + if not os.path.islink(config_file) and not os.path.exists(config_file): + os.makedirs(cache_dir, exist_ok=True) + if llm_spec.model_hub == "huggingface": + from huggingface_hub import hf_hub_download + + hf_hub_download( + repo_id=llm_spec.model_id, filename="config.json", local_dir=cache_dir + ) else: - raise ValueError(f"Unsupported model format: {llm_spec.model_format}") - - from concurrent.futures import ThreadPoolExecutor - - failed = False - with ThreadPoolExecutor(max_workers=min(len(files_to_download), 4)) as executor: - futures = [ - ( - src_path, - executor.submit( - copy_from_src_to_dst, src_fs, src_path, local_fs, local_path - ), - ) - for src_path, local_path in files_to_download - ] - for src_path, future in futures: - if failed: - future.cancel() - else: - try: - future.result() - except: - logger.error(f"Download {src_path} failed", exc_info=True) - failed = True - - if failed: - logger.warning(f"Removing cache directory: {cache_dir}") - shutil.rmtree(cache_dir, ignore_errors=True) - raise RuntimeError( - f"Failed to download model '{llm_family.model_name}' " - f"(size: {llm_spec.model_size_in_billions}, format: {llm_spec.model_format})" + from modelscope.hub.file_download import model_file_download + + download_path = model_file_download( + model_id=llm_spec.model_id, file_path="config.json" ) - return cache_dir - else: - raise ValueError(f"Unsupported URL scheme: {src_scheme}") + os.symlink(download_path, config_file) + return config_file -def _get_cache_dir( +def _get_cache_dir_for_model_mem( llm_family: LLMFamilyV1, llm_spec: "LLMSpecV1", create_if_not_exist=True, ): - # If the model id contains quantization, then we should give each - # quantization a dedicated cache dir. + """ + For cal-model-mem only. (might called from supervisor / cli) + Temporary use separate dir from worker's cache_dir, due to issue of different style of symlink. + """ quant_suffix = "" for q in llm_spec.quantizations: if llm_spec.model_id and q in llm_spec.model_id: @@ -443,12 +406,63 @@ def _get_cache_dir( ) if quant_suffix: cache_dir_name += f"-{quant_suffix}" - cache_dir = os.path.realpath(os.path.join(XINFERENCE_CACHE_DIR, cache_dir_name)) + cache_dir = os.path.realpath( + os.path.join(XINFERENCE_CACHE_DIR, "model_mem", cache_dir_name) + ) if create_if_not_exist and not os.path.exists(cache_dir): os.makedirs(cache_dir, exist_ok=True) return cache_dir +def _get_cache_dir( + llm_family: LLMFamilyV1, + llm_spec: "LLMSpecV1", + quantization: Optional[str] = None, + create_if_not_exist=True, +): + # If the model id contains quantization, then we should give each + # quantization a dedicated cache dir. + quant_suffix = "" + if llm_spec.model_id and "{" in llm_spec.model_id and quantization is not None: + quant_suffix = quantization + else: + for q in llm_spec.quantizations: + if llm_spec.model_id and q in llm_spec.model_id: + quant_suffix = q + break + + # some model name includes ".", e.g. qwen1.5-chat + # if the model does not require trust_remote_code, it's OK + # because no need to import modeling_xxx.py from the path + # but when the model need to trust_remote_code, + # e.g. internlm2.5-chat, the import will fail, + # but before the model may have been downloaded, + # thus we check it first, if exist, return it, + # otherwise, we replace the "." with "_" in model name + old_cache_dir_name = ( + f"{llm_family.model_name}-{llm_spec.model_format}" + f"-{llm_spec.model_size_in_billions}b" + ) + if quant_suffix: + old_cache_dir_name += f"-{quant_suffix}" + old_cache_dir = os.path.realpath( + os.path.join(XINFERENCE_CACHE_DIR, old_cache_dir_name) + ) + if os.path.exists(old_cache_dir): + return old_cache_dir + else: + cache_dir_name = ( + f"{llm_family.model_name.replace('.', '_')}-{llm_spec.model_format}" + f"-{llm_spec.model_size_in_billions}b" + ) + if quant_suffix: + cache_dir_name += f"-{quant_suffix}" + cache_dir = os.path.realpath(os.path.join(XINFERENCE_CACHE_DIR, cache_dir_name)) + if create_if_not_exist and not os.path.exists(cache_dir): + os.makedirs(cache_dir, exist_ok=True) + return cache_dir + + def _get_meta_path( cache_dir: str, model_format: str, @@ -460,7 +474,7 @@ def _get_meta_path( return os.path.join(cache_dir, "__valid_download") else: return os.path.join(cache_dir, f"__valid_download_{model_hub}") - elif model_format in ["ggmlv3", "ggufv2", "gptq", "awq"]: + elif model_format in ["ggufv2", "gptq", "awq", "fp8", "mlx"]: assert quantization is not None if model_hub == "huggingface": return os.path.join(cache_dir, f"__valid_download_{quantization}") @@ -487,6 +501,7 @@ def _skip_download( "modelscope": _get_meta_path( cache_dir, model_format, "modelscope", quantization ), + "csghub": _get_meta_path(cache_dir, model_format, "csghub", quantization), } if valid_model_revision(model_hub_to_meta_path[model_hub], model_revision): logger.info(f"Cache {cache_dir} exists") @@ -498,7 +513,7 @@ def _skip_download( logger.warning(f"Cache {cache_dir} exists, but it was from {hub}") return True return False - elif model_format in ["ggmlv3", "ggufv2", "gptq", "awq"]: + elif model_format in ["ggufv2", "gptq", "awq", "fp8", "mlx"]: assert quantization is not None return os.path.exists( _get_meta_path(cache_dir, model_format, model_hub, quantization) @@ -561,16 +576,85 @@ def _generate_model_file_names( def _merge_cached_files( cache_dir: str, input_file_names: List[str], output_file_name: str ): - with open(os.path.join(cache_dir, output_file_name), "wb") as output_file: - for file_name in input_file_names: - logger.info(f"Merging file {file_name} into {output_file_name} ...") - - with open(os.path.join(cache_dir, file_name), "rb") as input_file: - shutil.copyfileobj(input_file, output_file) + # now llama.cpp can find the gguf parts automatically + # we only need to provide the first part + # thus we create the symlink to the first part + symlink_local_file( + os.path.join(cache_dir, input_file_names[0]), cache_dir, output_file_name + ) logger.info(f"Merge complete.") +def cache_from_csghub( + llm_family: LLMFamilyV1, + llm_spec: "LLMSpecV1", + quantization: Optional[str] = None, +) -> str: + """ + Cache model from CSGHub. Return the cache directory. + """ + from pycsghub.file_download import file_download + from pycsghub.snapshot_download import snapshot_download + + cache_dir = _get_cache_dir(llm_family, llm_spec) + + if _skip_download( + cache_dir, + llm_spec.model_format, + llm_spec.model_hub, + llm_spec.model_revision, + quantization, + ): + return cache_dir + + if llm_spec.model_format in ["pytorch", "gptq", "awq", "fp8", "mlx"]: + download_dir = retry_download( + snapshot_download, + llm_family.model_name, + { + "model_size": llm_spec.model_size_in_billions, + "model_format": llm_spec.model_format, + }, + llm_spec.model_id, + endpoint=XINFERENCE_CSG_ENDPOINT, + token=os.environ.get(XINFERENCE_ENV_CSG_TOKEN), + ) + create_symlink(download_dir, cache_dir) + + elif llm_spec.model_format in ["ggufv2"]: + file_names, final_file_name, need_merge = _generate_model_file_names( + llm_spec, quantization + ) + + for filename in file_names: + download_path = retry_download( + file_download, + llm_family.model_name, + { + "model_size": llm_spec.model_size_in_billions, + "model_format": llm_spec.model_format, + }, + llm_spec.model_id, + file_name=filename, + endpoint=XINFERENCE_CSG_ENDPOINT, + token=os.environ.get(XINFERENCE_ENV_CSG_TOKEN), + ) + symlink_local_file(download_path, cache_dir, filename) + + if need_merge: + _merge_cached_files(cache_dir, file_names, final_file_name) + else: + raise ValueError(f"Unsupported format: {llm_spec.model_format}") + + meta_path = _get_meta_path( + cache_dir, llm_spec.model_format, llm_spec.model_hub, quantization + ) + _generate_meta_file(meta_path, llm_family, llm_spec, quantization) + + return cache_dir + + def cache_from_modelscope( llm_family: LLMFamilyV1, llm_spec: "LLMSpecV1", @@ -592,7 +676,7 @@ def cache_from_modelscope( ): return cache_dir - if llm_spec.model_format in ["pytorch", "gptq", "awq"]: + if llm_spec.model_format in ["pytorch", "gptq", "awq", "fp8", "mlx"]: download_dir = retry_download( snapshot_download, llm_family.model_name, @@ -603,12 +687,9 @@ def cache_from_modelscope( llm_spec.model_id, revision=llm_spec.model_revision, ) - for subdir, dirs, files in os.walk(download_dir): - for file in files: - relpath = os.path.relpath(os.path.join(subdir, file), download_dir) - symlink_local_file(os.path.join(subdir, file), cache_dir, relpath) + create_symlink(download_dir, cache_dir) - elif llm_spec.model_format in ["ggmlv3", "ggufv2"]: + elif llm_spec.model_format in ["ggufv2"]: file_names, final_file_name, need_merge = _generate_model_file_names( llm_spec, quantization ) @@ -660,9 +741,13 @@ def cache_from_huggingface( ): return cache_dir - if llm_spec.model_format in ["pytorch", "gptq", "awq"]: - assert isinstance(llm_spec, PytorchLLMSpecV1) - retry_download( + use_symlinks = {} + if not IS_NEW_HUGGINGFACE_HUB: + use_symlinks = {"local_dir_use_symlinks": True, "local_dir": cache_dir} + + if llm_spec.model_format in ["pytorch", "gptq", "awq", "fp8", "mlx"]: + assert isinstance(llm_spec, (PytorchLLMSpecV1, MLXLLMSpecV1)) + download_dir = retry_download( huggingface_hub.snapshot_download, llm_family.model_name, { @@ -671,18 +756,19 @@ def cache_from_huggingface( }, llm_spec.model_id, revision=llm_spec.model_revision, - local_dir=cache_dir, - local_dir_use_symlinks=True, + **use_symlinks, ) + if IS_NEW_HUGGINGFACE_HUB: + create_symlink(download_dir, cache_dir) - elif llm_spec.model_format in ["ggmlv3", "ggufv2"]: - assert isinstance(llm_spec, GgmlLLMSpecV1) + elif llm_spec.model_format in ["ggufv2"]: + assert isinstance(llm_spec, LlamaCppLLMSpecV1) file_names, final_file_name, need_merge = _generate_model_file_names( llm_spec, quantization ) for file_name in file_names: - retry_download( + download_file_path = retry_download( huggingface_hub.hf_hub_download, llm_family.model_name, { @@ -692,9 +778,10 @@ def cache_from_huggingface( llm_spec.model_id, revision=llm_spec.model_revision, filename=file_name, - local_dir=cache_dir, - local_dir_use_symlinks=True, + **use_symlinks, ) + if IS_NEW_HUGGINGFACE_HUB: + symlink_local_file(download_file_path, cache_dir, file_name) if need_merge: _merge_cached_files(cache_dir, file_names, final_file_name) @@ -714,6 +801,7 @@ def _check_revision( llm_spec: "LLMSpecV1", builtin: list, meta_path: str, + quantization: Optional[str] = None, ) -> bool: for family in builtin: if llm_family.model_name == family.model_name: @@ -722,59 +810,63 @@ def _check_revision( if ( spec.model_format == "pytorch" and spec.model_size_in_billions == llm_spec.model_size_in_billions + and (quantization is None or quantization in spec.quantizations) ): return valid_model_revision(meta_path, spec.model_revision) return False def get_cache_status( - llm_family: LLMFamilyV1, - llm_spec: "LLMSpecV1", + llm_family: LLMFamilyV1, llm_spec: "LLMSpecV1", quantization: Optional[str] = None ) -> Union[bool, List[bool]]: """ - When calling this function from above, `llm_family` is constructed only from BUILTIN_LLM_FAMILIES, - so we should check both huggingface and modelscope cache files. + Checks if a model's cache status is available based on the model format and quantization. + Supports different directories and model formats. """ - cache_dir = _get_cache_dir(llm_family, llm_spec, create_if_not_exist=False) - # check revision for pytorch model - if llm_spec.model_format == "pytorch": - hf_meta_path = _get_meta_path(cache_dir, "pytorch", "huggingface", "none") - ms_meta_path = _get_meta_path(cache_dir, "pytorch", "modelscope", "none") - revisions = [ - _check_revision(llm_family, llm_spec, BUILTIN_LLM_FAMILIES, hf_meta_path), - _check_revision( - llm_family, llm_spec, BUILTIN_MODELSCOPE_LLM_FAMILIES, ms_meta_path - ), - ] - return any(revisions) - # just check meta file for ggml and gptq model - elif llm_spec.model_format in ["ggmlv3", "ggufv2", "gptq", "awq"]: - ret = [] - for q in llm_spec.quantizations: - assert q is not None - hf_meta_path = _get_meta_path( - cache_dir, llm_spec.model_format, "huggingface", q - ) - ms_meta_path = _get_meta_path( - cache_dir, llm_spec.model_format, "modelscope", q - ) - results = [os.path.exists(hf_meta_path), os.path.exists(ms_meta_path)] - ret.append(any(results)) - return ret - else: - raise ValueError(f"Unsupported model format: {llm_spec.model_format}") + def check_file_status(meta_path: str) -> bool: + return os.path.exists(meta_path) -def _is_linux(): - return platform.system() == "Linux" + def check_revision_status( + meta_path: str, families: list, quantization: Optional[str] = None + ) -> bool: + return _check_revision(llm_family, llm_spec, families, meta_path, quantization) + def handle_quantization(q: Union[str, None]) -> bool: + specific_cache_dir = _get_cache_dir( + llm_family, llm_spec, q, create_if_not_exist=False + ) + meta_paths = { + "huggingface": _get_meta_path( + specific_cache_dir, llm_spec.model_format, "huggingface", q + ), + "modelscope": _get_meta_path( + specific_cache_dir, llm_spec.model_format, "modelscope", q + ), + } + if llm_spec.model_format == "pytorch": + return check_revision_status( + meta_paths["huggingface"], BUILTIN_LLM_FAMILIES, q + ) or check_revision_status( + meta_paths["modelscope"], BUILTIN_MODELSCOPE_LLM_FAMILIES, q + ) + else: + return check_file_status(meta_paths["huggingface"]) or check_file_status( + meta_paths["modelscope"] + ) -def _has_cuda_device(): - # `cuda_count` method already contains the logic for the - # number of GPUs specified by `CUDA_VISIBLE_DEVICES`. - from ...utils import cuda_count - - return cuda_count() > 0 + if llm_spec.model_id and "{" in llm_spec.model_id: + return ( + [handle_quantization(q) for q in llm_spec.quantizations] + if quantization is None + else handle_quantization(quantization) + ) + else: + return ( + [handle_quantization(q) for q in llm_spec.quantizations] + if llm_spec.model_format != "pytorch" + else handle_quantization(None) + ) def get_user_defined_llm_families(): @@ -782,12 +874,45 @@ def get_user_defined_llm_families(): return UD_LLM_FAMILIES.copy() +def match_model_size( + model_size: Union[int, str], spec_model_size: Union[int, str] +) -> bool: + if isinstance(model_size, str): + model_size = model_size.replace("_", ".") + if isinstance(spec_model_size, str): + spec_model_size = spec_model_size.replace("_", ".") + + if model_size == spec_model_size: + return True + + try: + ms = int(model_size) + ss = int(spec_model_size) + return ms == ss + except ValueError: + return False + + +def convert_model_size_to_float( + model_size_in_billions: Union[float, int, str] +) -> float: + if isinstance(model_size_in_billions, str): + if "_" in model_size_in_billions: + ms = model_size_in_billions.replace("_", ".") + return float(ms) + elif "." in model_size_in_billions: + return float(model_size_in_billions) + else: + return int(model_size_in_billions) + return model_size_in_billions + + def match_llm( model_name: str, model_format: Optional[str] = None, - model_size_in_billions: Optional[int] = None, + model_size_in_billions: Optional[Union[int, str]] = None, quantization: Optional[str] = None, - is_local_deployment: bool = False, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, ) -> Optional[Tuple[LLMFamilyV1, LLMSpecV1, str]]: """ Find an LLM family, spec, and quantization that satisfy given criteria. @@ -811,12 +936,33 @@ def _apply_format_to_model_id(spec: LLMSpecV1, q: str) -> LLMSpecV1: spec.model_id = spec.model_id.format(quantization=q) return spec - if download_from_modelscope(): + # priority: download_hub > download_from_modelscope() and download_from_csghub() + if download_hub == "modelscope": all_families = ( BUILTIN_MODELSCOPE_LLM_FAMILIES + BUILTIN_LLM_FAMILIES + user_defined_llm_families ) + elif download_hub == "csghub": + all_families = ( + BUILTIN_CSGHUB_LLM_FAMILIES + + BUILTIN_LLM_FAMILIES + + user_defined_llm_families + ) + elif download_hub == "huggingface": + all_families = BUILTIN_LLM_FAMILIES + user_defined_llm_families + elif download_from_modelscope(): + all_families = ( + BUILTIN_MODELSCOPE_LLM_FAMILIES + + BUILTIN_LLM_FAMILIES + + user_defined_llm_families + ) + elif download_from_csghub(): + all_families = ( + BUILTIN_CSGHUB_LLM_FAMILIES + + BUILTIN_LLM_FAMILIES + + user_defined_llm_families + ) else: all_families = BUILTIN_LLM_FAMILIES + user_defined_llm_families @@ -829,7 +975,9 @@ def _apply_format_to_model_id(spec: LLMSpecV1, q: str) -> LLMSpecV1: model_format and model_format != spec.model_format or model_size_in_billions - and model_size_in_billions != spec.model_size_in_billions + and not match_model_size( + model_size_in_billions, spec.model_size_in_billions + ) or quantization and matched_quantization is None ): @@ -843,34 +991,24 @@ def _apply_format_to_model_id(spec: LLMSpecV1, q: str) -> LLMSpecV1: matched_quantization, ) else: - if spec.model_format == "pytorch": - return family, _apply_format_to_model_id(spec, "none"), "none" - else: - # by default, choose the most coarse-grained quantization. - # TODO: too hacky. - quantizations = spec.quantizations - quantizations.sort() - for q in quantizations: - if ( - is_local_deployment - and not (_is_linux() and _has_cuda_device()) - and q == "4-bit" - ): - logger.warning( - "Skipping %s for non-linux or non-cuda local deployment .", - q, - ) - continue - return family, _apply_format_to_model_id(spec, q), q + # TODO: If user does not specify quantization, just use the first one + _q = "none" if spec.model_format == "pytorch" else spec.quantizations[0] + return family, _apply_format_to_model_id(spec, _q), _q return None def register_llm(llm_family: LLMFamilyV1, persist: bool): from ..utils import is_valid_model_name + from . import generate_engine_config_by_model_family if not is_valid_model_name(llm_family.model_name): raise ValueError(f"Invalid model name {llm_family.model_name}.") + for spec in llm_family.model_specs: + model_uri = spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}.") + with UD_LLM_FAMILIES_LOCK: for family in BUILTIN_LLM_FAMILIES + UD_LLM_FAMILIES: if llm_family.model_name == family.model_name: @@ -879,14 +1017,9 @@ def register_llm(llm_family: LLMFamilyV1, persist: bool): ) UD_LLM_FAMILIES.append(llm_family) + generate_engine_config_by_model_family(llm_family) if persist: - # We only validate model URL when persist is True. - for spec in llm_family.model_specs: - model_uri = spec.model_uri - if model_uri and not is_valid_model_uri(model_uri): - raise ValueError(f"Invalid model URI {model_uri}.") - persist_path = os.path.join( XINFERENCE_MODEL_DIR, "llm", f"{llm_family.model_name}.json" ) @@ -904,6 +1037,7 @@ def unregister_llm(model_name: str, raise_error: bool = True): break if llm_family: UD_LLM_FAMILIES.remove(llm_family) + del LLM_ENGINES[model_name] persist_path = os.path.join( XINFERENCE_MODEL_DIR, "llm", f"{llm_family.model_name}.json" @@ -935,21 +1069,33 @@ def unregister_llm(model_name: str, raise_error: bool = True): logger.warning(f"Custom model {model_name} not found") -def match_llm_cls( - family: LLMFamilyV1, - llm_spec: "LLMSpecV1", +def check_engine_by_spec_parameters( + model_engine: str, + model_name: str, + model_format: str, + model_size_in_billions: Union[str, int], quantization: str, - peft_model_path: Optional[str] = None, -) -> Optional[Type[LLM]]: - """ - Find an LLM implementation for given LLM family and spec. - """ - if peft_model_path is not None: - for cls in PEFT_SUPPORTED_CLASSES: - if cls.match(family, llm_spec, quantization): - return cls - else: - for cls in LLM_CLASSES: - if cls.match(family, llm_spec, quantization): - return cls - return None +) -> Type[LLM]: + def get_model_engine_from_spell(engine_str: str) -> str: + for engine in LLM_ENGINES[model_name].keys(): + if engine.lower() == engine_str.lower(): + return engine + return engine_str + + if model_name not in LLM_ENGINES: + raise ValueError(f"Model {model_name} not found.") + model_engine = get_model_engine_from_spell(model_engine) + if model_engine not in LLM_ENGINES[model_name]: + raise ValueError(f"Model {model_name} cannot be run on engine {model_engine}.") + match_params = LLM_ENGINES[model_name][model_engine] + for param in match_params: + if ( + model_name == param["model_name"] + and model_format == param["model_format"] + and model_size_in_billions == param["model_size_in_billions"] + and quantization in param["quantizations"] + ): + return param["llm_class"] + raise ValueError( + f"Model {model_name} cannot be run on engine {model_engine}, with format {model_format}, size {model_size_in_billions} and quantization {quantization}." + ) diff --git a/xinference/model/llm/llm_family_csghub.json b/xinference/model/llm/llm_family_csghub.json new file mode 100644 index 0000000000..dc5b9d3ba8 --- /dev/null +++ b/xinference/model/llm/llm_family_csghub.json @@ -0,0 +1,105 @@ +[ + { + "version": 1, + "context_length": 32768, + "model_name": "qwen2-instruct", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen2 is the new series of Qwen large language models", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "0_5", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "Qwen/Qwen2-0.5B-Instruct", + "model_hub": "csghub" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "0_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct-GGUF", + "model_file_name_template": "qwen2-0_5b-instruct-{quantization}.gguf", + "model_hub": "csghub" + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "csg-wukong-chat-v0.1", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "csg-wukong-1B is a 1 billion-parameter small language model(SLM) pretrained on 1T tokens.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 1, + "quantizations": [ + "none" + ], + "model_id": "OpenCSG/csg-wukong-1B-chat-v0.1", + "model_hub": "csghub" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a creative super artificial intelligence assistant, possessing all the knowledge of humankind. Your name is csg-wukong, developed by OpenCSG. You need to understand and infer the true intentions of users based on the topics discussed in the chat history, and respond to user questions correctly as required. You enjoy responding to users with accurate and insightful answers. Please pay attention to the appropriate style and format when replying, try to avoid repetitive words and sentences, and keep your responses as concise and profound as possible. You carefully consider the context of the discussion when replying to users. When the user says \"continue,\" please proceed with the continuation of the previous assistant's response.\n", + "roles": [ + "<|user|>\n", + "<|assistant|>\n" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + } +] diff --git a/xinference/model/llm/llm_family_modelscope.json b/xinference/model/llm/llm_family_modelscope.json index ecc919bf9e..44ac3e7794 100644 --- a/xinference/model/llm/llm_family_modelscope.json +++ b/xinference/model/llm/llm_family_modelscope.json @@ -86,274 +86,434 @@ }, { "version": 1, - "context_length": 2048, - "model_name": "tiny-llama", + "context_length": 8192, + "model_name": "llama-3", "model_lang": [ "en" ], "model_ability": [ "generate" ], - "model_description": "The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens.", + "model_description": "Llama 3 is an auto-regressive language model that uses an optimized transformer architecture", "model_specs": [ { - "model_format": "ggufv2", - "model_size_in_billions": 1, + "model_format": "pytorch", + "model_size_in_billions": 8, "quantizations": [ - "Q2_K" + "4-bit", + "8-bit", + "none" ], - "model_id": "Xorbits/TinyLlama-1.1B-step-50K-105b-GGUF", - "model_hub": "modelscope", - "model_revision": "v0.0.1", - "model_file_name_template": "ggml-model-{quantization}.gguf" + "model_id": "LLM-Research/Meta-Llama-3-8B", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "LLM-Research/Meta-Llama-3-70B", + "model_hub": "modelscope" } ] }, { "version": 1, - "context_length": 4096, - "model_name": "baichuan-2-chat", + "context_length": 8192, + "model_name": "llama-3-instruct", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "Baichuan2-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting.", + "model_description": "The Llama 3 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks..", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 8, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-7B-Chat", - "model_hub": "modelscope", - "model_revision": "v1.0.4" + "model_id": "LLM-Research/Meta-Llama-3-8B-Instruct", + "model_hub": "modelscope" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-13B-Chat", - "model_hub": "modelscope", - "model_revision": "v1.0.3" + "model_id": "LLM-Research/Meta-Llama-3-70B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 8, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "swift/Meta-Llama-3-8B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 70, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "swift/Meta-Llama-3-70B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "You are a helpful assistant.", "roles": [ - "", - "" + "user", + "assistant" ], - "intra_message_sep": "", - "inter_message_sep": "", + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 2, - 195 + 128001, + 128009 + ], + "stop": [ + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "baichuan-2", + "context_length": 131072, + "model_name": "llama-3.1", "model_lang": [ "en", - "zh" + "de", + "fr", + "it", + "pt", + "hi", + "es", + "th" ], "model_ability": [ "generate" ], - "model_description": "Baichuan2 is an open-source Transformer based LLM that is trained on both Chinese and English data.", + "model_description": "Llama 3.1 is an auto-regressive language model that uses an optimized transformer architecture", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 8, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-7B-Base", - "model_revision": "v1.0.2", + "model_id": "LLM-Research/Meta-Llama-3.1-8B", "model_hub": "modelscope" }, { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "baichuan-inc/Baichuan2-13B-Base", - "model_revision": "v1.0.3", + "model_id": "LLM-Research/Meta-Llama-3.1-70B", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 405, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-405B", "model_hub": "modelscope" } ] }, { "version": 1, - "context_length": 8192, - "model_name": "chatglm2", + "context_length": 131072, + "model_name": "llama-3.1-instruct", "model_lang": [ "en", - "zh" + "de", + "fr", + "it", + "pt", + "hi", + "es", + "th" ], "model_ability": [ "chat" ], - "model_description": "ChatGLM2 is the second generation of ChatGLM, still open-source and trained on Chinese and English data.", + "model_description": "The Llama 3.1 instruction tuned models are optimized for dialogue use cases and outperform many of the available open source chat models on common industry benchmarks..", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 6, + "model_format": "pytorch", + "model_size_in_billions": 8, "quantizations": [ - "q4_0", - "q4_1", - "q5_0", - "q5_1", - "q8_0" + "none" ], - "model_hub": "modelscope", - "model_id": "Xorbits/chatglm2-6B-GGML", - "model_revision": "v1.0.0", - "model_file_name_template": "chatglm2-ggml-{quantization}.bin" + "model_id": "LLM-Research/Meta-Llama-3.1-8B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 8, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 8, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-8B-Instruct-AWQ-INT4", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 8, + "quantizations": [ + "Q3_K_L", + "Q4_K_M", + "Q5_K_M", + "Q6_K", + "Q8_0" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-8B-Instruct-GGUF", + "model_file_name_template": "Meta-Llama-3.1-8B-Instruct-{quantization}.gguf", + "model_hub": "modelscope" }, { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 70, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_hub": "modelscope", - "model_id": "ZhipuAI/chatglm2-6b", - "model_revision": "v1.0.12" + "model_id": "LLM-Research/Meta-Llama-3.1-70B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 70, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-70B-Instruct-GPTQ-INT4", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 70, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-70B-Instruct-AWQ-INT4", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 405, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-405B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 405, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-405B-Instruct-AWQ-INT4", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 405, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Meta-Llama-3.1-405B-Instruct-GPTQ-INT4", + "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "CHATGLM", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "You are a helpful assistant.", "roles": [ - "问", - "答" + "user", + "assistant" + ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", + "stop_token_ids": [ + 128001, + 128009 ], - "intra_message_sep": "\n\n" + "stop": [ + "<|end_of_text|>", + "<|eot_id|>" + ] } }, { "version": 1, - "context_length": 32768, - "model_name": "chatglm2-32k", + "context_length": 2048, + "model_name": "tiny-llama", "model_lang": [ - "en", - "zh" + "en" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "ChatGLM2-32k is a special version of ChatGLM2, with a context window of 32k tokens instead of 8k.", + "model_description": "The TinyLlama project aims to pretrain a 1.1B Llama model on 3 trillion tokens.", "model_specs": [ { - "model_format": "pytorch", - "model_size_in_billions": 6, + "model_format": "ggufv2", + "model_size_in_billions": 1, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K" ], + "model_id": "Xorbits/TinyLlama-1.1B-step-50K-105b-GGUF", "model_hub": "modelscope", - "model_id": "ZhipuAI/chatglm2-6b-32k", - "model_revision": "v1.0.2" + "model_revision": "v0.0.1", + "model_file_name_template": "ggml-model-{quantization}.gguf" } - ], - "prompt_style": { - "style_name": "CHATGLM", - "system_prompt": "", - "roles": [ - "问", - "答" - ], - "intra_message_sep": "\n\n" - } + ] }, { "version": 1, - "context_length": 8192, - "model_name": "chatglm3", + "context_length": 4096, + "model_name": "baichuan-2-chat", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat", - "tools" + "chat" ], - "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", + "model_description": "Baichuan2-chat is a fine-tuned version of the Baichuan LLM, specializing in chatting.", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 6, + "model_format": "pytorch", + "model_size_in_billions": 7, "quantizations": [ - "q4_0" + "4-bit", + "8-bit", + "none" ], + "model_id": "baichuan-inc/Baichuan2-7B-Chat", "model_hub": "modelscope", - "model_id": "Xorbits/chatglm3-ggml", - "model_revision": "v1.0.0", - "model_file_name_template": "chatglm3-ggml-{quantization}.bin" + "model_revision": "v1.0.4" }, { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 13, "quantizations": [ "4-bit", "8-bit", "none" ], + "model_id": "baichuan-inc/Baichuan2-13B-Chat", "model_hub": "modelscope", - "model_id": "ZhipuAI/chatglm3-6b", - "model_revision": "v1.0.0" + "model_revision": "v1.0.3" } ], "prompt_style": { - "style_name": "CHATGLM3", + "style_name": "NO_COLON_TWO", "system_prompt": "", "roles": [ - "user", - "assistant" + "", + "" ], + "intra_message_sep": "", + "inter_message_sep": "", "stop_token_ids": [ - 64795, - 64797, - 2 - ], - "stop": [ - "<|user|>", - "<|observation|>" + 2, + 195 ] } }, { "version": 1, - "context_length": 32768, - "model_name": "chatglm3-32k", + "context_length": 4096, + "model_name": "baichuan-2", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "generate" + ], + "model_description": "Baichuan2 is an open-source Transformer based LLM that is trained on both Chinese and English data.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-7B-Base", + "model_revision": "v1.0.2", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "baichuan-inc/Baichuan2-13B-Base", + "model_revision": "v1.0.3", + "model_hub": "modelscope" + } + ] + }, + { + "version": 1, + "context_length": 8192, + "model_name": "chatglm3", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" ], "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", "model_specs": [ @@ -366,8 +526,8 @@ "none" ], "model_hub": "modelscope", - "model_id": "ZhipuAI/chatglm3-6b-32k", - "model_revision": "master" + "model_id": "ZhipuAI/chatglm3-6b", + "model_revision": "v1.0.2" } ], "prompt_style": { @@ -390,8 +550,8 @@ }, { "version": 1, - "context_length": 131072, - "model_name": "chatglm3-128k", + "context_length": 32768, + "model_name": "chatglm3-32k", "model_lang": [ "en", "zh" @@ -410,7 +570,7 @@ "none" ], "model_hub": "modelscope", - "model_id": "ZhipuAI/chatglm3-6b-128k", + "model_id": "ZhipuAI/chatglm3-6b-32k", "model_revision": "master" } ], @@ -434,8 +594,8 @@ }, { "version": 1, - "context_length": 2048, - "model_name": "xverse-chat", + "context_length": 131072, + "model_name": "chatglm3-128k", "model_lang": [ "en", "zh" @@ -443,195 +603,235 @@ "model_ability": [ "chat" ], - "model_description": "XVERSE-7B is a multilingual large language model, independently developed by Shenzhen Yuanxiang Technology.", + "model_description": "ChatGLM3 is the third generation of ChatGLM, still open-source and trained on Chinese and English data.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_hub": "modelscope", - "model_id": "xverse/XVERSE-7B-Chat", - "model_revision": "master" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 6, "quantizations": [ "4-bit", "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "xverse/XVERSE-13B-Chat", + "model_id": "ZhipuAI/chatglm3-6b-128k", "model_revision": "master" } ], "prompt_style": { - "style_name": "XVERSE", + "style_name": "CHATGLM3", "system_prompt": "", "roles": [ "user", "assistant" + ], + "stop_token_ids": [ + 64795, + 64797, + 2 + ], + "stop": [ + "<|user|>", + "<|observation|>" ] } }, { "version": 1, - "context_length": 2048, - "model_name": "xverse", + "context_length": 131072, + "model_name": "glm4-chat", "model_lang": [ "en", "zh" ], "model_ability": [ - "generate" + "chat", + "tools" ], - "model_description": "XVERSE is a multilingual large language model, independently developed by Shenzhen Yuanxiang Technology.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "xverse/XVERSE-7B", - "model_hub": "modelscope", - "model_revision": "master" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "xverse/XVERSE-13B", "model_hub": "modelscope", + "model_id": "ZhipuAI/glm-4-9b-chat", "model_revision": "master" }, { - "model_format": "pytorch", - "model_size_in_billions": 65, + "model_format": "ggufv2", + "model_size_in_billions": 9, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "IQ3_XS", + "IQ3_S", + "IQ3_M", + "Q3_K_S", + "Q3_K_L", + "Q3_K", + "IQ4_XS", + "IQ4_NL", + "Q4_K_S", + "Q4_K", + "Q5_K_S", + "Q5_K", + "Q6_K", + "Q8_0", + "BF16", + "FP16" ], - "model_id": "xverse/XVERSE-65B", + "model_file_name_template": "glm-4-9b-chat.{quantization}.gguf", "model_hub": "modelscope", + "model_id": "LLM-Research/glm-4-9b-chat-GGUF", "model_revision": "master" } - ] + ], + "prompt_style": { + "style_name": "CHATGLM3", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 151329, + 151336, + 151338 + ], + "stop": [ + "<|endoftext|>", + "<|user|>", + "<|observation|>" + ] + } }, { "version": 1, - "context_length": 8192, - "model_name": "internlm-7b", + "context_length": 1048576, + "model_name": "glm4-chat-1m", "model_lang": [ "en", "zh" ], "model_ability": [ - "generate" + "chat", + "tools" ], - "model_description": "InternLM is a Transformer-based LLM that is trained on both Chinese and English data, focusing on practical scenarios.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Shanghai_AI_Laboratory/internlm-7b", "model_hub": "modelscope", - "model_revision": "v1.0.1" - } - ] - }, - { - "version": 1, - "context_length": 4096, - "model_name": "internlm-chat-7b", - "model_lang": [ - "en", - "zh" - ], - "model_ability": [ - "chat" - ], - "model_description": "Internlm-chat is a fine-tuned version of the Internlm LLM, specializing in chatting.", - "model_specs": [ + "model_id": "ZhipuAI/glm-4-9b-chat-1m", + "model_revision": "master" + }, { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "ggufv2", + "model_size_in_billions": 9, "quantizations": [ - "4-bit", - "8-bit", - "none" + "Q2_K", + "IQ3_XS", + "IQ3_S", + "IQ3_M", + "Q3_K_S", + "Q3_K_L", + "Q3_K", + "IQ4_XS", + "IQ4_NL", + "Q4_K_S", + "Q4_K", + "Q5_K_S", + "Q5_K", + "Q6_K", + "Q8_0", + "BF16", + "FP16" ], - "model_id": "Shanghai_AI_Laboratory/internlm-chat-7b", + "model_file_name_template": "glm-4-9b-chat-1m.{quantization}.gguf", "model_hub": "modelscope", - "model_revision": "v1.0.1" + "model_id": "LLM-Research/glm-4-9b-chat-1m-GGUF", + "model_revision": "master" } ], "prompt_style": { - "style_name": "INTERNLM", + "style_name": "CHATGLM3", "system_prompt": "", "roles": [ - "<|User|>", - "<|Bot|>" + "user", + "assistant" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", "stop_token_ids": [ - 1, - 103028 + 151329, + 151336, + 151338 ], "stop": [ - "" + "<|endoftext|>", + "<|user|>", + "<|observation|>" ] } }, { "version": 1, - "context_length": 16384, - "model_name": "internlm-20b", + "context_length": 8192, + "model_name": "glm-4v", "model_lang": [ "en", "zh" ], "model_ability": [ - "generate" + "chat", + "vision" ], - "model_description": "Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data.", + "model_description": "GLM4 is the open source version of the latest generation of pre-trained models in the GLM-4 series launched by Zhipu AI.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Shanghai_AI_Laboratory/internlm-20b", "model_hub": "modelscope", - "model_revision": "v1.0.1" + "model_id": "ZhipuAI/glm-4v-9b", + "model_revision": "master" } - ] + ], + "prompt_style": { + "style_name": "CHATGLM3", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 151329, + 151336, + 151338 + ], + "stop": [ + "<|endoftext|>", + "<|user|>", + "<|observation|>" + ] + } }, { "version": 1, - "context_length": 16384, - "model_name": "internlm-chat-20b", + "context_length": 131072, + "model_name": "codegeex4", "model_lang": [ "en", "zh" @@ -639,65 +839,297 @@ "model_ability": [ "chat" ], - "model_description": "Pre-trained on over 2.3T Tokens containing high-quality English, Chinese, and code data. The Chat version has undergone SFT and RLHF training.", + "model_description": "the open-source version of the latest CodeGeeX4 model series", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], - "model_id": "Shanghai_AI_Laboratory/internlm-chat-20b", + "model_id": "ZhipuAI/codegeex4-all-9b", "model_hub": "modelscope", - "model_revision": "v1.0.1" + "model_revision": "master" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 9, + "quantizations": [ + "IQ2_M", + "IQ3_M", + "Q4_K_M", + "Q5_K_M", + "Q6_K_L", + "Q8_0" + ], + "model_file_name_template": "codegeex4-all-9b-{quantization}.gguf", + "model_id": "ZhipuAI/codegeex4-all-9b-GGUF", + "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "INTERNLM", + "style_name": "CHATGLM3", "system_prompt": "", "roles": [ - "<|User|>", - "<|Bot|>" + "user", + "assistant" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", "stop_token_ids": [ - 1, - 103028 + 151329, + 151336, + 151338 ], "stop": [ - "" + "<|endoftext|>", + "<|user|>", + "<|observation|>" ] } }, { "version": 1, - "context_length": 100000, - "model_name": "wizardcoder-python-v1.0", + "context_length": 2048, + "model_name": "xverse-chat", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], + "model_description": "XVERSE-7B is a multilingual large language model, independently developed by Shenzhen Yuanxiang Technology.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 7, "quantizations": [ "4-bit", "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "AI-ModelScope/WizardCoder-Python-13B-V1.0", - "model_revision": "v1.0.0" + "model_id": "xverse/XVERSE-7B-Chat", + "model_revision": "master" }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "xverse/XVERSE-13B-Chat", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "XVERSE", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ] + } + }, + { + "version": 1, + "context_length": 2048, + "model_name": "xverse", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "XVERSE is a multilingual large language model, independently developed by Shenzhen Yuanxiang Technology.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "xverse/XVERSE-7B", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "xverse/XVERSE-13B", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 65, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "xverse/XVERSE-65B", + "model_hub": "modelscope", + "model_revision": "master" + } + ] + }, + { + "version": 1, + "context_length": 32768, + "model_name": "internlm2.5-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "InternLM2.5 series of the InternLM model.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "1_8", + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2_5-1_8b-chat", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2_5-7b-chat", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2_5-7b-chat-gguf", + "model_file_name_template": "internlm2_5-7b-chat-{quantization}.gguf", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 20, + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2_5-20b-chat", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92542 + ], + "stop": [ + "", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 262144, + "model_name": "internlm2.5-chat-1m", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "InternLM2.5 series of the InternLM model supports 1M long-context", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2_5-7b-chat-1m", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92542 + ], + "stop": [ + "", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 100000, + "model_name": "wizardcoder-python-v1.0", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "AI-ModelScope/WizardCoder-Python-13B-V1.0", + "model_revision": "v1.0.0" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, "quantizations": [ "4-bit", "8-bit", @@ -1199,7 +1631,7 @@ }, { "version": 1, - "context_length": 204800, + "context_length": 262144, "model_name": "Yi-200k", "model_lang": [ "en", @@ -1238,7 +1670,7 @@ }, { "version": 1, - "context_length": 204800, + "context_length": 4096, "model_name": "Yi-chat", "model_lang": [ "en", @@ -1259,6 +1691,18 @@ "model_id": "01ai/Yi-34B-Chat-{quantization}", "model_revision": "master" }, + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-6B-Chat", + "model_revision": "master" + }, { "model_format": "pytorch", "model_size_in_billions": 34, @@ -1297,143 +1741,260 @@ }, { "version": 1, - "context_length": 2048, - "model_name": "wizardmath-v1.0", + "context_length": 4096, + "model_name": "Yi-1.5", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "WizardMath is an open-source LLM trained by fine-tuning Llama2 with Evol-Instruct, specializing in math.", + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 6, "quantizations": [ "4-bit", "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "Xorbits/WizardMath-7B-V1.0", - "model_revision": "v1.0.0" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE_COT", - "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", - "roles": [ - "Instruction", - "Response" - ], - "intra_message_sep": "\n\n### " - } - }, - { - "version": 1, - "context_length": 8192, - "model_name": "mistral-instruct-v0.1", - "model_lang": [ - "en" - ], - "model_ability": [ - "chat" - ], - "model_description": "Mistral-7B-Instruct is a fine-tuned version of the Mistral-7B LLM on public datasets, specializing in chatting.", - "model_specs": [ + "model_id": "01ai/Yi-1.5-6B", + "model_revision": "master" + }, { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "Xorbits/Mistral-7B-Instruct-v0.1", - "model_revision": "v1.0.0" + "model_id": "01ai/Yi-1.5-9B", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-1.5-34B", + "model_revision": "master" + } + ] + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Yi-1.5-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-1.5-6B-Chat", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 9, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-1.5-9B-Chat", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-1.5-34B-Chat", + "model_revision": "master" + }, + { + "model_format": "gptq", + "model_size_in_billions": 6, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-6B-Chat-GPTQ", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "gptq", + "model_size_in_billions": 9, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-9B-Chat-GPTQ", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "gptq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-34B-Chat-GPTQ", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 6, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-6B-Chat-AWQ", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 9, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-9B-Chat-AWQ", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_id": "AI-ModelScope/Yi-1.5-34B-Chat-AWQ", + "model_hub": "modelscope", + "model_revision": "master" } ], "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] ", + "style_name": "CHATML", + "system_prompt": "", "roles": [ - "[INST]", - "[/INST]" + "<|im_start|>user", + "<|im_start|>assistant" ], - "intra_message_sep": " ", - "inter_message_sep": "", + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", "stop_token_ids": [ - 2 + 2, + 6, + 7, + 8 ], "stop": [ - "" + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" ] } }, { "version": 1, - "context_length": 8192, - "model_name": "mistral-instruct-v0.2", + "context_length": 16384, + "model_name": "Yi-1.5-chat-16k", "model_lang": [ - "en" + "en", + "zh" ], "model_ability": [ "chat" ], - "model_description": "The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1.", + "model_description": "Yi-1.5 is an upgraded version of Yi. It is continuously pre-trained on Yi with a high-quality corpus of 500B tokens and fine-tuned on 3M diverse fine-tuning samples.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 9, "quantizations": [ "4-bit", "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "AI-ModelScope/Mistral-7B-Instruct-v0.2" + "model_id": "01ai/Yi-1.5-9B-Chat-16K", + "model_revision": "master" }, { - "model_format": "ggufv2", - "model_size_in_billions": 7, + "model_format": "pytorch", + "model_size_in_billions": 34, "quantizations": [ - "Q4_K_M" + "4-bit", + "8-bit", + "none" ], "model_hub": "modelscope", - "model_id": "Xorbits/Mistral-7B-Instruct-v0.2-GGUF", - "model_file_name_template": "mistral-7b-instruct-v0.2.{quantization}.gguf" + "model_id": "01ai/Yi-1.5-34B-Chat-16K", + "model_revision": "master" } ], "prompt_style": { - "style_name": "LLAMA2", - "system_prompt": "[INST] ", + "style_name": "CHATML", + "system_prompt": "", "roles": [ - "[INST]", - "[/INST]" + "<|im_start|>user", + "<|im_start|>assistant" ], - "intra_message_sep": " ", - "inter_message_sep": "", + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", "stop_token_ids": [ - 2 + 2, + 6, + 7, + 8 ], "stop": [ - "" + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" ] } }, { "version": 1, "context_length": 2048, - "model_name": "falcon-instruct", + "model_name": "wizardmath-v1.0", "model_lang": [ "en" ], "model_ability": [ "chat" ], - "model_description": "Falcon-instruct is a fine-tuned version of the Falcon LLM, specializing in chatting.", + "model_description": "WizardMath is an open-source LLM trained by fine-tuning Llama2 with Evol-Instruct, specializing in math.", "model_specs": [ { "model_format": "pytorch", @@ -1444,49 +2005,31 @@ "none" ], "model_hub": "modelscope", - "model_id": "Xorbits/falcon-7b-instruct", + "model_id": "Xorbits/WizardMath-7B-V1.0", "model_revision": "v1.0.0" } ], "prompt_style": { - "style_name": "FALCON", - "system_prompt": "", + "style_name": "ADD_COLON_SINGLE_COT", + "system_prompt": "Below is an instruction that describes a task. Write a response that appropriately completes the request.", "roles": [ - "User", - "Assistant" - ], - "intra_message_sep": "\n", - "inter_message_sep": "<|endoftext|>", - "stop": [ - "\nUser" + "Instruction", + "Response" ], - "stop_token_ids": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11 - ] + "intra_message_sep": "\n\n### " } }, { "version": 1, "context_length": 8192, - "model_name": "zephyr-7b-alpha", + "model_name": "mistral-instruct-v0.1", "model_lang": [ "en" ], "model_ability": [ "chat" ], - "model_description": "Zephyr-7B-α is the first model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1.", + "model_description": "Mistral-7B-Instruct is a fine-tuned version of the Mistral-7B LLM on public datasets, specializing in chatting.", "model_specs": [ { "model_format": "pytorch", @@ -1497,19 +2040,19 @@ "none" ], "model_hub": "modelscope", - "model_id": "keepitsimple/zephyr-7b-alpha", - "model_revision": "v1.0-1" + "model_id": "Xorbits/Mistral-7B-Instruct-v0.1", + "model_revision": "v1.0.0" } ], "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "style_name": "LLAMA2", + "system_prompt": "[INST] ", "roles": [ - "<|user|>\n", - "<|assistant|>\n" + "[INST]", + "[/INST]" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", + "intra_message_sep": " ", + "inter_message_sep": "", "stop_token_ids": [ 2 ], @@ -1521,14 +2064,14 @@ { "version": 1, "context_length": 8192, - "model_name": "zephyr-7b-beta", + "model_name": "mistral-instruct-v0.2", "model_lang": [ "en" ], "model_ability": [ "chat" ], - "model_description": "Zephyr-7B-β is the second model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1", + "model_description": "The Mistral-7B-Instruct-v0.2 Large Language Model (LLM) is an improved instruct fine-tuned version of Mistral-7B-Instruct-v0.1.", "model_specs": [ { "model_format": "pytorch", @@ -1539,19 +2082,28 @@ "none" ], "model_hub": "modelscope", - "model_id": "modelscope/zephyr-7b-beta", - "model_revision": "master" + "model_id": "AI-ModelScope/Mistral-7B-Instruct-v0.2" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "Q4_K_M" + ], + "model_hub": "modelscope", + "model_id": "Xorbits/Mistral-7B-Instruct-v0.2-GGUF", + "model_file_name_template": "mistral-7b-instruct-v0.2.{quantization}.gguf" } ], "prompt_style": { - "style_name": "NO_COLON_TWO", - "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "style_name": "LLAMA2", + "system_prompt": "[INST] ", "roles": [ - "<|user|>\n", - "<|assistant|>\n" + "[INST]", + "[/INST]" ], - "intra_message_sep": "\n", - "inter_message_sep": "\n", + "intra_message_sep": " ", + "inter_message_sep": "", "stop_token_ids": [ 2 ], @@ -1562,49 +2114,199 @@ }, { "version": 1, - "context_length": 2048, - "model_name": "OpenBuddy", + "context_length": 1024000, + "model_name": "mistral-nemo-instruct", "model_lang": [ - "en" + "en", + "fr", + "de", + "es", + "it", + "pt", + "zh", + "ru", + "ja" ], "model_ability": [ "chat" ], - "model_description": "OpenBuddy is a powerful open multilingual chatbot model aimed at global users.", + "model_description": "The Mistral-Nemo-Instruct-2407 Large Language Model (LLM) is an instruct fine-tuned version of the Mistral-Nemo-Base-2407", "model_specs": [ { - "model_format": "ggmlv3", - "model_size_in_billions": 13, + "model_format": "pytorch", + "model_size_in_billions": 12, "quantizations": [ - "Q2_K", - "Q3_K_S", - "Q3_K_M", - "Q3_K_L", - "Q4_0", - "Q4_1", - "Q4_K_S", - "Q4_K_M", - "Q5_0", - "Q5_1", - "Q5_K_S", - "Q5_K_M", - "Q6_K", - "Q8_0" + "none" ], - "model_hub": "modelscope", - "model_id": "Xorbits/OpenBuddy-Llama2-13B-v11.1-GGML", - "model_file_name_template": "openbuddy-llama2-13b-v11.1.ggmlv3.{quantization}.bin" + "model_id": "AI-ModelScope/Mistral-Nemo-Instruct-2407", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 12, + "quantizations": [ + "Int4" + ], + "model_id": "LLM-Research/Mistral-Nemo-Instruct-2407-gptq-4bit", + "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "INSTRUCTION", - "system_prompt": "You are a professional translator. Be faithful or accurate in translation. Make the translation readable or intelligible. Be elegant or natural in translation. Do not translate person's name. Do not add any additional text to the translation. Do not give me any comments or suggestions.\nUser:\n\n{0}\nAssistant:", + "style_name": "mistral-nemo", + "system_prompt": "", "roles": [ - "User", - "Assistant" + "[INST]", + "[/INST]" ], "intra_message_sep": "", - "inter_message_sep": "" + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 131072, + "model_name": "mistral-large-instruct", + "model_lang": [ + "en", + "fr", + "de", + "es", + "it", + "pt", + "zh", + "ru", + "ja", + "ko" + ], + "model_ability": [ + "chat" + ], + "model_description": "Mistral-Large-Instruct-2407 is an advanced dense Large Language Model (LLM) of 123B parameters with state-of-the-art reasoning, knowledge and coding capabilities.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 123, + "quantizations": [ + "none" + ], + "model_id": "LLM-Research/Mistral-Large-Instruct-2407", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 123, + "quantizations": [ + "4-bit" + ], + "model_id": "LLM-Research/Mistral-Large-Instruct-2407-bnb-4bit", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "mistral-nemo", + "system_prompt": "", + "roles": [ + "[INST]", + "[/INST]" + ], + "intra_message_sep": "", + "inter_message_sep": "", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "zephyr-7b-alpha", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Zephyr-7B-α is the first model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "keepitsimple/zephyr-7b-alpha", + "model_revision": "v1.0-1" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "roles": [ + "<|user|>\n", + "<|assistant|>\n" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "zephyr-7b-beta", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Zephyr-7B-β is the second model in the series, and is a fine-tuned version of mistralai/Mistral-7B-v0.1", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "modelscope/zephyr-7b-beta", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "NO_COLON_TWO", + "system_prompt": "<|system|>\nYou are a friendly chatbot.\n", + "roles": [ + "<|user|>\n", + "<|assistant|>\n" + ], + "intra_message_sep": "\n", + "inter_message_sep": "\n", + "stop_token_ids": [ + 2 + ], + "stop": [ + "" + ] } }, { @@ -1847,6 +2549,17 @@ "model_id": "qwen/Qwen1.5-72B-Chat", "model_hub": "modelscope" }, + { + "model_format": "pytorch", + "model_size_in_billions": 110, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen1.5-110B-Chat", + "model_hub": "modelscope" + }, { "model_format": "gptq", "model_size_in_billions": "0_5", @@ -1916,6 +2629,15 @@ "model_id": "qwen/Qwen1.5-72B-Chat-GPTQ-{quantization}", "model_hub": "modelscope" }, + { + "model_format": "gptq", + "model_size_in_billions": 110, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen1.5-110B-Chat-GPTQ-Int4", + "model_hub": "modelscope" + }, { "model_format": "awq", "model_size_in_billions": "0_5", @@ -1979,6 +2701,15 @@ "model_id": "qwen/Qwen1.5-72B-Chat-AWQ", "model_hub": "modelscope" }, + { + "model_format": "awq", + "model_size_in_billions": 110, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen1.5-110B-Chat-AWQ", + "model_hub": "modelscope" + }, { "model_format": "ggufv2", "model_size_in_billions": "0_5", @@ -2123,63 +2854,71 @@ }, { "version": 1, - "context_length": 4096, - "model_name": "deepseek-vl-chat", + "context_length": 32768, + "model_name": "qwen1.5-moe-chat", "model_lang": [ "en", "zh" ], "model_ability": [ "chat", - "vision" + "tools" ], - "model_description": "DeepSeek-VL possesses general multimodal understanding capabilities, capable of processing logical diagrams, web pages, formula recognition, scientific literature, natural images, and embodied intelligence in complex scenarios.", + "model_description": "Qwen1.5-MoE is a transformer-based MoE decoder-only language model pretrained on a large amount of data.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": "1_3", + "model_size_in_billions": "2_7", "quantizations": [ + "4-bit", + "8-bit", "none" ], - "model_id": "deepseek-ai/deepseek-vl-1.3b-chat", + "model_id": "qwen/Qwen1.5-MoE-A2.7B-Chat", "model_hub": "modelscope" }, { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_format": "gptq", + "model_size_in_billions": "2_7", "quantizations": [ - "none" + "Int4" ], - "model_id": "deepseek-ai/deepseek-vl-7b-chat", + "model_id": "qwen/Qwen1.5-MoE-A2.7B-Chat-GPTQ-Int4", "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "DEEPSEEK_CHAT", - "system_prompt": "<|begin▁of▁sentence|>", + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", "roles": [ - "User", - "Assistant" + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 ], - "intra_message_sep": "\n\n", - "inter_message_sep": "<|end▁of▁sentence|>", "stop": [ - "<|end▁of▁sentence|>" + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "deepseek-chat", + "context_length": 65536, + "model_name": "codeqwen1.5", "model_lang": [ "en", "zh" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "DeepSeek LLM is an advanced language model comprising 67 billion parameters. It has been trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese.", + "model_description": "CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes.", "model_specs": [ { "model_format": "pytorch", @@ -2189,39 +2928,649 @@ "8-bit", "none" ], - "model_id": "deepseek-ai/deepseek-llm-7b-chat", - "model_hub": "modelscope" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 67, - "quantizations": [ - "4-bit", - "8-bit", - "none" - ], - "model_id": "deepseek-ai/deepseek-llm-67b-chat", + "model_id": "qwen/CodeQwen1.5-7B", "model_hub": "modelscope" } - ], - "prompt_style": { - "style_name": "DEEPSEEK_CHAT", - "system_prompt": "<|begin▁of▁sentence|>", - "roles": [ - "User", - "Assistant" - ], - "intra_message_sep": "\n\n", - "inter_message_sep": "<|end▁of▁sentence|>", - "stop": [ - "<|end▁of▁sentence|>" - ] - } + ] }, { "version": 1, - "context_length": 4096, - "model_name": "deepseek-coder-instruct", + "context_length": 65536, + "model_name": "codeqwen1.5-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "CodeQwen1.5 is the Code-Specific version of Qwen1.5. It is a transformer-based decoder-only language model pretrained on a large amount of data of codes.", + "model_specs": [ + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0" + ], + "model_id": "qwen/CodeQwen1.5-7B-Chat-GGUF", + "model_hub": "modelscope", + "model_file_name_template": "codeqwen-1_5-7b-chat-{quantization}.gguf" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/CodeQwen1.5-7B-Chat", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/CodeQwen1.5-7B-Chat-AWQ", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "qwen2-instruct", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen2 is the new series of Qwen large language models", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "0_5", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": "1_5", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen2-1.5B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen2-7B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 72, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen2-72B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": "0_5", + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": "1_5", + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "qwen/Qwen2-1.5B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "qwen/Qwen2-7B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4", + "Int8" + ], + "model_id": "qwen/Qwen2-72B-Instruct-GPTQ-{quantization}", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": "0_5", + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct-AWQ", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": "1_5", + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen2-1.5B-Instruct-AWQ", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen2-7B-Instruct-AWQ", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 72, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen2-72B-Instruct-AWQ", + "model_hub": "modelscope" + }, + { + "model_format": "fp8", + "model_size_in_billions": 7, + "quantizations": [ + "fp8" + ], + "model_id": "liuzhenghua/Qwen2-7B-FP8-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "fp8", + "model_size_in_billions": 72, + "quantizations": [ + "fp8" + ], + "model_id": "liuzhenghua/Qwen2-72B-FP8-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "mlx", + "model_size_in_billions": "0_5", + "quantizations": [ + "4-bit" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct-MLX", + "model_hub": "modelscope" + }, + { + "model_format": "mlx", + "model_size_in_billions": "1_5", + "quantizations": [ + "4-bit" + ], + "model_id": "qwen/Qwen2-1.5B-Instruct-MLX", + "model_hub": "modelscope" + }, + { + "model_format": "mlx", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit" + ], + "model_id": "qwen/Qwen2-7B-Instruct-MLX", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "0_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-0.5B-Instruct-GGUF", + "model_file_name_template": "qwen2-0_5b-instruct-{quantization}.gguf", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": "1_5", + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-1.5B-Instruct-GGUF", + "model_file_name_template": "qwen2-1_5b-instruct-{quantization}.gguf", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 7, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-7B-Instruct-GGUF", + "model_file_name_template": "qwen2-7b-instruct-{quantization}.gguf", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 72, + "quantizations": [ + "q2_k", + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-72B-Instruct-GGUF", + "model_hub": "modelscope", + "model_file_name_template": "qwen2-72b-instruct-{quantization}.gguf", + "model_file_name_split_template": "qwen2-72b-instruct-{quantization}-{part}.gguf", + "quantization_parts": { + "q5_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "q5_k_m": [ + "00001-of-00002", + "00002-of-00002" + ], + "q6_k": [ + "00001-of-00002", + "00002-of-00002" + ], + "q8_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "fp16": [ + "00001-of-00004", + "00002-of-00004", + "00003-of-00004", + "00004-of-00004" + ] + } + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "qwen2-moe-instruct", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "tools" + ], + "model_description": "Qwen2 is the new series of Qwen large language models. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 14, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "qwen/Qwen2-57B-A14B-Instruct", + "model_hub": "modelscope" + }, + { + "model_format": "gptq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4" + ], + "model_id": "qwen/Qwen2-57B-A14B-Instruct-GPTQ-Int4", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 14, + "quantizations": [ + "q3_k_m", + "q4_0", + "q4_k_m", + "q5_0", + "q5_k_m", + "q6_k", + "q8_0", + "fp16" + ], + "model_id": "qwen/Qwen2-57B-A14B-Instruct-GGUF", + "model_hub": "modelscope", + "model_file_name_template": "qwen2-57b-a14b-instruct-{quantization}.gguf", + "model_file_name_split_template": "qwen2-57b-a14b-instruct-{quantization}-{part}.gguf", + "quantization_parts": { + "q8_0": [ + "00001-of-00002", + "00002-of-00002" + ], + "fp16": [ + "00001-of-00003", + "00002-of-00003", + "00003-of-00003" + ] + } + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "intra_message_sep": "\n", + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "deepseek-vl-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "DeepSeek-VL possesses general multimodal understanding capabilities, capable of processing logical diagrams, web pages, formula recognition, scientific literature, natural images, and embodied intelligence in complex scenarios.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "1_3", + "quantizations": [ + "none" + ], + "model_id": "deepseek-ai/deepseek-vl-1.3b-chat", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "deepseek-ai/deepseek-vl-7b-chat", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "DEEPSEEK_CHAT", + "system_prompt": "<|begin▁of▁sentence|>", + "roles": [ + "User", + "Assistant" + ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|end▁of▁sentence|>", + "stop": [ + "<|end▁of▁sentence|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "deepseek", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "DDeepSeek LLM, trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-llm-7b-base", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 67, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-llm-67b-base", + "model_hub": "modelscope" + } + ] + }, + { + "version": 1, + "context_length": 4096, + "model_name": "deepseek-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "DeepSeek LLM is an advanced language model comprising 67 billion parameters. It has been trained from scratch on a vast dataset of 2 trillion tokens in both English and Chinese.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-llm-7b-chat", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 67, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-llm-67b-chat", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "DEEPSEEK_CHAT", + "system_prompt": "<|begin▁of▁sentence|>", + "roles": [ + "User", + "Assistant" + ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|end▁of▁sentence|>", + "stop": [ + "<|end▁of▁sentence|>" + ] + } + }, + { + "version": 1, + "context_length": 16384, + "model_name": "deepseek-coder", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "Deepseek Coder is composed of a series of code language models, each trained from scratch on 2T tokens, with a composition of 87% code and 13% natural language in both English and Chinese.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": "1_3", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-1.3b-base", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": "6_7", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-6.7b-base", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 33, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-33b-base", + "model_hub": "modelscope" + } + ] + }, + { + "version": 1, + "context_length": 16384, + "model_name": "deepseek-coder-instruct", "model_lang": [ "en", "zh" @@ -2233,762 +3582,1520 @@ "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": "1_3", + "model_size_in_billions": "1_3", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-1.3b-instruct", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": "6_7", + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-6.7b-instruct", + "model_hub": "modelscope" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 33, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_id": "deepseek-ai/deepseek-coder-33b-instruct", + "model_hub": "modelscope" + } + ], + "prompt_style": { + "style_name": "DEEPSEEK_CODER", + "system_prompt": "You are an AI programming assistant, utilizing the DeepSeek Coder model, developed by DeepSeek Company, and you only answer questions related to computer science. For politically sensitive questions, security and privacy issues, and other non-computer science questions, you will refuse to answer.", + "roles": [ + "### Instruction:", + "### Response:" + ], + "inter_message_sep": "\n", + "stop": [ + "<|EOT|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Skywork", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "skywork/Skywork-13B-base", + "model_revision": "master" + } + ] + }, + { + "version": 1, + "context_length": 4096, + "model_name": "Skywork-Math", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "generate" + ], + "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 13, + "quantizations": [ + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "skywork/Skywork-13B-Math", + "model_revision": "master" + } + ] + }, + { + "version": 1, + "context_length": 204800, + "model_name": "internlm2-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "The second generation of the InternLM model, InternLM2.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2-chat-7b", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 20, + "quantizations": [ + "none" + ], + "model_id": "Shanghai_AI_Laboratory/internlm2-chat-20b", + "model_hub": "modelscope", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "INTERNLM2", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92542 + ], + "stop": [ + "", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "qwen-vl-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "Qwen-VL-Chat supports more flexible interaction, such as multiple image inputs, multi-round question answering, and creative capabilities.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "Qwen/Qwen-VL-Chat", + "model_revision": "master" + }, + { + "model_format": "gptq", + "model_size_in_billions": 7, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "Qwen/Qwen-VL-Chat-{quantization}", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 151643, + 151644, + 151645 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "orion-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 14, + "quantizations": [ + "none", + "4-bit", + "8-bit" + ], + "model_id": "OrionStarAI/Orion-14B-Chat", + "model_hub": "modelscope" + }, + { + "model_format": "awq", + "model_size_in_billions": 14, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OrionStarAI/Orion-14B-Chat-{quantization}" + } + ], + "prompt_style": { + "style_name": "orion", + "roles": [ + "Human", + "assistant" + ], + "stop": [ + "", + "", + "" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "orion-chat-rag", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 14, + "quantizations": [ + "none", + "4-bit", + "8-bit" + ], + "model_hub": "modelscope", + "model_id": "OrionStarAI/Orion-14B-Chat-RAG" + } + ], + "prompt_style": { + "style_name": "orion", + "roles": [ + "Human", + "assistant" + ], + "stop": [ + "", + "", + "" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "yi-vl-chat", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "Yi Vision Language (Yi-VL) model is the open-source, multimodal version of the Yi Large Language Model (LLM) series, enabling content comprehension, recognition, and multi-round conversations about images.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 6, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-VL-6B" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 34, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "01ai/Yi-VL-34B" + } + ], + "prompt_style": { + "style_name": "CHATML", + "system_prompt": "", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "inter_message_sep": "", + "stop_token_ids": [ + 2, + 6, + 7, + 8 + ], + "stop": [ + "<|endoftext|>", + "<|im_start|>", + "<|im_end|>", + "<|im_sep|>" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "gemma-it", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 2, + "quantizations": [ + "none", + "4-bit", + "8-bit" + ], + "model_hub": "modelscope", + "model_id": "AI-ModelScope/gemma-2b-it" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 7, + "quantizations": [ + "none", + "4-bit", + "8-bit" + ], + "model_hub": "modelscope", + "model_id": "AI-ModelScope/gemma-7b-it" + } + ], + "prompt_style": { + "style_name": "gemma", + "roles": [ + "user", + "model" + ], + "stop": [ + "", + "" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "gemma-2-it", + "model_lang": [ + "en" + ], + "model_ability": [ + "chat" + ], + "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 2, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-1.3b-instruct", + "model_id": "LLM-Research/gemma-2-2b-it", "model_hub": "modelscope" }, { "model_format": "pytorch", - "model_size_in_billions": "6_7", + "model_size_in_billions": 9, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-6.7b-instruct", + "model_id": "AI-ModelScope/gemma-2-9b-it", "model_hub": "modelscope" }, { "model_format": "pytorch", - "model_size_in_billions": 33, + "model_size_in_billions": 27, "quantizations": [ + "none", "4-bit", - "8-bit", - "none" + "8-bit" ], - "model_id": "deepseek-ai/deepseek-coder-33b-instruct", + "model_id": "AI-ModelScope/gemma-2-27b-it", + "model_hub": "modelscope" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 9, + "quantizations": [ + "Q2_K", + "Q3_K_L", + "Q3_K_M", + "Q3_K_S", + "Q4_K_L", + "Q4_K_M", + "Q4_K_S", + "Q5_K_L", + "Q5_K_M", + "Q5_K_S", + "Q6_K", + "Q6_K_L", + "Q8_0", + "f32" + ], + "model_id": "LLM-Research/gemma-2-9b-it-GGUF", + "model_file_name_template": "gemma-2-9b-it-{quantization}.gguf", "model_hub": "modelscope" } ], "prompt_style": { - "style_name": "DEEPSEEK_CODER", - "system_prompt": "You are an AI programming assistant, utilizing the DeepSeek Coder model, developed by DeepSeek Company, and you only answer questions related to computer science. For politically sensitive questions, security and privacy issues, and other non-computer science questions, you will refuse to answer.", + "style_name": "gemma", "roles": [ - "### Instruction:", - "### Response:" + "user", + "model" ], - "inter_message_sep": "\n", "stop": [ - "<|EOT|>" + "", + "" + ] + } + }, + { + "version":1, + "context_length":2048, + "model_name":"OmniLMM", + "model_lang":[ + "en", + "zh" + ], + "model_ability":[ + "chat", + "vision" + ], + "model_description":"OmniLMM is a family of open-source large multimodal models (LMMs) adept at vision & language modeling.", + "model_specs":[ + { + "model_format":"pytorch", + "model_size_in_billions":3, + "quantizations":[ + "none" + ], + "model_id":"OpenBMB/MiniCPM-V", + "model_hub":"modelscope", + "model_revision":"master" + }, + { + "model_format":"pytorch", + "model_size_in_billions":12, + "quantizations":[ + "none" + ], + "model_id":"OpenBMB/OmniLMM-12B", + "model_hub":"modelscope", + "model_revision":"master" + } + ], + "prompt_style":{ + "style_name":"OmniLMM", + "system_prompt":"The role of first msg should be user", + "roles":[ + "user", + "assistant" ] } }, { "version": 1, "context_length": 4096, - "model_name": "Skywork", + "model_name": "minicpm-2b-sft-bf16", "model_lang": [ - "en", "zh" ], "model_ability": [ - "generate" + "chat" ], - "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 2, "quantizations": [ - "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "skywork/Skywork-13B-base", + "model_id": "OpenBMB/miniCPM-bf16", "model_revision": "master" } - ] + ], + "prompt_style": { + "style_name": "MINICPM-2B", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 1, + 2 + ], + "stop": [ + "", + "" + ] + } }, { "version": 1, "context_length": 4096, - "model_name": "Skywork-Math", + "model_name": "minicpm-2b-sft-fp32", "model_lang": [ - "en", "zh" ], "model_ability": [ - "generate" + "chat" ], - "model_description": "Skywork is a series of large models developed by the Kunlun Group · Skywork team.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 13, + "model_size_in_billions": 2, "quantizations": [ - "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "skywork/Skywork-13B-Math", + "model_id": "OpenBMB/MiniCPM-2B-sft-fp32", "model_revision": "master" } - ] + ], + "prompt_style": { + "style_name": "MINICPM-2B", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 1, + 2 + ], + "stop": [ + "", + "" + ] + } }, { "version": 1, - "context_length": 204800, - "model_name": "internlm2-chat", + "context_length": 4096, + "model_name": "minicpm-2b-dpo-bf16", "model_lang": [ - "en", "zh" ], "model_ability": [ "chat" ], - "model_description": "The second generation of the InternLM model, InternLM2.", + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 2, "quantizations": [ "none" ], - "model_id": "Shanghai_AI_Laboratory/internlm2-chat-7b", "model_hub": "modelscope", + "model_id": "OpenBMB/MiniCPM-2B-dpo-bf16", "model_revision": "master" - }, + } + ], + "prompt_style": { + "style_name": "MINICPM-2B", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 1, + 2 + ], + "stop": [ + "", + "" + ] + } + }, + { + "version": 1, + "context_length": 4096, + "model_name": "minicpm-2b-dpo-fp16", + "model_lang": [ + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 20, + "model_size_in_billions": 2, "quantizations": [ "none" ], - "model_id": "Shanghai_AI_Laboratory/internlm2-chat-20b", "model_hub": "modelscope", + "model_id": "OpenBMB/MiniCPM-2B-dpo-fp16", "model_revision": "master" } ], "prompt_style": { - "style_name": "INTERNLM2", - "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "style_name": "MINICPM-2B", + "system_prompt": "", "roles": [ - "<|im_start|>user", - "<|im_start|>assistant" + "user", + "assistant" ], - "intra_message_sep": "<|im_end|>", "stop_token_ids": [ - 92542 + 1, + 2 ], "stop": [ - "<|im_end|>" + "", + "" ] } }, { "version": 1, "context_length": 4096, - "model_name": "qwen-vl-chat", + "model_name": "minicpm-2b-dpo-fp32", "model_lang": [ + "zh" + ], + "model_ability": [ + "chat" + ], + "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 2, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenBMB/MiniCPM-2B-dpo-fp32", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "MINICPM-2B", + "system_prompt": "", + "roles": [ + "user", + "assistant" + ], + "stop_token_ids": [ + 1, + 2 + ], + "stop": [ + "", + "" + ] + } + }, + { + "version":1, + "context_length":8192, + "model_name":"MiniCPM-Llama3-V-2_5", + "model_lang":[ "en", "zh" ], - "model_ability": [ + "model_ability":[ "chat", "vision" ], - "model_description": "Qwen-VL-Chat supports more flexible interaction, such as multiple image inputs, multi-round question answering, and creative capabilities.", - "model_specs": [ + "model_description":"MiniCPM-Llama3-V 2.5 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Llama3-8B-Instruct with a total of 8B parameters.", + "model_specs":[ { - "model_format": "pytorch", - "model_size_in_billions": 7, - "quantizations": [ + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ "none" ], "model_hub": "modelscope", - "model_id": "Qwen/Qwen-VL-Chat", - "model_revision": "master" + "model_id":"OpenBMB/MiniCPM-Llama3-V-2_5", + "model_revision":"master" }, { - "model_format": "gptq", - "model_size_in_billions": 7, - "quantizations": [ - "Int4" + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "int4" ], "model_hub": "modelscope", - "model_id": "Qwen/Qwen-VL-Chat-{quantization}", - "model_revision": "master" + "model_id":"OpenBMB/MiniCPM-Llama3-V-2_5-{quantization}", + "model_revision":"master" } ], - "prompt_style": { - "style_name": "QWEN", - "system_prompt": "You are a helpful assistant.", - "roles": [ + "prompt_style":{ + "style_name":"OmniLMM", + "system_prompt":"The role of first msg should be user", + "roles":[ "user", "assistant" ] } }, { - "version": 1, - "context_length": 4096, - "model_name": "orion-chat", - "model_lang": [ + "version":1, + "context_length":32768, + "model_name":"MiniCPM-V-2.6", + "model_lang":[ "en", "zh" ], - "model_ability": [ - "chat" + "model_ability":[ + "chat", + "vision" ], - "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", - "model_specs": [ + "model_description":"MiniCPM-V 2.6 is the latest model in the MiniCPM-V series. The model is built on SigLip-400M and Qwen2-7B with a total of 8B parameters.", + "model_specs":[ { - "model_format": "pytorch", - "model_size_in_billions": 14, - "quantizations": [ - "none", - "4-bit", - "8-bit" + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "none" ], - "model_id": "OrionStarAI/Orion-14B-Chat", - "model_hub": "modelscope" + "model_hub": "modelscope", + "model_id":"OpenBMB/MiniCPM-V-2_6", + "model_revision":"master" }, { - "model_format": "awq", - "model_size_in_billions": 14, - "quantizations": [ - "Int4" + "model_format":"pytorch", + "model_size_in_billions":8, + "quantizations":[ + "4-bit" ], "model_hub": "modelscope", - "model_id": "OrionStarAI/Orion-14B-Chat-{quantization}" + "model_id":"OpenBMB/MiniCPM-V-2_6-int4", + "model_revision":"master" } ], - "prompt_style": { - "style_name": "orion", - "roles": [ - "Human", + "prompt_style":{ + "style_name":"QWEN", + "system_prompt":"You are a helpful assistant", + "roles":[ + "user", "assistant" - ], - "stop": [ - "", - "", - "" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "orion-chat-rag", + "context_length": 2048, + "model_name": "aquila2", "model_lang": [ - "en", "zh" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "Orion-14B series models are open-source multilingual large language models trained from scratch by OrionStarAI.", + "model_description": "Aquila2 series models are the base language models", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 14, + "model_size_in_billions": 34, "quantizations": [ - "none", - "4-bit", - "8-bit" + "none" ], "model_hub": "modelscope", - "model_id": "OrionStarAI/Orion-14B-Chat-RAG" + "model_id": "BAAI/Aquila2-34B", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "BAAI/Aquila2-70B-Expr", + "model_revision": "master" } - ], - "prompt_style": { - "style_name": "orion", - "roles": [ - "Human", - "assistant" - ], - "stop": [ - "", - "", - "" - ] - } + ] }, { "version": 1, - "context_length": 204800, - "model_name": "yi-vl-chat", + "context_length": 2048, + "model_name": "aquila2-chat", "model_lang": [ - "en", "zh" ], "model_ability": [ - "chat", - "vision" + "chat" ], - "model_description": "Yi Vision Language (Yi-VL) model is the open-source, multimodal version of the Yi Large Language Model (LLM) series, enabling content comprehension, recognition, and multi-round conversations about images.", + "model_description": "Aquila2-chat series models are the chat models", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 6, + "model_size_in_billions": 34, "quantizations": [ "none" ], "model_hub": "modelscope", - "model_id": "01ai/Yi-VL-6B" + "model_id": "BAAI/AquilaChat2-34B", + "model_revision": "master" }, { - "model_format": "pytorch", + "model_format": "gptq", "model_size_in_billions": 34, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "BAAI/AquilaChat2-34B-Int4-GPTQ", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 70, "quantizations": [ "none" ], "model_hub": "modelscope", - "model_id": "01ai/Yi-VL-34B" + "model_id": "BAAI/AquilaChat2-70B-Expr", + "model_revision": "master" } ], "prompt_style": { - "style_name": "CHATML", + "style_name": "ADD_COLON_SINGLE", + "intra_message_sep": "\n", "system_prompt": "", "roles": [ - "<|im_start|>user", - "<|im_start|>assistant" + "USER", + "ASSISTANT" ], - "intra_message_sep": "<|im_end|>", - "inter_message_sep": "", "stop_token_ids": [ - 2, - 6, - 7, - 8 + 100006, + 100007 ], "stop": [ - "<|endoftext|>", - "<|im_start|>", - "<|im_end|>", - "<|im_sep|>" + "[CLS]", + "" ] } }, { "version": 1, - "context_length": 8192, - "model_name": "gemma-it", + "context_length": 16384, + "model_name": "aquila2-chat-16k", "model_lang": [ - "en" + "zh" ], "model_ability": [ - "chat" + "generate" ], - "model_description": "Gemma is a family of lightweight, state-of-the-art open models from Google, built from the same research and technology used to create the Gemini models.", + "model_description": "AquilaChat2-16k series models are the long-text chat models", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, - "quantizations": [ - "none", - "4-bit", - "8-bit" - ], - "model_hub": "modelscope", - "model_id": "AI-ModelScope/gemma-2b-it" - }, - { - "model_format": "pytorch", - "model_size_in_billions": 7, + "model_size_in_billions": 34, "quantizations": [ - "none", - "4-bit", - "8-bit" + "none" ], "model_hub": "modelscope", - "model_id": "AI-ModelScope/gemma-7b-it" + "model_id": "BAAI/AquilaChat2-34B-16K", + "model_revision": "master" } ], "prompt_style": { - "style_name": "gemma", + "style_name": "ADD_COLON_SINGLE", + "intra_message_sep": "\n", + "system_prompt": "", "roles": [ - "user", - "model" + "USER", + "ASSISTANT" ], - "stop": [ - "", - "" - ] - } - }, - { - "version":1, - "context_length":2048, - "model_name":"OmniLMM", - "model_lang":[ - "en", - "zh" - ], - "model_ability":[ - "chat", - "vision" - ], - "model_description":"mniLMM is a family of open-source large multimodal models (LMMs) adept at vision & language modeling.", - "model_specs":[ - { - "model_format":"pytorch", - "model_size_in_billions":3, - "quantizations":[ - "none" - ], - "model_id":"OpenBMB/MiniCPM-V", - "model_hub":"modelscope", - "model_revision":"master" - }, - { - "model_format":"pytorch", - "model_size_in_billions":12, - "quantizations":[ - "none" - ], - "model_id":"OpenBMB/OmniLMM-12B", - "model_hub":"modelscope", - "model_revision":"master" - } - ], - "prompt_style":{ - "style_name":"OmniLMM", - "system_prompt":"The role of first msg should be user", - "roles":[ - "user", - "assistant" + "stop_token_ids": [ + 100006, + 100007 + ], + "stop": [ + "[CLS]", + "" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-sft-bf16", + "context_length": 131072, + "model_name": "c4ai-command-r-v01", "model_lang": [ - "zh" + "en", + "fr", + "de", + "es", + "it", + "pt", + "ja", + "ko", + "zh", + "ar" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "C4AI Command-R is a research release of a 35 billion parameter highly performant generative model.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 35, "quantizations": [ "none" ], "model_hub": "modelscope", - "model_id": "OpenBMB/miniCPM-bf16", + "model_id": "AI-ModelScope/c4ai-command-r-v01", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 35, + "quantizations": [ + "4-bit" + ], + "model_hub": "modelscope", + "model_id": "mirror013/c4ai-command-r-v01-4bit", + "model_revision": "master" + }, + { + "model_format": "ggufv2", + "model_size_in_billions": 35, + "quantizations": [ + "Q2_K", + "Q3_K_M", + "Q4_K_M", + "Q5_K_M" + ], + "model_id": "mirror013/C4AI-Command-R-v01-GGUF", + "model_file_name_template": "c4ai-command-r-v01-{quantization}.gguf", + "model_hub": "modelscope", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 104, + "quantizations": [ + "none" + ], + "model_hub": "modelscope", + "model_id": "AI-ModelScope/c4ai-command-r-plus", "model_revision": "master" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "c4ai-command-r", + "system_prompt": "You are Command-R, a brilliant, sophisticated, AI-assistant trained to assist human users by providing thorough responses. You are trained by Cohere.", "roles": [ - "user", - "assistant" + "<|USER_TOKEN|>", + "<|CHATBOT_TOKEN|>" ], + "intra_message_sep": "", + "inter_message_sep": "<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|>", "stop_token_ids": [ - 1, - 2 - ], - "stop": [ - "", - "" + 6, + 255001 ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-sft-fp32", + "context_length": 128000, + "model_name": "phi-3-mini-128k-instruct", "model_lang": [ - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "The Phi-3-Mini-128K-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 4, "quantizations": [ + "4-bit", + "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "OpenBMB/MiniCPM-2B-sft-fp32", + "model_id": "LLM-Research/Phi-3-mini-128k-instruct", "model_revision": "master" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "PHI3", + "system_prompt": "You are a helpful AI assistant.", "roles": [ "user", "assistant" ], - "stop_token_ids": [ - 1, - 2 + "intra_message_sep": "\n", + "inter_message_sep": "<|end|>\n", + "stop_token_ids":[ + 32000, + 32007 ], "stop": [ - "", - "" + "<|endoftext|>", + "<|end|>" ] } }, { "version": 1, "context_length": 4096, - "model_name": "minicpm-2b-dpo-bf16", + "model_name": "phi-3-mini-4k-instruct", "model_lang": [ - "zh" + "en" ], "model_ability": [ "chat" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "The Phi-3-Mini-4k-Instruct is a 3.8 billion-parameter, lightweight, state-of-the-art open model trained using the Phi-3 datasets.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 4, "quantizations": [ + "4-bit", + "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "OpenBMB/MiniCPM-2B-dpo-bf16", + "model_id": "LLM-Research/Phi-3-mini-4k-instruct", "model_revision": "master" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "PHI3", + "system_prompt": "You are a helpful AI assistant.", "roles": [ "user", "assistant" ], - "stop_token_ids": [ - 1, - 2 + "intra_message_sep": "\n", + "inter_message_sep": "<|end|>\n", + "stop_token_ids":[ + 32000, + 32007 ], "stop": [ - "", - "" + "<|endoftext|>", + "<|end|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-dpo-fp16", + "context_length": 32768, + "model_name": "internvl-chat", "model_lang": [ - "zh" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "InternVL 1.5 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. ", + "model_specs": [ + { + "model_format": "pytorch", + "model_size_in_billions": 26, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL-Chat-V1-5", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "INTERNVL", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92543, + 92542 + ], + "stop": [ + "", + "<|im_end|>", + "<|im_start|>" + ] + } + }, + { + "version": 1, + "context_length": 32768, + "model_name": "internvl2", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "InternVL 2 is an open-source multimodal large language model (MLLM) to bridge the capability gap between open-source and proprietary commercial models in multimodal understanding. ", + "model_specs": [ + + { + "model_format": "pytorch", + "model_size_in_billions": 1, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-1B", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 2, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-2B", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 2, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-2B-AWQ", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 4, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-4B", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 8, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-8B", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 8, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-8B-AWQ", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 26, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-26B", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 26, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-26B-AWQ", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 40, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-40B", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 40, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-40B-AWQ", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 76, + "quantizations": [ + "4-bit", + "8-bit", + "none" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-Llama3-76B", + "model_revision": "master" + }, + { + "model_format": "awq", + "model_size_in_billions": 76, + "quantizations": [ + "Int4" + ], + "model_hub": "modelscope", + "model_id": "OpenGVLab/InternVL2-Llama3-76B-AWQ", + "model_revision": "master" + } + ], + "prompt_style": { + "style_name": "INTERNVL", + "system_prompt": "You are InternLM (书生·浦语), a helpful, honest, and harmless AI assistant developed by Shanghai AI Laboratory (上海人工智能实验室).", + "roles": [ + "<|im_start|>user", + "<|im_start|>assistant" + ], + "intra_message_sep": "<|im_end|>", + "stop_token_ids": [ + 2, + 92543, + 92542 + ], + "stop": [ + "", + "<|im_end|>", + "<|im_start|>" + ] + } + }, + { + "version": 1, + "context_length": 8192, + "model_name": "cogvlm2", + "model_lang": [ + "en", + "zh" + ], + "model_ability": [ + "chat", + "vision" + ], + "model_description": "CogVLM2 have achieved good results in many lists compared to the previous generation of CogVLM open source models. Its excellent performance can compete with some non-open source models.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 20, "quantizations": [ "none" ], "model_hub": "modelscope", - "model_id": "OpenBMB/MiniCPM-2B-dpo-fp16", + "model_id": "ZhipuAI/cogvlm2-llama3-chinese-chat-19B", + "model_revision": "master" + }, + { + "model_format": "pytorch", + "model_size_in_billions": 20, + "quantizations": [ + "int4" + ], + "model_hub": "modelscope", + "model_id": "ZhipuAI/cogvlm2-llama3-chinese-chat-19B-{quantization}", "model_revision": "master" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.", "roles": [ "user", "assistant" ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 1, - 2 + 128001, + 128009 ], "stop": [ - "", - "" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 4096, - "model_name": "minicpm-2b-dpo-fp32", + "context_length": 8192, + "model_name": "cogvlm2-video-llama3-chat", "model_lang": [ - "zh" + "en", + "zh" ], "model_ability": [ - "chat" + "chat", + "vision" ], - "model_description": "MiniCPM is an End-Size LLM developed by ModelBest Inc. and TsinghuaNLP, with only 2.4B parameters excluding embeddings.", + "model_description": "CogVLM2-Video achieves state-of-the-art performance on multiple video question answering tasks.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 2, + "model_size_in_billions": 12, "quantizations": [ + "4-bit", + "8-bit", "none" ], "model_hub": "modelscope", - "model_id": "OpenBMB/MiniCPM-2B-dpo-fp32", + "model_id": "ZhipuAI/cogvlm2-video-llama3-chat", "model_revision": "master" } ], "prompt_style": { - "style_name": "MINICPM-2B", - "system_prompt": "", + "style_name": "LLAMA3", + "system_prompt": "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions.", "roles": [ "user", "assistant" ], + "intra_message_sep": "\n\n", + "inter_message_sep": "<|eot_id|>", "stop_token_ids": [ - 1, - 2 + 128001, + 128009 ], "stop": [ - "", - "" + "<|end_of_text|>", + "<|eot_id|>" ] } }, { "version": 1, - "context_length": 2048, - "model_name": "aquila2", + "context_length": 8192, + "model_name": "telechat", "model_lang": [ + "en", "zh" ], "model_ability": [ - "generate" + "chat" ], - "model_description": "Aquila2 series models are the base language models", + "model_description": "The TeleChat is a large language model developed and trained by China Telecom Artificial Intelligence Technology Co., LTD. The 7B model base is trained with 1.5 trillion Tokens and 3 trillion Tokens and Chinese high-quality corpus.", "model_specs": [ { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 7, "quantizations": [ + "4-bit", + "8-bit", "none" ], + "model_id": "TeleAI/telechat-7B", "model_hub": "modelscope", - "model_id": "BAAI/Aquila2-34B", "model_revision": "master" }, { - "model_format": "pytorch", - "model_size_in_billions": 70, + "model_format": "gptq", + "model_size_in_billions": 7, "quantizations": [ - "none" + "int4", + "int8" ], + "model_id": "TeleAI/telechat-7B-{quantization}", "model_hub": "modelscope", - "model_id": "BAAI/Aquila2-70B-Expr", "model_revision": "master" - } - ] - }, - { - "version": 1, - "context_length": 2048, - "model_name": "aquila2-chat", - "model_lang": [ - "zh" - ], - "model_ability": [ - "generate" - ], - "model_description": "Aquila2-chat series models are the chat models", - "model_specs": [ + }, { "model_format": "pytorch", - "model_size_in_billions": 34, + "model_size_in_billions": 12, "quantizations": [ + "4-bit", + "8-bit", "none" ], + "model_id": "TeleAI/TeleChat-12B", "model_hub": "modelscope", - "model_id": "BAAI/AquilaChat2-34B", "model_revision": "master" }, { "model_format": "gptq", - "model_size_in_billions": 34, + "model_size_in_billions": 12, "quantizations": [ - "Int4" + "int4", + "int8" ], + "model_id": "TeleAI/TeleChat-12B-{quantization}", "model_hub": "modelscope", - "model_id": "BAAI/AquilaChat2-34B-Int4-GPTQ", "model_revision": "master" }, { "model_format": "pytorch", - "model_size_in_billions": 70, + "model_size_in_billions": 52, "quantizations": [ + "4-bit", + "8-bit", "none" ], + "model_id": "TeleAI/TeleChat-52B", "model_hub": "modelscope", - "model_id": "BAAI/AquilaChat2-70B-Expr", "model_revision": "master" } ], "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "intra_message_sep": "\n", - "system_prompt": "", + "style_name": "NO_COLON_TWO", + "system_prompt": "You are a helpful assistant.", "roles": [ - "USER", - "ASSISTANT" - ], - "stop_token_ids": [ - 100006, - 100007 + "<_user>", + "<_bot>" ], + "intra_message_sep": "", + "inter_message_sep": "", "stop": [ - "[CLS]", - "" - ] - } - }, - { - "version": 1, - "context_length": 16384, - "model_name": "aquila2-chat-16k", - "model_lang": [ - "zh" - ], - "model_ability": [ - "generate" - ], - "model_description": "AquilaChat2-16k series models are the long-text chat models", - "model_specs": [ - { - "model_format": "pytorch", - "model_size_in_billions": 34, - "quantizations": [ - "none" - ], - "model_hub": "modelscope", - "model_id": "BAAI/AquilaChat2-34B-16K", - "model_revision": "master" - } - ], - "prompt_style": { - "style_name": "ADD_COLON_SINGLE", - "intra_message_sep": "\n", - "system_prompt": "", - "roles": [ - "USER", - "ASSISTANT" + "<_end>", + "<_start>" ], "stop_token_ids": [ - 100006, - 100007 - ], - "stop": [ - "[CLS]", - "" + 160133, + 160132 ] } } diff --git a/xinference/model/llm/lmdeploy/__init__.py b/xinference/model/llm/lmdeploy/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/model/llm/lmdeploy/core.py b/xinference/model/llm/lmdeploy/core.py new file mode 100644 index 0000000000..22fbd53e72 --- /dev/null +++ b/xinference/model/llm/lmdeploy/core.py @@ -0,0 +1,557 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import uuid +from typing import AsyncGenerator, Dict, Iterator, List, Optional, TypedDict, Union + +import torch + +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionChunkChoice, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionUsage, + LoRA, +) +from ..core import LLM +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import ChatModelMixin + +logger = logging.getLogger(__name__) + +try: + import lmdeploy # noqa: F401 + + LMDEPLOY_INSTALLED = True +except ImportError: + LMDEPLOY_INSTALLED = False + +LMDEPLOY_SUPPORTED_CHAT_MODELS = ["internvl2"] +LMDEPLOY_MODEL_CHAT_TEMPLATE_NAME = { + "internvl2": "internvl-internlm2", +} + + +class LMDeployModelConfig(TypedDict, total=False): + model_format: Optional[str] + tp: Optional[int] + session_len: Optional[int] + max_batch_size: Optional[int] + cache_max_entry_count: Optional[float] + cache_block_seq_len: Optional[int] + enable_prefix_caching: Optional[bool] + quant_policy: Optional[int] + rope_scaling_factor: Optional[float] + use_logn_attn: Optional[bool] + download_dir: Optional[str] + revision: Optional[str] + max_prefill_token_num: Optional[int] + num_tokens_per_iter: Optional[int] + max_prefill_iters: Optional[int] + + +class LMDeployGenerateConfig(TypedDict, total=False): + n: Optional[int] + max_new_tokens: Optional[int] + top_p: Optional[float] + top_k: Optional[int] + temperature: Optional[float] + repetition_penalty: Optional[float] + ignore_eos: Optional[bool] + random_seed: Optional[int] + stop_words: Optional[List[str]] + bad_words: Optional[List[str]] + min_new_tokens: Optional[int] + skip_special_tokens: Optional[bool] + logprobs: Optional[int] + + +class LMDeployModel(LLM): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + model_config: Optional[LMDeployModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__(model_uid, model_family, model_spec, quantization, model_path) + self._model_config: LMDeployModelConfig = self._sanitize_model_config( + model_config + ) + if peft_model is not None: + raise ValueError("LMDEPLOY engine has not supported lora yet.") + + def _sanitize_model_config( + self, model_config: Optional[LMDeployModelConfig] + ) -> LMDeployModelConfig: + if model_config is None: + model_config = LMDeployModelConfig() + model_config.setdefault("session_len", 8192) + if self.model_spec.model_format == "awq": + model_config.setdefault("model_format", "awq") + return model_config + + def load(self): + try: + import lmdeploy # noqa: F401, F811 + except ImportError: + error_message = "Failed to import module 'lmdeploy'" + installation_guide = [ + "Please make sure 'lmdeploy' is installed. ", + "You can install it by `pip install lmdeploy`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + raise ValueError("LMDEPLOY engine has not supported generate yet.") + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + return False + + def generate( + self, + prompt: str, + generate_config: Optional[Dict] = None, + ) -> Union[Completion, Iterator[ChatCompletionChunk]]: + raise NotImplementedError("LMDeploy generate ablility does not support now.") + + +class LMDeployChatModel(LMDeployModel, ChatModelMixin): + def load(self): + try: + from lmdeploy import ( + ChatTemplateConfig, + TurbomindEngineConfig, + VisionConfig, + pipeline, + ) + except ImportError: + error_message = "Failed to import module 'lmdeploy'" + installation_guide = [ + "Please make sure 'lmdeploy' is installed. ", + "You can install it by `pip install lmdeploy`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + chat_temp_name = "" + family = self.model_family.model_family or self.model_family.model_name + for key in LMDEPLOY_MODEL_CHAT_TEMPLATE_NAME.keys(): + if family in key: + chat_temp_name = LMDEPLOY_MODEL_CHAT_TEMPLATE_NAME[key] + break + if chat_temp_name == "": + raise ValueError(f"Can not find correct chat template.") + + chat_template_config = ChatTemplateConfig(chat_temp_name) + chat_template_config.meta_instruction = ( + self.model_family.prompt_style.system_prompt + ) + count = torch.cuda.device_count() + if count > 1: + self._model_config.setdefault("tp", torch.cuda.device_count()) + + self._model = pipeline( + self.model_path, + chat_template_config=chat_template_config, + backend_config=TurbomindEngineConfig(**self._model_config), + vision_config=VisionConfig(thread_safe=True), + ) + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format == "awq": + # Currently, only 4-bit weight quantization is supported for AWQ, but got 8 bits. + if "4" not in quantization: + return False + if llm_family.model_name not in LMDEPLOY_SUPPORTED_CHAT_MODELS: + return False + return LMDEPLOY_INSTALLED + + async def async_chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[Dict] = None, + ) -> Union[ChatCompletion, AsyncGenerator[ChatCompletionChunk, None]]: + stream = ( + generate_config.get("stream", False) + if isinstance(generate_config, dict) + else False + ) + stream_options = ( + generate_config.get("stream_options", None) + if isinstance(generate_config, dict) + else False + ) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + + chat_history = chat_history or [] + + if stream: + chunk = self._chat_stream(prompt, chat_history, include_usage) + return self._async_to_chat_completion_chunks(chunk) + else: + chunk = await self._chat(prompt, chat_history) + return self._to_chat_completion(chunk) + + async def _chat_stream(self, prompt, chat_history, include_usage): + from lmdeploy.messages import Response + + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + completion_id = str(uuid.uuid1()) + async for output in self._generate( + prompt, + chat_history, + session_id=-1, + stream_response=True, + ): + new_text = output.text if isinstance(output, Response) else output.response + + completion_choice = ChatCompletionChunkChoice( + text=new_text, + index=0, + logprobs=None, + finish_reason=output.finish_reason, + ) + chunk = ChatCompletionChunk( + id=completion_id, + object="chat.completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + prompt_tokens = output.input_token_len + completion_tokens = output.generate_token_len + total_tokens = prompt_tokens + completion_tokens + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + print(chunk) + yield chunk + if include_usage: + chunk = ChatCompletionChunk( + id=completion_id, + object="chat.completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk + + async def _chat(self, prompt, chat_history): + from lmdeploy.messages import Response + + response, finish_reason = "", "" + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + async for output in self._generate( + prompt, + chat_history, + session_id=-1, + stream_response=False, + ): + response += output.text if isinstance(output, Response) else output.response + prompt_tokens = output.input_token_len + completion_tokens = output.generate_token_len + total_tokens = output.input_token_len + output.generate_token_len + finish_reason = output.finish_reason + + chunk = ChatCompletion( + id=str(uuid.uuid1()), + object="chat.completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason=finish_reason, logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ), + ) + return chunk + + # copy from lmdeploy + # Reference: lmdeploy.serve.async_engine.py + async def _generate( + self, + prompt, + chat_history, + session_id: int, + generate_config: Optional[Dict] = None, + tools: Optional[List[object]] = None, + stream_response: bool = True, + sequence_start: bool = True, + sequence_end: bool = True, # no interactive mode by default + step: int = 0, + do_preprocess: bool = False, + adapter_name: Optional[str] = None, + **kwargs, + ): + import random + + from lmdeploy.messages import EngineGenerationConfig, GenerationConfig + from lmdeploy.serve.async_engine import GenOut + from lmdeploy.tokenizer import DetokenizeState + + session_id = -1 + + if str(session_id) not in self._model.id2step: + self._model.id2step[str(session_id)] = 0 + if generate_config is None: + generate_config = GenerationConfig() + if type(generate_config) is GenerationConfig: + generate_config = EngineGenerationConfig.From( + generate_config, self._model.tokenizer + ) + if generate_config.stop_words is None: # type: ignore + generate_config.stop_words = self._model.stop_words # type: ignore + if generate_config.random_seed is None and sequence_start: # type: ignore + generate_config.random_seed = random.getrandbits(64) # type: ignore + if generate_config.n > 1: # type: ignore + logger.warning( + f"n({generate_config.n}) > 1 hasn't been supported yet. " # type: ignore + f"Fallback to 1" + ) + generate_config.n = 1 # type: ignore + + prompt_input = await self._get_prompt_input(prompt, chat_history) + prompt = prompt_input["prompt"] + input_ids = prompt_input["input_ids"] + finish_reason = None + logger.info( + f"prompt={prompt!r}, " + f"gen_config={generate_config}, " + f"prompt_token_id={input_ids}, " + f"adapter_name={adapter_name}." + ) + logger.info( + f"session_id={session_id}, " # type: ignore + f"history_tokens={self._model.id2step[str(session_id)]}, " + f"input_tokens={len(input_ids)}, " + f"max_new_tokens={generate_config.max_new_tokens}, " + f"seq_start={sequence_start}, seq_end={sequence_end}, " + f"step={step}, prep={do_preprocess}" + ) + + if generate_config.max_new_tokens is None: # type: ignore + # for interactive endpoint, will try maximum possible token num + generate_config.max_new_tokens = max( # type: ignore + 128, + self._model.session_len + - self._model.id2step[str(session_id)] + - len(input_ids), + ) + elif ( + self._model.id2step[str(session_id)] + + len(input_ids) + + generate_config.max_new_tokens # type: ignore + > self._model.session_len + ): + generate_config.max_new_tokens = max( # type: ignore + self._model.session_len + - self._model.id2step[str(session_id)] + - len(input_ids), + 128, + ) + logger.error(f"Truncate max_new_tokens to {generate_config.max_new_tokens}") # type: ignore + + if ( + self._model.id2step[str(session_id)] + + len(input_ids) + + generate_config.max_new_tokens # type: ignore + > self._model.session_len + ): + logger.error(f"run out of tokens. session_id={session_id}.") + yield GenOut( + "", self._model.id2step[str(session_id)], len(input_ids), 0, "length" + ) + if sequence_end is True and sequence_start is False: + await self._model.end_session(session_id) + else: + generator = await self._model.get_generator(False, session_id) + async with self._model.safe_run(session_id): + state = DetokenizeState(len(input_ids)) + start_ids_offset = state.ids_offset + response = "" + async for outputs in generator.async_stream_infer( + session_id=session_id, + **prompt_input, + gen_config=generate_config, + adapter_name=adapter_name, + stream_output=stream_response, + sequence_start=sequence_start, + sequence_end=sequence_end, + step=self._model.id2step[str(session_id)], + ): + # decode res + res, tokens = ( + input_ids + outputs.token_ids, + outputs.num_token, + ) # noqa + if len(res) <= state.ids_offset: + continue + + ids_offset = state.ids_offset + response, state = self._model.tokenizer.detokenize_incrementally( + res, + state, + skip_special_tokens=generate_config.skip_special_tokens, # type: ignore + ) + + res = res[ids_offset:] + logprobs = None + if outputs.logprobs: + log_offset = ids_offset - start_ids_offset + logprobs = outputs.logprobs[log_offset:] + + # response, history token len, + # input token len, gen token len + yield GenOut( + response, + self._model.id2step[str(session_id)], + len(input_ids), + tokens, + finish_reason, + res, + logprobs, + ) + + finish_reason = ( + "length" if tokens >= generate_config.max_new_tokens else "stop" # type: ignore + ) + # utf-8 char at the end means it's a potential unfinished + # byte sequence + if not response.endswith("�"): + response = "" # avaid returning the last response twice + yield GenOut( + response, + self._model.id2step[str(session_id)], + len(input_ids), + tokens, + finish_reason, + ) + # update step + self._model.id2step[str(session_id)] += len(input_ids) + tokens + if sequence_end: + self._model.id2step[str(session_id)] = 0 + # manually end pytorch session + # TODO modify pytorch or turbomind api + if self._model.backend == "pytorch" and sequence_end: + await self._model.end_session(session_id) + + # copy from lmdeploy + # Reference: lmdeploy.serve.vl_async_engine.py + async def _get_prompt_input( + self, + prompt: Union[str, List[Dict]], + chat_history: Optional[List[ChatCompletionMessage]] = None, + sequence_start: bool = True, + tools: Optional[List[object]] = None, + **kwargs, + ): + """get input_ids, embeddings and offsets.""" + IMAGE_TOKEN = "" + IMAGE_DUMMY_TOKEN_INDEX = 0 + import numpy as np + + assert self.model_family.prompt_style is not None + prompt_style = self.model_family.prompt_style.copy() + chat_history = chat_history or [] + + decorated, _ = self.get_prompt(prompt, chat_history, prompt_style) # type: ignore + chat_history.append(ChatCompletionMessage(role="user", content=prompt)) # type: ignore + prompt = chat_history # type: ignore + + decorated = decorated.replace("", "") + + segs = decorated.split(IMAGE_TOKEN) + + results = {} + input_ids = [] # type: ignore + if len(segs) > 1: + images = await self._model.vl_prompt_template.async_collect_pil_images( + prompt + ) + + features = await self._model.vl_encoder.async_infer(images) + + from lmdeploy.vl.templates import MiniCPMVTempateWrapper + + if isinstance(self._model.vl_prompt_template, MiniCPMVTempateWrapper): + ( + decorated, + features, + ) = self._model.vl_prompt_template.update_image_token( # noqa: E501 + decorated, features + ) + segs = decorated.split(IMAGE_TOKEN) + + features = [x.cpu().numpy() for x in features] + input_ids = [] + begins = [] + ends = [] + if len(segs) != len(features) + 1: + logger.error( + f"the number of {IMAGE_TOKEN} is not equal " + f"to input images, {len(segs) - 1} vs {len(features)}" + ) + features = features[: len(segs) - 1] + for i, seg in enumerate(segs): + if i > 0 and i <= len(features): + image_dim = features[i - 1].shape[0] + begins.append(len(input_ids)) + ends.append(begins[-1] + image_dim) + input_ids.extend([IMAGE_DUMMY_TOKEN_INDEX] * image_dim) + seg_ids = self._model.tokenizer.encode( + seg, add_bos=((i == 0) and sequence_start) + ) + input_ids.extend(seg_ids) + ranges = np.stack([begins, ends], axis=1).tolist() + results["input_embeddings"] = features + results["input_embedding_ranges"] = ranges + else: + input_ids = self._model.tokenizer.encode(decorated, add_bos=sequence_start) + + results["input_ids"] = input_ids + results["prompt"] = decorated + + return results diff --git a/xinference/model/llm/ggml/__init__.py b/xinference/model/llm/lmdeploy/tests/__init__.py similarity index 100% rename from xinference/model/llm/ggml/__init__.py rename to xinference/model/llm/lmdeploy/tests/__init__.py diff --git a/xinference/model/llm/memory.py b/xinference/model/llm/memory.py new file mode 100644 index 0000000000..982804e6b3 --- /dev/null +++ b/xinference/model/llm/memory.py @@ -0,0 +1,332 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# NOTE: +# +# The algorithum is ported from https://github.com/RahulSChand/gpu_poor +# +# Improvement: +# +# The original js code only calculate kv_cache_dtype by float32, instead of most case we run model with float16. +# +# Known Issue: +# +# * On vllm, some MHA model use smaller memory than calculation (qwen1.5-7B-chat-gptq-int4, +# qwen1.5-14B-chat-gptq-int4 with large activation_mem). +# +# * On vllm, gemma-it-7B pytorch format model use larger gpu mem than calculation + +import json +import math +from dataclasses import dataclass +from logging import getLogger +from math import ceil +from typing import Any, Optional, Union + +from .llm_family import convert_model_size_to_float + +logger = getLogger(__name__) + + +@dataclass +class ModelLayersInfo: + vocab_size: int + heads: int # num_attention_heads, num_heads or n_head + hidden_dim: int # hidden_size, d_model, or n_embd + inter_dim: int # intermediate_size, n_inner or d_ff + num_layers: int # num_layers, num_hidden_layers or n_layer + + +@dataclass +class ModelMemInfo: + """Memory required by model, unit in MB""" + + model_mem: int + kv_cache_mem: int + activation_mem: int + overhead: int + total: int + + +QUANT_NORMALIZE = {"int4": "4-bit", "int8": "8-bit", "4-bit": "4-bit", "8-bit": "8-bit"} + +GGUF_MULTI_FACTOR_DICT = { + "q4_0": 18, + "q4_1": 20, + "q5_0": 22, + "q5_1": 24, + "q8_0": 34, + "q8_1": 40, +} + +GGUF_MULTI_FACTOR_DICT_64 = { + "q6_K": 54.0, + "q3": 26.0, + "q4": 38.0, + "q5": 46.0, +} + +GGUF_MULTI_FACTOR_DICT_COMBINE = { + "q3_K_L": [38.0, 26.0], + "q3_K_M": [46.0, 26.0], + "q4_K_S": [46.0, 38.0], + "q4_K_M": [54.0, 38.0], + "q5_K_M": [54.0, 46.0], + "q2_K": [26.0, 22.0], +} + + +# Return gpu memory in MB +def estimate_llm_gpu_memory( + model_size_in_billions: Union[str, int], + quantization: Optional[str], + context_length: int, # input+output + model_format: str, + model_name: Optional[str] = None, + kv_cache_dtype: int = 16, +) -> Optional[ModelMemInfo]: + """ + model_size_in_billions: must be str like 1_8 or 46_7, to match llm. + """ + info = get_model_layers_info( + model_size_in_billions, + model_name, + model_format, + quantization, + ) + if info is None: + return None + size_in_billions = convert_model_size_to_float(model_size_in_billions) + return estimate_llm_gpu_memory_details( + info, + size_in_billions, + quantization, + context_length, + model_format, + kv_cache_dtype, + ) + + +def estimate_llm_gpu_memory_details( + info: ModelLayersInfo, + size_in_billions: float, + quantization: Optional[str], + context_length: int, # input+output + model_format: str, + kv_cache_dtype: int = 16, +) -> ModelMemInfo: + """return model_mem, kv_cache, overhead, activation_mem""" + if kv_cache_dtype not in [8, 16, 32]: + raise ValueError(f"Invalid kv_cache_dtype {kv_cache_dtype}") + if kv_cache_dtype == 8: + kv_dtype_size = 1 + elif kv_cache_dtype == 16: + kv_dtype_size = 2 + else: + kv_dtype_size = 4 + overhead = 650.0 + if model_format == "ggufv2": + assert quantization is not None and quantization != "none" + model_size_in_mb = _compute_model_size_gguf(info, quantization) + inference_mem = float( + context_length * kv_dtype_size * info.hidden_dim * info.num_layers + ) + inference_mem = inference_mem / 1024.0 / 1024.0 + activation_mem = _compute_inference_only_activation_memory(context_length, info) + overhead = overhead + context_length * 0.1 + else: + if quantization is not None: + assert isinstance(quantization, str) + quantization = QUANT_NORMALIZE[quantization.lower()] + assert quantization is not None + + model_size = size_in_billions * 1000000000.0 + model_size_in_mb = _convert_to_mb_model_size(model_size, quantization) + # KV cache + inference_mem = float( + context_length * 2 * kv_dtype_size * info.hidden_dim * info.num_layers + ) + inference_mem = inference_mem / 1024.0 / 1024.0 + activation_mem = _compute_inference_only_activation_memory(context_length, info) + + total_mem = ceil(inference_mem + model_size_in_mb + overhead + activation_mem) + return ModelMemInfo( + model_mem=ceil(model_size_in_mb), + kv_cache_mem=ceil(inference_mem), + activation_mem=ceil(activation_mem), + overhead=ceil(overhead), + total=total_mem, + ) + + +def _load_item_from_json(config_data: Any, *keys: str) -> str: + assert len(keys) > 0 + for key in keys: + v = config_data.get(key) + if v is not None: + return v + raise ValueError("load ModelLayersInfo: missing %s" % (keys[0])) + + +def load_model_config_json(config_path: str) -> ModelLayersInfo: + with open(config_path, "r") as f: + config_data = json.load(f) + return ModelLayersInfo( + vocab_size=int(_load_item_from_json(config_data, "vocab_size")), + heads=int( + _load_item_from_json( + config_data, "num_key_value_heads", "num_attention_heads" + ) + ), + hidden_dim=int( + _load_item_from_json(config_data, "hidden_size", "d_model", "n_embd") + ), + inter_dim=int(_load_item_from_json(config_data, "intermediate_size")), + num_layers=int( + _load_item_from_json( + config_data, "num_hidden_layers", "num_layers", "n_layer" + ) + ), + ) + + +def get_model_layers_info( + model_size_in_billions: Union[str, int], + model_name: Optional[str], + model_format: Optional[str], + quantization: Optional[str], +) -> Optional[ModelLayersInfo]: + from . import match_llm + from .llm_family import cache_model_config + + if not model_name: + logger.debug("get_model_layers_info by default size=%s", model_size_in_billions) + size_in_billions = convert_model_size_to_float(model_size_in_billions) + return _get_default_layers_from_size(size_in_billions) + match_result = match_llm( + model_name=model_name, + model_format=model_format, + model_size_in_billions=model_size_in_billions, + quantization=quantization, + ) + if not match_result: + return None + llm_family, llm_spec, _quant = match_result + config_path = cache_model_config(llm_family, llm_spec) + return load_model_config_json(config_path) + + +def _get_default_layers_from_size(size_in_billion: float) -> ModelLayersInfo: + if size_in_billion < 5: + vocab_size = 32000 + heads = 32 + num_layers = 24 + elif size_in_billion < 10: + vocab_size = 32000 + heads = 32 + num_layers = 32 + elif size_in_billion < 24: + vocab_size = 32000 + heads = 40 + num_layers = 40 + elif size_in_billion < 55: + vocab_size = 32000 + heads = 60 + num_layers = 48 + else: + vocab_size = 32000 + heads = 64 + num_layers = 80 + + model_size = int(size_in_billion * 1000000000) + A = num_layers * 4 + 3 * 4 * num_layers + B = 2 * vocab_size + C = -1 * model_size + h = (-B + math.sqrt(B**2 - 4 * A * C)) / (2 * A) + h = math.ceil(h) + return ModelLayersInfo( + vocab_size=vocab_size, + heads=heads, + hidden_dim=h, + inter_dim=4 * h, + num_layers=num_layers, + ) + + +def _convert_to_mb_model_size(model_size: float, quantization: Optional[str]) -> float: + extra = 0.0 + fB = 2.0 + size = (model_size * fB) / (1024.0 * 1024.0) + # bnb_q4 == 4-bit ? + if quantization == "8-bit" or quantization == "4-bit": + extra = 0.06 * size + if quantization == "8-bit": + size = size / 2 + if quantization == "4-bit": + size = size / 4 + return size + extra + + +def _compute_inference_only_activation_memory( + context_length: int, info: ModelLayersInfo +) -> float: + hidden_dim = info.hidden_dim + heads = info.heads + ret = ( + (context_length * hidden_dim * 5 * 2 + (context_length**2) * heads * 2) + / 1024 + / 1024 + ) + return ret + + +def _compute_model_size_gguf(info: ModelLayersInfo, quantization: str) -> float: + assert quantization is not None + vocab_size = info.vocab_size + num_layers = info.num_layers + hidden_dim = info.hidden_dim + inter_dim = info.inter_dim + total_params = int( + vocab_size * hidden_dim * 2 + + num_layers * 4 * (hidden_dim**2) + + num_layers * 3 * inter_dim * hidden_dim + ) + other_v_down_params = ( + num_layers * (hidden_dim**2) + num_layers * hidden_dim * inter_dim + ) + other_param_q2k = ( + total_params - (hidden_dim**2) * num_layers * 2 + 2 * vocab_size * hidden_dim + ) + + total = 0.0 + v1 = GGUF_MULTI_FACTOR_DICT.get(quantization) + if v1 is not None: + total = (v1 * total_params) / (32 * 1024 * 1024) + v2 = GGUF_MULTI_FACTOR_DICT_64.get(quantization) + if v2 is not None: + total = (v2 * total_params) / (64 * 1024 * 1024) + v3 = GGUF_MULTI_FACTOR_DICT_COMBINE.get(quantization) + if v3 is not None: + factors = v3 + if quantization == "q2_K": + total = ( + (total_params - other_param_q2k) * factors[1] + + other_param_q2k * factors[0] + ) / (64 * 1024 * 1024) + else: + total = ( + (total_params - other_v_down_params) * factors[1] + + other_v_down_params * factors[0] + ) / (64 * 1024 * 1024) + return total diff --git a/xinference/model/llm/ggml/tests/__init__.py b/xinference/model/llm/mlx/__init__.py similarity index 100% rename from xinference/model/llm/ggml/tests/__init__.py rename to xinference/model/llm/mlx/__init__.py diff --git a/xinference/model/llm/mlx/core.py b/xinference/model/llm/mlx/core.py new file mode 100644 index 0000000000..e41db2b693 --- /dev/null +++ b/xinference/model/llm/mlx/core.py @@ -0,0 +1,415 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import platform +import sys +import time +import uuid +from typing import Dict, Iterable, Iterator, List, Optional, TypedDict, Union + +from ....fields import max_tokens_field +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, + LoRA, +) +from ..core import LLM +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import ChatModelMixin + +logger = logging.getLogger(__name__) + + +class MLXModelConfig(TypedDict, total=False): + revision: Optional[str] + max_gpu_memory: str + trust_remote_code: bool + + +class MLXGenerateConfig(TypedDict, total=False): + max_tokens: int + temperature: float + repetition_penalty: Optional[float] + repetition_context_size: Optional[float] + top_p: float + logit_bias: Optional[Dict[int, float]] + stop: Optional[Union[str, List[str]]] + stop_token_ids: Optional[Union[int, List[int]]] + stream: bool + stream_options: Optional[Union[dict, None]] + + +class MLXModel(LLM): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + model_config: Optional[MLXModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__(model_uid, model_family, model_spec, quantization, model_path) + self._use_fast_tokenizer = True + self._model_config: MLXModelConfig = self._sanitize_model_config(model_config) + if peft_model is not None: + raise ValueError("MLX engine has not supported lora yet") + + def _sanitize_model_config( + self, model_config: Optional[MLXModelConfig] + ) -> MLXModelConfig: + if model_config is None: + model_config = MLXModelConfig() + model_config.setdefault("revision", self.model_spec.model_revision) + model_config.setdefault("trust_remote_code", True) + return model_config + + def _sanitize_generate_config( + self, + generate_config: Optional[MLXGenerateConfig], + ) -> MLXGenerateConfig: + if generate_config is None: + generate_config = MLXGenerateConfig() + + generate_config.setdefault("max_tokens", max_tokens_field.default) + # default config is adapted from + # https://github.com/ml-explore/mlx-examples/blob/f212b770d8b5143e23102eda20400ae43340f844/llms/mlx_lm/utils.py#L129 + generate_config.setdefault("temperature", 0.0) + generate_config.setdefault("repetition_penalty", None) + generate_config.setdefault("repetition_context_size", 20) + generate_config.setdefault("top_p", 1.0) + generate_config.setdefault("logit_bias", None) + return generate_config + + def _load_model(self, **kwargs): + try: + import mlx.core as mx + from mlx_lm import load + except ImportError: + error_message = "Failed to import module 'mlx_lm'" + installation_guide = [ + "Please make sure 'mlx_lm' is installed. ", + "You can install it by `pip install mlx_lm`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + tokenizer_config = dict( + use_fast=self._use_fast_tokenizer, + trust_remote_code=kwargs["trust_remote_code"], + revision=kwargs["revision"], + ) + logger.debug( + "loading model with tokenizer config: %s, model config: %s", + tokenizer_config, + self._model_config, + ) + + cache_limit_gb = kwargs.get("cache_limit_gb", None) + if cache_limit_gb: + logger.debug(f"Setting cache limit to {cache_limit_gb} GB") + mx.metal.set_cache_limit(cache_limit_gb * 1024 * 1024 * 1024) + + return load( + self.model_path, + tokenizer_config=tokenizer_config, + model_config=self._model_config, + ) + + def load(self): + kwargs = {} + kwargs["revision"] = self._model_config.get( + "revision", self.model_spec.model_revision + ) + kwargs["trust_remote_code"] = self._model_config.get("trust_remote_code") + kwargs["cache_limit_gb"] = self._model_config.pop("cache_limit_gb", None) + + self._model, self._tokenizer = self._load_model(**kwargs) + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format not in ["mlx"]: + return False + if sys.platform != "darwin" or platform.processor() != "arm": + # only work for Mac M chips + return False + if "generate" not in llm_family.model_ability: + return False + return True + + def _generate_stream(self, prompt: str, kwargs: MLXGenerateConfig): + import mlx.core as mx + from mlx_lm.utils import generate_step + + model = self._model + model_uid = self.model_uid + tokenizer = self._tokenizer + max_tokens = kwargs["max_tokens"] + chunk_id = str(uuid.uuid4()) + stop_token_ids = kwargs.get("stop_token_ids", []) + stream = kwargs.get("stream", False) + stream_options = kwargs.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + + prompt_tokens = mx.array(tokenizer.encode(prompt)) + input_echo_len = len(prompt_tokens) + + i = 0 + start = time.time() + output = "" + for (token, _), i in zip( + generate_step( + prompt_tokens, + model, + temp=kwargs["temperature"], + repetition_penalty=kwargs["repetition_penalty"], + repetition_context_size=kwargs["repetition_context_size"], + top_p=kwargs["top_p"], + logit_bias=kwargs["logit_bias"], + ), + range(max_tokens), + ): + if token == tokenizer.eos_token_id or token in stop_token_ids: # type: ignore + break + + # Yield the last segment if streaming + out = tokenizer.decode( + token, + skip_special_tokens=True, + spaces_between_special_tokens=False, + clean_up_tokenization_spaces=True, + ) + + if stream: + # this special character is mainly for qwen + out = out.strip("�") + output = out + else: + output += out + + completion_choice = CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=None + ) + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + + yield completion_chunk, completion_usage + + logger.info( + f"Average generation speed: {i / (time.time() - start):.2f} tokens/s." + ) + + if i == max_tokens - 1: + finish_reason = "length" + else: + finish_reason = "stop" + + if stream: + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason=finish_reason + ) + else: + completion_choice = CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=finish_reason + ) + + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + + yield completion_chunk, completion_usage + + if include_usage: + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + yield completion_chunk, completion_usage + + def generate( + self, prompt: str, generate_config: Optional[MLXGenerateConfig] = None + ) -> Union[Completion, Iterator[CompletionChunk]]: + def generator_wrapper( + prompt: str, generate_config: MLXGenerateConfig + ) -> Iterator[CompletionChunk]: + for completion_chunk, completion_usage in self._generate_stream( + prompt, + generate_config, + ): + completion_chunk["usage"] = completion_usage + yield completion_chunk + + logger.debug( + "Enter generate, prompt: %s, generate config: %s", prompt, generate_config + ) + + generate_config = self._sanitize_generate_config(generate_config) + + assert self._model is not None + assert self._tokenizer is not None + + stream = generate_config.get("stream", False) + if not stream: + for completion_chunk, completion_usage in self._generate_stream( + prompt, + generate_config, + ): + pass + completion = Completion( + id=completion_chunk["id"], + object=completion_chunk["object"], + created=completion_chunk["created"], + model=completion_chunk["model"], + choices=completion_chunk["choices"], + usage=completion_usage, + ) + return completion + else: + return generator_wrapper(prompt, generate_config) + + +class MLXChatModel(MLXModel, ChatModelMixin): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + model_config: Optional[MLXModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__( + model_uid, + model_family, + model_spec, + quantization, + model_path, + model_config, + peft_model, + ) + + def _sanitize_generate_config( + self, + generate_config: Optional[MLXGenerateConfig], + ) -> MLXGenerateConfig: + generate_config = super()._sanitize_generate_config(generate_config) + if ( + (not generate_config.get("stop")) + and self.model_family.prompt_style + and self.model_family.prompt_style.stop + ): + generate_config["stop"] = self.model_family.prompt_style.stop.copy() + if ( + generate_config.get("stop_token_ids", None) is None + and self.model_family.prompt_style + and self.model_family.prompt_style.stop_token_ids + ): + generate_config[ + "stop_token_ids" + ] = self.model_family.prompt_style.stop_token_ids.copy() + + return generate_config + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format not in ["mlx"]: + return False + if sys.platform != "darwin" or platform.processor() != "arm": + # only work for Mac M chips + return False + if "chat" not in llm_family.model_ability: + return False + return True + + def chat( + self, + prompt: str, + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[MLXGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + tools = generate_config.pop("tools", []) if generate_config else None # type: ignore + full_prompt = self.get_full_prompt( + self.model_family, prompt, system_prompt, chat_history, tools + ) + + generate_config = self._sanitize_generate_config(generate_config) + # TODO(codingl2k1): qwen hacky to set stop for function call. + model_family = self.model_family.model_family or self.model_family.model_name + if tools and model_family in ["qwen-chat", "qwen1.5-chat"]: + stop = generate_config.get("stop") + if isinstance(stop, str): + generate_config["stop"] = [stop, "Observation:"] + elif isinstance(stop, Iterable): + assert not isinstance(stop, str) + generate_config["stop"] = list(stop) + ["Observation:"] + else: + generate_config["stop"] = "Observation:" + + stream = generate_config.get("stream", False) + if stream: + it = self.generate(full_prompt, generate_config) + assert isinstance(it, Iterator) + return self._to_chat_completion_chunks(it) + else: + c = self.generate(full_prompt, generate_config) + assert not isinstance(c, Iterator) + if tools: + return self._tool_calls_completion( + self.model_family, self.model_uid, c, tools + ) + return self._to_chat_completion(c) diff --git a/xinference/model/llm/pytorch/__init__.py b/xinference/model/llm/mlx/tests/__init__.py similarity index 100% rename from xinference/model/llm/pytorch/__init__.py rename to xinference/model/llm/mlx/tests/__init__.py diff --git a/xinference/model/llm/mlx/tests/test_mlx.py b/xinference/model/llm/mlx/tests/test_mlx.py new file mode 100644 index 0000000000..4fe69fd34f --- /dev/null +++ b/xinference/model/llm/mlx/tests/test_mlx.py @@ -0,0 +1,41 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import platform +import sys + +import pytest + +from .....client import Client + + +@pytest.mark.skipif( + sys.platform != "darwin" or platform.processor() != "arm", + reason="MLX only works for Apple silicon chip", +) +def test_load_mlx(setup): + endpoint, _ = setup + client = Client(endpoint) + + model_uid = client.launch_model( + model_name="qwen2-instruct", + model_engine="MLX", + model_size_in_billions="0_5", + model_format="mlx", + quantization="4-bit", + ) + assert len(client.list_models()) == 1 + model = client.get_model(model_uid) + completion = model.chat("write a poem.") + assert "content" in completion["choices"][0]["message"] + assert len(completion["choices"][0]["message"]["content"]) != 0 diff --git a/xinference/model/llm/pytorch/baichuan.py b/xinference/model/llm/pytorch/baichuan.py deleted file mode 100644 index 8b3adb2c88..0000000000 --- a/xinference/model/llm/pytorch/baichuan.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Optional - -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchModelConfig - - -class BaichuanPytorchChatModel(PytorchChatModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, - ) - self._use_fast_tokenizer = False - - def _load_model(self, **kwargs): - try: - from transformers import AutoModelForCausalLM, AutoTokenizer - from transformers.generation.utils import GenerationConfig - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - use_fast=self._use_fast_tokenizer, - trust_remote_code=kwargs["trust_remote_code"], - revision=kwargs["revision"], - ) - model = AutoModelForCausalLM.from_pretrained( - self.model_path, - **kwargs, - ) - model.generation_config = GenerationConfig.from_pretrained(self.model_path) - return model, tokenizer - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "pytorch": - return False - if llm_family.model_name not in ["baichuan-chat", "baichuan-2-chat"]: - return False - if "chat" not in llm_family.model_ability: - return False - return True diff --git a/xinference/model/llm/pytorch/chatglm.py b/xinference/model/llm/pytorch/chatglm.py deleted file mode 100644 index 9675be149a..0000000000 --- a/xinference/model/llm/pytorch/chatglm.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import time -import uuid -from typing import Any, Dict, Iterator, List, Optional, Union - -from ....types import ( - SPECIAL_TOOL_PROMPT, - ChatCompletion, - ChatCompletionChoice, - ChatCompletionChunk, - ChatCompletionMessage, - CompletionChoice, - CompletionChunk, - CompletionUsage, - PytorchGenerateConfig, -) -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchModelConfig - - -class ChatglmPytorchChatModel(PytorchChatModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, - ) - - def _load_model(self, **kwargs): - try: - from transformers import AutoModel, AutoTokenizer - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - trust_remote_code=kwargs["trust_remote_code"], - encode_special_tokens=True, - revision=kwargs["revision"], - ) - model = AutoModel.from_pretrained( - self.model_path, - **kwargs, - ) - return model, tokenizer - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "pytorch": - return False - if "chatglm" not in llm_family.model_name: - return False - if "chat" not in llm_family.model_ability: - return False - return True - - @staticmethod - def _handle_tools(generate_config) -> Optional[dict]: - """Convert openai tools to ChatGLM tools.""" - if generate_config is None: - return None - tools = generate_config.pop("tools", None) - if tools is None: - return None - chatglm_tools = [] - for elem in tools: - if elem.get("type") != "function" or "function" not in elem: - raise ValueError("ChatGLM tools only support function type.") - chatglm_tools.append(elem["function"]) - return { - "role": "system", - "content": f"Answer the following questions as best as you can. You have access to the following tools:", - "tools": chatglm_tools, - } - - def chat( - self, - prompt: str, - system_prompt: Optional[str] = None, - chat_history: Optional[List[ChatCompletionMessage]] = None, - generate_config: Optional[PytorchGenerateConfig] = None, - ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: - tools = self._handle_tools(generate_config) - kwargs: Dict[str, Any] = {} - generate_config = generate_config or {} - temperature = generate_config.get("temperature") - if temperature is not None: - kwargs["temperature"] = float(temperature) - top_p = generate_config.get("top_p") - if top_p is not None: - kwargs["top_p"] = float(top_p) - max_new_tokens = generate_config.get("max_tokens") - if max_new_tokens is not None: - kwargs["max_new_tokens"] = int(max_new_tokens) - # Tool calls only works for non stream, so we call chat directly. - if prompt == SPECIAL_TOOL_PROMPT and chat_history: - tool_message = chat_history.pop() - content = tool_message.get("content") - assert content is not None - prompt = content - kwargs["role"] = "observation" - chat_history = [h for h in chat_history if not h.get("tool_calls")] - if not chat_history: - chat_history = [] - if tools: - msg = self._model.chat( - self._tokenizer, prompt, [tools] + chat_history, **kwargs - ) - return self._tool_calls_completion( - self.model_family, self.model_uid, msg, tools - ) - else: - stream = generate_config.get("stream", False) - if stream: - - def _stream_generator(): - last_chunk_text_length = 0 - chunk_id = "chat-" + str(uuid.uuid1()) - for chunk_text, _ in self._model.stream_chat( - self._tokenizer, prompt, chat_history, **kwargs - ): - chunk_text = chunk_text[last_chunk_text_length:] - last_chunk_text_length += len(chunk_text) - completion_choice = CompletionChoice( - text=chunk_text, index=0, logprobs=None, finish_reason=None - ) - yield CompletionChunk( - id=chunk_id, - object="text_completion", - created=int(time.time()), - model=self.model_uid, - choices=[completion_choice], - ) - - return self._to_chat_completion_chunks(_stream_generator()) - else: - response, _ = self._model.chat( - self._tokenizer, prompt, chat_history, **kwargs - ) - return ChatCompletion( - id="chat" + str(uuid.uuid1()), - object="chat.completion", - created=int(time.time()), - model=self.model_uid, - choices=[ - ChatCompletionChoice( - index=0, - message={"role": "assistant", "content": response}, - finish_reason="stop", - ) - ], - usage=CompletionUsage( - prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 - ), - ) diff --git a/xinference/model/llm/pytorch/core.py b/xinference/model/llm/pytorch/core.py deleted file mode 100644 index 88ca44ee7b..0000000000 --- a/xinference/model/llm/pytorch/core.py +++ /dev/null @@ -1,517 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import logging -import os -from typing import Iterable, Iterator, List, Optional, Union - -from ....device_utils import ( - get_device_preferred_dtype, - gpu_count, - is_hf_accelerate_supported, -) -from ....types import ( - ChatCompletion, - ChatCompletionChunk, - ChatCompletionMessage, - Completion, - CompletionChunk, - CreateCompletionTorch, - Embedding, - EmbeddingData, - EmbeddingUsage, - PytorchGenerateConfig, - PytorchModelConfig, -) -from ...utils import select_device -from ..core import LLM -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from ..utils import ChatModelMixin - -logger = logging.getLogger(__name__) - - -class PytorchModel(LLM): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__(model_uid, model_family, model_spec, quantization, model_path) - self._use_fast_tokenizer = True - self._pytorch_model_config: PytorchModelConfig = self._sanitize_model_config( - pytorch_model_config - ) - self._peft_model_path = peft_model_path - - def _sanitize_model_config( - self, pytorch_model_config: Optional[PytorchModelConfig] - ) -> PytorchModelConfig: - if pytorch_model_config is None: - pytorch_model_config = PytorchModelConfig() - pytorch_model_config.setdefault("revision", self.model_spec.model_revision) - pytorch_model_config.setdefault("gptq_ckpt", None) - pytorch_model_config.setdefault("gptq_wbits", 16) - pytorch_model_config.setdefault("gptq_groupsize", -1) - pytorch_model_config.setdefault("gptq_act_order", False) - pytorch_model_config.setdefault("device", "auto") - pytorch_model_config.setdefault("trust_remote_code", True) - return pytorch_model_config - - def _sanitize_generate_config( - self, - generate_config: Optional[PytorchGenerateConfig], - ) -> PytorchGenerateConfig: - if generate_config is None: - generate_config = PytorchGenerateConfig(**CreateCompletionTorch().dict()) - else: - # Validate generate_config and fill default values to the generate config. - generate_config = PytorchGenerateConfig( - **CreateCompletionTorch(**generate_config).dict() - ) - generate_config["model"] = self.model_uid - return generate_config - - def _load_model(self, **kwargs): - try: - from transformers import AutoModelForCausalLM, AutoTokenizer - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - use_fast=self._use_fast_tokenizer, - trust_remote_code=kwargs["trust_remote_code"], - revision=kwargs["revision"], - ) - model = AutoModelForCausalLM.from_pretrained( - self.model_path, - low_cpu_mem_usage=True, - **kwargs, - ) - return model, tokenizer - - def _apply_lora(self): - if self._peft_model_path is not None: - try: - from peft import PeftModel - except ImportError: - raise ImportError( - f"Failed to import 'PeftModel' from 'peft'. Please make sure 'peft' is installed.\n\n" - ) - - # Apply LoRA - self._model = PeftModel.from_pretrained( - self._model, - self._peft_model_path, - ) - logger.info( - f"Successfully loaded the PEFT adaptor for model {self.model_uid}." - ) - - def load(self): - try: - import torch - except ImportError: - raise ImportError( - f"Failed to import module 'torch'. Please make sure 'torch' is installed.\n\n" - ) - from .compression import load_compress_model - - quantization = self.quantization - num_gpus = gpu_count() - device = self._pytorch_model_config.get("device", "auto") - self._pytorch_model_config["device"] = select_device(device) - self._device = self._pytorch_model_config["device"] - - kwargs = {} - - dtype = get_device_preferred_dtype(self._device) - - if dtype is not None: - kwargs["torch_dtype"] = dtype - else: - raise ValueError(f"Device {self._device} is not supported in temporary") - - kwargs["revision"] = self._pytorch_model_config.get( - "revision", self.model_spec.model_revision - ) - kwargs["trust_remote_code"] = self._pytorch_model_config.get( - "trust_remote_code" - ) - model_format = self.model_spec.model_format - - is_device_map_auto = False - - # This is required for Intel GPU to actually work with accelerate device_map until - # https://github.com/intel/intel-extension-for-pytorch/issues/522 - # is resolved - max_memory_env = os.getenv("ACCELERATE_MAX_MEMORY", None) - - if max_memory_env is not None: - max_memory_raw = json.loads(max_memory_env) - max_memory = { - int(k) if k.isdigit() else k: max_memory_raw[k] for k in max_memory_raw - } - kwargs["max_memory"] = max_memory - - if quantization != "none" and model_format == "pytorch": - if self._device == "cuda" and self._is_linux(): - kwargs["device_map"] = "auto" - is_device_map_auto = True - if quantization == "4-bit": - kwargs["load_in_4bit"] = True - kwargs["bnb_4bit_compute_dtype"] = torch.float16 - kwargs["bnb_4bit_use_double_quant"] = True - kwargs["llm_int8_skip_modules"] = [ - "lm_head", - "encoder", - "EncDecAttention", - ] - elif quantization == "8-bit": - kwargs["load_in_8bit"] = True - else: - raise ValueError( - f"Quantization {quantization} is not supported in temporary" - ) - else: - if num_gpus != 1 and self._device == "cuda": - raise ValueError(f"Quantization is not supported for multi-gpu") - elif quantization != "8-bit": - raise ValueError( - f"Only 8-bit quantization is supported if it is not linux system or cuda device" - ) - else: - self._model, self._tokenizer = load_compress_model( - model_path=self.model_path, - device=self._device, - torch_dtype=kwargs["torch_dtype"], - use_fast=self._use_fast_tokenizer, - revision=kwargs["revision"], - ) - logger.debug(f"Model Memory: {self._model.get_memory_footprint()}") - return - - if num_gpus > 0 and is_hf_accelerate_supported(self._device): - kwargs.update({"device_map": "auto"}) - is_device_map_auto = True - - self._model, self._tokenizer = self._load_model(**kwargs) - self._apply_lora() - - if not is_device_map_auto: - self._model.to(self._device) - logger.debug(f"Model Memory: {self._model.get_memory_footprint()}") - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: - return False - model_family = llm_family.model_family or llm_family.model_name - if model_family in [ - "baichuan-chat", - "vicuna-v1.3", - "falcon", - "falcon-instruct", - "chatglm", - "chatglm2", - "chatglm2-32k", - "llama-2", - "llama-2-chat", - ]: - return False - if "generate" not in llm_family.model_ability: - return False - return True - - def generate( - self, prompt: str, generate_config: Optional[PytorchGenerateConfig] = None - ) -> Union[Completion, Iterator[CompletionChunk]]: - from .utils import generate_stream, generate_stream_falcon - - model_family_name = self.model_family.model_name.lower() - - def generator_wrapper( - prompt: str, generate_config: PytorchGenerateConfig - ) -> Iterator[CompletionChunk]: - if "falcon" in model_family_name: - for completion_chunk, completion_usage in generate_stream_falcon( - self.model_uid, - self._model, - self._tokenizer, - prompt, - self._device, - generate_config, - ): - completion_chunk["usage"] = completion_usage - yield completion_chunk - else: - for completion_chunk, completion_usage in generate_stream( - self.model_uid, - self._model, - self._tokenizer, - prompt, - self._device, - generate_config, - ): - completion_chunk["usage"] = completion_usage - yield completion_chunk - - logger.debug( - "Enter generate, prompt: %s, generate config: %s", prompt, generate_config - ) - - generate_config = self._sanitize_generate_config(generate_config) - - assert self._model is not None - assert self._tokenizer is not None - - stream = generate_config.get("stream", False) - if not stream: - if "falcon" in model_family_name: - for completion_chunk, completion_usage in generate_stream_falcon( - self.model_uid, - self._model, - self._tokenizer, - prompt, - self._device, - generate_config, - ): - pass - else: - for completion_chunk, completion_usage in generate_stream( - self.model_uid, - self._model, - self._tokenizer, - prompt, - self._device, - generate_config, - ): - pass - completion = Completion( - id=completion_chunk["id"], - object=completion_chunk["object"], - created=completion_chunk["created"], - model=completion_chunk["model"], - choices=completion_chunk["choices"], - usage=completion_usage, - ) - return completion - else: - return generator_wrapper(prompt, generate_config) - - def create_embedding(self, input: Union[str, List[str]]) -> Embedding: - try: - import torch - import torch.nn.functional as F - except ImportError as e: - raise ImportError( - "Could not import torch. Please install it with `pip install torch`." - ) from e - - if isinstance(input, str): - inputs = [input] - else: - inputs = input - - tokenizer = self._tokenizer - tokenizer.pad_token = tokenizer.eos_token - is_llama = "llama" in str(type(self._model)) # llama supports batch inference - is_chatglm = "chatglm" in str(type(self._model)) - if is_llama: - encoding = tokenizer.batch_encode_plus( - inputs, padding=True, return_tensors="pt" - ) - input_ids = encoding["input_ids"].to(self._device) - attention_mask = encoding["attention_mask"].to(self._device) - model_output = self._model( - input_ids, attention_mask, output_hidden_states=True - ) - data = model_output.hidden_states[-1] - mask = attention_mask.unsqueeze(-1).expand(data.size()).float() - masked_embeddings = data * mask - sum_embeddings = torch.sum(masked_embeddings, dim=1) - seq_length = torch.sum(mask, dim=1) - embedding = sum_embeddings / seq_length - normalized_embeddings = F.normalize(embedding, p=2, dim=1) - normalized_embeddings = normalized_embeddings.tolist() - token_num = torch.sum(attention_mask).item() - - embedding_list = [] - for index, data in enumerate(normalized_embeddings): - embedding_list.append( - EmbeddingData(index=index, object="embedding", embedding=data) - ) - - usage = EmbeddingUsage(prompt_tokens=token_num, total_tokens=token_num) - - ret = Embedding( - object="list", - model=self.model_uid, - data=embedding_list, - usage=usage, - ) - - else: - embedding = [] - token_num = 0 - for index, text in enumerate(inputs): - input_ids = tokenizer.encode(text, return_tensors="pt").to(self._device) - model_output = self._model(input_ids, output_hidden_states=True) - if is_chatglm: - data = (model_output.hidden_states[-1].transpose(0, 1))[0] - else: - data = model_output.hidden_states[-1][0] - data = F.normalize(torch.mean(data, dim=0), p=2, dim=0) - data = data.tolist() - - embedding.append( - EmbeddingData(index=index, object="embedding", embedding=data) - ) - token_num += len(input_ids[0]) - - usage = EmbeddingUsage(prompt_tokens=token_num, total_tokens=token_num) - ret = Embedding( - object="list", model=self.model_uid, data=embedding, usage=usage - ) - - return ret - - -class PytorchChatModel(PytorchModel, ChatModelMixin): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config, - peft_model_path, - ) - - def _sanitize_generate_config( - self, - generate_config: Optional[PytorchGenerateConfig], - ) -> PytorchGenerateConfig: - generate_config = super()._sanitize_generate_config(generate_config) - if ( - (not generate_config.get("stop")) - and self.model_family.prompt_style - and self.model_family.prompt_style.stop - ): - generate_config["stop"] = self.model_family.prompt_style.stop.copy() - if ( - generate_config.get("stop_token_ids", None) is None - and self.model_family.prompt_style - and self.model_family.prompt_style.stop_token_ids - ): - generate_config[ - "stop_token_ids" - ] = self.model_family.prompt_style.stop_token_ids.copy() - - return generate_config - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: - return False - if llm_family.model_name in [ - "baichuan-chat", - "baichuan-2-chat", - "vicuna-v1.3", - "falcon", - "falcon-instruct", - "chatglm", - "chatglm2", - "chatglm2-32k", - "llama-2", - "llama-2-chat", - "internlm2-chat", - "qwen-vl-chat", - "OmniLMM", - "yi-vl-chat", - "deepseek-vl-chat", - ]: - return False - if "chat" not in llm_family.model_ability: - return False - return True - - def chat( - self, - prompt: str, - system_prompt: Optional[str] = None, - chat_history: Optional[List[ChatCompletionMessage]] = None, - generate_config: Optional[PytorchGenerateConfig] = None, - ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: - assert self.model_family.prompt_style is not None - prompt_style = self.model_family.prompt_style.copy() - if system_prompt: - prompt_style.system_prompt = system_prompt - chat_history = chat_history or [] - tools = generate_config.pop("tools", []) if generate_config else None - full_prompt = self.get_prompt(prompt, chat_history, prompt_style, tools=tools) - - generate_config = self._sanitize_generate_config(generate_config) - # TODO(codingl2k1): qwen hacky to set stop for function call. - model_family = self.model_family.model_family or self.model_family.model_name - if tools and model_family in ["qwen-chat", "qwen1.5-chat"]: - stop = generate_config.get("stop") - if isinstance(stop, str): - generate_config["stop"] = [stop, "Observation:"] - elif isinstance(stop, Iterable): - assert not isinstance(stop, str) - generate_config["stop"] = list(stop) + ["Observation:"] - else: - generate_config["stop"] = "Observation:" - - stream = generate_config.get("stream", False) - if stream: - it = self.generate(full_prompt, generate_config) - assert isinstance(it, Iterator) - return self._to_chat_completion_chunks(it) - else: - c = self.generate(full_prompt, generate_config) - assert not isinstance(c, Iterator) - if tools: - return self._tool_calls_completion( - self.model_family, self.model_uid, c, tools - ) - return self._to_chat_completion(c) diff --git a/xinference/model/llm/pytorch/falcon.py b/xinference/model/llm/pytorch/falcon.py deleted file mode 100644 index 782f29e750..0000000000 --- a/xinference/model/llm/pytorch/falcon.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Optional - -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchModel, PytorchModelConfig - - -class FalconPytorchModel(PytorchModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, - ) - - def _load_model(self, **kwargs): - try: - from transformers import AutoModelForCausalLM, AutoTokenizer - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - trust_remote_code=kwargs["trust_remote_code"], - revision=kwargs["revision"], - ) - model = AutoModelForCausalLM.from_pretrained( - self.model_path, - low_cpu_mem_usage=True, - **kwargs, - ) - tokenizer.pad_token_id = 9 - return model, tokenizer - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "pytorch": - return False - if "falcon" not in llm_family.model_name: - return False - if "generate" not in llm_family.model_ability: - return False - return True - - -class FalconPytorchChatModel(PytorchChatModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, - ) - - def _load_model(self, **kwargs): - try: - from transformers import AutoModelForCausalLM, AutoTokenizer - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - trust_remote_code=kwargs["trust_remote_code"], - revision=kwargs["revision"], - ) - model = AutoModelForCausalLM.from_pretrained( - self.model_path, - low_cpu_mem_usage=True, - **kwargs, - ) - tokenizer.pad_token_id = 9 - return model, tokenizer - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "pytorch": - return False - if "falcon" not in llm_family.model_name: - return False - if "chat" not in llm_family.model_ability: - return False - return True diff --git a/xinference/model/llm/pytorch/qwen_vl.py b/xinference/model/llm/pytorch/qwen_vl.py deleted file mode 100644 index fb3b86ca41..0000000000 --- a/xinference/model/llm/pytorch/qwen_vl.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import base64 -import logging -import operator -import tempfile -import time -import uuid -from typing import Dict, Iterator, List, Optional, Union - -from ....model.utils import select_device -from ....types import ( - ChatCompletion, - ChatCompletionChoice, - ChatCompletionChunk, - ChatCompletionMessage, - CompletionUsage, -) -from ..llm_family import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchGenerateConfig - -logger = logging.getLogger(__name__) - - -class QwenVLChatModel(PytorchChatModel): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._tokenizer = None - self._model = None - - @classmethod - def match( - cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str - ) -> bool: - if "qwen" in model_family.model_name: - return True - return False - - def load(self): - from transformers import AutoModelForCausalLM, AutoTokenizer - from transformers.generation import GenerationConfig - - device = self._pytorch_model_config.get("device", "auto") - device = select_device(device) - # for multiple GPU, set back to auto to make multiple devices work - device = "auto" if device == "cuda" else device - - self._tokenizer = AutoTokenizer.from_pretrained( - self.model_path, - trust_remote_code=True, - code_revision=self.model_spec.model_revision, - ) - self._model = AutoModelForCausalLM.from_pretrained( - self.model_path, - device_map=device, - trust_remote_code=True, - code_revision=self.model_spec.model_revision, - ).eval() - # Specify hyperparameters for generation - self._model.generation_config = GenerationConfig.from_pretrained( - self.model_path, - trust_remote_code=True, - code_revision=self.model_spec.model_revision, - ) - self._apply_lora() - - def _message_content_to_qwen(self, content) -> str: - def _ensure_url(_url): - if _url.startswith("data:"): - logging.info("Parse url by base64 decoder.") - # https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images - # e.g. f"data:image/jpeg;base64,{base64_image}" - _type, data = _url.split(";") - _, ext = _type.split("/") - data = data[len("base64,") :] - data = base64.b64decode(data.encode("utf-8")) - - with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as f: - f.write(data) - logging.info("Dump base64 data to %s", f.name) - return f.name - else: - if len(_url) > 2048: - raise Exception(f"Image url is too long, {len(_url)} > 2048.") - return _url - - if not isinstance(content, str): - # TODO(codingl2k1): Optimize _ensure_url - content = [ - ( - {"image": _ensure_url(c["image_url"]["url"]), "type": "image"} - if c.get("type") == "image_url" - else c - ) - for c in content - ] - content = sorted(content, key=operator.itemgetter("type")) - return self._tokenizer.from_list_format(content) - return content - - def chat( - self, - prompt: Union[str, List[Dict]], - system_prompt: Optional[str] = None, - chat_history: Optional[List[ChatCompletionMessage]] = None, - generate_config: Optional[PytorchGenerateConfig] = None, - ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: - if generate_config and generate_config.get("stream"): - raise Exception( - f"Chat with model {self.model_family.model_name} does not support stream." - ) - prompt = self._message_content_to_qwen(prompt) - # Convert openai history to qwen vl history - qwen_history = [] - query_to_response: List = [] - for h in chat_history or []: - role = h["role"] - content = self._message_content_to_qwen(h["content"]) - if len(query_to_response) == 0 and role == "user": - query_to_response.append(content) - if len(query_to_response) == 1 and role == "assistant": - query_to_response.append(content) - if len(query_to_response) == 2: - qwen_history.append(query_to_response) - query_to_response = [] - response, history = self._model.chat( - self._tokenizer, query=prompt, history=qwen_history - ) - return ChatCompletion( - id="chat" + str(uuid.uuid1()), - object="chat.completion", - created=int(time.time()), - model=self.model_uid, - choices=[ - ChatCompletionChoice( - index=0, - message={"role": "assistant", "content": response}, - finish_reason="stop", - ) - ], - usage=CompletionUsage( - prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 - ), - ) diff --git a/xinference/model/llm/pytorch/spec_decoding_utils.py b/xinference/model/llm/pytorch/spec_decoding_utils.py deleted file mode 100644 index 33f804bbb6..0000000000 --- a/xinference/model/llm/pytorch/spec_decoding_utils.py +++ /dev/null @@ -1,531 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import gc -import logging -import time -import uuid -from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple - -from ....device_utils import empty_cache - -try: - import torch - from torch.nn import functional as F -except ImportError: - raise ImportError( - f"Failed to import module 'torch'. Please make sure 'torch' is installed.\n\n" - ) - -try: - from transformers import PreTrainedModel, PreTrainedTokenizer - from transformers.generation.logits_process import ( - LogitsProcessorList, - TemperatureLogitsWarper, - TopKLogitsWarper, - TopPLogitsWarper, - ) -except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - -from ....types import CompletionChoice, CompletionChunk, CompletionUsage - -logger = logging.getLogger(__name__) - - -def prepare_logits_processor( - temperature: float, top_p: float, top_k: int -) -> LogitsProcessorList: - processor_list = LogitsProcessorList() - # TemperatureLogitsWarper doesn't accept 0.0, 1.0 makes it a no-op, so we skip two cases. - if temperature >= 1e-5 and temperature != 1.0: - processor_list.append(TemperatureLogitsWarper(temperature)) - if 1e-8 <= top_p < 1.0: - processor_list.append(TopPLogitsWarper(top_p)) - if top_k > 0: - processor_list.append(TopKLogitsWarper(top_k)) - return processor_list - - -def get_context_length(config): - """Get the context length of a model from a huggingface model config.""" - if ( - hasattr(config, "max_sequence_length") - and config.max_sequence_length is not None - ): - return config.max_sequence_length - elif hasattr(config, "seq_length") and config.seq_length is not None: - return config.seq_length - elif ( - hasattr(config, "max_position_embeddings") - and config.max_position_embeddings is not None - ): - return config.max_position_embeddings - else: - return 2048 - - -def normalize_logits( - logits_processor: LogitsProcessorList, - input_ids: List[int], - logits: torch.FloatTensor, # [1, n_seq, n_vocab] -) -> torch.Tensor: - """ - Parameters - ---------- - logits : torch.Tensor - Logits of shape `(n_batch, n_seq, n_vocab)`. - - Returns - ------- - torch.Tensor - Normalized logits of shape `(n_batch, n_seq, n_vocab)`. - """ - - def _helper( - _input_ids: torch.LongTensor, _logits: torch.FloatTensor # [1, n_vocab] - ) -> torch.Tensor: - if logits_processor: - last_token_logits = logits_processor( - _input_ids, - _logits, - )[0] - else: - return _logits[0] - - return last_token_logits # [n_vocab,] - - input_ids = torch.as_tensor([input_ids], device=logits.device).long() - for i in range(logits.shape[1]): - normalized = _helper( - input_ids[ - : -logits.shape[1] + i - ], # input_ids may not equal logits.shape[1] - logits[:, i, :], - ) - logits[:, i, :] = normalized.clone() - return F.softmax(logits, dim=-1) - - -def sample( - last_token_logits: torch.FloatTensor, temperature: float, top_p: float -) -> int: - """ - Parameters - ---------- - last_token_logits : torch.FloatTensor - Last token logits of shape [n_vocab,] - - Returns - ------- - int - Token ID. - """ - if temperature < 1e-5 or top_p < 1e-8: # greedy - _, indices = torch.topk(last_token_logits, 2) - tokens = [int(index) for index in indices.tolist()] - else: - indices = torch.multinomial(last_token_logits, num_samples=2) - tokens = [int(token) for token in indices.tolist()] - return tokens[0] - - -def rollback_kv_cache( - kv_cache: Tuple[Tuple[torch.Tensor, torch.Tensor], ...], n: int -) -> Tuple[Tuple[torch.Tensor, torch.Tensor], ...]: - ret = [] - for k_cache, v_cache in kv_cache: - k_cache = k_cache[:, :, :-n, :] # [1, n_head, n_seq - n, n_dim] - v_cache = v_cache[:, :, :-n, :] - - assert isinstance(k_cache, torch.Tensor) - assert isinstance(v_cache, torch.Tensor) - ret.append((k_cache, v_cache)) - - return tuple(ret) - - -def rollback_logits(logits: torch.Tensor, n: int): - return logits[:, :-n, :] # [1, n_seq, n_vocab] - - -def is_partial_stop(output: str, stop_str: str): - """Check whether the output contains a partial stop str.""" - for i in range(0, min(len(output), len(stop_str))): - if stop_str.startswith(output[-i:]): - return True - return False - - -def draft( - input_ids: List[int], - kv_cache: Optional[Tuple[Tuple[torch.Tensor, torch.Tensor], ...]], - logits: Optional[torch.FloatTensor], - draft_model: "PreTrainedModel", - gamma: int, - logits_processor: LogitsProcessorList, - temperature: float, - top_p: float, -): - """ - Parameters - ---------- - input_ids : List[int] - On the prefill stage, `input_ids` are the prompt tokens. - - On the decode stage. It includes the prompt tokens, the token generated by the original model - at the end of each full iteration, or the token generated by the draft model draft - iteration. - - Returns - ------- - int - The number of generated draft tokens. - List[int] - Outputs, including the draft tokens. - Tuple[Tuple[torch.Tensor, torch.Tensor], ...] - KV cache. - torch.FloatTensor - Logits. - """ - draft_output_ids = input_ids.copy() - - if kv_cache is not None: - input_ids = draft_output_ids[-2:] - - num_draft_tokens = 0 - while num_draft_tokens < gamma: - if kv_cache is None: - # prefill. - draft_model_out = draft_model( - torch.as_tensor([input_ids], device=draft_model.device), - use_cache=True, - ) - logits = normalize_logits( - logits_processor, input_ids, draft_model_out.logits - ) - else: - draft_model_out = draft_model( - torch.as_tensor([input_ids], device=draft_model.device), - use_cache=True, - past_key_values=kv_cache, - ) - normalized = normalize_logits( - logits_processor, draft_output_ids, draft_model_out.logits - ) - assert logits is not None - logits = torch.cat((logits, normalized), dim=1) - kv_cache = draft_model_out.past_key_values - draft_token = sample( - logits[0, -1, :], - temperature, - top_p, - ) - draft_output_ids.append(draft_token) - input_ids = [draft_token] - num_draft_tokens += 1 - - assert kv_cache is not None - return num_draft_tokens, draft_output_ids, kv_cache, logits - - -@torch.inference_mode() -def speculative_generate_stream( - model_uid: str, - draft_model: "PreTrainedModel", - model: "PreTrainedModel", - tokenizer: "PreTrainedTokenizer", - prompt: str, - generate_config: Dict[str, Any], -) -> Iterator[Tuple[CompletionChunk, CompletionUsage]]: - logger.debug( - f"Enter speculative_generate_stream, prompt: {prompt}, generate_config: {generate_config}" - ) - - # TODO: currently, repetition penalty leads to garbled outputs. - if float(generate_config.get("repetition_penalty", 1.0)) != 1.0: - raise ValueError( - "repetition penalty is not supported by speculative decoding yet" - ) - - gamma = generate_config.get("gamma", 4) - stream = generate_config.get("stream", False) - temperature = float(generate_config.get("temperature", 1.0)) - top_p = float(generate_config.get("top_p", 1.0)) - top_k = int(generate_config.get("top_k", -1)) # -1 means disable - max_new_tokens = int(generate_config.get("max_tokens", 256)) - echo = bool(generate_config.get("echo", False)) - stop_str = generate_config.get("stop", None) - stop_token_ids = generate_config.get("stop_token_ids", None) or [] - stop_token_ids.append(tokenizer.eos_token_id) - - logits_processor = prepare_logits_processor(temperature, top_p, top_k) - request_id = str(uuid.uuid1()) - - if "qwen" in str(type(model)).lower(): - # TODO: hacky. - input_ids = tokenizer(prompt, allowed_special="all").input_ids - else: - input_ids = tokenizer(prompt).input_ids - - num_prompt_tokens = len(input_ids) - output_ids = list(input_ids) - - # internal states. - draft_kv_cache = None - draft_logits = None - kv_cache = None - logits = None - next_token = ( - None # the token generated by the original model at each full iteration. - ) - last_output_length = 0 - finish_reason = "stop" - - # performance stats. - total_seconds_on_drafting = 0.0 - total_seconds_on_eval = 0.0 - total_seconds_on_accepting = 0.0 - total_num_draft_tokens = 0 - total_num_accepted_tokens = 0 - - while len(output_ids) < max_new_tokens + num_prompt_tokens: - # allow the draft model to generate more than max_tokens since some of the generated - # tokens could be rejected. - start = time.time() - num_draft_tokens, output_ids, draft_kv_cache, draft_logits = draft( - input_ids=output_ids, - kv_cache=draft_kv_cache, - logits=draft_logits, - draft_model=draft_model, - gamma=gamma, - logits_processor=logits_processor, - temperature=temperature - * 0.5, # make the draft model outputs less random for better quality. - top_p=top_p, - ) - total_seconds_on_drafting += time.time() - start - total_num_draft_tokens += num_draft_tokens - - # eval stage. - start = time.time() - if kv_cache is None: - # prefill. - out = model( - torch.as_tensor([output_ids], device=model.device), use_cache=True - ) - logits = normalize_logits(logits_processor, output_ids, out.logits) - else: - out = model( - torch.as_tensor( - [[next_token] + output_ids[-num_draft_tokens:]], device=model.device - ), - use_cache=True, - past_key_values=kv_cache, - ) - normalized = normalize_logits(logits_processor, output_ids, out.logits) - logits = torch.cat((logits, normalized), dim=1) - kv_cache = out.past_key_values - total_seconds_on_eval += time.time() - start - - # accepting stage. - start = time.time() - assert draft_logits is not None - assert draft_kv_cache is not None - accepted = 0 - stopped = False - for draft_token_idx in range(-num_draft_tokens, 0): - r = torch.rand(1, device=logits.device) - draft_token = output_ids[draft_token_idx] - token_logits = logits[:, draft_token_idx - 1, :] # [1, n_vocab,] - draft_token_logits = draft_logits[:, draft_token_idx, :].to( - logits.device - ) # [1, n_vocab,] - if token_logits[0, draft_token] / draft_token_logits[0, draft_token] > r: - accepted += 1 - total_num_accepted_tokens += 1 - if draft_token in stop_token_ids: - stopped = True - else: - if logger.getEffectiveLevel() <= logging.DEBUG: - logger.debug( - f"Accepted ({accepted}/{num_draft_tokens}): '{tokenizer.decode(output_ids[-num_draft_tokens: draft_token_idx])}'" - ) - logger.debug( - f"Rejected: '{tokenizer.decode(output_ids[draft_token_idx:])}'" - ) - # rollback. - output_ids = output_ids[:draft_token_idx] - draft_kv_cache = rollback_kv_cache( - draft_kv_cache, num_draft_tokens - accepted - ) - kv_cache = rollback_kv_cache(kv_cache, num_draft_tokens - accepted) - draft_logits = rollback_logits( - draft_logits, num_draft_tokens - accepted - ) - logits = rollback_logits(logits, num_draft_tokens - accepted) - - # sample the next token according to the modified distribution of shape [1, n_vocab] - modified_dist = token_logits - draft_token_logits - modified_dist = torch.where( - modified_dist > 0, modified_dist, torch.zeros_like(modified_dist) - ) - normalized = normalize_logits( - logits_processor, - output_ids, - modified_dist.unsqueeze(1), # [1, 1, n_vocab] - ) - next_token = sample( - normalized[0, -1, :], - 0, # must be 0, since the dist is quiet unified, higher temperature results in garbled text - top_p, - ) - output_ids.append(next_token) - if logger.getEffectiveLevel() <= logging.DEBUG: - logger.debug(f"Generated: '{tokenizer.decode([next_token])}'") - if next_token in stop_token_ids: - stopped = True - break - - if accepted == num_draft_tokens: - if logger.getEffectiveLevel() <= logging.DEBUG: - logger.debug( - f"Accepted ({accepted}/{num_draft_tokens}): '{tokenizer.decode(output_ids[-num_draft_tokens:])}'" - ) - next_token = sample( - logits[0, -1, :], - temperature, - top_p, - ) - output_ids.append(next_token) - if logger.getEffectiveLevel() <= logging.DEBUG: - logger.debug(f"Generated: '{tokenizer.decode([next_token])}'") - if next_token in stop_token_ids: - stopped = True - - total_seconds_on_accepting += time.time() - start - - if ( - accepted > 0 # more than 2 tokens has been generated, flush. - or len(output_ids) >= max_new_tokens - or stopped - ): - output = tokenizer.decode( - output_ids if echo else output_ids[num_prompt_tokens:], - spaces_between_special_tokens=False, - clean_up_tokenization_spaces=True, - ) - rfind_start = len(prompt) if echo else 0 - - partially_stopped = False - if stop_str: - if isinstance(stop_str, str): - pos = output.rfind(stop_str, rfind_start) - if pos != -1: - output = output[:pos] - stopped = True - else: - partially_stopped = is_partial_stop(output, stop_str) - elif isinstance(stop_str, Iterable): - for each_stop in stop_str: - pos = output.rfind(each_stop, rfind_start) - if pos != -1: - output = output[:pos] - stopped = True - break - else: - partially_stopped = is_partial_stop(output, each_stop) - if partially_stopped: - break - else: - raise ValueError(f"Invalid stop field type {type(stop_str)}") - - if stream: - # return the delta. - output_length = len(output) - output = output[last_output_length:] - last_output_length = output_length - - # prevent yielding partial stop sequence. - if not partially_stopped: - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=None - ) - completion_chunk = CompletionChunk( - id=request_id, - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=num_prompt_tokens, - completion_tokens=len(output_ids) - num_prompt_tokens, - total_tokens=len(output_ids), - ) - - yield completion_chunk, completion_usage - if stopped: - break - else: - finish_reason = "length" - - logger.info( - f"In total, {total_num_accepted_tokens}/{total_num_draft_tokens} draft tokens are " - f"accepted, acceptance rate: {total_num_accepted_tokens / total_num_draft_tokens:.2f}" - ) - total_seconds = ( - total_seconds_on_drafting + total_seconds_on_eval + total_seconds_on_accepting - ) - logger.info( - f"In total, {total_seconds_on_drafting:.2f}s, {total_seconds_on_eval:.2f}s and " - f"{total_seconds_on_accepting:.2f}s are spent on drafting, eval, and accepting " - f"respectively. Average generation speed: {(len(output_ids) - num_prompt_tokens) / total_seconds:.2f} tokens/s." - ) - - if stream: - completion_choice = CompletionChoice( - text="", index=0, logprobs=None, finish_reason=finish_reason - ) - else: - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=finish_reason - ) - - completion_chunk = CompletionChunk( - id=request_id, - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=num_prompt_tokens, - completion_tokens=len(output_ids) - num_prompt_tokens, - total_tokens=len(output_ids), - ) - - yield completion_chunk, completion_usage - - # clean up. - del kv_cache - del draft_kv_cache - gc.collect() - empty_cache() diff --git a/xinference/model/llm/pytorch/spec_model.py b/xinference/model/llm/pytorch/spec_model.py deleted file mode 100644 index 134ade2342..0000000000 --- a/xinference/model/llm/pytorch/spec_model.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -from typing import Iterator, List, Optional, Union - -from ....device_utils import ( - get_device_preferred_dtype, - gpu_count, - is_hf_accelerate_supported, -) -from ....types import Completion, CompletionChunk, Embedding -from ...utils import select_device -from .. import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchGenerateConfig, PytorchModelConfig - -logger = logging.getLogger(__name__) - - -class SpeculativeModel(PytorchChatModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - draft_model_family: "LLMFamilyV1", - draft_model_spec: "LLMSpecV1", - draft_quantization: str, - draft_model_path: str, - ): - super().__init__(model_uid, model_family, model_spec, quantization, model_path) - self._pytorch_model_config: PytorchModelConfig = self._sanitize_model_config( - PytorchModelConfig() - ) - self._draft_model_family = draft_model_family - self._draft_model_spec = draft_model_spec - self._draft_quantization = draft_quantization - self._draft_model_path = draft_model_path - - def _load_model(self, model_path, **kwargs): - try: - from transformers import AutoModelForCausalLM, AutoTokenizer - except ImportError: - error_message = "Failed to import module 'transformers'" - installation_guide = [ - "Please make sure 'transformers' is installed. ", - "You can install it by `pip install transformers`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - tokenizer = AutoTokenizer.from_pretrained( - model_path, - use_fast=self._use_fast_tokenizer, - trust_remote_code=kwargs["trust_remote_code"], - revision=kwargs["revision"], - ) - model = AutoModelForCausalLM.from_pretrained( - model_path, - low_cpu_mem_usage=True, - **kwargs, - ) - return model, tokenizer - - def load(self): - try: - import torch # noqa: F401 - except ImportError: - raise ImportError( - f"Failed to import module 'torch'. Please make sure 'torch' is installed.\n\n" - ) - - num_gpus = gpu_count() - device = self._pytorch_model_config.get("device", "auto") - self._pytorch_model_config["device"] = select_device(device) - self._device = self._pytorch_model_config["device"] - - kwargs = {} - - dtype = get_device_preferred_dtype(self._device) - - if dtype is not None: - kwargs["torch_dtype"] = dtype - else: - raise ValueError(f"Device {self._device} is not supported in temporary") - - kwargs["trust_remote_code"] = self._pytorch_model_config.get( - "trust_remote_code" - ) - - if self.quantization != "none": - raise ValueError( - "Quantization is not supported by speculative decoding yet" - ) - - is_device_map_auto = False - - if num_gpus > 0 and is_hf_accelerate_supported(self._device): - kwargs.update({"device_map": "auto"}) - is_device_map_auto = True - - self._model, self._tokenizer = self._load_model( - model_path=self.model_path, - revision=self.model_spec.model_revision, - **kwargs, - ) - if not is_device_map_auto: - self._model.to(self._device) - logger.debug( - f"Model {self.model_uid} memory footprint: {self._model.get_memory_footprint()}" - ) - - self._draft_model, _ = self._load_model( - model_path=self._draft_model_path, - revision=self._draft_model_spec.model_revision, - **kwargs, - ) - if not is_device_map_auto: - self._model.to(self._device) - logger.debug( - f"Draft model {self.model_uid} memory footprint: {self._model.get_memory_footprint()}" - ) - - def generate( - self, prompt: str, generate_config: Optional[PytorchGenerateConfig] = None - ) -> Union[Completion, Iterator[CompletionChunk]]: - def generator_wrapper( - _prompt: str, _generate_config: PytorchGenerateConfig - ) -> Iterator[CompletionChunk]: - for _completion_chunk, _completion_usage in speculative_generate_stream( - model_uid=self.model_uid, - draft_model=self._draft_model, - model=self._model, - tokenizer=self._tokenizer, - prompt=_prompt, - generate_config=_generate_config, - ): - yield _completion_chunk - - from .spec_decoding_utils import speculative_generate_stream - - generate_config = self._sanitize_generate_config(generate_config) - - assert self._draft_model is not None - assert self._model is not None - assert self._tokenizer is not None - - stream = generate_config.get("stream", False) - if not stream: - for completion_chunk, completion_usage in speculative_generate_stream( - model_uid=self.model_uid, - draft_model=self._draft_model, - model=self._model, - tokenizer=self._tokenizer, - prompt=prompt, - generate_config=generate_config, - ): - pass - - completion = Completion( - id=completion_chunk["id"], - object=completion_chunk["object"], - created=completion_chunk["created"], - model=completion_chunk["model"], - choices=completion_chunk["choices"], - usage=completion_usage, - ) - return completion - else: - return generator_wrapper(prompt, generate_config) - - def create_embedding(self, input: Union[str, List[str]]) -> Embedding: - raise NotImplementedError diff --git a/xinference/model/llm/pytorch/tests/test_spec_decoding.py b/xinference/model/llm/pytorch/tests/test_spec_decoding.py deleted file mode 100644 index 106a964801..0000000000 --- a/xinference/model/llm/pytorch/tests/test_spec_decoding.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging - -import pytest -import torch -from transformers import AutoModelForCausalLM, AutoTokenizer - -from ..spec_decoding_utils import speculative_generate_stream - -logging.basicConfig(level=logging.DEBUG) - - -@pytest.mark.skip(reason="Temporary disabled") -def test_spec_decoding(): - """ - Use the draft model itself as the target model. If the decoding works, all the draft tokens - should be accepted, and the result of speculative decoding should be the same as the regular - decoding, which starts with "The largest animal ever recorded is the Tyrannosaurus Rex". - """ - - model_id = "PY007/TinyLlama-1.1B-Chat-v0.3" - draft_model = AutoModelForCausalLM.from_pretrained( - model_id, - device_map="auto", - torch_dtype=torch.float16, - ) - tokenizer = AutoTokenizer.from_pretrained(model_id) - prompt = "What is the largest animal?" - formatted_prompt = f"<|im_start|>user\n{prompt}<|im_end|>\n<|im_start|>assistant\n" - - for completion_chunk, completion_usage in speculative_generate_stream( - model_uid=model_id, - draft_model=draft_model, - model=draft_model, - tokenizer=tokenizer, - prompt=formatted_prompt, - generate_config={"model": "test", "temperature": 0, "max_tokens": 64}, - ): - pass - - completion = completion_chunk["choices"][0]["text"] - assert completion.startswith( - "The largest animal ever recorded is the Tyrannosaurus Rex" - ) diff --git a/xinference/model/llm/pytorch/utils.py b/xinference/model/llm/pytorch/utils.py deleted file mode 100644 index 98c3c4a557..0000000000 --- a/xinference/model/llm/pytorch/utils.py +++ /dev/null @@ -1,493 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import gc -import logging -import time -import uuid -from threading import Thread -from typing import Iterable, Iterator, Tuple - -import torch -from transformers import GenerationConfig, TextIteratorStreamer -from transformers.generation.logits_process import ( - LogitsProcessorList, - RepetitionPenaltyLogitsProcessor, - TemperatureLogitsWarper, - TopKLogitsWarper, - TopPLogitsWarper, -) - -from ....device_utils import empty_cache -from ....types import ( - CompletionChoice, - CompletionChunk, - CompletionUsage, - max_tokens_field, -) - -logger = logging.getLogger(__name__) - - -def is_sentence_complete(output: str): - """Check whether the output is a complete sentence.""" - end_symbols = (".", "?", "!", "...", "。", "?", "!", "…", '"', "'", "”") - return output.endswith(end_symbols) - - -def is_partial_stop(output: str, stop_str: str): - """Check whether the output contains a partial stop str.""" - for i in range(0, min(len(output), len(stop_str))): - if stop_str.startswith(output[-i:]): - return True - return False - - -def get_context_length(config): - """Get the context length of a model from a huggingface model config.""" - if ( - hasattr(config, "max_sequence_length") - and config.max_sequence_length is not None - ): - max_sequence_length = config.max_sequence_length - else: - max_sequence_length = 2048 - if hasattr(config, "seq_length") and config.seq_length is not None: - seq_length = config.seq_length - else: - seq_length = 2048 - if ( - hasattr(config, "max_position_embeddings") - and config.max_position_embeddings is not None - ): - max_position_embeddings = config.max_position_embeddings - else: - max_position_embeddings = 2048 - return max(max_sequence_length, seq_length, max_position_embeddings) - - -def prepare_logits_processor( - temperature: float, repetition_penalty: float, top_p: float, top_k: int -) -> LogitsProcessorList: - processor_list = LogitsProcessorList() - # TemperatureLogitsWarper doesn't accept 0.0, 1.0 makes it a no-op so we skip two cases. - if temperature >= 1e-5 and temperature != 1.0: - processor_list.append(TemperatureLogitsWarper(temperature)) - if repetition_penalty > 1.0: - processor_list.append(RepetitionPenaltyLogitsProcessor(repetition_penalty)) - if 1e-8 <= top_p < 1.0: - processor_list.append(TopPLogitsWarper(top_p)) - if top_k > 0: - processor_list.append(TopKLogitsWarper(top_k)) - return processor_list - - -@torch.inference_mode() -def generate_stream( - model_uid, - model, - tokenizer, - prompt, - device, - generate_config, - judge_sent_end=False, -) -> Iterator[Tuple[CompletionChunk, CompletionUsage]]: - context_len = get_context_length(model.config) - stream_interval = generate_config.get("stream_interval", 2) - stream = generate_config.get("stream", False) - - len_prompt = len(prompt) - - temperature = float(generate_config.get("temperature", 1.0)) - repetition_penalty = float(generate_config.get("repetition_penalty", 1.0)) - top_p = float(generate_config.get("top_p", 1.0)) - top_k = int(generate_config.get("top_k", -1)) # -1 means disable - max_new_tokens = int(generate_config.get("max_tokens", max_tokens_field.default)) - echo = bool(generate_config.get("echo", False)) - stop_str = generate_config.get("stop", None) - stop_token_ids = generate_config.get("stop_token_ids", None) or [] - stop_token_ids.append(tokenizer.eos_token_id) - - logits_processor = prepare_logits_processor( - temperature, repetition_penalty, top_p, top_k - ) - - if ".modeling_qwen." in str(type(model)).lower(): - # TODO: hacky - input_ids = tokenizer(prompt, allowed_special="all").input_ids - else: - input_ids = tokenizer(prompt).input_ids - output_ids = list(input_ids) - - if model.config.is_encoder_decoder: - max_src_len = context_len - else: - max_src_len = context_len - max_new_tokens - 8 - if max_src_len < 0: - raise ValueError("Max tokens exceeds model's max length") - - input_ids = input_ids[-max_src_len:] - input_echo_len = len(input_ids) - - if model.config.is_encoder_decoder: - encoder_output = model.encoder( - input_ids=torch.as_tensor([input_ids], device=device) - )[0] - start_ids = torch.as_tensor( - [[model.generation_config.decoder_start_token_id]], - dtype=torch.int64, - device=device, - ) - - start = time.time() - past_key_values = out = None - sent_interrupt = False - token = None - last_output_length = 0 - for i in range(max_new_tokens): - if i == 0: - if model.config.is_encoder_decoder: - out = model.decoder( - input_ids=start_ids, - encoder_hidden_states=encoder_output, - use_cache=True, - ) - logits = model.lm_head(out[0]) - else: - out = model(torch.as_tensor([input_ids], device=device), use_cache=True) - logits = out.logits - past_key_values = out.past_key_values - else: - if model.config.is_encoder_decoder: - out = model.decoder( - input_ids=torch.as_tensor( - [[token] if not sent_interrupt else output_ids], device=device - ), - encoder_hidden_states=encoder_output, - use_cache=True, - past_key_values=past_key_values if not sent_interrupt else None, - ) - sent_interrupt = False - - logits = model.lm_head(out[0]) - else: - out = model( - input_ids=torch.as_tensor( - [[token] if not sent_interrupt else output_ids], device=device - ), - use_cache=True, - past_key_values=past_key_values if not sent_interrupt else None, - ) - sent_interrupt = False - logits = out.logits - past_key_values = out.past_key_values - - if logits_processor: - if repetition_penalty > 1.0: - tmp_output_ids = torch.as_tensor([output_ids], device=logits.device) - else: - tmp_output_ids = None - last_token_logits = logits_processor(tmp_output_ids, logits[:, -1, :])[0] - else: - last_token_logits = logits[0, -1, :] - - if device == "mps": - # Switch to CPU by avoiding some bugs in mps backend. - last_token_logits = last_token_logits.float().to("cpu") - - if temperature < 1e-5 or top_p < 1e-8: # greedy - _, indices = torch.topk(last_token_logits, 2) - tokens = [int(index) for index in indices.tolist()] - else: - probs = torch.softmax(last_token_logits, dim=-1) - indices = torch.multinomial(probs, num_samples=2) - tokens = [int(token) for token in indices.tolist()] - token = tokens[0] - output_ids.append(token) - - if token in stop_token_ids: - stopped = True - else: - stopped = False - - if i % stream_interval == 0 or i == max_new_tokens - 1 or stopped: - if echo: - tmp_output_ids = output_ids - rfind_start = len_prompt - else: - tmp_output_ids = output_ids[input_echo_len:] - rfind_start = 0 - - output = tokenizer.decode( - tmp_output_ids, - skip_special_tokens=True, - spaces_between_special_tokens=False, - clean_up_tokenization_spaces=True, - ) - - # TODO: For the issue of incomplete sentences interrupting output, apply a patch and others can also modify it to a more elegant way - if judge_sent_end and stopped and not is_sentence_complete(output): - if len(tokens) > 1: - token = tokens[1] - output_ids[-1] = token - else: - output_ids.pop() - stopped = False - sent_interrupt = True - - partially_stopped = False - if stop_str: - if isinstance(stop_str, str): - pos = output.rfind(stop_str, rfind_start) - if pos != -1: - output = output[:pos] - stopped = True - else: - partially_stopped = is_partial_stop(output, stop_str) - elif isinstance(stop_str, Iterable): - for each_stop in stop_str: - pos = output.rfind(each_stop, rfind_start) - if pos != -1: - output = output[:pos] - stopped = True - break - else: - partially_stopped = is_partial_stop(output, each_stop) - if partially_stopped: - break - else: - raise ValueError("Invalid stop field type.") - - if stream: - output = output.strip("�") - tmp_output_length = len(output) - output = output[last_output_length:] - last_output_length = tmp_output_length - - # prevent yielding partial stop sequence - if not partially_stopped: - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=None - ) - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=input_echo_len, - completion_tokens=i, - total_tokens=(input_echo_len + i), - ) - - yield completion_chunk, completion_usage - - if stopped: - break - - elapsed_time = time.time() - start - logger.info(f"Average generation speed: {i / elapsed_time:.2f} tokens/s.") - - # finish stream event, which contains finish reason - if stopped: - finish_reason = "stop" - elif i == max_new_tokens - 1: - finish_reason = "length" - else: - finish_reason = None - - if stream: - completion_choice = CompletionChoice( - text="", index=0, logprobs=None, finish_reason=finish_reason - ) - else: - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=finish_reason - ) - - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=input_echo_len, - completion_tokens=i, - total_tokens=(input_echo_len + i), - ) - - yield completion_chunk, completion_usage - - # clean - del past_key_values, out - gc.collect() - empty_cache() - - -@torch.inference_mode() -def generate_stream_falcon( - model_uid, - model, - tokenizer, - prompt, - device, - generate_config, - judge_sent_end=False, -) -> Iterator[Tuple[CompletionChunk, CompletionUsage]]: - context_len = get_context_length(model.config) - stream_interval = generate_config.get("stream_interval", 2) - stream = generate_config.get("stream", False) - - len_prompt = len(prompt) - - temperature = float(generate_config.get("temperature", 1.0)) - repetition_penalty = float(generate_config.get("repetition_penalty", 1.0)) - top_p = float(generate_config.get("top_p", 1.0)) - top_k = int(generate_config.get("top_k", 50)) # -1 means disable - max_new_tokens = int(generate_config.get("max_tokens", max_tokens_field.default)) - echo = bool(generate_config.get("echo", False)) - stop_str = generate_config.get("stop", None) - stop_token_ids = generate_config.get("stop_token_ids", None) or [] - stop_token_ids.append(tokenizer.eos_token_id) - - inputs = tokenizer(prompt, return_tensors="pt").to(model.device) - input_ids = inputs["input_ids"] - attention_mask = inputs["attention_mask"] - - max_src_len = context_len - max_new_tokens - 8 - - input_ids = input_ids[-max_src_len:] # truncate from the left - attention_mask = attention_mask[-max_src_len:] # truncate from the left - input_echo_len = len(input_ids) - - decode_config = dict(skip_special_tokens=True, clean_up_tokenization_spaces=True) - streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, **decode_config) - - generation_config = GenerationConfig( - max_new_tokens=max_new_tokens, - do_sample=temperature >= 1e-5, - temperature=temperature, - repetition_penalty=repetition_penalty, - no_repeat_ngram_size=10, - top_p=top_p, - top_k=top_k, - eos_token_id=stop_token_ids, - ) - - generation_kwargs = dict( - inputs=input_ids, - attention_mask=attention_mask, - streamer=streamer, - generation_config=generation_config, - ) - - thread = Thread(target=model.generate, kwargs=generation_kwargs) - thread.start() - - if echo: - # means keep the prompt - output = prompt - else: - output = "" - - last_output_length = 0 - for i, new_text in enumerate(streamer): - output += new_text - if i % stream_interval == 0: - if echo: - rfind_start = len_prompt - else: - rfind_start = 0 - - partially_stopped = False - if stop_str: - if isinstance(stop_str, str): - pos = output.rfind(stop_str, rfind_start) - if pos != -1: - output = output[:pos] - else: - partially_stopped = is_partial_stop(output, stop_str) - elif isinstance(stop_str, Iterable): - for each_stop in stop_str: - pos = output.rfind(each_stop, rfind_start) - if pos != -1: - output = output[:pos] - break - else: - partially_stopped = is_partial_stop(output, each_stop) - if partially_stopped: - break - else: - raise ValueError("Invalid stop field type.") - - if stream: - output = output.strip("�") - tmp_output_length = len(output) - output = output[last_output_length:] - last_output_length = tmp_output_length - - # prevent yielding partial stop sequence - if not partially_stopped: - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=None - ) - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=input_echo_len, - completion_tokens=i, - total_tokens=(input_echo_len + i), - ) - - yield completion_chunk, completion_usage - output = output.strip() - - # finish stream event, which contains finish reason - if i == max_new_tokens - 1: - finish_reason = "length" - elif partially_stopped: - finish_reason = None - else: - finish_reason = "stop" - - completion_choice = CompletionChoice( - text=output, index=0, logprobs=None, finish_reason=finish_reason - ) - completion_chunk = CompletionChunk( - id=str(uuid.uuid1()), - object="text_completion", - created=int(time.time()), - model=model_uid, - choices=[completion_choice], - ) - completion_usage = CompletionUsage( - prompt_tokens=input_echo_len, - completion_tokens=i, - total_tokens=(input_echo_len + i), - ) - - yield completion_chunk, completion_usage - - # clean - gc.collect() - empty_cache() diff --git a/xinference/model/llm/pytorch/vicuna.py b/xinference/model/llm/pytorch/vicuna.py deleted file mode 100644 index 89231a0702..0000000000 --- a/xinference/model/llm/pytorch/vicuna.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Copyright 2022-2023 XProbe Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from typing import Optional - -from .. import LLMFamilyV1, LLMSpecV1 -from .core import PytorchChatModel, PytorchModelConfig - - -class VicunaPytorchChatModel(PytorchChatModel): - def __init__( - self, - model_uid: str, - model_family: "LLMFamilyV1", - model_spec: "LLMSpecV1", - quantization: str, - model_path: str, - pytorch_model_config: Optional["PytorchModelConfig"] = None, - peft_model_path: Optional[str] = None, - ): - super().__init__( - model_uid, - model_family, - model_spec, - quantization, - model_path, - pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, - ) - self._use_fast_tokenizer = False - - @classmethod - def match( - cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str - ) -> bool: - if llm_spec.model_format != "pytorch": - return False - if "vicuna" not in llm_family.model_name: - return False - if "chat" not in llm_family.model_ability: - return False - return True diff --git a/xinference/model/llm/sglang/core.py b/xinference/model/llm/sglang/core.py index 97cea3f68f..3c31b4fe7a 100644 --- a/xinference/model/llm/sglang/core.py +++ b/xinference/model/llm/sglang/core.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json import logging import time import uuid from typing import AsyncGenerator, Dict, List, Optional, TypedDict, Union -from ....constants import XINFERENCE_ENABLE_SGLANG from ....types import ( ChatCompletion, ChatCompletionChunk, @@ -53,6 +53,7 @@ class SGLANGGenerateConfig(TypedDict, total=False): stop: Optional[Union[str, List[str]]] ignore_eos: bool stream: bool + stream_options: Optional[Union[dict, None]] try: @@ -62,15 +63,26 @@ class SGLANGGenerateConfig(TypedDict, total=False): except ImportError: SGLANG_INSTALLED = False -SGLANG_SUPPORTED_MODELS = ["llama-2", "mistral-v0.1", "mixtral-v0.1"] +SGLANG_SUPPORTED_MODELS = [ + "llama-2", + "llama-3", + "llama-3.1", + "mistral-v0.1", + "mixtral-v0.1", +] SGLANG_SUPPORTED_CHAT_MODELS = [ "llama-2-chat", + "llama-3-instruct", + "llama-3.1-instruct", "qwen-chat", "qwen1.5-chat", + "qwen2-instruct", + "qwen2-moe-instruct", "mistral-instruct-v0.1", "mistral-instruct-v0.2", "mixtral-instruct-v0.1", "gemma-it", + "gemma-2-it", ] @@ -101,6 +113,13 @@ def load(self): raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") self._model_config = self._sanitize_model_config(self._model_config) + + # Fix: GH#2169 + if sgl.__version__ >= "0.2.14": + self._model_config.setdefault("triton_attention_reduce_in_fp32", False) + else: + self._model_config.setdefault("attention_reduce_in_fp32", False) + logger.info( f"Loading {self.model_uid} with following model config: {self._model_config}" ) @@ -111,6 +130,10 @@ def load(self): **self._model_config, ) + def stop(self): + logger.info("Stopping SGLang engine") + self._engine.shutdown() + def _sanitize_model_config( self, model_config: Optional[SGLANGModelConfig] ) -> SGLANGModelConfig: @@ -121,20 +144,21 @@ def _sanitize_model_config( model_config.setdefault("tokenizer_mode", "auto") model_config.setdefault("trust_remote_code", True) model_config.setdefault("tp_size", cuda_count) - # See https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/server_args.py#L37 - mem_fraction_static = model_config.pop("mem_fraction_static", None) + # See https://github.com/sgl-project/sglang/blob/00023d622a6d484e67ef4a0e444f708b8fc861c8/python/sglang/srt/server_args.py#L100-L109 + mem_fraction_static = model_config.get("mem_fraction_static") if mem_fraction_static is None: tp_size = model_config.get("tp_size", cuda_count) - if tp_size >= 8: - model_config["mem_fraction_static"] = 0.80 + if tp_size >= 16: + model_config["mem_fraction_static"] = 0.79 + elif tp_size >= 8: + model_config["mem_fraction_static"] = 0.83 elif tp_size >= 4: - model_config["mem_fraction_static"] = 0.82 - elif tp_size >= 2: model_config["mem_fraction_static"] = 0.85 + elif tp_size >= 2: + model_config["mem_fraction_static"] = 0.87 else: - model_config["mem_fraction_static"] = 0.90 + model_config["mem_fraction_static"] = 0.88 model_config.setdefault("log_level", "info") - model_config.setdefault("attention_reduce_in_fp32", False) return model_config @@ -157,6 +181,8 @@ def _sanitize_generate_config( ) generate_config.setdefault("stop", []) generate_config.setdefault("stream", False) + stream_options = generate_config.get("stream_options") + generate_config.setdefault("stream_options", stream_options) generate_config.setdefault("ignore_eos", False) return generate_config @@ -165,13 +191,11 @@ def _sanitize_generate_config( def match( cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str ) -> bool: - if not XINFERENCE_ENABLE_SGLANG: - return False if not cls._has_cuda_device(): return False if not cls._is_linux(): return False - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + if llm_spec.model_format not in ["pytorch", "gptq", "awq", "fp8"]: return False if llm_spec.model_format == "pytorch": if quantization != "none" and not (quantization is None): @@ -192,7 +216,7 @@ def match( @staticmethod def _convert_state_to_completion_chunk( - request_id: str, model: str, output_text: str, meta_info: Dict + request_id: str, model: str, output_text: str ) -> CompletionChunk: choices: List[CompletionChoice] = [ CompletionChoice( @@ -209,13 +233,6 @@ def _convert_state_to_completion_chunk( model=model, choices=choices, ) - prompt_tokens = meta_info["prompt_tokens"] - completion_tokens = meta_info["completion_tokens"] - chunk["usage"] = CompletionUsage( - prompt_tokens=prompt_tokens, - completion_tokens=completion_tokens, - total_tokens=prompt_tokens + completion_tokens, - ) return chunk @staticmethod @@ -245,55 +262,117 @@ def _convert_state_to_completion( usage=usage, ) + @classmethod + def _filter_sampling_params(cls, sampling_params: dict): + if not sampling_params.get("lora_name"): + sampling_params.pop("lora_name", None) + return sampling_params + + async def _stream_generate(self, prompt: str, **sampling_params): + import aiohttp + + sampling_params = self._filter_sampling_params(sampling_params) + json_data = { + "text": prompt, + "sampling_params": sampling_params, + "stream": True, + } + pos = 0 + + timeout = aiohttp.ClientTimeout(total=3 * 3600) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.post( + self._engine.generate_url, json=json_data # type: ignore + ) as response: + async for chunk, _ in response.content.iter_chunks(): + chunk = chunk.decode("utf-8") + if chunk and chunk.startswith("data:"): + stop = "data: [DONE]\n\n" + need_stop = False + if chunk.endswith(stop): + chunk = chunk[: -len(stop)] + need_stop = True + if chunk: + data = json.loads(chunk[5:].strip("\n")) + cur = data["text"][pos:] + if cur: + yield data["meta_info"], cur + pos += len(cur) + if need_stop: + break + + async def _non_stream_generate(self, prompt: str, **sampling_params) -> dict: + import aiohttp + + sampling_params = self._filter_sampling_params(sampling_params) + json_data = { + "text": prompt, + "sampling_params": sampling_params, + } + async with aiohttp.ClientSession(trust_env=True) as session: + async with session.post( + self._engine.generate_url, json=json_data # type: ignore + ) as response: + return await response.json() + async def async_generate( self, prompt: str, generate_config: Optional[SGLANGGenerateConfig] = None, ) -> Union[Completion, AsyncGenerator[CompletionChunk, None]]: - try: - import sglang as sgl - from sglang import assistant, gen, user - except ImportError: - error_message = "Failed to import module 'sglang'" - installation_guide = [ - "Please make sure 'sglang' is installed. ", - "You can install it by `pip install sglang[all]`\n", - ] - - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - - @sgl.function - def pipeline(s, question): - s += user(question) - s += assistant(gen("answer")) - sanitized_generate_config = self._sanitize_generate_config(generate_config) logger.debug( "Enter generate, prompt: %s, generate config: %s", prompt, generate_config ) stream = sanitized_generate_config.pop("stream") - request_id = str(uuid.uuid1()) - state = pipeline.run( - question=prompt, - backend=self._engine, - stream=stream, - **sanitized_generate_config, + stream_options = sanitized_generate_config.pop("stream_options") + + include_usage = ( + stream_options.pop("include_usage") + if isinstance(stream_options, dict) + else False ) + + request_id = str(uuid.uuid1()) if not stream: + state = await self._non_stream_generate(prompt, **sanitized_generate_config) return self._convert_state_to_completion( request_id, model=self.model_uid, - output_text=state["answer"], - meta_info=state.get_meta_info(name="answer"), + output_text=state["text"], + meta_info=state["meta_info"], ) else: async def stream_results() -> AsyncGenerator[CompletionChunk, None]: - async for out, meta_info in state.text_async_iter( - var_name="answer", return_meta_data=True + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + async for meta_info, out in self._stream_generate( + prompt, **sanitized_generate_config ): chunk = self._convert_state_to_completion_chunk( - request_id, self.model_uid, output_text=out, meta_info=meta_info + request_id, self.model_uid, output_text=out + ) + prompt_tokens = meta_info["prompt_tokens"] + completion_tokens = meta_info["completion_tokens"] + total_tokens = prompt_tokens + completion_tokens + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk + if include_usage: + chunk = CompletionChunk( + id=request_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, ) yield chunk @@ -305,9 +384,7 @@ class SGLANGChatModel(SGLANGModel, ChatModelMixin): def match( cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str ) -> bool: - if not XINFERENCE_ENABLE_SGLANG: - return False - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + if llm_spec.model_format not in ["pytorch", "gptq", "awq", "fp8"]: return False if llm_spec.model_format == "pytorch": if quantization != "none" and not (quantization is None): diff --git a/xinference/model/llm/tests/test_llm_family.py b/xinference/model/llm/tests/test_llm_family.py index fe093822a2..252491282c 100644 --- a/xinference/model/llm/tests/test_llm_family.py +++ b/xinference/model/llm/tests/test_llm_family.py @@ -16,16 +16,15 @@ import os import shutil import tempfile -from unittest.mock import MagicMock, Mock, patch +from unittest.mock import patch import pytest from ....constants import XINFERENCE_ENV_MODEL_SRC from ...utils import is_locale_chinese_simplified, valid_model_revision from ..llm_family import ( - AWSRegion, CustomLLMFamilyV1, - GgmlLLMSpecV1, + LlamaCppLLMSpecV1, LLMFamilyV1, PromptStyleV1, PytorchLLMSpecV1, @@ -33,9 +32,10 @@ _get_cache_dir, _get_meta_path, _skip_download, - is_self_hosted, + convert_model_size_to_float, is_valid_model_uri, match_llm, + match_model_size, parse_uri, ) @@ -53,15 +53,15 @@ def test_deserialize_llm_family_v1(): ], "model_specs":[ { - "model_format":"ggmlv3", + "model_format":"ggufv2", "model_size_in_billions":2, "quantizations": ["q4_0", "q4_1"], "quantization_parts": { "q4_2": ["a", "b"] }, "model_id":"example/TestModel", - "model_file_name_template":"TestModel.{quantization}.ggmlv3.bin", - "model_file_name_split_template":"TestModel.{quantization}.ggmlv3.bin.{part}" + "model_file_name_template":"TestModel.{quantization}.bin", + "model_file_name_split_template":"TestModel.{quantization}.bin.{part}" }, { "model_format":"pytorch", @@ -89,18 +89,18 @@ def test_deserialize_llm_family_v1(): assert model_family.model_ability == ["embed", "generate"] assert len(model_family.model_specs) == 2 - ggml_spec = model_family.model_specs[0] - assert ggml_spec.model_format == "ggmlv3" - assert ggml_spec.model_size_in_billions == 2 - assert ggml_spec.model_id == "example/TestModel" - assert ggml_spec.model_hub == "huggingface" - assert ggml_spec.model_file_name_template == "TestModel.{quantization}.ggmlv3.bin" + gguf_spec = model_family.model_specs[0] + assert gguf_spec.model_format == "ggufv2" + assert gguf_spec.model_size_in_billions == 2 + assert gguf_spec.model_id == "example/TestModel" + assert gguf_spec.model_hub == "huggingface" + assert gguf_spec.model_file_name_template == "TestModel.{quantization}.bin" assert ( - ggml_spec.model_file_name_split_template - == "TestModel.{quantization}.ggmlv3.bin.{part}" + gguf_spec.model_file_name_split_template + == "TestModel.{quantization}.bin.{part}" ) - assert ggml_spec.quantization_parts["q4_2"][0] == "a" - assert ggml_spec.quantization_parts["q4_2"][1] == "b" + assert gguf_spec.quantization_parts["q4_2"][0] == "a" + assert gguf_spec.quantization_parts["q4_2"][1] == "b" pytorch_spec = model_family.model_specs[1] assert pytorch_spec.model_format == "pytorch" @@ -122,15 +122,15 @@ def test_deserialize_llm_family_v1(): def test_serialize_llm_family_v1(): - ggml_spec = GgmlLLMSpecV1( - model_format="ggmlv3", + gguf_spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=2, quantizations=["q4_0", "q4_1"], quantization_parts={"q4_2": ["a", "b"]}, model_id="example/TestModel", model_revision="123", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", - model_file_name_split_template="TestModel.{quantization}.ggmlv3.bin.{part}", + model_file_name_template="TestModel.{quantization}.bin", + model_file_name_split_template="TestModel.{quantization}.bin.{part}", ) pytorch_spec = PytorchLLMSpecV1( model_format="pytorch", @@ -155,11 +155,11 @@ def test_serialize_llm_family_v1(): model_name="TestModel", model_lang=["en"], model_ability=["embed", "generate"], - model_specs=[ggml_spec, pytorch_spec], + model_specs=[gguf_spec, pytorch_spec], prompt_style=prompt_style, ) - expected = """{"version": 1, "context_length": 2048, "model_name": "TestModel", "model_lang": ["en"], "model_ability": ["embed", "generate"], "model_description": null, "model_family": null, "model_specs": [{"model_format": "ggmlv3", "model_hub": "huggingface", "model_size_in_billions": 2, "quantizations": ["q4_0", "q4_1"], "quantization_parts": {"q4_2": ["a", "b"]}, "model_id": "example/TestModel", "model_revision": "123", "model_file_name_template": "TestModel.{quantization}.ggmlv3.bin", "model_file_name_split_template": "TestModel.{quantization}.ggmlv3.bin.{part}", "model_uri": null}, {"model_format": "pytorch", "model_hub": "huggingface", "model_size_in_billions": 3, "quantizations": ["int8", "int4", "none"], "model_id": "example/TestModel", "model_revision": "456", "model_uri": null}], "prompt_style": {"style_name": "ADD_COLON_SINGLE", "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.", "roles": ["user", "assistant"], "intra_message_sep": "\\n### ", "inter_message_sep": "\\n### ", "stop": null, "stop_token_ids": null}}""" + expected = """{"version": 1, "context_length": 2048, "model_name": "TestModel", "model_lang": ["en"], "model_ability": ["embed", "generate"], "model_description": null, "model_family": null, "model_specs": [{"model_format": "ggufv2", "model_hub": "huggingface", "model_size_in_billions": 2, "quantizations": ["q4_0", "q4_1"], "quantization_parts": {"q4_2": ["a", "b"]}, "model_id": "example/TestModel", "model_revision": "123", "model_file_name_template": "TestModel.{quantization}.bin", "model_file_name_split_template": "TestModel.{quantization}.bin.{part}", "model_uri": null}, {"model_format": "pytorch", "model_hub": "huggingface", "model_size_in_billions": 3, "quantizations": ["int8", "int4", "none"], "model_id": "example/TestModel", "model_revision": "456", "model_uri": null}], "prompt_style": {"style_name": "ADD_COLON_SINGLE", "system_prompt": "A chat between a curious human and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the human's questions.", "roles": ["user", "assistant"], "intra_message_sep": "\\n### ", "inter_message_sep": "\\n### ", "stop": null, "stop_token_ids": null}}""" assert json.loads(llm_family.json()) == json.loads(expected) llm_family_context_length = LLMFamilyV1( @@ -169,7 +169,7 @@ def test_serialize_llm_family_v1(): model_name="TestModel", model_lang=["en"], model_ability=["embed", "generate"], - model_specs=[ggml_spec, pytorch_spec], + model_specs=[gguf_spec, pytorch_spec], prompt_style=prompt_style, ) @@ -212,13 +212,13 @@ def test_cache_from_huggingface_pytorch(): shutil.rmtree(cache_dir) -def test_cache_from_huggingface_ggml(): +def test_cache_from_huggingface_gguf(): from ..llm_family import cache_from_huggingface - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", quantizations=["q4_0"], model_file_name_template="README.md", ) @@ -226,9 +226,9 @@ def test_cache_from_huggingface_ggml(): version=1, context_length=2048, model_type="LLM", - model_name="orca", + model_name="qwen1.5-chat", model_lang=["en"], - model_ability=["embed", "chat"], + model_ability=["chat"], model_specs=[spec], prompt_style=None, ) @@ -250,8 +250,8 @@ def test_cache_from_uri_local(): with open("model.bin", "w") as fd: fd.write("foo") - spec = GgmlLLMSpecV1( - model_format="ggmlv3", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=3, model_id="TestModel", model_uri=os.path.abspath(os.getcwd()), @@ -322,119 +322,13 @@ def test_parse_uri(): assert path == "bucket/dir" -def test_cache_from_uri_remote(): - from ..llm_family import cache_from_uri - - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TestModel", - model_uri="s3://test_bucket", - quantizations=[""], - model_file_name_template="model.bin", - ) - family = LLMFamilyV1( - version=1, - context_length=2048, - model_type="LLM", - model_name="test_cache_from_uri_remote", - model_lang=["en"], - model_ability=["embed", "chat"], - model_specs=[spec], - prompt_style=None, - ) - - from unittest.mock import patch - - import fsspec - - fsspec.real_filesystem = fsspec.filesystem - - def fsspec_filesystem_side_effect(scheme: str, *args, **kwargs): - if scheme == "s3": - mock_fs = Mock() - mock_fs.info.return_value = {"size": 3} - mock_fs.walk.return_value = [("test_bucket", None, ["model.bin"])] - mock_file = MagicMock() - mock_file_descriptor = Mock() - mock_file_descriptor.read.side_effect = ["foo".encode(), None] - mock_file.__enter__.return_value = mock_file_descriptor - mock_fs.open.return_value = mock_file - return mock_fs - else: - return fsspec.real_filesystem(scheme) - - with patch("fsspec.filesystem", side_effect=fsspec_filesystem_side_effect): - cache_dir = cache_from_uri(family, spec) - assert os.path.exists(cache_dir) - assert os.path.exists(os.path.join(cache_dir, "model.bin")) - shutil.rmtree(cache_dir, ignore_errors=True) - - -def test_cache_from_uri_remote_exception_handling(): - from ....constants import XINFERENCE_CACHE_DIR - from ..llm_family import cache_from_uri - - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TestModel", - model_uri="s3://test_bucket", - quantizations=[""], - model_file_name_template="model.bin", - ) - family = LLMFamilyV1( - version=1, - context_length=2048, - model_type="LLM", - model_name="test_cache_from_uri_remote_exception_handling", - model_lang=["en"], - model_ability=["embed", "chat"], - model_specs=[spec], - prompt_style=None, - ) - - from unittest.mock import patch - - import fsspec - - fsspec.real_filesystem = fsspec.filesystem - - def fsspec_filesystem_side_effect(scheme: str, *args, **kwargs): - if scheme == "s3": - mock_fs = Mock() - mock_fs.info.return_value = {"size": 3} - mock_fs.walk.return_value = [("test_bucket", None, ["model.bin"])] - mock_file = MagicMock() - mock_file_descriptor = Mock() - mock_file_descriptor.read.side_effect = Exception("Mock exception") - mock_file.__enter__.return_value = mock_file_descriptor - mock_fs.open.return_value = mock_file - return mock_fs - else: - return fsspec.real_filesystem(scheme) - - with pytest.raises( - RuntimeError, - match="Failed to download model 'test_cache_from_uri_remote_exception_handling'", - ): - with patch("fsspec.filesystem", side_effect=fsspec_filesystem_side_effect): - cache_from_uri(family, spec) - - cache_dir_name = ( - f"{family.model_name}-{spec.model_format}" f"-{spec.model_size_in_billions}b" - ) - cache_dir = os.path.realpath(os.path.join(XINFERENCE_CACHE_DIR, cache_dir_name)) - assert not os.path.exists(cache_dir) - - def test_legacy_cache(): from ..llm_family import cache, get_legacy_cache_path - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", quantizations=["test_legacy_cache"], model_file_name_template="README.md", ) @@ -442,9 +336,9 @@ def test_legacy_cache(): version=1, context_length=2048, model_type="LLM", - model_name="orca", + model_name="qwen1.5-chat", model_lang=["en"], - model_ability=["embed", "chat"], + model_ability=["chat"], model_specs=[spec], prompt_style=None, ) @@ -466,41 +360,13 @@ def test_legacy_cache(): shutil.rmtree(os.path.dirname(cache_path), ignore_errors=True) -@pytest.mark.skip(reason="Temporary disabled") -def test_cache_from_self_hosted_storage(): - from ..llm_family import cache_from_self_hosted_storage - - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", - quantizations=[""], - model_file_name_template="README.md", - ) - family = LLMFamilyV1( - version=1, - context_length=2048, - model_type="LLM", - model_name="orca", - model_lang=["en"], - model_ability=["embed", "chat"], - model_specs=[spec], - prompt_style=None, - ) - - cache_dir = cache_from_self_hosted_storage(family, spec, quantization="") - assert os.path.exists(cache_dir) - assert os.path.exists(os.path.join(cache_dir, "README.md")) - shutil.rmtree(cache_dir, ignore_errors=True) - - def test_custom_llm(): from ..llm_family import get_user_defined_llm_families, register_llm, unregister_llm - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", quantizations=[""], model_file_name_template="README.md", ) @@ -508,9 +374,9 @@ def test_custom_llm(): version=1, context_length=2048, model_type="LLM", - model_name="custom_model", + model_name="custom-qwen1.5-chat", model_lang=["en"], - model_ability=["embed", "chat"], + model_ability=["chat"], model_specs=[spec], prompt_style=None, ) @@ -527,10 +393,10 @@ def test_persistent_custom_llm(): from ....constants import XINFERENCE_MODEL_DIR from ..llm_family import get_user_defined_llm_families, register_llm, unregister_llm - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", quantizations=[""], model_file_name_template="README.md", ) @@ -540,7 +406,7 @@ def test_persistent_custom_llm(): model_type="LLM", model_name="custom_model", model_lang=["en"], - model_ability=["embed", "chat"], + model_ability=["chat"], model_specs=[spec], prompt_style=None, ) @@ -573,93 +439,17 @@ def en_us(): assert not is_locale_chinese_simplified() -def test_download_from_self_hosted_storage(): - from ....constants import XINFERENCE_ENV_MODEL_SRC - from ..llm_family import download_from_self_hosted_storage - - assert not download_from_self_hosted_storage() - - os.environ[XINFERENCE_ENV_MODEL_SRC] = "xorbits" - assert download_from_self_hosted_storage() - del os.environ[XINFERENCE_ENV_MODEL_SRC] - - -def test_aws_region_set(): - with AWSRegion("foo"): - assert os.environ["AWS_DEFAULT_REGION"] == "foo" - - # Ensure the region is deleted if it wasn't set before - assert "AWS_DEFAULT_REGION" not in os.environ - - -def test_aws_region_restore(): - # Set an initial region - os.environ["AWS_DEFAULT_REGION"] = "us-west-1" - - with AWSRegion("foo"): - assert os.environ["AWS_DEFAULT_REGION"] == "foo" - - # Ensure the region is restored to its original value after exiting the context - assert os.environ["AWS_DEFAULT_REGION"] == "us-west-1" - - -def test_aws_region_no_restore_if_not_set(): - # Ensure AWS_DEFAULT_REGION is not set - if "AWS_DEFAULT_REGION" in os.environ: - del os.environ["AWS_DEFAULT_REGION"] - - with AWSRegion("foo"): - assert os.environ["AWS_DEFAULT_REGION"] == "foo" - - # Ensure the region is deleted if it wasn't set before - assert "AWS_DEFAULT_REGION" not in os.environ - - -def test_aws_region_exception_handling(): - with pytest.raises(ValueError): - with AWSRegion("foo"): - raise ValueError("Test exception") - - # Ensure the region is deleted if it wasn't set before - assert "AWS_DEFAULT_REGION" not in os.environ - - -@pytest.mark.skip(reason="Temporary disabled") -def test_is_self_hosted(): - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", - quantizations=[""], - model_file_name_template="README.md", - ) - family = LLMFamilyV1( - version=1, - context_length=2048, - model_type="LLM", - model_name="orca", - model_lang=["en"], - model_ability=["embed", "chat"], - model_specs=[spec], - prompt_style=None, - ) - assert is_self_hosted(family, spec) - - family.model_name = "foo" - assert not is_self_hosted(family, spec) - - def test_match_llm(): assert match_llm("fake") is None - family, spec, q = match_llm("orca", model_format="ggmlv3") - assert family.model_name == "orca" - assert q == "q4_0" + family, spec, q = match_llm("qwen1.5-chat", model_format="ggufv2") + assert family.model_name == "qwen1.5-chat" + assert q == "q2_k" family, spec, q = match_llm( - "llama-2-chat", model_format="ggmlv3", quantization="Q4_0" + "llama-2-chat", model_format="ggufv2", quantization="Q4_0" ) assert family.model_name == "llama-2-chat" - assert q == "q4_0" + assert q == "Q4_0" family, spec, q = match_llm( "code-llama", model_format="ggufv2", quantization="q4_0" @@ -785,24 +575,24 @@ def test_skip_download_pytorch(): assert not os.path.exists(ms_meta_path) -def test_skip_download_ggml(): - hf_spec = GgmlLLMSpecV1( - model_format="ggmlv3", +def test_skip_download_gguf(): + hf_spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=2, quantizations=["q4_0", "q4_1"], model_id="example/TestModel", model_hub="huggingface", model_revision="123", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", + model_file_name_template="TestModel.{quantization}.bin", ) - ms_spec = GgmlLLMSpecV1( - model_format="ggmlv3", + ms_spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=2, quantizations=["q4_0", "q4_1"], model_id="example/TestModel", model_hub="modelscope", model_revision="123", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", + model_file_name_template="TestModel.{quantization}.bin", ) prompt_style = PromptStyleV1( style_name="ADD_COLON_SINGLE", @@ -914,13 +704,13 @@ def test_get_cache_status_pytorch(): shutil.rmtree(cache_dir) -def test_get_cache_status_ggml(): +def test_get_cache_status_gguf(): from ..llm_family import cache_from_huggingface, get_cache_status - spec = GgmlLLMSpecV1( - model_format="ggmlv3", - model_size_in_billions=3, - model_id="TheBloke/orca_mini_3B-GGML", + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", quantizations=["q4_0", "q5_0"], model_file_name_template="README.md", ) @@ -928,9 +718,9 @@ def test_get_cache_status_ggml(): version=1, context_length=2048, model_type="LLM", - model_name="orca", + model_name="qwen1.5-chat", model_lang=["en"], - model_ability=["embed", "chat"], + model_ability=["chat"], model_specs=[spec], prompt_style=None, ) @@ -958,25 +748,25 @@ def test_parse_prompt_style(): # take some examples to assert assert "qwen-chat" in BUILTIN_LLM_PROMPT_STYLE assert "chatglm3" in BUILTIN_LLM_PROMPT_STYLE - assert "baichuan-chat" in BUILTIN_LLM_PROMPT_STYLE + assert "baichuan-2-chat" in BUILTIN_LLM_PROMPT_STYLE - hf_spec = GgmlLLMSpecV1( - model_format="ggmlv3", + hf_spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=2, quantizations=["q4_0", "q4_1"], model_id="example/TestModel", model_hub="huggingface", model_revision="123", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", + model_file_name_template="TestModel.{quantization}.bin", ) - ms_spec = GgmlLLMSpecV1( - model_format="ggmlv3", + ms_spec = LlamaCppLLMSpecV1( + model_format="ggufv2", model_size_in_billions=2, quantizations=["q4_0", "q4_1"], model_id="example/TestModel", model_hub="modelscope", model_revision="123", - model_file_name_template="TestModel.{quantization}.ggmlv3.bin", + model_file_name_template="TestModel.{quantization}.bin", ) llm_family = CustomLLMFamilyV1( @@ -992,6 +782,20 @@ def test_parse_prompt_style(): model_spec = CustomLLMFamilyV1.parse_raw(bytes(llm_family.json(), "utf8")) assert model_spec.model_name == llm_family.model_name + # test vision + llm_family = CustomLLMFamilyV1( + version=1, + model_type="LLM", + model_name="test_LLM", + model_lang=["en"], + model_ability=["chat", "generate"], + model_specs=[hf_spec, ms_spec], + model_family="qwen-vl-chat", + prompt_style="qwen-vl-chat", + ) + model_spec = CustomLLMFamilyV1.parse_raw(bytes(llm_family.json(), "utf-8")) + assert "vision" in model_spec.model_ability + # error: missing model_family llm_family = CustomLLMFamilyV1( version=1, @@ -1032,3 +836,295 @@ def test_parse_prompt_style(): ) with pytest.raises(ValueError): CustomLLMFamilyV1.parse_raw(bytes(llm_family.json(), "utf8")) + + +def test_match_model_size(): + assert match_model_size("1", "1") + assert match_model_size("1", 1) + assert match_model_size(1, 1) + assert not match_model_size("1", "b") + assert not match_model_size("1", "1b") + assert match_model_size("1.8", "1_8") + assert match_model_size("1_8", "1.8") + assert not match_model_size("1", "1_8") + assert not match_model_size("1__8", "1_8") + assert not match_model_size("1_8", 18) + assert not match_model_size("1_8", "18") + assert not match_model_size("1.8", 18) + assert not match_model_size("1.8", 1) + assert match_model_size("001", 1) + + +def test_convert_model_size_to_float(): + assert convert_model_size_to_float("1_8") == 1.8 + assert convert_model_size_to_float("1.8") == 1.8 + assert convert_model_size_to_float(7) == float(7) + assert convert_model_size_to_float(1.8) == 1.8 + + +@pytest.mark.skipif( + True, + reason="Current system does not support vLLM", +) +def test_quert_engine_vLLM(): + from ..llm_family import LLM_ENGINES, check_engine_by_spec_parameters + + model_name = "qwen1.5-chat" + assert model_name in LLM_ENGINES + + assert ( + "vLLM" in LLM_ENGINES[model_name] and len(LLM_ENGINES[model_name]["vLLM"]) == 21 + ) + + assert check_engine_by_spec_parameters( + model_engine="vLLM", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int4", + ) + assert ( + check_engine_by_spec_parameters( + model_engine="vLLM", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int8", + ) + is None + ) + assert check_engine_by_spec_parameters( + model_engine="vLLM", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="none", + ) + assert ( + check_engine_by_spec_parameters( + model_engine="vLLM", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="4-bit", + ) + is None + ) + assert ( + check_engine_by_spec_parameters( + model_engine="vLLM", + model_name=model_name, + model_format="ggufv2", + model_size_in_billions="1_8", + quantization="q2_k", + ) + is None + ) + + +@pytest.mark.skipif( + True, + reason="Current system does not support SGLang", +) +def test_quert_engine_SGLang(): + from ..llm_family import LLM_ENGINES, check_engine_by_spec_parameters + + model_name = "qwen1.5-chat" + assert model_name in LLM_ENGINES + + assert ( + "SGLang" in LLM_ENGINES[model_name] + and len(LLM_ENGINES[model_name]["SGLang"]) == 21 + ) + + assert check_engine_by_spec_parameters( + model_engine="SGLang", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int4", + ) + assert ( + check_engine_by_spec_parameters( + model_engine="SGLang", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int8", + ) + is None + ) + assert check_engine_by_spec_parameters( + model_engine="SGLang", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="none", + ) + assert ( + check_engine_by_spec_parameters( + model_engine="SGLang", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="4-bit", + ) + is None + ) + assert ( + check_engine_by_spec_parameters( + model_engine="SGLang", + model_name=model_name, + model_format="ggufv2", + model_size_in_billions="1_8", + quantization="q2_k", + ) + is None + ) + + +def test_query_engine_general(): + from ..llama_cpp.core import LlamaCppChatModel + from ..llm_family import ( + LLM_ENGINES, + check_engine_by_spec_parameters, + get_user_defined_llm_families, + register_llm, + unregister_llm, + ) + + assert check_engine_by_spec_parameters( + model_engine="transformers", + model_name="aquila2", + model_format="pytorch", + model_size_in_billions=7, + quantization="none", + ) + + model_name = "qwen1.5-chat" + assert model_name in LLM_ENGINES + + assert "Transformers" in LLM_ENGINES[model_name] + assert "llama.cpp" in LLM_ENGINES[model_name] + + assert check_engine_by_spec_parameters( + model_engine="transformers", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int4", + ) + assert check_engine_by_spec_parameters( + model_engine="transformers", + model_name=model_name, + model_format="gptq", + model_size_in_billions="1_8", + quantization="Int8", + ) + assert check_engine_by_spec_parameters( + model_engine="transformers", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="none", + ) + assert check_engine_by_spec_parameters( + model_engine="transformers", + model_name=model_name, + model_format="pytorch", + model_size_in_billions="1_8", + quantization="4-bit", + ) + assert ( + check_engine_by_spec_parameters( + model_engine="llama.cpp", + model_name=model_name, + model_format="ggufv2", + model_size_in_billions="1_8", + quantization="q2_k", + ) + is LlamaCppChatModel + ) + with pytest.raises(ValueError) as exif: + check_engine_by_spec_parameters( + model_engine="llama.cpp", + model_name=model_name, + model_format="ggufv2", + model_size_in_billions="2_2", + quantization="q2_k", + ) + assert ( + str(exif.value) + == "Model qwen1.5-chat cannot be run on engine llama.cpp, with format ggufv2, size 2_2 and quantization q2_k." + ) + + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="0_5", + model_id="Qwen/Qwen1.5-0.5B-Chat-GGUF", + quantizations=[""], + model_file_name_template="README.md", + ) + family = LLMFamilyV1( + version=1, + context_length=2048, + model_type="LLM", + model_name="custom_model", + model_lang=["en"], + model_ability=["chat"], + model_specs=[spec], + prompt_style=None, + ) + + register_llm(family, False) + + assert family in get_user_defined_llm_families() + assert "custom_model" in LLM_ENGINES and "llama.cpp" in LLM_ENGINES["custom_model"] + assert check_engine_by_spec_parameters( + model_engine="llama.cpp", + model_name="custom_model", + model_format="ggufv2", + model_size_in_billions="0_5", + quantization="", + ) + + unregister_llm(family.model_name) + assert family not in get_user_defined_llm_families() + assert "custom_model" not in LLM_ENGINES + + spec = LlamaCppLLMSpecV1( + model_format="ggufv2", + model_size_in_billions="1_8", + model_id="null", + quantizations=["default"], + model_file_name_template="qwen1_5-1_8b-chat-q4_0.gguf", + ) + family = LLMFamilyV1( + version=1, + context_length=2048, + model_type="LLM", + model_name="custom-qwen1.5-chat", + model_lang=["en", "zh"], + model_ability=["generate", "chat"], + model_specs=[spec], + prompt_style={ + "style_name": "QWEN", + "system_prompt": "You are a helpful assistant.", + "roles": ["user", "assistant"], + "intra_message_sep": "\n", + "inter_message_sep": "", + "stop": ["<|endoftext|>", "<|im_start|>", "<|im_end|>"], + "stop_token_ids": [151643, 151644, 151645], + }, + ) + + register_llm(family, False) + + assert family in get_user_defined_llm_families() + assert "custom-qwen1.5-chat" in LLM_ENGINES and ["llama.cpp"] == list( + LLM_ENGINES["custom-qwen1.5-chat"].keys() + ) + + unregister_llm(family.model_name) + assert family not in get_user_defined_llm_families() + assert "custom-qwen1.5-chat" not in LLM_ENGINES diff --git a/xinference/model/llm/tests/test_memory_estimate.py b/xinference/model/llm/tests/test_memory_estimate.py new file mode 100644 index 0000000000..6981b237db --- /dev/null +++ b/xinference/model/llm/tests/test_memory_estimate.py @@ -0,0 +1,55 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ..memory import estimate_llm_gpu_memory + + +def test_llm_estimate_memory(): + # TODO GGML is not tested yet + + # without model_name, use default ModelLayersInfo + mem_info = estimate_llm_gpu_memory(1.8, None, 2048, "pytorch", kv_cache_dtype=32) + assert mem_info.total == 5162 + mem_info = estimate_llm_gpu_memory( + 72, "8-bit", 1024 + 2048, "pytorch", kv_cache_dtype=32 + ) + assert mem_info.total == 92943 + mem_info = estimate_llm_gpu_memory( + 72, "4-bit", 1024 + 2048, "pytorch", kv_cache_dtype=32 + ) + assert mem_info.total == 58611 + mem_info = estimate_llm_gpu_memory(7, "Int4", 32768, "gptq", kv_cache_dtype=32) + assert mem_info.total == 100550 + + # with model_name to match_llm + mem_info = estimate_llm_gpu_memory( + 72, "Int4", 32768, "gptq", kv_cache_dtype=16, model_name="qwen1.5-chat" + ) + assert mem_info.total == 258775 + + # model_size_in_billions use int + mem_info = estimate_llm_gpu_memory( + 32, "Int4", 32768, "gptq", kv_cache_dtype=8, model_name="qwen1.5-chat" + ) + # model_size_in_billions use str + mem_info = estimate_llm_gpu_memory( + "32", "Int4", 32768, "gptq", kv_cache_dtype=8, model_name="qwen1.5-chat" + ) + assert mem_info.total == 58035 + + # model_size_in_billions use float + mem_info = estimate_llm_gpu_memory( + "1.8", None, 2048, "pytorch", kv_cache_dtype=32, model_name="qwen1.5-chat" + ) + assert mem_info.total == 5020 diff --git a/xinference/model/llm/tests/test_stream_options.py b/xinference/model/llm/tests/test_stream_options.py new file mode 100644 index 0000000000..917890e09d --- /dev/null +++ b/xinference/model/llm/tests/test_stream_options.py @@ -0,0 +1,1078 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import os.path + +import openai +import pytest +import requests +from packaging import version + +from ....constants import XINFERENCE_ENV_MODEL_SRC + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_llamacpp_chatglm(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", + "model_format": "ggufv2", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_llamacpp(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + # os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "llama.cpp", + "model_name": "qwen1.5-chat", + "model_size_in_billions": "0_5", + "model_format": "ggufv2", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "What is the capital of France?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch_chatglm(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "chatglm3", + "model_size_in_billions": "6", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "baichuan-2-chat", + "model_size_in_billions": "7", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch_deepseek_vl(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "deepseek-vl-chat", + "model_size_in_billions": "1_3", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch_internlm2(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "internlm2-chat", + "model_size_in_billions": "7", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch_qwen_vl(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "qwen-vl-chat", + "model_size_in_billions": "7", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_pytorch_yi_vl(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "Transformers", + "model_name": "yi-vl-chat", + "model_size_in_billions": "6", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_sgalng(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "SGLang", + "model_name": "qwen-chat", + "model_size_in_billions": "7", + "quantization": "Int4", + "model_format": "gptq", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_options_vllm(setup): + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "vLLM", + "model_name": "qwen-chat", + "model_size_in_billions": "7", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + # chat + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello!"}, + {"role": "assistant", "content": "Hi what can I help you?"}, + {"role": "user", "content": "法国的首都是哪里?"}, + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + result1 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": False, + }, + ): + result1.append(chunk) + assert result1 + assert type(result1[0]).__name__ == stream_chunk_type_name + # stop + assert result1[-1].choices[0].finish_reason == "stop" + + result2 = await openai_chat_completion( + messages=messages, stream=False, model=model_uid_res + ) + + assert result2 + assert type(result2).__name__ == response_type_name + # stop + assert result2.choices[0].finish_reason == "stop" + + result3 = [] + async for chunk in await openai_chat_completion( + messages=messages, + stream=True, + model=model_uid_res, + max_tokens=None, + stream_options={ + "include_usage": True, + }, + ): + result3.append(chunk) + assert result3 + assert type(result3[0]).__name__ == stream_chunk_type_name + # usage + assert not result3[-1].choices + assert result3[-1].usage + + +@pytest.mark.asyncio +@pytest.mark.skip(reason="Too large model to be tested") +async def test_openai_stream_tools_vllm(setup): + import json + + endpoint, _ = setup + url = f"{endpoint}/v1/models" + os.environ.get(XINFERENCE_ENV_MODEL_SRC, "modelscope") + + # list + response = requests.get(url) + response_data = response.json() + assert len(response_data["data"]) == 0 + + # launch + payload = { + "model_uid": "test_restful_api", + "model_engine": "vLLM", + "model_name": "qwen-chat", + "model_size_in_billions": "7", + "quantization": "none", + "model_format": "pytorch", + } + + response = requests.post(url, json=payload) + response_data = response.json() + model_uid_res = response_data["model_uid"] + assert model_uid_res == "test_restful_api" + + def get_current_weather(location: str, unit="fahrenheit"): + """Get the current weather in a given location""" + if "tokyo" in location.lower(): + return json.dumps({"location": "Tokyo", "temperature": "10", "unit": unit}) + else: + return json.dumps({"location": location, "temperature": "unknown"}) + + def handle_tools_response(messages, tool_calls): + for tool_call in tool_calls: + function_name = tool_call.function.name + function_to_call = get_current_weather + function_args = json.loads(tool_call.function.arguments) + function_response = function_to_call( + location=function_args.get("location"), + unit=function_args.get("unit"), + ) + messages.append( + { + "tool_call_id": tool_call.id, + "role": "tool", + "name": function_name, + "content": function_response, + } + ) + + # create conversation with tool call + messages = [ + { + "role": "user", + "content": "What's the weather like in tokyo? Use tools to answer.", + } + ] + tools = [ + { + "type": "function", + "function": { + "name": "get_current_weather", + "description": "Get the current weather in a given location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA", + }, + "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, + }, + "required": ["location"], + }, + }, + } + ] + + if version.parse(openai.__version__) < version.parse("1.0"): + openai.api_key = "" + openai.api_base = f"{endpoint}/v1" + openai_chat_completion = openai.ChatCompletion.acreate + stream_chunk_type_name = "OpenAIObject" + response_type_name = "OpenAIObject" + else: + client = openai.AsyncClient(api_key="not empty", base_url=f"{endpoint}/v1") + openai_chat_completion = client.chat.completions.create + stream_chunk_type_name = "ChatCompletionChunk" + response_type_name = "ChatCompletion" + + # Step 1: Get the initial response with stream=True + result_stream_initial = [] + for chunk in openai_chat_completion( + messages=messages, + model=model_uid_res, + stream=True, + tools=tools, + ): + result_stream_initial.append(chunk) + + assert result_stream_initial + assert type(result_stream_initial[0]).__name__ == stream_chunk_type_name + + # Simulate the tool calls for the initial stream response + tool_calls = result_stream_initial[-1].choices[0].delta.tool_calls + assert tool_calls + handle_tools_response(messages, tool_calls) + + # Step 2: Get the final response after tool calls with stream=True + result_stream_final = [] + for chunk in openai_chat_completion( + messages=messages, + model=model_uid_res, + stream=True, + ): + result_stream_final.append(chunk) + + assert result_stream_final + assert type(result_stream_final[0]).__name__ == stream_chunk_type_name + + # Combine streamed chunks into a single response + final_response_stream = "".join( + chunk.choices[0].delta.content for chunk in result_stream_final + ) + assert "tokyo" in final_response_stream.lower() + + # Step 3: Get the initial response with stream=False + messages = messages[:1] # reset to initial messages + initial_response = openai_chat_completion( + messages=messages, # reset to initial messages + model=model_uid_res, + tools=tools, + stream=False, + ) + + assert initial_response + assert type(initial_response).__name__ == response_type_name + + # Simulate the tool calls for the initial non-stream response + tool_calls = initial_response.choices[0].message.tool_calls + assert tool_calls is not None + handle_tools_response(messages, tool_calls) + + # Step 4: Get the final response after tool calls with stream=False + final_response = openai_chat_completion( + messages=messages, model=model_uid_res, stream=False + ) + + assert final_response + assert type(final_response).__name__ == response_type_name + + # Check the final response contains the weather info + assert "tokyo" in final_response.choices[0].message.content.lower() diff --git a/xinference/model/llm/tests/test_utils.py b/xinference/model/llm/tests/test_utils.py index d5e40d7561..42125a0048 100644 --- a/xinference/model/llm/tests/test_utils.py +++ b/xinference/model/llm/tests/test_utils.py @@ -46,36 +46,6 @@ def test_prompt_style_add_colon_single(): ) -def test_prompt_style_add_colon_two(): - prompt_style = PromptStyleV1( - style_name="ADD_COLON_TWO", - system_prompt=( - "A chat between a curious user and an artificial intelligence assistant. The " - "assistant gives helpful, detailed, and polite answers to the user's questions." - ), - roles=["USER", "ASSISTANT"], - intra_message_sep=" ", - inter_message_sep="", - ) - chat_history = [ - ChatCompletionMessage(role=prompt_style.roles[0], content="Hi there."), - ChatCompletionMessage( - role=prompt_style.roles[1], content="Hello, how may I help you?" - ), - ] - expected = ( - "A chat between a curious user and an artificial intelligence assistant. The " - "assistant gives helpful, detailed, and polite answers to the user's questions. " - "USER: Hi there. " - "ASSISTANT: Hello, how may I help you?" - "USER: Write a poem. " - "ASSISTANT:" - ) - assert expected == ChatModelMixin.get_prompt( - "Write a poem.", chat_history, prompt_style - ) - - def test_prompt_style_no_colon_two(): prompt_style = PromptStyleV1( style_name="NO_COLON_TWO", @@ -140,64 +110,22 @@ def test_prompt_style_llama2(): ) -def test_prompt_style_falcon(): - prompt_style = PromptStyleV1( - style_name="FALCON", - system_prompt="", - roles=["User", "Assistant"], - intra_message_sep="\n", - inter_message_sep="<|endoftext|>", - stop=["\nUser"], - stop_token_ids=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], - ) - chat_history = [ - ChatCompletionMessage(role=prompt_style.roles[0], content="Hi there."), - ChatCompletionMessage( - role=prompt_style.roles[1], content="Hello, how may I help you?" - ), - ] - expected = ( - "User: Hi there.\n\n" - "Assistant: Hello, how may I help you?\n\n" - "User: Write a poem.\n\n" - "Assistant:" - ) - - assert expected == ChatModelMixin.get_prompt( - "Write a poem.", chat_history, prompt_style - ) - - -def test_prompt_style_chatglm_v1(): +def test_prompt_style_llama3(): prompt_style = PromptStyleV1( - style_name="CHATGLM", - system_prompt="", - roles=["问", "答"], - intra_message_sep="\n", - ) - chat_history = [ - ChatCompletionMessage(role=prompt_style.roles[0], content="Hi there."), - ChatCompletionMessage( - role=prompt_style.roles[1], content="Hello, how may I help you?" + style_name="LLAMA3", + system_prompt=( + "You are a helpful, respectful and honest assistant. Always answer" + " as helpfully as possible, while being safe. Your answers should not include any" + " harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please" + " ensure that your responses are socially unbiased and positive in nature.\n\nIf a" + " question does not make any sense, or is not factually coherent, explain why instead" + " of answering something not correct. If you don't know the answer to a question," + " please don't share false information" ), - ] - expected = ( - "[Round 0]\n问:Hi there.\n" - "答:Hello, how may I help you?\n" - "[Round 1]\n问:Write a poem.\n" - "答:" - ) - assert expected == ChatModelMixin.get_prompt( - "Write a poem.", chat_history, prompt_style - ) - - -def test_prompt_style_chatglm_v2(): - prompt_style = PromptStyleV1( - style_name="CHATGLM", - system_prompt="", - roles=["问", "答"], + roles=["user", "assistant"], intra_message_sep="\n\n", + inter_message_sep="<|eot_id|>", + stop_token_ids=[128001, 128009], ) chat_history = [ ChatCompletionMessage(role=prompt_style.roles[0], content="Hi there."), @@ -206,10 +134,18 @@ def test_prompt_style_chatglm_v2(): ), ] expected = ( - "[Round 1]\n\n问:Hi there.\n\n" - "答:Hello, how may I help you?\n\n" - "[Round 2]\n\n问:Write a poem.\n\n" - "答:" + "<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n" + "You are a helpful, respectful and honest assistant. Always answer" + " as helpfully as possible, while being safe. Your answers should not include any" + " harmful, unethical, racist, sexist, toxic, dangerous, or illegal content. Please" + " ensure that your responses are socially unbiased and positive in nature.\n\nIf a" + " question does not make any sense, or is not factually coherent, explain why instead" + " of answering something not correct. If you don't know the answer to a question," + " please don't share false information<|eot_id|>" + "<|start_header_id|>user<|end_header_id|>\n\nHi there.<|eot_id|>" + "<|start_header_id|>assistant<|end_header_id|>\n\nHello, how may I help you?<|eot_id|>" + "<|start_header_id|>user<|end_header_id|>\n\nWrite a poem.<|eot_id|>" + "<|start_header_id|>assistant<|end_header_id|>\n\n" ) assert expected == ChatModelMixin.get_prompt( "Write a poem.", chat_history, prompt_style @@ -316,33 +252,6 @@ def test_prompt_style_chatml(): ) -def test_prompt_style_internlm(): - prompt_style = PromptStyleV1( - style_name="INTERNLM", - system_prompt="", - roles=["<|User|>", "<|Bot|>"], - intra_message_sep="\n", - inter_message_sep="\n", - ) - - expected = "<|User|>:Write a poem.\n<|Bot|>:" - actual = ChatModelMixin.get_prompt("Write a poem.", [], prompt_style) - assert expected == actual - - chat_history = [ - ChatCompletionMessage(role=prompt_style.roles[0], content="Hi there."), - ChatCompletionMessage( - role=prompt_style.roles[1], content="Hello, how may I help you?" - ), - ] - expected = ( - "<|User|>:Hi there.\n<|Bot|>:Hello, how may I help you?\n" - "<|User|>:Write a poem.\n<|Bot|>:" - ) - actual = ChatModelMixin.get_prompt("Write a poem.", chat_history, prompt_style) - assert expected == actual - - def test_prompt_style_add_colon_single_cot(): prompt_style = PromptStyleV1( style_name="ADD_COLON_SINGLE_COT", diff --git a/xinference/model/llm/pytorch/tests/__init__.py b/xinference/model/llm/transformers/__init__.py similarity index 100% rename from xinference/model/llm/pytorch/tests/__init__.py rename to xinference/model/llm/transformers/__init__.py diff --git a/xinference/model/llm/transformers/chatglm.py b/xinference/model/llm/transformers/chatglm.py new file mode 100644 index 0000000000..797402b220 --- /dev/null +++ b/xinference/model/llm/transformers/chatglm.py @@ -0,0 +1,585 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import copy +import json +import threading +import time +import uuid +from typing import Any, Dict, Iterator, List, Optional, Union + +import torch +from transformers.generation.logits_process import LogitsProcessor +from transformers.generation.utils import LogitsProcessorList + +from ....core.scheduler import InferenceRequest +from ....types import ( + SPECIAL_TOOL_PROMPT, + ChatCompletion, + ChatCompletionChoice, + ChatCompletionChunk, + ChatCompletionMessage, + CompletionChoice, + CompletionChunk, + CompletionUsage, + LoRA, + PytorchGenerateConfig, +) +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import GLM4_TOOL_CALL_FAMILY +from .core import PytorchChatModel, PytorchModelConfig + + +class InvalidScoreLogitsProcessor(LogitsProcessor): + def __call__( + self, input_ids: torch.LongTensor, scores: torch.FloatTensor + ) -> torch.FloatTensor: + if torch.isnan(scores).any() or torch.isinf(scores).any(): + scores.zero_() + scores[..., 198] = 5e4 + return scores + + +class ChatglmPytorchChatModel(PytorchChatModel): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + pytorch_model_config: Optional[PytorchModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__( + model_uid, + model_family, + model_spec, + quantization, + model_path, + pytorch_model_config=pytorch_model_config, + peft_model=peft_model, + ) + + def _get_model_class(self): + from transformers import AutoModel + + return AutoModel + + def _load_model(self, **kwargs): + try: + from transformers import AutoModel, AutoTokenizer + except ImportError: + error_message = "Failed to import module 'transformers'" + installation_guide = [ + "Please make sure 'transformers' is installed. ", + "You can install it by `pip install transformers`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + trust_remote_code=kwargs["trust_remote_code"], + encode_special_tokens=True, + revision=kwargs["revision"], + ) + model = AutoModel.from_pretrained( + self.model_path, + **kwargs, + ) + return model, tokenizer + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format != "pytorch": + return False + model_family = llm_family.model_family or llm_family.model_name + if "chatglm" not in model_family and "glm4" not in model_family: + return False + if "chat" not in llm_family.model_ability: + return False + return True + + def _handle_tools(self, chat_history, generate_config) -> bool: + """Convert openai tools to ChatGLM tools.""" + if generate_config is None: + return False + tools = generate_config.pop("tools", None) + if tools is None: + return False + # Convert a iterable to a list + tools = list(tools) + tool_choice = generate_config.pop("tool_choice", "none") + if self.model_family.model_name in GLM4_TOOL_CALL_FAMILY: + chat_history[:] = self._process_messages( + chat_history, tools=tools, tool_choice=tool_choice + ) + return True + else: + chatglm_tools = [] + for elem in tools: + if elem.get("type") != "function" or "function" not in elem: + raise ValueError("ChatGLM tools only support function type.") + chatglm_tools.append(elem["function"]) + tool_prompt_message = { + "role": "system", + "content": f"Answer the following questions as best as you can. You have access to the following tools:", + "tools": chatglm_tools, + } + chat_history.insert(0, tool_prompt_message) + return True + + @staticmethod + def _process_messages(messages, tools=None, tool_choice="none"): + # This method is adapted from https://github.com/THUDM/GLM-4/blob/main/basic_demo/openai_api_server.py + _messages = messages + processed_messages = [] + msg_has_sys = False + + def _filter_tools(_tool_choice, _tools): + function_name = _tool_choice.get("function", {}).get("name", None) + if not function_name: + return [] + filtered_tools = [ + tool + for tool in _tools + if tool.get("function", {}).get("name") == function_name + ] + return filtered_tools + + if tool_choice != "none": + if isinstance(tool_choice, dict): + tools = _filter_tools(tool_choice, tools) + + if tools: + processed_messages.append( + {"role": "system", "content": None, "tools": tools} + ) + msg_has_sys = True + + if isinstance(tool_choice, dict) and tools: + processed_messages.append( + { + "role": "assistant", + "metadata": tool_choice["function"]["name"], + "content": "", + } + ) + + for m in _messages: + role, content = m["role"], m["content"] or "" + tool_calls = m.get("tool_calls") + + if role == "function": + processed_messages.append({"role": "observation", "content": content}) + elif role == "tool": + processed_messages.append( + {"role": "observation", "content": content, "function_call": True} + ) + elif role == "assistant": + if tool_calls: + for tool_call in tool_calls: + processed_messages.append( + { + "role": "assistant", + "metadata": tool_call.get("function", {}).get("name"), + "content": tool_call.get("function", {}).get( + "arguments" + ), + } + ) + else: + for response in content.split("\n"): + if "\n" in response: + metadata, sub_content = response.split("\n", maxsplit=1) + else: + metadata, sub_content = "", response + processed_messages.append( + { + "role": role, + "metadata": metadata, + "content": sub_content.strip(), + } + ) + else: + if role == "system" and msg_has_sys: + msg_has_sys = False + continue + processed_messages.append({"role": role, "content": content}) + + if not tools or tool_choice == "none": + for m in _messages: + if m["role"] == "system": + processed_messages.insert( + 0, {"role": m["role"], "content": m["content"]} + ) + break + return processed_messages + + @staticmethod + def _process_response(output, history, tools, end=False): + # Copy from https://huggingface.co/THUDM/glm-4-9b-chat/blob/main/modeling_chatglm.py + content = "" + history = copy.deepcopy(history) + if not tools and end: + return None, None + for response in output.split("<|assistant|>"): + if "\n" in response: + metadata, content = response.split("\n", maxsplit=1) + else: + metadata, content = "", response + if not metadata.strip(): + if tools and any(t.startswith(response) for t in tools) and not end: + # Waiting for tool call complete. + return None, None + content = content.strip() + history.append( + {"role": "assistant", "metadata": metadata, "content": content} + ) + content = content.replace("[[训练时间]]", "2023年") + else: + if tools and metadata in tools and not end: + return None, None + history.append( + {"role": "assistant", "metadata": metadata, "content": content} + ) + metadata = metadata.strip() + if tools and metadata in tools and end: + try: + parameters = json.loads(content) + content = {"name": metadata.strip(), "parameters": parameters} + except json.JSONDecodeError: + content = {"name": metadata.strip(), "content": content} + else: + content = {"name": metadata.strip(), "content": content} + return content, history + + def _get_generate_args( + self, + tokenizer, + query: str, + history: Optional[List[Dict]] = None, + role: str = "user", + past_key_values=None, + max_length: int = 8192, + do_sample=True, + top_p=0.8, + temperature=0.8, + logits_processor=None, + **kwargs, + ): + # Copy from https://huggingface.co/THUDM/glm-4-9b-chat/blob/main/modeling_chatglm.py + if history is None: + history = [] + if logits_processor is None: + logits_processor = LogitsProcessorList() + logits_processor.append(InvalidScoreLogitsProcessor()) + eos_token_id = [ + tokenizer.eos_token_id, + tokenizer.convert_tokens_to_ids("<|user|>"), + tokenizer.convert_tokens_to_ids("<|observation|>"), + ] + gen_kwargs = { + "max_length": max_length, + "do_sample": do_sample, + "top_p": top_p, + "temperature": temperature, + "logits_processor": logits_processor, + **kwargs, + } + if past_key_values is None: + inputs = tokenizer.apply_chat_template( + history + [{"role": role, "content": query}], + add_generation_prompt=True, + tokenize=True, + return_tensors="pt", + return_dict=True, + ) + else: + inputs = tokenizer.apply_chat_template( + [{"role": role, "content": query}], + add_special_tokens=False, + add_generation_prompt=True, + tokenize=True, + return_tensors="pt", + return_dict=True, + ) + inputs = inputs.to(self._model.device) + if past_key_values is not None: + past_length = past_key_values[0][0].shape[2] + inputs.position_ids += past_length + attention_mask = inputs.attention_mask + attention_mask = torch.cat( + (attention_mask.new_ones(1, past_length), attention_mask), dim=1 + ) + inputs["attention_mask"] = attention_mask + history.append({"role": role, "content": query}) + tools = history[0]["role"] == "system" and history[0].get("tools") + tools = ( + [ + t.get("function", {}).get("name", "") + for t in tools + if isinstance(t, dict) + ] + if tools + else [] + ) + kwargs = dict(inputs) + kwargs["past_key_values"] = past_key_values + kwargs["eos_token_id"] = eos_token_id + kwargs.update(gen_kwargs) + return kwargs, tools + + @torch.inference_mode() + def _stream_chat( + self, + tokenizer, + query: str, + history: Optional[List[Dict]] = None, + role: str = "user", + past_key_values=None, + max_length: int = 8192, + do_sample=True, + top_p=0.8, + temperature=0.8, + logits_processor=None, + **kwargs, + ): + from transformers import TextIteratorStreamer + + kwargs, tools = self._get_generate_args( + tokenizer=tokenizer, + query=query, + history=history, + role=role, + past_key_values=past_key_values, + max_length=max_length, + do_sample=do_sample, + top_p=top_p, + temperature=temperature, + logits_processor=logits_processor, + **kwargs, + ) + + streamer = TextIteratorStreamer( + tokenizer, skip_prompt=True, skip_special_tokens=True + ) + kwargs["streamer"] = streamer + thread = threading.Thread(target=self._model.generate, kwargs=kwargs) + thread.start() + + response = "" + for token in streamer: + response += token + if response and response[-1] != "�": + new_response, new_history = self._process_response( + response, history, tools, end=False + ) + if new_response is None: + continue + yield new_response, new_history + if tools: + new_response, new_history = self._process_response( + response, history, tools, end=True + ) + if new_response: + yield new_response, new_history + + @torch.inference_mode() + def _non_stream_chat( + self, + tokenizer, + query: str, + history: Optional[List[Dict]] = None, + role: str = "user", + past_key_values=None, + max_length: int = 8192, + do_sample=True, + top_p=0.8, + temperature=0.8, + logits_processor=None, + **kwargs, + ): + kwargs, tools = self._get_generate_args( + tokenizer=tokenizer, + query=query, + history=history, + role=role, + past_key_values=past_key_values, + max_length=max_length, + do_sample=do_sample, + top_p=top_p, + temperature=temperature, + logits_processor=logits_processor, + **kwargs, + ) + + outputs = self._model.generate(**kwargs) + outputs = outputs[:, kwargs["input_ids"].shape[1] :] + response = tokenizer.decode(outputs[0], skip_special_tokens=True) + if tools: + return self._process_response(response, history, tools, end=True) + else: + return self._process_response(response, history, tools) + + def chat( + self, + prompt: str, + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + kwargs: Dict[str, Any] = {} + generate_config = generate_config or {} + temperature = generate_config.get("temperature") + if temperature is not None: + kwargs["temperature"] = float(temperature) + top_p = generate_config.get("top_p") + if top_p is not None: + kwargs["top_p"] = float(top_p) + max_new_tokens = generate_config.get("max_tokens") + if max_new_tokens is not None: + kwargs["max_new_tokens"] = int(max_new_tokens) + chat_history = chat_history or [] + tools = self._handle_tools(chat_history, generate_config) + # Tool calls only works for non stream, so we call chat directly. + if prompt == SPECIAL_TOOL_PROMPT and chat_history: + tool_message = chat_history.pop() + content = tool_message.get("content") + assert content is not None + prompt = content + kwargs["role"] = "observation" + chat_history = [h for h in chat_history if not h.get("tool_calls")] + if system_prompt: + chat_history.append({"role": "system", "content": system_prompt}) + stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + if stream and ( + not tools or self.model_family.model_name in GLM4_TOOL_CALL_FAMILY + ): + + def _stream_generator(): + last_chunk_text_length = 0 + chunk_id = "chat-" + str(uuid.uuid1()) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + inputs = self._tokenizer([prompt], return_tensors="pt") + inputs = inputs.to(self._model.device) + prompt_tokens = len(inputs["input_ids"][0]) + for chunk_text, _ in self._stream_chat( + self._tokenizer, prompt, chat_history, **kwargs + ): + if tools and isinstance(chunk_text, dict): + yield self._tool_calls_completion_chunk( + self.model_family, self.model_uid, [chunk_text, _], tools + ) + return + completion_tokens = completion_tokens + 1 + total_tokens = prompt_tokens + completion_tokens + chunk_text = chunk_text[last_chunk_text_length:] + last_chunk_text_length += len(chunk_text) + completion_choice = CompletionChoice( + text=chunk_text, index=0, logprobs=None, finish_reason=None + ) + yield CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + usage=CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ), + ) + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + if include_usage: + chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk + + return self._to_chat_completion_chunks(_stream_generator()) + else: + response = self._non_stream_chat( + self._tokenizer, prompt, chat_history, **kwargs + ) + if tools: + return self._tool_calls_completion( + self.model_family, self.model_uid, response, tools + ) + else: + content, _ = response + return ChatCompletion( + id="chat" + str(uuid.uuid1()), + object="chat.completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + ChatCompletionChoice( + index=0, + message={"role": "assistant", "content": content}, + finish_reason="stop", + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + Set temperature and top_p to 0.8 by default + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + temperature = raw_config.get("temperature", None) + if temperature is None: + raw_config["temperature"] = 0.8 + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.8 + + return raw_config diff --git a/xinference/model/llm/transformers/cogvlm2.py b/xinference/model/llm/transformers/cogvlm2.py new file mode 100644 index 0000000000..79b15be69c --- /dev/null +++ b/xinference/model/llm/transformers/cogvlm2.py @@ -0,0 +1,465 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, Iterator, List, Optional, Tuple, Union + +import torch + +from ....core.scheduler import InferenceRequest +from ....model.utils import select_device +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig +from .utils import get_max_src_len + +logger = logging.getLogger(__name__) + + +LANGUAGE_TOKEN_TYPE = 0 +VISION_TOKEN_TYPE = 1 + + +def recur_move_to(item, tgt, criterion_func): + """ + This function is copied from https://github.com/THUDM/CogVLM2/blob/main/basic_demo/cli_demo_batch_inference.py + """ + if criterion_func(item): + device_copy = item.to(tgt) + return device_copy + elif isinstance(item, list): + return [recur_move_to(v, tgt, criterion_func) for v in item] + elif isinstance(item, tuple): + return tuple([recur_move_to(v, tgt, criterion_func) for v in item]) + elif isinstance(item, dict): + return {k: recur_move_to(v, tgt, criterion_func) for k, v in item.items()} + else: + return item + + +class CogVLM2Model(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._torch_type = None + self._device = None + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "cogvlm2" in family.lower() and "video" not in family.lower(): + return True + return False + + def load(self, **kwargs): + from transformers import AutoModelForCausalLM, AutoTokenizer + from transformers.generation import GenerationConfig + + device = self._pytorch_model_config.get("device", "auto") + self._device = select_device(device) + self._torch_type = ( + torch.bfloat16 + if torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 8 + else torch.float16 + ) + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + self._tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + + self._model = AutoModelForCausalLM.from_pretrained( + self.model_path, + torch_dtype=self._torch_type, + trust_remote_code=True, + low_cpu_mem_usage=True, + device_map="auto", + ).eval() + + # Specify hyperparameters for generation + self._model.generation_config = GenerationConfig.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + self._save_tensorizer() + + def _message_content_to_cogvlm2(self, content): + if not isinstance(content, str): + texts = [] + image_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + image_futures = [] + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + text = " ".join(texts) + if len(images) == 0: + return text, None + elif len(images) == 1: + return text, images + else: + raise RuntimeError( + "Only one image per message is supported by CogVLM2." + ) + return content, None + + def _history_content_to_cogvlm2( + self, system_prompt: str, chat_history: List[ChatCompletionMessage] + ): + query = system_prompt + history: List[Tuple] = [] + pixel_values = None + for i in range(0, len(chat_history), 2): + user = chat_history[i]["content"] + if isinstance(user, List): + for content in user: + c_type = content.get("type") + if c_type == "text": + user = content["text"] + elif c_type == "image_url" and not pixel_values: + pixel_values = _decode_image(content["image_url"]["url"]) + assistant = chat_history[i + 1]["content"] + history.append((user, assistant)) + query = assistant # type: ignore + return query, history, [pixel_values] + + def get_query_and_history( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + ): + content, image = self._message_content_to_cogvlm2(prompt) + + history = [] + history_image = None + if chat_history: + query, history, history_image = self._history_content_to_cogvlm2( + system_prompt, chat_history # type: ignore + ) + + if image and history_image: + history = [] + query = content + else: + image = image if image else history_image + query = content + return query, image, history + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + system_prompt = system_prompt if system_prompt else "" + stream = generate_config.get("stream", False) if generate_config else False + + sanitized_config = { + "pad_token_id": 128002, + "max_new_tokens": generate_config.get("max_tokens", 512) + if generate_config + else 512, + } + + query, image, history = self.get_query_and_history( + prompt, system_prompt=system_prompt, chat_history=chat_history + ) + + input_by_model = self._model.build_conversation_input_ids( + self._tokenizer, + query=query, + history=history, + images=image, + template_version="chat", + ) + + inputs = { + "input_ids": input_by_model["input_ids"].unsqueeze(0).to(self._device), + "token_type_ids": input_by_model["token_type_ids"] + .unsqueeze(0) + .to(self._device), + "attention_mask": input_by_model["attention_mask"] + .unsqueeze(0) + .to(self._device), + "images": [ + [input_by_model["images"][0].to(self._device).to(self._torch_type)] + ] + if image is not None + else None, + } + + if stream: + it = self._streaming_chat_response(inputs, sanitized_config) + return self._to_chat_completion_chunks(it) + else: + with torch.no_grad(): + outputs = self._model.generate(**inputs, **sanitized_config) + outputs = outputs[:, inputs["input_ids"].shape[1] :] + response = self._tokenizer.decode(outputs[0]) + response = response.split("<|end_of_text|>")[0] + + chunk = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return self._to_chat_completion(chunk) + + def _streaming_chat_response( + self, inputs: Dict, config: Dict + ) -> Iterator[CompletionChunk]: + from threading import Thread + + from transformers import TextIteratorStreamer + + streamer = TextIteratorStreamer( + self._tokenizer, skip_prompt=True, skip_special_tokens=True + ) + generation_kwargs = { + "input_ids": inputs["input_ids"], + "attention_mask": inputs["attention_mask"], + "token_type_ids": inputs["token_type_ids"], + "images": inputs["images"], + "max_new_tokens": config["max_new_tokens"], + "pad_token_id": config["pad_token_id"], + "streamer": streamer, + } + + thread = Thread(target=self._model.generate, kwargs=generation_kwargs) + thread.start() + + completion_id = str(uuid.uuid1()) + for new_text in streamer: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=new_text, finish_reason=None, logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + yield chunk + + @staticmethod + def build_position_ids(x, attention_mask=None): + """ + Copied from https://huggingface.co/THUDM/cogvlm2-llama3-chinese-chat-19B-int4/blob/main/modeling_cogvlm.py + """ + # Fix: 参考官方开源代码 + if attention_mask is not None: + tmp = x.clone() + tmp[~(attention_mask.bool())] = -1 + else: + tmp = x.clone() + # image boi eoi token as LANGUAGE_TOKEN_TYPE + is_boi_eoi = torch.zeros_like(x, dtype=torch.bool) + is_boi_eoi[:, 1:] |= (tmp[:, 1:] == VISION_TOKEN_TYPE) & ( + tmp[:, :-1] == LANGUAGE_TOKEN_TYPE + ) + is_boi_eoi[:, 0] |= tmp[:, 0] == VISION_TOKEN_TYPE + is_boi_eoi[:, :-1] |= (tmp[:, :-1] == VISION_TOKEN_TYPE) & ( + tmp[:, 1:] == LANGUAGE_TOKEN_TYPE + ) + is_boi_eoi[:, -1] |= tmp[:, -1] == VISION_TOKEN_TYPE + tmp[is_boi_eoi] = LANGUAGE_TOKEN_TYPE + # final position ids + y = torch.zeros_like(x, dtype=torch.long) + y[:, 1:] = (tmp[:, 1:] == LANGUAGE_TOKEN_TYPE) | ( + (tmp[:, 1:] == VISION_TOKEN_TYPE) & (tmp[:, :-1] == LANGUAGE_TOKEN_TYPE) + ) + y = y.cumsum(dim=-1) + return y + + def get_dtype(self): + return self._torch_type + + def _get_full_prompt(self, prompt, system_prompt, chat_history, tools): + query, image, history = self.get_query_and_history( + prompt, system_prompt=system_prompt, chat_history=chat_history + ) + + input_by_model: dict = self._model.build_conversation_input_ids( # type: ignore + self._tokenizer, + query=query, + history=history, + images=image, + template_version="chat", + ) + return { + "input_ids": input_by_model["input_ids"], # seq_len + "token_type_ids": input_by_model["token_type_ids"], # seq_len + "attention_mask": input_by_model["attention_mask"], # seq_len + "images": input_by_model["images"], + } + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + See https://huggingface.co/THUDM/cogvlm2-llama3-chat-19B/blob/main/generation_config.json + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + temperature = raw_config.get("temperature", None) + if temperature is None: + raw_config["temperature"] = 0.6 + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.9 + return raw_config + + def build_prefill_kwargs(self, prompts: List, req_list: List[InferenceRequest]): + context_len = self.get_context_len() + assert isinstance(prompts[0], dict) + images = [] + max_length = float("-inf") + for i, feature in enumerate(prompts): + req = req_list[i] + if "images" in feature: + images.append(feature.pop("images", None)) + max_src_len = get_max_src_len(context_len, req) + input_ids = feature["input_ids"][-max_src_len:] + req.prompt_tokens = input_ids.tolist() + feature["input_ids"] = input_ids + feature["token_type_ids"] = feature["token_type_ids"][-max_src_len:] + feature["attention_mask"] = feature["attention_mask"][-max_src_len:] + req.extra_kwargs["attention_mask_seq_len"] = feature[ + "attention_mask" + ].shape[0] + max_length = max(len(input_ids), max_length) + + def pad_to_max_length_internal(feature, max_len, idx): + padding_length = max_len - len(feature["input_ids"]) + req_list[idx].padding_len = padding_length + feature["input_ids"] = torch.cat( + [torch.full((padding_length,), 0), feature["input_ids"]] + ) + feature["token_type_ids"] = torch.cat( + [ + torch.zeros(padding_length, dtype=torch.long), + feature["token_type_ids"], + ] + ) + feature["attention_mask"] = torch.cat( + [ + torch.zeros(padding_length, dtype=torch.long), + feature["attention_mask"], + ] + ) + return feature + + features = [ + pad_to_max_length_internal(feature, max_length, i) + for i, feature in enumerate(prompts) + ] + batch = { + key: torch.stack([feature[key] for feature in features]) + for key in features[0].keys() + } + + position_ids = self.build_position_ids(batch["token_type_ids"]) + batch["position_ids"] = position_ids + + for i in range(len(prompts)): + req = req_list[i] + req.extra_kwargs["max_position_id"] = position_ids[i : i + 1, -1].item() + + if images: + batch["images"] = images + + batch = recur_move_to( + batch, self._device, lambda x: isinstance(x, torch.Tensor) + ) + dtype = self.get_dtype() + if dtype: + batch = recur_move_to( + batch, + dtype, + lambda x: isinstance(x, torch.Tensor) and torch.is_floating_point(x), + ) + return batch + + def build_decode_token_type_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + token_type_ids = torch.full( + (batch_size, 1), fill_value=1, dtype=torch.long, device=self._device + ) + return token_type_ids + + def build_decode_position_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + tmp = [] + for r in reqs: + r.extra_kwargs["max_position_id"] += 1 + tmp.append(r.extra_kwargs["max_position_id"]) + position_ids = torch.as_tensor( + tmp, device=self._device, dtype=torch.long + ).unsqueeze(1) + return position_ids diff --git a/xinference/model/llm/transformers/cogvlm2_video.py b/xinference/model/llm/transformers/cogvlm2_video.py new file mode 100644 index 0000000000..24f31e0b5c --- /dev/null +++ b/xinference/model/llm/transformers/cogvlm2_video.py @@ -0,0 +1,524 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, Iterator, List, Optional, Tuple, Union + +import torch + +from ....core.scheduler import InferenceRequest +from ....model.utils import select_device +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig +from .utils import get_max_src_len + +logger = logging.getLogger(__name__) + + +LANGUAGE_TOKEN_TYPE = 0 +VISION_TOKEN_TYPE = 1 + + +def recur_move_to(item, tgt, criterion_func): + """ + This function is copied from https://github.com/THUDM/CogVLM2/blob/main/basic_demo/cli_demo_batch_inference.py + """ + if criterion_func(item): + device_copy = item.to(tgt) + return device_copy + elif isinstance(item, list): + return [recur_move_to(v, tgt, criterion_func) for v in item] + elif isinstance(item, tuple): + return tuple([recur_move_to(v, tgt, criterion_func) for v in item]) + elif isinstance(item, dict): + return {k: recur_move_to(v, tgt, criterion_func) for k, v in item.items()} + else: + return item + + +class CogVLM2VideoModel(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._torch_type = None + self._device = None + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "cogvlm2" in family.lower() and "video" in family.lower(): + return True + return False + + def load(self, **kwargs): + from transformers import AutoModelForCausalLM, AutoTokenizer + from transformers.generation import GenerationConfig + + device = self._pytorch_model_config.get("device", "auto") + self._device = select_device(device) + self._torch_type = ( + torch.bfloat16 + if torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 8 + else torch.float16 + ) + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + if "8-bit" in self.quantization.lower(): + kwargs["load_in_8bit"] = True + elif "4-bit" in self.quantization.lower(): + kwargs["load_in_4bit"] = True + + self._tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + + self._model = AutoModelForCausalLM.from_pretrained( + self.model_path, + torch_dtype=self._torch_type, + trust_remote_code=True, + low_cpu_mem_usage=True, + device_map="auto", + **kwargs + ).eval() + + # Specify hyperparameters for generation + self._model.generation_config = GenerationConfig.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + self._save_tensorizer() + + def _load_video(self, video_path): + import numpy as np + from decord import VideoReader, bridge, cpu + + bridge.set_bridge("torch") + num_frames = 24 + + decord_vr = VideoReader(video_path, ctx=cpu(0)) + frame_id_list = None + total_frames = len(decord_vr) + timestamps = decord_vr.get_frame_timestamp(np.arange(total_frames)) + timestamps = [i[0] for i in timestamps] + max_second = round(max(timestamps)) + 1 + frame_id_list = [] + for second in range(max_second): + closest_num = min(timestamps, key=lambda x: abs(x - second)) + index = timestamps.index(closest_num) + frame_id_list.append(index) + if len(frame_id_list) >= num_frames: + break + video_data = decord_vr.get_batch(frame_id_list) + video_data = video_data.permute(3, 0, 1, 2) + return video_data + + def _message_content_to_cogvlm2(self, content): + if not isinstance(content, str): + texts = [] + image_urls = [] + video_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + elif c_type == "video_url": + video_urls.append(c["video_url"]["url"]) + if len(video_urls) > 1: + raise RuntimeError("Only one video per message is supported") + image_futures = [] + video = None + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + for v in video_urls: + video = self._load_video(v) + text = " ".join(texts) + return text, images, video + return content, [], None + + def _history_content_to_cogvlm2( + self, system_prompt: str, chat_history: List[ChatCompletionMessage] + ): + query = system_prompt + history: List[Tuple] = [] + pixel_values = None + video_urls: List[str] = [] + for i in range(0, len(chat_history), 2): + user = chat_history[i]["content"] + if isinstance(user, List): + for content in user: + c_type = content.get("type") + if c_type == "text": + user = content["text"] + elif c_type == "image_url" and not pixel_values: + pixel_values = _decode_image(content["image_url"]["url"]) + elif c_type == "video_url": + video_urls.append(content["video_url"]["url"]) + assistant = chat_history[i + 1]["content"] + history.append((user, assistant)) + query = assistant # type: ignore + if len(video_urls) > 1: + raise RuntimeError("Only one video per message is supported") + video = None + for v in video_urls: + video = self._load_video(v) + return query, history, [pixel_values], video + + def get_query_and_history( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + ): + content, image, video = self._message_content_to_cogvlm2(prompt) + + history = [] + history_image = None + history_video = None + if chat_history: + ( + query, + history, + history_image, + history_video, + ) = self._history_content_to_cogvlm2( + system_prompt, chat_history # type: ignore + ) + + if image and history_image: + history = [] + query = content + else: + image = image if image else history_image + query = content + + if video is not None and history_video is not None: + history = [] + query = content + else: + video = video if video is not None else history_video + query = content + + return query, image, video, history + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + system_prompt = system_prompt if system_prompt else "" + stream = generate_config.get("stream", False) if generate_config else False + + sanitized_config = { + "pad_token_id": 128002, + "max_new_tokens": generate_config.get("max_tokens", 512) + if generate_config + else 512, + } + + query, image, video, history = self.get_query_and_history( + prompt, system_prompt=system_prompt, chat_history=chat_history + ) + + if video is not None: + image = [video] + + input_by_model = self._model.build_conversation_input_ids( + self._tokenizer, + query=query, + history=history, + images=image, + template_version="chat", + ) + + inputs = { + "input_ids": input_by_model["input_ids"].unsqueeze(0).to(self._device), + "token_type_ids": input_by_model["token_type_ids"] + .unsqueeze(0) + .to(self._device), + "attention_mask": input_by_model["attention_mask"] + .unsqueeze(0) + .to(self._device), + "images": [ + [input_by_model["images"][0].to(self._device).to(self._torch_type)] + ] + if image is not None + else None, + } + + if stream: + it = self._streaming_chat_response(inputs, sanitized_config) + return self._to_chat_completion_chunks(it) + else: + with torch.no_grad(): + outputs = self._model.generate(**inputs, **sanitized_config) + outputs = outputs[:, inputs["input_ids"].shape[1] :] + response = self._tokenizer.decode(outputs[0]) + response = response.split("<|end_of_text|>")[0] + + chunk = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return self._to_chat_completion(chunk) + + def _streaming_chat_response( + self, inputs: Dict, config: Dict + ) -> Iterator[CompletionChunk]: + from threading import Thread + + from transformers import TextIteratorStreamer + + streamer = TextIteratorStreamer( + self._tokenizer, skip_prompt=True, skip_special_tokens=True + ) + generation_kwargs = { + "input_ids": inputs["input_ids"], + "attention_mask": inputs["attention_mask"], + "token_type_ids": inputs["token_type_ids"], + "images": inputs["images"], + "max_new_tokens": config["max_new_tokens"], + "pad_token_id": config["pad_token_id"], + "streamer": streamer, + } + + thread = Thread(target=self._model.generate, kwargs=generation_kwargs) + thread.start() + + completion_id = str(uuid.uuid1()) + for new_text in streamer: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=new_text, finish_reason=None, logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + yield chunk + + @staticmethod + def build_position_ids(x, attention_mask=None): + """ + Copied from https://huggingface.co/THUDM/cogvlm2-llama3-chinese-chat-19B-int4/blob/main/modeling_cogvlm.py + """ + # Fix: 参考官方开源代码 + if attention_mask is not None: + tmp = x.clone() + tmp[~(attention_mask.bool())] = -1 + else: + tmp = x.clone() + # image boi eoi token as LANGUAGE_TOKEN_TYPE + is_boi_eoi = torch.zeros_like(x, dtype=torch.bool) + is_boi_eoi[:, 1:] |= (tmp[:, 1:] == VISION_TOKEN_TYPE) & ( + tmp[:, :-1] == LANGUAGE_TOKEN_TYPE + ) + is_boi_eoi[:, 0] |= tmp[:, 0] == VISION_TOKEN_TYPE + is_boi_eoi[:, :-1] |= (tmp[:, :-1] == VISION_TOKEN_TYPE) & ( + tmp[:, 1:] == LANGUAGE_TOKEN_TYPE + ) + is_boi_eoi[:, -1] |= tmp[:, -1] == VISION_TOKEN_TYPE + tmp[is_boi_eoi] = LANGUAGE_TOKEN_TYPE + # final position ids + y = torch.zeros_like(x, dtype=torch.long) + y[:, 1:] = (tmp[:, 1:] == LANGUAGE_TOKEN_TYPE) | ( + (tmp[:, 1:] == VISION_TOKEN_TYPE) & (tmp[:, :-1] == LANGUAGE_TOKEN_TYPE) + ) + y = y.cumsum(dim=-1) + return y + + def get_dtype(self): + return self._torch_type + + def _get_full_prompt(self, prompt, system_prompt, chat_history, tools): + query, image, video, history = self.get_query_and_history( + prompt, system_prompt=system_prompt, chat_history=chat_history + ) + + if video: + image = [video] + + input_by_model: dict = self._model.build_conversation_input_ids( # type: ignore + self._tokenizer, + query=query, + history=history, + images=image, + template_version="chat", + ) + return { + "input_ids": input_by_model["input_ids"], # seq_len + "token_type_ids": input_by_model["token_type_ids"], # seq_len + "attention_mask": input_by_model["attention_mask"], # seq_len + "images": input_by_model["images"], + } + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + See https://huggingface.co/THUDM/cogvlm2-llama3-chat-19B/blob/main/generation_config.json + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + temperature = raw_config.get("temperature", None) + if temperature is None: + raw_config["temperature"] = 0.6 + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.9 + return raw_config + + def build_prefill_kwargs(self, prompts: List, req_list: List[InferenceRequest]): + context_len = self.get_context_len() + assert isinstance(prompts[0], dict) + images = [] + max_length = float("-inf") + for i, feature in enumerate(prompts): + req = req_list[i] + if "images" in feature: + images.append(feature.pop("images", None)) + max_src_len = get_max_src_len(context_len, req) + input_ids = feature["input_ids"][-max_src_len:] + req.prompt_tokens = input_ids.tolist() + feature["input_ids"] = input_ids + feature["token_type_ids"] = feature["token_type_ids"][-max_src_len:] + feature["attention_mask"] = feature["attention_mask"][-max_src_len:] + req.extra_kwargs["attention_mask_seq_len"] = feature[ + "attention_mask" + ].shape[0] + max_length = max(len(input_ids), max_length) + + def pad_to_max_length_internal(feature, max_len, idx): + padding_length = max_len - len(feature["input_ids"]) + req_list[idx].padding_len = padding_length + feature["input_ids"] = torch.cat( + [torch.full((padding_length,), 0), feature["input_ids"]] + ) + feature["token_type_ids"] = torch.cat( + [ + torch.zeros(padding_length, dtype=torch.long), + feature["token_type_ids"], + ] + ) + feature["attention_mask"] = torch.cat( + [ + torch.zeros(padding_length, dtype=torch.long), + feature["attention_mask"], + ] + ) + return feature + + features = [ + pad_to_max_length_internal(feature, max_length, i) + for i, feature in enumerate(prompts) + ] + batch = { + key: torch.stack([feature[key] for feature in features]) + for key in features[0].keys() + } + + position_ids = self.build_position_ids(batch["token_type_ids"]) + batch["position_ids"] = position_ids + + for i in range(len(prompts)): + req = req_list[i] + req.extra_kwargs["max_position_id"] = position_ids[i : i + 1, -1].item() + + if images: + batch["images"] = images + + batch = recur_move_to( + batch, self._device, lambda x: isinstance(x, torch.Tensor) + ) + dtype = self.get_dtype() + if dtype: + batch = recur_move_to( + batch, + dtype, + lambda x: isinstance(x, torch.Tensor) and torch.is_floating_point(x), + ) + return batch + + def build_decode_token_type_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + token_type_ids = torch.full( + (batch_size, 1), fill_value=1, dtype=torch.long, device=self._device + ) + return token_type_ids + + def build_decode_position_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + tmp = [] + for r in reqs: + r.extra_kwargs["max_position_id"] += 1 + tmp.append(r.extra_kwargs["max_position_id"]) + position_ids = torch.as_tensor( + tmp, device=self._device, dtype=torch.long + ).unsqueeze(1) + return position_ids diff --git a/xinference/model/llm/pytorch/compression.py b/xinference/model/llm/transformers/compression.py similarity index 100% rename from xinference/model/llm/pytorch/compression.py rename to xinference/model/llm/transformers/compression.py diff --git a/xinference/model/llm/transformers/core.py b/xinference/model/llm/transformers/core.py new file mode 100644 index 0000000000..b02f88e947 --- /dev/null +++ b/xinference/model/llm/transformers/core.py @@ -0,0 +1,813 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import logging +import os +from functools import lru_cache +from typing import Iterable, Iterator, List, Optional, Tuple, Union + +import torch + +from ....core.scheduler import InferenceRequest +from ....device_utils import ( + get_device_preferred_dtype, + gpu_count, + is_hf_accelerate_supported, +) +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CreateCompletionTorch, + LoRA, + PytorchGenerateConfig, + PytorchModelConfig, +) +from ...utils import select_device +from ..core import LLM +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import QWEN_TOOL_CALL_FAMILY, ChatModelMixin +from .utils import get_context_length, get_max_src_len, pad_prefill_tokens + +logger = logging.getLogger(__name__) + +NON_DEFAULT_MODEL_LIST: List[str] = [ + "chatglm3", + "chatglm3-32k", + "chatglm3-128k", + "glm4-chat", + "glm4-chat-1m", + "llama-2", + "llama-2-chat", + "internlm2-chat", + "internlm2.5-chat", + "qwen-vl-chat", + "OmniLMM", + "yi-vl-chat", + "deepseek-vl-chat", + "internvl-chat", + "internvl2", + "cogvlm2", + "cogvlm2-video-llama3-chat", + "MiniCPM-Llama3-V-2_5", + "MiniCPM-V-2.6", + "glm-4v", +] + + +class PytorchModel(LLM): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + pytorch_model_config: Optional[PytorchModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__(model_uid, model_family, model_spec, quantization, model_path) + self._use_fast_tokenizer = True + self._pytorch_model_config: PytorchModelConfig = self._sanitize_model_config( + pytorch_model_config + ) + self._peft_model = peft_model + + def _sanitize_model_config( + self, pytorch_model_config: Optional[PytorchModelConfig] + ) -> PytorchModelConfig: + if pytorch_model_config is None: + pytorch_model_config = PytorchModelConfig() + pytorch_model_config.setdefault("revision", self.model_spec.model_revision) + pytorch_model_config.setdefault("gptq_ckpt", None) + pytorch_model_config.setdefault("gptq_wbits", 16) + pytorch_model_config.setdefault("gptq_groupsize", -1) + pytorch_model_config.setdefault("gptq_act_order", False) + pytorch_model_config.setdefault("device", "auto") + pytorch_model_config.setdefault("trust_remote_code", True) + pytorch_model_config.setdefault("max_num_seqs", 16) + pytorch_model_config.setdefault("enable_tensorizer", False) + return pytorch_model_config + + def _sanitize_generate_config( + self, + generate_config: Optional[PytorchGenerateConfig], + ) -> PytorchGenerateConfig: + if generate_config is None: + generate_config = PytorchGenerateConfig(**CreateCompletionTorch().dict()) + else: + # Validate generate_config and fill default values to the generate config. + generate_config = PytorchGenerateConfig( + **CreateCompletionTorch(**generate_config).dict() + ) + generate_config["model"] = self.model_uid + return generate_config + + def _check_tensorizer_integrity(self): + if not self._pytorch_model_config.get("enable_tensorizer"): + return False + + from .tensorizer_utils import check_tensorizer_integrity + + integrity = check_tensorizer_integrity( + self.model_path, + [component[0] for component in self._get_components()], + ) + logger.info(f"Tensorizer files integrity: {integrity} {self.model_uid}") + return integrity + + def _load_tensorizer(self, **kwargs): + enable_tensorizer = self._pytorch_model_config.get("enable_tensorizer", None) + if enable_tensorizer: + from .tensorizer_utils import load_from_tensorizer + + component_metadata = [ + (name, type, kwargs) + for name, _, type, kwargs in self._get_components(**kwargs) + ] + model, tokenizer = load_from_tensorizer( + self.model_path, component_metadata, self._get_model_class(), **kwargs + ) + return model, tokenizer + + def _save_tensorizer(self, **kwargs): + enable_tensorizer = self._pytorch_model_config.get("enable_tensorizer", None) + if enable_tensorizer: + from .tensorizer_utils import save_to_tensorizer + + components = [(name, obj) for name, obj, _, _ in self._get_components()] + save_to_tensorizer(self.model_path, self._model, components, **kwargs) + + def _get_model_class(self): + from transformers import AutoModelForCausalLM + + return AutoModelForCausalLM + + def _get_components(self, **kwargs): + from transformers import AutoTokenizer + + return [ + ( + "tokenizer", + getattr(self, "_tokenizer", None), + AutoTokenizer, + { + "use_fast": self._use_fast_tokenizer, + "trust_remote_code": kwargs.get("trust_remote_code", True), + "revision": kwargs.get("revision"), + "code_revision": kwargs.get("code_revision", None), + }, + ) + ] + + def _load_model(self, **kwargs): + try: + from transformers import AutoModelForCausalLM, AutoTokenizer + except ImportError: + error_message = "Failed to import module 'transformers'" + installation_guide = [ + "Please make sure 'transformers' is installed. ", + "You can install it by `pip install transformers`\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + use_fast=self._use_fast_tokenizer, + trust_remote_code=kwargs["trust_remote_code"], + revision=kwargs["revision"], + ) + model = AutoModelForCausalLM.from_pretrained( + self.model_path, + low_cpu_mem_usage=True, + **kwargs, + ) + + return model, tokenizer + + def _apply_lora(self): + if self._peft_model is not None: + try: + from peft import PeftModel + except ImportError: + raise ImportError( + f"Failed to import 'PeftModel' from 'peft'. Please make sure 'peft' is installed.\n\n" + ) + + for i, peft_model in enumerate(self._peft_model): + if i == 0: + self._model = PeftModel.from_pretrained( + self._model, + peft_model.local_path, + adapter_name=peft_model.lora_name, + ) + else: + self._model.load_adapter( + peft_model.local_path, adapter_name=peft_model.lora_name + ) + logger.info( + f"PEFT adaptor '{peft_model.lora_name}' successfully loaded for model '{self.model_uid}'." + ) + + def load(self): + try: + import torch + except ImportError: + raise ImportError( + f"Failed to import module 'torch'. Please make sure 'torch' is installed.\n\n" + ) + from .compression import load_compress_model + + quantization = self.quantization + num_gpus = gpu_count() + device = self._pytorch_model_config.get("device", "auto") + self._pytorch_model_config["device"] = select_device(device) + self._device = self._pytorch_model_config["device"] + + kwargs = {} + + dtype = get_device_preferred_dtype(self._device) + + if dtype is not None: + kwargs["torch_dtype"] = dtype + else: + raise ValueError(f"Device {self._device} is not supported in temporary") + + kwargs["revision"] = self._pytorch_model_config.get( + "revision", self.model_spec.model_revision + ) + kwargs["trust_remote_code"] = self._pytorch_model_config.get( + "trust_remote_code" + ) + model_format = self.model_spec.model_format + + is_device_map_auto = False + + # This is required for Intel GPU to actually work with accelerate device_map until + # https://github.com/intel/intel-extension-for-pytorch/issues/522 + # is resolved + max_memory_env = os.getenv("ACCELERATE_MAX_MEMORY", None) + + if max_memory_env is not None: + max_memory_raw = json.loads(max_memory_env) + max_memory = { + int(k) if k.isdigit() else k: max_memory_raw[k] for k in max_memory_raw + } + kwargs["max_memory"] = max_memory + + if quantization != "none" and model_format == "pytorch": + if self._device == "cuda" and self._is_linux(): + kwargs["device_map"] = "auto" + is_device_map_auto = True + if quantization == "4-bit": + kwargs["load_in_4bit"] = True + kwargs["bnb_4bit_compute_dtype"] = torch.float16 + kwargs["bnb_4bit_use_double_quant"] = True + kwargs["llm_int8_skip_modules"] = [ + "lm_head", + "encoder", + "EncDecAttention", + ] + elif quantization == "8-bit": + kwargs["load_in_8bit"] = True + else: + raise ValueError( + f"Quantization {quantization} is not supported in temporary" + ) + else: + if num_gpus != 1 and self._device == "cuda": + raise ValueError(f"Quantization is not supported for multi-gpu") + elif quantization != "8-bit": + raise ValueError( + f"Only 8-bit quantization is supported if it is not linux system or cuda device" + ) + else: + ( + self._model, + self._tokenizer, + ) = load_compress_model( + model_path=self.model_path, + device=self._device, + torch_dtype=kwargs["torch_dtype"], + use_fast=self._use_fast_tokenizer, + revision=kwargs["revision"], + ) + logger.debug(f"Model Memory: {self._model.get_memory_footprint()}") + return + + if num_gpus > 0 and is_hf_accelerate_supported(self._device): + kwargs.update({"device_map": "auto"}) + is_device_map_auto = True + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer(**kwargs) + else: + self._model, self._tokenizer = self._load_model(**kwargs) + + self._apply_lora() + + if not is_device_map_auto: + self._model.to(self._device) + + self._save_tensorizer(**kwargs) + + logger.debug(f"Model Memory: {self._model.get_memory_footprint()}") + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + return False + model_family = llm_family.model_family or llm_family.model_name + if model_family in NON_DEFAULT_MODEL_LIST: + return False + if "generate" not in llm_family.model_ability: + return False + return True + + def generate( + self, prompt: str, generate_config: Optional[PytorchGenerateConfig] = None + ) -> Union[Completion, Iterator[CompletionChunk]]: + from .utils import generate_stream + + def generator_wrapper( + prompt: str, generate_config: PytorchGenerateConfig + ) -> Iterator[CompletionChunk]: + for completion_chunk, completion_usage in generate_stream( + self.model_uid, + self._model, + self._tokenizer, + prompt, + self._device, + generate_config, + ): + completion_chunk["usage"] = completion_usage + yield completion_chunk + + logger.debug( + "Enter generate, prompt: %s, generate config: %s", prompt, generate_config + ) + + generate_config = self._sanitize_generate_config(generate_config) + + assert self._model is not None + assert self._tokenizer is not None + + lora_model = generate_config.pop("lora_name") + + if lora_model is not None and self._peft_model is not None: + for lora in self._peft_model: + if lora_model == lora.lora_name: + self._model.set_adapter(lora_model) + logger.info(f"Set lora model to {lora_model}") + break + else: + self._model.disable_adapter() + logger.info(f"No lora model {lora_model} found, skip setting") + + stream = generate_config.get("stream", False) + if not stream: + for completion_chunk, completion_usage in generate_stream( + self.model_uid, + self._model, + self._tokenizer, + prompt, + self._device, + generate_config, + ): + pass + completion = Completion( + id=completion_chunk["id"], + object=completion_chunk["object"], + created=completion_chunk["created"], + model=completion_chunk["model"], + choices=completion_chunk["choices"], + usage=completion_usage, + ) + return completion + else: + return generator_wrapper(prompt, generate_config) + + def build_prefill_attention_mask( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build attention mask for prefill phase. + Padding `0` on the left. + Note that the parameter `seq_length` is from `input_ids`. + """ + data = [] + for r in reqs: + real_len = seq_length - r.padding_len + x = torch.cat( + [ + torch.full((r.padding_len,), 0, dtype=torch.long), + torch.ones((real_len,), dtype=torch.long), + ] + ) + data.append(x) + r.extra_kwargs["attention_mask_seq_len"] = real_len + return torch.stack(data).to(self._device) + + def build_decode_attention_mask( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build attention mask for decode phase. + Note that the `seq_length` parameter is from merged kv_cache. + So we need pad `0` on the left again. + """ + data = [] + for r in reqs: + r.extra_kwargs["attention_mask_seq_len"] += 1 + attention_mask_seq_len = r.extra_kwargs["attention_mask_seq_len"] + pad_len = seq_length - attention_mask_seq_len + x = torch.cat( + [ + torch.full((pad_len,), 0, dtype=torch.long), + torch.ones((attention_mask_seq_len,), dtype=torch.long), + ] + ) + data.append(x) + return torch.stack(data).to(self._device) + + def build_prefill_position_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build position ids for prefill phase. + Padding `0` on the left. + Note that the parameter `seq_length` is from `input_ids`. + Record the `max_position_id` on request for the decode phase. + """ + res = [] + for r in reqs: + real_seq_len = seq_length - r.padding_len + res.append( + torch.cat( + [ + torch.full((r.padding_len,), 0, dtype=torch.long), + torch.arange(0, real_seq_len, dtype=torch.long), + ] + ) + ) + r.extra_kwargs["max_position_id"] = real_seq_len - 1 + return torch.stack(res).to(self._device) + + def build_decode_position_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build position ids for decode phase. + For most models, just let the `max_position_id` in previous step += 1 and use the latest `max_position_id` + """ + data = [] + for r in reqs: + r.extra_kwargs["max_position_id"] += 1 + data.append([r.extra_kwargs["max_position_id"]]) + position_ids = torch.as_tensor(data, dtype=torch.long, device=self._device) + return position_ids + + def build_prefill_token_type_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build token_type_ids for prefill phase. + For most models, this is not required. + """ + return None + + def build_decode_token_type_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Build token_type_ids for decode phase. + For most models, this is not required. + """ + return None + + def build_prefill_inputs(self, prompts: List, req_list: List[InferenceRequest]): + """ + Get inputs for inference. Models may have their own impl. + """ + assert isinstance(prompts[0], str) + inputs = self._tokenizer(prompts, padding=False).input_ids + context_len = self.get_context_len() + input_ids = torch.as_tensor( + pad_prefill_tokens(inputs, context_len, req_list), device=self._device + ) + return input_ids + + def build_prefill_kwargs(self, prompts: List, req_list: List[InferenceRequest]): + """ + Get all inputs parameters for prefill phase. Models may have their own impl. + """ + input_ids = self.build_prefill_inputs(prompts, req_list) + res = {"input_ids": input_ids} + batch_size, seq_len = input_ids.shape + attention_mask = self.build_prefill_attention_mask( + batch_size, seq_len, req_list + ) + if attention_mask is not None: + res["attention_mask"] = attention_mask + position_ids = self.build_prefill_position_ids(batch_size, seq_len, req_list) + if position_ids is not None: + res["position_ids"] = position_ids + token_type_ids = self.build_prefill_token_type_ids( + batch_size, seq_len, req_list + ) + if token_type_ids is not None: + res["token_type_ids"] = token_type_ids + return res + + def build_decode_kwargs( + self, + prompts: List, + req_list: List[InferenceRequest], + batch_size: int, + seq_len: int, + ): + """ + Get all inputs parameters for decode phase. Models may have their own impl. + """ + res = {"input_ids": torch.as_tensor(prompts, device=self._device)} + attention_mask = self.build_decode_attention_mask(batch_size, seq_len, req_list) + if attention_mask is not None: + res["attention_mask"] = attention_mask + position_ids = self.build_decode_position_ids(batch_size, seq_len, req_list) + if position_ids is not None: + res["position_ids"] = position_ids + token_type_ids = self.build_decode_token_type_ids(batch_size, seq_len, req_list) + if token_type_ids is not None: + res["token_type_ids"] = token_type_ids + return res + + @staticmethod + def get_batch_size_and_seq_len_indexes_from_kv() -> Tuple[int, int]: + """ + From huggingface transformers document, the `pask_key_values` has the shape of + `(batch_size, num_heads, sequence_length, embed_size_per_head)`. + However, for some models, the shape may be changed. + """ + return 0, 2 + + def get_dtype(self): + raise NotImplementedError("Not implemented.") + + @lru_cache + def get_context_len(self): + return get_context_length(self._model.config) + + def get_max_num_seqs(self) -> int: + return self._pytorch_model_config.get("max_num_seqs") # type: ignore + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + return self._sanitize_generate_config(req.generate_config) + + def prepare_batch_inference(self, req_list: List[InferenceRequest]): + # check some parameters + for r in req_list: + try: + if r.sanitized_generate_config is None: + r.sanitized_generate_config = self.prepare_sanitize_generate_config( + r + ) + if r.is_prefill: + # check some generate params + max_src_len = get_max_src_len(self.get_context_len(), r) # type: ignore + if max_src_len < 0: + r.stopped = True + r.error_msg = "Max tokens exceeds model's max length" + continue + if r.stream_interval <= 0: + r.stopped = True + r.error_msg = "`stream_interval` must be greater than 0" + continue + stop_str = r.sanitized_generate_config.get("stop", None) + if stop_str and ( + not ( + isinstance(stop_str, str) or isinstance(stop_str, Iterable) + ) + ): + r.stopped = True + r.error_msg = "Invalid `stop` field type" + continue + # Catch exception here. If not catch exception, the request would hang. + except Exception as e: + logger.exception(f"prepare inference error with {e}") + r.stopped = True + r.error_msg = str(e) + + def get_builtin_stop_token_ids(self) -> Tuple: + return ( + tuple(self.model_family.prompt_style.stop_token_ids) + if self.model_family.prompt_style + and self.model_family.prompt_style.stop_token_ids + else tuple() + ) + + def handle_batch_inference_results(self, req_list: List[InferenceRequest]): + for req in req_list: + if req.error_msg is None: + # nothing need handle for non-stream case + if req.stream: + results = [] + for i, c in enumerate(req.completion): + if c == "": + chunk = req.completion[i + 1] + results.append( + CompletionChunk( + id=chunk["id"], + object=chunk["object"], + created=chunk["created"], + model=chunk["model"], + choices=[ + CompletionChoice( + text="", + index=0, + logprobs=None, + finish_reason=None, + ) + ], + ) + ) + continue + elif c == "": + break + else: + results.append(c) + + if req.stopped and req.include_usage: + results.append(req.completion[-1]) + req.completion = results + + def batch_inference(self, req_list: List[InferenceRequest]): + from .utils import batch_inference_one_step + + self.prepare_batch_inference(req_list) + batch_inference_one_step( + self, req_list, self.model_uid, self._model, self._tokenizer + ) + self.handle_batch_inference_results(req_list) + + +class PytorchChatModel(PytorchModel, ChatModelMixin): + def __init__( + self, + model_uid: str, + model_family: "LLMFamilyV1", + model_spec: "LLMSpecV1", + quantization: str, + model_path: str, + pytorch_model_config: Optional[PytorchModelConfig] = None, + peft_model: Optional[List[LoRA]] = None, + ): + super().__init__( + model_uid, + model_family, + model_spec, + quantization, + model_path, + pytorch_model_config, + peft_model, + ) + + def _sanitize_generate_config( + self, + generate_config: Optional[PytorchGenerateConfig], + ) -> PytorchGenerateConfig: + generate_config = super()._sanitize_generate_config(generate_config) + if ( + (not generate_config.get("stop")) + and self.model_family.prompt_style + and self.model_family.prompt_style.stop + ): + generate_config["stop"] = self.model_family.prompt_style.stop.copy() + if ( + generate_config.get("stop_token_ids", None) is None + and self.model_family.prompt_style + and self.model_family.prompt_style.stop_token_ids + ): + generate_config[ + "stop_token_ids" + ] = self.model_family.prompt_style.stop_token_ids.copy() + + return generate_config + + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + return False + model_family = llm_family.model_family or llm_family.model_name + if model_family in NON_DEFAULT_MODEL_LIST: + return False + if "chat" not in llm_family.model_ability: + return False + return True + + def chat( + self, + prompt: str, + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + tools = generate_config.pop("tools", []) if generate_config else None + full_prompt = self._get_full_prompt(prompt, system_prompt, chat_history, tools) + + generate_config = self._sanitize_generate_config(generate_config) + # TODO(codingl2k1): qwen hacky to set stop for function call. + model_family = self.model_family.model_family or self.model_family.model_name + if tools and model_family in QWEN_TOOL_CALL_FAMILY: + stop = generate_config.get("stop") + if isinstance(stop, str): + generate_config["stop"] = [stop, "Observation:"] + elif isinstance(stop, Iterable): + assert not isinstance(stop, str) + generate_config["stop"] = list(stop) + ["Observation:"] + else: + generate_config["stop"] = "Observation:" + + stream = generate_config.get("stream", False) + if stream: + it = self.generate(full_prompt, generate_config) + assert isinstance(it, Iterator) + return self._to_chat_completion_chunks(it) + else: + c = self.generate(full_prompt, generate_config) + assert not isinstance(c, Iterator) + if tools: + return self._tool_calls_completion( + self.model_family, self.model_uid, c, tools + ) + return self._to_chat_completion(c) + + def load(self): + super().load() + + def _get_full_prompt(self, prompt, system_prompt, chat_history, tools): + assert self.model_family.prompt_style is not None + prompt_style = self.model_family.prompt_style.copy() + if system_prompt: + prompt_style.system_prompt = system_prompt + chat_history = chat_history or [] + full_prompt = ChatModelMixin.get_prompt( + prompt, chat_history, prompt_style, tools=tools + ) + return full_prompt + + def prepare_batch_inference(self, req_list: List[InferenceRequest]): + super().prepare_batch_inference(req_list) + for r in req_list: + try: + if not r.stopped and r.is_prefill: + r.full_prompt = self._get_full_prompt( + r.prompt, r.system_prompt, r.chat_history, None + ) + except Exception as e: + logger.exception(f"prepare inference error with {e}") + r.stopped = True + r.error_msg = str(e) + + def handle_batch_inference_results(self, req_list: List[InferenceRequest]): + for req in req_list: + if req.error_msg is None and req.completion: + if req.stream: + results = [] + for i, c in enumerate(req.completion): + if c == "": + results.append( + self._get_first_chat_completion_chunk( + req.completion[i + 1] + ) + ) + elif c == "": + break + else: + results.append(self._to_chat_completion_chunk(c)) + + if req.stopped and req.include_usage: + results.append( + self._get_final_chat_completion_chunk(req.completion[-1]) + ) + req.completion = results + else: + req.completion[0] = self._to_chat_completion(req.completion[0]) diff --git a/xinference/model/llm/pytorch/deepseek_vl.py b/xinference/model/llm/transformers/deepseek_vl.py similarity index 61% rename from xinference/model/llm/pytorch/deepseek_vl.py rename to xinference/model/llm/transformers/deepseek_vl.py index 08cb812c2c..d24158f5d4 100644 --- a/xinference/model/llm/pytorch/deepseek_vl.py +++ b/xinference/model/llm/transformers/deepseek_vl.py @@ -27,9 +27,11 @@ from ....model.utils import select_device from ....types import ( ChatCompletion, - ChatCompletionChoice, ChatCompletionChunk, ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, CompletionUsage, ) from ..llm_family import LLMFamilyV1, LLMSpecV1 @@ -50,7 +52,8 @@ def __init__(self, *args, **kwargs): def match( cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str ) -> bool: - if "deepseek" in model_family.model_name: + llm_family = model_family.model_family or model_family.model_name + if "deepseek-vl" in llm_family: return True return False @@ -67,12 +70,12 @@ def load(self): self._type = torch.float16 if self._device == "mps" else torch.bfloat16 # specify the path to the model - self._vl_chat_processor: VLChatProcessor = VLChatProcessor.from_pretrained( + self._vl_chat_processor: VLChatProcessor = VLChatProcessor.from_pretrained( # type: ignore self.model_path ) self._tokenizer = self._vl_chat_processor.tokenizer - vl_gpt: MultiModalityCausalLM = AutoModelForCausalLM.from_pretrained( + vl_gpt: MultiModalityCausalLM = AutoModelForCausalLM.from_pretrained( # type: ignore self.model_path, trust_remote_code=True, device_map=self._device ) self._model = vl_gpt.to(self._type).eval() @@ -149,10 +152,16 @@ def chat( chat_history: Optional[List[ChatCompletionMessage]] = None, generate_config: Optional[PytorchGenerateConfig] = None, ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: - if generate_config and generate_config.get("stream"): - raise Exception( - f"Chat with model {self.model_family.model_name} does not support stream." - ) + if not generate_config: + generate_config = {} + + stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) prompt, images = self._message_content_to_deepseek(prompt) prompt_messages: List[Dict[str, Any]] = [ { @@ -184,6 +193,7 @@ def chat( deepseek_history.extend(prompt_messages) + from ....thirdparty.deepseek_vl.serve.inference import generate from ....thirdparty.deepseek_vl.utils.io import load_pil_images # load images and prepare for inputs @@ -192,41 +202,114 @@ def chat( conversations=deepseek_history, images=pil_images, force_batchify=True ).to(self._model.device, self._model.dtype) - # run image encoder to get the image embeddings - inputs_embeds = self._model.prepare_inputs_embeds(**prepare_inputs) - - # run the model to get the response - outputs = self._model.language_model.generate( - inputs_embeds=inputs_embeds, - attention_mask=prepare_inputs.attention_mask, - pad_token_id=self._tokenizer.eos_token_id, - bos_token_id=self._tokenizer.bos_token_id, - eos_token_id=self._tokenizer.eos_token_id, - max_new_tokens=512, - do_sample=True, - top_p=0.95, - temperature=0.2, - repetition_penalty=1.1, - use_cache=True, - ) + temperature = generate_config.get("temperature", 0.2) + top_p = generate_config.get("top_p", 0.95) + max_new_tokens = generate_config.get("max_tokens", 512) + repetition_penalty = generate_config.get("repetition_penalty", 1.1) + + conversation = self._vl_chat_processor.new_chat_template() + stop_str = conversation.sep2 + stop_words = [stop_str] - answer = self._tokenizer.decode( - outputs[0].cpu().tolist(), skip_special_tokens=True + streamer = generate( + vl_gpt=self._model, + tokenizer=self._tokenizer, + prepare_inputs=prepare_inputs, + max_gen_len=max_new_tokens, + temperature=temperature, + repetition_penalty=repetition_penalty, + top_p=top_p, + stop_words=stop_words, ) - return ChatCompletion( - id="chat" + str(uuid.uuid1()), - object="chat.completion", + if stream: + it = self._generate_stream(streamer, stop_str, include_usage, prompt) + return self._to_chat_completion_chunks(it) + else: + c = self._generate(streamer, stop_str) + return self._to_chat_completion(c) + + def _generate(self, streamer, stop_str) -> Completion: + generated_text = "" + for new_text in streamer: + if new_text.endswith(stop_str): + new_text = new_text[: -len(stop_str)] + generated_text += new_text + + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", created=int(time.time()), model=self.model_uid, choices=[ - ChatCompletionChoice( - index=0, - message={"role": "assistant", "content": answer}, - finish_reason="stop", + CompletionChoice( + index=0, text=generated_text, finish_reason="stop", logprobs=None ) ], usage=CompletionUsage( prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 ), ) + return c + + def _generate_stream( + self, streamer, stop_str, include_usage, prompt + ) -> Iterator[CompletionChunk]: + completion_id = str(uuid.uuid1()) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + input_ids = self._tokenizer(prompt).input_ids + prompt_tokens = len(input_ids) + for i, new_text in enumerate(streamer): + if new_text.endswith(stop_str): + new_text = new_text[: -len(stop_str)] + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_tokens = i + total_tokens = prompt_tokens + completion_tokens + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + if include_usage: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk diff --git a/xinference/model/llm/transformers/glm4v.py b/xinference/model/llm/transformers/glm4v.py new file mode 100644 index 0000000000..4df4f9cd4d --- /dev/null +++ b/xinference/model/llm/transformers/glm4v.py @@ -0,0 +1,419 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import typing +import uuid +from concurrent.futures import ThreadPoolExecutor +from threading import Thread +from typing import Dict, Iterator, List, Optional, Union + +import torch + +from ....core.scheduler import InferenceRequest +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ...utils import select_device +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig +from .utils import get_max_src_len + +logger = logging.getLogger(__name__) + + +class Glm4VModel(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._device = None + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "glm-4v" in family.lower(): + return True + return False + + def load(self): + from transformers import AutoModelForCausalLM, AutoTokenizer + + device = self._pytorch_model_config.get("device", "auto") + self._device = select_device(device) + + kwargs = {"device_map": self._device} + quantization = self.quantization + + # referenced from PytorchModel.load + if quantization != "none": + if self._device == "cuda" and self._is_linux(): + kwargs["device_map"] = "auto" + if quantization == "4-bit": + kwargs["load_in_4bit"] = True + elif quantization == "8-bit": + kwargs["load_in_8bit"] = True + else: + raise ValueError( + f"Quantization {quantization} is not supported in temporary" + ) + else: + if quantization != "8-bit": + raise ValueError( + f"Only 8-bit quantization is supported if it is not linux system or cuda device" + ) + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + model = AutoModelForCausalLM.from_pretrained( + self.model_path, + low_cpu_mem_usage=True, + trust_remote_code=True, + torch_dtype=torch.float16, + **kwargs, + ) + self._model = model.eval() + + tokenizer = AutoTokenizer.from_pretrained( + self.model_path, trust_remote_code=True + ) + self._tokenizer = tokenizer + self._save_tensorizer() + + def _message_content_to_chat(self, content): + if not isinstance(content, str): + texts = [] + image_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + image_futures = [] + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + text = " ".join(texts) + if len(images) == 0: + return text, [] + elif len(images) == 1: + return text, images + else: + raise RuntimeError("Only one image per message is supported") + return content, [] + + def _get_chat_msgs( + self, + prompt: Union[str, List[Dict]], + chat_history: Optional[List[ChatCompletionMessage]] = None, + ): + content, images_chat = self._message_content_to_chat(prompt) + + msgs = [] + query_to_response: List[Dict] = [] + images_history = [] + for h in chat_history or []: + role = h["role"] + content_h, images_tmp = self._message_content_to_chat(h["content"]) + if images_tmp: + images_history = images_tmp + if len(query_to_response) == 0 and role == "user": + query_to_response.append({"role": "user", "content": content_h}) + if len(query_to_response) == 1 and role == "assistant": + query_to_response.append({"role": "assistant", "content": content_h}) + if len(query_to_response) == 2: + msgs.extend(query_to_response) + query_to_response = [] + image = None + if len(images_chat) > 0: + image = images_chat[0] + elif len(images_history) > 0: + image = images_history[0] + msgs.append({"role": "user", "content": content, "image": image}) + return msgs + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + from transformers import TextIteratorStreamer + + if not generate_config: + generate_config = {} + + stream = generate_config.get("stream", False) + msgs = self._get_chat_msgs(prompt, chat_history) + + inputs = self._tokenizer.apply_chat_template( + msgs, + add_generation_prompt=True, + tokenize=True, + return_tensors="pt", + return_dict=True, + ) # chat mode + inputs = inputs.to(self._model.device) + + generate_kwargs = { + **inputs, + "eos_token_id": [151329, 151336, 151338], + "do_sample": True, + "max_length": generate_config.get("max_tokens", 2048), + "temperature": generate_config.get("temperature", 0.7), + } + stop_str = "<|endoftext|>" + + if stream: + streamer = TextIteratorStreamer( + tokenizer=self._tokenizer, + timeout=60, + skip_prompt=True, + skip_special_tokens=True, + ) + generate_kwargs = { + **generate_kwargs, + "streamer": streamer, + } + t = Thread(target=self._model.generate, kwargs=generate_kwargs) + t.start() + + it = self.chat_stream(streamer, stop_str) + return self._to_chat_completion_chunks(it) + else: + with torch.no_grad(): + outputs = self._model.generate(**generate_kwargs) + outputs = outputs[:, inputs["input_ids"].shape[1] :] + response = self._tokenizer.decode(outputs[0]) + if response.endswith(stop_str): + response = response[: -len(stop_str)] + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return self._to_chat_completion(c) + + def chat_stream(self, streamer, stop_str) -> Iterator[CompletionChunk]: + completion_id = str(uuid.uuid1()) + for new_text in streamer: + if not new_text.endswith(stop_str): + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk + + def _get_full_prompt(self, prompt, system_prompt, chat_history, tools): + msgs = self._get_chat_msgs(prompt, chat_history) + inputs = self._tokenizer.apply_chat_template( + msgs, + add_generation_prompt=True, + tokenize=True, + return_tensors="pt", + return_dict=True, + ) + return { + "input_ids": inputs.input_ids.squeeze(0), + "images": inputs.images.squeeze(0), + } + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + Refer to https://huggingface.co/THUDM/glm-4v-9b/blob/main/generation_config.json + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + temperature = raw_config.get("temperature", None) + if temperature is None: + raw_config["temperature"] = 0.8 + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.8 + return raw_config + + def build_prefill_inputs(self, prompts: List, req_list: List[InferenceRequest]): + context_len = self.get_context_len() + assert isinstance(prompts[0], dict) + images = [] + max_length = float("-inf") + for i, feature in enumerate(prompts): + req = req_list[i] + if "images" in feature: + images.append(feature.pop("images", None)) + max_src_len = get_max_src_len(context_len, req) + input_ids = feature["input_ids"][-max_src_len:] + req.prompt_tokens = input_ids.tolist() + feature["input_ids"] = input_ids + max_length = max(len(input_ids), max_length) + + def pad_to_max_length_internal(feature, max_len, idx): + padding_length = max_len - len(feature["input_ids"]) + req_list[idx].padding_len = padding_length + feature["input_ids"] = torch.cat( + [torch.full((padding_length,), 0), feature["input_ids"]] + ) + return feature + + features = [ + pad_to_max_length_internal(feature, max_length, i) + for i, feature in enumerate(prompts) + ] + batch = { + key: torch.stack([feature[key] for feature in features]) + for key in features[0].keys() + } + if images: + batch["images"] = torch.stack(images).to(self._device) + batch["input_ids"] = batch["input_ids"].to(self._device) + return batch + + @staticmethod + def is_empty(images_list: Optional[List[List[torch.Tensor]]]): + """ + Copied from https://huggingface.co/THUDM/glm-4v-9b/blob/main/modeling_chatglm.py + """ + if images_list is None or len(images_list) == 0: + return True + for image_list in images_list: + if image_list is not None: + return False + return True + + @typing.no_type_check + def get_full_attention_mask( + self, attention_mask, input_ids, images, req_list: List[InferenceRequest] + ): + """ + Modified according to https://huggingface.co/THUDM/glm-4v-9b/blob/main/modeling_chatglm.py + """ + image_size: int = self._model.config.vision_config["image_size"] + patch_size: int = self._model.config.vision_config["patch_size"] + num_patches = (image_size // patch_size // 2) ** 2 + new_attention_masks = [] + + # if not image, use this default id + eoi_token_pos = 6 + boi_token_pos = 4 + + for i in range(len(input_ids)): + input_id = input_ids[i].tolist() + req = req_list[i] + if not self.is_empty(images): + _boi_token_pos, _eoi_token_pos = input_id.index( + self._model.config.boi_token_id + ), input_id.index(self._model.config.eoi_token_id) + else: + _boi_token_pos = boi_token_pos + req.padding_len + _eoi_token_pos = eoi_token_pos + req.padding_len + assert eoi_token_pos - boi_token_pos == 2 + new_attention_masks.append( + torch.cat( + ( + attention_mask[i, : _boi_token_pos + 1], + attention_mask.new_ones(num_patches), + attention_mask[i, _eoi_token_pos:], + ) + ) + ) + attention_mask = torch.stack(new_attention_masks, dim=0).to(self._device) + return attention_mask + + def build_prefill_kwargs(self, prompts: List, req_list: List[InferenceRequest]): + batch = self.build_prefill_inputs(prompts, req_list) + batch_size, seq_len = batch["input_ids"].shape + attention_mask = self.build_prefill_attention_mask( + batch_size, seq_len, req_list + ) + if attention_mask is not None: + full_attention_mask = self.get_full_attention_mask( + attention_mask, batch["input_ids"], batch["images"], req_list + ) + batch["attention_mask"] = full_attention_mask + for r in req_list: + r.extra_kwargs["attention_mask_seq_len"] = full_attention_mask.shape[1] + position_ids = self.build_prefill_position_ids(batch_size, seq_len, req_list) + if position_ids is not None: + batch["position_ids"] = position_ids + return batch + + def build_decode_attention_mask( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + max_seq_len = max(r.extra_kwargs["attention_mask_seq_len"] for r in reqs) + + new_attention_mask = [] + for r in reqs: + attn_mask_seq_len = r.extra_kwargs["attention_mask_seq_len"] + pad_len = max_seq_len - attn_mask_seq_len + new_attention_mask.append( + torch.cat( + [torch.full((pad_len,), 0), torch.ones((attn_mask_seq_len + 1,))] + ) + ) + r.extra_kwargs["attention_mask_seq_len"] += 1 + return torch.stack(new_attention_mask, dim=0).to(self._device) diff --git a/xinference/model/llm/transformers/intern_vl.py b/xinference/model/llm/transformers/intern_vl.py new file mode 100644 index 0000000000..02632e2af8 --- /dev/null +++ b/xinference/model/llm/transformers/intern_vl.py @@ -0,0 +1,540 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, Iterator, List, Optional, Union + +import torch + +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig + +logger = logging.getLogger(__name__) + +IMAGENET_MEAN = (0.485, 0.456, 0.406) +IMAGENET_STD = (0.229, 0.224, 0.225) + + +def _message_content_to_intern(content, image_cnt): + if not isinstance(content, str): + texts = [] + image_urls = [] + video_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + elif c_type == "video_url": + video_urls.append(c["video_url"]["url"]) + if len(video_urls) > 1: + raise RuntimeError("Only one video per message is supported") + image_futures = [] + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + videos = [] + for vid_url in video_urls: + videos.append(_load_video(vid_url, num_segments=8, max_num=1)) + prefix = "" + for i, _ in enumerate(images): + prefix += f"Image-{image_cnt + i + 1}: \n\n" + + if len(videos) > 0: + prefix = "".join( + [f"Frame{i+1}: \n" for i in range(len(videos[0][1]))] + ) + + text = prefix + " ".join(texts) + return text, images, videos + return content, [], [] + + +def _get_prompt_and_chat_history( + prompt: Union[str, List[Dict]], + chat_history: Optional[List[ChatCompletionMessage]] = None, +): + # Convert openai history to intern vl history + images = [] + videos = [] + history = [] + image_cnt = 0 + for h1, h2 in zip(*[iter(chat_history or [])] * 2): + content1, img, vid = _message_content_to_intern(h1["content"], image_cnt) + content2, _, _ = _message_content_to_intern(h2["content"], image_cnt) + history.append([content1, content2]) + images.extend(img) + image_cnt += len(img) + videos.extend(vid) + + question, img, vid = _message_content_to_intern(prompt, image_cnt) + images.extend(img) + videos.extend(vid) + return question, history, images, videos + + +def _build_transform(input_size=448): + import torchvision.transforms as T + from torchvision.transforms.functional import InterpolationMode + + MEAN, STD = IMAGENET_MEAN, IMAGENET_STD + transform = T.Compose( + [ + T.Lambda(lambda img: img.convert("RGB") if img.mode != "RGB" else img), + T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC), + T.ToTensor(), + T.Normalize(mean=MEAN, std=STD), + ] + ) + return transform + + +def _find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, image_size): + best_ratio_diff = float("inf") + best_ratio = (1, 1) + area = width * height + for ratio in target_ratios: + target_aspect_ratio = ratio[0] / ratio[1] + ratio_diff = abs(aspect_ratio - target_aspect_ratio) + if ratio_diff < best_ratio_diff: + best_ratio_diff = ratio_diff + best_ratio = ratio + elif ratio_diff == best_ratio_diff: + if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]: + best_ratio = ratio + return best_ratio + + +def _dynamic_preprocess( + image, min_num=1, max_num=12, image_size=448, use_thumbnail=False +): + orig_width, orig_height = image.size + aspect_ratio = orig_width / orig_height + + # calculate the existing image aspect ratio + target_ratios = set( + (i, j) + for n in range(min_num, max_num + 1) + for i in range(1, n + 1) + for j in range(1, n + 1) + if i * j <= max_num and i * j >= min_num + ) + target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1]) + + # find the closest aspect ratio to the target + target_aspect_ratio = _find_closest_aspect_ratio( + aspect_ratio, target_ratios, orig_width, orig_height, image_size + ) + + # calculate the target width and height + target_width = image_size * target_aspect_ratio[0] + target_height = image_size * target_aspect_ratio[1] + blocks = target_aspect_ratio[0] * target_aspect_ratio[1] + + # resize the image + resized_img = image.resize((target_width, target_height)) + processed_images = [] + for i in range(blocks): + box = ( + (i % (target_width // image_size)) * image_size, + (i // (target_width // image_size)) * image_size, + ((i % (target_width // image_size)) + 1) * image_size, + ((i // (target_width // image_size)) + 1) * image_size, + ) + # split the image + split_img = resized_img.crop(box) + processed_images.append(split_img) + assert len(processed_images) == blocks + if use_thumbnail and len(processed_images) != 1: + thumbnail_img = image.resize((image_size, image_size)) + processed_images.append(thumbnail_img) + return processed_images + + +def _load_image(image_file, input_size=448, max_num=12): + image = image_file.convert("RGB") + transform = _build_transform(input_size=input_size) + images = _dynamic_preprocess( + image, image_size=input_size, use_thumbnail=True, max_num=max_num + ) + pixel_values = [transform(image) for image in images] + pixel_values = torch.stack(pixel_values) + return pixel_values + + +# video multi-round conversation +def _get_index(bound, fps, max_frame, first_idx=0, num_segments=32): + import numpy as np + + if bound: + start, end = bound[0], bound[1] + else: + start, end = -100000, 100000 + start_idx = max(first_idx, round(start * fps)) + end_idx = min(round(end * fps), max_frame) + seg_size = float(end_idx - start_idx) / num_segments + frame_indices = np.array( + [ + int(start_idx + (seg_size / 2) + np.round(seg_size * idx)) + for idx in range(num_segments) + ] + ) + return frame_indices + + +def _load_video(video_path, bound=None, input_size=448, max_num=1, num_segments=32): + from decord import VideoReader, cpu + from PIL import Image + + vr = VideoReader(video_path, ctx=cpu(0), num_threads=1) + max_frame = len(vr) - 1 + fps = float(vr.get_avg_fps()) + + pixel_values_list, num_patches_list = [], [] + transform = _build_transform(input_size=input_size) + frame_indices = _get_index( + bound, fps, max_frame, first_idx=0, num_segments=num_segments + ) + for frame_index in frame_indices: + img = Image.fromarray(vr[frame_index].asnumpy()).convert("RGB") + img = _dynamic_preprocess( + img, image_size=input_size, use_thumbnail=True, max_num=max_num + ) + pixel_values = [transform(tile) for tile in img] + pixel_values = torch.stack(pixel_values) + pixel_values = pixel_values.to(torch.bfloat16).cuda() + num_patches_list.append(pixel_values.shape[0]) + pixel_values_list.append(pixel_values) + pixel_values = torch.cat(pixel_values_list) + return pixel_values, num_patches_list + + +class InternVLChatModel(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "internvl" not in family.lower(): + return False + if "pytorch" not in model_spec.model_format: + return False + return True + + def _get_model_class(self): + from transformers import AutoModel + + return AutoModel + + # Copy from InternVL page + # reference: https://huggingface.co/OpenGVLab/InternVL2-8B + def _split_model(self): + import math + + device_map = {} + world_size = torch.cuda.device_count() + # single gpu + if world_size == 1: + return None + model_size = f"{self.model_spec.model_size_in_billions}B" + num_layers = { + "1B": 24, + "2B": 24, + "4B": 32, + "8B": 32, + "26B": 48, + "40B": 60, + "76B": 80, + }[model_size] + # Since the first GPU will be used for ViT, treat it as half a GPU. + num_layers_per_gpu = math.ceil(num_layers / (world_size - 0.5)) + num_layers_per_gpu = [num_layers_per_gpu] * world_size + num_layers_per_gpu[0] = math.ceil(num_layers_per_gpu[0] * 0.5) + layer_cnt = 0 + for i, num_layer in enumerate(num_layers_per_gpu): + for j in range(num_layer): + device_map[f"language_model.model.layers.{layer_cnt}"] = i + layer_cnt += 1 + device_map["vision_model"] = 0 + device_map["mlp1"] = 0 + device_map["language_model.model.tok_embeddings"] = 0 + device_map["language_model.model.embed_tokens"] = 0 + device_map["language_model.output"] = 0 + device_map["language_model.model.norm"] = 0 + device_map["language_model.lm_head"] = 0 + device_map[f"language_model.model.layers.{num_layers - 1}"] = 0 + return device_map + + def load(self, **kwargs): + from transformers import AutoModel, AutoTokenizer + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + device = self._split_model() + + kwargs = { + "torch_dtype": torch.bfloat16, + "low_cpu_mem_usage": True, + "trust_remote_code": True, + } + + if device is not None: + kwargs["device_map"] = device + + if "8-bit" in self.quantization.lower(): + kwargs["load_in_8bit"] = True + elif "4-bit" in self.quantization.lower(): + kwargs["load_in_4bit"] = True + + self._model = AutoModel.from_pretrained(self.model_path, **kwargs).eval() + + if device is None and "none" in self.quantization.lower(): + self._model.cuda() + + self._tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + trust_remote_code=True, + use_fast=False, + ) + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + from ....thirdparty.internvl.conversation import get_conv_template + + IMG_START_TOKEN = "" + IMG_END_TOKEN = "" + IMG_CONTEXT_TOKEN = "" + + generation_config = { + "max_new_tokens": generate_config.get("max_tokens", 1024) + if generate_config + else 1024, + "do_sample": False, + } + + stream = ( + generate_config.get("stream", False) + if isinstance(generate_config, dict) + else False + ) + stream_options = ( + generate_config.get("stream_options", None) + if isinstance(generate_config, dict) + else False + ) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + + content, history, images, videos = _get_prompt_and_chat_history( + prompt, chat_history + ) + + num_patches_list = [] + if len(images) == 1: + content = content.replace("Image-1: \n\n", "\n") + history = [ + [item[0].replace("Image-1: \n\n", "\n"), item[1]] + for item in history + ] + pixel_values = _load_image(images[-1], max_num=12).to(torch.bfloat16).cuda() + num_patches_list = ( + [pixel_values.shape[0]] if pixel_values is not None else [] + ) + elif len(images) > 1: + pixel_values = [ + _load_image(img, max_num=12).to(torch.bfloat16).cuda() for img in images + ] + num_patches_list = [values.size(0) for values in pixel_values] + pixel_values = torch.cat(pixel_values, dim=0) + else: + pixel_values = None + + if len(videos) > 0: + pixel_values = videos[0][0] + num_patches_list = videos[0][1] + + assert pixel_values is None or len(pixel_values) == sum(num_patches_list) + + img_context_token_id = self._tokenizer.convert_tokens_to_ids(IMG_CONTEXT_TOKEN) + self._model.img_context_token_id = img_context_token_id + + template = get_conv_template(self._model.template) + template.system_message = self._model.system_message + eos_token_id = self._tokenizer.convert_tokens_to_ids(template.sep) + + history = [] if history is None else history + for old_question, old_answer in history: + template.append_message(template.roles[0], old_question) + template.append_message(template.roles[1], old_answer) + template.append_message(template.roles[0], content) + template.append_message(template.roles[1], None) + query = template.get_prompt() + + for num_patches in num_patches_list: + image_tokens = ( + IMG_START_TOKEN + + IMG_CONTEXT_TOKEN * self._model.num_image_token * num_patches + + IMG_END_TOKEN + ) + query = query.replace("", image_tokens, 1) + + model_inputs = self._tokenizer(query, return_tensors="pt") + input_ids = model_inputs["input_ids"].cuda() + attention_mask = model_inputs["attention_mask"].cuda() + generation_config["eos_token_id"] = eos_token_id + generate_kwargs = { + "pixel_values": pixel_values, + "input_ids": input_ids, + "attention_mask": attention_mask, + } + generate_kwargs.update(generation_config) + + if stream: + chunk = self._generate_stream(generate_kwargs, input_ids, include_usage) + return self._to_chat_completion_chunks(chunk) + else: + chunk = self._generate(generate_kwargs, input_ids, template) + return self._to_chat_completion(chunk) + + def _generate(self, generate_kwargs, input_ids, template): + prompt_tokens = len(input_ids[0]) + generation_output = self._model.generate(**generate_kwargs) + completion_tokens = len(generation_output[0]) + response = self._tokenizer.batch_decode( + generation_output, skip_special_tokens=True + )[0] + response = response.split(template.sep)[0].strip() + chunk = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=prompt_tokens + completion_tokens, + ), + ) + return chunk + + def _generate_stream(self, generate_kwargs, input_ids, include_usage): + from threading import Thread + + from transformers import TextIteratorStreamer + + # Initialize the streamer + streamer = TextIteratorStreamer( + self._tokenizer, skip_prompt=True, skip_special_tokens=True, timeout=10 + ) + # Define the generation configuration + generate_kwargs["streamer"] = streamer + # Start the model chat in a separate thread + thread = Thread( + target=self._model.generate, + kwargs=generate_kwargs, + ) + thread.start() + + completion_id = str(uuid.uuid1()) + prompt_tokens = len(input_ids[0]) + completion_tokens = 0 + # Loop through the streamer to get the new text as it is generated + for i, new_text in enumerate(streamer): + if new_text == self._model.conv_template.sep: + break + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_tokens = max(completion_tokens, len(streamer.token_cache)) + total_tokens = prompt_tokens + completion_tokens + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + if include_usage: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk diff --git a/xinference/model/llm/pytorch/internlm2.py b/xinference/model/llm/transformers/internlm2.py similarity index 68% rename from xinference/model/llm/pytorch/internlm2.py rename to xinference/model/llm/transformers/internlm2.py index 1eb8aec683..fc7b1c7588 100644 --- a/xinference/model/llm/pytorch/internlm2.py +++ b/xinference/model/llm/transformers/internlm2.py @@ -15,6 +15,7 @@ import uuid from typing import Any, Dict, Iterator, List, Optional, Union +from ....core.scheduler import InferenceRequest from ....types import ( ChatCompletion, ChatCompletionChoice, @@ -23,6 +24,7 @@ CompletionChoice, CompletionChunk, CompletionUsage, + LoRA, PytorchGenerateConfig, ) from ..llm_family import LLMFamilyV1, LLMSpecV1 @@ -38,7 +40,7 @@ def __init__( quantization: str, model_path: str, pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, + peft_model: Optional[List[LoRA]] = None, ): super().__init__( model_uid, @@ -47,9 +49,14 @@ def __init__( quantization, model_path, pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, + peft_model=peft_model, ) + def _get_model_class(self): + from transformers import AutoModel + + return AutoModel + def _load_model(self, **kwargs): try: from transformers import AutoModel, AutoTokenizer @@ -78,14 +85,24 @@ def _load_model(self, **kwargs): def match( cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str ) -> bool: - if llm_spec.model_format != "pytorch": - return False model_family = llm_family.model_family or llm_family.model_name - if model_family != "internlm2-chat": - return False - if "chat" not in llm_family.model_ability: - return False - return True + if model_family in ["internlm2-chat", "internlm2.5-chat"]: + return True + return False + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + Overwrite this func for this special model. + Cannot use the default configuration, which works poorly on this model. + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + temperature = raw_config.get("temperature", None) + if temperature is None: + raw_config["temperature"] = 0.8 + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.8 + return raw_config def chat( self, @@ -107,6 +124,12 @@ def chat( kwargs["max_length"] = int(max_new_tokens) stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) if chat_history: input_history = [ (chat_history[i]["content"], (chat_history[i + 1]["content"])) @@ -114,14 +137,22 @@ def chat( ] else: input_history = [] + if system_prompt: + kwargs["meta_instruction"] = system_prompt if stream: def _stream_generator(): last_chunk_text_length = 0 chunk_id = "chat-" + str(uuid.uuid1()) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + inputs = self._tokenizer([prompt], return_tensors="pt") + inputs = inputs.to(self._model.device) + prompt_tokens = len(inputs["input_ids"][0]) for chunk_text, _ in self._model.stream_chat( self._tokenizer, prompt, input_history, **kwargs ): + completion_tokens = completion_tokens + 1 + total_tokens = prompt_tokens + completion_tokens chunk_text = chunk_text[last_chunk_text_length:] last_chunk_text_length += len(chunk_text) completion_choice = CompletionChoice( @@ -133,7 +164,26 @@ def _stream_generator(): created=int(time.time()), model=self.model_uid, choices=[completion_choice], + usage=CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ), + ) + if include_usage: + chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, ) + yield chunk return self._to_chat_completion_chunks(_stream_generator()) else: diff --git a/xinference/model/llm/pytorch/llama_2.py b/xinference/model/llm/transformers/llama_2.py similarity index 88% rename from xinference/model/llm/pytorch/llama_2.py rename to xinference/model/llm/transformers/llama_2.py index 27f3235a9b..4e5e01d263 100644 --- a/xinference/model/llm/pytorch/llama_2.py +++ b/xinference/model/llm/transformers/llama_2.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Optional +from typing import List, Optional +from ....types import LoRA from ..llm_family import LLMFamilyV1, LLMSpecV1 from .core import PytorchChatModel, PytorchModel, PytorchModelConfig @@ -27,7 +28,7 @@ def __init__( quantization: str, model_path: str, pytorch_model_config: Optional[PytorchModelConfig] = None, - peft_model_path: Optional[str] = None, + peft_model: Optional[List[LoRA]] = None, ): super().__init__( model_uid, @@ -36,7 +37,7 @@ def __init__( quantization, model_path, pytorch_model_config=pytorch_model_config, - peft_model_path=peft_model_path, + peft_model=peft_model, ) def _load_model(self, **kwargs): @@ -54,7 +55,8 @@ def match( ) -> bool: if llm_spec.model_format != "pytorch": return False - if "llama-2" not in llm_family.model_name: + model_family = llm_family.model_family or llm_family.model_name + if "llama-2" not in model_family: return False if "generate" not in llm_family.model_ability: return False @@ -69,8 +71,8 @@ def __init__( model_spec: "LLMSpecV1", quantization: str, model_path: str, - peft_model_path: Optional[str] = None, pytorch_model_config: Optional["PytorchModelConfig"] = None, + peft_model: Optional[List[LoRA]] = None, ): super().__init__( model_uid, @@ -78,7 +80,7 @@ def __init__( model_spec, quantization, model_path, - peft_model_path=peft_model_path, + peft_model=peft_model, pytorch_model_config=pytorch_model_config, ) self._use_fast_tokenizer = False @@ -98,7 +100,8 @@ def match( ) -> bool: if llm_spec.model_format != "pytorch": return False - if "llama-2" not in llm_family.model_name: + model_family = llm_family.model_family or llm_family.model_name + if "llama-2" not in model_family: return False if "chat" not in llm_family.model_ability: return False diff --git a/xinference/model/llm/transformers/minicpmv25.py b/xinference/model/llm/transformers/minicpmv25.py new file mode 100644 index 0000000000..af22319759 --- /dev/null +++ b/xinference/model/llm/transformers/minicpmv25.py @@ -0,0 +1,222 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import json +import logging +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, Iterator, List, Optional, Union + +import torch + +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ...utils import select_device +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig + +logger = logging.getLogger(__name__) + + +class MiniCPMV25Model(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._device = None + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "MiniCPM-Llama3-V-2_5".lower() in family.lower(): + return True + return False + + def _get_model_class(self): + from transformers import AutoModel + + return AutoModel + + def load(self, **kwargs): + from transformers import AutoModel, AutoTokenizer + from transformers.generation import GenerationConfig + + device = self._pytorch_model_config.get("device", "auto") + self._device = select_device(device) + self._device = "auto" if self._device == "cuda" else self._device + + if "int4" in self.model_path and device == "mps": + logger.error( + "Error: running int4 model with bitsandbytes on Mac is not supported right now." + ) + exit() + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + if "int4" in self.model_path: + model = AutoModel.from_pretrained(self.model_path, trust_remote_code=True) + else: + model = AutoModel.from_pretrained( + self.model_path, + trust_remote_code=True, + torch_dtype=torch.float16, + device_map=self._device, + ) + tokenizer = AutoTokenizer.from_pretrained( + self.model_path, trust_remote_code=True + ) + self._model = model.eval() + self._tokenizer = tokenizer + + # Specify hyperparameters for generation + self._model.generation_config = GenerationConfig.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + self._save_tensorizer() + + def _message_content_to_chat(self, content): + if not isinstance(content, str): + texts = [] + image_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + image_futures = [] + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + text = " ".join(texts) + if len(images) == 0: + return text, [] + elif len(images) == 1: + return text, images + else: + raise RuntimeError("Only one image per message is supported") + return content, [] + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + stream = generate_config.get("stream", False) if generate_config else False + content, images_chat = self._message_content_to_chat(prompt) + + msgs = [] + query_to_response: List[Dict] = [] + images_history = [] + for h in chat_history or []: + role = h["role"] + content_h, images_tmp = self._message_content_to_chat(h["content"]) + if images_tmp != []: + images_history = images_tmp + if len(query_to_response) == 0 and role == "user": + query_to_response.append({"role": "user", "content": content_h}) + if len(query_to_response) == 1 and role == "assistant": + query_to_response.append({"role": "assistant", "content": content_h}) + if len(query_to_response) == 2: + msgs.extend(query_to_response) + query_to_response = [] + image = None + if len(images_chat) > 0: + image = images_chat[0] + elif len(images_history) > 0: + image = images_history[0] + msgs.append({"role": "user", "content": content}) + + chat = self._model.chat( + image=image, + msgs=json.dumps(msgs, ensure_ascii=True), + tokenizer=self._tokenizer, + sampling=True, + **generate_config + ) + if stream: + it = self.chat_stream(chat) + return self._to_chat_completion_chunks(it) + else: + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=chat, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return self._to_chat_completion(c) + + def chat_stream(self, chat) -> Iterator[CompletionChunk]: + completion_id = str(uuid.uuid1()) + for new_text in chat: + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk diff --git a/xinference/model/llm/transformers/minicpmv26.py b/xinference/model/llm/transformers/minicpmv26.py new file mode 100644 index 0000000000..0900bc4a86 --- /dev/null +++ b/xinference/model/llm/transformers/minicpmv26.py @@ -0,0 +1,272 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from typing import Dict, Iterator, List, Optional, Union + +import torch +from PIL import Image + +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ...utils import select_device +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image +from .core import PytorchChatModel, PytorchGenerateConfig + +logger = logging.getLogger(__name__) + + +class MiniCPMV26Model(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._device = None + self._tokenizer = None + self._model = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + family = model_family.model_family or model_family.model_name + if "MiniCPM-V-2.6".lower() in family.lower(): + return True + return False + + def _get_model_class(self): + from transformers import AutoModel + + return AutoModel + + def load(self, **kwargs): + from transformers import AutoModel, AutoTokenizer + from transformers.generation import GenerationConfig + + device = self._pytorch_model_config.get("device", "auto") + self._device = select_device(device) + self._device = ( + "auto" + if self._device == "cuda" and self.quantization is None + else self._device + ) + + if "int4" in self.model_path and device == "mps": + logger.error( + "Error: running int4 model with bitsandbytes on Mac is not supported right now." + ) + exit() + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer() + return + + if "int4" in self.model_path: + model = AutoModel.from_pretrained(self.model_path, trust_remote_code=True) + else: + model = AutoModel.from_pretrained( + self.model_path, + trust_remote_code=True, + torch_dtype=torch.float16, + device_map=self._device, + ) + tokenizer = AutoTokenizer.from_pretrained( + self.model_path, trust_remote_code=True + ) + self._model = model.eval() + self._tokenizer = tokenizer + + # Specify hyperparameters for generation + self._model.generation_config = GenerationConfig.from_pretrained( + self.model_path, + trust_remote_code=True, + ) + self._save_tensorizer() + + def _message_content_to_chat(self, content): + MAX_NUM_FRAMES = 64 + + def encode_video(video_path): + from decord import VideoReader, cpu + + def uniform_sample(l, n): + gap = len(l) / n + idxs = [int(i * gap + gap / 2) for i in range(n)] + return [l[i] for i in idxs] + + vr = VideoReader(video_path, ctx=cpu(0)) + sample_fps = round(vr.get_avg_fps() / 1) # FPS + frame_idx = [i for i in range(0, len(vr), sample_fps)] + if len(frame_idx) > MAX_NUM_FRAMES: + frame_idx = uniform_sample(frame_idx, MAX_NUM_FRAMES) + frames = vr.get_batch(frame_idx).asnumpy() + frames = [Image.fromarray(v.astype("uint8")) for v in frames] + print("num frames:", len(frames)) + return frames + + def _load_video(_url): + frames = None + if _url.startswith("data:"): + raise RuntimeError("Only video url format is supported") + else: + frames = encode_video(_url) + return frames + + if not isinstance(content, str): + texts = [] + image_urls = [] + video_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + texts.append(c["text"]) + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + elif c_type == "video_url": + video_urls.append(c["video_url"]["url"]) + image_futures = [] + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + frames = [] + if len(video_urls) > 1: + raise RuntimeError("Only one video per message is supported") + for v in video_urls: + frames = _load_video(v) + text = " ".join(texts) + return text, images, frames + return content, [], [] + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + stream = generate_config.get("stream", False) if generate_config else False + videoExisted = False + + content, images_chat, video_frames = self._message_content_to_chat(prompt) + if len(video_frames) > 0: + videoExisted = True + images_chat = video_frames + + msgs = [] + query_to_response: List[Dict] = [] + for h in chat_history or []: + images_history = [] + role = h["role"] + content_h, images_tmp, video_frames_h = self._message_content_to_chat( + h["content"] + ) + if images_tmp != []: + images_history = images_tmp + if len(video_frames_h) > 0: + videoExisted = True + images_history = video_frames_h + if len(query_to_response) == 0 and role == "user": + query_to_response.append( + {"role": "user", "content": images_history + [content_h]} + ) + if len(query_to_response) == 1 and role == "assistant": + query_to_response.append( + {"role": "assistant", "content": images_history + [content_h]} + ) + if len(query_to_response) == 2: + msgs.extend(query_to_response) + query_to_response = [] + msgs.append({"role": "user", "content": images_chat + [content]}) + + # Set decode params for video + params = {} + if videoExisted: + params = {"use_image_id": False, "max_slice_nums": 1} + + chat = self._model.chat( + image=None, + msgs=msgs, + tokenizer=self._tokenizer, + sampling=True, + **generate_config, + **params, + ) + if stream: + it = self.chat_stream(chat) + return self._to_chat_completion_chunks(it) + else: + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=chat, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return self._to_chat_completion(c) + + def chat_stream(self, chat) -> Iterator[CompletionChunk]: + completion_id = str(uuid.uuid1()) + for new_text in chat: + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=-1, + completion_tokens=-1, + total_tokens=-1, + ) + chunk["usage"] = completion_usage + yield chunk diff --git a/xinference/model/llm/pytorch/omnilmm.py b/xinference/model/llm/transformers/omnilmm.py similarity index 98% rename from xinference/model/llm/pytorch/omnilmm.py rename to xinference/model/llm/transformers/omnilmm.py index 64907fc2e1..583f3cc56e 100644 --- a/xinference/model/llm/pytorch/omnilmm.py +++ b/xinference/model/llm/transformers/omnilmm.py @@ -44,14 +44,14 @@ def __init__(self, *args, **kwargs): def match( cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str ) -> bool: - if "OmniLMM" in model_family.model_name: + llm_family = model_family.model_family or model_family.model_name + if "OmniLMM" in llm_family: return True return False def load(self): device = self._pytorch_model_config.get("device", "auto") device = select_device(device) - self._model = OmniLMMChat(self.model_path, device_map=device) def _message_content_to_OmniLMM( diff --git a/xinference/model/llm/transformers/qwen_vl.py b/xinference/model/llm/transformers/qwen_vl.py new file mode 100644 index 0000000000..8a2be562e3 --- /dev/null +++ b/xinference/model/llm/transformers/qwen_vl.py @@ -0,0 +1,408 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import base64 +import logging +import operator +import tempfile +import time +import typing +import uuid +from typing import Dict, Iterator, List, Optional, Tuple, Union + +import torch +from transformers import PreTrainedTokenizer + +from ....core.scheduler import InferenceRequest +from ....model.utils import select_device +from ....types import ( + ChatCompletion, + ChatCompletionChunk, + ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, +) +from ..llm_family import LLMFamilyV1, LLMSpecV1 +from .core import PytorchChatModel, PytorchGenerateConfig +from .utils import pad_prefill_tokens + +logger = logging.getLogger(__name__) + + +class QwenVLChatModel(PytorchChatModel): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._tokenizer = None + self._model = None + self._device = None + + @classmethod + def match( + cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str + ) -> bool: + llm_family = model_family.model_family or model_family.model_name + if "qwen" in llm_family and "vision" in model_family.model_ability: + return True + return False + + def load(self): + from transformers import AutoModelForCausalLM, AutoTokenizer + from transformers.generation import GenerationConfig + + if self._check_tensorizer_integrity(): + self._model, self._tokenizer = self._load_tensorizer( + code_revision=self.model_spec.model_revision + ) + self._apply_lora() + return + + device = self._pytorch_model_config.get("device", "auto") + device = select_device(device) + self._device = device + # for multiple GPU, set back to auto to make multiple devices work + device = "auto" if device == "cuda" else device + + self._tokenizer = AutoTokenizer.from_pretrained( + self.model_path, + trust_remote_code=True, + code_revision=self.model_spec.model_revision, + ) + self._model = AutoModelForCausalLM.from_pretrained( + self.model_path, + device_map=device, + trust_remote_code=True, + code_revision=self.model_spec.model_revision, + ).eval() + + # Specify hyperparameters for generation + self._model.generation_config = GenerationConfig.from_pretrained( + self.model_path, + trust_remote_code=True, + code_revision=self.model_spec.model_revision, + ) + self._apply_lora() + self._save_tensorizer(code_revision=self.model_spec.model_revision) + + def _message_content_to_qwen(self, content) -> str: + def _ensure_url(_url): + if _url.startswith("data:"): + logging.info("Parse url by base64 decoder.") + # https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images + # e.g. f"data:image/jpeg;base64,{base64_image}" + _type, data = _url.split(";") + _, ext = _type.split("/") + data = data[len("base64,") :] + data = base64.b64decode(data.encode("utf-8")) + + with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as f: + f.write(data) + logging.info("Dump base64 data to %s", f.name) + return f.name + else: + if len(_url) > 2048: + raise Exception(f"Image url is too long, {len(_url)} > 2048.") + return _url + + if not isinstance(content, str): + # TODO(codingl2k1): Optimize _ensure_url + content = [ + ( + {"image": _ensure_url(c["image_url"]["url"]), "type": "image"} + if c.get("type") == "image_url" + else c + ) + for c in content + ] + content = sorted(content, key=operator.itemgetter("type")) + return self._tokenizer.from_list_format(content) + return content + + def _get_prompt_and_chat_history( + self, + prompt: Union[str, List[Dict]], + chat_history: Optional[List[ChatCompletionMessage]] = None, + ): + prompt = self._message_content_to_qwen(prompt) + # Convert openai history to qwen vl history + qwen_history = [] + query_to_response: List = [] + for h in chat_history or []: + role = h["role"] + content = self._message_content_to_qwen(h["content"]) + if len(query_to_response) == 0 and role == "user": + query_to_response.append(content) + if len(query_to_response) == 1 and role == "assistant": + query_to_response.append(content) + if len(query_to_response) == 2: + qwen_history.append(query_to_response) + query_to_response = [] + return prompt, qwen_history + + def chat( + self, + prompt: Union[str, List[Dict]], + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[PytorchGenerateConfig] = None, + ) -> Union[ChatCompletion, Iterator[ChatCompletionChunk]]: + prompt, qwen_history = self._get_prompt_and_chat_history( + prompt, chat_history=chat_history + ) + + stream = generate_config.get("stream", False) if generate_config else False + stream_options = ( + generate_config.pop("stream_options", None) if generate_config else None + ) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + if stream: + it = self._generate_stream(prompt, qwen_history, include_usage) # type: ignore + return self._to_chat_completion_chunks(it) + else: + c = self._generate(prompt, qwen_history) # type: ignore + return self._to_chat_completion(c) + + def _generate(self, prompt: str, qwen_history: List) -> Completion: + response, history = self._model.chat( + self._tokenizer, query=prompt, history=qwen_history + ) + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[ + CompletionChoice( + index=0, text=response, finish_reason="stop", logprobs=None + ) + ], + usage=CompletionUsage( + prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 + ), + ) + return c + + def _generate_stream( + self, prompt: str, qwen_history: List, include_usage + ) -> Iterator[CompletionChunk]: + # response, history = model.chat(tokenizer, message, history=history) + response_generator = self._model.chat_stream( + self._tokenizer, query=prompt, history=qwen_history + ) + completion_id = str(uuid.uuid1()) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + input_ids = self._tokenizer(prompt, allowed_special="all").input_ids + prompt_tokens = len(input_ids) + full_response = "" + for response in response_generator: + inc_content = response[len(full_response) :] + full_response = response + completion_choice = CompletionChoice( + text=inc_content, index=0, logprobs=None, finish_reason=None + ) + completion_chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_tokens = completion_tokens + 1 + total_tokens = prompt_tokens + completion_tokens + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + completion_chunk["usage"] = completion_usage + yield completion_chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + completion_chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + completion_chunk["usage"] = completion_usage + yield completion_chunk + if include_usage: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk + + @staticmethod + def get_batch_size_and_seq_len_indexes_from_kv() -> Tuple[int, int]: + """ + Qwen-vl is very special for its kv_cache impl. + Its dimension is `bs * seq_len * head_num * dim`. + See https://huggingface.co/Qwen/Qwen-VL-Chat/blob/main/modeling_qwen.py + """ + return 0, 1 + + @staticmethod + @typing.no_type_check + def make_context( + tokenizer: PreTrainedTokenizer, + query: str, + history: List[Tuple[str, str]] = None, + system: str = "", + max_window_size: int = 6144, + chat_format: str = "chatml", + ): + """ + This function is from https://huggingface.co/Qwen/Qwen-VL-Chat/blob/main/qwen_generation_utils.py. + Use this function to get input_ids with image. + """ + if history is None: + history = [] + + if chat_format == "chatml": + im_start, im_end = "<|im_start|>", "<|im_end|>" + im_start_tokens = [tokenizer.im_start_id] + im_end_tokens = [tokenizer.im_end_id] + nl_tokens = tokenizer.encode("\n") + + def _tokenize_str(role, content): + return f"{role}\n{content}", tokenizer.encode( + role, allowed_special=set(tokenizer.IMAGE_ST) + ) + nl_tokens + tokenizer.encode( + content, allowed_special=set(tokenizer.IMAGE_ST) + ) + + system_text, system_tokens_part = _tokenize_str("system", system) + system_tokens = im_start_tokens + system_tokens_part + im_end_tokens + + raw_text = "" + context_tokens = [] + + for turn_query, turn_response in reversed(history): + query_text, query_tokens_part = _tokenize_str("user", turn_query) + query_tokens = im_start_tokens + query_tokens_part + im_end_tokens + if turn_response is not None: + response_text, response_tokens_part = _tokenize_str( + "assistant", turn_response + ) + response_tokens = ( + im_start_tokens + response_tokens_part + im_end_tokens + ) + + next_context_tokens = ( + nl_tokens + query_tokens + nl_tokens + response_tokens + ) + prev_chat = f"\n{im_start}{query_text}{im_end}\n{im_start}{response_text}{im_end}" + else: + next_context_tokens = nl_tokens + query_tokens + nl_tokens + prev_chat = f"\n{im_start}{query_text}{im_end}\n" + + current_context_size = ( + len(system_tokens) + len(next_context_tokens) + len(context_tokens) + ) + if current_context_size < max_window_size: + context_tokens = next_context_tokens + context_tokens + raw_text = prev_chat + raw_text + else: + break + + context_tokens = system_tokens + context_tokens + raw_text = f"{im_start}{system_text}{im_end}" + raw_text + context_tokens += ( + nl_tokens + + im_start_tokens + + _tokenize_str("user", query)[1] + + im_end_tokens + + nl_tokens + + im_start_tokens + + tokenizer.encode("assistant") + + nl_tokens + ) + raw_text += f"\n{im_start}user\n{query}{im_end}\n{im_start}assistant\n" + + elif chat_format == "raw": + raw_text = query + context_tokens = tokenizer.encode(raw_text) + else: + raise NotImplementedError(f"Unknown chat format {chat_format!r}") + + return raw_text, context_tokens + + def _get_full_prompt(self, prompt, system_prompt, chat_history, tools): + prompt, qwen_history = self._get_prompt_and_chat_history( + prompt, chat_history=chat_history + ) + _, context_tokens = self.make_context(self._tokenizer, prompt, qwen_history) + return context_tokens + + def prepare_sanitize_generate_config(self, req: InferenceRequest): + """ + Refer to https://huggingface.co/Qwen/Qwen-VL-Chat/blob/main/generation_config.json + """ + raw_config = req.inference_kwargs.get("raw_params", {}) + top_p = raw_config.get("top_p", None) + if top_p is None: + raw_config["top_p"] = 0.3 + top_k = raw_config.get("top_k", None) + if top_k is None: + raw_config["top_k"] = 0 + return raw_config + + def build_prefill_inputs(self, prompts: List, req_list: List[InferenceRequest]): + context_len = self.get_context_len() + inputs = pad_prefill_tokens(prompts, context_len, req_list) + input_ids = torch.as_tensor( + pad_prefill_tokens(inputs, context_len, req_list), device=self._device + ) + return input_ids + + def build_prefill_position_ids( + self, batch_size: int, seq_length: int, reqs: List[InferenceRequest] + ): + """ + Qwen-vl fill `1` for position_ids padding + """ + res = [] + for r in reqs: + real_seq_len = seq_length - r.padding_len + res.append( + torch.cat( + [ + torch.full((r.padding_len,), 1, dtype=torch.long), + torch.arange(0, real_seq_len, dtype=torch.long), + ] + ) + ) + r.extra_kwargs["max_position_id"] = real_seq_len - 1 + return torch.stack(res).to(self._device) diff --git a/xinference/model/llm/transformers/tensorizer_utils.py b/xinference/model/llm/transformers/tensorizer_utils.py new file mode 100644 index 0000000000..a3c322db7c --- /dev/null +++ b/xinference/model/llm/transformers/tensorizer_utils.py @@ -0,0 +1,342 @@ +# Copyright 2022-2024 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import io +import logging +import os +import tempfile +import zipfile +from functools import partial +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple + +from ....constants import XINFERENCE_TENSORIZER_DIR +from ....device_utils import get_available_device + +logger = logging.getLogger(__name__) + +__all__ = [ + "get_tensorizer_dir", + "check_tensorizer_integrity", + "load_from_tensorizer", + "save_to_tensorizer", + "_load_pretrained_from_tensorizer", + "_load_model_from_tensorizer", + "_tensorizer_serialize_model", + "_tensorizer_serialize_pretrained", + "_file_is_non_empty", +] + + +def _filter_kwargs(kwargs): + kwargs["trust_remote_code"] = kwargs.get("trust_remote_code", True) + return { + k: v for k, v in kwargs.items() if k in ["code_revision", "trust_remote_code"] + } + + +def _file_is_non_empty( + path: str, +) -> bool: + try: + return os.stat(path).st_size > 0 + except FileNotFoundError: + return False + + +def get_tensorizer_dir(model_path: str) -> str: + model_dir = os.path.basename(model_path.rstrip("/")) + return f"{XINFERENCE_TENSORIZER_DIR}/{model_dir}" + + +def check_tensorizer_integrity( + model_path: str, + components: Optional[List[str]] = None, + model_prefix: Optional[str] = "model", +) -> bool: + tensorizer_dir = get_tensorizer_dir(model_path) + dir = tensorizer_dir.rstrip("/") + tensors_uri: str = f"{dir}/{model_prefix}.tensors" + # iterate over components and get their paths + paths = [tensors_uri] + if components is not None: + for component in components: + component_uri: str = f"{tensorizer_dir.rstrip('/')}/{component}.zip" + paths.append(component_uri) + return all(_file_is_non_empty(path) for path in paths) + + +def load_from_tensorizer( + model_path: str, + components: Optional[List[Tuple[str, Any, Dict[str, Any]]]] = None, + model_class: Any = None, + config_class: Any = None, + model_prefix: Optional[str] = "model", + **kwargs, +): + kwargs = _filter_kwargs(kwargs) + try: + from transformers import AutoConfig, AutoModel + except ImportError: + error_message = "Failed to import module 'transformers'" + installation_guide = [ + "Please make sure 'transformers' is installed. ", + "You can install it by `pip install transformers`\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + model_class = model_class or AutoModel + config_class = config_class or AutoConfig + + tensorizer_dir = get_tensorizer_dir(model_path) + logger.debug(f"Loading from tensorizer: {tensorizer_dir}") + + device = get_available_device() + tensorizer_model = ( + _load_model_from_tensorizer( + model_path, + tensorizer_dir, + model_class, + config_class, + model_prefix, + device, + **kwargs, + ) + .to(device) + .eval() + ) + + tensorizer_components = [] + + if components is not None: + for component, component_class, kwargs in components: + deserialized_component = _load_pretrained_from_tensorizer( + component_class, tensorizer_dir, component, **kwargs + ) + tensorizer_components.append(deserialized_component) + + return tensorizer_model, *tensorizer_components + + +def _load_pretrained_from_tensorizer( + component_class: Any, + tensorizer_dir: str, + prefix: str, + **kwargs, +): + logger.debug(f"Loading components from tensorizer: {component_class} {kwargs}") + + try: + from tensorizer import stream_io + except ImportError: + error_message = "Failed to import module 'tensorizer'" + installation_guide = [ + "Please make sure 'tensorizer' is installed.\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + _read_stream = partial(stream_io.open_stream, mode="rb") + + logger.debug(f"Loading pretrained from tensorizer: {tensorizer_dir}") + load_path: str = f"{tensorizer_dir.rstrip('/')}/{prefix}.zip" + logger.info(f"Loading {load_path}") + with io.BytesIO() as downloaded: + # Download to a BytesIO object first, because ZipFile doesn't play nice + # with streams that don't fully support random access + with _read_stream(load_path) as stream: + downloaded.write(stream.read()) + downloaded.seek(0) + with zipfile.ZipFile( + downloaded, mode="r" + ) as file, tempfile.TemporaryDirectory() as directory: + file.extractall(path=directory) + return component_class.from_pretrained( + directory, cache_dir=None, local_files_only=True, **kwargs + ) + + +def _load_model_from_tensorizer( + model_path: str, + tensorizer_dir: str, + model_class, + config_class, + model_prefix: Optional[str] = "model", + device=None, + dtype=None, + **kwargs, +): + logger.debug(f"Loading model from tensorizer: {tensorizer_dir} {kwargs}") + + # assert device is not None + if device is None: + raise ValueError("device must be specified") + + import time + + try: + import torch + except ImportError: + error_message = "Failed to import module 'torch'" + installation_guide = [ + "Please make sure 'torch' is installed.\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + try: + from transformers import PretrainedConfig + except ImportError: + error_message = "Failed to import module 'transformers'" + installation_guide = [ + "Please make sure 'transformers' is installed. ", + "You can install it by `pip install transformers`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + try: + from tensorizer import TensorDeserializer, stream_io, utils + except ImportError: + error_message = "Failed to import module 'tensorizer'" + installation_guide = [ + "Please make sure 'tensorizer' is installed.\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + if model_prefix is None: + model_prefix = "model" + + dir: str = tensorizer_dir.rstrip("/") + tensors_uri: str = f"{dir}/{model_prefix}.tensors" + + _read_stream = partial(stream_io.open_stream, mode="rb") + + if config_class is None: + config_loader = model_class.load_config + else: + config_loader = config_class.from_pretrained + try: + config, _ = config_loader(model_path, return_unused_kwargs=True, **kwargs) + if isinstance(config, PretrainedConfig): + config.gradient_checkpointing = True + except ValueError: + config = config_loader(model_path, **kwargs) + + with utils.no_init_or_tensor(): + model_loader = getattr(model_class, "from_config", model_class) + model = model_loader(config, **kwargs) + + is_cuda: bool = torch.device(device).type == "cuda" + ram_usage = utils.get_mem_usage() + logger.info(f"Loading {tensors_uri}, {ram_usage}") + begin_load = time.perf_counter() + + with _read_stream(tensors_uri) as tensor_stream, TensorDeserializer( + tensor_stream, device=device, dtype=dtype, plaid_mode=is_cuda + ) as tensor_deserializer: + tensor_deserializer.load_into_module(model) + tensor_load_s = time.perf_counter() - begin_load + bytes_read: int = tensor_deserializer.total_bytes_read + + rate_str = utils.convert_bytes(bytes_read / tensor_load_s) + tensors_sz = utils.convert_bytes(bytes_read) + logger.info( + f"Model tensors loaded in {tensor_load_s:0.2f}s, read " + f"{tensors_sz} @ {rate_str}/s, {utils.get_mem_usage()}" + ) + + return model + + +def save_to_tensorizer( + model_path: str, + model, + components: Optional[List[Tuple[str, Any]]] = None, + model_prefix: Optional[str] = "model", + force: Optional[bool] = False, + **kwargs, +): + kwargs = _filter_kwargs(kwargs) + _tensorizer_serialize_model(model_path, model, model_prefix, force, **kwargs) + + if components is not None: + for component_prefix, component in components: + _tensorizer_serialize_pretrained(model_path, component, component_prefix) + + +def _tensorizer_serialize_model( + model_path: str, + model, + model_prefix: Optional[str] = "model", + force: Optional[bool] = False, + **kwargs, +): + try: + from tensorizer import TensorSerializer, stream_io + except ImportError: + error_message = "Failed to import module 'tensorizer'" + installation_guide = [ + "Please make sure 'tensorizer' is installed.\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + tensorizer_dir = get_tensorizer_dir(model_path) + tensor_path: str = f"{tensorizer_dir}/{model_prefix}.tensors" + + _write_stream = partial(stream_io.open_stream, mode="wb+") + + if os.path.exists(tensor_path): + logger.info(f"Cache {tensor_path} exists, skip tensorizer serialize model") + return + + logger.info(f"Writing tensors to {tensor_path}") + with _write_stream(tensor_path) as f: + serializer = TensorSerializer(f) + serializer.write_module(model, include_non_persistent_buffers=False) + serializer.close() + + logger.info(f"Tensorizer serialize model done: {tensor_path}") + + +def _tensorizer_serialize_pretrained( + model_path: str, component, prefix: str = "pretrained" +): + try: + from tensorizer import stream_io + except ImportError: + error_message = "Failed to import module 'tensorizer'" + installation_guide = [ + "Please make sure 'tensorizer' is installed.\n", + ] + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + + tensorizer_dir = get_tensorizer_dir(model_path) + save_path: str = f"{tensorizer_dir.rstrip('/')}/{prefix}.zip" + + if os.path.exists(save_path): + logger.info(f"Cache {save_path} exists, skip tensorizer serialize pretrained") + return + + logger.info(f"Writing component to {save_path}") + _write_stream = partial(stream_io.open_stream, mode="wb+") + + with _write_stream(save_path) as stream, zipfile.ZipFile( + stream, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=5 + ) as file, tempfile.TemporaryDirectory() as directory: + if hasattr(component, "save_pretrained"): + component.save_pretrained(directory) + else: + logger.warning("The component does not have a 'save_pretrained' method.") + for path in Path(directory).iterdir(): + file.write(filename=path, arcname=path.name) + + logger.info(f"Tensorizer serialize pretrained done: {save_path}") diff --git a/xinference/model/llm/ggml/tools/__init__.py b/xinference/model/llm/transformers/tests/__init__.py similarity index 93% rename from xinference/model/llm/ggml/tools/__init__.py rename to xinference/model/llm/transformers/tests/__init__.py index e32bd7fbe7..37f6558d95 100644 --- a/xinference/model/llm/ggml/tools/__init__.py +++ b/xinference/model/llm/transformers/tests/__init__.py @@ -11,5 +11,3 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -from .convert_ggml_to_gguf import convert diff --git a/xinference/model/llm/pytorch/tests/test_opt.py b/xinference/model/llm/transformers/tests/test_opt.py similarity index 90% rename from xinference/model/llm/pytorch/tests/test_opt.py rename to xinference/model/llm/transformers/tests/test_opt.py index 13a0f9975e..d7dd30a512 100644 --- a/xinference/model/llm/pytorch/tests/test_opt.py +++ b/xinference/model/llm/transformers/tests/test_opt.py @@ -17,7 +17,6 @@ import threading import time from concurrent.futures import ThreadPoolExecutor -from pathlib import Path from typing import Union import pytest @@ -49,6 +48,8 @@ class MockPytorchModel(MockNonPytorchModel, PytorchModel): @pytest.mark.asyncio @pytest.mark.parametrize("quantization", ["none"]) async def test_opt_pytorch_model(setup, quantization): + from .....constants import XINFERENCE_CACHE_DIR + endpoint, _ = setup client = Client(endpoint) assert len(client.list_models()) == 0 @@ -57,6 +58,7 @@ async def test_opt_pytorch_model(setup, quantization): with pytest.raises(ValueError): client.launch_model( model_name="opt", + model_engine="transformers", model_size_in_billions=1, model_format="pytorch", quantization=quantization, @@ -65,6 +67,7 @@ async def test_opt_pytorch_model(setup, quantization): else: model_uid = client.launch_model( model_name="opt", + model_engine="transformers", model_size_in_billions=1, model_format="pytorch", quantization=quantization, @@ -95,14 +98,13 @@ def _check(): assert len(client.list_models()) == 0 # check for cached revision - home_address = str(Path.home()) - snapshot_address = ( - home_address - + "/.cache/huggingface/hub/models--facebook--opt-125m/snapshots" + valid_file = os.path.join( + XINFERENCE_CACHE_DIR, "opt-pytorch-1b", "__valid_download" ) - actual_revision = os.listdir(snapshot_address) + with open(valid_file, "r") as f: + actual_revision = json.load(f)["revision"] model_name = "opt" - expected_revision: Union[str, None] = "" + expected_revision: Union[str, None] = "" # type: ignore for family in BUILTIN_LLM_FAMILIES: if model_name != family.model_name: @@ -110,7 +112,7 @@ def _check(): for spec in family.model_specs: expected_revision = spec.model_revision - assert [expected_revision] == actual_revision + assert expected_revision == actual_revision @pytest.mark.asyncio diff --git a/xinference/model/llm/transformers/tests/test_tensorizer.py b/xinference/model/llm/transformers/tests/test_tensorizer.py new file mode 100644 index 0000000000..a4e228259c --- /dev/null +++ b/xinference/model/llm/transformers/tests/test_tensorizer.py @@ -0,0 +1,116 @@ +import os +import shutil +from unittest.mock import MagicMock, patch + +import pytest +from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer + +from .....constants import XINFERENCE_CACHE_DIR +from ...llm_family import LLMFamilyV1, PytorchLLMSpecV1, cache +from ..tensorizer_utils import ( + _tensorizer_serialize_model, + get_tensorizer_dir, + save_to_tensorizer, +) + + +# case1: test if tensorizer_serialize_model and .tensor file exists in the correct path +class TestTensorizerSerializeModel: + @pytest.fixture(autouse=True) + def setup_and_teardown(self): + # Setup: Load the model and tokenizer + model_full_name = "qwen1.5-chat-pytorch-0_5b" + self.model_path = f"{XINFERENCE_CACHE_DIR}/{model_full_name.replace('.', '_')}" + self.tensorizer_dir = get_tensorizer_dir(self.model_path) + spec = PytorchLLMSpecV1( + model_format="pytorch", + model_size_in_billions="0_5", + quantizations=["4-bit", "8-bit", "none"], + model_id="Qwen/Qwen1.5-0.5B-Chat", + model_revision=None, + ) + family = LLMFamilyV1( + version=1, + context_length=32768, + model_type="LLM", + model_name="qwen1.5-chat", + model_lang=["en", "zh"], + model_ability=["chat", "tools"], + model_specs=[spec], + prompt_style=None, + ) + + if not os.path.exists(self.model_path): + cache(llm_family=family, llm_spec=spec, quantization=None) + + self.model_config = AutoConfig.from_pretrained(self.model_path) + self.tokenizer = AutoTokenizer.from_pretrained(self.model_path, use_fast=True) + self.model = AutoModelForCausalLM.from_pretrained( + self.model_path, + low_cpu_mem_usage=True, + ) + self.model_prefix = "model" + self.force = True + yield + + # Cleanup: Remove the entire directories after the test + self._cleanup_directory(self.tensorizer_dir) + + def _cleanup_directory(self, directory): + if os.path.exists(directory): + shutil.rmtree(directory) + + # Test if model.tensor & tokenizer.zip files generated + def test_tensor_file_exists(self): + expected_tensor_file = f"{self.tensorizer_dir}/{self.model_prefix}.tensors" + expected_tokenizer_file = f"{self.tensorizer_dir}/tokenizer.zip" + + if os.path.exists(expected_tensor_file): + os.remove(expected_tensor_file) + + if os.path.exists(expected_tokenizer_file): + os.remove(expected_tokenizer_file) + + save_to_tensorizer( + self.model_path, + self.model, + [("tokenizer", self.tokenizer)], + ) + + assert os.path.exists( + expected_tensor_file + ), f"{expected_tensor_file} does not exist" + + assert os.path.exists( + expected_tokenizer_file + ), f"{expected_tokenizer_file} does not exist" + + +@pytest.fixture +def mock_environment(tmp_path): + model_path = str(tmp_path / "model") + tensorizer_dir = str(tmp_path / "tensorizer") + os.makedirs(tensorizer_dir, exist_ok=True) + tensor_path = f"{tensorizer_dir}/model.tensors" + # Create a dummy cache file to simulate cache existence + with open(tensor_path, "w") as f: + f.write("dummy content") + return model_path, tensorizer_dir, tensor_path + + +@patch("xinference.model.llm.transformers.tensorizer_utils.get_tensorizer_dir") +@patch("xinference.model.llm.transformers.tensorizer_utils.logger") +def test_tensorizer_serialize_model_cache_exists( + mock_logger, mock_get_tensorizer_dir, mock_environment +): + model_path, tensorizer_dir, tensor_path = mock_environment + mock_get_tensorizer_dir.return_value = tensorizer_dir + model = MagicMock() + + # Call the function with the mocked environment + _tensorizer_serialize_model(model_path, model) + + # Check if the logger.info was called with the expected message, indicating early return due to cache existence + mock_logger.info.assert_called_with( + f"Cache {tensor_path} exists, skip tensorizer serialize model" + ) diff --git a/xinference/model/llm/transformers/utils.py b/xinference/model/llm/transformers/utils.py new file mode 100644 index 0000000000..5ada9a512c --- /dev/null +++ b/xinference/model/llm/transformers/utils.py @@ -0,0 +1,784 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gc +import logging +import os +import time +import uuid +from typing import TYPE_CHECKING, Dict, Iterable, Iterator, List, Optional, Tuple + +import torch +from transformers.cache_utils import DynamicCache +from transformers.generation.logits_process import ( + LogitsProcessorList, + RepetitionPenaltyLogitsProcessor, + TemperatureLogitsWarper, + TopKLogitsWarper, + TopPLogitsWarper, +) + +from ....core.scheduler import InferenceRequest +from ....device_utils import empty_cache +from ....types import ( + Completion, + CompletionChoice, + CompletionChunk, + CompletionUsage, + max_tokens_field, +) + +if TYPE_CHECKING: + from ...llm.transformers.core import PytorchModel + +logger = logging.getLogger(__name__) + + +def is_sentence_complete(output: str): + """Check whether the output is a complete sentence.""" + end_symbols = (".", "?", "!", "...", "。", "?", "!", "…", '"', "'", "”") + return output.endswith(end_symbols) + + +def is_partial_stop(output: str, stop_str: str): + """Check whether the output contains a partial stop str.""" + for i in range(0, min(len(output), len(stop_str))): + if stop_str.startswith(output[-i:]): + return True + return False + + +def get_context_length(config) -> int: + """Get the context length of a model from a huggingface model config.""" + if ( + hasattr(config, "max_sequence_length") + and config.max_sequence_length is not None + ): + max_sequence_length = config.max_sequence_length + else: + max_sequence_length = 2048 + if hasattr(config, "seq_length") and config.seq_length is not None: + seq_length = config.seq_length + else: + seq_length = 2048 + if ( + hasattr(config, "max_position_embeddings") + and config.max_position_embeddings is not None + ): + max_position_embeddings = config.max_position_embeddings + else: + max_position_embeddings = 2048 + return max(max_sequence_length, seq_length, max_position_embeddings) + + +def prepare_logits_processor( + temperature: float, repetition_penalty: float, top_p: float, top_k: int +) -> LogitsProcessorList: + processor_list = LogitsProcessorList() + # TemperatureLogitsWarper doesn't accept 0.0, 1.0 makes it a no-op so we skip two cases. + if temperature >= 1e-5 and temperature != 1.0: + processor_list.append(TemperatureLogitsWarper(temperature)) + if repetition_penalty > 1.0: + processor_list.append(RepetitionPenaltyLogitsProcessor(repetition_penalty)) + if 1e-8 <= top_p < 1.0: + processor_list.append(TopPLogitsWarper(top_p)) + if top_k > 0: + processor_list.append(TopKLogitsWarper(top_k)) + return processor_list + + +@torch.inference_mode() +def generate_stream( + model_uid, + model, + tokenizer, + prompt, + device, + generate_config, + judge_sent_end=False, +) -> Iterator[Tuple[CompletionChunk, CompletionUsage]]: + context_len = get_context_length(model.config) + stream_interval = generate_config.get("stream_interval", 2) + stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] if isinstance(stream_options, dict) else False + ) + + len_prompt = len(prompt) + + temperature = float(generate_config.get("temperature", 1.0)) + repetition_penalty = float(generate_config.get("repetition_penalty", 1.0)) + top_p = float(generate_config.get("top_p", 1.0)) + top_k = int(generate_config.get("top_k", -1)) # -1 means disable + max_new_tokens = int(generate_config.get("max_tokens", max_tokens_field.default)) + echo = bool(generate_config.get("echo", False)) + stop_str = generate_config.get("stop", None) + stop_token_ids = generate_config.get("stop_token_ids", None) or [] + stop_token_ids.append(tokenizer.eos_token_id) + chunk_id = str(uuid.uuid4()) + + logits_processor = prepare_logits_processor( + temperature, repetition_penalty, top_p, top_k + ) + + if ".modeling_qwen." in str(type(model)).lower(): + # TODO: hacky + input_ids = tokenizer(prompt, allowed_special="all").input_ids + else: + input_ids = tokenizer(prompt).input_ids + output_ids = list(input_ids) + + if model.config.is_encoder_decoder: + max_src_len = context_len + else: + max_src_len = context_len - max_new_tokens - 8 + if max_src_len < 0: + raise ValueError("Max tokens exceeds model's max length") + + input_ids = input_ids[-max_src_len:] + input_echo_len = len(input_ids) + + if model.config.is_encoder_decoder: + encoder_output = model.encoder( + input_ids=torch.as_tensor([input_ids], device=device) + )[0] + start_ids = torch.as_tensor( + [[model.generation_config.decoder_start_token_id]], + dtype=torch.int64, + device=device, + ) + + start = time.time() + past_key_values = out = None + sent_interrupt = False + token = None + last_output_length = 0 + for i in range(max_new_tokens): + if i == 0: + if model.config.is_encoder_decoder: + out = model.decoder( + input_ids=start_ids, + encoder_hidden_states=encoder_output, + use_cache=True, + ) + logits = model.lm_head(out[0]) + else: + out = model(torch.as_tensor([input_ids], device=device), use_cache=True) + logits = out.logits + past_key_values = out.past_key_values + else: + if model.config.is_encoder_decoder: + out = model.decoder( + input_ids=torch.as_tensor( + [[token] if not sent_interrupt else output_ids], device=device + ), + encoder_hidden_states=encoder_output, + use_cache=True, + past_key_values=past_key_values if not sent_interrupt else None, + ) + sent_interrupt = False + + logits = model.lm_head(out[0]) + else: + out = model( + input_ids=torch.as_tensor( + [[token] if not sent_interrupt else output_ids], device=device + ), + use_cache=True, + past_key_values=past_key_values if not sent_interrupt else None, + ) + sent_interrupt = False + logits = out.logits + past_key_values = out.past_key_values + + if logits_processor: + if repetition_penalty > 1.0: + tmp_output_ids = torch.as_tensor([output_ids], device=logits.device) + else: + tmp_output_ids = None + last_token_logits = logits_processor(tmp_output_ids, logits[:, -1, :])[0] + else: + last_token_logits = logits[0, -1, :] + + if device == "mps": + # Switch to CPU by avoiding some bugs in mps backend. + last_token_logits = last_token_logits.float().to("cpu") + + if temperature < 1e-5 or top_p < 1e-8: # greedy + _, indices = torch.topk(last_token_logits, 2) + tokens = [int(index) for index in indices.tolist()] + else: + probs = torch.softmax(last_token_logits, dim=-1) + indices = torch.multinomial(probs, num_samples=2) + tokens = [int(token) for token in indices.tolist()] + token = tokens[0] + output_ids.append(token) + + if token in stop_token_ids: + stopped = True + else: + stopped = False + + if i % stream_interval == 0 or i == max_new_tokens - 1 or stopped: + if echo: + tmp_output_ids = output_ids + rfind_start = len_prompt + else: + tmp_output_ids = output_ids[input_echo_len:] + rfind_start = 0 + + output = tokenizer.decode( + tmp_output_ids, + skip_special_tokens=True, + spaces_between_special_tokens=False, + clean_up_tokenization_spaces=True, + ) + + # TODO: For the issue of incomplete sentences interrupting output, apply a patch and others can also modify it to a more elegant way + if judge_sent_end and stopped and not is_sentence_complete(output): + if len(tokens) > 1: + token = tokens[1] + output_ids[-1] = token + else: + output_ids.pop() + stopped = False + sent_interrupt = True + + partially_stopped = False + if stop_str: + if isinstance(stop_str, str): + pos = output.rfind(stop_str, rfind_start) + if pos != -1: + output = output[:pos] + stopped = True + else: + partially_stopped = is_partial_stop(output, stop_str) + elif isinstance(stop_str, Iterable): + for each_stop in stop_str: + pos = output.rfind(each_stop, rfind_start) + if pos != -1: + output = output[:pos] + stopped = True + break + else: + partially_stopped = is_partial_stop(output, each_stop) + if partially_stopped: + break + else: + raise ValueError("Invalid stop field type.") + + if stream: + output = output.strip("�") + tmp_output_length = len(output) + output = output[last_output_length:] + last_output_length = tmp_output_length + + # prevent yielding partial stop sequence + if not partially_stopped: + completion_choice = CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=None + ) + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + + yield completion_chunk, completion_usage + + if stopped: + break + + elapsed_time = time.time() - start + logger.info(f"Average generation speed: {i / elapsed_time:.2f} tokens/s.") + + # finish stream event, which contains finish reason + if stopped: + finish_reason = "stop" + elif i == max_new_tokens - 1: + finish_reason = "length" + else: + finish_reason = None + + if stream: + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason=finish_reason + ) + else: + completion_choice = CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=finish_reason + ) + + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + + yield completion_chunk, completion_usage + + if include_usage: + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[], + ) + completion_usage = CompletionUsage( + prompt_tokens=input_echo_len, + completion_tokens=i, + total_tokens=(input_echo_len + i), + ) + yield completion_chunk, completion_usage + + # clean + del past_key_values, out + gc.collect() + empty_cache() + + +def _get_token_from_logits( + req: InferenceRequest, i: int, logits, temperature, repetition_penalty, top_p, top_k +): + logits_processor = prepare_logits_processor( + temperature, repetition_penalty, top_p, top_k + ) + + if logits_processor: + if repetition_penalty > 1.0: + tmp_output_ids = torch.as_tensor( + [req.prompt_tokens + req.new_tokens], device=logits.device + ) + else: + tmp_output_ids = None + last_token_logits = logits_processor(tmp_output_ids, logits[i : i + 1, -1, :])[ + 0 + ] + else: + last_token_logits = logits[i : i + 1, -1, :] + + if temperature < 1e-5 or top_p < 1e-8: # greedy + _, indices = torch.topk(last_token_logits, 2) + else: + probs = torch.softmax(last_token_logits, dim=-1) + indices = torch.multinomial(probs, num_samples=2) + token = indices[0].int().item() + return token + + +def _pad_to_max_length(x: List[int], max_len: int, pad: int) -> List[int]: + assert len(x) <= max_len + return [pad] * (max_len - len(x)) + x + + +def _pad_seqs_inplace(seqs: List[List[int]], reqs: List[InferenceRequest], pad: int): + max_len = max(len(seq) for seq in seqs) + n = len(seqs) + i = 0 + while i < n: + prev_seq_len = len(seqs[i]) + seqs[i] = _pad_to_max_length(seqs[i], max_len, pad) + padding_len = len(seqs[i]) - prev_seq_len + reqs[i].padding_len = padding_len + i += 1 + + +def get_max_src_len(context_len: int, r: InferenceRequest) -> int: + max_new_tokens = int( + r.sanitized_generate_config.get("max_tokens", max_tokens_field.default) + ) + return context_len - max_new_tokens - 8 + + +def pad_prefill_tokens( + input_ids: List[List[int]], context_len: int, req_list: List[InferenceRequest] +): + prompt_tokens = [] + for i, input_id in enumerate(input_ids): + req = req_list[i] + max_src_len = get_max_src_len(context_len, req) + req.prompt_tokens = input_id[-max_src_len:] + prompt_tokens.append(req.prompt_tokens) + _pad_seqs_inplace(prompt_tokens, req_list, 0) + return prompt_tokens + + +def _get_completion_chunk( + output: str, + chunk_id: str, + finish_reason: Optional[str], + model_uid: str, + r: InferenceRequest, + just_usage: bool, +): + completion_choice = ( + [ + CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=finish_reason + ) + ] + if not just_usage + else [] + ) + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=completion_choice, + ) + completion_usage = CompletionUsage( + prompt_tokens=len(r.prompt_tokens), + completion_tokens=len(r.new_tokens), + total_tokens=len(r.prompt_tokens) + len(r.new_tokens), + ) + completion_chunk["usage"] = completion_usage + return completion_chunk + + +def _get_completion( + output: str, + chunk_id: str, + finish_reason: Optional[str], + model_uid: str, + r: InferenceRequest, +): + completion_choice = CompletionChoice( + text=output, index=0, logprobs=None, finish_reason=finish_reason + ) + + completion_chunk = CompletionChunk( + id=chunk_id, + object="text_completion", + created=int(time.time()), + model=model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=len(r.prompt_tokens), + completion_tokens=len(r.new_tokens), + total_tokens=len(r.prompt_tokens) + len(r.new_tokens), + ) + completion = Completion( + id=completion_chunk["id"], + object=completion_chunk["object"], + created=completion_chunk["created"], + model=completion_chunk["model"], + choices=completion_chunk["choices"], + usage=completion_usage, + ) + return completion + + +def _get_pad_param(seq_len_idx: int, pad_len: int) -> Tuple: + dimensions = [0] * 8 + dimensions[-2 * (seq_len_idx + 1)] = pad_len + return tuple(dimensions) + + +def _merge_kv_cache( + xinf_model_obj: "PytorchModel", + past_kv: Tuple[Tuple[torch.Tensor]], + new_kv: Tuple[Tuple[torch.Tensor]], +): + from torch.nn.functional import pad + + _, seq_len_idx = xinf_model_obj.get_batch_size_and_seq_len_indexes_from_kv() + past_cache = DynamicCache.from_legacy_cache(past_kv) + new_cache = DynamicCache.from_legacy_cache(new_kv) + past_seq_len = past_kv[0][0].shape[seq_len_idx] + new_seq_len = new_kv[0][0].shape[seq_len_idx] + if past_seq_len != new_seq_len: + padding_target = new_cache if past_seq_len > new_seq_len else past_cache + padding_len = abs(past_seq_len - new_seq_len) + pad_param = _get_pad_param(seq_len_idx, padding_len) + for idx in range(len(padding_target)): + k = padding_target.key_cache[idx] + v = padding_target.value_cache[idx] + _k = pad(k, pad_param) + _v = pad(v, pad_param) + padding_target.key_cache[idx] = _k + padding_target.value_cache[idx] = _v + + ret_kv = DynamicCache() + for idx in range(len(past_cache)): + k1, k2 = new_cache.key_cache[idx], past_cache.key_cache[idx] + v1, v2 = new_cache.value_cache[idx], past_cache.value_cache[idx] + ret_kv.update(torch.cat((k1, k2), 0), torch.cat((v1, v2), 0), idx) + return ret_kv.to_legacy_cache() + + +def get_batch_size_and_seq_len_from_kv_cache(kv, xinf_model_obj: "PytorchModel"): + bs_idx, seq_len_idx = xinf_model_obj.get_batch_size_and_seq_len_indexes_from_kv() + return kv[0][0].shape[bs_idx], kv[0][0].shape[seq_len_idx] + 1 + + +@torch.inference_mode() +def _batch_inference_one_step_internal( + xinf_model_obj: "PytorchModel", + req_list: List[InferenceRequest], + model_uid, + model, + tokenizer, + decode_round: int = 16, + bos_flag: str = "", + eos_flag: str = "", +): + # need to judge stopped here, + # since some requests state may change to stopped due to invalid parameters, e.g. max_src_len + valid_req_list = [r for r in req_list if not r.stopped] + if not valid_req_list: + return + generate_config_mapping: Dict[InferenceRequest, Tuple] = { + r: r.get_generate_configs( + tokenizer.eos_token_id, xinf_model_obj.get_builtin_stop_token_ids() + ) + for r in valid_req_list + } + s_time = time.time() + + prefill_reqs = [] + prompts = [] + decode_reqs = [] + for r in valid_req_list: + if r.is_prefill: + prompts.append(r.full_prompt if r.full_prompt is not None else r.prompt) + prefill_reqs.append(r) + else: + decode_reqs.append(r) + + if prompts: # prefill first + prefill_kws = xinf_model_obj.build_prefill_kwargs(prompts, prefill_reqs) + out = model(**prefill_kws, use_cache=True) + + logits = out.logits + past_key_values = out.past_key_values + + for i, r in enumerate(prefill_reqs): + ( + max_new_tokens, + stream_interval, + include_usage, + stop_str, + stop_token_ids, + temperature, + repetition_penalty, + top_p, + top_k, + ) = generate_config_mapping[r] + + token = _get_token_from_logits( + r, i, logits, temperature, repetition_penalty, top_p, top_k + ) + r.is_prefill = False + r.append_new_token(token) + + if decode_reqs: + decode_kv = decode_reqs[0].kv_cache + # prefill and decode kv cache need to be merged at `batch_size` and `seq_len` dimensions. + merged_kv_cache = _merge_kv_cache( + xinf_model_obj, decode_kv, past_key_values + ) + for r in valid_req_list: + r.kv_cache = merged_kv_cache + empty_cache() + else: + for r in valid_req_list: + r.kv_cache = past_key_values + + past_key_values = valid_req_list[0].kv_cache + stop_token_mapping: Dict[InferenceRequest, int] = {} + output_mapping: Dict[InferenceRequest, str] = {} + # here, only decode phase, just run some rounds + for _i in range(decode_round): + batch_size, seq_len = get_batch_size_and_seq_len_from_kv_cache( + past_key_values, xinf_model_obj + ) + decode_tokens: List[List[int]] = [[r.new_tokens[-1]] for r in valid_req_list] + inf_kws = xinf_model_obj.build_decode_kwargs( + decode_tokens, valid_req_list, batch_size, seq_len + ) + out = model(**inf_kws, use_cache=True, past_key_values=past_key_values) + logits = out.logits + past_key_values = out.past_key_values + + for i, r in enumerate(valid_req_list): + ( + max_new_tokens, + stream_interval, + include_usage, + stop_str, + stop_token_ids, + temperature, + repetition_penalty, + top_p, + top_k, + ) = generate_config_mapping[r] + + token = _get_token_from_logits( + r, i, logits, temperature, repetition_penalty, top_p, top_k + ) + r.kv_cache = past_key_values + r.append_new_token(token) + + output = None + if not r.stopped: + stopped = token in stop_token_ids + + if stopped: + finish_reason = "stop" + elif len(r.new_tokens) == max_new_tokens: + finish_reason = "length" + stopped = True + else: + finish_reason = None + + # handle stop str + if stop_str and r not in output_mapping: + output = tokenizer.decode( + r.new_tokens, + skip_special_tokens=True, + spaces_between_special_tokens=False, + clean_up_tokenization_spaces=True, + ) + if isinstance(stop_str, str): + stop_str = [stop_str] + for stop in stop_str: + pos = output.rfind(stop) + if pos != -1: + output = output[:pos] + output_mapping[r] = output + stopped = True + finish_reason = "stop" + break + + r.stopped = stopped + r.finish_reason = finish_reason + + if r.stopped and r not in stop_token_mapping and r not in output_mapping: + stop_token_mapping[r] = _i + 1 + + if r.stream: + """ + Note that you can't just decode based on the newest r.new_tokens here, + which may destroy the integrity of the parsed characters, + and at the same time is not good at handling some special characters. + So the implementation here is to decode all the tokens that have been generated each time, + and then take the slice. + """ + if r.stopped or len(r.new_tokens) % stream_interval == 0: + if output is None: + output = tokenizer.decode( + r.new_tokens, + skip_special_tokens=True, + spaces_between_special_tokens=False, + clean_up_tokenization_spaces=True, + ) + + if r.last_output_length == 0: + r.completion.append(bos_flag) + + # this special character is mainly for qwen + output = output.strip("�") + output = output[r.last_output_length :] + r.last_output_length += len(output) + + completion_chunk = _get_completion_chunk( + output, r.chunk_id, r.finish_reason, model_uid, r, False + ) + r.completion.append(completion_chunk) + if r.stopped: + r.completion.append(eos_flag) + + # last round, handle stream result + # append usage information when enable `include_usage` for OPENAI API compatibility + # The reason for counting the usage in the last round of the iteration is that, + # these tokens are real generated and should be counted. + if r.stopped and _i == decode_round - 1 and include_usage: + r.completion.append( + _get_completion_chunk( + "", r.chunk_id, r.finish_reason, model_uid, r, True + ) + ) + else: + # last round, handle non-stream result + if r.stopped and _i == decode_round - 1: + invalid_token_num = decode_round - stop_token_mapping[r] + outputs = ( + tokenizer.decode( + r.new_tokens[: -(invalid_token_num + 1)] + if r.finish_reason == "stop" + else r.new_tokens[:-invalid_token_num], + skip_special_tokens=True, + spaces_between_special_tokens=False, + clean_up_tokenization_spaces=True, + ) + if r not in output_mapping + else output_mapping[r] + ) + completion = _get_completion( + outputs, r.chunk_id, r.finish_reason, model_uid, r + ) + r.completion = [completion] + + e_time = time.time() + logger.debug( + f"Average throughput for a step: {(len(valid_req_list) * decode_round + len(prompts)) / (e_time - s_time)} token/s." + ) + + +def batch_inference_one_step( + xinf_model_obj: "PytorchModel", + req_list: List[InferenceRequest], + model_uid, + model, + tokenizer, +): + from ....core.model import OutOfMemoryError + + try: + _batch_inference_one_step_internal( + xinf_model_obj, req_list, model_uid, model, tokenizer + ) + except OutOfMemoryError: + logger.exception( + f"Batch inference out of memory. " + f"Xinference will restart the model: {model_uid}. " + f"Please be patient for a few moments." + ) + # Just kill the process and let xinference auto-recover the model + os._exit(1) + except Exception as e: + logger.exception(f"Internal error for batch inference: {e}.") + # If internal error happens, just skip all the requests in this batch. + # If not handle here, the client will hang. + for r in req_list: + r.stopped = True + r.error_msg = str(e) diff --git a/xinference/model/llm/pytorch/yi_vl.py b/xinference/model/llm/transformers/yi_vl.py similarity index 64% rename from xinference/model/llm/pytorch/yi_vl.py rename to xinference/model/llm/transformers/yi_vl.py index 91c325f86e..e4b3d1f6ce 100644 --- a/xinference/model/llm/pytorch/yi_vl.py +++ b/xinference/model/llm/transformers/yi_vl.py @@ -11,28 +11,27 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import base64 import logging import time import uuid from concurrent.futures import ThreadPoolExecutor -from io import BytesIO from threading import Thread from typing import Dict, Iterator, List, Optional, Union -import requests import torch -from PIL import Image from ....model.utils import select_device from ....types import ( ChatCompletion, - ChatCompletionChoice, ChatCompletionChunk, ChatCompletionMessage, + Completion, + CompletionChoice, + CompletionChunk, CompletionUsage, ) from ..llm_family import LLMFamilyV1, LLMSpecV1 +from ..utils import _decode_image from .core import PytorchChatModel, PytorchGenerateConfig logger = logging.getLogger(__name__) @@ -49,7 +48,8 @@ def __init__(self, *args, **kwargs): def match( cls, model_family: "LLMFamilyV1", model_spec: "LLMSpecV1", quantization: str ) -> bool: - if "yi" in model_family.model_name: + llm_family = model_family.model_family or model_family.model_name + if "yi-vl" in llm_family: return True return False @@ -75,25 +75,6 @@ def load(self): @staticmethod def _message_content_to_yi(content) -> Union[str, tuple]: - def _load_image(_url): - if _url.startswith("data:"): - logging.info("Parse url by base64 decoder.") - # https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images - # e.g. f"data:image/jpeg;base64,{base64_image}" - _type, data = _url.split(";") - _, ext = _type.split("/") - data = data[len("base64,") :] - data = base64.b64decode(data.encode("utf-8")) - - return Image.open(BytesIO(data)) - else: - try: - response = requests.get(_url) - except requests.exceptions.MissingSchema: - return Image.open(_url) - else: - return Image.open(BytesIO(response.content)) - if not isinstance(content, str): from ....thirdparty.llava.model.constants import DEFAULT_IMAGE_TOKEN @@ -108,7 +89,7 @@ def _load_image(_url): image_futures = [] with ThreadPoolExecutor() as executor: for image_url in image_urls: - fut = executor.submit(_load_image, image_url) + fut = executor.submit(_decode_image, image_url) image_futures.append(fut) images = [fut.result() for fut in image_futures] text = " ".join(texts) @@ -122,38 +103,6 @@ def _load_image(_url): raise RuntimeError("Only one image per message is supported by Yi VL.") return content - @staticmethod - def _parse_text(text): - lines = text.split("\n") - lines = [line for line in lines if line != ""] - count = 0 - for i, line in enumerate(lines): - if "```" in line: - count += 1 - items = line.split("`") - if count % 2 == 1: - lines[i] = f'
'
-                else:
-                    lines[i] = f"
" - else: - if i > 0: - if count % 2 == 1: - line = line.replace("`", r"\`") - line = line.replace("<", "<") - line = line.replace(">", ">") - line = line.replace(" ", " ") - line = line.replace("*", "*") - line = line.replace("_", "_") - line = line.replace("-", "-") - line = line.replace(".", ".") - line = line.replace("!", "!") - line = line.replace("(", "(") - line = line.replace(")", ")") - line = line.replace("$", "$") - lines[i] = "
" + line - text = "".join(lines) - return text - def chat( self, prompt: Union[str, List[Dict]], @@ -164,12 +113,18 @@ def chat( from transformers import TextIteratorStreamer # TODO(codingl2k1): implement stream mode. - if generate_config and generate_config.get("stream"): - raise Exception( - f"Chat with model {self.model_family.model_name} does not support stream." - ) + if not generate_config: generate_config = {} + + stream = generate_config.get("stream", False) + stream_options = generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) + from ....thirdparty.llava.conversation import conv_templates from ....thirdparty.llava.mm_utils import ( KeywordsStoppingCriteria, @@ -196,11 +151,11 @@ def chat( ) images = state.get_images(return_pil=True) - image = images[0] - - image_tensor = self._image_processor.preprocess(image, return_tensors="pt")[ - "pixel_values" - ][0] + if images: + image = images[0] + image_tensor = self._image_processor.preprocess(image, return_tensors="pt")[ + "pixel_values" + ][0] stop_str = state.sep keywords = [stop_str] @@ -217,7 +172,9 @@ def chat( "input_ids": input_ids, "images": image_tensor.unsqueeze(0) .to(dtype=torch.bfloat16) - .to(self._model.device), + .to(self._model.device) + if images + else None, "streamer": streamer, "do_sample": True, "top_p": float(top_p), @@ -229,25 +186,92 @@ def chat( t = Thread(target=self._model.generate, kwargs=generate_kwargs) t.start() + if stream: + it = self._generate_stream(streamer, stop_str, input_ids, include_usage) + return self._to_chat_completion_chunks(it) + else: + c = self._generate(streamer, stop_str) + return self._to_chat_completion(c) + + def _generate(self, streamer, stop_str) -> Completion: generated_text = "" for new_text in streamer: generated_text += new_text if generated_text.endswith(stop_str): generated_text = generated_text[: -len(stop_str)] - r = self._parse_text(generated_text) - return ChatCompletion( - id="chat" + str(uuid.uuid1()), - object="chat.completion", + + c = Completion( + id=str(uuid.uuid1()), + object="text_completion", created=int(time.time()), model=self.model_uid, choices=[ - ChatCompletionChoice( - index=0, - message={"role": "assistant", "content": r}, - finish_reason="stop", + CompletionChoice( + index=0, text=generated_text, finish_reason="stop", logprobs=None ) ], usage=CompletionUsage( prompt_tokens=-1, completion_tokens=-1, total_tokens=-1 ), ) + return c + + def _generate_stream( + self, streamer, stop_str, input_ids, include_usage + ) -> Iterator[CompletionChunk]: + completion_id = str(uuid.uuid1()) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 + prompt_tokens = len(input_ids[0]) + for i, new_text in enumerate(streamer): + if not new_text.endswith(stop_str): + completion_choice = CompletionChoice( + text=new_text, index=0, logprobs=None, finish_reason=None + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_tokens = i + total_tokens = prompt_tokens + completion_tokens + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + + completion_choice = CompletionChoice( + text="", index=0, logprobs=None, finish_reason="stop" + ) + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[completion_choice], + ) + completion_usage = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + chunk["usage"] = completion_usage + yield chunk + if include_usage: + chunk = CompletionChunk( + id=completion_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk diff --git a/xinference/model/llm/utils.py b/xinference/model/llm/utils.py index f404aba5e5..8107d890a0 100644 --- a/xinference/model/llm/utils.py +++ b/xinference/model/llm/utils.py @@ -11,14 +11,19 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import base64 import functools import json import logging import os import time import uuid +from io import BytesIO from typing import AsyncGenerator, Dict, Iterator, List, Optional, Tuple, cast +import requests +from PIL import Image + from ...types import ( SPECIAL_TOOL_PROMPT, ChatCompletion, @@ -27,8 +32,9 @@ Completion, CompletionChunk, ) +from ..utils import ensure_cache_cleared from .llm_family import ( - GgmlLLMSpecV1, + LlamaCppLLMSpecV1, LLMFamilyV1, LLMSpecV1, PromptStyleV1, @@ -39,6 +45,20 @@ logger = logging.getLogger(__name__) +QWEN_TOOL_CALL_FAMILY = [ + "qwen-chat", + "qwen1.5-chat", + "qwen1.5-moe-chat", + "qwen2-instruct", + "qwen2-moe-instruct", +] + +GLM4_TOOL_CALL_FAMILY = [ + "glm4-chat", + "glm4-chat-1m", +] + + class ChatModelMixin: @staticmethod def get_prompt( @@ -46,7 +66,7 @@ def get_prompt( chat_history: List[ChatCompletionMessage], prompt_style: PromptStyleV1, tools: Optional[List[Dict]] = None, - ) -> str: + ): """ Inspired by FastChat. Format chat history into a prompt according to the prompty style of different models. @@ -78,17 +98,6 @@ def get_role(role_name: str): else: ret += role + ":" return ret - elif prompt_style.style_name == "ADD_COLON_TWO": - seps = [prompt_style.intra_message_sep, prompt_style.inter_message_sep] - ret = prompt_style.system_prompt + seps[0] - for i, message in enumerate(chat_history): - role = get_role(message["role"]) - content = message["content"] - if content: - ret += role + ": " + content + seps[i % 2] - else: - ret += role + ":" - return ret elif prompt_style.style_name == "NO_COLON_TWO": seps = [prompt_style.intra_message_sep, prompt_style.inter_message_sep] ret = prompt_style.system_prompt @@ -114,20 +123,21 @@ def get_role(role_name: str): else: ret += role return ret - elif prompt_style.style_name == "FALCON": - ret = prompt_style.system_prompt - for message in chat_history: + elif prompt_style.style_name == "LLAMA3": + ret = ( + f"<|begin_of_text|><|start_header_id|>system<|end_header_id|>" + f"{prompt_style.intra_message_sep}{prompt_style.system_prompt}{prompt_style.inter_message_sep}" + ) + for i, message in enumerate(chat_history): role = get_role(message["role"]) content = message["content"] if content: ret += ( - role - + ": " - + content.replace("\r\n", "\n").replace("\n\n", "\n") + f"<|start_header_id|>{role}<|end_header_id|>" + f"{prompt_style.intra_message_sep}{content}{prompt_style.inter_message_sep}" ) - ret += "\n\n" else: - ret += role + ":" + ret += f"<|start_header_id|>{role}<|end_header_id|>{prompt_style.intra_message_sep}" return ret elif prompt_style.style_name == "MIXTRAL_V01": ret = "" @@ -138,22 +148,6 @@ def get_role(role_name: str): else: # assistant ret += f"{content}
" return ret - elif prompt_style.style_name == "CHATGLM": - round_add_n = 1 if prompt_style.intra_message_sep == "\n\n" else 0 - if prompt_style.system_prompt: - ret = prompt_style.system_prompt + prompt_style.intra_message_sep - else: - ret = "" - for i, message in enumerate(chat_history): - role = get_role(message["role"]) - content = message["content"] - if i % 2 == 0: - ret += f"[Round {i // 2 + round_add_n}]{prompt_style.intra_message_sep}" - if content: - ret += role + ":" + content + prompt_style.intra_message_sep - else: - ret += role + ":" - return ret elif prompt_style.style_name == "CHATGLM3": prompts = ( [f"<|system|>\n {prompt_style.system_prompt}"] @@ -163,7 +157,7 @@ def get_role(role_name: str): for i, message in enumerate(chat_history): role = get_role(message["role"]) - content = message["content"] + content = message.get("content") tool_calls = message.get("tool_calls") if tool_calls: content = tool_calls[0]["function"] @@ -212,16 +206,14 @@ def get_role(role_name: str): tools_name_text = [] for func_info in tools: parameters = [] - required_parameters = func_info["function"]["parameters"].get( - "required", [] - ) - for name, p in func_info["function"]["parameters"][ - "properties" - ].items(): - param = dict({"name": name}, **p) - if name in required_parameters: - param["required"] = True - parameters.append(param) + fp = func_info["function"].get("parameters", {}) + if fp: + required_parameters = fp.get("required", []) + for name, p in fp["properties"].items(): + param = dict({"name": name}, **p) + if name in required_parameters: + param["required"] = True + parameters.append(param) name = func_info["function"]["name"] desc = func_info["function"]["description"] @@ -248,7 +240,7 @@ def get_role(role_name: str): ret = f"<|im_start|>system\n{prompt_style.system_prompt}<|im_end|>" for message in chat_history: role = get_role(message["role"]) - content = message["content"] + content = message.get("content") ret += prompt_style.intra_message_sep if tools: @@ -295,25 +287,6 @@ def get_role(role_name: str): else: ret += role + "\n" return ret - elif prompt_style.style_name == "INTERNLM": - seps = [prompt_style.intra_message_sep, prompt_style.inter_message_sep] - ret = "" - for i, message in enumerate(chat_history[:-2]): - if i % 2 == 0: - ret += "" - role = get_role(message["role"]) - content = message["content"] - ret += role + ":" + str(content) + seps[i % 2] - if len(ret) == 0: - ret += "" - ret += ( - chat_history[-2]["role"] - + ":" - + str(chat_history[-2]["content"]) - + seps[0] - ) - ret += chat_history[-1]["role"] + ":" - return ret elif prompt_style.style_name == "INTERNLM2": ret = ( "" @@ -342,9 +315,6 @@ def get_role(role_name: str): else: ret += role + ": Let's think step by step." return ret - elif prompt_style.style_name == "INSTRUCTION": - message = chat_history[-2] - return prompt_style.system_prompt.format(message["content"]) elif prompt_style.style_name == "DEEPSEEK_CHAT": seps = [prompt_style.intra_message_sep, prompt_style.inter_message_sep] ret = prompt_style.system_prompt @@ -431,11 +401,119 @@ def get_role(role_name: str): else: ret += "" + content.strip() return ret + elif prompt_style.style_name == "PHI3": + ret = f"<|system|>{prompt_style.intra_message_sep}{prompt_style.system_prompt}{prompt_style.inter_message_sep}" + for message in chat_history: + content = message["content"] or "" + role = get_role(message["role"]) + if content: + ret += f"<|{role}|>{prompt_style.intra_message_sep}{content}{prompt_style.inter_message_sep}" + else: + ret += f"<|{role}|>{prompt_style.intra_message_sep}" + ret += "<|assistant|>\n" + return ret + elif prompt_style.style_name == "c4ai-command-r": + ret = ( + f"<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>" + f"{prompt_style.system_prompt}{prompt_style.inter_message_sep}" + ) + for i, message in enumerate(chat_history): + role = get_role(message["role"]) + content = message["content"] + if content: + ret += f"{role}{content}{prompt_style.inter_message_sep}" + else: + ret += role + return ret + elif prompt_style.style_name == "mistral-nemo": + seps = [prompt_style.intra_message_sep, prompt_style.inter_message_sep] + ret = "" + for i, message in enumerate(chat_history): + role = get_role(message["role"]) + content = message["content"] + if content: + if i == len(chat_history) - 2 and prompt_style.system_prompt: + ret += ( + role + + " " + + prompt_style.system_prompt + + "\n\n" + + content + + seps[i % 2] + ) + else: + ret += role + " " + content + seps[i % 2] + else: + ret += role + return ret + elif prompt_style.style_name == "INTERNVL": + ret = ( + "" + if prompt_style.system_prompt == "" + else "<|im_start|>system\n" + + prompt_style.system_prompt + + prompt_style.intra_message_sep + + "\n" + ) + images = [] # type: ignore + for message in chat_history: + role = get_role(message["role"]) + content = message["content"] + if isinstance(content, str): + if content: + ret += ( + role + + "\n" + + content + + prompt_style.intra_message_sep + + "\n" + ) + else: + ret += role + "\n" + elif isinstance(content, list): + text = "" + image_urls = [] + for c in content: + c_type = c.get("type") + if c_type == "text": + text = c["text"] + elif c_type == "image_url": + image_urls.append(c["image_url"]["url"]) + image_futures = [] + from concurrent.futures import ThreadPoolExecutor + + with ThreadPoolExecutor() as executor: + for image_url in image_urls: + fut = executor.submit(_decode_image, image_url) + image_futures.append(fut) + images = [fut.result() for fut in image_futures] + if len(image_futures) == 0: + ret += ( + role + "\n" + text + prompt_style.intra_message_sep + "\n" + ) + else: + ret += ( + role + + "\n" + + f"\n{text}" + + prompt_style.intra_message_sep + + "\n" + ) + + return (ret, images) else: raise ValueError(f"Invalid prompt style: {prompt_style.style_name}") @classmethod def _to_chat_completion_chunk(cls, chunk: CompletionChunk) -> ChatCompletionChunk: + choices = chunk.get("choices") + if ( + chunk.get("object") == "chat.completion.chunk" + and choices + and "delta" in choices[0] + ): + # Already a ChatCompletionChunk, we don't need to convert chunk. + return cast(ChatCompletionChunk, chunk) chat_chunk = { "id": "chat" + chunk["id"], "model": chunk["model"], @@ -445,16 +523,18 @@ def _to_chat_completion_chunk(cls, chunk: CompletionChunk) -> ChatCompletionChun { "index": i, "delta": { - "content": choice["text"], + "content": choice.get("text"), + **( + {"tool_calls": choice["tool_calls"]} + if "tool_calls" in choice + else {} + ), }, "finish_reason": choice["finish_reason"], } for i, choice in enumerate(chunk["choices"]) ], } - usage = chunk.get("usage") - if usage is not None: - chat_chunk["usage"] = usage return cast(ChatCompletionChunk, chat_chunk) @classmethod @@ -478,12 +558,26 @@ def _get_first_chat_completion_chunk( for i, choice in enumerate(chunk["choices"]) ], } + return cast(ChatCompletionChunk, chat_chunk) + + @classmethod + def _get_final_chat_completion_chunk( + cls, chunk: CompletionChunk + ) -> ChatCompletionChunk: + chat_chunk = { + "id": "chat" + chunk["id"], + "model": chunk["model"], + "created": chunk["created"], + "object": "chat.completion.chunk", + "choices": [], + } usage = chunk.get("usage") if usage is not None: chat_chunk["usage"] = usage return cast(ChatCompletionChunk, chat_chunk) @classmethod + @ensure_cache_cleared def _to_chat_completion_chunks( cls, chunks: Iterator[CompletionChunk], @@ -491,7 +585,12 @@ def _to_chat_completion_chunks( for i, chunk in enumerate(chunks): if i == 0: yield cls._get_first_chat_completion_chunk(chunk) - yield cls._to_chat_completion_chunk(chunk) + # usage + choices = chunk.get("choices") + if not choices: + yield cls._get_final_chat_completion_chunk(chunk) + else: + yield cls._to_chat_completion_chunk(chunk) @classmethod async def _async_to_chat_completion_chunks( @@ -502,10 +601,16 @@ async def _async_to_chat_completion_chunks( async for chunk in chunks: if i == 0: yield cls._get_first_chat_completion_chunk(chunk) - yield cls._to_chat_completion_chunk(chunk) + # usage + choices = chunk.get("choices") + if not choices: + yield cls._get_final_chat_completion_chunk(chunk) + else: + yield cls._to_chat_completion_chunk(chunk) i += 1 @staticmethod + @ensure_cache_cleared def _to_chat_completion(completion: Completion) -> ChatCompletion: return { "id": "chat" + completion["id"], @@ -544,10 +649,14 @@ def tool_call(n, **kwargs): return arguments, None, None @staticmethod - def _eval_chatglm3_arguments(c, tools): - if isinstance(c[0], str): - return c[0], None, None - return None, c[0]["name"], c[0]["parameters"] + def _eval_glm_chat_arguments(c, tools): + try: + if isinstance(c[0], str): + return c[0], None, None + return None, c[0]["name"], c[0]["parameters"] + except KeyError: + logger.error("Can't parse glm output: %s", c) + return str(c), None, None @staticmethod def _eval_qwen_chat_arguments(c, tools): @@ -592,21 +701,103 @@ def _eval_qwen_chat_arguments(c, tools): return text, None, None @classmethod - def _tool_calls_completion(cls, model_family, model_uid, c, tools): - _id = str(uuid.uuid4()) + def _eval_tool_arguments(cls, model_family, c, tools): family = model_family.model_family or model_family.model_name if family in ["gorilla-openfunctions-v1", "gorilla-openfunctions-v2"]: content, func, args = cls._eval_gorilla_openfunctions_arguments(c, tools) - elif "chatglm3" == family: - content, func, args = cls._eval_chatglm3_arguments(c, tools) - elif family in ["qwen-chat", "qwen1.5-chat"]: + elif family in GLM4_TOOL_CALL_FAMILY: + content, func, args = cls._eval_glm_chat_arguments(c, tools) + elif family in QWEN_TOOL_CALL_FAMILY: content, func, args = cls._eval_qwen_chat_arguments(c, tools) else: raise Exception( f"Model {model_family.model_name} is not support tool calls." ) logger.debug("Tool call content: %s, func: %s, args: %s", content, func, args) + return content, func, args + + @classmethod + def _tools_token_filter(cls, model_family): + """ + Generates a filter function for Qwen series models to retain outputs after "\nFinal Answer:". + + Returns: + A function that takes tokens (string output by the model so far) and delta (new tokens added) as input, + returns the part after "\nFinal Answer:" if found, else returns delta. + """ + family = model_family.model_family or model_family.model_name + if family in QWEN_TOOL_CALL_FAMILY: + # Encapsulating function to reset 'found' after each call + found = False + + def process_tokens(tokens: str, delta: str): + nonlocal found + # Once "Final Answer:" is found, future tokens are allowed. + if found: + return delta + # Check if the token ends with "\nFinal Answer:" and update `found`. + final_answer_idx = tokens.lower().rfind("\nfinal answer:") + if final_answer_idx != -1: + found = True + return tokens[final_answer_idx + len("\nfinal answer:") :] + return "" + + return process_tokens + else: + return lambda tokens, delta: delta + + @classmethod + def _tool_calls_completion_chunk(cls, model_family, model_uid, c, tools): + _id = str(uuid.uuid4()) + content, func, args = cls._eval_tool_arguments(model_family, c, tools) + if func: + d = { + "role": "assistant", + "content": content, + "tool_calls": [ + { + "id": f"call_{_id}", + "type": "function", + "function": { + "name": func, + "arguments": json.dumps(args), + }, + } + ], + } + finish_reason = "tool_calls" + else: + d = {"role": "assistant", "content": content, "tool_calls": []} + finish_reason = "stop" + try: + usage = c.get("usage") + assert "prompt_tokens" in usage + except Exception: + usage = { + "prompt_tokens": -1, + "completion_tokens": -1, + "total_tokens": -1, + } + return { + "id": "chat" + f"cmpl-{_id}", + "model": model_uid, + "object": "chat.completion.chunk", + "created": int(time.time()), + "choices": [ + { + "index": 0, + "delta": d, + "logprobs": None, + "finish_reason": finish_reason, + } + ], + "usage": usage, + } + @classmethod + def _tool_calls_completion(cls, model_family, model_uid, c, tools): + _id = str(uuid.uuid4()) + content, func, args = cls._eval_tool_arguments(model_family, c, tools) if func: m = { "role": "assistant", @@ -626,6 +817,15 @@ def _tool_calls_completion(cls, model_family, model_uid, c, tools): else: m = {"role": "assistant", "content": content, "tool_calls": []} finish_reason = "stop" + try: + usage = c.get("usage") + assert "prompt_tokens" in usage + except Exception: + usage = { + "prompt_tokens": -1, + "completion_tokens": -1, + "total_tokens": -1, + } return { "id": "chat" + f"cmpl-{_id}", "model": model_uid, @@ -638,19 +838,27 @@ def _tool_calls_completion(cls, model_family, model_uid, c, tools): "finish_reason": finish_reason, } ], - "usage": { - "prompt_tokens": -1, - "completion_tokens": -1, - "total_tokens": -1, - }, + "usage": usage, } + @classmethod + def get_full_prompt(cls, model_family, prompt, system_prompt, chat_history, tools): + assert model_family.prompt_style is not None + prompt_style = model_family.prompt_style.copy() + if system_prompt: + prompt_style.system_prompt = system_prompt + chat_history = chat_history or [] + full_prompt = cls.get_prompt(prompt, chat_history, prompt_style, tools=tools) + return full_prompt + def get_file_location( llm_family: LLMFamilyV1, spec: LLMSpecV1, quantization: str ) -> Tuple[str, bool]: - cache_dir = _get_cache_dir(llm_family, spec, create_if_not_exist=False) - cache_status = get_cache_status(llm_family, spec) + cache_dir = _get_cache_dir( + llm_family, spec, quantization, create_if_not_exist=False + ) + cache_status = get_cache_status(llm_family, spec, quantization) if isinstance(cache_status, list): is_cached = None for q, cs in zip(spec.quantizations, cache_status): @@ -661,10 +869,10 @@ def get_file_location( is_cached = cache_status assert isinstance(is_cached, bool) - if spec.model_format in ["pytorch", "gptq", "awq"]: + if spec.model_format in ["pytorch", "gptq", "awq", "fp8", "mlx"]: return cache_dir, is_cached - elif spec.model_format in ["ggmlv3", "ggufv2"]: - assert isinstance(spec, GgmlLLMSpecV1) + elif spec.model_format in ["ggufv2"]: + assert isinstance(spec, LlamaCppLLMSpecV1) filename = spec.model_file_name_template.format(quantization=quantization) model_path = os.path.join(cache_dir, filename) return model_path, is_cached @@ -676,3 +884,22 @@ def get_model_version( llm_family: LLMFamilyV1, llm_spec: LLMSpecV1, quantization: str ) -> str: return f"{llm_family.model_name}--{llm_spec.model_size_in_billions}B--{llm_spec.model_format}--{quantization}" + + +def _decode_image(_url): + if _url.startswith("data:"): + logging.info("Parse url by base64 decoder.") + # https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images + # e.g. f"data:image/jpeg;base64,{base64_image}" + _type, data = _url.split(";") + _, ext = _type.split("/") + data = data[len("base64,") :] + data = base64.b64decode(data.encode("utf-8")) + return Image.open(BytesIO(data)).convert("RGB") + else: + try: + response = requests.get(_url) + except requests.exceptions.MissingSchema: + return Image.open(_url).convert("RGB") + else: + return Image.open(BytesIO(response.content)).convert("RGB") diff --git a/xinference/model/llm/vllm/core.py b/xinference/model/llm/vllm/core.py index d26e6a72f0..372efc7a3e 100644 --- a/xinference/model/llm/vllm/core.py +++ b/xinference/model/llm/vllm/core.py @@ -12,12 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio +import json import logging import multiprocessing +import os import time import uuid from typing import ( TYPE_CHECKING, + Any, AsyncGenerator, Dict, Iterable, @@ -27,7 +31,6 @@ Union, ) -from ....constants import XINFERENCE_DISABLE_VLLM from ....types import ( ChatCompletion, ChatCompletionChunk, @@ -36,10 +39,13 @@ CompletionChoice, CompletionChunk, CompletionUsage, + LoRA, + ToolCallFunction, + ToolCalls, ) from .. import LLM, LLMFamilyV1, LLMSpecV1 from ..llm_family import CustomLLMFamilyV1 -from ..utils import ChatModelMixin +from ..utils import QWEN_TOOL_CALL_FAMILY, ChatModelMixin logger = logging.getLogger(__name__) @@ -61,16 +67,19 @@ class VLLMModelConfig(TypedDict, total=False): class VLLMGenerateConfig(TypedDict, total=False): + lora_name: Optional[str] n: int best_of: Optional[int] presence_penalty: float frequency_penalty: float temperature: float top_p: float + top_k: int max_tokens: int stop_token_ids: Optional[List[int]] stop: Optional[Union[str, List[str]]] stream: bool # non-sampling param, should not be passed to the engine. + stream_options: Optional[Union[dict, None]] try: @@ -80,38 +89,52 @@ class VLLMGenerateConfig(TypedDict, total=False): except ImportError: VLLM_INSTALLED = False +VLLM_SUPPORTED_VISION_MODEL_LIST: List[str] = [ + "internvl2", +] VLLM_SUPPORTED_MODELS = [ "llama-2", - "baichuan", - "internlm-16k", + "llama-3", "mistral-v0.1", + "codestral-v0.1", "Yi", + "Yi-1.5", "code-llama", "code-llama-python", + "deepseek", + "deepseek-coder", ] VLLM_SUPPORTED_CHAT_MODELS = [ "llama-2-chat", - "vicuna-v1.3", - "vicuna-v1.5", - "baichuan-chat", + "llama-3-instruct", "baichuan-2-chat", - "internlm-chat-7b", - "internlm-chat-8k", - "internlm-chat-20b", + "internlm2-chat", + "internlm2.5-chat", + "internlm2.5-chat-1m", "qwen-chat", "Yi-chat", + "Yi-1.5-chat", + "Yi-1.5-chat-16k", "code-llama-instruct", "mistral-instruct-v0.1", "mistral-instruct-v0.2", + "mistral-instruct-v0.3", "mixtral-instruct-v0.1", + "mixtral-8x22B-instruct-v0.1", "chatglm3", "chatglm3-32k", "chatglm3-128k", + "glm4-chat", + "glm4-chat-1m", + "codegeex4", "deepseek-chat", "deepseek-coder-instruct", ] if VLLM_INSTALLED and vllm.__version__ >= "0.3.0": VLLM_SUPPORTED_CHAT_MODELS.append("qwen1.5-chat") + VLLM_SUPPORTED_MODELS.append("codeqwen1.5") + VLLM_SUPPORTED_CHAT_MODELS.append("codeqwen1.5-chat") + VLLM_SUPPORTED_CHAT_MODELS.append("qwen2-instruct") if VLLM_INSTALLED and vllm.__version__ >= "0.3.2": VLLM_SUPPORTED_CHAT_MODELS.append("gemma-it") @@ -120,6 +143,20 @@ class VLLMGenerateConfig(TypedDict, total=False): VLLM_SUPPORTED_CHAT_MODELS.append("orion-chat") VLLM_SUPPORTED_CHAT_MODELS.append("orion-chat-rag") +if VLLM_INSTALLED and vllm.__version__ >= "0.4.0": + VLLM_SUPPORTED_CHAT_MODELS.append("qwen1.5-moe-chat") + VLLM_SUPPORTED_CHAT_MODELS.append("qwen2-moe-instruct") + VLLM_SUPPORTED_CHAT_MODELS.append("c4ai-command-r-v01") + +if VLLM_INSTALLED and vllm.__version__ >= "0.5.3": + VLLM_SUPPORTED_CHAT_MODELS.append("gemma-2-it") + VLLM_SUPPORTED_CHAT_MODELS.append("mistral-nemo-instruct") + VLLM_SUPPORTED_CHAT_MODELS.append("mistral-large-instruct") + +if VLLM_INSTALLED and vllm.__version__ > "0.5.3": + VLLM_SUPPORTED_MODELS.append("llama-3.1") + VLLM_SUPPORTED_CHAT_MODELS.append("llama-3.1-instruct") + class VLLMModel(LLM): def __init__( @@ -130,16 +167,30 @@ def __init__( quantization: str, model_path: str, model_config: Optional[VLLMModelConfig], + peft_model: Optional[List[LoRA]] = None, ): + try: + from vllm.lora.request import LoRARequest + except ImportError: + error_message = "Failed to import module 'vllm'" + installation_guide = [ + "Please make sure 'vllm' is installed. ", + "You can install it by `pip install vllm`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") super().__init__(model_uid, model_family, model_spec, quantization, model_path) self._model_config = model_config self._engine = None + self.lora_modules = peft_model + self.lora_requests: List[LoRARequest] = [] def load(self): try: import vllm from vllm.engine.arg_utils import AsyncEngineArgs from vllm.engine.async_llm_engine import AsyncLLMEngine + from vllm.lora.request import LoRARequest except ImportError: error_message = "Failed to import module 'vllm'" installation_guide = [ @@ -158,13 +209,71 @@ def load(self): multiprocessing.set_start_method("fork", force=True) self._model_config = self._sanitize_model_config(self._model_config) + + if self.lora_modules is None: + self.lora_requests = [] + else: + self.lora_requests = [ + LoRARequest( + lora_name=lora.lora_name, + lora_int_id=i, + lora_local_path=lora.local_path, + ) + for i, lora in enumerate(self.lora_modules, start=1) + ] + + enable_lora = len(self.lora_requests) > 0 + max_loras = len(self.lora_requests) + logger.info( f"Loading {self.model_uid} with following model config: {self._model_config}" + f"Enable lora: {enable_lora}. Lora count: {max_loras}." ) - engine_args = AsyncEngineArgs(model=self.model_path, **self._model_config) + engine_args = AsyncEngineArgs( + model=self.model_path, + enable_lora=enable_lora, + max_loras=max_loras, + **self._model_config, + ) self._engine = AsyncLLMEngine.from_engine_args(engine_args) + self._check_health_task = None + if hasattr(self._engine, "check_health"): + # vLLM introduced `check_health` since v0.4.1 + self._check_health_task = asyncio.create_task(self._check_healthy()) + + def stop(self): + # though the vLLM engine will shutdown when deleted, + # but some issue e.g. GH#1682 reported + # when deleting, the engine exists still + logger.info("Stopping vLLM engine") + if self._check_health_task: + self._check_health_task.cancel() + if model_executor := getattr(self._engine.engine, "model_executor", None): + model_executor.shutdown() + self._engine = None + + async def _check_healthy(self, interval: int = 30): + from vllm.engine.async_llm_engine import AsyncEngineDeadError + + logger.debug("Begin to check health of vLLM") + + while self._engine is not None: + try: + await self._engine.check_health() + except (AsyncEngineDeadError, RuntimeError): + logger.info("Detecting vLLM is not health, prepare to quit the process") + try: + self.stop() + except: + # ignore error when stop + pass + # Just kill the process and let xinference auto-recover the model + os._exit(1) + else: + await asyncio.sleep(interval) + def _sanitize_model_config( self, model_config: Optional[VLLMModelConfig] ) -> VLLMModelConfig: @@ -193,6 +302,7 @@ def _sanitize_generate_config( generate_config = {} sanitized = VLLMGenerateConfig() + sanitized.setdefault("lora_name", generate_config.get("lora_name", None)) sanitized.setdefault("n", generate_config.get("n", 1)) sanitized.setdefault("best_of", generate_config.get("best_of", None)) sanitized.setdefault( @@ -203,12 +313,16 @@ def _sanitize_generate_config( ) sanitized.setdefault("temperature", generate_config.get("temperature", 1.0)) sanitized.setdefault("top_p", generate_config.get("top_p", 1.0)) + sanitized.setdefault("top_k", generate_config.get("top_k", -1)) sanitized.setdefault("max_tokens", generate_config.get("max_tokens", 1024)) sanitized.setdefault("stop", generate_config.get("stop", None)) sanitized.setdefault( "stop_token_ids", generate_config.get("stop_token_ids", None) ) - sanitized.setdefault("stream", generate_config.get("stream", None)) + sanitized.setdefault("stream", generate_config.get("stream", False)) + sanitized.setdefault( + "stream_options", generate_config.get("stream_options", None) + ) return sanitized @@ -216,21 +330,26 @@ def _sanitize_generate_config( def match( cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str ) -> bool: - if XINFERENCE_DISABLE_VLLM: - return False if not cls._has_cuda_device(): return False if not cls._is_linux(): return False - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + if llm_spec.model_format not in ["pytorch", "gptq", "awq", "fp8"]: return False if llm_spec.model_format == "pytorch": if quantization != "none" and not (quantization is None): return False - if llm_spec.model_format in ["gptq", "awq"]: - # Currently, only 4-bit weight quantization is supported for GPTQ, but got 8 bits. + if llm_spec.model_format == "awq": + # Currently, only 4-bit weight quantization is supported for AWQ, but got 8 bits. if "4" not in quantization: return False + if llm_spec.model_format == "gptq": + if VLLM_INSTALLED and vllm.__version__ >= "0.3.3": + if not any(q in quantization for q in ("3", "4", "8")): + return False + else: + if "4" not in quantization: + return False if isinstance(llm_family, CustomLLMFamilyV1): if llm_family.model_family not in VLLM_SUPPORTED_MODELS: return False @@ -298,8 +417,9 @@ def _convert_request_output_to_completion( async def async_generate( self, - prompt: str, + prompt: Union[str, Dict[str, Any]], generate_config: Optional[Dict] = None, + tools: object = False, ) -> Union[Completion, AsyncGenerator[CompletionChunk, None]]: try: from vllm.sampling_params import SamplingParams @@ -317,25 +437,79 @@ async def async_generate( "Enter generate, prompt: %s, generate config: %s", prompt, generate_config ) + lora_model = sanitized_generate_config.pop("lora_name") + + lora_request = None + if lora_model is not None: + for lora in self.lora_requests: + if lora_model == lora.lora_name: + lora_request = lora + break + stream = sanitized_generate_config.pop("stream") + stream_options = sanitized_generate_config.pop("stream_options", None) + include_usage = ( + stream_options["include_usage"] + if isinstance(stream_options, dict) + else False + ) sampling_params = SamplingParams(**sanitized_generate_config) request_id = str(uuid.uuid1()) assert self._engine is not None - results_generator = self._engine.generate(prompt, sampling_params, request_id) + results_generator = self._engine.generate( + prompt, sampling_params, request_id, lora_request=lora_request + ) async def stream_results() -> AsyncGenerator[CompletionChunk, None]: previous_texts = [""] * sanitized_generate_config["n"] + tools_token_filter = ChatModelMixin._tools_token_filter(self.model_family) + prompt_tokens, completion_tokens, total_tokens = 0, 0, 0 async for _request_output in results_generator: chunk = self._convert_request_output_to_completion_chunk( request_id=request_id, model=self.model_uid, request_output=_request_output, ) + for i, choice in enumerate(chunk["choices"]): delta = choice["text"][len(previous_texts[i]) :] previous_texts[i] = choice["text"] choice["text"] = delta + + if tools: + # only handle the first choice + choice = chunk["choices"][0] + if choice["finish_reason"] is not None: + # use previous text for evaluation temporarily + choice_delta = choice["text"] + choice["text"] = previous_texts[0] + _content, func, args = ChatModelMixin._eval_tool_arguments( + self.model_family, chunk, tools + ) + choice["text"] = tools_token_filter( + tokens=previous_texts[0], delta=choice_delta + ) + if func is not None: + choice["text"] = None + choice["finish_reason"] = "tool_calls" + choice["tool_calls"] = [ + ToolCalls( + id=str(uuid.uuid4()), + type="function", + function=ToolCallFunction( + name=func, + arguments=json.dumps(args, ensure_ascii=False), + ), + ) + ] + else: + # use a filter function to skip Qwen's react thought process + choice["text"] = tools_token_filter( + tokens=previous_texts[0], delta=choice["text"] + ) + if not choice["text"]: + continue prompt_tokens = len(_request_output.prompt_token_ids) completion_tokens = sum( len(output.token_ids) for output in _request_output.outputs @@ -347,6 +521,20 @@ async def stream_results() -> AsyncGenerator[CompletionChunk, None]: total_tokens=total_tokens, ) yield chunk + if include_usage: + chunk = CompletionChunk( + id=request_id, + object="text_completion", + created=int(time.time()), + model=self.model_uid, + choices=[], + ) + chunk["usage"] = CompletionUsage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + yield chunk if stream: return stream_results() @@ -366,17 +554,22 @@ class VLLMChatModel(VLLMModel, ChatModelMixin): def match( cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str ) -> bool: - if XINFERENCE_DISABLE_VLLM: - return False - if llm_spec.model_format not in ["pytorch", "gptq", "awq"]: + if llm_spec.model_format not in ["pytorch", "gptq", "awq", "fp8"]: return False if llm_spec.model_format == "pytorch": if quantization != "none" and not (quantization is None): return False - if llm_spec.model_format in ["gptq", "awq"]: - # Currently, only 4-bit weight quantization is supported for GPTQ, but got 8 bits. + if llm_spec.model_format == "awq": + # Currently, only 4-bit weight quantization is supported for AWQ, but got 8 bits. if "4" not in quantization: return False + if llm_spec.model_format == "gptq": + if VLLM_INSTALLED and vllm.__version__ >= "0.3.3": + if not any(q in quantization for q in ("3", "4", "8")): + return False + else: + if "4" not in quantization: + return False if isinstance(llm_family, CustomLLMFamilyV1): if llm_family.model_family not in VLLM_SUPPORTED_CHAT_MODELS: return False @@ -423,7 +616,7 @@ async def async_chat( generate_config = self._sanitize_chat_config(generate_config) # TODO(codingl2k1): qwen hacky to set stop for function call. model_family = self.model_family.model_family or self.model_family.model_name - if tools and "qwen-chat" == model_family: + if tools and model_family in QWEN_TOOL_CALL_FAMILY: stop = generate_config.get("stop") if isinstance(stop, str): generate_config["stop"] = [stop, "Observation:"] @@ -436,7 +629,7 @@ async def async_chat( stream = generate_config.get("stream", None) if stream: - agen = await self.async_generate(full_prompt, generate_config) + agen = await self.async_generate(full_prompt, generate_config, tools) assert isinstance(agen, AsyncGenerator) return self._async_to_chat_completion_chunks(agen) else: @@ -447,3 +640,73 @@ async def async_chat( self.model_family, self.model_uid, c, tools ) return self._to_chat_completion(c) + + +class VLLMVisionModel(VLLMModel, ChatModelMixin): + @classmethod + def match( + cls, llm_family: "LLMFamilyV1", llm_spec: "LLMSpecV1", quantization: str + ) -> bool: + if llm_spec.model_format != "pytorch": + return False + if llm_spec.model_format == "pytorch": + if quantization != "none" and not (quantization is None): + return False + if isinstance(llm_family, CustomLLMFamilyV1): + if llm_family.model_family not in VLLM_SUPPORTED_VISION_MODEL_LIST: + return False + else: + if llm_family.model_name not in VLLM_SUPPORTED_VISION_MODEL_LIST: + return False + if "vision" not in llm_family.model_ability: + return False + return VLLM_INSTALLED + + def _sanitize_chat_config( + self, + generate_config: Optional[Dict] = None, + ) -> Dict: + if not generate_config: + generate_config = {} + if self.model_family.prompt_style: + if self.model_family.prompt_style.stop_token_ids: + generate_config.setdefault( + "stop_token_ids", + self.model_family.prompt_style.stop_token_ids.copy(), + ) + return generate_config + + async def async_chat( + self, + prompt: str, + system_prompt: Optional[str] = None, + chat_history: Optional[List[ChatCompletionMessage]] = None, + generate_config: Optional[Dict] = None, + ) -> Union[ChatCompletion, AsyncGenerator[ChatCompletionChunk, None]]: + # only support single image, waiting vllm support multi images + assert self.model_family.prompt_style is not None + prompt_style = self.model_family.prompt_style.copy() + chat_history = chat_history or [] + prompt, images = self.get_prompt(prompt, chat_history, prompt_style) + + if len(images) == 0: + inputs = { + "prompt": prompt, + } + else: + inputs = { + "prompt": prompt, + "multi_modal_data": {"image": images[-1]}, # type: ignore + } + generate_config = self._sanitize_chat_config(generate_config) + + stream = generate_config.get("stream", None) + + if stream: + agen = await self.async_generate(inputs, generate_config) + assert isinstance(agen, AsyncGenerator) + return self._async_to_chat_completion_chunks(agen) + else: + c = await self.async_generate(inputs, generate_config) + assert not isinstance(c, AsyncGenerator) + return self._to_chat_completion(c) diff --git a/xinference/model/rerank/core.py b/xinference/model/rerank/core.py index 6af2224186..2d73e2f399 100644 --- a/xinference/model/rerank/core.py +++ b/xinference/model/rerank/core.py @@ -12,16 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. +import gc import logging import os import uuid from collections import defaultdict -from typing import Dict, List, Optional, Tuple +from collections.abc import Sequence +from typing import Dict, List, Literal, Optional, Tuple import numpy as np +import torch from ...constants import XINFERENCE_CACHE_DIR -from ...types import Document, DocumentObj, Rerank +from ...device_utils import empty_cache +from ...types import Document, DocumentObj, Rerank, RerankTokens from ..core import CacheableModelSpec, ModelDescription from ..utils import is_model_cached @@ -31,6 +35,8 @@ # Init when registering all the builtin models. MODEL_NAME_TO_REVISION: Dict[str, List[str]] = defaultdict(list) RERANK_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) +RERANK_EMPTY_CACHE_COUNT = int(os.getenv("XINFERENCE_RERANK_EMPTY_CACHE_COUNT", "10")) +assert RERANK_EMPTY_CACHE_COUNT > 0 def get_rerank_model_descriptions(): @@ -42,8 +48,9 @@ def get_rerank_model_descriptions(): class RerankModelSpec(CacheableModelSpec): model_name: str language: List[str] + type: Optional[str] = "unknown" model_id: str - model_revision: str + model_revision: Optional[str] model_hub: str = "huggingface" @@ -63,6 +70,7 @@ def to_dict(self): "model_type": "rerank", "address": self.address, "accelerators": self.devices, + "type": self._model_spec.type, "model_name": self._model_spec.model_name, "language": self._model_spec.language, "model_revision": self._model_spec.model_revision, @@ -97,35 +105,90 @@ def generate_rerank_description(model_spec: RerankModelSpec) -> Dict[str, List[D class RerankModel: def __init__( self, + model_spec: RerankModelSpec, model_uid: str, - model_path: str, + model_path: Optional[str] = None, device: Optional[str] = None, use_fp16: bool = False, model_config: Optional[Dict] = None, ): + self._model_spec = model_spec self._model_uid = model_uid self._model_path = model_path self._device = device self._model_config = model_config or dict() self._use_fp16 = use_fp16 self._model = None + self._counter = 0 + if model_spec.type == "unknown": + model_spec.type = self._auto_detect_type(model_path) + + @staticmethod + def _get_tokenizer(model_path): + from transformers import AutoTokenizer + + tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) + return tokenizer + + @staticmethod + def _auto_detect_type(model_path): + """This method may not be stable due to the fact that the tokenizer name may be changed. + Therefore, we only use this method for unknown model types.""" + + type_mapper = { + "LlamaTokenizerFast": "LLM-based layerwise", + "GemmaTokenizerFast": "LLM-based", + "XLMRobertaTokenizerFast": "normal", + } + + tokenizer = RerankModel._get_tokenizer(model_path) + rerank_type = type_mapper.get(type(tokenizer).__name__) + if rerank_type is None: + logger.warning( + f"Can't determine the rerank type based on the tokenizer {tokenizer}, use normal type by default." + ) + return "normal" + return rerank_type def load(self): - try: - from sentence_transformers.cross_encoder import CrossEncoder - except ImportError: - error_message = "Failed to import module 'SentenceTransformer'" - installation_guide = [ - "Please make sure 'sentence-transformers' is installed. ", - "You can install it by `pip install sentence-transformers`\n", - ] + if self._model_spec.type == "normal": + try: + from sentence_transformers.cross_encoder import CrossEncoder + except ImportError: + error_message = "Failed to import module 'sentence-transformers'" + installation_guide = [ + "Please make sure 'sentence-transformers' is installed. ", + "You can install it by `pip install sentence-transformers`\n", + ] + + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + self._model = CrossEncoder( + self._model_path, + device=self._device, + trust_remote_code=True, + **self._model_config, + ) + if self._use_fp16: + self._model.model.half() + else: + try: + if self._model_spec.type == "LLM-based": + from FlagEmbedding import FlagLLMReranker as FlagReranker + elif self._model_spec.type == "LLM-based layerwise": + from FlagEmbedding import LayerWiseFlagLLMReranker as FlagReranker + else: + raise RuntimeError( + f"Unsupported Rank model type: {self._model_spec.type}" + ) + except ImportError: + error_message = "Failed to import module 'FlagEmbedding'" + installation_guide = [ + "Please make sure 'FlagEmbedding' is installed. ", + "You can install it by `pip install FlagEmbedding`\n", + ] - raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") - self._model = CrossEncoder( - self._model_path, device=self._device, **self._model_config - ) - if self._use_fp16: - self._model.model.half() + raise ImportError(f"{error_message}\n\n{''.join(installation_guide)}") + self._model = FlagReranker(self._model_path, use_fp16=self._use_fp16) def rerank( self, @@ -134,15 +197,32 @@ def rerank( top_n: Optional[int], max_chunks_per_doc: Optional[int], return_documents: Optional[bool], + return_len: Optional[bool], **kwargs, ) -> Rerank: + self._counter += 1 + if self._counter % RERANK_EMPTY_CACHE_COUNT == 0: + logger.debug("Empty rerank cache.") + gc.collect() + empty_cache() assert self._model is not None if kwargs: raise ValueError("rerank hasn't support extra parameter.") if max_chunks_per_doc is not None: raise ValueError("rerank hasn't support `max_chunks_per_doc` parameter.") sentence_combinations = [[query, doc] for doc in documents] - similarity_scores = self._model.predict(sentence_combinations) + if self._model_spec.type == "normal": + similarity_scores = self._model.predict( + sentence_combinations, convert_to_numpy=False, convert_to_tensor=True + ).cpu() + if similarity_scores.dtype == torch.bfloat16: + similarity_scores = similarity_scores.float() + else: + # Related issue: https://github.com/xorbitsai/inference/issues/1775 + similarity_scores = self._model.compute_score(sentence_combinations) + if not isinstance(similarity_scores, Sequence): + similarity_scores = [similarity_scores] + sim_scores_argsort = list(reversed(np.argsort(similarity_scores))) if top_n is not None: sim_scores_argsort = sim_scores_argsort[:top_n] @@ -164,7 +244,28 @@ def rerank( ) for arg in sim_scores_argsort ] - return Rerank(id=str(uuid.uuid1()), results=docs) + if return_len: + tokenizer = self._get_tokenizer(self._model_path) + input_len = sum([len(tokenizer.tokenize(t)) for t in documents]) + + # Rerank Model output is just score or documents + # while return_documents = True + output_len = input_len + + # api_version, billed_units, warnings + # is for Cohere API compatibility, set to None + metadata = { + "api_version": None, + "billed_units": None, + "tokens": ( + RerankTokens(input_tokens=input_len, output_tokens=output_len) + if return_len + else None + ), + "warnings": None, + } + + return Rerank(id=str(uuid.uuid1()), results=docs, meta=metadata) def get_cache_dir(model_spec: RerankModelSpec): @@ -184,7 +285,13 @@ def cache(model_spec: RerankModelSpec): def create_rerank_model_instance( - subpool_addr: str, devices: List[str], model_uid: str, model_name: str, **kwargs + subpool_addr: str, + devices: List[str], + model_uid: str, + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, + **kwargs, ) -> Tuple[RerankModel, RerankModelDescription]: from ..utils import download_from_modelscope from . import BUILTIN_RERANK_MODELS, MODELSCOPE_RERANK_MODELS @@ -197,34 +304,30 @@ def create_rerank_model_instance( break if model_spec is None: - if download_from_modelscope(): - if model_name in MODELSCOPE_RERANK_MODELS: - logger.debug(f"Rerank model {model_name} found in ModelScope.") - model_spec = MODELSCOPE_RERANK_MODELS[model_name] - else: - logger.debug( - f"Rerank model {model_name} not found in ModelScope, " - f"now try to download from huggingface." - ) - if model_name in BUILTIN_RERANK_MODELS: - model_spec = BUILTIN_RERANK_MODELS[model_name] - else: - raise ValueError( - f"Rerank model {model_name} not found, available" - f"model list: {BUILTIN_RERANK_MODELS.keys()}" - ) + if download_hub == "huggingface" and model_name in BUILTIN_RERANK_MODELS: + logger.debug(f"Rerank model {model_name} found in Huggingface.") + model_spec = BUILTIN_RERANK_MODELS[model_name] + elif download_hub == "modelscope" and model_name in MODELSCOPE_RERANK_MODELS: + logger.debug(f"Rerank model {model_name} found in ModelScope.") + model_spec = MODELSCOPE_RERANK_MODELS[model_name] + elif download_from_modelscope() and model_name in MODELSCOPE_RERANK_MODELS: + logger.debug(f"Rerank model {model_name} found in ModelScope.") + model_spec = MODELSCOPE_RERANK_MODELS[model_name] + elif model_name in BUILTIN_RERANK_MODELS: + logger.debug(f"Rerank model {model_name} found in Huggingface.") + model_spec = BUILTIN_RERANK_MODELS[model_name] else: - if model_name in BUILTIN_RERANK_MODELS: - model_spec = BUILTIN_RERANK_MODELS[model_name] - else: - raise ValueError( - f"Rerank model {model_name} not found, available" - f"model list: {BUILTIN_RERANK_MODELS.keys()}" - ) - - model_path = cache(model_spec) + raise ValueError( + f"Rerank model {model_name} not found, available" + f"Huggingface: {BUILTIN_RERANK_MODELS.keys()}" + f"ModelScope: {MODELSCOPE_RERANK_MODELS.keys()}" + ) + if not model_path: + model_path = cache(model_spec) use_fp16 = kwargs.pop("use_fp16", False) - model = RerankModel(model_uid, model_path, use_fp16=use_fp16, model_config=kwargs) + model = RerankModel( + model_spec, model_uid, model_path, use_fp16=use_fp16, model_config=kwargs + ) model_description = RerankModelDescription( subpool_addr, devices, model_spec, model_path=model_path ) diff --git a/xinference/model/rerank/custom.py b/xinference/model/rerank/custom.py index 12c86f3942..d81ee48986 100644 --- a/xinference/model/rerank/custom.py +++ b/xinference/model/rerank/custom.py @@ -48,6 +48,10 @@ def register_rerank(model_spec: CustomRerankModelSpec, persist: bool): if not is_valid_model_name(model_spec.model_name): raise ValueError(f"Invalid model name {model_spec.model_name}.") + model_uri = model_spec.model_uri + if model_uri and not is_valid_model_uri(model_uri): + raise ValueError(f"Invalid model URI {model_uri}.") + with UD_RERANK_LOCK: for model_name in ( list(BUILTIN_RERANK_MODELS.keys()) @@ -62,11 +66,6 @@ def register_rerank(model_spec: CustomRerankModelSpec, persist: bool): UD_RERANKS.append(model_spec) if persist: - # We only validate model URL when persist is True. - model_uri = model_spec.model_uri - if model_uri and not is_valid_model_uri(model_uri): - raise ValueError(f"Invalid model URI {model_uri}.") - persist_path = os.path.join( XINFERENCE_MODEL_DIR, "rerank", f"{model_spec.model_name}.json" ) diff --git a/xinference/model/rerank/model_spec.json b/xinference/model/rerank/model_spec.json index 34f62dfba4..e537a3d6d6 100644 --- a/xinference/model/rerank/model_spec.json +++ b/xinference/model/rerank/model_spec.json @@ -1,20 +1,51 @@ [ { "model_name": "bge-reranker-large", + "type": "normal", "language": ["en", "zh"], "model_id": "BAAI/bge-reranker-large", "model_revision": "27c9168d479987529781de8474dff94d69beca11" }, { "model_name": "bge-reranker-base", + "type": "normal", "language": ["en", "zh"], "model_id": "BAAI/bge-reranker-base", "model_revision": "465b4b7ddf2be0a020c8ad6e525b9bb1dbb708ae" }, { "model_name": "bce-reranker-base_v1", + "type": "normal", "language": ["en", "zh"], "model_id": "maidalun1020/bce-reranker-base_v1", "model_revision": "eaa31a577a0574e87a08959bd229ca14ce1b5496" + }, + { + "model_name": "bge-reranker-v2-m3", + "type": "normal", + "language": ["en", "zh", "multilingual"], + "model_id": "BAAI/bge-reranker-v2-m3", + "model_revision": "12e974610ba9083ed95f3edf08d7e899581f4de4" + }, + { + "model_name": "bge-reranker-v2-gemma", + "type": "LLM-based", + "language": ["en", "zh", "multilingual"], + "model_id": "BAAI/bge-reranker-v2-gemma", + "model_revision": "1787044f8b6fb740a9de4557c3a12377f84d9e17" + }, + { + "model_name": "bge-reranker-v2-minicpm-layerwise", + "type": "LLM-based layerwise", + "language": ["en", "zh", "multilingual"], + "model_id": "BAAI/bge-reranker-v2-minicpm-layerwise", + "model_revision": "47b5332b296c4d8cb6ee2c60502cc62a0d708881" + }, + { + "model_name": "jina-reranker-v2", + "type": "normal", + "language": ["en", "zh", "multilingual"], + "model_id": "jinaai/jina-reranker-v2-base-multilingual", + "model_revision": "298e48cada4a9318650d7fbd795f63827f884087" } ] diff --git a/xinference/model/rerank/model_spec_modelscope.json b/xinference/model/rerank/model_spec_modelscope.json index 29b39bed5d..68b2b1aea7 100644 --- a/xinference/model/rerank/model_spec_modelscope.json +++ b/xinference/model/rerank/model_spec_modelscope.json @@ -1,6 +1,7 @@ [ { "model_name": "bge-reranker-base", + "type": "normal", "language": ["en", "zh"], "model_id": "Xorbits/bge-reranker-base", "model_revision": "v0.0.1", @@ -8,16 +9,39 @@ }, { "model_name": "bge-reranker-large", + "type": "normal", "language": ["en", "zh"], "model_id": "Xorbits/bge-reranker-large", "model_revision": "v0.0.1", "model_hub": "modelscope" }, - { + { "model_name": "bce-reranker-base_v1", + "type": "normal", "language": ["en", "zh"], "model_id": "maidalun/bce-reranker-base_v1", "model_revision": "v0.0.1", "model_hub": "modelscope" + }, + { + "model_name": "bge-reranker-v2-m3", + "type": "normal", + "language": ["en", "zh", "multilingual"], + "model_id": "AI-ModelScope/bge-reranker-v2-m3", + "model_hub": "modelscope" + }, + { + "model_name": "bge-reranker-v2-gemma", + "type": "LLM-based", + "language": ["en", "zh", "multilingual"], + "model_id": "AI-ModelScope/bge-reranker-v2-gemma", + "model_hub": "modelscope" + }, + { + "model_name": "bge-reranker-v2-minicpm-layerwise", + "type": "LLM-based layerwise", + "language": ["en", "zh", "multilingual"], + "model_id": "zfffff/bge-reranker-v2-minicpm-layerwise", + "model_hub": "modelscope" } ] diff --git a/xinference/model/rerank/tests/test_rerank.py b/xinference/model/rerank/tests/test_rerank.py index 94f7e0d9fc..057432005c 100644 --- a/xinference/model/rerank/tests/test_rerank.py +++ b/xinference/model/rerank/tests/test_rerank.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import json import os import shutil import tempfile @@ -20,11 +21,12 @@ from ....client import Client -def test_restful_api(setup): +@pytest.mark.parametrize("model_name", ["bge-reranker-base", "bge-reranker-v2-m3"]) +def test_restful_api(model_name, setup): endpoint, _ = setup client = Client(endpoint) - model_uid = client.launch_model(model_name="bge-reranker-base", model_type="rerank") + model_uid = client.launch_model(model_name=model_name, model_type="rerank") assert len(client.list_models()) == 1 model = client.get_model(model_uid) # We want to compute the similarity between the query sentence @@ -43,14 +45,27 @@ def test_restful_api(setup): "A cheetah is running behind its prey.", ] - scores = model.rerank(corpus, query) + scores = model.rerank(corpus, query, return_documents=True) assert scores["results"][0]["index"] == 0 - assert scores["results"][0]["document"] == corpus[0] + assert scores["results"][0]["document"]["text"] == corpus[0] - scores = model.rerank(corpus, query, top_n=3) + scores = model.rerank(corpus, query, top_n=3, return_documents=True) assert len(scores["results"]) == 3 assert scores["results"][0]["index"] == 0 - assert scores["results"][0]["document"] == corpus[0] + assert scores["results"][0]["document"]["text"] == corpus[0] + + scores = model.rerank(corpus, query, return_len=True) + assert ( + scores["meta"]["tokens"]["input_tokens"] + == scores["meta"]["tokens"]["output_tokens"] + ) + + print(scores) + + scores = model.rerank(corpus, query) + assert scores["meta"]["tokens"] == None + + print(scores) kwargs = { "invalid": "invalid", @@ -106,7 +121,8 @@ def test_register_custom_rerank(): language=["zh"], model_uri="file:///c/d", ) - register_rerank(model_spec, False) + with pytest.raises(ValueError): + register_rerank(model_spec, False) # name conflict model_spec = CustomRerankModelSpec( @@ -125,3 +141,17 @@ def test_register_custom_rerank(): unregister_rerank("custom_test_d") shutil.rmtree(tmp_dir, ignore_errors=True) + + +def test_auto_detect_type(): + from ..core import RerankModel + + rerank_model_json = os.path.join(os.path.dirname(__file__), "../model_spec.json") + with open(rerank_model_json, "r") as f: + rerank_models = json.load(f) + for m in rerank_models: + try: + assert m["type"] == RerankModel._auto_detect_type(m["model_id"]) + except EnvironmentError: + # gated repo, ignore + continue diff --git a/xinference/model/utils.py b/xinference/model/utils.py index 8e15a31365..e03e3da69c 100644 --- a/xinference/model/utils.py +++ b/xinference/model/utils.py @@ -11,22 +11,29 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + +import functools +import gc +import inspect import json import logging import os -import shutil +import random from json import JSONDecodeError from pathlib import Path -from typing import Any, Callable, Dict, Optional, Tuple +from typing import Any, Callable, Dict, Optional, Tuple, Union -from fsspec import AbstractFileSystem +import huggingface_hub +import numpy as np +import torch from ..constants import XINFERENCE_CACHE_DIR, XINFERENCE_ENV_MODEL_SRC -from ..device_utils import get_available_device, is_device_available +from ..device_utils import empty_cache, get_available_device, is_device_available from .core import CacheableModelSpec logger = logging.getLogger(__name__) MAX_ATTEMPTS = 3 +IS_NEW_HUGGINGFACE_HUB: bool = huggingface_hub.__version__ >= "0.23.0" def is_locale_chinese_simplified() -> bool: @@ -40,14 +47,20 @@ def is_locale_chinese_simplified() -> bool: def download_from_modelscope() -> bool: - if os.environ.get(XINFERENCE_ENV_MODEL_SRC) == "modelscope": - return True + if os.environ.get(XINFERENCE_ENV_MODEL_SRC): + return os.environ.get(XINFERENCE_ENV_MODEL_SRC) == "modelscope" elif is_locale_chinese_simplified(): return True else: return False +def download_from_csghub() -> bool: + if os.environ.get(XINFERENCE_ENV_MODEL_SRC) == "csghub": + return True + return False + + def symlink_local_file(path: str, local_dir: str, relpath: str) -> str: from huggingface_hub.file_download import _create_symlink @@ -76,6 +89,13 @@ def symlink_local_file(path: str, local_dir: str, relpath: str) -> str: return local_dir_filepath +def create_symlink(download_dir: str, cache_dir: str): + for subdir, dirs, files in os.walk(download_dir): + for file in files: + relpath = os.path.relpath(os.path.join(subdir, file), download_dir) + symlink_local_file(os.path.join(subdir, file), cache_dir, relpath) + + def retry_download( download_func: Callable, model_name: str, @@ -205,12 +225,7 @@ def is_valid_model_uri(model_uri: Optional[str]) -> bool: return True -def cache_from_uri( - model_spec: CacheableModelSpec, - self_hosted_storage: bool = False, -) -> str: - from fsspec import AbstractFileSystem, filesystem - +def cache_from_uri(model_spec: CacheableModelSpec) -> str: cache_dir = os.path.realpath( os.path.join(XINFERENCE_CACHE_DIR, model_spec.model_name) ) @@ -232,48 +247,6 @@ def cache_from_uri( os.makedirs(XINFERENCE_CACHE_DIR, exist_ok=True) os.symlink(src_root, cache_dir, target_is_directory=True) return cache_dir - elif src_scheme in ["s3"]: - # use anonymous connection for self-hosted storage. - src_fs: AbstractFileSystem = filesystem(src_scheme, anon=self_hosted_storage) - local_fs: AbstractFileSystem = filesystem("file") - - files_to_download = [] - os.makedirs(cache_dir, exist_ok=True) - - for path, _, files in src_fs.walk(model_spec.model_uri): - for file in files: - src_path = f"{path}/{file}" - local_path = src_path.replace(src_root, cache_dir) - files_to_download.append((src_path, local_path)) - - from concurrent.futures import ThreadPoolExecutor - - failed = False - with ThreadPoolExecutor(max_workers=min(len(files_to_download), 4)) as executor: - futures = [ - ( - src_path, - executor.submit( - copy_from_src_to_dst, src_fs, src_path, local_fs, local_path - ), - ) - for src_path, local_path in files_to_download - ] - for src_path, future in futures: - if failed: - future.cancel() - else: - try: - future.result() - except: - logger.error(f"Download {src_path} failed", exc_info=True) - failed = True - - if failed: - logger.warning(f"Removing cache directory: {cache_dir}") - shutil.rmtree(cache_dir, ignore_errors=True) - raise RuntimeError(f"Failed to download model '{model_spec.model_name}' ") - return cache_dir else: raise ValueError(f"Unsupported URL scheme: {src_scheme}") @@ -306,22 +279,23 @@ def cache(model_spec: CacheableModelSpec, model_description_type: type): model_spec.model_id, revision=model_spec.model_revision, ) - for subdir, dirs, files in os.walk(download_dir): - for file in files: - relpath = os.path.relpath(os.path.join(subdir, file), download_dir) - symlink_local_file(os.path.join(subdir, file), cache_dir, relpath) + create_symlink(download_dir, cache_dir) else: from huggingface_hub import snapshot_download as hf_download - retry_download( + use_symlinks = {} + if not IS_NEW_HUGGINGFACE_HUB: + use_symlinks = {"local_dir_use_symlinks": True, "local_dir": cache_dir} + download_dir = retry_download( hf_download, model_spec.model_name, None, model_spec.model_id, revision=model_spec.model_revision, - local_dir=cache_dir, - local_dir_use_symlinks=True, + **use_symlinks, ) + if IS_NEW_HUGGINGFACE_HUB: + create_symlink(download_dir, cache_dir) with open(meta_path, "w") as f: import json @@ -330,51 +304,6 @@ def cache(model_spec: CacheableModelSpec, model_description_type: type): return cache_dir -def copy_from_src_to_dst( - _src_fs: "AbstractFileSystem", - _src_path: str, - dst_fs: "AbstractFileSystem", - dst_path: str, - max_attempt: int = 3, -): - from tqdm import tqdm - - for attempt in range(max_attempt): - logger.info(f"Copy from {_src_path} to {dst_path}, attempt: {attempt}") - try: - with _src_fs.open(_src_path, "rb") as src_file: - file_size = _src_fs.info(_src_path)["size"] - - dst_fs.makedirs(os.path.dirname(dst_path), exist_ok=True) - with dst_fs.open(dst_path, "wb") as dst_file: - chunk_size = 1024 * 1024 # 1 MB - - with tqdm( - total=file_size, - unit="B", - unit_scale=True, - unit_divisor=1024, - desc=_src_path, - ) as pbar: - while True: - chunk = src_file.read(chunk_size) - if not chunk: - break - dst_file.write(chunk) - pbar.update(len(chunk)) - logger.info( - f"Copy from {_src_path} to {dst_path} finished, attempt: {attempt}" - ) - break - except: - logger.error( - f"Failed to copy from {_src_path} to {dst_path} on attempt {attempt + 1}", - exc_info=True, - ) - if attempt + 1 == max_attempt: - raise - - def patch_trust_remote_code(): """sentence-transformers calls transformers without the trust_remote_code=True, some embedding models will fail to load, e.g. jina-embeddings-v2-base-en @@ -415,3 +344,47 @@ def select_device(device): raise ValueError(f"{device} is unavailable in your environment") return device + + +def convert_float_to_int_or_str(model_size: float) -> Union[int, str]: + """convert float to int or string + + if float can be presented as int, convert it to int, otherwise convert it to string + """ + if int(model_size) == model_size: + return int(model_size) + else: + return str(model_size) + + +def ensure_cache_cleared(func: Callable): + assert not inspect.iscoroutinefunction(func) and not inspect.isasyncgenfunction( + func + ) + if inspect.isgeneratorfunction(func): + + @functools.wraps(func) + def inner(*args, **kwargs): + for obj in func(*args, **kwargs): + yield obj + gc.collect() + empty_cache() + + else: + + @functools.wraps(func) + def inner(*args, **kwargs): + try: + return func(*args, **kwargs) + finally: + gc.collect() + empty_cache() + + return inner + + +def set_all_random_seed(seed: int): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) diff --git a/xinference/model/video/__init__.py b/xinference/model/video/__init__.py new file mode 100644 index 0000000000..e1325b0bbb --- /dev/null +++ b/xinference/model/video/__init__.py @@ -0,0 +1,62 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import codecs +import json +import os +from itertools import chain + +from .core import ( + BUILTIN_VIDEO_MODELS, + MODEL_NAME_TO_REVISION, + MODELSCOPE_VIDEO_MODELS, + VIDEO_MODEL_DESCRIPTIONS, + VideoModelFamilyV1, + generate_video_description, + get_cache_status, + get_video_model_descriptions, +) + +_model_spec_json = os.path.join(os.path.dirname(__file__), "model_spec.json") +_model_spec_modelscope_json = os.path.join( + os.path.dirname(__file__), "model_spec_modelscope.json" +) +BUILTIN_VIDEO_MODELS.update( + dict( + (spec["model_name"], VideoModelFamilyV1(**spec)) + for spec in json.load(codecs.open(_model_spec_json, "r", encoding="utf-8")) + ) +) +for model_name, model_spec in BUILTIN_VIDEO_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) + +MODELSCOPE_VIDEO_MODELS.update( + dict( + (spec["model_name"], VideoModelFamilyV1(**spec)) + for spec in json.load( + codecs.open(_model_spec_modelscope_json, "r", encoding="utf-8") + ) + ) +) +for model_name, model_spec in MODELSCOPE_VIDEO_MODELS.items(): + MODEL_NAME_TO_REVISION[model_name].append(model_spec.model_revision) + +# register model description +for model_name, model_spec in chain( + MODELSCOPE_VIDEO_MODELS.items(), BUILTIN_VIDEO_MODELS.items() +): + VIDEO_MODEL_DESCRIPTIONS.update(generate_video_description(model_spec)) + +del _model_spec_json +del _model_spec_modelscope_json diff --git a/xinference/model/video/core.py b/xinference/model/video/core.py new file mode 100644 index 0000000000..c81cd89b22 --- /dev/null +++ b/xinference/model/video/core.py @@ -0,0 +1,180 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import os +from collections import defaultdict +from typing import Any, Dict, List, Literal, Optional, Tuple + +from ...constants import XINFERENCE_CACHE_DIR +from ..core import CacheableModelSpec, ModelDescription +from ..utils import valid_model_revision +from .diffusers import DiffUsersVideoModel + +MAX_ATTEMPTS = 3 + +logger = logging.getLogger(__name__) + +MODEL_NAME_TO_REVISION: Dict[str, List[str]] = defaultdict(list) +VIDEO_MODEL_DESCRIPTIONS: Dict[str, List[Dict]] = defaultdict(list) +BUILTIN_VIDEO_MODELS: Dict[str, "VideoModelFamilyV1"] = {} +MODELSCOPE_VIDEO_MODELS: Dict[str, "VideoModelFamilyV1"] = {} + + +def get_video_model_descriptions(): + import copy + + return copy.deepcopy(VIDEO_MODEL_DESCRIPTIONS) + + +class VideoModelFamilyV1(CacheableModelSpec): + model_family: str + model_name: str + model_id: str + model_revision: str + model_hub: str = "huggingface" + model_ability: Optional[List[str]] + default_model_config: Optional[Dict[str, Any]] + default_generate_config: Optional[Dict[str, Any]] + + +class VideoModelDescription(ModelDescription): + def __init__( + self, + address: Optional[str], + devices: Optional[List[str]], + model_spec: VideoModelFamilyV1, + model_path: Optional[str] = None, + ): + super().__init__(address, devices, model_path=model_path) + self._model_spec = model_spec + + def to_dict(self): + return { + "model_type": "video", + "address": self.address, + "accelerators": self.devices, + "model_name": self._model_spec.model_name, + "model_family": self._model_spec.model_family, + "model_revision": self._model_spec.model_revision, + "model_ability": self._model_spec.model_ability, + } + + def to_version_info(self): + if self._model_path is None: + is_cached = get_cache_status(self._model_spec) + file_location = get_cache_dir(self._model_spec) + else: + is_cached = True + file_location = self._model_path + + return [ + { + "model_version": self._model_spec.model_name, + "model_file_location": file_location, + "cache_status": is_cached, + } + ] + + +def generate_video_description( + video_model: VideoModelFamilyV1, +) -> Dict[str, List[Dict]]: + res = defaultdict(list) + res[video_model.model_name].extend( + VideoModelDescription(None, None, video_model).to_version_info() + ) + return res + + +def match_diffusion( + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, +) -> VideoModelFamilyV1: + from ..utils import download_from_modelscope + from . import BUILTIN_VIDEO_MODELS, MODELSCOPE_VIDEO_MODELS + + if download_hub == "modelscope" and model_name in MODELSCOPE_VIDEO_MODELS: + logger.debug(f"Video model {model_name} found in ModelScope.") + return MODELSCOPE_VIDEO_MODELS[model_name] + elif download_hub == "huggingface" and model_name in BUILTIN_VIDEO_MODELS: + logger.debug(f"Video model {model_name} found in Huggingface.") + return BUILTIN_VIDEO_MODELS[model_name] + elif download_from_modelscope() and model_name in MODELSCOPE_VIDEO_MODELS: + logger.debug(f"Video model {model_name} found in ModelScope.") + return MODELSCOPE_VIDEO_MODELS[model_name] + elif model_name in BUILTIN_VIDEO_MODELS: + logger.debug(f"Video model {model_name} found in Huggingface.") + return BUILTIN_VIDEO_MODELS[model_name] + else: + raise ValueError( + f"Video model {model_name} not found, available" + f"model list: {BUILTIN_VIDEO_MODELS.keys()}" + ) + + +def cache(model_spec: VideoModelFamilyV1): + from ..utils import cache + + return cache(model_spec, VideoModelDescription) + + +def get_cache_dir(model_spec: VideoModelFamilyV1): + return os.path.realpath(os.path.join(XINFERENCE_CACHE_DIR, model_spec.model_name)) + + +def get_cache_status( + model_spec: VideoModelFamilyV1, +) -> bool: + cache_dir = get_cache_dir(model_spec) + meta_path = os.path.join(cache_dir, "__valid_download") + + model_name = model_spec.model_name + if model_name in BUILTIN_VIDEO_MODELS and model_name in MODELSCOPE_VIDEO_MODELS: + hf_spec = BUILTIN_VIDEO_MODELS[model_name] + ms_spec = MODELSCOPE_VIDEO_MODELS[model_name] + + return any( + [ + valid_model_revision(meta_path, hf_spec.model_revision), + valid_model_revision(meta_path, ms_spec.model_revision), + ] + ) + else: # Usually for UT + return valid_model_revision(meta_path, model_spec.model_revision) + + +def create_video_model_instance( + subpool_addr: str, + devices: List[str], + model_uid: str, + model_name: str, + download_hub: Optional[Literal["huggingface", "modelscope", "csghub"]] = None, + model_path: Optional[str] = None, + **kwargs, +) -> Tuple[DiffUsersVideoModel, VideoModelDescription]: + model_spec = match_diffusion(model_name, download_hub) + if not model_path: + model_path = cache(model_spec) + assert model_path is not None + + model = DiffUsersVideoModel( + model_uid, + model_path, + model_spec, + **kwargs, + ) + model_description = VideoModelDescription( + subpool_addr, devices, model_spec, model_path=model_path + ) + return model, model_description diff --git a/xinference/model/video/diffusers.py b/xinference/model/video/diffusers.py new file mode 100644 index 0000000000..3c2f801a56 --- /dev/null +++ b/xinference/model/video/diffusers.py @@ -0,0 +1,183 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import logging +import os +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from functools import partial +from typing import TYPE_CHECKING, List, Union + +import numpy as np +import PIL.Image + +from ...constants import XINFERENCE_VIDEO_DIR +from ...device_utils import gpu_count, move_model_to_available_device +from ...types import Video, VideoList + +if TYPE_CHECKING: + from .core import VideoModelFamilyV1 + + +logger = logging.getLogger(__name__) + + +def export_to_video_imageio( + video_frames: Union[List[np.ndarray], List["PIL.Image.Image"]], + output_video_path: str, + fps: int = 8, +) -> str: + """ + Export the video frames to a video file using imageio lib to Avoid "green screen" issue (for example CogVideoX) + """ + import imageio + + if isinstance(video_frames[0], PIL.Image.Image): + video_frames = [np.array(frame) for frame in video_frames] + with imageio.get_writer(output_video_path, fps=fps) as writer: + for frame in video_frames: + writer.append_data(frame) + return output_video_path + + +class DiffUsersVideoModel: + def __init__( + self, + model_uid: str, + model_path: str, + model_spec: "VideoModelFamilyV1", + **kwargs, + ): + self._model_uid = model_uid + self._model_path = model_path + self._model_spec = model_spec + self._model = None + self._kwargs = kwargs + + @property + def model_spec(self): + return self._model_spec + + def load(self): + import torch + + kwargs = self._model_spec.default_model_config.copy() + kwargs.update(self._kwargs) + + scheduler_cls_name = kwargs.pop("scheduler", None) + + torch_dtype = kwargs.get("torch_dtype") + if isinstance(torch_dtype, str): + kwargs["torch_dtype"] = getattr(torch, torch_dtype) + logger.debug("Loading video model with kwargs: %s", kwargs) + + if self._model_spec.model_family == "CogVideoX": + import diffusers + from diffusers import CogVideoXPipeline + + pipeline = self._model = CogVideoXPipeline.from_pretrained( + self._model_path, **kwargs + ) + else: + raise Exception( + f"Unsupported model family: {self._model_spec.model_family}" + ) + + if scheduler_cls_name: + logger.debug("Using scheduler: %s", scheduler_cls_name) + pipeline.scheduler = getattr(diffusers, scheduler_cls_name).from_config( + pipeline.scheduler.config, timestep_spacing="trailing" + ) + if kwargs.get("compile_graph", False): + pipeline.transformer = torch.compile( + pipeline.transformer, mode="max-autotune", fullgraph=True + ) + if kwargs.get("cpu_offload", False): + logger.debug("CPU offloading model") + pipeline.enable_model_cpu_offload() + if kwargs.get("sequential_cpu_offload", True): + pipeline.enable_sequential_cpu_offload() + pipeline.vae.enable_slicing() + pipeline.vae.enable_tiling() + elif not kwargs.get("device_map"): + logger.debug("Loading model to available device") + if gpu_count() > 1: + kwargs["device_map"] = "balanced" + else: + pipeline = move_model_to_available_device(self._model) + # Recommended if your computer has < 64 GB of RAM + pipeline.enable_attention_slicing() + + def text_to_video( + self, + prompt: str, + n: int = 1, + num_inference_steps: int = 50, + response_format: str = "b64_json", + **kwargs, + ) -> VideoList: + import gc + + # cv2 bug will cause the video cannot be normally displayed + # thus we use the imageio one + # from diffusers.utils import export_to_video + from ...device_utils import empty_cache + + assert self._model is not None + assert callable(self._model) + generate_kwargs = self._model_spec.default_generate_config.copy() + generate_kwargs.update(kwargs) + generate_kwargs["num_videos_per_prompt"] = n + logger.debug( + "diffusers text_to_video args: %s", + generate_kwargs, + ) + output = self._model( + prompt=prompt, + num_inference_steps=num_inference_steps, + **generate_kwargs, + ) + + # clean cache + gc.collect() + empty_cache() + + os.makedirs(XINFERENCE_VIDEO_DIR, exist_ok=True) + urls = [] + for f in output.frames: + path = os.path.join(XINFERENCE_VIDEO_DIR, uuid.uuid4().hex + ".mp4") + p = export_to_video_imageio(f, path, fps=8) + urls.append(p) + if response_format == "url": + return VideoList( + created=int(time.time()), + data=[Video(url=url, b64_json=None) for url in urls], + ) + elif response_format == "b64_json": + + def _gen_base64_video(_video_url): + try: + with open(_video_url, "rb") as f: + return base64.b64encode(f.read()).decode() + finally: + os.remove(_video_url) + + with ThreadPoolExecutor() as executor: + results = list(map(partial(executor.submit, _gen_base64_video), urls)) # type: ignore + video_list = [Video(url=None, b64_json=s.result()) for s in results] + return VideoList(created=int(time.time()), data=video_list) + else: + raise ValueError(f"Unsupported response format: {response_format}") diff --git a/xinference/model/video/model_spec.json b/xinference/model/video/model_spec.json new file mode 100644 index 0000000000..515467ab40 --- /dev/null +++ b/xinference/model/video/model_spec.json @@ -0,0 +1,34 @@ +[ + { + "model_name": "CogVideoX-2b", + "model_family": "CogVideoX", + "model_id": "THUDM/CogVideoX-2b", + "model_revision": "4bbfb1de622b80bc1b77b6e9aced75f816be0e38", + "model_ability": [ + "text2video" + ], + "default_model_config": { + "scheduler": "CogVideoXDDIMScheduler", + "torch_dtype": "float16" + }, + "default_generate_config": { + "guidance_scale": 6 + } + }, + { + "model_name": "CogVideoX-5b", + "model_family": "CogVideoX", + "model_id": "THUDM/CogVideoX-5b", + "model_revision": "8d6ea3f817438460b25595a120f109b88d5fdfad", + "model_ability": [ + "text2video" + ], + "default_model_config": { + "scheduler": "CogVideoXDPMScheduler", + "torch_dtype": "bfloat16" + }, + "default_generate_config": { + "guidance_scale": 7 + } + } +] diff --git a/xinference/model/video/model_spec_modelscope.json b/xinference/model/video/model_spec_modelscope.json new file mode 100644 index 0000000000..edf5f0073d --- /dev/null +++ b/xinference/model/video/model_spec_modelscope.json @@ -0,0 +1,36 @@ +[ + { + "model_name": "CogVideoX-2b", + "model_family": "CogVideoX", + "model_hub": "modelscope", + "model_id": "ZhipuAI/CogVideoX-2b", + "model_revision": "master", + "model_ability": [ + "text2video" + ], + "default_model_config": { + "scheduler": "CogVideoXDDIMScheduler", + "torch_dtype": "float16" + }, + "default_generate_config": { + "guidance_scale": 6 + } + }, + { + "model_name": "CogVideoX-5b", + "model_family": "CogVideoX", + "model_hub": "modelscope", + "model_id": "ZhipuAI/CogVideoX-5b", + "model_revision": "master", + "model_ability": [ + "text2video" + ], + "default_model_config": { + "scheduler": "CogVideoXDPMScheduler", + "torch_dtype": "bfloat16" + }, + "default_generate_config": { + "guidance_scale": 7 + } + } +] diff --git a/xinference/model/video/tests/__init__.py b/xinference/model/video/tests/__init__.py new file mode 100644 index 0000000000..37f6558d95 --- /dev/null +++ b/xinference/model/video/tests/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/xinference/model/video/tests/test_diffusers_video.py b/xinference/model/video/tests/test_diffusers_video.py new file mode 100644 index 0000000000..3676612c05 --- /dev/null +++ b/xinference/model/video/tests/test_diffusers_video.py @@ -0,0 +1,63 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging + +import pytest + +from .. import BUILTIN_VIDEO_MODELS +from ..core import cache +from ..diffusers import DiffUsersVideoModel + +logger = logging.getLogger(__name__) + + +@pytest.mark.skip(reason="Video model requires too many GRAM.") +def test_model(): + test_model_spec = next(iter(BUILTIN_VIDEO_MODELS.values())) + model_path = cache(test_model_spec) + model = DiffUsersVideoModel("mock", model_path, test_model_spec) + # input is a string + input_text = "an apple" + model.load() + r = model.text_to_image(input_text) + assert r + + +@pytest.mark.skip(reason="Video model requires too many GRAM.") +def test_client(setup): + endpoint, _ = setup + from ....client import Client + + client = Client(endpoint) + + model_uid = client.launch_model( + model_uid="my_video_model", + model_name="CogVideoX-2b", + model_type="video", + ) + model = client.get_model(model_uid) + assert model + + r = model.text_to_video( + prompt="A panda, dressed in a small, red jacket and a tiny hat, " + "sits on a wooden stool in a serene bamboo forest. " + "The panda's fluffy paws strum a miniature acoustic guitar, " + "producing soft, melodic tunes. Nearby, a few other pandas gather, " + "watching curiously and some clapping in rhythm. " + "Sunlight filters through the tall bamboo, casting a gentle glow on the scene. " + "The panda's face is expressive, showing concentration and joy as it plays. " + "The background includes a small, flowing stream and vibrant green foliage, " + "enhancing the peaceful and magical atmosphere of this unique musical performance." + ) + assert r diff --git a/xinference/thirdparty/cosyvoice/__init__.py b/xinference/thirdparty/cosyvoice/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/bin/__init__.py b/xinference/thirdparty/cosyvoice/bin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/bin/inference.py b/xinference/thirdparty/cosyvoice/bin/inference.py new file mode 100644 index 0000000000..6b777fa1cb --- /dev/null +++ b/xinference/thirdparty/cosyvoice/bin/inference.py @@ -0,0 +1,114 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import argparse +import logging +logging.getLogger('matplotlib').setLevel(logging.WARNING) +import os + +import torch +from torch.utils.data import DataLoader +import torchaudio +from hyperpyyaml import load_hyperpyyaml +from tqdm import tqdm +from cosyvoice.cli.model import CosyVoiceModel + +from cosyvoice.dataset.dataset import Dataset + +def get_args(): + parser = argparse.ArgumentParser(description='inference with your model') + parser.add_argument('--config', required=True, help='config file') + parser.add_argument('--prompt_data', required=True, help='prompt data file') + parser.add_argument('--prompt_utt2data', required=True, help='prompt data file') + parser.add_argument('--tts_text', required=True, help='tts input file') + parser.add_argument('--llm_model', required=True, help='llm model file') + parser.add_argument('--flow_model', required=True, help='flow model file') + parser.add_argument('--hifigan_model', required=True, help='hifigan model file') + parser.add_argument('--gpu', + type=int, + default=-1, + help='gpu id for this rank, -1 for cpu') + parser.add_argument('--mode', + default='sft', + choices=['sft', 'zero_shot'], + help='inference mode') + parser.add_argument('--result_dir', required=True, help='asr result file') + args = parser.parse_args() + print(args) + return args + + +def main(): + args = get_args() + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(levelname)s %(message)s') + os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu) + + # Init cosyvoice models from configs + use_cuda = args.gpu >= 0 and torch.cuda.is_available() + device = torch.device('cuda' if use_cuda else 'cpu') + with open(args.config, 'r') as f: + configs = load_hyperpyyaml(f) + + model = CosyVoiceModel(configs['llm'], configs['flow'], configs['hift']) + model.load(args.llm_model, args.flow_model, args.hifigan_model) + + test_dataset = Dataset(args.prompt_data, data_pipeline=configs['data_pipeline'], mode='inference', shuffle=False, partition=False, tts_file=args.tts_text, prompt_utt2data=args.prompt_utt2data) + test_data_loader = DataLoader(test_dataset, batch_size=None, num_workers=0) + + del configs + os.makedirs(args.result_dir, exist_ok=True) + fn = os.path.join(args.result_dir, 'wav.scp') + f = open(fn, 'w') + with torch.no_grad(): + for batch_idx, batch in tqdm(enumerate(test_data_loader)): + utts = batch["utts"] + assert len(utts) == 1, "inference mode only support batchsize 1" + text = batch["text"] + text_token = batch["text_token"].to(device) + text_token_len = batch["text_token_len"].to(device) + tts_text = batch["tts_text"] + tts_index = batch["tts_index"] + tts_text_token = batch["tts_text_token"].to(device) + tts_text_token_len = batch["tts_text_token_len"].to(device) + speech_token = batch["speech_token"].to(device) + speech_token_len = batch["speech_token_len"].to(device) + speech_feat = batch["speech_feat"].to(device) + speech_feat_len = batch["speech_feat_len"].to(device) + utt_embedding = batch["utt_embedding"].to(device) + spk_embedding = batch["spk_embedding"].to(device) + if args.mode == 'sft': + model_input = {'text': tts_text_token, 'text_len': tts_text_token_len, + 'llm_embedding': spk_embedding, 'flow_embedding': spk_embedding} + else: + model_input = {'text': tts_text_token, 'text_len': tts_text_token_len, + 'prompt_text': text_token, 'prompt_text_len': text_token_len, + 'llm_prompt_speech_token': speech_token, 'llm_prompt_speech_token_len': speech_token_len, + 'flow_prompt_speech_token': speech_token, 'flow_prompt_speech_token_len': speech_token_len, + 'prompt_speech_feat': speech_feat, 'prompt_speech_feat_len': speech_feat_len, + 'llm_embedding': utt_embedding, 'flow_embedding': utt_embedding} + model_output = model.inference(**model_input) + tts_key = '{}_{}'.format(utts[0], tts_index[0]) + tts_fn = os.path.join(args.result_dir, '{}.wav'.format(tts_key)) + torchaudio.save(tts_fn, model_output['tts_speech'], sample_rate=22050) + f.write('{} {}\n'.format(tts_key, tts_fn)) + f.flush() + f.close() + logging.info('Result wav.scp saved in {}'.format(fn)) + + +if __name__ == '__main__': + main() diff --git a/xinference/thirdparty/cosyvoice/bin/train.py b/xinference/thirdparty/cosyvoice/bin/train.py new file mode 100644 index 0000000000..a9d0e0581d --- /dev/null +++ b/xinference/thirdparty/cosyvoice/bin/train.py @@ -0,0 +1,136 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +import argparse +import datetime +import logging +logging.getLogger('matplotlib').setLevel(logging.WARNING) +from copy import deepcopy +import torch +import torch.distributed as dist +import deepspeed + +from hyperpyyaml import load_hyperpyyaml + +from torch.distributed.elastic.multiprocessing.errors import record + +from cosyvoice.utils.executor import Executor +from cosyvoice.utils.train_utils import ( + init_distributed, + init_dataset_and_dataloader, + init_optimizer_and_scheduler, + init_summarywriter, save_model, + wrap_cuda_model, check_modify_and_save_config) + + +def get_args(): + parser = argparse.ArgumentParser(description='training your network') + parser.add_argument('--train_engine', + default='torch_ddp', + choices=['torch_ddp', 'deepspeed'], + help='Engine for paralleled training') + parser.add_argument('--model', required=True, help='model which will be trained') + parser.add_argument('--config', required=True, help='config file') + parser.add_argument('--train_data', required=True, help='train data file') + parser.add_argument('--cv_data', required=True, help='cv data file') + parser.add_argument('--checkpoint', help='checkpoint model') + parser.add_argument('--model_dir', required=True, help='save model dir') + parser.add_argument('--tensorboard_dir', + default='tensorboard', + help='tensorboard log dir') + parser.add_argument('--ddp.dist_backend', + dest='dist_backend', + default='nccl', + choices=['nccl', 'gloo'], + help='distributed backend') + parser.add_argument('--num_workers', + default=0, + type=int, + help='num of subprocess workers for reading') + parser.add_argument('--prefetch', + default=100, + type=int, + help='prefetch number') + parser.add_argument('--pin_memory', + action='store_true', + default=False, + help='Use pinned memory buffers used for reading') + parser.add_argument('--deepspeed.save_states', + dest='save_states', + default='model_only', + choices=['model_only', 'model+optimizer'], + help='save model/optimizer states') + parser.add_argument('--timeout', + default=30, + type=int, + help='timeout (in seconds) of cosyvoice_join.') + parser = deepspeed.add_config_arguments(parser) + args = parser.parse_args() + return args + + +@record +def main(): + args = get_args() + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(levelname)s %(message)s') + + override_dict = {k: None for k in ['llm', 'flow', 'hift'] if k != args.model} + with open(args.config, 'r') as f: + configs = load_hyperpyyaml(f, overrides=override_dict) + configs['train_conf'].update(vars(args)) + + # Init env for ddp + init_distributed(args) + + # Get dataset & dataloader + train_dataset, cv_dataset, train_data_loader, cv_data_loader = \ + init_dataset_and_dataloader(args, configs) + + # Do some sanity checks and save config to arsg.model_dir + configs = check_modify_and_save_config(args, configs) + + # Tensorboard summary + writer = init_summarywriter(args) + + # load checkpoint + model = configs[args.model] + if args.checkpoint is not None: + model.load_state_dict(torch.load(args.checkpoint, map_location='cpu')) + + # Dispatch model from cpu to gpu + model = wrap_cuda_model(args, model) + + # Get optimizer & scheduler + model, optimizer, scheduler = init_optimizer_and_scheduler(args, configs, model) + + # Save init checkpoints + info_dict = deepcopy(configs['train_conf']) + save_model(model, 'init', info_dict) + + # Get executor + executor = Executor() + + # Start training loop + for epoch in range(info_dict['max_epoch']): + executor.epoch = epoch + train_dataset.set_epoch(epoch) + dist.barrier() + group_join = dist.new_group(backend="gloo", timeout=datetime.timedelta(seconds=args.timeout)) + executor.train_one_epoc(model, optimizer, scheduler, train_data_loader, cv_data_loader, writer, info_dict, group_join) + dist.destroy_process_group(group_join) + +if __name__ == '__main__': + main() diff --git a/xinference/thirdparty/cosyvoice/cli/__init__.py b/xinference/thirdparty/cosyvoice/cli/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/cli/cosyvoice.py b/xinference/thirdparty/cosyvoice/cli/cosyvoice.py new file mode 100644 index 0000000000..ea8c448289 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/cli/cosyvoice.py @@ -0,0 +1,83 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import torch +from hyperpyyaml import load_hyperpyyaml +from modelscope import snapshot_download +from cosyvoice.cli.frontend import CosyVoiceFrontEnd +from cosyvoice.cli.model import CosyVoiceModel + +class CosyVoice: + + def __init__(self, model_dir): + instruct = True if '-Instruct' in model_dir else False + self.model_dir = model_dir + if not os.path.exists(model_dir): + model_dir = snapshot_download(model_dir) + with open('{}/cosyvoice.yaml'.format(model_dir), 'r') as f: + configs = load_hyperpyyaml(f) + self.frontend = CosyVoiceFrontEnd(configs['get_tokenizer'], + configs['feat_extractor'], + '{}/campplus.onnx'.format(model_dir), + '{}/speech_tokenizer_v1.onnx'.format(model_dir), + '{}/spk2info.pt'.format(model_dir), + instruct, + configs['allowed_special']) + self.model = CosyVoiceModel(configs['llm'], configs['flow'], configs['hift']) + self.model.load('{}/llm.pt'.format(model_dir), + '{}/flow.pt'.format(model_dir), + '{}/hift.pt'.format(model_dir)) + del configs + + def list_avaliable_spks(self): + spks = list(self.frontend.spk2info.keys()) + return spks + + def inference_sft(self, tts_text, spk_id): + tts_speeches = [] + for i in self.frontend.text_normalize(tts_text, split=True): + model_input = self.frontend.frontend_sft(i, spk_id) + model_output = self.model.inference(**model_input) + tts_speeches.append(model_output['tts_speech']) + return {'tts_speech': torch.concat(tts_speeches, dim=1)} + + def inference_zero_shot(self, tts_text, prompt_text, prompt_speech_16k): + prompt_text = self.frontend.text_normalize(prompt_text, split=False) + tts_speeches = [] + for i in self.frontend.text_normalize(tts_text, split=True): + model_input = self.frontend.frontend_zero_shot(i, prompt_text, prompt_speech_16k) + model_output = self.model.inference(**model_input) + tts_speeches.append(model_output['tts_speech']) + return {'tts_speech': torch.concat(tts_speeches, dim=1)} + + def inference_cross_lingual(self, tts_text, prompt_speech_16k): + if self.frontend.instruct is True: + raise ValueError('{} do not support cross_lingual inference'.format(self.model_dir)) + tts_speeches = [] + for i in self.frontend.text_normalize(tts_text, split=True): + model_input = self.frontend.frontend_cross_lingual(i, prompt_speech_16k) + model_output = self.model.inference(**model_input) + tts_speeches.append(model_output['tts_speech']) + return {'tts_speech': torch.concat(tts_speeches, dim=1)} + + def inference_instruct(self, tts_text, spk_id, instruct_text): + if self.frontend.instruct is False: + raise ValueError('{} do not support instruct inference'.format(self.model_dir)) + instruct_text = self.frontend.text_normalize(instruct_text, split=False) + tts_speeches = [] + for i in self.frontend.text_normalize(tts_text, split=True): + model_input = self.frontend.frontend_instruct(i, spk_id, instruct_text) + model_output = self.model.inference(**model_input) + tts_speeches.append(model_output['tts_speech']) + return {'tts_speech': torch.concat(tts_speeches, dim=1)} diff --git a/xinference/thirdparty/cosyvoice/cli/frontend.py b/xinference/thirdparty/cosyvoice/cli/frontend.py new file mode 100644 index 0000000000..3ed85500cd --- /dev/null +++ b/xinference/thirdparty/cosyvoice/cli/frontend.py @@ -0,0 +1,168 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from functools import partial +import onnxruntime +import torch +import numpy as np +import whisper +from typing import Callable +import torchaudio.compliance.kaldi as kaldi +import torchaudio +import os +import re +import inflect +try: + import ttsfrd + use_ttsfrd = True +except ImportError: + print("failed to import ttsfrd, use WeTextProcessing instead") + from tn.chinese.normalizer import Normalizer as ZhNormalizer + from tn.english.normalizer import Normalizer as EnNormalizer + use_ttsfrd = False +from cosyvoice.utils.frontend_utils import contains_chinese, replace_blank, replace_corner_mark, remove_bracket, spell_out_number, split_paragraph + + +class CosyVoiceFrontEnd: + + def __init__(self, + get_tokenizer: Callable, + feat_extractor: Callable, + campplus_model: str, + speech_tokenizer_model: str, + spk2info: str = '', + instruct: bool = False, + allowed_special: str = 'all'): + self.tokenizer = get_tokenizer() + self.feat_extractor = feat_extractor + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + option = onnxruntime.SessionOptions() + option.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL + option.intra_op_num_threads = 1 + self.campplus_session = onnxruntime.InferenceSession(campplus_model, sess_options=option, providers=["CPUExecutionProvider"]) + self.speech_tokenizer_session = onnxruntime.InferenceSession(speech_tokenizer_model, sess_options=option, providers=["CUDAExecutionProvider"if torch.cuda.is_available() else "CPUExecutionProvider"]) + if os.path.exists(spk2info): + self.spk2info = torch.load(spk2info, map_location=self.device) + self.instruct = instruct + self.allowed_special = allowed_special + self.inflect_parser = inflect.engine() + self.use_ttsfrd = use_ttsfrd + if self.use_ttsfrd: + self.frd = ttsfrd.TtsFrontendEngine() + ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) + assert self.frd.initialize('{}/../../pretrained_models/CosyVoice-ttsfrd/resource'.format(ROOT_DIR)) is True, 'failed to initialize ttsfrd resource' + self.frd.set_lang_type('pinyin') + self.frd.enable_pinyin_mix(True) + self.frd.set_breakmodel_index(1) + else: + self.zh_tn_model = ZhNormalizer(remove_erhua=False, full_to_half=False) + self.en_tn_model = EnNormalizer() + + def _extract_text_token(self, text): + text_token = self.tokenizer.encode(text, allowed_special=self.allowed_special) + text_token = torch.tensor([text_token], dtype=torch.int32).to(self.device) + text_token_len = torch.tensor([text_token.shape[1]], dtype=torch.int32).to(self.device) + return text_token, text_token_len + + def _extract_speech_token(self, speech): + feat = whisper.log_mel_spectrogram(speech, n_mels=128) + speech_token = self.speech_tokenizer_session.run(None, {self.speech_tokenizer_session.get_inputs()[0].name: feat.detach().cpu().numpy(), + self.speech_tokenizer_session.get_inputs()[1].name: np.array([feat.shape[2]], dtype=np.int32)})[0].flatten().tolist() + speech_token = torch.tensor([speech_token], dtype=torch.int32).to(self.device) + speech_token_len = torch.tensor([speech_token.shape[1]], dtype=torch.int32).to(self.device) + return speech_token, speech_token_len + + def _extract_spk_embedding(self, speech): + feat = kaldi.fbank(speech, + num_mel_bins=80, + dither=0, + sample_frequency=16000) + feat = feat - feat.mean(dim=0, keepdim=True) + embedding = self.campplus_session.run(None, {self.campplus_session.get_inputs()[0].name: feat.unsqueeze(dim=0).cpu().numpy()})[0].flatten().tolist() + embedding = torch.tensor([embedding]).to(self.device) + return embedding + + def _extract_speech_feat(self, speech): + speech_feat = self.feat_extractor(speech).squeeze(dim=0).transpose(0, 1).to(self.device) + speech_feat = speech_feat.unsqueeze(dim=0) + speech_feat_len = torch.tensor([speech_feat.shape[1]], dtype=torch.int32).to(self.device) + return speech_feat, speech_feat_len + + def text_normalize(self, text, split=True): + text = text.strip() + if contains_chinese(text): + if self.use_ttsfrd: + text = self.frd.get_frd_extra_info(text, 'input') + else: + text = self.zh_tn_model.normalize(text) + text = text.replace("\n", "") + text = replace_blank(text) + text = replace_corner_mark(text) + text = text.replace(".", "、") + text = text.replace(" - ", ",") + text = remove_bracket(text) + text = re.sub(r'[,,]+$', '。', text) + texts = [i for i in split_paragraph(text, partial(self.tokenizer.encode, allowed_special=self.allowed_special), "zh", token_max_n=80, + token_min_n=60, merge_len=20, + comma_split=False)] + else: + if self.use_ttsfrd: + text = self.frd.get_frd_extra_info(text, 'input') + else: + text = self.en_tn_model.normalize(text) + text = spell_out_number(text, self.inflect_parser) + texts = [i for i in split_paragraph(text, partial(self.tokenizer.encode, allowed_special=self.allowed_special), "en", token_max_n=80, + token_min_n=60, merge_len=20, + comma_split=False)] + if split is False: + return text + return texts + + def frontend_sft(self, tts_text, spk_id): + tts_text_token, tts_text_token_len = self._extract_text_token(tts_text) + embedding = self.spk2info[spk_id]['embedding'] + model_input = {'text': tts_text_token, 'text_len': tts_text_token_len, 'llm_embedding': embedding, 'flow_embedding': embedding} + return model_input + + def frontend_zero_shot(self, tts_text, prompt_text, prompt_speech_16k): + tts_text_token, tts_text_token_len = self._extract_text_token(tts_text) + prompt_text_token, prompt_text_token_len = self._extract_text_token(prompt_text) + prompt_speech_22050 = torchaudio.transforms.Resample(orig_freq=16000, new_freq=22050)(prompt_speech_16k) + speech_feat, speech_feat_len = self._extract_speech_feat(prompt_speech_22050) + speech_token, speech_token_len = self._extract_speech_token(prompt_speech_16k) + embedding = self._extract_spk_embedding(prompt_speech_16k) + model_input = {'text': tts_text_token, 'text_len': tts_text_token_len, + 'prompt_text': prompt_text_token, 'prompt_text_len': prompt_text_token_len, + 'llm_prompt_speech_token': speech_token, 'llm_prompt_speech_token_len': speech_token_len, + 'flow_prompt_speech_token': speech_token, 'flow_prompt_speech_token_len': speech_token_len, + 'prompt_speech_feat': speech_feat, 'prompt_speech_feat_len': speech_feat_len, + 'llm_embedding': embedding, 'flow_embedding': embedding} + return model_input + + def frontend_cross_lingual(self, tts_text, prompt_speech_16k): + model_input = self.frontend_zero_shot(tts_text, '', prompt_speech_16k) + # in cross lingual mode, we remove prompt in llm + del model_input['prompt_text'] + del model_input['prompt_text_len'] + del model_input['llm_prompt_speech_token'] + del model_input['llm_prompt_speech_token_len'] + return model_input + + def frontend_instruct(self, tts_text, spk_id, instruct_text): + model_input = self.frontend_sft(tts_text, spk_id) + # in instruct mode, we remove spk_embedding in llm due to information leakage + del model_input['llm_embedding'] + instruct_text_token, instruct_text_token_len = self._extract_text_token(instruct_text + '') + model_input['prompt_text'] = instruct_text_token + model_input['prompt_text_len'] = instruct_text_token_len + return model_input diff --git a/xinference/thirdparty/cosyvoice/cli/model.py b/xinference/thirdparty/cosyvoice/cli/model.py new file mode 100644 index 0000000000..f4625e396c --- /dev/null +++ b/xinference/thirdparty/cosyvoice/cli/model.py @@ -0,0 +1,60 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch + +class CosyVoiceModel: + + def __init__(self, + llm: torch.nn.Module, + flow: torch.nn.Module, + hift: torch.nn.Module): + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + self.llm = llm + self.flow = flow + self.hift = hift + + def load(self, llm_model, flow_model, hift_model): + self.llm.load_state_dict(torch.load(llm_model, map_location=self.device)) + self.llm.to(self.device).eval() + self.flow.load_state_dict(torch.load(flow_model, map_location=self.device)) + self.flow.to(self.device).eval() + self.hift.load_state_dict(torch.load(hift_model, map_location=self.device)) + self.hift.to(self.device).eval() + + def inference(self, text, text_len, flow_embedding, llm_embedding=torch.zeros(0, 192), + prompt_text=torch.zeros(1, 0, dtype=torch.int32), prompt_text_len=torch.zeros(1, dtype=torch.int32), + llm_prompt_speech_token=torch.zeros(1, 0, dtype=torch.int32), llm_prompt_speech_token_len=torch.zeros(1, dtype=torch.int32), + flow_prompt_speech_token=torch.zeros(1, 0, dtype=torch.int32), flow_prompt_speech_token_len=torch.zeros(1, dtype=torch.int32), + prompt_speech_feat=torch.zeros(1, 0, 80), prompt_speech_feat_len=torch.zeros(1, dtype=torch.int32)): + tts_speech_token = self.llm.inference(text=text.to(self.device), + text_len=text_len.to(self.device), + prompt_text=prompt_text.to(self.device), + prompt_text_len=prompt_text_len.to(self.device), + prompt_speech_token=llm_prompt_speech_token.to(self.device), + prompt_speech_token_len=llm_prompt_speech_token_len.to(self.device), + embedding=llm_embedding.to(self.device), + beam_size=1, + sampling=25, + max_token_text_ratio=30, + min_token_text_ratio=3) + tts_mel = self.flow.inference(token=tts_speech_token, + token_len=torch.tensor([tts_speech_token.size(1)], dtype=torch.int32).to(self.device), + prompt_token=flow_prompt_speech_token.to(self.device), + prompt_token_len=flow_prompt_speech_token_len.to(self.device), + prompt_feat=prompt_speech_feat.to(self.device), + prompt_feat_len=prompt_speech_feat_len.to(self.device), + embedding=flow_embedding.to(self.device)) + tts_speech = self.hift.inference(mel=tts_mel).cpu() + torch.cuda.empty_cache() + return {'tts_speech': tts_speech} diff --git a/xinference/thirdparty/cosyvoice/dataset/__init__.py b/xinference/thirdparty/cosyvoice/dataset/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/dataset/dataset.py b/xinference/thirdparty/cosyvoice/dataset/dataset.py new file mode 100644 index 0000000000..431fae124d --- /dev/null +++ b/xinference/thirdparty/cosyvoice/dataset/dataset.py @@ -0,0 +1,160 @@ +# Copyright (c) 2021 Mobvoi Inc. (authors: Binbin Zhang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import random +import json +import math +from functools import partial + +import torch +import torch.distributed as dist +from torch.utils.data import IterableDataset +from cosyvoice.utils.file_utils import read_lists, read_json_lists + + +class Processor(IterableDataset): + + def __init__(self, source, f, *args, **kw): + assert callable(f) + self.source = source + self.f = f + self.args = args + self.kw = kw + + def set_epoch(self, epoch): + self.source.set_epoch(epoch) + + def __iter__(self): + """ Return an iterator over the source dataset processed by the + given processor. + """ + assert self.source is not None + assert callable(self.f) + return self.f(iter(self.source), *self.args, **self.kw) + + def apply(self, f): + assert callable(f) + return Processor(self, f, *self.args, **self.kw) + + +class DistributedSampler: + + def __init__(self, shuffle=True, partition=True): + self.epoch = -1 + self.update() + self.shuffle = shuffle + self.partition = partition + + def update(self): + assert dist.is_available() + if dist.is_initialized(): + self.rank = dist.get_rank() + self.world_size = dist.get_world_size() + else: + self.rank = 0 + self.world_size = 1 + worker_info = torch.utils.data.get_worker_info() + if worker_info is None: + self.worker_id = 0 + self.num_workers = 1 + else: + self.worker_id = worker_info.id + self.num_workers = worker_info.num_workers + return dict(rank=self.rank, + world_size=self.world_size, + worker_id=self.worker_id, + num_workers=self.num_workers) + + def set_epoch(self, epoch): + self.epoch = epoch + + def sample(self, data): + """ Sample data according to rank/world_size/num_workers + + Args: + data(List): input data list + + Returns: + List: data list after sample + """ + data = list(range(len(data))) + # force datalist even + if self.partition: + if self.shuffle: + random.Random(self.epoch).shuffle(data) + if len(data) < self.world_size: + data = data * math.ceil(self.world_size / len(data)) + data = data[:self.world_size] + data = data[self.rank::self.world_size] + if len(data) < self.num_workers: + data = data * math.ceil(self.num_workers / len(data)) + data = data[:self.num_workers] + data = data[self.worker_id::self.num_workers] + return data + + +class DataList(IterableDataset): + + def __init__(self, lists, shuffle=True, partition=True): + self.lists = lists + self.sampler = DistributedSampler(shuffle, partition) + + def set_epoch(self, epoch): + self.sampler.set_epoch(epoch) + + def __iter__(self): + sampler_info = self.sampler.update() + indexes = self.sampler.sample(self.lists) + for index in indexes: + data = dict(src=self.lists[index]) + data.update(sampler_info) + yield data + + +def Dataset(data_list_file, + data_pipeline, + mode='train', + shuffle=True, + partition=True, + tts_file='', + prompt_utt2data=''): + """ Construct dataset from arguments + + We have two shuffle stage in the Dataset. The first is global + shuffle at shards tar/raw file level. The second is global shuffle + at training samples level. + + Args: + data_type(str): raw/shard + tokenizer (BaseTokenizer): tokenizer to tokenize + partition(bool): whether to do data partition in terms of rank + """ + assert mode in ['train', 'inference'] + lists = read_lists(data_list_file) + if mode == 'inference': + with open(tts_file) as f: + tts_data = json.load(f) + utt2lists = read_json_lists(prompt_utt2data) + # filter unnecessary file in inference mode + lists = list(set([utt2lists[utt] for utt in tts_data.keys() if utt2lists[utt] in lists])) + dataset = DataList(lists, + shuffle=shuffle, + partition=partition) + if mode == 'inference': + # map partial arg tts_data in inference mode + data_pipeline[0] = partial(data_pipeline[0], tts_data=tts_data) + for func in data_pipeline: + dataset = Processor(dataset, func, mode=mode) + return dataset diff --git a/xinference/thirdparty/cosyvoice/dataset/processor.py b/xinference/thirdparty/cosyvoice/dataset/processor.py new file mode 100644 index 0000000000..11f31c4d47 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/dataset/processor.py @@ -0,0 +1,369 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import random + +import pyarrow.parquet as pq +from io import BytesIO +import torch +import torchaudio +from torch.nn.utils.rnn import pad_sequence +import torch.nn.functional as F + +torchaudio.set_audio_backend('soundfile') + +AUDIO_FORMAT_SETS = set(['flac', 'mp3', 'm4a', 'ogg', 'opus', 'wav', 'wma']) + + +def parquet_opener(data, mode='train', tts_data={}): + """ Give url or local file, return file descriptor + Inplace operation. + + Args: + data(Iterable[str]): url or local file list + + Returns: + Iterable[{src, stream}] + """ + for sample in data: + assert 'src' in sample + url = sample['src'] + try: + df = pq.read_table(url).to_pandas() + for i in range(len(df)): + if mode == 'inference' and df.loc[i, 'utt'] not in tts_data: + continue + sample.update(dict(df.loc[i])) + if mode == 'train': + # NOTE do not return sample directly, must initialize a new dict + yield {**sample} + else: + for index, text in enumerate(tts_data[df.loc[i, 'utt']]): + yield {**sample, 'tts_index': index, 'tts_text': text} + except Exception as ex: + logging.warning('Failed to open {}, ex info {}'.format(url, ex)) + +def filter(data, + max_length=10240, + min_length=10, + token_max_length=200, + token_min_length=1, + min_output_input_ratio=0.0005, + max_output_input_ratio=1, + mode='train'): + """ Filter sample according to feature and label length + Inplace operation. + + Args:: + data: Iterable[{key, wav, label, sample_rate}] + max_length: drop utterance which is greater than max_length(10ms) + min_length: drop utterance which is less than min_length(10ms) + token_max_length: drop utterance which is greater than + token_max_length, especially when use char unit for + english modeling + token_min_length: drop utterance which is + less than token_max_length + min_output_input_ratio: minimal ration of + token_length / feats_length(10ms) + max_output_input_ratio: maximum ration of + token_length / feats_length(10ms) + + Returns: + Iterable[{key, wav, label, sample_rate}] + """ + for sample in data: + sample['speech'], sample['sample_rate'] = torchaudio.load(BytesIO(sample['audio_data'])) + del sample['audio_data'] + # sample['wav'] is torch.Tensor, we have 100 frames every second + num_frames = sample['speech'].size(1) / sample['sample_rate'] * 100 + if num_frames < min_length: + continue + if num_frames > max_length: + continue + if len(sample['text_token']) < token_min_length: + continue + if len(sample['text_token']) > token_max_length: + continue + if len(sample['speech_token']) == 0: + continue + if num_frames != 0: + if len(sample['text_token']) / num_frames < min_output_input_ratio: + continue + if len(sample['text_token']) / num_frames > max_output_input_ratio: + continue + yield sample + + +def resample(data, resample_rate=22050, min_sample_rate=16000, mode='train'): + """ Resample data. + Inplace operation. + + Args: + data: Iterable[{key, wav, label, sample_rate}] + resample_rate: target resample rate + + Returns: + Iterable[{key, wav, label, sample_rate}] + """ + for sample in data: + assert 'sample_rate' in sample + assert 'speech' in sample + sample_rate = sample['sample_rate'] + waveform = sample['speech'] + if sample_rate != resample_rate: + if sample_rate < min_sample_rate: + continue + sample['sample_rate'] = resample_rate + sample['speech'] = torchaudio.transforms.Resample( + orig_freq=sample_rate, new_freq=resample_rate)(waveform) + max_val = sample['speech'].abs().max() + if max_val > 1: + sample['speech'] /= max_val + yield sample + + +def compute_fbank(data, + feat_extractor, + mode='train'): + """ Extract fbank + + Args: + data: Iterable[{key, wav, label, sample_rate}] + + Returns: + Iterable[{key, feat, label}] + """ + for sample in data: + assert 'sample_rate' in sample + assert 'speech' in sample + assert 'utt' in sample + assert 'text_token' in sample + waveform = sample['speech'] + mat = feat_extractor(waveform).squeeze(dim=0).transpose(0, 1) + sample['speech_feat'] = mat + del sample['speech'] + yield sample + + +def parse_embedding(data, normalize, mode='train'): + """ Parse utt_embedding/spk_embedding + + Args: + data: Iterable[{key, wav, label, sample_rate}] + + Returns: + Iterable[{key, feat, label}] + """ + for sample in data: + sample['utt_embedding'] = torch.tensor(sample['utt_embedding'], dtype=torch.float32) + sample['spk_embedding'] = torch.tensor(sample['spk_embedding'], dtype=torch.float32) + if normalize: + sample['utt_embedding'] = F.normalize(sample['utt_embedding'], dim=0) + sample['spk_embedding'] = F.normalize(sample['spk_embedding'], dim=0) + yield sample + + +def tokenize(data, get_tokenizer, allowed_special, mode='train'): + """ Decode text to chars or BPE + Inplace operation + + Args: + data: Iterable[{key, wav, txt, sample_rate}] + + Returns: + Iterable[{key, wav, txt, tokens, label, sample_rate}] + """ + tokenizer = get_tokenizer() + for sample in data: + assert 'text' in sample + sample['text_token'] = tokenizer.encode(sample['text'], allowed_special=allowed_special) + if mode == 'inference': + sample['tts_text_token'] = tokenizer.encode(sample['tts_text'], allowed_special=allowed_special) + yield sample + + +def shuffle(data, shuffle_size=10000, mode='train'): + """ Local shuffle the data + + Args: + data: Iterable[{key, feat, label}] + shuffle_size: buffer size for shuffle + + Returns: + Iterable[{key, feat, label}] + """ + buf = [] + for sample in data: + buf.append(sample) + if len(buf) >= shuffle_size: + random.shuffle(buf) + for x in buf: + yield x + buf = [] + # The sample left over + random.shuffle(buf) + for x in buf: + yield x + + +def sort(data, sort_size=500, mode='train'): + """ Sort the data by feature length. + Sort is used after shuffle and before batch, so we can group + utts with similar lengths into a batch, and `sort_size` should + be less than `shuffle_size` + + Args: + data: Iterable[{key, feat, label}] + sort_size: buffer size for sort + + Returns: + Iterable[{key, feat, label}] + """ + + buf = [] + for sample in data: + buf.append(sample) + if len(buf) >= sort_size: + buf.sort(key=lambda x: x['speech_feat'].size(0)) + for x in buf: + yield x + buf = [] + # The sample left over + buf.sort(key=lambda x: x['speech_feat'].size(0)) + for x in buf: + yield x + + +def static_batch(data, batch_size=16): + """ Static batch the data by `batch_size` + + Args: + data: Iterable[{key, feat, label}] + batch_size: batch size + + Returns: + Iterable[List[{key, feat, label}]] + """ + buf = [] + for sample in data: + buf.append(sample) + if len(buf) >= batch_size: + yield buf + buf = [] + if len(buf) > 0: + yield buf + + +def dynamic_batch(data, max_frames_in_batch=12000, mode='train'): + """ Dynamic batch the data until the total frames in batch + reach `max_frames_in_batch` + + Args: + data: Iterable[{key, feat, label}] + max_frames_in_batch: max_frames in one batch + + Returns: + Iterable[List[{key, feat, label}]] + """ + buf = [] + longest_frames = 0 + for sample in data: + assert 'speech_feat' in sample + assert isinstance(sample['speech_feat'], torch.Tensor) + new_sample_frames = sample['speech_feat'].size(0) + longest_frames = max(longest_frames, new_sample_frames) + frames_after_padding = longest_frames * (len(buf) + 1) + if frames_after_padding > max_frames_in_batch: + yield buf + buf = [sample] + longest_frames = new_sample_frames + else: + buf.append(sample) + if len(buf) > 0: + yield buf + + +def batch(data, batch_type='static', batch_size=16, max_frames_in_batch=12000, mode='train'): + """ Wrapper for static/dynamic batch + """ + if mode == 'inference': + return static_batch(data, 1) + else: + if batch_type == 'static': + return static_batch(data, batch_size) + elif batch_type == 'dynamic': + return dynamic_batch(data, max_frames_in_batch) + else: + logging.fatal('Unsupported batch type {}'.format(batch_type)) + + +def padding(data, use_spk_embedding, mode='train'): + """ Padding the data into training data + + Args: + data: Iterable[List[{key, feat, label}]] + + Returns: + Iterable[Tuple(keys, feats, labels, feats lengths, label lengths)] + """ + for sample in data: + assert isinstance(sample, list) + speech_feat_len = torch.tensor([x['speech_feat'].size(1) for x in sample], + dtype=torch.int32) + order = torch.argsort(speech_feat_len, descending=True) + + utts = [sample[i]['utt'] for i in order] + speech_token = [torch.tensor(sample[i]['speech_token']) for i in order] + speech_token_len = torch.tensor([i.size(0) for i in speech_token], dtype=torch.int32) + speech_token = pad_sequence(speech_token, + batch_first=True, + padding_value=0) + speech_feat = [sample[i]['speech_feat'] for i in order] + speech_feat_len = torch.tensor([i.size(0) for i in speech_feat], dtype=torch.int32) + speech_feat = pad_sequence(speech_feat, + batch_first=True, + padding_value=0) + text = [sample[i]['text'] for i in order] + text_token = [torch.tensor(sample[i]['text_token']) for i in order] + text_token_len = torch.tensor([i.size(0) for i in text_token], dtype=torch.int32) + text_token = pad_sequence(text_token, batch_first=True, padding_value=0) + utt_embedding = torch.stack([sample[i]['utt_embedding'] for i in order], dim=0) + spk_embedding = torch.stack([sample[i]['spk_embedding'] for i in order], dim=0) + batch = { + "utts": utts, + "speech_token": speech_token, + "speech_token_len": speech_token_len, + "speech_feat": speech_feat, + "speech_feat_len": speech_feat_len, + "text": text, + "text_token": text_token, + "text_token_len": text_token_len, + "utt_embedding": utt_embedding, + "spk_embedding": spk_embedding, + } + if mode == 'inference': + tts_text = [sample[i]['tts_text'] for i in order] + tts_index = [sample[i]['tts_index'] for i in order] + tts_text_token = [torch.tensor(sample[i]['tts_text_token']) for i in order] + tts_text_token_len = torch.tensor([i.size(0) for i in tts_text_token], dtype=torch.int32) + tts_text_token = pad_sequence(tts_text_token, batch_first=True, padding_value=-1) + batch.update({'tts_text': tts_text, + 'tts_index': tts_index, + 'tts_text_token': tts_text_token, + 'tts_text_token_len': tts_text_token_len}) + if use_spk_embedding is True: + batch["embedding"] = batch["spk_embedding"] + else: + batch["embedding"] = batch["utt_embedding"] + yield batch diff --git a/xinference/thirdparty/cosyvoice/flow/__init__.py b/xinference/thirdparty/cosyvoice/flow/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/flow/decoder.py b/xinference/thirdparty/cosyvoice/flow/decoder.py new file mode 100755 index 0000000000..4349279939 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/flow/decoder.py @@ -0,0 +1,222 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch +import torch.nn as nn +from einops import pack, rearrange, repeat +from matcha.models.components.decoder import SinusoidalPosEmb, Block1D, ResnetBlock1D, Downsample1D, TimestepEmbedding, Upsample1D +from matcha.models.components.transformer import BasicTransformerBlock + + +class ConditionalDecoder(nn.Module): + def __init__( + self, + in_channels, + out_channels, + channels=(256, 256), + dropout=0.05, + attention_head_dim=64, + n_blocks=1, + num_mid_blocks=2, + num_heads=4, + act_fn="snake", + ): + """ + This decoder requires an input with the same shape of the target. So, if your text content + is shorter or longer than the outputs, please re-sampling it before feeding to the decoder. + """ + super().__init__() + channels = tuple(channels) + self.in_channels = in_channels + self.out_channels = out_channels + + self.time_embeddings = SinusoidalPosEmb(in_channels) + time_embed_dim = channels[0] * 4 + self.time_mlp = TimestepEmbedding( + in_channels=in_channels, + time_embed_dim=time_embed_dim, + act_fn="silu", + ) + self.down_blocks = nn.ModuleList([]) + self.mid_blocks = nn.ModuleList([]) + self.up_blocks = nn.ModuleList([]) + + output_channel = in_channels + for i in range(len(channels)): # pylint: disable=consider-using-enumerate + input_channel = output_channel + output_channel = channels[i] + is_last = i == len(channels) - 1 + resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim) + transformer_blocks = nn.ModuleList( + [ + BasicTransformerBlock( + dim=output_channel, + num_attention_heads=num_heads, + attention_head_dim=attention_head_dim, + dropout=dropout, + activation_fn=act_fn, + ) + for _ in range(n_blocks) + ] + ) + downsample = ( + Downsample1D(output_channel) if not is_last else nn.Conv1d(output_channel, output_channel, 3, padding=1) + ) + self.down_blocks.append(nn.ModuleList([resnet, transformer_blocks, downsample])) + + for i in range(num_mid_blocks): + input_channel = channels[-1] + out_channels = channels[-1] + resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim) + + transformer_blocks = nn.ModuleList( + [ + BasicTransformerBlock( + dim=output_channel, + num_attention_heads=num_heads, + attention_head_dim=attention_head_dim, + dropout=dropout, + activation_fn=act_fn, + ) + for _ in range(n_blocks) + ] + ) + + self.mid_blocks.append(nn.ModuleList([resnet, transformer_blocks])) + + channels = channels[::-1] + (channels[0],) + for i in range(len(channels) - 1): + input_channel = channels[i] * 2 + output_channel = channels[i + 1] + is_last = i == len(channels) - 2 + resnet = ResnetBlock1D( + dim=input_channel, + dim_out=output_channel, + time_emb_dim=time_embed_dim, + ) + transformer_blocks = nn.ModuleList( + [ + BasicTransformerBlock( + dim=output_channel, + num_attention_heads=num_heads, + attention_head_dim=attention_head_dim, + dropout=dropout, + activation_fn=act_fn, + ) + for _ in range(n_blocks) + ] + ) + upsample = ( + Upsample1D(output_channel, use_conv_transpose=True) + if not is_last + else nn.Conv1d(output_channel, output_channel, 3, padding=1) + ) + self.up_blocks.append(nn.ModuleList([resnet, transformer_blocks, upsample])) + self.final_block = Block1D(channels[-1], channels[-1]) + self.final_proj = nn.Conv1d(channels[-1], self.out_channels, 1) + self.initialize_weights() + + + def initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv1d): + nn.init.kaiming_normal_(m.weight, nonlinearity="relu") + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.GroupNorm): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight, nonlinearity="relu") + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x, mask, mu, t, spks=None, cond=None): + """Forward pass of the UNet1DConditional model. + + Args: + x (torch.Tensor): shape (batch_size, in_channels, time) + mask (_type_): shape (batch_size, 1, time) + t (_type_): shape (batch_size) + spks (_type_, optional): shape: (batch_size, condition_channels). Defaults to None. + cond (_type_, optional): placeholder for future use. Defaults to None. + + Raises: + ValueError: _description_ + ValueError: _description_ + + Returns: + _type_: _description_ + """ + + t = self.time_embeddings(t) + t = self.time_mlp(t) + + x = pack([x, mu], "b * t")[0] + + if spks is not None: + spks = repeat(spks, "b c -> b c t", t=x.shape[-1]) + x = pack([x, spks], "b * t")[0] + if cond is not None: + x = pack([x, cond], "b * t")[0] + + hiddens = [] + masks = [mask] + for resnet, transformer_blocks, downsample in self.down_blocks: + mask_down = masks[-1] + x = resnet(x, mask_down, t) + x = rearrange(x, "b c t -> b t c").contiguous() + attn_mask = torch.matmul(mask_down.transpose(1, 2).contiguous(), mask_down) + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=attn_mask, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t").contiguous() + hiddens.append(x) # Save hidden states for skip connections + x = downsample(x * mask_down) + masks.append(mask_down[:, :, ::2]) + masks = masks[:-1] + mask_mid = masks[-1] + + for resnet, transformer_blocks in self.mid_blocks: + x = resnet(x, mask_mid, t) + x = rearrange(x, "b c t -> b t c").contiguous() + attn_mask = torch.matmul(mask_mid.transpose(1, 2).contiguous(), mask_mid) + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=attn_mask, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t").contiguous() + + for resnet, transformer_blocks, upsample in self.up_blocks: + mask_up = masks.pop() + skip = hiddens.pop() + x = pack([x[:, :, :skip.shape[-1]], skip], "b * t")[0] + x = resnet(x, mask_up, t) + x = rearrange(x, "b c t -> b t c").contiguous() + attn_mask = torch.matmul(mask_up.transpose(1, 2).contiguous(), mask_up) + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=attn_mask, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t").contiguous() + x = upsample(x * mask_up) + x = self.final_block(x, mask_up) + output = self.final_proj(x * mask_up) + return output * mask diff --git a/xinference/thirdparty/cosyvoice/flow/flow.py b/xinference/thirdparty/cosyvoice/flow/flow.py new file mode 100644 index 0000000000..009160ab07 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/flow/flow.py @@ -0,0 +1,135 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +from typing import Dict, Optional +import torch +import torch.nn as nn +from torch.nn import functional as F +from omegaconf import DictConfig +from cosyvoice.utils.mask import make_pad_mask + + +class MaskedDiffWithXvec(torch.nn.Module): + def __init__(self, + input_size: int = 512, + output_size: int = 80, + spk_embed_dim: int = 192, + output_type: str = "mel", + vocab_size: int = 4096, + input_frame_rate: int = 50, + only_mask_loss: bool = True, + encoder: torch.nn.Module = None, + length_regulator: torch.nn.Module = None, + decoder: torch.nn.Module = None, + decoder_conf: Dict = {'in_channels': 240, 'out_channel': 80, 'spk_emb_dim': 80, 'n_spks': 1, 'cfm_params': DictConfig({'sigma_min': 1e-06, 'solver': 'euler', 't_scheduler': 'cosine', 'training_cfg_rate': 0.2, 'inference_cfg_rate': 0.7, 'reg_loss_type': 'l1'}), 'decoder_params': {'channels': [256, 256], 'dropout': 0.0, 'attention_head_dim': 64, 'n_blocks': 4, 'num_mid_blocks': 12, 'num_heads': 8, 'act_fn': 'gelu'}}, + mel_feat_conf: Dict = {'n_fft': 1024, 'num_mels': 80, 'sampling_rate': 22050, 'hop_size': 256, 'win_size': 1024, 'fmin': 0, 'fmax': 8000}): + super().__init__() + self.input_size = input_size + self.output_size = output_size + self.decoder_conf = decoder_conf + self.mel_feat_conf = mel_feat_conf + self.vocab_size = vocab_size + self.output_type = output_type + self.input_frame_rate = input_frame_rate + logging.info(f"input frame rate={self.input_frame_rate}") + self.input_embedding = nn.Embedding(vocab_size, input_size) + self.spk_embed_affine_layer = torch.nn.Linear(spk_embed_dim, output_size) + self.encoder = encoder + self.encoder_proj = torch.nn.Linear(self.encoder.output_size(), output_size) + self.decoder = decoder + self.length_regulator = length_regulator + self.only_mask_loss = only_mask_loss + + def forward( + self, + batch: dict, + device: torch.device, + ) -> Dict[str, Optional[torch.Tensor]]: + token = batch['speech_token'].to(device) + token_len = batch['speech_token_len'].to(device) + feat = batch['speech_feat'].to(device) + feat_len = batch['speech_feat_len'].to(device) + embedding = batch['embedding'].to(device) + + # xvec projection + embedding = F.normalize(embedding, dim=1) + embedding = self.spk_embed_affine_layer(embedding) + + # concat text and prompt_text + mask = (~make_pad_mask(token_len)).float().unsqueeze(-1).to(device) + token = self.input_embedding(torch.clamp(token, min=0)) * mask + + # text encode + h, h_lengths = self.encoder(token, token_len) + h = self.encoder_proj(h) + h, h_lengths = self.length_regulator(h, feat_len) + + # get conditions + conds = torch.zeros(feat.shape, device=token.device) + conds = conds.transpose(1, 2) + + mask = (~make_pad_mask(feat_len)).to(h) + feat = F.interpolate(feat.unsqueeze(dim=1), size=h.shape[1:], mode="nearest").squeeze(dim=1) + loss, _ = self.decoder.compute_loss( + feat.transpose(1, 2).contiguous(), + mask.unsqueeze(1), + h.transpose(1, 2).contiguous(), + embedding, + cond=conds + ) + return {'loss': loss} + + @torch.inference_mode() + def inference(self, + token, + token_len, + prompt_token, + prompt_token_len, + prompt_feat, + prompt_feat_len, + embedding): + assert token.shape[0] == 1 + # xvec projection + embedding = F.normalize(embedding, dim=1) + embedding = self.spk_embed_affine_layer(embedding) + + # concat text and prompt_text + token, token_len = torch.concat([prompt_token, token], dim=1), prompt_token_len + token_len + mask = (~make_pad_mask(token_len)).float().unsqueeze(-1).to(embedding) + token = self.input_embedding(torch.clamp(token, min=0)) * mask + + # text encode + h, h_lengths = self.encoder(token, token_len) + h = self.encoder_proj(h) + feat_len = (token_len / 50 * 22050 / 256).int() + h, h_lengths = self.length_regulator(h, feat_len) + + # get conditions + conds = torch.zeros([1, feat_len.max().item(), self.output_size], device=token.device) + if prompt_feat.shape[1] != 0: + for i, j in enumerate(prompt_feat_len): + conds[i, :j] = prompt_feat[i] + conds = conds.transpose(1, 2) + + mask = (~make_pad_mask(feat_len)).to(h) + feat = self.decoder( + mu=h.transpose(1, 2).contiguous(), + mask=mask.unsqueeze(1), + spks=embedding, + cond=conds, + n_timesteps=10 + ) + if prompt_feat.shape[1] != 0: + feat = feat[:, :, prompt_feat.shape[1]:] + return feat diff --git a/xinference/thirdparty/cosyvoice/flow/flow_matching.py b/xinference/thirdparty/cosyvoice/flow/flow_matching.py new file mode 100755 index 0000000000..f82eaaeaf9 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/flow/flow_matching.py @@ -0,0 +1,138 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch +import torch.nn.functional as F +from matcha.models.components.flow_matching import BASECFM + +class ConditionalCFM(BASECFM): + def __init__(self, in_channels, cfm_params, n_spks=1, spk_emb_dim=64, estimator: torch.nn.Module = None): + super().__init__( + n_feats=in_channels, + cfm_params=cfm_params, + n_spks=n_spks, + spk_emb_dim=spk_emb_dim, + ) + self.t_scheduler = cfm_params.t_scheduler + self.training_cfg_rate = cfm_params.training_cfg_rate + self.inference_cfg_rate = cfm_params.inference_cfg_rate + in_channels = in_channels + (spk_emb_dim if n_spks > 0 else 0) + # Just change the architecture of the estimator here + self.estimator = estimator + + @torch.inference_mode() + def forward(self, mu, mask, n_timesteps, temperature=1.0, spks=None, cond=None): + """Forward diffusion + + Args: + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): output_mask + shape: (batch_size, 1, mel_timesteps) + n_timesteps (int): number of diffusion steps + temperature (float, optional): temperature for scaling noise. Defaults to 1.0. + spks (torch.Tensor, optional): speaker ids. Defaults to None. + shape: (batch_size, spk_emb_dim) + cond: Not used but kept for future purposes + + Returns: + sample: generated mel-spectrogram + shape: (batch_size, n_feats, mel_timesteps) + """ + z = torch.randn_like(mu) * temperature + t_span = torch.linspace(0, 1, n_timesteps + 1, device=mu.device) + if self.t_scheduler == 'cosine': + t_span = 1 - torch.cos(t_span * 0.5 * torch.pi) + return self.solve_euler(z, t_span=t_span, mu=mu, mask=mask, spks=spks, cond=cond) + + def solve_euler(self, x, t_span, mu, mask, spks, cond): + """ + Fixed euler solver for ODEs. + Args: + x (torch.Tensor): random noise + t_span (torch.Tensor): n_timesteps interpolated + shape: (n_timesteps + 1,) + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): output_mask + shape: (batch_size, 1, mel_timesteps) + spks (torch.Tensor, optional): speaker ids. Defaults to None. + shape: (batch_size, spk_emb_dim) + cond: Not used but kept for future purposes + """ + t, _, dt = t_span[0], t_span[-1], t_span[1] - t_span[0] + + # I am storing this because I can later plot it by putting a debugger here and saving it to a file + # Or in future might add like a return_all_steps flag + sol = [] + + for step in range(1, len(t_span)): + dphi_dt = self.estimator(x, mask, mu, t, spks, cond) + # Classifier-Free Guidance inference introduced in VoiceBox + if self.inference_cfg_rate > 0: + cfg_dphi_dt = self.estimator( + x, mask, + torch.zeros_like(mu), t, + torch.zeros_like(spks) if spks is not None else None, + torch.zeros_like(cond) + ) + dphi_dt = ((1.0 + self.inference_cfg_rate) * dphi_dt - + self.inference_cfg_rate * cfg_dphi_dt) + x = x + dt * dphi_dt + t = t + dt + sol.append(x) + if step < len(t_span) - 1: + dt = t_span[step + 1] - t + + return sol[-1] + + def compute_loss(self, x1, mask, mu, spks=None, cond=None): + """Computes diffusion loss + + Args: + x1 (torch.Tensor): Target + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): target mask + shape: (batch_size, 1, mel_timesteps) + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + spks (torch.Tensor, optional): speaker embedding. Defaults to None. + shape: (batch_size, spk_emb_dim) + + Returns: + loss: conditional flow matching loss + y: conditional flow + shape: (batch_size, n_feats, mel_timesteps) + """ + b, _, t = mu.shape + + # random timestep + t = torch.rand([b, 1, 1], device=mu.device, dtype=mu.dtype) + if self.t_scheduler == 'cosine': + t = 1 - torch.cos(t * 0.5 * torch.pi) + # sample noise p(x_0) + z = torch.randn_like(x1) + + y = (1 - (1 - self.sigma_min) * t) * z + t * x1 + u = x1 - (1 - self.sigma_min) * z + + # during training, we randomly drop condition to trade off mode coverage and sample fidelity + if self.training_cfg_rate > 0: + cfg_mask = torch.rand(b, device=x1.device) > self.training_cfg_rate + mu = mu * cfg_mask.view(-1, 1, 1) + spks = spks * cfg_mask.view(-1, 1) + cond = cond * cfg_mask.view(-1, 1, 1) + + pred = self.estimator(y, mask, mu, t.squeeze(), spks, cond) + loss = F.mse_loss(pred * mask, u * mask, reduction="sum") / (torch.sum(mask) * u.shape[1]) + return loss, y diff --git a/xinference/thirdparty/cosyvoice/flow/length_regulator.py b/xinference/thirdparty/cosyvoice/flow/length_regulator.py new file mode 100755 index 0000000000..622f29aacc --- /dev/null +++ b/xinference/thirdparty/cosyvoice/flow/length_regulator.py @@ -0,0 +1,49 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Tuple +import torch.nn as nn +from torch.nn import functional as F +from cosyvoice.utils.mask import make_pad_mask + + +class InterpolateRegulator(nn.Module): + def __init__( + self, + channels: int, + sampling_ratios: Tuple, + out_channels: int = None, + groups: int = 1, + ): + super().__init__() + self.sampling_ratios = sampling_ratios + out_channels = out_channels or channels + model = nn.ModuleList([]) + if len(sampling_ratios) > 0: + for _ in sampling_ratios: + module = nn.Conv1d(channels, channels, 3, 1, 1) + norm = nn.GroupNorm(groups, channels) + act = nn.Mish() + model.extend([module, norm, act]) + model.append( + nn.Conv1d(channels, out_channels, 1, 1) + ) + self.model = nn.Sequential(*model) + + def forward(self, x, ylens=None): + # x in (B, T, D) + mask = (~make_pad_mask(ylens)).to(x).unsqueeze(-1) + x = F.interpolate(x.transpose(1, 2).contiguous(), size=ylens.max(), mode='nearest') + out = self.model(x).transpose(1, 2).contiguous() + olens = ylens + return out * mask, olens diff --git a/xinference/thirdparty/cosyvoice/hifigan/__init__.py b/xinference/thirdparty/cosyvoice/hifigan/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/hifigan/f0_predictor.py b/xinference/thirdparty/cosyvoice/hifigan/f0_predictor.py new file mode 100755 index 0000000000..36b85f4ed9 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/hifigan/f0_predictor.py @@ -0,0 +1,55 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Kai Hu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch +import torch.nn as nn +from torch.nn.utils import weight_norm + + +class ConvRNNF0Predictor(nn.Module): + def __init__(self, + num_class: int = 1, + in_channels: int = 80, + cond_channels: int = 512 + ): + super().__init__() + + self.num_class = num_class + self.condnet = nn.Sequential( + weight_norm( + nn.Conv1d(in_channels, cond_channels, kernel_size=3, padding=1) + ), + nn.ELU(), + weight_norm( + nn.Conv1d(cond_channels, cond_channels, kernel_size=3, padding=1) + ), + nn.ELU(), + weight_norm( + nn.Conv1d(cond_channels, cond_channels, kernel_size=3, padding=1) + ), + nn.ELU(), + weight_norm( + nn.Conv1d(cond_channels, cond_channels, kernel_size=3, padding=1) + ), + nn.ELU(), + weight_norm( + nn.Conv1d(cond_channels, cond_channels, kernel_size=3, padding=1) + ), + nn.ELU(), + ) + self.classifier = nn.Linear(in_features=cond_channels, out_features=self.num_class) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.condnet(x) + x = x.transpose(1, 2) + return torch.abs(self.classifier(x).squeeze(-1)) diff --git a/xinference/thirdparty/cosyvoice/hifigan/generator.py b/xinference/thirdparty/cosyvoice/hifigan/generator.py new file mode 100644 index 0000000000..a45419b582 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/hifigan/generator.py @@ -0,0 +1,391 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Kai Hu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""HIFI-GAN""" + +import typing as tp +import numpy as np +from scipy.signal import get_window +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import Conv1d +from torch.nn import ConvTranspose1d +from torch.nn.utils import remove_weight_norm +from torch.nn.utils import weight_norm +from torch.distributions.uniform import Uniform + +from cosyvoice.transformer.activation import Snake +from cosyvoice.utils.common import get_padding +from cosyvoice.utils.common import init_weights + + +"""hifigan based generator implementation. + +This code is modified from https://github.com/jik876/hifi-gan + ,https://github.com/kan-bayashi/ParallelWaveGAN and + https://github.com/NVIDIA/BigVGAN + +""" +class ResBlock(torch.nn.Module): + """Residual block module in HiFiGAN/BigVGAN.""" + def __init__( + self, + channels: int = 512, + kernel_size: int = 3, + dilations: tp.List[int] = [1, 3, 5], + ): + super(ResBlock, self).__init__() + self.convs1 = nn.ModuleList() + self.convs2 = nn.ModuleList() + + for dilation in dilations: + self.convs1.append( + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation, + padding=get_padding(kernel_size, dilation) + ) + ) + ) + self.convs2.append( + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1) + ) + ) + ) + self.convs1.apply(init_weights) + self.convs2.apply(init_weights) + self.activations1 = nn.ModuleList([ + Snake(channels, alpha_logscale=False) + for _ in range(len(self.convs1)) + ]) + self.activations2 = nn.ModuleList([ + Snake(channels, alpha_logscale=False) + for _ in range(len(self.convs2)) + ]) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + for idx in range(len(self.convs1)): + xt = self.activations1[idx](x) + xt = self.convs1[idx](xt) + xt = self.activations2[idx](xt) + xt = self.convs2[idx](xt) + x = xt + x + return x + + def remove_weight_norm(self): + for idx in range(len(self.convs1)): + remove_weight_norm(self.convs1[idx]) + remove_weight_norm(self.convs2[idx]) + +class SineGen(torch.nn.Module): + """ Definition of sine generator + SineGen(samp_rate, harmonic_num = 0, + sine_amp = 0.1, noise_std = 0.003, + voiced_threshold = 0, + flag_for_pulse=False) + samp_rate: sampling rate in Hz + harmonic_num: number of harmonic overtones (default 0) + sine_amp: amplitude of sine-wavefrom (default 0.1) + noise_std: std of Gaussian noise (default 0.003) + voiced_thoreshold: F0 threshold for U/V classification (default 0) + flag_for_pulse: this SinGen is used inside PulseGen (default False) + Note: when flag_for_pulse is True, the first time step of a voiced + segment is always sin(np.pi) or cos(0) + """ + + def __init__(self, samp_rate, harmonic_num=0, + sine_amp=0.1, noise_std=0.003, + voiced_threshold=0): + super(SineGen, self).__init__() + self.sine_amp = sine_amp + self.noise_std = noise_std + self.harmonic_num = harmonic_num + self.sampling_rate = samp_rate + self.voiced_threshold = voiced_threshold + + def _f02uv(self, f0): + # generate uv signal + uv = (f0 > self.voiced_threshold).type(torch.float32) + return uv + + @torch.no_grad() + def forward(self, f0): + """ + :param f0: [B, 1, sample_len], Hz + :return: [B, 1, sample_len] + """ + + F_mat = torch.zeros((f0.size(0), self.harmonic_num + 1, f0.size(-1))).to(f0.device) + for i in range(self.harmonic_num + 1): + F_mat[:, i: i + 1, :] = f0 * (i + 1) / self.sampling_rate + + theta_mat = 2 * np.pi * (torch.cumsum(F_mat, dim=-1) % 1) + u_dist = Uniform(low=-np.pi, high=np.pi) + phase_vec = u_dist.sample(sample_shape=(f0.size(0), self.harmonic_num + 1, 1)).to(F_mat.device) + phase_vec[:, 0, :] = 0 + + # generate sine waveforms + sine_waves = self.sine_amp * torch.sin(theta_mat + phase_vec) + + # generate uv signal + uv = self._f02uv(f0) + + # noise: for unvoiced should be similar to sine_amp + # std = self.sine_amp/3 -> max value ~ self.sine_amp + # . for voiced regions is self.noise_std + noise_amp = uv * self.noise_std + (1 - uv) * self.sine_amp / 3 + noise = noise_amp * torch.randn_like(sine_waves) + + # first: set the unvoiced part to 0 by uv + # then: additive noise + sine_waves = sine_waves * uv + noise + return sine_waves, uv, noise + + +class SourceModuleHnNSF(torch.nn.Module): + """ SourceModule for hn-nsf + SourceModule(sampling_rate, harmonic_num=0, sine_amp=0.1, + add_noise_std=0.003, voiced_threshod=0) + sampling_rate: sampling_rate in Hz + harmonic_num: number of harmonic above F0 (default: 0) + sine_amp: amplitude of sine source signal (default: 0.1) + add_noise_std: std of additive Gaussian noise (default: 0.003) + note that amplitude of noise in unvoiced is decided + by sine_amp + voiced_threshold: threhold to set U/V given F0 (default: 0) + Sine_source, noise_source = SourceModuleHnNSF(F0_sampled) + F0_sampled (batchsize, length, 1) + Sine_source (batchsize, length, 1) + noise_source (batchsize, length 1) + uv (batchsize, length, 1) + """ + + def __init__(self, sampling_rate, upsample_scale, harmonic_num=0, sine_amp=0.1, + add_noise_std=0.003, voiced_threshod=0): + super(SourceModuleHnNSF, self).__init__() + + self.sine_amp = sine_amp + self.noise_std = add_noise_std + + # to produce sine waveforms + self.l_sin_gen = SineGen(sampling_rate, harmonic_num, + sine_amp, add_noise_std, voiced_threshod) + + # to merge source harmonics into a single excitation + self.l_linear = torch.nn.Linear(harmonic_num + 1, 1) + self.l_tanh = torch.nn.Tanh() + + def forward(self, x): + """ + Sine_source, noise_source = SourceModuleHnNSF(F0_sampled) + F0_sampled (batchsize, length, 1) + Sine_source (batchsize, length, 1) + noise_source (batchsize, length 1) + """ + # source for harmonic branch + with torch.no_grad(): + sine_wavs, uv, _ = self.l_sin_gen(x.transpose(1, 2)) + sine_wavs = sine_wavs.transpose(1, 2) + uv = uv.transpose(1, 2) + sine_merge = self.l_tanh(self.l_linear(sine_wavs)) + + # source for noise branch, in the same shape as uv + noise = torch.randn_like(uv) * self.sine_amp / 3 + return sine_merge, noise, uv + + +class HiFTGenerator(nn.Module): + """ + HiFTNet Generator: Neural Source Filter + ISTFTNet + https://arxiv.org/abs/2309.09493 + """ + def __init__( + self, + in_channels: int = 80, + base_channels: int = 512, + nb_harmonics: int = 8, + sampling_rate: int = 22050, + nsf_alpha: float = 0.1, + nsf_sigma: float = 0.003, + nsf_voiced_threshold: float = 10, + upsample_rates: tp.List[int] = [8, 8], + upsample_kernel_sizes: tp.List[int] = [16, 16], + istft_params: tp.Dict[str, int] = {"n_fft": 16, "hop_len": 4}, + resblock_kernel_sizes: tp.List[int] = [3, 7, 11], + resblock_dilation_sizes: tp.List[tp.List[int]] = [[1, 3, 5], [1, 3, 5], [1, 3, 5]], + source_resblock_kernel_sizes: tp.List[int] = [7, 11], + source_resblock_dilation_sizes: tp.List[tp.List[int]] = [[1, 3, 5], [1, 3, 5]], + lrelu_slope: float = 0.1, + audio_limit: float = 0.99, + f0_predictor: torch.nn.Module = None, + ): + super(HiFTGenerator, self).__init__() + + self.out_channels = 1 + self.nb_harmonics = nb_harmonics + self.sampling_rate = sampling_rate + self.istft_params = istft_params + self.lrelu_slope = lrelu_slope + self.audio_limit = audio_limit + + self.num_kernels = len(resblock_kernel_sizes) + self.num_upsamples = len(upsample_rates) + self.m_source = SourceModuleHnNSF( + sampling_rate=sampling_rate, + upsample_scale=np.prod(upsample_rates) * istft_params["hop_len"], + harmonic_num=nb_harmonics, + sine_amp=nsf_alpha, + add_noise_std=nsf_sigma, + voiced_threshod=nsf_voiced_threshold) + self.f0_upsamp = torch.nn.Upsample(scale_factor=np.prod(upsample_rates) * istft_params["hop_len"]) + + self.conv_pre = weight_norm( + Conv1d(in_channels, base_channels, 7, 1, padding=3) + ) + + # Up + self.ups = nn.ModuleList() + for i, (u, k) in enumerate(zip(upsample_rates, upsample_kernel_sizes)): + self.ups.append( + weight_norm( + ConvTranspose1d( + base_channels // (2**i), + base_channels // (2**(i + 1)), + k, + u, + padding=(k - u) // 2, + ) + ) + ) + + # Down + self.source_downs = nn.ModuleList() + self.source_resblocks = nn.ModuleList() + downsample_rates = [1] + upsample_rates[::-1][:-1] + downsample_cum_rates = np.cumprod(downsample_rates) + for i, (u, k, d) in enumerate(zip(downsample_cum_rates[::-1], source_resblock_kernel_sizes, + source_resblock_dilation_sizes)): + if u == 1: + self.source_downs.append( + Conv1d(istft_params["n_fft"] + 2, base_channels // (2 ** (i + 1)), 1, 1) + ) + else: + self.source_downs.append( + Conv1d(istft_params["n_fft"] + 2, base_channels // (2 ** (i + 1)), u * 2, u, padding=(u // 2)) + ) + + self.source_resblocks.append( + ResBlock(base_channels // (2 ** (i + 1)), k, d) + ) + + self.resblocks = nn.ModuleList() + for i in range(len(self.ups)): + ch = base_channels // (2**(i + 1)) + for j, (k, d) in enumerate(zip(resblock_kernel_sizes, resblock_dilation_sizes)): + self.resblocks.append(ResBlock(ch, k, d)) + + self.conv_post = weight_norm(Conv1d(ch, istft_params["n_fft"] + 2, 7, 1, padding=3)) + self.ups.apply(init_weights) + self.conv_post.apply(init_weights) + self.reflection_pad = nn.ReflectionPad1d((1, 0)) + self.stft_window = torch.from_numpy(get_window("hann", istft_params["n_fft"], fftbins=True).astype(np.float32)) + self.f0_predictor = f0_predictor + + def _f02source(self, f0: torch.Tensor) -> torch.Tensor: + f0 = self.f0_upsamp(f0[:, None]).transpose(1, 2) # bs,n,t + + har_source, _, _ = self.m_source(f0) + return har_source.transpose(1, 2) + + def _stft(self, x): + spec = torch.stft( + x, + self.istft_params["n_fft"], self.istft_params["hop_len"], self.istft_params["n_fft"], window=self.stft_window.to(x.device), + return_complex=True) + spec = torch.view_as_real(spec) # [B, F, TT, 2] + return spec[..., 0], spec[..., 1] + + def _istft(self, magnitude, phase): + magnitude = torch.clip(magnitude, max=1e2) + real = magnitude * torch.cos(phase) + img = magnitude * torch.sin(phase) + inverse_transform = torch.istft(torch.complex(real, img), self.istft_params["n_fft"], self.istft_params["hop_len"], self.istft_params["n_fft"], window=self.stft_window.to(magnitude.device)) + return inverse_transform + + def forward(self, x: torch.Tensor) -> torch.Tensor: + f0 = self.f0_predictor(x) + s = self._f02source(f0) + + s_stft_real, s_stft_imag = self._stft(s.squeeze(1)) + s_stft = torch.cat([s_stft_real, s_stft_imag], dim=1) + + x = self.conv_pre(x) + for i in range(self.num_upsamples): + x = F.leaky_relu(x, self.lrelu_slope) + x = self.ups[i](x) + + if i == self.num_upsamples - 1: + x = self.reflection_pad(x) + + # fusion + si = self.source_downs[i](s_stft) + si = self.source_resblocks[i](si) + x = x + si + + xs = None + for j in range(self.num_kernels): + if xs is None: + xs = self.resblocks[i * self.num_kernels + j](x) + else: + xs += self.resblocks[i * self.num_kernels + j](x) + x = xs / self.num_kernels + + x = F.leaky_relu(x) + x = self.conv_post(x) + magnitude = torch.exp(x[:, :self.istft_params["n_fft"] // 2 + 1, :]) + phase = torch.sin(x[:, self.istft_params["n_fft"] // 2 + 1:, :]) # actually, sin is redundancy + + x = self._istft(magnitude, phase) + x = torch.clamp(x, -self.audio_limit, self.audio_limit) + return x + + def remove_weight_norm(self): + print('Removing weight norm...') + for l in self.ups: + remove_weight_norm(l) + for l in self.resblocks: + l.remove_weight_norm() + remove_weight_norm(self.conv_pre) + remove_weight_norm(self.conv_post) + self.source_module.remove_weight_norm() + for l in self.source_downs: + remove_weight_norm(l) + for l in self.source_resblocks: + l.remove_weight_norm() + + @torch.inference_mode() + def inference(self, mel: torch.Tensor) -> torch.Tensor: + return self.forward(x=mel) diff --git a/xinference/thirdparty/cosyvoice/llm/__init__.py b/xinference/thirdparty/cosyvoice/llm/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/llm/llm.py b/xinference/thirdparty/cosyvoice/llm/llm.py new file mode 100644 index 0000000000..3b418c5d10 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/llm/llm.py @@ -0,0 +1,206 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from typing import Dict, Optional, Union +import torch +from torch import nn +import torch.nn.functional as F +from torch.nn.utils.rnn import pad_sequence, unpad_sequence +from cosyvoice.utils.common import IGNORE_ID +from cosyvoice.transformer.label_smoothing_loss import LabelSmoothingLoss +from cosyvoice.utils.common import th_accuracy + + +class TransformerLM(torch.nn.Module): + def __init__( + self, + text_encoder_input_size: int, + llm_input_size: int, + llm_output_size: int, + text_token_size: int, + speech_token_size: int, + text_encoder: torch.nn.Module, + llm: torch.nn.Module, + length_normalized_loss: bool = True, + lsm_weight: float = 0.0, + spk_embed_dim: int = 192, + ): + super().__init__() + self.llm_input_size = llm_input_size + self.speech_token_size = speech_token_size + # 1. build text token inputs related modules + self.text_embedding = torch.nn.Embedding(text_token_size, text_encoder_input_size) + self.text_encoder = text_encoder + self.text_encoder_affine_layer = nn.Linear( + self.text_encoder.output_size(), + llm_input_size + ) + + # 2. build speech token language model related modules + self.sos_eos = 0 + self.task_id = 1 + self.llm_embedding = torch.nn.Embedding(2, llm_input_size) + self.llm = llm + self.llm_decoder = nn.Linear(llm_output_size, speech_token_size + 1) + self.criterion_ce = LabelSmoothingLoss( + size=speech_token_size + 1, + padding_idx=IGNORE_ID, + smoothing=lsm_weight, + normalize_length=length_normalized_loss, + ) + + # 3. [Optional] build speech token related modules + self.speech_embedding = torch.nn.Embedding(speech_token_size, llm_input_size) + self.spk_embed_affine_layer = torch.nn.Linear(spk_embed_dim, llm_input_size) + + def encode( + self, + text: torch.Tensor, + text_lengths: torch.Tensor, + ): + encoder_out, encoder_mask = self.text_encoder(text, text_lengths, decoding_chunk_size=1, num_decoding_left_chunks=-1) + encoder_out_lens = encoder_mask.squeeze(1).sum(1) + encoder_out = self.text_encoder_affine_layer(encoder_out) + return encoder_out, encoder_out_lens + + def pad_unpad_sequence(self, sos_eos_emb, embedding, text_token, text_token_len, task_id_emb, speech_token, speech_token_len): + text_token = unpad_sequence(text_token, text_token_len.cpu(), batch_first=True) + speech_token = unpad_sequence(speech_token, speech_token_len.cpu(), batch_first=True) + lm_input = [torch.concat([sos_eos_emb.squeeze(dim=0), embedding[i], text_token[i], task_id_emb.squeeze(dim=0), speech_token[i]], dim=0) for i in range(len(text_token))] + lm_input_len = torch.tensor([i.size(0) for i in lm_input], dtype=torch.int32) + lm_input = pad_sequence(lm_input, batch_first=True, padding_value=IGNORE_ID) + return lm_input, lm_input_len + + def forward( + self, + batch: dict, + device: torch.device, + ) -> Dict[str, Optional[torch.Tensor]]: + """ + Args: + text: (B, L, D) + text_lengths: (B,) + audio: (B, T, N) or (B, T) + audio_lengths: (B,) + """ + text_token = batch['text_token'].to(device) + text_token_len = batch['text_token_len'].to(device) + speech_token = batch['speech_token'].to(device) + speech_token_len = batch['speech_token_len'].to(device) + embedding = batch['embedding'].to(device) + + # 1. prepare llm_target + lm_target = [torch.tensor([IGNORE_ID] * (2 + text_token_len[i]) + speech_token[i, :speech_token_len[i]].tolist() + [self.speech_token_size]) for i in range(text_token.size(0))] + lm_target = pad_sequence(lm_target, batch_first=True, padding_value=IGNORE_ID).to(device) + + # 1. encode text_token + text_token = self.text_embedding(text_token) + text_token, text_token_len = self.encode(text_token, text_token_len) + + # 2. embedding projection + embedding = F.normalize(embedding, dim=1) + embedding = self.spk_embed_affine_layer(embedding) + embedding = embedding.unsqueeze(1) + + # 3. eos and task_id + sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape(1, 1, -1) + task_id_emb = self.llm_embedding.weight[self.task_id].reshape(1, 1, -1) + + # 4. encode speech_token + speech_token = self.speech_embedding(speech_token) + + # 5. unpad and pad + lm_input, lm_input_len = self.pad_unpad_sequence(sos_eos_emb, embedding, text_token, text_token_len, task_id_emb, speech_token, speech_token_len) + + # 6. run lm forward + lm_output, lm_output_mask = self.llm(lm_input, lm_input_len.to(device)) + logits = self.llm_decoder(lm_output) + loss = self.criterion_ce(logits, lm_target) + acc = th_accuracy(logits.view(-1, self.speech_token_size + 1), lm_target, ignore_label=IGNORE_ID) + return {'loss': loss, 'acc': acc} + + def sampling_ids( + self, + weighted_scores: torch.Tensor, + sampling: Union[bool, int, float] = True, + beam_size: int = 1, + ignore_eos: bool = True, + ): + while True: + prob, indices = weighted_scores.softmax(dim=-1).topk(sampling) + top_ids = prob.multinomial(beam_size, replacement=True) + top_ids = indices[top_ids] + if (not ignore_eos) or (self.speech_token_size not in top_ids): + break + return top_ids + + @torch.inference_mode() + def inference( + self, + text: torch.Tensor, + text_len: torch.Tensor, + prompt_text: torch.Tensor, + prompt_text_len: torch.Tensor, + prompt_speech_token: torch.Tensor, + prompt_speech_token_len: torch.Tensor, + embedding: torch.Tensor, + beam_size: int = 1, + sampling: int = 25, + max_token_text_ratio: float = 20, + min_token_text_ratio: float = 2, + ) -> torch.Tensor: + device = text.device + text = torch.concat([prompt_text, text], dim=1) + text_len += prompt_text_len + text = self.text_embedding(text) + + # 1. encode text + text, text_len = self.encode(text, text_len) + + # 2. encode embedding + if embedding.shape[0] != 0: + embedding = F.normalize(embedding, dim=1) + embedding = self.spk_embed_affine_layer(embedding) + embedding = embedding.unsqueeze(dim=1) + else: + embedding = torch.zeros(1, 0, self.llm_input_size).to(device) + + # 3. concat llm_input + sos_eos_emb = self.llm_embedding.weight[self.sos_eos].reshape(1, 1, -1) + task_id_emb = self.llm_embedding.weight[self.task_id].reshape(1, 1, -1) + if prompt_speech_token_len != 0: + prompt_speech_token_emb = self.speech_embedding(prompt_speech_token) + else: + prompt_speech_token_emb = torch.zeros(1, 0, self.llm_input_size).to(device) + lm_input = torch.concat([sos_eos_emb, embedding, text, task_id_emb, prompt_speech_token_emb], dim=1) + + # 4. cal min/max_length + min_len = int((text_len - prompt_text_len) * min_token_text_ratio) + max_len = int((text_len - prompt_text_len) * max_token_text_ratio) + + # 5. step by step decode + out_tokens = [] + offset = 0 + att_cache, cnn_cache = torch.zeros((0, 0, 0, 0), device=lm_input.device), torch.zeros((0, 0, 0, 0), device=lm_input.device) + for i in range(max_len): + y_pred, att_cache, cnn_cache = self.llm.forward_chunk(lm_input, offset=0, required_cache_size=-1, att_cache=att_cache, cnn_cache=cnn_cache, + att_mask=torch.tril(torch.ones((1, lm_input.shape[1], lm_input.shape[1]), device=lm_input.device)).to(torch.bool)) + logp = self.llm_decoder(y_pred[:, -1]).log_softmax(dim=-1) + top_ids = self.sampling_ids(logp.squeeze(dim=0), sampling, beam_size, ignore_eos=True if i < min_len else False).item() + if top_ids == self.speech_token_size: + break + out_tokens.append(top_ids) + offset += lm_input.size(1) + lm_input = self.speech_embedding.weight[top_ids].reshape(1, 1, -1) + + return torch.tensor([out_tokens], dtype=torch.int64, device=device) diff --git a/xinference/thirdparty/cosyvoice/transformer/__init__.py b/xinference/thirdparty/cosyvoice/transformer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/transformer/activation.py b/xinference/thirdparty/cosyvoice/transformer/activation.py new file mode 100644 index 0000000000..8cea548163 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/activation.py @@ -0,0 +1,84 @@ +# Copyright (c) 2020 Johns Hopkins University (Shinji Watanabe) +# 2020 Northwestern Polytechnical University (Pengcheng Guo) +# 2020 Mobvoi Inc (Binbin Zhang) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Swish() activation function for Conformer.""" + +import torch +from torch import nn, sin, pow +from torch.nn import Parameter + + +class Swish(torch.nn.Module): + """Construct an Swish object.""" + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Return Swish activation function.""" + return x * torch.sigmoid(x) + + +# Implementation adapted from https://github.com/EdwardDixon/snake under the MIT license. +# LICENSE is in incl_licenses directory. +class Snake(nn.Module): + ''' + Implementation of a sine-based periodic activation function + Shape: + - Input: (B, C, T) + - Output: (B, C, T), same shape as the input + Parameters: + - alpha - trainable parameter + References: + - This activation function is from this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda: + https://arxiv.org/abs/2006.08195 + Examples: + >>> a1 = snake(256) + >>> x = torch.randn(256) + >>> x = a1(x) + ''' + def __init__(self, in_features, alpha=1.0, alpha_trainable=True, alpha_logscale=False): + ''' + Initialization. + INPUT: + - in_features: shape of the input + - alpha: trainable parameter + alpha is initialized to 1 by default, higher values = higher-frequency. + alpha will be trained along with the rest of your model. + ''' + super(Snake, self).__init__() + self.in_features = in_features + + # initialize alpha + self.alpha_logscale = alpha_logscale + if self.alpha_logscale: # log scale alphas initialized to zeros + self.alpha = Parameter(torch.zeros(in_features) * alpha) + else: # linear scale alphas initialized to ones + self.alpha = Parameter(torch.ones(in_features) * alpha) + + self.alpha.requires_grad = alpha_trainable + + self.no_div_by_zero = 0.000000001 + + def forward(self, x): + ''' + Forward pass of the function. + Applies the function to the input elementwise. + Snake ∶= x + 1/a * sin^2 (xa) + ''' + alpha = self.alpha.unsqueeze(0).unsqueeze(-1) # line up with x to [B, C, T] + if self.alpha_logscale: + alpha = torch.exp(alpha) + x = x + (1.0 / (alpha + self.no_div_by_zero)) * pow(sin(x * alpha), 2) + + return x diff --git a/xinference/thirdparty/cosyvoice/transformer/attention.py b/xinference/thirdparty/cosyvoice/transformer/attention.py new file mode 100644 index 0000000000..cb6723af96 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/attention.py @@ -0,0 +1,326 @@ +# Copyright (c) 2019 Shigeki Karita +# 2020 Mobvoi Inc (Binbin Zhang) +# 2022 Xingchen Song (sxc19@mails.tsinghua.edu.cn) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Multi-Head Attention layer definition.""" + +import math +from typing import Tuple + +import torch +from torch import nn + + +class MultiHeadedAttention(nn.Module): + """Multi-Head Attention layer. + + Args: + n_head (int): The number of heads. + n_feat (int): The number of features. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, + n_head: int, + n_feat: int, + dropout_rate: float, + key_bias: bool = True): + """Construct an MultiHeadedAttention object.""" + super().__init__() + assert n_feat % n_head == 0 + # We assume d_v always equals d_k + self.d_k = n_feat // n_head + self.h = n_head + self.linear_q = nn.Linear(n_feat, n_feat) + self.linear_k = nn.Linear(n_feat, n_feat, bias=key_bias) + self.linear_v = nn.Linear(n_feat, n_feat) + self.linear_out = nn.Linear(n_feat, n_feat) + self.dropout = nn.Dropout(p=dropout_rate) + + def forward_qkv( + self, query: torch.Tensor, key: torch.Tensor, value: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Transform query, key and value. + + Args: + query (torch.Tensor): Query tensor (#batch, time1, size). + key (torch.Tensor): Key tensor (#batch, time2, size). + value (torch.Tensor): Value tensor (#batch, time2, size). + + Returns: + torch.Tensor: Transformed query tensor, size + (#batch, n_head, time1, d_k). + torch.Tensor: Transformed key tensor, size + (#batch, n_head, time2, d_k). + torch.Tensor: Transformed value tensor, size + (#batch, n_head, time2, d_k). + + """ + n_batch = query.size(0) + q = self.linear_q(query).view(n_batch, -1, self.h, self.d_k) + k = self.linear_k(key).view(n_batch, -1, self.h, self.d_k) + v = self.linear_v(value).view(n_batch, -1, self.h, self.d_k) + q = q.transpose(1, 2) # (batch, head, time1, d_k) + k = k.transpose(1, 2) # (batch, head, time2, d_k) + v = v.transpose(1, 2) # (batch, head, time2, d_k) + + return q, k, v + + def forward_attention( + self, + value: torch.Tensor, + scores: torch.Tensor, + mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool) + ) -> torch.Tensor: + """Compute attention context vector. + + Args: + value (torch.Tensor): Transformed value, size + (#batch, n_head, time2, d_k). + scores (torch.Tensor): Attention score, size + (#batch, n_head, time1, time2). + mask (torch.Tensor): Mask, size (#batch, 1, time2) or + (#batch, time1, time2), (0, 0, 0) means fake mask. + + Returns: + torch.Tensor: Transformed value (#batch, time1, d_model) + weighted by the attention score (#batch, time1, time2). + + """ + n_batch = value.size(0) + # NOTE(xcsong): When will `if mask.size(2) > 0` be True? + # 1. onnx(16/4) [WHY? Because we feed real cache & real mask for the + # 1st chunk to ease the onnx export.] + # 2. pytorch training + if mask.size(2) > 0: # time2 > 0 + mask = mask.unsqueeze(1).eq(0) # (batch, 1, *, time2) + # For last chunk, time2 might be larger than scores.size(-1) + mask = mask[:, :, :, :scores.size(-1)] # (batch, 1, *, time2) + scores = scores.masked_fill(mask, -float('inf')) + attn = torch.softmax(scores, dim=-1).masked_fill( + mask, 0.0) # (batch, head, time1, time2) + # NOTE(xcsong): When will `if mask.size(2) > 0` be False? + # 1. onnx(16/-1, -1/-1, 16/0) + # 2. jit (16/-1, -1/-1, 16/0, 16/4) + else: + attn = torch.softmax(scores, dim=-1) # (batch, head, time1, time2) + + p_attn = self.dropout(attn) + x = torch.matmul(p_attn, value) # (batch, head, time1, d_k) + x = (x.transpose(1, 2).contiguous().view(n_batch, -1, + self.h * self.d_k) + ) # (batch, time1, d_model) + + return self.linear_out(x) # (batch, time1, d_model) + + def forward( + self, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + pos_emb: torch.Tensor = torch.empty(0), + cache: torch.Tensor = torch.zeros((0, 0, 0, 0)) + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute scaled dot product attention. + + Args: + query (torch.Tensor): Query tensor (#batch, time1, size). + key (torch.Tensor): Key tensor (#batch, time2, size). + value (torch.Tensor): Value tensor (#batch, time2, size). + mask (torch.Tensor): Mask tensor (#batch, 1, time2) or + (#batch, time1, time2). + 1.When applying cross attention between decoder and encoder, + the batch padding mask for input is in (#batch, 1, T) shape. + 2.When applying self attention of encoder, + the mask is in (#batch, T, T) shape. + 3.When applying self attention of decoder, + the mask is in (#batch, L, L) shape. + 4.If the different position in decoder see different block + of the encoder, such as Mocha, the passed in mask could be + in (#batch, L, T) shape. But there is no such case in current + CosyVoice. + cache (torch.Tensor): Cache tensor (1, head, cache_t, d_k * 2), + where `cache_t == chunk_size * num_decoding_left_chunks` + and `head * d_k == size` + + + Returns: + torch.Tensor: Output tensor (#batch, time1, d_model). + torch.Tensor: Cache tensor (1, head, cache_t + time1, d_k * 2) + where `cache_t == chunk_size * num_decoding_left_chunks` + and `head * d_k == size` + + """ + q, k, v = self.forward_qkv(query, key, value) + + # NOTE(xcsong): + # when export onnx model, for 1st chunk, we feed + # cache(1, head, 0, d_k * 2) (16/-1, -1/-1, 16/0 mode) + # or cache(1, head, real_cache_t, d_k * 2) (16/4 mode). + # In all modes, `if cache.size(0) > 0` will alwayse be `True` + # and we will always do splitting and + # concatnation(this will simplify onnx export). Note that + # it's OK to concat & split zero-shaped tensors(see code below). + # when export jit model, for 1st chunk, we always feed + # cache(0, 0, 0, 0) since jit supports dynamic if-branch. + # >>> a = torch.ones((1, 2, 0, 4)) + # >>> b = torch.ones((1, 2, 3, 4)) + # >>> c = torch.cat((a, b), dim=2) + # >>> torch.equal(b, c) # True + # >>> d = torch.split(a, 2, dim=-1) + # >>> torch.equal(d[0], d[1]) # True + if cache.size(0) > 0: + key_cache, value_cache = torch.split(cache, + cache.size(-1) // 2, + dim=-1) + k = torch.cat([key_cache, k], dim=2) + v = torch.cat([value_cache, v], dim=2) + # NOTE(xcsong): We do cache slicing in encoder.forward_chunk, since it's + # non-trivial to calculate `next_cache_start` here. + new_cache = torch.cat((k, v), dim=-1) + + scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k) + return self.forward_attention(v, scores, mask), new_cache + + +class RelPositionMultiHeadedAttention(MultiHeadedAttention): + """Multi-Head Attention layer with relative position encoding. + Paper: https://arxiv.org/abs/1901.02860 + Args: + n_head (int): The number of heads. + n_feat (int): The number of features. + dropout_rate (float): Dropout rate. + """ + + def __init__(self, + n_head: int, + n_feat: int, + dropout_rate: float, + key_bias: bool = True): + """Construct an RelPositionMultiHeadedAttention object.""" + super().__init__(n_head, n_feat, dropout_rate, key_bias) + # linear transformation for positional encoding + self.linear_pos = nn.Linear(n_feat, n_feat, bias=False) + # these two learnable bias are used in matrix c and matrix d + # as described in https://arxiv.org/abs/1901.02860 Section 3.3 + self.pos_bias_u = nn.Parameter(torch.Tensor(self.h, self.d_k)) + self.pos_bias_v = nn.Parameter(torch.Tensor(self.h, self.d_k)) + torch.nn.init.xavier_uniform_(self.pos_bias_u) + torch.nn.init.xavier_uniform_(self.pos_bias_v) + + def rel_shift(self, x): + """Compute relative positional encoding. + + Args: + x (torch.Tensor): Input tensor (batch, head, time1, 2*time1-1). + time1 means the length of query vector. + + Returns: + torch.Tensor: Output tensor. + + """ + zero_pad = torch.zeros((*x.size()[:3], 1), device=x.device, dtype=x.dtype) + x_padded = torch.cat([zero_pad, x], dim=-1) + + x_padded = x_padded.view(*x.size()[:2], x.size(3) + 1, x.size(2)) + x = x_padded[:, :, 1:].view_as(x)[ + :, :, :, : x.size(-1) // 2 + 1 + ] # only keep the positions from 0 to time2 + return x + + def forward( + self, + query: torch.Tensor, + key: torch.Tensor, + value: torch.Tensor, + mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + pos_emb: torch.Tensor = torch.empty(0), + cache: torch.Tensor = torch.zeros((0, 0, 0, 0)) + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute 'Scaled Dot Product Attention' with rel. positional encoding. + Args: + query (torch.Tensor): Query tensor (#batch, time1, size). + key (torch.Tensor): Key tensor (#batch, time2, size). + value (torch.Tensor): Value tensor (#batch, time2, size). + mask (torch.Tensor): Mask tensor (#batch, 1, time2) or + (#batch, time1, time2), (0, 0, 0) means fake mask. + pos_emb (torch.Tensor): Positional embedding tensor + (#batch, time2, size). + cache (torch.Tensor): Cache tensor (1, head, cache_t, d_k * 2), + where `cache_t == chunk_size * num_decoding_left_chunks` + and `head * d_k == size` + Returns: + torch.Tensor: Output tensor (#batch, time1, d_model). + torch.Tensor: Cache tensor (1, head, cache_t + time1, d_k * 2) + where `cache_t == chunk_size * num_decoding_left_chunks` + and `head * d_k == size` + """ + q, k, v = self.forward_qkv(query, key, value) + q = q.transpose(1, 2) # (batch, time1, head, d_k) + + # NOTE(xcsong): + # when export onnx model, for 1st chunk, we feed + # cache(1, head, 0, d_k * 2) (16/-1, -1/-1, 16/0 mode) + # or cache(1, head, real_cache_t, d_k * 2) (16/4 mode). + # In all modes, `if cache.size(0) > 0` will alwayse be `True` + # and we will always do splitting and + # concatnation(this will simplify onnx export). Note that + # it's OK to concat & split zero-shaped tensors(see code below). + # when export jit model, for 1st chunk, we always feed + # cache(0, 0, 0, 0) since jit supports dynamic if-branch. + # >>> a = torch.ones((1, 2, 0, 4)) + # >>> b = torch.ones((1, 2, 3, 4)) + # >>> c = torch.cat((a, b), dim=2) + # >>> torch.equal(b, c) # True + # >>> d = torch.split(a, 2, dim=-1) + # >>> torch.equal(d[0], d[1]) # True + if cache.size(0) > 0: + key_cache, value_cache = torch.split(cache, + cache.size(-1) // 2, + dim=-1) + k = torch.cat([key_cache, k], dim=2) + v = torch.cat([value_cache, v], dim=2) + # NOTE(xcsong): We do cache slicing in encoder.forward_chunk, since it's + # non-trivial to calculate `next_cache_start` here. + new_cache = torch.cat((k, v), dim=-1) + + n_batch_pos = pos_emb.size(0) + p = self.linear_pos(pos_emb).view(n_batch_pos, -1, self.h, self.d_k) + p = p.transpose(1, 2) # (batch, head, time1, d_k) + + # (batch, head, time1, d_k) + q_with_bias_u = (q + self.pos_bias_u).transpose(1, 2) + # (batch, head, time1, d_k) + q_with_bias_v = (q + self.pos_bias_v).transpose(1, 2) + + # compute attention score + # first compute matrix a and matrix c + # as described in https://arxiv.org/abs/1901.02860 Section 3.3 + # (batch, head, time1, time2) + matrix_ac = torch.matmul(q_with_bias_u, k.transpose(-2, -1)) + + # compute matrix b and matrix d + # (batch, head, time1, time2) + matrix_bd = torch.matmul(q_with_bias_v, p.transpose(-2, -1)) + # NOTE(Xiang Lyu): Keep rel_shift since espnet rel_pos_emb is used + if matrix_ac.shape != matrix_bd.shape: + matrix_bd = self.rel_shift(matrix_bd) + + scores = (matrix_ac + matrix_bd) / math.sqrt( + self.d_k) # (batch, head, time1, time2) + + return self.forward_attention(v, scores, mask), new_cache diff --git a/xinference/thirdparty/cosyvoice/transformer/convolution.py b/xinference/thirdparty/cosyvoice/transformer/convolution.py new file mode 100644 index 0000000000..4d5d961491 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/convolution.py @@ -0,0 +1,145 @@ +# Copyright (c) 2020 Mobvoi Inc. (authors: Binbin Zhang, Di Wu) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""ConvolutionModule definition.""" + +from typing import Tuple + +import torch +from torch import nn + + +class ConvolutionModule(nn.Module): + """ConvolutionModule in Conformer model.""" + + def __init__(self, + channels: int, + kernel_size: int = 15, + activation: nn.Module = nn.ReLU(), + norm: str = "batch_norm", + causal: bool = False, + bias: bool = True): + """Construct an ConvolutionModule object. + Args: + channels (int): The number of channels of conv layers. + kernel_size (int): Kernel size of conv layers. + causal (int): Whether use causal convolution or not + """ + super().__init__() + + self.pointwise_conv1 = nn.Conv1d( + channels, + 2 * channels, + kernel_size=1, + stride=1, + padding=0, + bias=bias, + ) + # self.lorder is used to distinguish if it's a causal convolution, + # if self.lorder > 0: it's a causal convolution, the input will be + # padded with self.lorder frames on the left in forward. + # else: it's a symmetrical convolution + if causal: + padding = 0 + self.lorder = kernel_size - 1 + else: + # kernel_size should be an odd number for none causal convolution + assert (kernel_size - 1) % 2 == 0 + padding = (kernel_size - 1) // 2 + self.lorder = 0 + self.depthwise_conv = nn.Conv1d( + channels, + channels, + kernel_size, + stride=1, + padding=padding, + groups=channels, + bias=bias, + ) + + assert norm in ['batch_norm', 'layer_norm'] + if norm == "batch_norm": + self.use_layer_norm = False + self.norm = nn.BatchNorm1d(channels) + else: + self.use_layer_norm = True + self.norm = nn.LayerNorm(channels) + + self.pointwise_conv2 = nn.Conv1d( + channels, + channels, + kernel_size=1, + stride=1, + padding=0, + bias=bias, + ) + self.activation = activation + + def forward( + self, + x: torch.Tensor, + mask_pad: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + cache: torch.Tensor = torch.zeros((0, 0, 0)), + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute convolution module. + Args: + x (torch.Tensor): Input tensor (#batch, time, channels). + mask_pad (torch.Tensor): used for batch padding (#batch, 1, time), + (0, 0, 0) means fake mask. + cache (torch.Tensor): left context cache, it is only + used in causal convolution (#batch, channels, cache_t), + (0, 0, 0) meas fake cache. + Returns: + torch.Tensor: Output tensor (#batch, time, channels). + """ + # exchange the temporal dimension and the feature dimension + x = x.transpose(1, 2) # (#batch, channels, time) + + # mask batch padding + if mask_pad.size(2) > 0: # time > 0 + x.masked_fill_(~mask_pad, 0.0) + + if self.lorder > 0: + if cache.size(2) == 0: # cache_t == 0 + x = nn.functional.pad(x, (self.lorder, 0), 'constant', 0.0) + else: + assert cache.size(0) == x.size(0) # equal batch + assert cache.size(1) == x.size(1) # equal channel + x = torch.cat((cache, x), dim=2) + assert (x.size(2) > self.lorder) + new_cache = x[:, :, -self.lorder:] + else: + # It's better we just return None if no cache is required, + # However, for JIT export, here we just fake one tensor instead of + # None. + new_cache = torch.zeros((0, 0, 0), dtype=x.dtype, device=x.device) + + # GLU mechanism + x = self.pointwise_conv1(x) # (batch, 2*channel, dim) + x = nn.functional.glu(x, dim=1) # (batch, channel, dim) + + # 1D Depthwise Conv + x = self.depthwise_conv(x) + if self.use_layer_norm: + x = x.transpose(1, 2) + x = self.activation(self.norm(x)) + if self.use_layer_norm: + x = x.transpose(1, 2) + x = self.pointwise_conv2(x) + # mask batch padding + if mask_pad.size(2) > 0: # time > 0 + x.masked_fill_(~mask_pad, 0.0) + + return x.transpose(1, 2), new_cache diff --git a/xinference/thirdparty/cosyvoice/transformer/decoder.py b/xinference/thirdparty/cosyvoice/transformer/decoder.py new file mode 100644 index 0000000000..961c875eab --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/decoder.py @@ -0,0 +1,396 @@ +# Copyright (c) 2021 Mobvoi Inc. (authors: Binbin Zhang, Di Wu) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Decoder definition.""" +from typing import Tuple, List, Optional + +import torch +import torch.utils.checkpoint as ckpt +import logging + +from cosyvoice.transformer.decoder_layer import DecoderLayer +from cosyvoice.transformer.positionwise_feed_forward import PositionwiseFeedForward +from cosyvoice.utils.class_utils import ( + COSYVOICE_EMB_CLASSES, + COSYVOICE_ATTENTION_CLASSES, + COSYVOICE_ACTIVATION_CLASSES, +) +from cosyvoice.utils.mask import (subsequent_mask, make_pad_mask) + + +class TransformerDecoder(torch.nn.Module): + """Base class of Transfomer decoder module. + Args: + vocab_size: output dim + encoder_output_size: dimension of attention + attention_heads: the number of heads of multi head attention + linear_units: the hidden units number of position-wise feedforward + num_blocks: the number of decoder blocks + dropout_rate: dropout rate + self_attention_dropout_rate: dropout rate for attention + input_layer: input layer type + use_output_layer: whether to use output layer + pos_enc_class: PositionalEncoding or ScaledPositionalEncoding + normalize_before: + True: use layer_norm before each sub-block of a layer. + False: use layer_norm after each sub-block of a layer. + src_attention: if false, encoder-decoder cross attention is not + applied, such as CIF model + key_bias: whether use bias in attention.linear_k, False for whisper models. + gradient_checkpointing: rerunning a forward-pass segment for each + checkpointed segment during backward. + tie_word_embedding: Tie or clone module weights depending of whether we are + using TorchScript or not + """ + + def __init__( + self, + vocab_size: int, + encoder_output_size: int, + attention_heads: int = 4, + linear_units: int = 2048, + num_blocks: int = 6, + dropout_rate: float = 0.1, + positional_dropout_rate: float = 0.1, + self_attention_dropout_rate: float = 0.0, + src_attention_dropout_rate: float = 0.0, + input_layer: str = "embed", + use_output_layer: bool = True, + normalize_before: bool = True, + src_attention: bool = True, + key_bias: bool = True, + activation_type: str = "relu", + gradient_checkpointing: bool = False, + tie_word_embedding: bool = False, + ): + super().__init__() + attention_dim = encoder_output_size + activation = COSYVOICE_ACTIVATION_CLASSES[activation_type]() + + self.embed = torch.nn.Sequential( + torch.nn.Identity() if input_layer == "no_pos" else + torch.nn.Embedding(vocab_size, attention_dim), + COSYVOICE_EMB_CLASSES[input_layer](attention_dim, + positional_dropout_rate), + ) + + self.normalize_before = normalize_before + self.after_norm = torch.nn.LayerNorm(attention_dim, eps=1e-5) + self.use_output_layer = use_output_layer + if use_output_layer: + self.output_layer = torch.nn.Linear(attention_dim, vocab_size) + else: + self.output_layer = torch.nn.Identity() + self.num_blocks = num_blocks + self.decoders = torch.nn.ModuleList([ + DecoderLayer( + attention_dim, + COSYVOICE_ATTENTION_CLASSES["selfattn"]( + attention_heads, attention_dim, + self_attention_dropout_rate, key_bias), + COSYVOICE_ATTENTION_CLASSES["selfattn"]( + attention_heads, attention_dim, src_attention_dropout_rate, + key_bias) if src_attention else None, + PositionwiseFeedForward(attention_dim, linear_units, + dropout_rate, activation), + dropout_rate, + normalize_before, + ) for _ in range(self.num_blocks) + ]) + + self.gradient_checkpointing = gradient_checkpointing + self.tie_word_embedding = tie_word_embedding + + def forward( + self, + memory: torch.Tensor, + memory_mask: torch.Tensor, + ys_in_pad: torch.Tensor, + ys_in_lens: torch.Tensor, + r_ys_in_pad: torch.Tensor = torch.empty(0), + reverse_weight: float = 0.0, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Forward decoder. + Args: + memory: encoded memory, float32 (batch, maxlen_in, feat) + memory_mask: encoder memory mask, (batch, 1, maxlen_in) + ys_in_pad: padded input token ids, int64 (batch, maxlen_out) + ys_in_lens: input lengths of this batch (batch) + r_ys_in_pad: not used in transformer decoder, in order to unify api + with bidirectional decoder + reverse_weight: not used in transformer decoder, in order to unify + api with bidirectional decode + Returns: + (tuple): tuple containing: + x: decoded token score before softmax (batch, maxlen_out, + vocab_size) if use_output_layer is True, + torch.tensor(0.0), in order to unify api with bidirectional decoder + olens: (batch, ) + NOTE(xcsong): + We pass the `__call__` method of the modules instead of `forward` to the + checkpointing API because `__call__` attaches all the hooks of the module. + https://discuss.pytorch.org/t/any-different-between-model-input-and-model-forward-input/3690/2 + """ + tgt = ys_in_pad + maxlen = tgt.size(1) + # tgt_mask: (B, 1, L) + tgt_mask = ~make_pad_mask(ys_in_lens, maxlen).unsqueeze(1) + tgt_mask = tgt_mask.to(tgt.device) + # m: (1, L, L) + m = subsequent_mask(tgt_mask.size(-1), + device=tgt_mask.device).unsqueeze(0) + # tgt_mask: (B, L, L) + tgt_mask = tgt_mask & m + x, _ = self.embed(tgt) + if self.gradient_checkpointing and self.training: + x = self.forward_layers_checkpointed(x, tgt_mask, memory, + memory_mask) + else: + x = self.forward_layers(x, tgt_mask, memory, memory_mask) + if self.normalize_before: + x = self.after_norm(x) + if self.use_output_layer: + x = self.output_layer(x) + olens = tgt_mask.sum(1) + return x, torch.tensor(0.0), olens + + def forward_layers(self, x: torch.Tensor, tgt_mask: torch.Tensor, + memory: torch.Tensor, + memory_mask: torch.Tensor) -> torch.Tensor: + for layer in self.decoders: + x, tgt_mask, memory, memory_mask = layer(x, tgt_mask, memory, + memory_mask) + return x + + @torch.jit.ignore(drop=True) + def forward_layers_checkpointed(self, x: torch.Tensor, + tgt_mask: torch.Tensor, + memory: torch.Tensor, + memory_mask: torch.Tensor) -> torch.Tensor: + for layer in self.decoders: + x, tgt_mask, memory, memory_mask = ckpt.checkpoint( + layer.__call__, x, tgt_mask, memory, memory_mask) + return x + + def forward_one_step( + self, + memory: torch.Tensor, + memory_mask: torch.Tensor, + tgt: torch.Tensor, + tgt_mask: torch.Tensor, + cache: Optional[List[torch.Tensor]] = None, + ) -> Tuple[torch.Tensor, List[torch.Tensor]]: + """Forward one step. + This is only used for decoding. + Args: + memory: encoded memory, float32 (batch, maxlen_in, feat) + memory_mask: encoded memory mask, (batch, 1, maxlen_in) + tgt: input token ids, int64 (batch, maxlen_out) + tgt_mask: input token mask, (batch, maxlen_out) + dtype=torch.uint8 in PyTorch 1.2- + dtype=torch.bool in PyTorch 1.2+ (include 1.2) + cache: cached output list of (batch, max_time_out-1, size) + Returns: + y, cache: NN output value and cache per `self.decoders`. + y.shape` is (batch, maxlen_out, token) + """ + x, _ = self.embed(tgt) + new_cache = [] + for i, decoder in enumerate(self.decoders): + if cache is None: + c = None + else: + c = cache[i] + x, tgt_mask, memory, memory_mask = decoder(x, + tgt_mask, + memory, + memory_mask, + cache=c) + new_cache.append(x) + if self.normalize_before: + y = self.after_norm(x[:, -1]) + else: + y = x[:, -1] + if self.use_output_layer: + y = torch.log_softmax(self.output_layer(y), dim=-1) + return y, new_cache + + def tie_or_clone_weights(self, jit_mode: bool = True): + """Tie or clone module weights (between word_emb and output_layer) + depending of whether we are using TorchScript or not""" + if not self.use_output_layer: + return + if jit_mode: + logging.info("clone emb.weight to output.weight") + self.output_layer.weight = torch.nn.Parameter( + self.embed[0].weight.clone()) + else: + logging.info("tie emb.weight with output.weight") + self.output_layer.weight = self.embed[0].weight + + if getattr(self.output_layer, "bias", None) is not None: + self.output_layer.bias.data = torch.nn.functional.pad( + self.output_layer.bias.data, + ( + 0, + self.output_layer.weight.shape[0] - + self.output_layer.bias.shape[0], + ), + "constant", + 0, + ) + + +class BiTransformerDecoder(torch.nn.Module): + """Base class of Transfomer decoder module. + Args: + vocab_size: output dim + encoder_output_size: dimension of attention + attention_heads: the number of heads of multi head attention + linear_units: the hidden units number of position-wise feedforward + num_blocks: the number of decoder blocks + r_num_blocks: the number of right to left decoder blocks + dropout_rate: dropout rate + self_attention_dropout_rate: dropout rate for attention + input_layer: input layer type + use_output_layer: whether to use output layer + pos_enc_class: PositionalEncoding or ScaledPositionalEncoding + normalize_before: + True: use layer_norm before each sub-block of a layer. + False: use layer_norm after each sub-block of a layer. + key_bias: whether use bias in attention.linear_k, False for whisper models. + """ + + def __init__( + self, + vocab_size: int, + encoder_output_size: int, + attention_heads: int = 4, + linear_units: int = 2048, + num_blocks: int = 6, + r_num_blocks: int = 0, + dropout_rate: float = 0.1, + positional_dropout_rate: float = 0.1, + self_attention_dropout_rate: float = 0.0, + src_attention_dropout_rate: float = 0.0, + input_layer: str = "embed", + use_output_layer: bool = True, + normalize_before: bool = True, + key_bias: bool = True, + gradient_checkpointing: bool = False, + tie_word_embedding: bool = False, + ): + + super().__init__() + self.tie_word_embedding = tie_word_embedding + self.left_decoder = TransformerDecoder( + vocab_size, + encoder_output_size, + attention_heads, + linear_units, + num_blocks, + dropout_rate, + positional_dropout_rate, + self_attention_dropout_rate, + src_attention_dropout_rate, + input_layer, + use_output_layer, + normalize_before, + key_bias=key_bias, + gradient_checkpointing=gradient_checkpointing, + tie_word_embedding=tie_word_embedding) + + self.right_decoder = TransformerDecoder( + vocab_size, + encoder_output_size, + attention_heads, + linear_units, + r_num_blocks, + dropout_rate, + positional_dropout_rate, + self_attention_dropout_rate, + src_attention_dropout_rate, + input_layer, + use_output_layer, + normalize_before, + key_bias=key_bias, + gradient_checkpointing=gradient_checkpointing, + tie_word_embedding=tie_word_embedding) + + def forward( + self, + memory: torch.Tensor, + memory_mask: torch.Tensor, + ys_in_pad: torch.Tensor, + ys_in_lens: torch.Tensor, + r_ys_in_pad: torch.Tensor, + reverse_weight: float = 0.0, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Forward decoder. + Args: + memory: encoded memory, float32 (batch, maxlen_in, feat) + memory_mask: encoder memory mask, (batch, 1, maxlen_in) + ys_in_pad: padded input token ids, int64 (batch, maxlen_out) + ys_in_lens: input lengths of this batch (batch) + r_ys_in_pad: padded input token ids, int64 (batch, maxlen_out), + used for right to left decoder + reverse_weight: used for right to left decoder + Returns: + (tuple): tuple containing: + x: decoded token score before softmax (batch, maxlen_out, + vocab_size) if use_output_layer is True, + r_x: x: decoded token score (right to left decoder) + before softmax (batch, maxlen_out, vocab_size) + if use_output_layer is True, + olens: (batch, ) + """ + l_x, _, olens = self.left_decoder(memory, memory_mask, ys_in_pad, + ys_in_lens) + r_x = torch.tensor(0.0) + if reverse_weight > 0.0: + r_x, _, olens = self.right_decoder(memory, memory_mask, + r_ys_in_pad, ys_in_lens) + return l_x, r_x, olens + + def forward_one_step( + self, + memory: torch.Tensor, + memory_mask: torch.Tensor, + tgt: torch.Tensor, + tgt_mask: torch.Tensor, + cache: Optional[List[torch.Tensor]] = None, + ) -> Tuple[torch.Tensor, List[torch.Tensor]]: + """Forward one step. + This is only used for decoding. + Args: + memory: encoded memory, float32 (batch, maxlen_in, feat) + memory_mask: encoded memory mask, (batch, 1, maxlen_in) + tgt: input token ids, int64 (batch, maxlen_out) + tgt_mask: input token mask, (batch, maxlen_out) + dtype=torch.uint8 in PyTorch 1.2- + dtype=torch.bool in PyTorch 1.2+ (include 1.2) + cache: cached output list of (batch, max_time_out-1, size) + Returns: + y, cache: NN output value and cache per `self.decoders`. + y.shape` is (batch, maxlen_out, token) + """ + return self.left_decoder.forward_one_step(memory, memory_mask, tgt, + tgt_mask, cache) + + def tie_or_clone_weights(self, jit_mode: bool = True): + """Tie or clone module weights (between word_emb and output_layer) + depending of whether we are using TorchScript or not""" + self.left_decoder.tie_or_clone_weights(jit_mode) + self.right_decoder.tie_or_clone_weights(jit_mode) diff --git a/xinference/thirdparty/cosyvoice/transformer/decoder_layer.py b/xinference/thirdparty/cosyvoice/transformer/decoder_layer.py new file mode 100644 index 0000000000..91c7c5d7fb --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/decoder_layer.py @@ -0,0 +1,132 @@ +# Copyright (c) 2019 Shigeki Karita +# 2020 Mobvoi Inc (Binbin Zhang) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Decoder self-attention layer definition.""" +from typing import Optional, Tuple + +import torch +from torch import nn + + +class DecoderLayer(nn.Module): + """Single decoder layer module. + + Args: + size (int): Input dimension. + self_attn (torch.nn.Module): Self-attention module instance. + `MultiHeadedAttention` instance can be used as the argument. + src_attn (torch.nn.Module): Inter-attention module instance. + `MultiHeadedAttention` instance can be used as the argument. + If `None` is passed, Inter-attention is not used, such as + CIF, GPT, and other decoder only model. + feed_forward (torch.nn.Module): Feed-forward module instance. + `PositionwiseFeedForward` instance can be used as the argument. + dropout_rate (float): Dropout rate. + normalize_before (bool): + True: use layer_norm before each sub-block. + False: to use layer_norm after each sub-block. + """ + + def __init__( + self, + size: int, + self_attn: nn.Module, + src_attn: Optional[nn.Module], + feed_forward: nn.Module, + dropout_rate: float, + normalize_before: bool = True, + ): + """Construct an DecoderLayer object.""" + super().__init__() + self.size = size + self.self_attn = self_attn + self.src_attn = src_attn + self.feed_forward = feed_forward + self.norm1 = nn.LayerNorm(size, eps=1e-5) + self.norm2 = nn.LayerNorm(size, eps=1e-5) + self.norm3 = nn.LayerNorm(size, eps=1e-5) + self.dropout = nn.Dropout(dropout_rate) + self.normalize_before = normalize_before + + def forward( + self, + tgt: torch.Tensor, + tgt_mask: torch.Tensor, + memory: torch.Tensor, + memory_mask: torch.Tensor, + cache: Optional[torch.Tensor] = None + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + """Compute decoded features. + + Args: + tgt (torch.Tensor): Input tensor (#batch, maxlen_out, size). + tgt_mask (torch.Tensor): Mask for input tensor + (#batch, maxlen_out). + memory (torch.Tensor): Encoded memory + (#batch, maxlen_in, size). + memory_mask (torch.Tensor): Encoded memory mask + (#batch, maxlen_in). + cache (torch.Tensor): cached tensors. + (#batch, maxlen_out - 1, size). + + Returns: + torch.Tensor: Output tensor (#batch, maxlen_out, size). + torch.Tensor: Mask for output tensor (#batch, maxlen_out). + torch.Tensor: Encoded memory (#batch, maxlen_in, size). + torch.Tensor: Encoded memory mask (#batch, maxlen_in). + + """ + residual = tgt + if self.normalize_before: + tgt = self.norm1(tgt) + + if cache is None: + tgt_q = tgt + tgt_q_mask = tgt_mask + else: + # compute only the last frame query keeping dim: max_time_out -> 1 + assert cache.shape == ( + tgt.shape[0], + tgt.shape[1] - 1, + self.size, + ), "{cache.shape} == {(tgt.shape[0], tgt.shape[1] - 1, self.size)}" + tgt_q = tgt[:, -1:, :] + residual = residual[:, -1:, :] + tgt_q_mask = tgt_mask[:, -1:, :] + + x = residual + self.dropout( + self.self_attn(tgt_q, tgt, tgt, tgt_q_mask)[0]) + if not self.normalize_before: + x = self.norm1(x) + + if self.src_attn is not None: + residual = x + if self.normalize_before: + x = self.norm2(x) + x = residual + self.dropout( + self.src_attn(x, memory, memory, memory_mask)[0]) + if not self.normalize_before: + x = self.norm2(x) + + residual = x + if self.normalize_before: + x = self.norm3(x) + x = residual + self.dropout(self.feed_forward(x)) + if not self.normalize_before: + x = self.norm3(x) + + if cache is not None: + x = torch.cat([cache, x], dim=1) + + return x, tgt_mask, memory, memory_mask diff --git a/xinference/thirdparty/cosyvoice/transformer/embedding.py b/xinference/thirdparty/cosyvoice/transformer/embedding.py new file mode 100644 index 0000000000..46130a503f --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/embedding.py @@ -0,0 +1,293 @@ +# Copyright (c) 2020 Mobvoi Inc. (authors: Binbin Zhang, Di Wu) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Positonal Encoding Module.""" + +import math +from typing import Tuple, Union + +import torch +import torch.nn.functional as F +import numpy as np + + +class PositionalEncoding(torch.nn.Module): + """Positional encoding. + + :param int d_model: embedding dim + :param float dropout_rate: dropout rate + :param int max_len: maximum input length + + PE(pos, 2i) = sin(pos/(10000^(2i/dmodel))) + PE(pos, 2i+1) = cos(pos/(10000^(2i/dmodel))) + """ + + def __init__(self, + d_model: int, + dropout_rate: float, + max_len: int = 5000, + reverse: bool = False): + """Construct an PositionalEncoding object.""" + super().__init__() + self.d_model = d_model + self.xscale = math.sqrt(self.d_model) + self.dropout = torch.nn.Dropout(p=dropout_rate) + self.max_len = max_len + + self.pe = torch.zeros(self.max_len, self.d_model) + position = torch.arange(0, self.max_len, + dtype=torch.float32).unsqueeze(1) + div_term = torch.exp( + torch.arange(0, self.d_model, 2, dtype=torch.float32) * + -(math.log(10000.0) / self.d_model)) + self.pe[:, 0::2] = torch.sin(position * div_term) + self.pe[:, 1::2] = torch.cos(position * div_term) + self.pe = self.pe.unsqueeze(0) + + def forward(self, + x: torch.Tensor, + offset: Union[int, torch.Tensor] = 0) \ + -> Tuple[torch.Tensor, torch.Tensor]: + """Add positional encoding. + + Args: + x (torch.Tensor): Input. Its shape is (batch, time, ...) + offset (int, torch.tensor): position offset + + Returns: + torch.Tensor: Encoded tensor. Its shape is (batch, time, ...) + torch.Tensor: for compatibility to RelPositionalEncoding + """ + + self.pe = self.pe.to(x.device) + pos_emb = self.position_encoding(offset, x.size(1), False) + x = x * self.xscale + pos_emb + return self.dropout(x), self.dropout(pos_emb) + + def position_encoding(self, + offset: Union[int, torch.Tensor], + size: int, + apply_dropout: bool = True) -> torch.Tensor: + """ For getting encoding in a streaming fashion + + Attention!!!!! + we apply dropout only once at the whole utterance level in a none + streaming way, but will call this function several times with + increasing input size in a streaming scenario, so the dropout will + be applied several times. + + Args: + offset (int or torch.tensor): start offset + size (int): required size of position encoding + + Returns: + torch.Tensor: Corresponding encoding + """ + # How to subscript a Union type: + # https://github.com/pytorch/pytorch/issues/69434 + if isinstance(offset, int): + assert offset + size <= self.max_len + pos_emb = self.pe[:, offset:offset + size] + elif isinstance(offset, torch.Tensor) and offset.dim() == 0: # scalar + assert offset + size <= self.max_len + pos_emb = self.pe[:, offset:offset + size] + else: # for batched streaming decoding on GPU + assert torch.max(offset) + size <= self.max_len + index = offset.unsqueeze(1) + \ + torch.arange(0, size).to(offset.device) # B X T + flag = index > 0 + # remove negative offset + index = index * flag + pos_emb = F.embedding(index, self.pe[0]) # B X T X d_model + + if apply_dropout: + pos_emb = self.dropout(pos_emb) + return pos_emb + + +class RelPositionalEncoding(PositionalEncoding): + """Relative positional encoding module. + See : Appendix B in https://arxiv.org/abs/1901.02860 + Args: + d_model (int): Embedding dimension. + dropout_rate (float): Dropout rate. + max_len (int): Maximum input length. + """ + + def __init__(self, d_model: int, dropout_rate: float, max_len: int = 5000): + """Initialize class.""" + super().__init__(d_model, dropout_rate, max_len, reverse=True) + + def forward(self, + x: torch.Tensor, + offset: Union[int, torch.Tensor] = 0) \ + -> Tuple[torch.Tensor, torch.Tensor]: + """Compute positional encoding. + Args: + x (torch.Tensor): Input tensor (batch, time, `*`). + Returns: + torch.Tensor: Encoded tensor (batch, time, `*`). + torch.Tensor: Positional embedding tensor (1, time, `*`). + """ + self.pe = self.pe.to(x.device) + x = x * self.xscale + pos_emb = self.position_encoding(offset, x.size(1), False) + return self.dropout(x), self.dropout(pos_emb) + + +class WhisperPositionalEncoding(PositionalEncoding): + """ Sinusoids position encoding used in openai-whisper.encoder + """ + + def __init__(self, d_model: int, dropout_rate: float, max_len: int = 1500): + super().__init__(d_model, dropout_rate, max_len) + self.xscale = 1.0 + log_timescale_increment = np.log(10000) / (d_model // 2 - 1) + inv_timescales = torch.exp(-log_timescale_increment * + torch.arange(d_model // 2)) + scaled_time = torch.arange(max_len)[:, np.newaxis] * \ + inv_timescales[np.newaxis, :] + pe = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], dim=1) + delattr(self, "pe") + self.register_buffer("pe", pe.unsqueeze(0)) + + +class LearnablePositionalEncoding(PositionalEncoding): + """ Learnable position encoding used in openai-whisper.decoder + """ + + def __init__(self, d_model: int, dropout_rate: float, max_len: int = 448): + super().__init__(d_model, dropout_rate, max_len) + # NOTE(xcsong): overwrite self.pe & self.xscale + self.pe = torch.nn.Parameter(torch.empty(1, max_len, d_model)) + self.xscale = 1.0 + + +class NoPositionalEncoding(torch.nn.Module): + """ No position encoding + """ + + def __init__(self, d_model: int, dropout_rate: float): + super().__init__() + self.d_model = d_model + self.dropout = torch.nn.Dropout(p=dropout_rate) + + def forward(self, + x: torch.Tensor, + offset: Union[int, torch.Tensor] = 0) \ + -> Tuple[torch.Tensor, torch.Tensor]: + """ Just return zero vector for interface compatibility + """ + pos_emb = torch.zeros(1, x.size(1), self.d_model).to(x.device) + return self.dropout(x), pos_emb + + def position_encoding(self, offset: Union[int, torch.Tensor], + size: int) -> torch.Tensor: + return torch.zeros(1, size, self.d_model) + + +class EspnetRelPositionalEncoding(torch.nn.Module): + """Relative positional encoding module (new implementation). + + Details can be found in https://github.com/espnet/espnet/pull/2816. + + See : Appendix B in https://arxiv.org/abs/1901.02860 + + Args: + d_model (int): Embedding dimension. + dropout_rate (float): Dropout rate. + max_len (int): Maximum input length. + + """ + + def __init__(self, d_model, dropout_rate, max_len=5000): + """Construct an PositionalEncoding object.""" + super(EspnetRelPositionalEncoding, self).__init__() + self.d_model = d_model + self.xscale = math.sqrt(self.d_model) + self.dropout = torch.nn.Dropout(p=dropout_rate) + self.pe = None + self.extend_pe(torch.tensor(0.0).expand(1, max_len)) + + def extend_pe(self, x): + """Reset the positional encodings.""" + if self.pe is not None: + # self.pe contains both positive and negative parts + # the length of self.pe is 2 * input_len - 1 + if self.pe.size(1) >= x.size(1) * 2 - 1: + if self.pe.dtype != x.dtype or self.pe.device != x.device: + self.pe = self.pe.to(dtype=x.dtype, device=x.device) + return + # Suppose `i` means to the position of query vecotr and `j` means the + # position of key vector. We use position relative positions when keys + # are to the left (i>j) and negative relative positions otherwise (i torch.Tensor: + """ For getting encoding in a streaming fashion + + Attention!!!!! + we apply dropout only once at the whole utterance level in a none + streaming way, but will call this function several times with + increasing input size in a streaming scenario, so the dropout will + be applied several times. + + Args: + offset (int or torch.tensor): start offset + size (int): required size of position encoding + + Returns: + torch.Tensor: Corresponding encoding + """ + pos_emb = self.pe[ + :, + self.pe.size(1) // 2 - size + 1 : self.pe.size(1) // 2 + size, + ] + return pos_emb diff --git a/xinference/thirdparty/cosyvoice/transformer/encoder.py b/xinference/thirdparty/cosyvoice/transformer/encoder.py new file mode 100644 index 0000000000..7e8bd230b2 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/encoder.py @@ -0,0 +1,472 @@ +# Copyright (c) 2021 Mobvoi Inc (Binbin Zhang, Di Wu) +# 2022 Xingchen Song (sxc19@mails.tsinghua.edu.cn) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Encoder definition.""" +from typing import Tuple + +import torch +import torch.utils.checkpoint as ckpt + +from cosyvoice.transformer.convolution import ConvolutionModule +from cosyvoice.transformer.encoder_layer import TransformerEncoderLayer +from cosyvoice.transformer.encoder_layer import ConformerEncoderLayer +from cosyvoice.transformer.positionwise_feed_forward import PositionwiseFeedForward +from cosyvoice.utils.class_utils import ( + COSYVOICE_EMB_CLASSES, + COSYVOICE_SUBSAMPLE_CLASSES, + COSYVOICE_ATTENTION_CLASSES, + COSYVOICE_ACTIVATION_CLASSES, +) +from cosyvoice.utils.mask import make_pad_mask +from cosyvoice.utils.mask import add_optional_chunk_mask + + +class BaseEncoder(torch.nn.Module): + + def __init__( + self, + input_size: int, + output_size: int = 256, + attention_heads: int = 4, + linear_units: int = 2048, + num_blocks: int = 6, + dropout_rate: float = 0.1, + positional_dropout_rate: float = 0.1, + attention_dropout_rate: float = 0.0, + input_layer: str = "conv2d", + pos_enc_layer_type: str = "abs_pos", + normalize_before: bool = True, + static_chunk_size: int = 0, + use_dynamic_chunk: bool = False, + global_cmvn: torch.nn.Module = None, + use_dynamic_left_chunk: bool = False, + gradient_checkpointing: bool = False, + ): + """ + Args: + input_size (int): input dim + output_size (int): dimension of attention + attention_heads (int): the number of heads of multi head attention + linear_units (int): the hidden units number of position-wise feed + forward + num_blocks (int): the number of decoder blocks + dropout_rate (float): dropout rate + attention_dropout_rate (float): dropout rate in attention + positional_dropout_rate (float): dropout rate after adding + positional encoding + input_layer (str): input layer type. + optional [linear, conv2d, conv2d6, conv2d8] + pos_enc_layer_type (str): Encoder positional encoding layer type. + opitonal [abs_pos, scaled_abs_pos, rel_pos, no_pos] + normalize_before (bool): + True: use layer_norm before each sub-block of a layer. + False: use layer_norm after each sub-block of a layer. + static_chunk_size (int): chunk size for static chunk training and + decoding + use_dynamic_chunk (bool): whether use dynamic chunk size for + training or not, You can only use fixed chunk(chunk_size > 0) + or dyanmic chunk size(use_dynamic_chunk = True) + global_cmvn (Optional[torch.nn.Module]): Optional GlobalCMVN module + use_dynamic_left_chunk (bool): whether use dynamic left chunk in + dynamic chunk training + key_bias: whether use bias in attention.linear_k, False for whisper models. + gradient_checkpointing: rerunning a forward-pass segment for each + checkpointed segment during backward. + """ + super().__init__() + self._output_size = output_size + + self.global_cmvn = global_cmvn + self.embed = COSYVOICE_SUBSAMPLE_CLASSES[input_layer]( + input_size, + output_size, + dropout_rate, + COSYVOICE_EMB_CLASSES[pos_enc_layer_type](output_size, + positional_dropout_rate), + ) + + self.normalize_before = normalize_before + self.after_norm = torch.nn.LayerNorm(output_size, eps=1e-5) + self.static_chunk_size = static_chunk_size + self.use_dynamic_chunk = use_dynamic_chunk + self.use_dynamic_left_chunk = use_dynamic_left_chunk + self.gradient_checkpointing = gradient_checkpointing + + def output_size(self) -> int: + return self._output_size + + def forward( + self, + xs: torch.Tensor, + xs_lens: torch.Tensor, + decoding_chunk_size: int = 0, + num_decoding_left_chunks: int = -1, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Embed positions in tensor. + + Args: + xs: padded input tensor (B, T, D) + xs_lens: input length (B) + decoding_chunk_size: decoding chunk size for dynamic chunk + 0: default for training, use random dynamic chunk. + <0: for decoding, use full chunk. + >0: for decoding, use fixed chunk size as set. + num_decoding_left_chunks: number of left chunks, this is for decoding, + the chunk size is decoding_chunk_size. + >=0: use num_decoding_left_chunks + <0: use all left chunks + Returns: + encoder output tensor xs, and subsampled masks + xs: padded output tensor (B, T' ~= T/subsample_rate, D) + masks: torch.Tensor batch padding mask after subsample + (B, 1, T' ~= T/subsample_rate) + NOTE(xcsong): + We pass the `__call__` method of the modules instead of `forward` to the + checkpointing API because `__call__` attaches all the hooks of the module. + https://discuss.pytorch.org/t/any-different-between-model-input-and-model-forward-input/3690/2 + """ + T = xs.size(1) + masks = ~make_pad_mask(xs_lens, T).unsqueeze(1) # (B, 1, T) + if self.global_cmvn is not None: + xs = self.global_cmvn(xs) + xs, pos_emb, masks = self.embed(xs, masks) + mask_pad = masks # (B, 1, T/subsample_rate) + chunk_masks = add_optional_chunk_mask(xs, masks, + self.use_dynamic_chunk, + self.use_dynamic_left_chunk, + decoding_chunk_size, + self.static_chunk_size, + num_decoding_left_chunks) + if self.gradient_checkpointing and self.training: + xs = self.forward_layers_checkpointed(xs, chunk_masks, pos_emb, + mask_pad) + else: + xs = self.forward_layers(xs, chunk_masks, pos_emb, mask_pad) + if self.normalize_before: + xs = self.after_norm(xs) + # Here we assume the mask is not changed in encoder layers, so just + # return the masks before encoder layers, and the masks will be used + # for cross attention with decoder later + return xs, masks + + def forward_layers(self, xs: torch.Tensor, chunk_masks: torch.Tensor, + pos_emb: torch.Tensor, + mask_pad: torch.Tensor) -> torch.Tensor: + for layer in self.encoders: + xs, chunk_masks, _, _ = layer(xs, chunk_masks, pos_emb, mask_pad) + return xs + + @torch.jit.ignore(drop=True) + def forward_layers_checkpointed(self, xs: torch.Tensor, + chunk_masks: torch.Tensor, + pos_emb: torch.Tensor, + mask_pad: torch.Tensor) -> torch.Tensor: + for layer in self.encoders: + xs, chunk_masks, _, _ = ckpt.checkpoint(layer.__call__, xs, + chunk_masks, pos_emb, + mask_pad) + return xs + + def forward_chunk( + self, + xs: torch.Tensor, + offset: int, + required_cache_size: int, + att_cache: torch.Tensor = torch.zeros(0, 0, 0, 0), + cnn_cache: torch.Tensor = torch.zeros(0, 0, 0, 0), + att_mask: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ Forward just one chunk + + Args: + xs (torch.Tensor): chunk input, with shape (b=1, time, mel-dim), + where `time == (chunk_size - 1) * subsample_rate + \ + subsample.right_context + 1` + offset (int): current offset in encoder output time stamp + required_cache_size (int): cache size required for next chunk + compuation + >=0: actual cache size + <0: means all history cache is required + att_cache (torch.Tensor): cache tensor for KEY & VALUE in + transformer/conformer attention, with shape + (elayers, head, cache_t1, d_k * 2), where + `head * d_k == hidden-dim` and + `cache_t1 == chunk_size * num_decoding_left_chunks`. + cnn_cache (torch.Tensor): cache tensor for cnn_module in conformer, + (elayers, b=1, hidden-dim, cache_t2), where + `cache_t2 == cnn.lorder - 1` + + Returns: + torch.Tensor: output of current input xs, + with shape (b=1, chunk_size, hidden-dim). + torch.Tensor: new attention cache required for next chunk, with + dynamic shape (elayers, head, ?, d_k * 2) + depending on required_cache_size. + torch.Tensor: new conformer cnn cache required for next chunk, with + same shape as the original cnn_cache. + + """ + assert xs.size(0) == 1 + # tmp_masks is just for interface compatibility + tmp_masks = torch.ones(1, + xs.size(1), + device=xs.device, + dtype=torch.bool) + tmp_masks = tmp_masks.unsqueeze(1) + if self.global_cmvn is not None: + xs = self.global_cmvn(xs) + # NOTE(xcsong): Before embed, shape(xs) is (b=1, time, mel-dim) + xs, pos_emb, _ = self.embed(xs, tmp_masks, offset) + # NOTE(xcsong): After embed, shape(xs) is (b=1, chunk_size, hidden-dim) + elayers, cache_t1 = att_cache.size(0), att_cache.size(2) + chunk_size = xs.size(1) + attention_key_size = cache_t1 + chunk_size + pos_emb = self.embed.position_encoding(offset=offset - cache_t1, + size=attention_key_size) + if required_cache_size < 0: + next_cache_start = 0 + elif required_cache_size == 0: + next_cache_start = attention_key_size + else: + next_cache_start = max(attention_key_size - required_cache_size, 0) + r_att_cache = [] + r_cnn_cache = [] + for i, layer in enumerate(self.encoders): + # NOTE(xcsong): Before layer.forward + # shape(att_cache[i:i + 1]) is (1, head, cache_t1, d_k * 2), + # shape(cnn_cache[i]) is (b=1, hidden-dim, cache_t2) + xs, _, new_att_cache, new_cnn_cache = layer( + xs, + att_mask, + pos_emb, + att_cache=att_cache[i:i + 1] if elayers > 0 else att_cache, + cnn_cache=cnn_cache[i] if cnn_cache.size(0) > 0 else cnn_cache) + # NOTE(xcsong): After layer.forward + # shape(new_att_cache) is (1, head, attention_key_size, d_k * 2), + # shape(new_cnn_cache) is (b=1, hidden-dim, cache_t2) + r_att_cache.append(new_att_cache[:, :, next_cache_start:, :]) + r_cnn_cache.append(new_cnn_cache.unsqueeze(0)) + if self.normalize_before: + xs = self.after_norm(xs) + + # NOTE(xcsong): shape(r_att_cache) is (elayers, head, ?, d_k * 2), + # ? may be larger than cache_t1, it depends on required_cache_size + r_att_cache = torch.cat(r_att_cache, dim=0) + # NOTE(xcsong): shape(r_cnn_cache) is (e, b=1, hidden-dim, cache_t2) + r_cnn_cache = torch.cat(r_cnn_cache, dim=0) + + return (xs, r_att_cache, r_cnn_cache) + + def forward_chunk_by_chunk( + self, + xs: torch.Tensor, + decoding_chunk_size: int, + num_decoding_left_chunks: int = -1, + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ Forward input chunk by chunk with chunk_size like a streaming + fashion + + Here we should pay special attention to computation cache in the + streaming style forward chunk by chunk. Three things should be taken + into account for computation in the current network: + 1. transformer/conformer encoder layers output cache + 2. convolution in conformer + 3. convolution in subsampling + + However, we don't implement subsampling cache for: + 1. We can control subsampling module to output the right result by + overlapping input instead of cache left context, even though it + wastes some computation, but subsampling only takes a very + small fraction of computation in the whole model. + 2. Typically, there are several covolution layers with subsampling + in subsampling module, it is tricky and complicated to do cache + with different convolution layers with different subsampling + rate. + 3. Currently, nn.Sequential is used to stack all the convolution + layers in subsampling, we need to rewrite it to make it work + with cache, which is not prefered. + Args: + xs (torch.Tensor): (1, max_len, dim) + chunk_size (int): decoding chunk size + """ + assert decoding_chunk_size > 0 + # The model is trained by static or dynamic chunk + assert self.static_chunk_size > 0 or self.use_dynamic_chunk + subsampling = self.embed.subsampling_rate + context = self.embed.right_context + 1 # Add current frame + stride = subsampling * decoding_chunk_size + decoding_window = (decoding_chunk_size - 1) * subsampling + context + num_frames = xs.size(1) + att_cache: torch.Tensor = torch.zeros((0, 0, 0, 0), device=xs.device) + cnn_cache: torch.Tensor = torch.zeros((0, 0, 0, 0), device=xs.device) + outputs = [] + offset = 0 + required_cache_size = decoding_chunk_size * num_decoding_left_chunks + + # Feed forward overlap input step by step + for cur in range(0, num_frames - context + 1, stride): + end = min(cur + decoding_window, num_frames) + chunk_xs = xs[:, cur:end, :] + (y, att_cache, + cnn_cache) = self.forward_chunk(chunk_xs, offset, + required_cache_size, att_cache, + cnn_cache) + outputs.append(y) + offset += y.size(1) + ys = torch.cat(outputs, 1) + masks = torch.ones((1, 1, ys.size(1)), + device=ys.device, + dtype=torch.bool) + return ys, masks + + +class TransformerEncoder(BaseEncoder): + """Transformer encoder module.""" + + def __init__( + self, + input_size: int, + output_size: int = 256, + attention_heads: int = 4, + linear_units: int = 2048, + num_blocks: int = 6, + dropout_rate: float = 0.1, + positional_dropout_rate: float = 0.1, + attention_dropout_rate: float = 0.0, + input_layer: str = "conv2d", + pos_enc_layer_type: str = "abs_pos", + normalize_before: bool = True, + static_chunk_size: int = 0, + use_dynamic_chunk: bool = False, + global_cmvn: torch.nn.Module = None, + use_dynamic_left_chunk: bool = False, + key_bias: bool = True, + selfattention_layer_type: str = "selfattn", + activation_type: str = "relu", + gradient_checkpointing: bool = False, + ): + """ Construct TransformerEncoder + + See Encoder for the meaning of each parameter. + """ + super().__init__(input_size, output_size, attention_heads, + linear_units, num_blocks, dropout_rate, + positional_dropout_rate, attention_dropout_rate, + input_layer, pos_enc_layer_type, normalize_before, + static_chunk_size, use_dynamic_chunk, global_cmvn, + use_dynamic_left_chunk, gradient_checkpointing) + activation = COSYVOICE_ACTIVATION_CLASSES[activation_type]() + self.encoders = torch.nn.ModuleList([ + TransformerEncoderLayer( + output_size, + COSYVOICE_ATTENTION_CLASSES[selfattention_layer_type](attention_heads, + output_size, + attention_dropout_rate, + key_bias), + PositionwiseFeedForward(output_size, linear_units, + dropout_rate, activation), + dropout_rate, normalize_before) for _ in range(num_blocks) + ]) + + +class ConformerEncoder(BaseEncoder): + """Conformer encoder module.""" + + def __init__( + self, + input_size: int, + output_size: int = 256, + attention_heads: int = 4, + linear_units: int = 2048, + num_blocks: int = 6, + dropout_rate: float = 0.1, + positional_dropout_rate: float = 0.1, + attention_dropout_rate: float = 0.0, + input_layer: str = "conv2d", + pos_enc_layer_type: str = "rel_pos", + normalize_before: bool = True, + static_chunk_size: int = 0, + use_dynamic_chunk: bool = False, + global_cmvn: torch.nn.Module = None, + use_dynamic_left_chunk: bool = False, + positionwise_conv_kernel_size: int = 1, + macaron_style: bool = True, + selfattention_layer_type: str = "rel_selfattn", + activation_type: str = "swish", + use_cnn_module: bool = True, + cnn_module_kernel: int = 15, + causal: bool = False, + cnn_module_norm: str = "batch_norm", + key_bias: bool = True, + gradient_checkpointing: bool = False, + ): + """Construct ConformerEncoder + + Args: + input_size to use_dynamic_chunk, see in BaseEncoder + positionwise_conv_kernel_size (int): Kernel size of positionwise + conv1d layer. + macaron_style (bool): Whether to use macaron style for + positionwise layer. + selfattention_layer_type (str): Encoder attention layer type, + the parameter has no effect now, it's just for configure + compatibility. + activation_type (str): Encoder activation function type. + use_cnn_module (bool): Whether to use convolution module. + cnn_module_kernel (int): Kernel size of convolution module. + causal (bool): whether to use causal convolution or not. + key_bias: whether use bias in attention.linear_k, False for whisper models. + """ + super().__init__(input_size, output_size, attention_heads, + linear_units, num_blocks, dropout_rate, + positional_dropout_rate, attention_dropout_rate, + input_layer, pos_enc_layer_type, normalize_before, + static_chunk_size, use_dynamic_chunk, global_cmvn, + use_dynamic_left_chunk, gradient_checkpointing) + activation = COSYVOICE_ACTIVATION_CLASSES[activation_type]() + + # self-attention module definition + encoder_selfattn_layer_args = ( + attention_heads, + output_size, + attention_dropout_rate, + key_bias, + ) + # feed-forward module definition + positionwise_layer_args = ( + output_size, + linear_units, + dropout_rate, + activation, + ) + # convolution module definition + convolution_layer_args = (output_size, cnn_module_kernel, activation, + cnn_module_norm, causal) + + self.encoders = torch.nn.ModuleList([ + ConformerEncoderLayer( + output_size, + COSYVOICE_ATTENTION_CLASSES[selfattention_layer_type]( + *encoder_selfattn_layer_args), + PositionwiseFeedForward(*positionwise_layer_args), + PositionwiseFeedForward( + *positionwise_layer_args) if macaron_style else None, + ConvolutionModule( + *convolution_layer_args) if use_cnn_module else None, + dropout_rate, + normalize_before, + ) for _ in range(num_blocks) + ]) diff --git a/xinference/thirdparty/cosyvoice/transformer/encoder_layer.py b/xinference/thirdparty/cosyvoice/transformer/encoder_layer.py new file mode 100644 index 0000000000..dfd758bc1c --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/encoder_layer.py @@ -0,0 +1,236 @@ +# Copyright (c) 2021 Mobvoi Inc (Binbin Zhang, Di Wu) +# 2022 Xingchen Song (sxc19@mails.tsinghua.edu.cn) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Encoder self-attention layer definition.""" + +from typing import Optional, Tuple + +import torch +from torch import nn + + +class TransformerEncoderLayer(nn.Module): + """Encoder layer module. + + Args: + size (int): Input dimension. + self_attn (torch.nn.Module): Self-attention module instance. + `MultiHeadedAttention` or `RelPositionMultiHeadedAttention` + instance can be used as the argument. + feed_forward (torch.nn.Module): Feed-forward module instance. + `PositionwiseFeedForward`, instance can be used as the argument. + dropout_rate (float): Dropout rate. + normalize_before (bool): + True: use layer_norm before each sub-block. + False: to use layer_norm after each sub-block. + """ + + def __init__( + self, + size: int, + self_attn: torch.nn.Module, + feed_forward: torch.nn.Module, + dropout_rate: float, + normalize_before: bool = True, + ): + """Construct an EncoderLayer object.""" + super().__init__() + self.self_attn = self_attn + self.feed_forward = feed_forward + self.norm1 = nn.LayerNorm(size, eps=1e-5) + self.norm2 = nn.LayerNorm(size, eps=1e-5) + self.dropout = nn.Dropout(dropout_rate) + self.size = size + self.normalize_before = normalize_before + + def forward( + self, + x: torch.Tensor, + mask: torch.Tensor, + pos_emb: torch.Tensor, + mask_pad: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + att_cache: torch.Tensor = torch.zeros((0, 0, 0, 0)), + cnn_cache: torch.Tensor = torch.zeros((0, 0, 0, 0)), + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + """Compute encoded features. + + Args: + x (torch.Tensor): (#batch, time, size) + mask (torch.Tensor): Mask tensor for the input (#batch, time,time), + (0, 0, 0) means fake mask. + pos_emb (torch.Tensor): just for interface compatibility + to ConformerEncoderLayer + mask_pad (torch.Tensor): does not used in transformer layer, + just for unified api with conformer. + att_cache (torch.Tensor): Cache tensor of the KEY & VALUE + (#batch=1, head, cache_t1, d_k * 2), head * d_k == size. + cnn_cache (torch.Tensor): Convolution cache in conformer layer + (#batch=1, size, cache_t2), not used here, it's for interface + compatibility to ConformerEncoderLayer. + Returns: + torch.Tensor: Output tensor (#batch, time, size). + torch.Tensor: Mask tensor (#batch, time, time). + torch.Tensor: att_cache tensor, + (#batch=1, head, cache_t1 + time, d_k * 2). + torch.Tensor: cnn_cahce tensor (#batch=1, size, cache_t2). + + """ + residual = x + if self.normalize_before: + x = self.norm1(x) + x_att, new_att_cache = self.self_attn(x, x, x, mask, pos_emb=pos_emb, cache=att_cache) + x = residual + self.dropout(x_att) + if not self.normalize_before: + x = self.norm1(x) + + residual = x + if self.normalize_before: + x = self.norm2(x) + x = residual + self.dropout(self.feed_forward(x)) + if not self.normalize_before: + x = self.norm2(x) + + fake_cnn_cache = torch.zeros((0, 0, 0), dtype=x.dtype, device=x.device) + return x, mask, new_att_cache, fake_cnn_cache + + +class ConformerEncoderLayer(nn.Module): + """Encoder layer module. + Args: + size (int): Input dimension. + self_attn (torch.nn.Module): Self-attention module instance. + `MultiHeadedAttention` or `RelPositionMultiHeadedAttention` + instance can be used as the argument. + feed_forward (torch.nn.Module): Feed-forward module instance. + `PositionwiseFeedForward` instance can be used as the argument. + feed_forward_macaron (torch.nn.Module): Additional feed-forward module + instance. + `PositionwiseFeedForward` instance can be used as the argument. + conv_module (torch.nn.Module): Convolution module instance. + `ConvlutionModule` instance can be used as the argument. + dropout_rate (float): Dropout rate. + normalize_before (bool): + True: use layer_norm before each sub-block. + False: use layer_norm after each sub-block. + """ + + def __init__( + self, + size: int, + self_attn: torch.nn.Module, + feed_forward: Optional[nn.Module] = None, + feed_forward_macaron: Optional[nn.Module] = None, + conv_module: Optional[nn.Module] = None, + dropout_rate: float = 0.1, + normalize_before: bool = True, + ): + """Construct an EncoderLayer object.""" + super().__init__() + self.self_attn = self_attn + self.feed_forward = feed_forward + self.feed_forward_macaron = feed_forward_macaron + self.conv_module = conv_module + self.norm_ff = nn.LayerNorm(size, eps=1e-5) # for the FNN module + self.norm_mha = nn.LayerNorm(size, eps=1e-5) # for the MHA module + if feed_forward_macaron is not None: + self.norm_ff_macaron = nn.LayerNorm(size, eps=1e-5) + self.ff_scale = 0.5 + else: + self.ff_scale = 1.0 + if self.conv_module is not None: + self.norm_conv = nn.LayerNorm(size, eps=1e-5) # for the CNN module + self.norm_final = nn.LayerNorm( + size, eps=1e-5) # for the final output of the block + self.dropout = nn.Dropout(dropout_rate) + self.size = size + self.normalize_before = normalize_before + + def forward( + self, + x: torch.Tensor, + mask: torch.Tensor, + pos_emb: torch.Tensor, + mask_pad: torch.Tensor = torch.ones((0, 0, 0), dtype=torch.bool), + att_cache: torch.Tensor = torch.zeros((0, 0, 0, 0)), + cnn_cache: torch.Tensor = torch.zeros((0, 0, 0, 0)), + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + """Compute encoded features. + + Args: + x (torch.Tensor): (#batch, time, size) + mask (torch.Tensor): Mask tensor for the input (#batch, time,time), + (0, 0, 0) means fake mask. + pos_emb (torch.Tensor): positional encoding, must not be None + for ConformerEncoderLayer. + mask_pad (torch.Tensor): batch padding mask used for conv module. + (#batch, 1,time), (0, 0, 0) means fake mask. + att_cache (torch.Tensor): Cache tensor of the KEY & VALUE + (#batch=1, head, cache_t1, d_k * 2), head * d_k == size. + cnn_cache (torch.Tensor): Convolution cache in conformer layer + (#batch=1, size, cache_t2) + Returns: + torch.Tensor: Output tensor (#batch, time, size). + torch.Tensor: Mask tensor (#batch, time, time). + torch.Tensor: att_cache tensor, + (#batch=1, head, cache_t1 + time, d_k * 2). + torch.Tensor: cnn_cahce tensor (#batch, size, cache_t2). + """ + + # whether to use macaron style + if self.feed_forward_macaron is not None: + residual = x + if self.normalize_before: + x = self.norm_ff_macaron(x) + x = residual + self.ff_scale * self.dropout( + self.feed_forward_macaron(x)) + if not self.normalize_before: + x = self.norm_ff_macaron(x) + + # multi-headed self-attention module + residual = x + if self.normalize_before: + x = self.norm_mha(x) + x_att, new_att_cache = self.self_attn(x, x, x, mask, pos_emb, + att_cache) + x = residual + self.dropout(x_att) + if not self.normalize_before: + x = self.norm_mha(x) + + # convolution module + # Fake new cnn cache here, and then change it in conv_module + new_cnn_cache = torch.zeros((0, 0, 0), dtype=x.dtype, device=x.device) + if self.conv_module is not None: + residual = x + if self.normalize_before: + x = self.norm_conv(x) + x, new_cnn_cache = self.conv_module(x, mask_pad, cnn_cache) + x = residual + self.dropout(x) + + if not self.normalize_before: + x = self.norm_conv(x) + + # feed forward module + residual = x + if self.normalize_before: + x = self.norm_ff(x) + + x = residual + self.ff_scale * self.dropout(self.feed_forward(x)) + if not self.normalize_before: + x = self.norm_ff(x) + + if self.conv_module is not None: + x = self.norm_final(x) + + return x, mask, new_att_cache, new_cnn_cache diff --git a/xinference/thirdparty/cosyvoice/transformer/label_smoothing_loss.py b/xinference/thirdparty/cosyvoice/transformer/label_smoothing_loss.py new file mode 100644 index 0000000000..feacabf096 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/label_smoothing_loss.py @@ -0,0 +1,96 @@ +# Copyright (c) 2019 Shigeki Karita +# 2020 Mobvoi Inc (Binbin Zhang) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Label smoothing module.""" + +import torch +from torch import nn + + +class LabelSmoothingLoss(nn.Module): + """Label-smoothing loss. + + In a standard CE loss, the label's data distribution is: + [0,1,2] -> + [ + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + ] + + In the smoothing version CE Loss,some probabilities + are taken from the true label prob (1.0) and are divided + among other labels. + + e.g. + smoothing=0.1 + [0,1,2] -> + [ + [0.9, 0.05, 0.05], + [0.05, 0.9, 0.05], + [0.05, 0.05, 0.9], + ] + + Args: + size (int): the number of class + padding_idx (int): padding class id which will be ignored for loss + smoothing (float): smoothing rate (0.0 means the conventional CE) + normalize_length (bool): + normalize loss by sequence length if True + normalize loss by batch size if False + """ + + def __init__(self, + size: int, + padding_idx: int, + smoothing: float, + normalize_length: bool = False): + """Construct an LabelSmoothingLoss object.""" + super(LabelSmoothingLoss, self).__init__() + self.criterion = nn.KLDivLoss(reduction="none") + self.padding_idx = padding_idx + self.confidence = 1.0 - smoothing + self.smoothing = smoothing + self.size = size + self.normalize_length = normalize_length + + def forward(self, x: torch.Tensor, target: torch.Tensor) -> torch.Tensor: + """Compute loss between x and target. + + The model outputs and data labels tensors are flatten to + (batch*seqlen, class) shape and a mask is applied to the + padding part which should not be calculated for loss. + + Args: + x (torch.Tensor): prediction (batch, seqlen, class) + target (torch.Tensor): + target signal masked with self.padding_id (batch, seqlen) + Returns: + loss (torch.Tensor) : The KL loss, scalar float value + """ + assert x.size(2) == self.size + batch_size = x.size(0) + x = x.view(-1, self.size) + target = target.view(-1) + # use zeros_like instead of torch.no_grad() for true_dist, + # since no_grad() can not be exported by JIT + true_dist = torch.zeros_like(x) + true_dist.fill_(self.smoothing / (self.size - 1)) + ignore = target == self.padding_idx # (B,) + total = len(target) - ignore.sum().item() + target = target.masked_fill(ignore, 0) # avoid -1 index + true_dist.scatter_(1, target.unsqueeze(1), self.confidence) + kl = self.criterion(torch.log_softmax(x, dim=1), true_dist) + denom = total if self.normalize_length else batch_size + return kl.masked_fill(ignore.unsqueeze(1), 0).sum() / denom diff --git a/xinference/thirdparty/cosyvoice/transformer/positionwise_feed_forward.py b/xinference/thirdparty/cosyvoice/transformer/positionwise_feed_forward.py new file mode 100644 index 0000000000..b7a2cf6e73 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/positionwise_feed_forward.py @@ -0,0 +1,115 @@ +# Copyright (c) 2019 Shigeki Karita +# 2020 Mobvoi Inc (Binbin Zhang) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Positionwise feed forward layer definition.""" + +import torch + + +class PositionwiseFeedForward(torch.nn.Module): + """Positionwise feed forward layer. + + FeedForward are appied on each position of the sequence. + The output dim is same with the input dim. + + Args: + idim (int): Input dimenstion. + hidden_units (int): The number of hidden units. + dropout_rate (float): Dropout rate. + activation (torch.nn.Module): Activation function + """ + + def __init__( + self, + idim: int, + hidden_units: int, + dropout_rate: float, + activation: torch.nn.Module = torch.nn.ReLU(), + ): + """Construct a PositionwiseFeedForward object.""" + super(PositionwiseFeedForward, self).__init__() + self.w_1 = torch.nn.Linear(idim, hidden_units) + self.activation = activation + self.dropout = torch.nn.Dropout(dropout_rate) + self.w_2 = torch.nn.Linear(hidden_units, idim) + + def forward(self, xs: torch.Tensor) -> torch.Tensor: + """Forward function. + + Args: + xs: input tensor (B, L, D) + Returns: + output tensor, (B, L, D) + """ + return self.w_2(self.dropout(self.activation(self.w_1(xs)))) + + +class MoEFFNLayer(torch.nn.Module): + """ + Mixture of expert with Positionwise feed forward layer + See also figure 1 in https://arxiv.org/pdf/2305.15663.pdf + The output dim is same with the input dim. + + Modified from https://github.com/Lightning-AI/lit-gpt/pull/823 + https://github.com/mistralai/mistral-src/blob/b46d6/moe_one_file_ref.py#L203-L219 + Args: + n_expert: number of expert. + n_expert_per_token: The actual number of experts used for each frame + idim (int): Input dimenstion. + hidden_units (int): The number of hidden units. + dropout_rate (float): Dropout rate. + activation (torch.nn.Module): Activation function + """ + + def __init__( + self, + n_expert: int, + n_expert_per_token: int, + idim: int, + hidden_units: int, + dropout_rate: float, + activation: torch.nn.Module = torch.nn.ReLU(), + ): + super(MoEFFNLayer, self).__init__() + self.gate = torch.nn.Linear(idim, n_expert, bias=False) + self.experts = torch.nn.ModuleList( + PositionwiseFeedForward(idim, hidden_units, dropout_rate, + activation) for _ in range(n_expert)) + self.n_expert_per_token = n_expert_per_token + + def forward(self, xs: torch.Tensor) -> torch.Tensor: + """Foward function. + Args: + xs: input tensor (B, L, D) + Returns: + output tensor, (B, L, D) + + """ + B, L, D = xs.size( + ) # batch size, sequence length, embedding dimension (idim) + xs = xs.view(-1, D) # (B*L, D) + router = self.gate(xs) # (B*L, n_expert) + logits, indices = torch.topk( + router, self.n_expert_per_token + ) # probs:(B*L, n_expert), indices: (B*L, n_expert) + weights = torch.nn.functional.softmax( + logits, dim=1, + dtype=torch.float).to(dtype=xs.dtype) # (B*L, n_expert_per_token) + output = torch.zeros_like(xs) # (B*L, D) + for i, expert in enumerate(self.experts): + mask = indices == i + batch_idx, ith_expert = torch.where(mask) + output[batch_idx] += weights[batch_idx, ith_expert, None] * expert( + xs[batch_idx]) + return output.view(B, L, D) diff --git a/xinference/thirdparty/cosyvoice/transformer/subsampling.py b/xinference/thirdparty/cosyvoice/transformer/subsampling.py new file mode 100644 index 0000000000..e17c2e324e --- /dev/null +++ b/xinference/thirdparty/cosyvoice/transformer/subsampling.py @@ -0,0 +1,383 @@ +# Copyright (c) 2021 Mobvoi Inc (Binbin Zhang, Di Wu) +# 2024 Alibaba Inc (Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Subsampling layer definition.""" + +from typing import Tuple, Union + +import torch + + +class BaseSubsampling(torch.nn.Module): + + def __init__(self): + super().__init__() + self.right_context = 0 + self.subsampling_rate = 1 + + def position_encoding(self, offset: Union[int, torch.Tensor], + size: int) -> torch.Tensor: + return self.pos_enc.position_encoding(offset, size) + + +class EmbedinigNoSubsampling(BaseSubsampling): + """Embedding input without subsampling + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + super().__init__() + self.embed = torch.nn.Embedding(idim, odim) + self.pos_enc = pos_enc_class + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Input x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: linear input tensor (#batch, time', odim), + where time' = time . + torch.Tensor: linear input mask (#batch, 1, time'), + where time' = time . + + """ + x = self.embed(x) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask + + +class LinearNoSubsampling(BaseSubsampling): + """Linear transform the input without subsampling + + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an linear object.""" + super().__init__() + self.out = torch.nn.Sequential( + torch.nn.Linear(idim, odim), + torch.nn.LayerNorm(odim, eps=1e-5), + torch.nn.Dropout(dropout_rate), + ) + self.pos_enc = pos_enc_class + self.right_context = 0 + self.subsampling_rate = 1 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Input x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: linear input tensor (#batch, time', odim), + where time' = time . + torch.Tensor: linear input mask (#batch, 1, time'), + where time' = time . + + """ + x = self.out(x) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask + + +class Conv1dSubsampling2(BaseSubsampling): + """Convolutional 1D subsampling (to 1/2 length). + It is designed for Whisper, ref: + https://github.com/openai/whisper/blob/main/whisper/model.py + + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an Conv1dSubsampling2 object.""" + super().__init__() + self.conv = torch.nn.Sequential( + torch.nn.Conv1d(idim, odim, kernel_size=3, padding=1), + torch.nn.GELU(), + torch.nn.Conv1d(odim, odim, kernel_size=3, stride=2, padding=1), + torch.nn.GELU(), + ) + self.pos_enc = pos_enc_class + # The right context for every conv layer is computed by: + # (kernel_size - 1) * frame_rate_of_this_layer + self.subsampling_rate = 2 + # 4 = (3 - 1) * 1 + (3 - 1) * 1 + self.right_context = 4 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Subsample x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: Subsampled tensor (#batch, time', odim), + where time' = time // 2. + torch.Tensor: Subsampled mask (#batch, 1, time'), + where time' = time // 2. + torch.Tensor: positional encoding + + """ + time = x.size(1) + x = x.transpose(1, 2) # (b, f, t) + x = self.conv(x) + x = x.transpose(1, 2) # (b, t, f) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask[:, :, (time + 1) % 2::2] + + +class Conv2dSubsampling4(BaseSubsampling): + """Convolutional 2D subsampling (to 1/4 length). + + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an Conv2dSubsampling4 object.""" + super().__init__() + self.conv = torch.nn.Sequential( + torch.nn.Conv2d(1, odim, 3, 2), + torch.nn.ReLU(), + torch.nn.Conv2d(odim, odim, 3, 2), + torch.nn.ReLU(), + ) + self.out = torch.nn.Sequential( + torch.nn.Linear(odim * (((idim - 1) // 2 - 1) // 2), odim)) + self.pos_enc = pos_enc_class + # The right context for every conv layer is computed by: + # (kernel_size - 1) * frame_rate_of_this_layer + self.subsampling_rate = 4 + # 6 = (3 - 1) * 1 + (3 - 1) * 2 + self.right_context = 6 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Subsample x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: Subsampled tensor (#batch, time', odim), + where time' = time // 4. + torch.Tensor: Subsampled mask (#batch, 1, time'), + where time' = time // 4. + torch.Tensor: positional encoding + + """ + x = x.unsqueeze(1) # (b, c=1, t, f) + x = self.conv(x) + b, c, t, f = x.size() + x = self.out(x.transpose(1, 2).contiguous().view(b, t, c * f)) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask[:, :, 2::2][:, :, 2::2] + + +class Conv2dSubsampling6(BaseSubsampling): + """Convolutional 2D subsampling (to 1/6 length). + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + pos_enc (torch.nn.Module): Custom position encoding layer. + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an Conv2dSubsampling6 object.""" + super().__init__() + self.conv = torch.nn.Sequential( + torch.nn.Conv2d(1, odim, 3, 2), + torch.nn.ReLU(), + torch.nn.Conv2d(odim, odim, 5, 3), + torch.nn.ReLU(), + ) + self.linear = torch.nn.Linear(odim * (((idim - 1) // 2 - 2) // 3), + odim) + self.pos_enc = pos_enc_class + # 10 = (3 - 1) * 1 + (5 - 1) * 2 + self.subsampling_rate = 6 + self.right_context = 10 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Subsample x. + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: Subsampled tensor (#batch, time', odim), + where time' = time // 6. + torch.Tensor: Subsampled mask (#batch, 1, time'), + where time' = time // 6. + torch.Tensor: positional encoding + """ + x = x.unsqueeze(1) # (b, c, t, f) + x = self.conv(x) + b, c, t, f = x.size() + x = self.linear(x.transpose(1, 2).contiguous().view(b, t, c * f)) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask[:, :, 2::2][:, :, 4::3] + + +class Conv2dSubsampling8(BaseSubsampling): + """Convolutional 2D subsampling (to 1/8 length). + + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an Conv2dSubsampling8 object.""" + super().__init__() + self.conv = torch.nn.Sequential( + torch.nn.Conv2d(1, odim, 3, 2), + torch.nn.ReLU(), + torch.nn.Conv2d(odim, odim, 3, 2), + torch.nn.ReLU(), + torch.nn.Conv2d(odim, odim, 3, 2), + torch.nn.ReLU(), + ) + self.linear = torch.nn.Linear( + odim * ((((idim - 1) // 2 - 1) // 2 - 1) // 2), odim) + self.pos_enc = pos_enc_class + self.subsampling_rate = 8 + # 14 = (3 - 1) * 1 + (3 - 1) * 2 + (3 - 1) * 4 + self.right_context = 14 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Subsample x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: Subsampled tensor (#batch, time', odim), + where time' = time // 8. + torch.Tensor: Subsampled mask (#batch, 1, time'), + where time' = time // 8. + torch.Tensor: positional encoding + """ + x = x.unsqueeze(1) # (b, c, t, f) + x = self.conv(x) + b, c, t, f = x.size() + x = self.linear(x.transpose(1, 2).contiguous().view(b, t, c * f)) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask[:, :, 2::2][:, :, 2::2][:, :, 2::2] + + +class LegacyLinearNoSubsampling(BaseSubsampling): + """Linear transform the input without subsampling + + Args: + idim (int): Input dimension. + odim (int): Output dimension. + dropout_rate (float): Dropout rate. + + """ + + def __init__(self, idim: int, odim: int, dropout_rate: float, + pos_enc_class: torch.nn.Module): + """Construct an linear object.""" + super().__init__() + self.out = torch.nn.Sequential( + torch.nn.Linear(idim, odim), + torch.nn.LayerNorm(odim, eps=1e-5), + torch.nn.Dropout(dropout_rate), + torch.nn.ReLU(), + ) + self.pos_enc = pos_enc_class + self.right_context = 0 + self.subsampling_rate = 1 + + def forward( + self, + x: torch.Tensor, + x_mask: torch.Tensor, + offset: Union[int, torch.Tensor] = 0 + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Input x. + + Args: + x (torch.Tensor): Input tensor (#batch, time, idim). + x_mask (torch.Tensor): Input mask (#batch, 1, time). + + Returns: + torch.Tensor: linear input tensor (#batch, time', odim), + where time' = time . + torch.Tensor: linear input mask (#batch, 1, time'), + where time' = time . + + """ + x = self.out(x) + x, pos_emb = self.pos_enc(x, offset) + return x, pos_emb, x_mask diff --git a/xinference/thirdparty/cosyvoice/utils/__init__.py b/xinference/thirdparty/cosyvoice/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/cosyvoice/utils/class_utils.py b/xinference/thirdparty/cosyvoice/utils/class_utils.py new file mode 100644 index 0000000000..b8cc471458 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/class_utils.py @@ -0,0 +1,70 @@ +# Copyright [2023-11-28] +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import torch + +from cosyvoice.transformer.activation import Swish +from cosyvoice.transformer.subsampling import ( + LinearNoSubsampling, + EmbedinigNoSubsampling, + Conv1dSubsampling2, + Conv2dSubsampling4, + Conv2dSubsampling6, + Conv2dSubsampling8, +) +from cosyvoice.transformer.embedding import (PositionalEncoding, + RelPositionalEncoding, + WhisperPositionalEncoding, + LearnablePositionalEncoding, + NoPositionalEncoding) +from cosyvoice.transformer.attention import (MultiHeadedAttention, + RelPositionMultiHeadedAttention) +from cosyvoice.transformer.embedding import EspnetRelPositionalEncoding +from cosyvoice.transformer.subsampling import LegacyLinearNoSubsampling + + +COSYVOICE_ACTIVATION_CLASSES = { + "hardtanh": torch.nn.Hardtanh, + "tanh": torch.nn.Tanh, + "relu": torch.nn.ReLU, + "selu": torch.nn.SELU, + "swish": getattr(torch.nn, "SiLU", Swish), + "gelu": torch.nn.GELU, +} + +COSYVOICE_SUBSAMPLE_CLASSES = { + "linear": LinearNoSubsampling, + "linear_legacy": LegacyLinearNoSubsampling, + "embed": EmbedinigNoSubsampling, + "conv1d2": Conv1dSubsampling2, + "conv2d": Conv2dSubsampling4, + "conv2d6": Conv2dSubsampling6, + "conv2d8": Conv2dSubsampling8, + 'paraformer_dummy': torch.nn.Identity +} + +COSYVOICE_EMB_CLASSES = { + "embed": PositionalEncoding, + "abs_pos": PositionalEncoding, + "rel_pos": RelPositionalEncoding, + "rel_pos_espnet": EspnetRelPositionalEncoding, + "no_pos": NoPositionalEncoding, + "abs_pos_whisper": WhisperPositionalEncoding, + "embed_learnable_pe": LearnablePositionalEncoding, +} + +COSYVOICE_ATTENTION_CLASSES = { + "selfattn": MultiHeadedAttention, + "rel_selfattn": RelPositionMultiHeadedAttention, +} diff --git a/xinference/thirdparty/cosyvoice/utils/common.py b/xinference/thirdparty/cosyvoice/utils/common.py new file mode 100644 index 0000000000..6ec5e17835 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/common.py @@ -0,0 +1,103 @@ +# Copyright (c) 2020 Mobvoi Inc (Binbin Zhang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +"""Unility functions for Transformer.""" + +from typing import List + +import torch + +IGNORE_ID = -1 + + +def pad_list(xs: List[torch.Tensor], pad_value: int): + """Perform padding for the list of tensors. + + Args: + xs (List): List of Tensors [(T_1, `*`), (T_2, `*`), ..., (T_B, `*`)]. + pad_value (float): Value for padding. + + Returns: + Tensor: Padded tensor (B, Tmax, `*`). + + Examples: + >>> x = [torch.ones(4), torch.ones(2), torch.ones(1)] + >>> x + [tensor([1., 1., 1., 1.]), tensor([1., 1.]), tensor([1.])] + >>> pad_list(x, 0) + tensor([[1., 1., 1., 1.], + [1., 1., 0., 0.], + [1., 0., 0., 0.]]) + + """ + max_len = max([len(item) for item in xs]) + batchs = len(xs) + ndim = xs[0].ndim + if ndim == 1: + pad_res = torch.zeros(batchs, + max_len, + dtype=xs[0].dtype, + device=xs[0].device) + elif ndim == 2: + pad_res = torch.zeros(batchs, + max_len, + xs[0].shape[1], + dtype=xs[0].dtype, + device=xs[0].device) + elif ndim == 3: + pad_res = torch.zeros(batchs, + max_len, + xs[0].shape[1], + xs[0].shape[2], + dtype=xs[0].dtype, + device=xs[0].device) + else: + raise ValueError(f"Unsupported ndim: {ndim}") + pad_res.fill_(pad_value) + for i in range(batchs): + pad_res[i, :len(xs[i])] = xs[i] + return pad_res + + +def th_accuracy(pad_outputs: torch.Tensor, pad_targets: torch.Tensor, + ignore_label: int) -> torch.Tensor: + """Calculate accuracy. + + Args: + pad_outputs (Tensor): Prediction tensors (B * Lmax, D). + pad_targets (LongTensor): Target label tensors (B, Lmax). + ignore_label (int): Ignore label id. + + Returns: + torch.Tensor: Accuracy value (0.0 - 1.0). + + """ + pad_pred = pad_outputs.view(pad_targets.size(0), pad_targets.size(1), + pad_outputs.size(1)).argmax(2) + mask = pad_targets != ignore_label + numerator = torch.sum( + pad_pred.masked_select(mask) == pad_targets.masked_select(mask)) + denominator = torch.sum(mask) + return (numerator / denominator).detach() + + +def get_padding(kernel_size, dilation=1): + return int((kernel_size * dilation - dilation) / 2) + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) diff --git a/xinference/thirdparty/cosyvoice/utils/executor.py b/xinference/thirdparty/cosyvoice/utils/executor.py new file mode 100644 index 0000000000..c12e52df9f --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/executor.py @@ -0,0 +1,110 @@ +# Copyright (c) 2020 Mobvoi Inc (Binbin Zhang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from contextlib import nullcontext +import os + +import torch +import torch.distributed as dist + +from cosyvoice.utils.train_utils import update_parameter_and_lr, log_per_step, log_per_save, batch_forward, batch_backward, save_model, cosyvoice_join + + +class Executor: + + def __init__(self): + self.step = 0 + self.epoch = 0 + self.rank = int(os.environ.get('RANK', 0)) + self.device = torch.device('cuda:{}'.format(self.rank)) + + def train_one_epoc(self, model, optimizer, scheduler, train_data_loader, cv_data_loader, writer, info_dict, group_join): + ''' Train one epoch + ''' + + lr = optimizer.param_groups[0]['lr'] + logging.info('Epoch {} TRAIN info lr {} rank {}'.format(self.epoch, lr, self.rank)) + logging.info('using accumulate grad, new batch size is {} times' + ' larger than before'.format(info_dict['accum_grad'])) + # A context manager to be used in conjunction with an instance of + # torch.nn.parallel.DistributedDataParallel to be able to train + # with uneven inputs across participating processes. + model.train() + model_context = model.join if info_dict['train_engine'] == 'torch_ddp' else nullcontext + with model_context(): + for batch_idx, batch_dict in enumerate(train_data_loader): + info_dict["tag"] = "TRAIN" + info_dict["step"] = self.step + info_dict["epoch"] = self.epoch + info_dict["batch_idx"] = batch_idx + if cosyvoice_join(group_join, info_dict): + break + + # Disable gradient synchronizations across DDP processes. + # Within this context, gradients will be accumulated on module + # variables, which will later be synchronized. + if info_dict['train_engine'] == 'torch_ddp' and (batch_idx + 1) % info_dict["accum_grad"] != 0: + context = model.no_sync + # Used for single gpu training and DDP gradient synchronization + # processes. + else: + context = nullcontext + + with context(): + info_dict = batch_forward(model, batch_dict, info_dict) + info_dict = batch_backward(model, info_dict) + + info_dict = update_parameter_and_lr(model, optimizer, scheduler, info_dict) + log_per_step(writer, info_dict) + # NOTE specify save_per_step in cosyvoice.yaml if you want to enable step save + if info_dict['save_per_step'] > 0 and (self.step + 1) % info_dict['save_per_step'] == 0 and (batch_idx + 1) % info_dict["accum_grad"] == 0: + dist.barrier() + self.cv(model, cv_data_loader, writer, info_dict, on_batch_end=False) + model.train() + if (batch_idx + 1) % info_dict["accum_grad"] == 0: + self.step += 1 + dist.barrier() + self.cv(model, cv_data_loader, writer, info_dict, on_batch_end=True) + + @torch.inference_mode() + def cv(self, model, cv_data_loader, writer, info_dict, on_batch_end=True): + ''' Cross validation on + ''' + logging.info('Epoch {} Step {} on_batch_end {} CV rank {}'.format(self.epoch, self.step + 1, on_batch_end, self.rank)) + model.eval() + total_num_utts, total_loss_dict = 0, {} # avoid division by 0 + for batch_idx, batch_dict in enumerate(cv_data_loader): + info_dict["tag"] = "CV" + info_dict["step"] = self.step + info_dict["epoch"] = self.epoch + info_dict["batch_idx"] = batch_idx + + num_utts = len(batch_dict["utts"]) + total_num_utts += num_utts + + info_dict = batch_forward(model, batch_dict, info_dict) + + for k, v in info_dict['loss_dict'].items(): + if k not in total_loss_dict: + total_loss_dict[k] = [] + total_loss_dict[k].append(v.item() * num_utts) + log_per_step(None, info_dict) + for k, v in total_loss_dict.items(): + total_loss_dict[k] = sum(v) / total_num_utts + info_dict['loss_dict'] = total_loss_dict + log_per_save(writer, info_dict) + model_name = 'epoch_{}_whole'.format(self.epoch) if on_batch_end else 'epoch_{}_step_{}'.format(self.epoch, self.step + 1) + save_model(model, model_name, info_dict) diff --git a/xinference/thirdparty/cosyvoice/utils/file_utils.py b/xinference/thirdparty/cosyvoice/utils/file_utils.py new file mode 100644 index 0000000000..92c448b9cc --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/file_utils.py @@ -0,0 +1,41 @@ +# Copyright (c) 2021 Mobvoi Inc. (authors: Binbin Zhang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import torchaudio + + +def read_lists(list_file): + lists = [] + with open(list_file, 'r', encoding='utf8') as fin: + for line in fin: + lists.append(line.strip()) + return lists + +def read_json_lists(list_file): + lists = read_lists(list_file) + results = {} + for fn in lists: + with open(fn, 'r', encoding='utf8') as fin: + results.update(json.load(fin)) + return results + +def load_wav(wav, target_sr): + speech, sample_rate = torchaudio.load(wav) + speech = speech.mean(dim=0, keepdim=True) + if sample_rate != target_sr: + assert sample_rate > target_sr, 'wav sample rate {} must be greater than {}'.format(sample_rate, target_sr) + speech = torchaudio.transforms.Resample(orig_freq=sample_rate, new_freq=target_sr)(speech) + return speech diff --git a/xinference/thirdparty/cosyvoice/utils/frontend_utils.py b/xinference/thirdparty/cosyvoice/utils/frontend_utils.py new file mode 100644 index 0000000000..59489a7a6f --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/frontend_utils.py @@ -0,0 +1,125 @@ +# Copyright (c) 2024 Alibaba Inc (authors: Xiang Lyu, Zhihao Du) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +chinese_char_pattern = re.compile(r'[\u4e00-\u9fff]+') + +# whether contain chinese character +def contains_chinese(text): + return bool(chinese_char_pattern.search(text)) + + +# replace special symbol +def replace_corner_mark(text): + text = text.replace('²', '平方') + text = text.replace('³', '立方') + return text + + +# remove meaningless symbol +def remove_bracket(text): + text = text.replace('(', '').replace(')', '') + text = text.replace('【', '').replace('】', '') + text = text.replace('`', '').replace('`', '') + text = text.replace("——", " ") + return text + + +# spell Arabic numerals +def spell_out_number(text: str, inflect_parser): + new_text = [] + st = None + for i, c in enumerate(text): + if not c.isdigit(): + if st is not None: + num_str = inflect_parser.number_to_words(text[st: i]) + new_text.append(num_str) + st = None + new_text.append(c) + else: + if st is None: + st = i + if st is not None and st < len(text): + num_str = inflect_parser.number_to_words(text[st:]) + new_text.append(num_str) + return ''.join(new_text) + + +# split paragrah logic: +# 1. per sentence max len token_max_n, min len token_min_n, merge if last sentence len less than merge_len +# 2. cal sentence len according to lang +# 3. split sentence according to puncatation +def split_paragraph(text: str, tokenize, lang="zh", token_max_n=80, token_min_n=60, merge_len=20, comma_split=False): + def calc_utt_length(_text: str): + if lang == "zh": + return len(_text) + else: + return len(tokenize(_text)) + + def should_merge(_text: str): + if lang == "zh": + return len(_text) < merge_len + else: + return len(tokenize(_text)) < merge_len + + if lang == "zh": + pounc = ['。', '?', '!', ';', ':', '、', '.', '?', '!', ';'] + else: + pounc = ['.', '?', '!', ';', ':'] + if comma_split: + pounc.extend([',', ',']) + st = 0 + utts = [] + for i, c in enumerate(text): + if c in pounc: + if len(text[st: i]) > 0: + utts.append(text[st: i] + c) + if i + 1 < len(text) and text[i + 1] in ['"', '”']: + tmp = utts.pop(-1) + utts.append(tmp + text[i + 1]) + st = i + 2 + else: + st = i + 1 + if len(utts) == 0: + if lang == "zh": + utts.append(text + '。') + else: + utts.append(text + '.') + final_utts = [] + cur_utt = "" + for utt in utts: + if calc_utt_length(cur_utt + utt) > token_max_n and calc_utt_length(cur_utt) > token_min_n: + final_utts.append(cur_utt) + cur_utt = "" + cur_utt = cur_utt + utt + if len(cur_utt) > 0: + if should_merge(cur_utt) and len(final_utts) != 0: + final_utts[-1] = final_utts[-1] + cur_utt + else: + final_utts.append(cur_utt) + + return final_utts + + +# remove blank between chinese character +def replace_blank(text: str): + out_str = [] + for i, c in enumerate(text): + if c == " ": + if ((text[i + 1].isascii() and text[i + 1] != " ") and + (text[i - 1].isascii() and text[i - 1] != " ")): + out_str.append(c) + else: + out_str.append(c) + return "".join(out_str) diff --git a/xinference/thirdparty/cosyvoice/utils/mask.py b/xinference/thirdparty/cosyvoice/utils/mask.py new file mode 100644 index 0000000000..2b460bbd5a --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/mask.py @@ -0,0 +1,227 @@ +# Copyright (c) 2019 Shigeki Karita +# 2020 Mobvoi Inc (Binbin Zhang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import torch +''' +def subsequent_mask( + size: int, + device: torch.device = torch.device("cpu"), +) -> torch.Tensor: + """Create mask for subsequent steps (size, size). + + This mask is used only in decoder which works in an auto-regressive mode. + This means the current step could only do attention with its left steps. + + In encoder, fully attention is used when streaming is not necessary and + the sequence is not long. In this case, no attention mask is needed. + + When streaming is need, chunk-based attention is used in encoder. See + subsequent_chunk_mask for the chunk-based attention mask. + + Args: + size (int): size of mask + str device (str): "cpu" or "cuda" or torch.Tensor.device + dtype (torch.device): result dtype + + Returns: + torch.Tensor: mask + + Examples: + >>> subsequent_mask(3) + [[1, 0, 0], + [1, 1, 0], + [1, 1, 1]] + """ + ret = torch.ones(size, size, device=device, dtype=torch.bool) + return torch.tril(ret) +''' + + +def subsequent_mask( + size: int, + device: torch.device = torch.device("cpu"), +) -> torch.Tensor: + """Create mask for subsequent steps (size, size). + + This mask is used only in decoder which works in an auto-regressive mode. + This means the current step could only do attention with its left steps. + + In encoder, fully attention is used when streaming is not necessary and + the sequence is not long. In this case, no attention mask is needed. + + When streaming is need, chunk-based attention is used in encoder. See + subsequent_chunk_mask for the chunk-based attention mask. + + Args: + size (int): size of mask + str device (str): "cpu" or "cuda" or torch.Tensor.device + dtype (torch.device): result dtype + + Returns: + torch.Tensor: mask + + Examples: + >>> subsequent_mask(3) + [[1, 0, 0], + [1, 1, 0], + [1, 1, 1]] + """ + arange = torch.arange(size, device=device) + mask = arange.expand(size, size) + arange = arange.unsqueeze(-1) + mask = mask <= arange + return mask + + +def subsequent_chunk_mask( + size: int, + chunk_size: int, + num_left_chunks: int = -1, + device: torch.device = torch.device("cpu"), +) -> torch.Tensor: + """Create mask for subsequent steps (size, size) with chunk size, + this is for streaming encoder + + Args: + size (int): size of mask + chunk_size (int): size of chunk + num_left_chunks (int): number of left chunks + <0: use full chunk + >=0: use num_left_chunks + device (torch.device): "cpu" or "cuda" or torch.Tensor.device + + Returns: + torch.Tensor: mask + + Examples: + >>> subsequent_chunk_mask(4, 2) + [[1, 1, 0, 0], + [1, 1, 0, 0], + [1, 1, 1, 1], + [1, 1, 1, 1]] + """ + ret = torch.zeros(size, size, device=device, dtype=torch.bool) + for i in range(size): + if num_left_chunks < 0: + start = 0 + else: + start = max((i // chunk_size - num_left_chunks) * chunk_size, 0) + ending = min((i // chunk_size + 1) * chunk_size, size) + ret[i, start:ending] = True + return ret + + +def add_optional_chunk_mask(xs: torch.Tensor, + masks: torch.Tensor, + use_dynamic_chunk: bool, + use_dynamic_left_chunk: bool, + decoding_chunk_size: int, + static_chunk_size: int, + num_decoding_left_chunks: int, + enable_full_context: bool = True): + """ Apply optional mask for encoder. + + Args: + xs (torch.Tensor): padded input, (B, L, D), L for max length + mask (torch.Tensor): mask for xs, (B, 1, L) + use_dynamic_chunk (bool): whether to use dynamic chunk or not + use_dynamic_left_chunk (bool): whether to use dynamic left chunk for + training. + decoding_chunk_size (int): decoding chunk size for dynamic chunk, it's + 0: default for training, use random dynamic chunk. + <0: for decoding, use full chunk. + >0: for decoding, use fixed chunk size as set. + static_chunk_size (int): chunk size for static chunk training/decoding + if it's greater than 0, if use_dynamic_chunk is true, + this parameter will be ignored + num_decoding_left_chunks: number of left chunks, this is for decoding, + the chunk size is decoding_chunk_size. + >=0: use num_decoding_left_chunks + <0: use all left chunks + enable_full_context (bool): + True: chunk size is either [1, 25] or full context(max_len) + False: chunk size ~ U[1, 25] + + Returns: + torch.Tensor: chunk mask of the input xs. + """ + # Whether to use chunk mask or not + if use_dynamic_chunk: + max_len = xs.size(1) + if decoding_chunk_size < 0: + chunk_size = max_len + num_left_chunks = -1 + elif decoding_chunk_size > 0: + chunk_size = decoding_chunk_size + num_left_chunks = num_decoding_left_chunks + else: + # chunk size is either [1, 25] or full context(max_len). + # Since we use 4 times subsampling and allow up to 1s(100 frames) + # delay, the maximum frame is 100 / 4 = 25. + chunk_size = torch.randint(1, max_len, (1, )).item() + num_left_chunks = -1 + if chunk_size > max_len // 2 and enable_full_context: + chunk_size = max_len + else: + chunk_size = chunk_size % 25 + 1 + if use_dynamic_left_chunk: + max_left_chunks = (max_len - 1) // chunk_size + num_left_chunks = torch.randint(0, max_left_chunks, + (1, )).item() + chunk_masks = subsequent_chunk_mask(xs.size(1), chunk_size, + num_left_chunks, + xs.device) # (L, L) + chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L) + chunk_masks = masks & chunk_masks # (B, L, L) + elif static_chunk_size > 0: + num_left_chunks = num_decoding_left_chunks + chunk_masks = subsequent_chunk_mask(xs.size(1), static_chunk_size, + num_left_chunks, + xs.device) # (L, L) + chunk_masks = chunk_masks.unsqueeze(0) # (1, L, L) + chunk_masks = masks & chunk_masks # (B, L, L) + else: + chunk_masks = masks + return chunk_masks + + +def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor: + """Make mask tensor containing indices of padded part. + + See description of make_non_pad_mask. + + Args: + lengths (torch.Tensor): Batch of lengths (B,). + Returns: + torch.Tensor: Mask tensor containing indices of padded part. + + Examples: + >>> lengths = [5, 3, 2] + >>> make_pad_mask(lengths) + masks = [[0, 0, 0, 0 ,0], + [0, 0, 0, 1, 1], + [0, 0, 1, 1, 1]] + """ + batch_size = lengths.size(0) + max_len = max_len if max_len > 0 else lengths.max().item() + seq_range = torch.arange(0, + max_len, + dtype=torch.int64, + device=lengths.device) + seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len) + seq_length_expand = lengths.unsqueeze(-1) + mask = seq_range_expand >= seq_length_expand + return mask diff --git a/xinference/thirdparty/cosyvoice/utils/scheduler.py b/xinference/thirdparty/cosyvoice/utils/scheduler.py new file mode 100644 index 0000000000..fbf4803f81 --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/scheduler.py @@ -0,0 +1,739 @@ +# Copyright (c) 2020 Mobvoi Inc (Binbin Zhang) +# 2022 Ximalaya Inc (Yuguang Yang) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Modified from ESPnet(https://github.com/espnet/espnet) +# NeMo(https://github.com/NVIDIA/NeMo) + +from typing import Union + +import math +import warnings +import torch +from torch.optim.lr_scheduler import _LRScheduler + + +class WarmupLR(_LRScheduler): + """The WarmupLR scheduler + + This scheduler is almost same as NoamLR Scheduler except for following + difference: + + NoamLR: + lr = optimizer.lr * model_size ** -0.5 + * min(step ** -0.5, step * warmup_step ** -1.5) + WarmupLR: + lr = optimizer.lr * warmup_step ** 0.5 + * min(step ** -0.5, step * warmup_step ** -1.5) + + Note that the maximum lr equals to optimizer.lr in this scheduler. + + """ + + def __init__( + self, + optimizer: torch.optim.Optimizer, + warmup_steps: Union[int, float] = 25000, + last_epoch: int = -1, + ): + self.warmup_steps = warmup_steps + + # __init__() must be invoked before setting field + # because step() is also invoked in __init__() + super().__init__(optimizer, last_epoch) + + def __repr__(self): + return f"{self.__class__.__name__}(warmup_steps={self.warmup_steps})" + + def get_lr(self): + step_num = self.last_epoch + 1 + if self.warmup_steps == 0: + return [lr * step_num**-0.5 for lr in self.base_lrs] + else: + return [ + lr * self.warmup_steps**0.5 * + min(step_num**-0.5, step_num * self.warmup_steps**-1.5) + for lr in self.base_lrs + ] + + def set_step(self, step: int): + self.last_epoch = step + + +class WarmupPolicy(_LRScheduler): + """Adds warmup kwargs and warmup logic to lr policy. + All arguments should be passed as kwargs for clarity, + Args: + warmup_steps: Number of training steps in warmup stage + warmup_ratio: Ratio of warmup steps to total steps + max_steps: Total number of steps while training or `None` for + infinite training + """ + + def __init__(self, + optimizer, + *, + warmup_steps=None, + warmup_ratio=None, + max_steps=None, + min_lr=0.0, + last_epoch=-1): + assert not (warmup_steps is not None and warmup_ratio is not None),\ + "Either use particular number of step or ratio" + assert warmup_ratio is None or max_steps is not None, \ + "If there is a ratio, there should be a total steps" + + # It is necessary to assign all attributes *before* __init__, + # as class is wrapped by an inner class. + self.max_steps = max_steps + if warmup_steps is not None: + self.warmup_steps = warmup_steps + elif warmup_ratio is not None: + self.warmup_steps = int(warmup_ratio * max_steps) + else: + self.warmup_steps = 0 + + self.min_lr = min_lr + super().__init__(optimizer, last_epoch) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn( + "To get the last learning rate computed " + "by the scheduler, please use `get_last_lr()`.", + UserWarning, + stacklevel=2) + + step = self.last_epoch + + if step <= self.warmup_steps and self.warmup_steps > 0: + return self._get_warmup_lr(step) + + if step > self.max_steps: + return [self.min_lr for _ in self.base_lrs] + + return self._get_lr(step) + + def _get_warmup_lr(self, step): + lr_val = (step + 1) / (self.warmup_steps + 1) + return [initial_lr * lr_val for initial_lr in self.base_lrs] + + def _get_lr(self, step): + """Simple const lr policy""" + return self.base_lrs + + +class SquareRootConstantPolicy(_LRScheduler): + """Adds warmup kwargs and warmup logic to lr policy. + All arguments should be passed as kwargs for clarity, + Args: + warmup_steps: Number of training steps in warmup stage + warmup_ratio: Ratio of warmup steps to total steps + max_steps: Total number of steps while training or `None` for + infinite training + """ + + def __init__(self, + optimizer, + *, + constant_steps=None, + constant_ratio=None, + max_steps=None, + min_lr=0.0, + last_epoch=-1): + assert not (constant_steps is not None + and constant_ratio is not None), \ + "Either use particular number of step or ratio" + assert constant_ratio is None or max_steps is not None, \ + "If there is a ratio, there should be a total steps" + + # It is necessary to assign all attributes *before* __init__, + # as class is wrapped by an inner class. + self.max_steps = max_steps + if constant_steps is not None: + self.constant_steps = constant_steps + elif constant_ratio is not None: + self.constant_steps = int(constant_ratio * max_steps) + else: + self.constant_steps = 0 + + self.constant_lr = 1 / (constant_steps**0.5) + self.min_lr = min_lr + super().__init__(optimizer, last_epoch) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn( + "To get the last learning rate computed " + "by the scheduler, please use `get_last_lr()`.", + UserWarning, + stacklevel=2) + + step = self.last_epoch + + if step <= self.constant_steps: + return [self.constant_lr for _ in self.base_lrs] + + if step > self.max_steps: + return [self.min_lr for _ in self.base_lrs] + + return self._get_lr(step) + + def _get_lr(self, step): + """Simple const lr policy""" + return self.base_lrs + + +class WarmupHoldPolicy(WarmupPolicy): + """Variant of WarmupPolicy which maintains high + learning rate for a defined number of steps. + All arguments should be passed as kwargs for clarity, + Args: + warmup_steps: Number of training steps in warmup stage + warmup_ratio: Ratio of warmup steps to total steps + hold_steps: Number of training steps to + hold the learning rate after warm up + hold_ratio: Ratio of hold steps to total steps + max_steps: Total number of steps while training or `None` for + infinite training + """ + + def __init__( + self, + optimizer, + *, + warmup_steps=None, + warmup_ratio=None, + hold_steps=None, + hold_ratio=None, + max_steps=None, + min_lr=0.0, + last_epoch=-1, + ): + assert not (hold_steps is not None and hold_ratio is not None), \ + "Either use particular number of step or ratio" + assert hold_ratio is None or max_steps is not None, \ + "If there is a ratio, there should be a total steps" + + self.min_lr = min_lr + self._last_warmup_lr = 0.0 + + # Necessary to duplicate as class attributes are hidden in inner class + self.max_steps = max_steps + if warmup_steps is not None: + self.warmup_steps = warmup_steps + elif warmup_ratio is not None: + self.warmup_steps = int(warmup_ratio * max_steps) + else: + self.warmup_steps = 0 + + if hold_steps is not None: + self.hold_steps = hold_steps + self.warmup_steps + elif hold_ratio is not None: + self.hold_steps = int(hold_ratio * max_steps) + self.warmup_steps + else: + self.hold_steps = 0 + + super().__init__( + optimizer, + warmup_steps=warmup_steps, + warmup_ratio=warmup_ratio, + max_steps=max_steps, + last_epoch=last_epoch, + min_lr=min_lr, + ) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn( + "To get the last learning rate computed by the scheduler," + " " + "please use `get_last_lr()`.", + UserWarning, + stacklevel=2) + + step = self.last_epoch + + # Warmup phase + if step <= self.warmup_steps and self.warmup_steps > 0: + return self._get_warmup_lr(step) + + # Hold phase + if (step >= self.warmup_steps) and (step < self.hold_steps): + return self.base_lrs + + if step > self.max_steps: + return [self.min_lr for _ in self.base_lrs] + + return self._get_lr(step) + + +class WarmupAnnealHoldPolicy(_LRScheduler): + """Adds warmup kwargs and warmup logic to lr policy. + All arguments should be passed as kwargs for clarity, + Args: + warmup_steps: Number of training steps in warmup stage + warmup_ratio: Ratio of warmup steps to total steps + max_steps: Total number of steps while training or `None` for + infinite training + min_lr: Minimum lr to hold the learning rate after decay at. + constant_steps: Number of steps to keep lr constant at. + constant_ratio: Ratio of steps to keep lr constant. + """ + + def __init__( + self, + optimizer, + *, + warmup_steps=None, + warmup_ratio=None, + constant_steps=None, + constant_ratio=None, + max_steps=None, + min_lr=0.0, + last_epoch=-1, + ): + assert not (warmup_steps is not None + and warmup_ratio is not None), \ + "Either use particular number of step or ratio" + assert not (constant_steps is not None + and constant_ratio is not None), \ + "Either use constant_steps or constant_ratio" + assert warmup_ratio is None or max_steps is not None, \ + "If there is a ratio, there should be a total steps" + + # It is necessary to assign all attributes *before* __init__, + # as class is wrapped by an inner class. + self.max_steps = max_steps + + if warmup_steps is not None: + self.warmup_steps = warmup_steps + elif warmup_ratio is not None: + self.warmup_steps = int(warmup_ratio * max_steps) + else: + self.warmup_steps = 0 + + if constant_steps is not None: + self.constant_steps = constant_steps + elif constant_ratio is not None: + self.constant_steps = int(constant_ratio * max_steps) + else: + self.constant_steps = 0 + + self.decay_steps = max_steps - (self.constant_steps + + self.warmup_steps) + + self.min_lr = min_lr + super().__init__(optimizer, last_epoch) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn( + "To get the last learning rate computed " + "by the scheduler, please use `get_last_lr()`.", + UserWarning, + stacklevel=2) + + step = self.last_epoch + + # Warmup steps + if self.warmup_steps > 0 and step <= self.warmup_steps: + return self._get_warmup_lr(step) + + # Constant steps after warmup and decay + if self.constant_steps > 0 and ( + self.warmup_steps + self.decay_steps) < step <= self.max_steps: + return self._get_constant_lr(step) + + # Min lr after max steps of updates + if step > self.max_steps: + return [self.min_lr for _ in self.base_lrs] + + return self._get_lr(step) + + def _get_warmup_lr(self, step): + lr_val = (step + 1) / (self.warmup_steps + 1) + return [initial_lr * lr_val for initial_lr in self.base_lrs] + + def _get_constant_lr(self, step): + return [self.min_lr for _ in self.base_lrs] + + def _get_lr(self, step): + """Simple const lr policy""" + return self.base_lrs + + +def _squareroot_annealing(initial_lr, step, max_steps, min_lr): + mult = ((max_steps - step) / max_steps)**0.5 + out_lr = initial_lr * mult + out_lr = max(out_lr, min_lr) + return out_lr + + +def _square_annealing(initial_lr, step, max_steps, min_lr): + mult = ((max_steps - step) / max_steps)**2 + out_lr = initial_lr * mult + out_lr = max(out_lr, min_lr) + return out_lr + + +def _cosine_annealing(initial_lr, step, max_steps, min_lr): + mult = 0.5 * (1 + math.cos(math.pi * step / max_steps)) + out_lr = (initial_lr - min_lr) * mult + min_lr + return out_lr + + +def _linear_warmup_with_cosine_annealing(max_lr, warmup_steps, step, + decay_steps, min_lr): + assert max_lr > min_lr + # Use linear warmup for the initial part. + if warmup_steps > 0 and step <= warmup_steps: + return max_lr * float(step) / float(warmup_steps) + + # For any steps larger than `decay_steps`, use `min_lr`. + if step > warmup_steps + decay_steps: + return min_lr + + # If we are done with the warmup period, use the decay style. + num_steps_ = step - warmup_steps + decay_steps_ = decay_steps + decay_ratio = float(num_steps_) / float(decay_steps_) + assert decay_ratio >= 0.0 + assert decay_ratio <= 1.0 + delta_lr = max_lr - min_lr + + coeff = 0.5 * (math.cos(math.pi * decay_ratio) + 1.0) + + return min_lr + coeff * delta_lr + + +def _poly_decay(initial_lr, step, decay_steps, power, min_lr, cycle): + if cycle: + multiplier = 1.0 if step == 0 else math.ceil(step / decay_steps) + decay_steps *= multiplier + else: + step = min(step, decay_steps) + p = step / decay_steps + lr = (initial_lr - min_lr) * math.pow(1.0 - p, power) + lr += min_lr + return lr + + +def _noam_hold_annealing(initial_lr, step, warmup_steps, hold_steps, + decay_rate, min_lr): + # hold_steps = total number of steps + # to hold the LR, not the warmup + hold steps. + T_warmup_decay = max(1, warmup_steps**decay_rate) + T_hold_decay = max(1, (step - hold_steps)**decay_rate) + lr = (initial_lr * T_warmup_decay) / T_hold_decay + lr = max(lr, min_lr) + return lr + + +class SquareAnnealing(WarmupPolicy): + + def __init__(self, + optimizer, + *, + max_steps, + min_lr=1e-5, + last_epoch=-1, + **kwargs): + super().__init__(optimizer=optimizer, + max_steps=max_steps, + last_epoch=last_epoch, + min_lr=min_lr, + **kwargs) + + def _get_lr(self, step): + new_lrs = [ + _square_annealing( + initial_lr=initial_lr, + step=step - self.warmup_steps, + max_steps=self.max_steps - self.warmup_steps, + min_lr=self.min_lr, + ) for initial_lr in self.base_lrs + ] + return new_lrs + + +class SquareRootAnnealing(WarmupPolicy): + + def __init__(self, + optimizer, + *, + max_steps, + min_lr=0, + last_epoch=-1, + **kwargs): + super().__init__(optimizer=optimizer, + max_steps=max_steps, + last_epoch=last_epoch, + min_lr=min_lr, + **kwargs) + + def _get_lr(self, step): + new_lrs = [ + _squareroot_annealing(initial_lr=initial_lr, + step=step, + max_steps=self.max_steps, + min_lr=self.min_lr) + for initial_lr in self.base_lrs + ] + return new_lrs + + +class CosineAnnealing(WarmupAnnealHoldPolicy): + + def __init__(self, + optimizer, + *, + max_steps, + min_lr=0, + last_epoch=-1, + **kwargs): + super().__init__(optimizer=optimizer, + max_steps=max_steps, + last_epoch=last_epoch, + min_lr=min_lr, + **kwargs) + + def _get_lr(self, step): + for initial_lr in self.base_lrs: + if initial_lr < self.min_lr: + raise ValueError( + f"{self} received an initial learning rate " + f"that was lower than the minimum learning rate.") + + if self.constant_steps is None or self.constant_steps == 0: + new_lrs = [ + _cosine_annealing( + initial_lr=initial_lr, + step=step - self.warmup_steps, + max_steps=self.max_steps - self.warmup_steps, + min_lr=self.min_lr, + ) for initial_lr in self.base_lrs + ] + else: + new_lrs = self._get_linear_warmup_with_cosine_annealing_lr(step) + return new_lrs + + def _get_warmup_lr(self, step): + if self.constant_steps is None or self.constant_steps == 0: + return super()._get_warmup_lr(step) + else: + # Use linear warmup for the initial part. + return self._get_linear_warmup_with_cosine_annealing_lr(step) + + def _get_constant_lr(self, step): + # Only called when `constant_steps` > 0. + return self._get_linear_warmup_with_cosine_annealing_lr(step) + + def _get_linear_warmup_with_cosine_annealing_lr(self, step): + # Cosine Schedule for Megatron LM, + # slightly different warmup schedule + constant LR at the end. + new_lrs = [ + _linear_warmup_with_cosine_annealing( + max_lr=self.base_lrs[0], + warmup_steps=self.warmup_steps, + step=step, + decay_steps=self.decay_steps, + min_lr=self.min_lr, + ) for _ in self.base_lrs + ] + return new_lrs + + +class NoamAnnealing(_LRScheduler): + + def __init__(self, + optimizer, + *, + d_model, + warmup_steps=None, + warmup_ratio=None, + max_steps=None, + min_lr=0.0, + last_epoch=-1): + self._normalize = d_model**(-0.5) + assert not (warmup_steps is not None + and warmup_ratio is not None), \ + "Either use particular number of step or ratio" + assert warmup_ratio is None or max_steps is not None, \ + "If there is a ratio, there should be a total steps" + + # It is necessary to assign all attributes *before* __init__, + # as class is wrapped by an inner class. + self.max_steps = max_steps + if warmup_steps is not None: + self.warmup_steps = warmup_steps + elif warmup_ratio is not None: + self.warmup_steps = int(warmup_ratio * max_steps) + else: + self.warmup_steps = 0 + + self.min_lr = min_lr + super().__init__(optimizer, last_epoch) + + def get_lr(self): + if not self._get_lr_called_within_step: + warnings.warn( + "To get the last learning rate computed " + "by the scheduler, please use `get_last_lr()`.", + UserWarning, + stacklevel=2) + + step = max(1, self.last_epoch) + + for initial_lr in self.base_lrs: + if initial_lr < self.min_lr: + raise ValueError( + f"{self} received an initial learning rate " + f"that was lower than the minimum learning rate.") + + new_lrs = [ + self._noam_annealing(initial_lr=initial_lr, step=step) + for initial_lr in self.base_lrs + ] + return new_lrs + + def _noam_annealing(self, initial_lr, step): + if self.warmup_steps > 0: + mult = self._normalize * min(step**(-0.5), + step * (self.warmup_steps**(-1.5))) + else: + mult = self._normalize * step**(-0.5) + + out_lr = initial_lr * mult + if step > self.warmup_steps: + out_lr = max(out_lr, self.min_lr) + return out_lr + + +class NoamHoldAnnealing(WarmupHoldPolicy): + + def __init__(self, + optimizer, + *, + max_steps, + decay_rate=0.5, + min_lr=0.0, + last_epoch=-1, + **kwargs): + """ + From Nemo: + Implementation of the Noam Hold Annealing policy + from the SqueezeFormer paper. + + Unlike NoamAnnealing, the peak learning rate + can be explicitly set for this scheduler. + The schedule first performs linear warmup, + then holds the peak LR, then decays with some schedule for + the remainder of the steps. + Therefore the min-lr is still dependent + on the hyper parameters selected. + + It's schedule is determined by three factors- + + Warmup Steps: Initial stage, where linear warmup + occurs uptil the peak LR is reached. Unlike NoamAnnealing, + the peak LR is explicitly stated here instead of a scaling factor. + + Hold Steps: Intermediate stage, where the peak LR + is maintained for some number of steps. In this region, + the high peak LR allows the model to converge faster + if training is stable. However the high LR + may also cause instability during training. + Should usually be a significant fraction of training + steps (around 30-40% of the entire training steps). + + Decay Steps: Final stage, where the LR rapidly decays + with some scaling rate (set by decay rate). + To attain Noam decay, use 0.5, + for Squeezeformer recommended decay, use 1.0. + The fast decay after prolonged high LR during + hold phase allows for rapid convergence. + + References: + - [Squeezeformer: + An Efficient Transformer for Automatic Speech Recognition] + (https://arxiv.org/abs/2206.00888) + + Args: + optimizer: Pytorch compatible Optimizer object. + warmup_steps: Number of training steps in warmup stage + warmup_ratio: Ratio of warmup steps to total steps + hold_steps: Number of training steps to + hold the learning rate after warm up + hold_ratio: Ratio of hold steps to total steps + max_steps: Total number of steps while training or `None` for + infinite training + decay_rate: Float value describing the polynomial decay + after the hold period. Default value + of 0.5 corresponds to Noam decay. + min_lr: Minimum learning rate. + """ + self.decay_rate = decay_rate + super().__init__(optimizer=optimizer, + max_steps=max_steps, + last_epoch=last_epoch, + min_lr=min_lr, + **kwargs) + + def _get_lr(self, step): + if self.warmup_steps is None or self.warmup_steps == 0: + raise ValueError( + "Noam scheduler cannot be used without warmup steps") + + if self.hold_steps > 0: + hold_steps = self.hold_steps - self.warmup_steps + else: + hold_steps = 0 + + new_lrs = [ + _noam_hold_annealing( + initial_lr, + step=step, + warmup_steps=self.warmup_steps, + hold_steps=hold_steps, + decay_rate=self.decay_rate, + min_lr=self.min_lr, + ) for initial_lr in self.base_lrs + ] + return new_lrs + + def set_step(self, step: int): + self.last_epoch = step + + +class ConstantLR(_LRScheduler): + """The ConstantLR scheduler + + This scheduler keeps a constant lr + + """ + + def __init__( + self, + optimizer: torch.optim.Optimizer, + ): + # __init__() must be invoked before setting field + # because step() is also invoked in __init__() + super().__init__(optimizer) + + def get_lr(self): + return self.base_lrs + + def set_step(self, step: int): + self.last_epoch = step diff --git a/xinference/thirdparty/cosyvoice/utils/train_utils.py b/xinference/thirdparty/cosyvoice/utils/train_utils.py new file mode 100644 index 0000000000..f8d7b4586c --- /dev/null +++ b/xinference/thirdparty/cosyvoice/utils/train_utils.py @@ -0,0 +1,289 @@ +# Copyright (c) 2021 Mobvoi Inc. (authors: Binbin Zhang) +# 2023 Horizon Inc. (authors: Xingchen Song) +# 2024 Alibaba Inc (authors: Xiang Lyu) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from contextlib import nullcontext +import logging +import os +import torch +import json +import re +import datetime +import yaml + +import deepspeed +import torch.optim as optim +import torch.distributed as dist + +from torch.utils.tensorboard import SummaryWriter +from torch.utils.data import DataLoader +from torch.nn.utils import clip_grad_norm_ + +from deepspeed.runtime.zero.stage_1_and_2 import estimate_zero2_model_states_mem_needs_all_live + +from cosyvoice.dataset.dataset import Dataset +from cosyvoice.utils.scheduler import WarmupLR, NoamHoldAnnealing, ConstantLR + + +def init_distributed(args): + world_size = int(os.environ.get('WORLD_SIZE', 1)) + local_rank = int(os.environ.get('LOCAL_RANK', 0)) + rank = int(os.environ.get('RANK', 0)) + logging.info('training on multiple gpus, this gpu {}'.format(local_rank) + + ', rank {}, world_size {}'.format(rank, world_size)) + if args.train_engine == 'torch_ddp': + torch.cuda.set_device(local_rank) + dist.init_process_group(args.dist_backend) + else: + deepspeed.init_distributed(dist_backend=args.dist_backend) + return world_size, local_rank, rank + + +def init_dataset_and_dataloader(args, configs): + train_dataset = Dataset(args.train_data, data_pipeline=configs['data_pipeline'], mode='train', shuffle=True, partition=True) + cv_dataset = Dataset(args.cv_data, data_pipeline=configs['data_pipeline'], mode='train', shuffle=False, partition=False) + + # do not use persistent_workers=True, as whisper tokenizer opens tiktoken file each time when the for loop starts + train_data_loader = DataLoader(train_dataset, + batch_size=None, + pin_memory=args.pin_memory, + num_workers=args.num_workers, + prefetch_factor=args.prefetch) + cv_data_loader = DataLoader(cv_dataset, + batch_size=None, + pin_memory=args.pin_memory, + num_workers=args.num_workers, + prefetch_factor=args.prefetch) + return train_dataset, cv_dataset, train_data_loader, cv_data_loader + + + +def check_modify_and_save_config(args, configs): + if args.train_engine == "torch_ddp": + configs['train_conf']["dtype"] = 'fp32' + else: + with open(args.deepspeed_config, 'r') as fin: + ds_configs = json.load(fin) + if "fp16" in ds_configs and ds_configs["fp16"]["enabled"]: + configs['train_conf']["dtype"] = "fp16" + elif "bf16" in ds_configs and ds_configs["bf16"]["enabled"]: + configs['train_conf']["dtype"] = "bf16" + else: + configs['train_conf']["dtype"] = "fp32" + assert ds_configs["train_micro_batch_size_per_gpu"] == 1 + # if use deepspeed, override ddp config + configs['train_conf']['save_per_step'] = int(configs['train_conf']['save_per_step'] * configs['train_conf']['accum_grad'] / ds_configs["gradient_accumulation_steps"]) + configs['train_conf']['accum_grad'] = ds_configs["gradient_accumulation_steps"] + configs['train_conf']['grad_clip'] = ds_configs["gradient_clipping"] + configs['train_conf']['log_interval'] = ds_configs["steps_per_print"] + return configs + + +def wrap_cuda_model(args, model): + local_world_size = int(os.environ.get('LOCAL_WORLD_SIZE', 1)) + world_size = int(os.environ.get('WORLD_SIZE', 1)) + if args.train_engine == "torch_ddp": # native pytorch ddp + assert (torch.cuda.is_available()) + model.cuda() + model = torch.nn.parallel.DistributedDataParallel(model, find_unused_parameters=True) + else: + if int(os.environ.get('RANK', 0)) == 0: + logging.info("Estimating model states memory needs (zero2)...") + estimate_zero2_model_states_mem_needs_all_live( + model, + num_gpus_per_node=local_world_size, + num_nodes=world_size // local_world_size) + return model + + +def init_optimizer_and_scheduler(args, configs, model): + if configs['train_conf']['optim'] == 'adam': + optimizer = optim.Adam(model.parameters(), **configs['train_conf']['optim_conf']) + elif configs['train_conf']['optim'] == 'adamw': + optimizer = optim.AdamW(model.parameters(), **configs['train_conf']['optim_conf']) + else: + raise ValueError("unknown optimizer: " + configs['train_conf']) + + if configs['train_conf']['scheduler'] == 'warmuplr': + scheduler_type = WarmupLR + scheduler = WarmupLR(optimizer, **configs['train_conf']['scheduler_conf']) + elif configs['train_conf']['scheduler'] == 'NoamHoldAnnealing': + scheduler_type = NoamHoldAnnealing + scheduler = NoamHoldAnnealing(optimizer, **configs['train_conf']['scheduler_conf']) + elif configs['train_conf']['scheduler'] == 'constantlr': + scheduler_type = ConstantLR + scheduler = ConstantLR(optimizer) + else: + raise ValueError("unknown scheduler: " + configs['train_conf']) + + # use deepspeed optimizer for speedup + if args.train_engine == "deepspeed": + def scheduler(opt): + return scheduler_type(opt, **configs['train_conf']['scheduler_conf']) + model, optimizer, _, scheduler = deepspeed.initialize( + args=args, + model=model, + optimizer=None, + lr_scheduler=scheduler, + model_parameters=model.parameters()) + + return model, optimizer, scheduler + + +def init_summarywriter(args): + writer = None + if int(os.environ.get('RANK', 0)) == 0: + os.makedirs(args.model_dir, exist_ok=True) + writer = SummaryWriter(args.tensorboard_dir) + return writer + + +def save_model(model, model_name, info_dict): + rank = int(os.environ.get('RANK', 0)) + model_dir = info_dict["model_dir"] + save_model_path = os.path.join(model_dir, '{}.pt'.format(model_name)) + + if info_dict["train_engine"] == "torch_ddp": + if rank == 0: + torch.save(model.module.state_dict(), save_model_path) + else: + with torch.no_grad(): + model.save_checkpoint(save_dir=model_dir, + tag=model_name, + client_state=info_dict) + if rank == 0: + info_path = re.sub('.pt$', '.yaml', save_model_path) + info_dict['save_time'] = datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S') + with open(info_path, 'w') as fout: + data = yaml.dump(info_dict) + fout.write(data) + logging.info('[Rank {}] Checkpoint: save to checkpoint {}'.format(rank, save_model_path)) + + +def cosyvoice_join(group_join, info_dict): + world_size = int(os.environ.get('WORLD_SIZE', 1)) + local_rank = int(os.environ.get('LOCAL_RANK', 0)) + rank = int(os.environ.get('RANK', 0)) + + if info_dict["batch_idx"] != 0: + # we try to join all rank in both ddp and deepspeed mode, in case different rank has different lr + try: + dist.monitored_barrier(group=group_join, + timeout=group_join.options._timeout) + return False + except RuntimeError as e: + logging.info("Detected uneven workload distribution: {}\n".format(e) + + "Break current worker to manually join all workers, " + + "world_size {}, current rank {}, current local_rank {}\n". + format(world_size, rank, local_rank)) + return True + else: + return False + + +def batch_forward(model, batch, info_dict): + device = int(os.environ.get('LOCAL_RANK', 0)) + + dtype = info_dict["dtype"] + if dtype == "fp16": + dtype = torch.float16 + elif dtype == "bf16": + dtype = torch.bfloat16 + else: # fp32 + dtype = torch.float32 + + if info_dict['train_engine'] == 'torch_ddp': + autocast = nullcontext() + else: + autocast = torch.cuda.amp.autocast(enabled=True, dtype=dtype, cache_enabled=False) + + with autocast: + info_dict['loss_dict'] = model(batch, device) + return info_dict + + +def batch_backward(model, info_dict): + if info_dict["train_engine"] == "deepspeed": + scaled_loss = model.backward(info_dict['loss_dict']['loss']) + else: + scaled_loss = info_dict['loss_dict']['loss'] / info_dict['accum_grad'] + scaled_loss.backward() + + info_dict['loss_dict']['loss'] = scaled_loss + return info_dict + + +def update_parameter_and_lr(model, optimizer, scheduler, info_dict): + grad_norm = 0.0 + if info_dict['train_engine'] == "deepspeed": + info_dict["is_gradient_accumulation_boundary"] = model.is_gradient_accumulation_boundary() + model.step() + grad_norm = model.get_global_grad_norm() + elif (info_dict['batch_idx'] + 1) % info_dict["accum_grad"] == 0: + grad_norm = clip_grad_norm_(model.parameters(), info_dict['grad_clip']) + if torch.isfinite(grad_norm): + optimizer.step() + optimizer.zero_grad() + scheduler.step() + info_dict["lr"] = optimizer.param_groups[0]['lr'] + info_dict["grad_norm"] = grad_norm + return info_dict + + +def log_per_step(writer, info_dict): + tag = info_dict["tag"] + epoch = info_dict.get('epoch', 0) + step = info_dict["step"] + batch_idx = info_dict["batch_idx"] + loss_dict = info_dict['loss_dict'] + rank = int(os.environ.get('RANK', 0)) + + # only rank 0 write to tensorboard to avoid multi-process write + if writer is not None: + if (info_dict['train_engine'] == 'deepspeed' and info_dict['is_gradient_accumulation_boundary'] is True) or \ + (info_dict['train_engine'] == 'torch_ddp' and (info_dict['batch_idx'] + 1) % info_dict['accum_grad'] == 0): + for k in ['epoch', 'lr', 'grad_norm']: + writer.add_scalar('{}/{}'.format(tag, k), info_dict[k], step + 1) + for k, v in loss_dict.items(): + writer.add_scalar('{}/{}'.format(tag, k), v, step + 1) + + # TRAIN & CV, Shell log (stdout) + if (info_dict['batch_idx'] + 1) % info_dict['log_interval'] == 0: + log_str = '{} Batch {}/{} '.format(tag, epoch, batch_idx + 1) + for name, value in loss_dict.items(): + log_str += '{} {:.6f} '.format(name, value) + if tag == "TRAIN": + log_str += 'lr {:.8f} grad_norm {:.6f}'.format( + info_dict["lr"], info_dict['grad_norm']) + log_str += ' rank {}'.format(rank) + logging.debug(log_str) + + +def log_per_save(writer, info_dict): + tag = info_dict["tag"] + epoch = info_dict["epoch"] + step = info_dict["step"] + loss_dict = info_dict["loss_dict"] + lr = info_dict['lr'] + rank = int(os.environ.get('RANK', 0)) + logging.info( + 'Epoch {} Step {} CV info lr {} {} rank {}'.format( + epoch, step + 1, lr, rank, ' '.join(['{}_{}'.format(k, v) for k, v in loss_dict.items()]))) + + if writer is not None: + for k in ['epoch', 'lr']: + writer.add_scalar('{}/{}'.format(tag, k), info_dict[k], step + 1) + for k, v in loss_dict.items(): + writer.add_scalar('{}/{}'.format(tag, k), v, step + 1) diff --git a/xinference/thirdparty/deepseek_vl/models/processing_vlm.py b/xinference/thirdparty/deepseek_vl/models/processing_vlm.py index 380a944828..22d074c700 100644 --- a/xinference/thirdparty/deepseek_vl/models/processing_vlm.py +++ b/xinference/thirdparty/deepseek_vl/models/processing_vlm.py @@ -25,8 +25,8 @@ from transformers import LlamaTokenizerFast from transformers.processing_utils import ProcessorMixin -from .image_processing_vlm import VLMImageProcessor from ..utils.conversation import get_conv_template +from .image_processing_vlm import VLMImageProcessor class DictOutput(object): diff --git a/xinference/thirdparty/deepseek_vl/models/siglip_vit.py b/xinference/thirdparty/deepseek_vl/models/siglip_vit.py index 663783f9a8..5caca73558 100644 --- a/xinference/thirdparty/deepseek_vl/models/siglip_vit.py +++ b/xinference/thirdparty/deepseek_vl/models/siglip_vit.py @@ -92,7 +92,7 @@ def norm_cdf(x): def trunc_normal_(tensor, mean=0.0, std=1.0, a=-2.0, b=2.0): # type: (torch.Tensor, float, float, float, float) -> torch.Tensor r"""The original timm.models.layers.weight_init.trunc_normal_ can not handle bfloat16 yet, here we first - convert the tensor to float32, apply the trunc_normal_() in float32, and then convert it back to its orignal dtype. + convert the tensor to float32, apply the trunc_normal_() in float32, and then convert it back to its original dtype. Fills the input Tensor with values drawn from a truncated normal distribution. The values are effectively drawn from the normal distribution :math:`\mathcal{N}(\text{mean}, \text{std}^2)` with values outside :math:`[a, b]` redrawn until they are within @@ -305,7 +305,7 @@ def __init__( img_size: Input image size. patch_size: Patch size. in_chans: Number of image input channels. - num_classes: Mumber of classes for classification head. + num_classes: Number of classes for classification head. global_pool: Type of global pooling for final sequence (default: 'token'). embed_dim: Transformer embedding dimension. depth: Depth of transformer. diff --git a/xinference/thirdparty/deepseek_vl/serve/__init__.py b/xinference/thirdparty/deepseek_vl/serve/__init__.py new file mode 100644 index 0000000000..37f6558d95 --- /dev/null +++ b/xinference/thirdparty/deepseek_vl/serve/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/xinference/thirdparty/deepseek_vl/serve/app_deepseek.py b/xinference/thirdparty/deepseek_vl/serve/app_deepseek.py index 424dc47af1..6face003a2 100755 --- a/xinference/thirdparty/deepseek_vl/serve/app_deepseek.py +++ b/xinference/thirdparty/deepseek_vl/serve/app_deepseek.py @@ -36,12 +36,8 @@ from app_modules.presets import CONCURRENT_COUNT, description, description_top, title from app_modules.utils import configure_logger, is_variable_assigned, strip_stop_words -from .inference import ( - convert_conversation_to_prompts, - deepseek_generate, - load_model, -) from ..utils.conversation import SeparatorStyle +from .inference import convert_conversation_to_prompts, deepseek_generate, load_model def load_models(): diff --git a/xinference/thirdparty/deepseek_vl/serve/app_modules/__init__.py b/xinference/thirdparty/deepseek_vl/serve/app_modules/__init__.py new file mode 100644 index 0000000000..37f6558d95 --- /dev/null +++ b/xinference/thirdparty/deepseek_vl/serve/app_modules/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022-2023 XProbe Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/xinference/thirdparty/deepseek_vl/serve/app_modules/utils.py b/xinference/thirdparty/deepseek_vl/serve/app_modules/utils.py index bb66e44161..35707fe81f 100755 --- a/xinference/thirdparty/deepseek_vl/serve/app_modules/utils.py +++ b/xinference/thirdparty/deepseek_vl/serve/app_modules/utils.py @@ -27,12 +27,13 @@ import time import mdtex2html -from .presets import ALREADY_CONVERTED_MARK from markdown import markdown from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import ClassNotFound, get_lexer_by_name, guess_lexer +from .presets import ALREADY_CONVERTED_MARK + logger = logging.getLogger("gradio_logger") diff --git a/xinference/thirdparty/deepseek_vl/serve/assets/custom.css b/xinference/thirdparty/deepseek_vl/serve/assets/custom.css index adb6344430..7402e0578a 100755 --- a/xinference/thirdparty/deepseek_vl/serve/assets/custom.css +++ b/xinference/thirdparty/deepseek_vl/serve/assets/custom.css @@ -141,7 +141,7 @@ thead th { color: #fdf8f8; box-shadow: 6px 6px 16px hsla(0, 0%, 0%, 0.2); } -/* Hightlight */ +/* Highlight */ #deepseek_chatbot .highlight { background-color: transparent; } diff --git a/xinference/thirdparty/fish_speech/__init__.py b/xinference/thirdparty/fish_speech/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/callbacks/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/callbacks/__init__.py new file mode 100644 index 0000000000..bbcf3f3365 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/callbacks/__init__.py @@ -0,0 +1,3 @@ +from .grad_norm import GradNormMonitor + +__all__ = ["GradNormMonitor"] diff --git a/xinference/thirdparty/fish_speech/fish_speech/callbacks/grad_norm.py b/xinference/thirdparty/fish_speech/fish_speech/callbacks/grad_norm.py new file mode 100644 index 0000000000..dbc95ef2a3 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/callbacks/grad_norm.py @@ -0,0 +1,113 @@ +from typing import Optional, Union + +import lightning.pytorch as pl +import torch +from lightning import LightningModule, Trainer +from lightning.pytorch.callbacks import Callback +from torch import Tensor, nn +from torch.utils._foreach_utils import ( + _group_tensors_by_device_and_dtype, + _has_foreach_support, +) + + +@torch.no_grad() +def grad_norm( + parameters: Union[Tensor, list[Tensor]], + norm_type: float = 2.0, +) -> float: + """ + Returns the norm of the gradients of the given parameters. + + Args: + parameters (Iterable[Tensor] or Tensor): an iterable of Tensors or a + single Tensor that will have gradients normalized + norm_type (float): type of the used p-norm. + + Returns: + Total norm of the parameter gradients (viewed as a single vector). + """ # noqa: E501 + + if isinstance(parameters, Tensor): + parameters = [parameters] + + grads = [p.grad for p in parameters if p.grad is not None] + if len(grads) == 0: + return None + + first_device = grads[0].device + grouped_grads: dict[ + tuple[torch.device, torch.dtype], list[list[Tensor]] + ] = _group_tensors_by_device_and_dtype( + [[g.detach() for g in grads]] + ) # type: ignore[assignment] + + norms = [] + for (device, _), ([grads], _) in grouped_grads.items(): + if _has_foreach_support(grads, device=device): + norms.extend(torch._foreach_norm(grads, norm_type)) + else: + norms.extend([torch.norm(g, norm_type) for g in grads]) + + return torch.norm(torch.stack([norm.to(first_device) for norm in norms]), norm_type) + + +class GradNormMonitor(Callback): + """ + Callback that computes the gradient norm of the model parameters. + """ + + def __init__( + self, + norm_type: float = 2.0, + logging_interval: str = "step", + sub_module: Optional[Union[str, list[str]]] = None, + ) -> None: + """ + Args: + norm_type (float): type of the used p-norm. + logging_interval (str): "step" or "epoch". + """ + super().__init__() + + self.norm_type = norm_type + self.logging_interval = logging_interval + self.sub_module = sub_module + + def on_after_backward(self, trainer: Trainer, model: LightningModule) -> None: + """ + Computes the gradient norm of the model parameters and logs it to the logger. + + Args: + trainer (Trainer): The trainer object + model (LightningModule): The current lightningModule + """ + + lightning_model = model + + if self.sub_module is None: + return self.log_sub_module_grad_norm(lightning_model, model, "") + + sub_modules = self.sub_module + if isinstance(sub_modules, str): + sub_modules = [sub_modules] + + for sub_module in sub_modules: + self.log_sub_module_grad_norm( + lightning_model, getattr(model, sub_module), f"/{sub_module}" + ) + + def log_sub_module_grad_norm( + self, lightning_model: LightningModule, model: nn.Module, path: str + ) -> None: + grad_norm_val = grad_norm(model.parameters(), self.norm_type) + if grad_norm_val is None: + return + + on_step = self.logging_interval == "step" + lightning_model.log( + f"train{path}/grad_norm", + grad_norm_val, + on_step=on_step, + on_epoch=not on_step, + ) diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/configs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/base.yaml b/xinference/thirdparty/fish_speech/fish_speech/configs/base.yaml new file mode 100644 index 0000000000..99e6dab54d --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/configs/base.yaml @@ -0,0 +1,87 @@ +# Base configuration for training a model +paths: + run_dir: results/${project} + ckpt_dir: ${paths.run_dir}/checkpoints + +hydra: + run: + dir: ${paths.run_dir} + +# Lightning Trainer +trainer: + _target_: lightning.pytorch.trainer.Trainer + + default_root_dir: ${paths.run_dir} + accelerator: gpu + num_nodes: 1 + devices: auto + strategy: + _target_: lightning.pytorch.strategies.DDPStrategy + process_group_backend: nccl # This should be override when training on windows + + precision: bf16-mixed + + # disable validation by epoch end + check_val_every_n_epoch: null + val_check_interval: 5000 + max_steps: 100_000 + + # Use torch.backends.cudnn.benchmark to speed up training + benchmark: true + +# Callbacks +callbacks: + model_checkpoint: + _target_: lightning.pytorch.callbacks.ModelCheckpoint + dirpath: ${paths.ckpt_dir} + filename: "step_{step:09d}" + save_last: false # additionally always save an exact copy of the last checkpoint to a file last.ckpt + save_top_k: 5 # save 5 latest checkpoints + monitor: step # use step to monitor checkpoints + mode: max # save the latest checkpoint with the highest global_step + every_n_epochs: null # don't save checkpoints by epoch end + every_n_train_steps: 5000 # save checkpoints every 5000 steps + auto_insert_metric_name: false + + model_summary: + _target_: lightning.pytorch.callbacks.ModelSummary + max_depth: 2 # the maximum depth of layer nesting that the summary will include + + learning_rate_monitor: + _target_: lightning.pytorch.callbacks.LearningRateMonitor + logging_interval: step + log_momentum: false + + grad_norm_monitor: + _target_: fish_speech.callbacks.GradNormMonitor + norm_type: 2 + logging_interval: step + +# Logger +logger: + tensorboard: + _target_: lightning.pytorch.loggers.tensorboard.TensorBoardLogger + save_dir: "${paths.run_dir}/tensorboard/" + name: null + log_graph: false + default_hp_metric: true + prefix: "" + + # wandb: + # _target_: lightning.pytorch.loggers.wandb.WandbLogger + # # name: "" # name of the run (normally generated by wandb) + # save_dir: "${paths.run_dir}" + # offline: False + # id: null # pass correct id to resume experiment! + # anonymous: null # enable anonymous logging + # project: "fish-speech" + # log_model: False # upload lightning ckpts + # prefix: "" # a string to put at the beginning of metric keys + # # entity: "" # set to name of your wandb team + # group: "" + # tags: ["vq", "hq", "finetune"] + # job_type: "" + +# Loop +train: true +test: false diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/firefly_gan_vq.yaml b/xinference/thirdparty/fish_speech/fish_speech/configs/firefly_gan_vq.yaml new file mode 100644 index 0000000000..7417623b03 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/configs/firefly_gan_vq.yaml @@ -0,0 +1,34 @@ +_target_: fish_speech.models.vqgan.modules.firefly.FireflyArchitecture +spec_transform: + _target_: fish_speech.utils.spectrogram.LogMelSpectrogram + sample_rate: 44100 + n_mels: 160 + n_fft: 2048 + hop_length: 512 + win_length: 2048 +backbone: + _target_: fish_speech.models.vqgan.modules.firefly.ConvNeXtEncoder + input_channels: 160 + depths: [3, 3, 9, 3] + dims: [128, 256, 384, 512] + drop_path_rate: 0.2 + kernel_size: 7 +head: + _target_: fish_speech.models.vqgan.modules.firefly.HiFiGANGenerator + hop_length: 512 + upsample_rates: [8, 8, 2, 2, 2] # aka. strides + upsample_kernel_sizes: [16, 16, 4, 4, 4] + resblock_kernel_sizes: [3, 7, 11] + resblock_dilation_sizes: [[1, 3, 5], [1, 3, 5], [1, 3, 5]] + num_mels: 512 + upsample_initial_channel: 512 + use_template: false + pre_conv_kernel_size: 13 + post_conv_kernel_size: 13 +quantizer: + _target_: fish_speech.models.vqgan.modules.fsq.DownsampleFiniteScalarQuantize + input_dim: 512 + n_groups: 4 + n_codebooks: 1 + levels: [8, 5, 5, 5] + downsample_factor: [2] diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/lora/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/configs/lora/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/lora/r_8_alpha_16.yaml b/xinference/thirdparty/fish_speech/fish_speech/configs/lora/r_8_alpha_16.yaml new file mode 100644 index 0000000000..aecc4d9766 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/configs/lora/r_8_alpha_16.yaml @@ -0,0 +1,4 @@ +_target_: fish_speech.models.text2semantic.lora.LoraConfig +r: 8 +lora_alpha: 16 +lora_dropout: 0.01 diff --git a/xinference/thirdparty/fish_speech/fish_speech/configs/text2semantic_finetune.yaml b/xinference/thirdparty/fish_speech/fish_speech/configs/text2semantic_finetune.yaml new file mode 100644 index 0000000000..1bf8fd6b6d --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/configs/text2semantic_finetune.yaml @@ -0,0 +1,83 @@ +defaults: + - base + - _self_ + +project: text2semantic_finetune_dual_ar +max_length: 4096 +pretrained_ckpt_path: checkpoints/fish-speech-1.2-sft + +# Lightning Trainer +trainer: + accumulate_grad_batches: 1 + gradient_clip_val: 1.0 + gradient_clip_algorithm: "norm" + max_steps: 1000 + precision: bf16-true + limit_val_batches: 10 + val_check_interval: 100 + +# Dataset Configuration +tokenizer: + _target_: transformers.AutoTokenizer.from_pretrained + pretrained_model_name_or_path: ${pretrained_ckpt_path} + +# Dataset Configuration +train_dataset: + _target_: fish_speech.datasets.semantic.AutoTextSemanticInstructionDataset + proto_files: + - data/protos + tokenizer: ${tokenizer} + causal: true + max_length: ${max_length} + use_speaker: false + interactive_prob: 0.7 + +val_dataset: + _target_: fish_speech.datasets.semantic.AutoTextSemanticInstructionDataset + proto_files: + - data/protos + tokenizer: ${tokenizer} + causal: true + max_length: ${max_length} + use_speaker: false + interactive_prob: 0.7 + +data: + _target_: fish_speech.datasets.semantic.SemanticDataModule + train_dataset: ${train_dataset} + val_dataset: ${val_dataset} + num_workers: 4 + batch_size: 8 + tokenizer: ${tokenizer} + max_length: ${max_length} + +# Model Configuration +model: + _target_: fish_speech.models.text2semantic.lit_module.TextToSemantic + model: + _target_: fish_speech.models.text2semantic.llama.BaseTransformer.from_pretrained + path: ${pretrained_ckpt_path} + load_weights: true + max_length: ${max_length} + lora_config: null + + optimizer: + _target_: torch.optim.AdamW + _partial_: true + lr: 1e-4 + weight_decay: 0 + betas: [0.9, 0.95] + eps: 1e-5 + + lr_scheduler: + _target_: torch.optim.lr_scheduler.LambdaLR + _partial_: true + lr_lambda: + _target_: fish_speech.scheduler.get_constant_schedule_with_warmup_lr_lambda + _partial_: true + num_warmup_steps: 10 + +# Callbacks +callbacks: + model_checkpoint: + every_n_train_steps: ${trainer.val_check_interval} diff --git a/xinference/thirdparty/fish_speech/fish_speech/conversation.py b/xinference/thirdparty/fish_speech/fish_speech/conversation.py new file mode 100644 index 0000000000..c9ca0ef918 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/conversation.py @@ -0,0 +1,2 @@ +SEMANTIC_TOKEN = "<|semantic|>" +CODEBOOK_PAD_TOKEN_ID = 0 diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/concat_repeat.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/concat_repeat.py new file mode 100644 index 0000000000..4aa596b95a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/concat_repeat.py @@ -0,0 +1,53 @@ +import bisect +import random +from typing import Iterable + +from torch.utils.data import Dataset, IterableDataset + + +class ConcatRepeatDataset(Dataset): + datasets: list[Dataset] + cumulative_sizes: list[int] + repeats: list[int] + + @staticmethod + def cumsum(sequence, repeats): + r, s = [], 0 + for dataset, repeat in zip(sequence, repeats): + l = len(dataset) * repeat + r.append(l + s) + s += l + return r + + def __init__(self, datasets: Iterable[Dataset], repeats: list[int]): + super().__init__() + + self.datasets = list(datasets) + self.repeats = repeats + + assert len(self.datasets) > 0, "datasets should not be an empty iterable" + assert len(self.datasets) == len( + repeats + ), "datasets and repeats should have the same length" + + for d in self.datasets: + assert not isinstance( + d, IterableDataset + ), "ConcatRepeatDataset does not support IterableDataset" + + self.cumulative_sizes = self.cumsum(self.datasets, self.repeats) + + def __len__(self): + return self.cumulative_sizes[-1] + + def __getitem__(self, idx): + dataset_idx = bisect.bisect_right(self.cumulative_sizes, idx) + + if dataset_idx == 0: + sample_idx = idx + else: + sample_idx = idx - self.cumulative_sizes[dataset_idx - 1] + + dataset = self.datasets[dataset_idx] + + return dataset[sample_idx % len(dataset)] diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text-data.proto b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text-data.proto new file mode 100644 index 0000000000..5eb26d94aa --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text-data.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package text_data; + +message Semantics { + repeated uint32 values = 1; +} + +message Sentence { + repeated string texts = 1; + repeated Semantics semantics = 3; +} + +message TextData { + string source = 1; + string name = 2; + repeated Sentence sentences = 4; +} + +message SampledData { + string source = 1; + string name = 2; + repeated Sentence samples = 3; +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_pb2.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_pb2.py new file mode 100644 index 0000000000..bfce0e8be5 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_pb2.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: text-data.proto +# Protobuf Python Version: 4.25.1 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x0ftext-data.proto\x12\ttext_data"\x1b\n\tSemantics\x12\x0e\n\x06values\x18\x01 \x03(\r"B\n\x08Sentence\x12\r\n\x05texts\x18\x01 \x03(\t\x12\'\n\tsemantics\x18\x03 \x03(\x0b\x32\x14.text_data.Semantics"P\n\x08TextData\x12\x0e\n\x06source\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12&\n\tsentences\x18\x04 \x03(\x0b\x32\x13.text_data.Sentence"Q\n\x0bSampledData\x12\x0e\n\x06source\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12$\n\x07samples\x18\x03 \x03(\x0b\x32\x13.text_data.Sentenceb\x06proto3' +) + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "text_data_pb2", _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals["_SEMANTICS"]._serialized_start = 30 + _globals["_SEMANTICS"]._serialized_end = 57 + _globals["_SENTENCE"]._serialized_start = 59 + _globals["_SENTENCE"]._serialized_end = 125 + _globals["_TEXTDATA"]._serialized_start = 127 + _globals["_TEXTDATA"]._serialized_end = 207 + _globals["_SAMPLEDDATA"]._serialized_start = 209 + _globals["_SAMPLEDDATA"]._serialized_end = 290 +# @@protoc_insertion_point(module_scope) diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_stream.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_stream.py new file mode 100644 index 0000000000..ec3c25bcd7 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/protos/text_data_stream.py @@ -0,0 +1,36 @@ +import struct + +from .text_data_pb2 import TextData + + +def read_pb_stream(f): + while True: + buf = f.read(4) + if len(buf) == 0: + break + size = struct.unpack("I", buf)[0] + buf = f.read(size) + text_data = TextData() + text_data.ParseFromString(buf) + yield text_data + + +def write_pb_stream(f, text_data): + buf = text_data.SerializeToString() + f.write(struct.pack("I", len(buf))) + f.write(buf) + + +def pack_pb_stream(text_data): + buf = text_data.SerializeToString() + return struct.pack("I", len(buf)) + buf + + +def split_pb_stream(f): + while True: + head = f.read(4) + if len(head) == 0: + break + size = struct.unpack("I", head)[0] + buf = f.read(size) + yield head + buf diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/semantic.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/semantic.py new file mode 100644 index 0000000000..3c64e01077 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/semantic.py @@ -0,0 +1,496 @@ +import random +from dataclasses import dataclass +from itertools import chain +from pathlib import Path +from random import Random +from typing import Optional, Union + +import numpy as np +import pyarrow.parquet as pq +import torch +import torch.nn.functional as F +from datasets.download.streaming_download_manager import xopen +from huggingface_hub import HfApi +from lightning import LightningDataModule +from torch.distributed import get_rank, get_world_size, is_initialized +from torch.utils.data import DataLoader, IterableDataset, get_worker_info +from transformers import AutoTokenizer + +from fish_speech.conversation import CODEBOOK_PAD_TOKEN_ID +from fish_speech.datasets.protos.text_data_pb2 import SampledData +from fish_speech.datasets.protos.text_data_stream import read_pb_stream +from fish_speech.text.clean import clean_text +from fish_speech.utils import RankedLogger +from fish_speech.utils.braceexpand import braceexpand + +log = RankedLogger(__name__, rank_zero_only=True) + + +def split_by_rank_worker(files): + # We need to know the total number of devices + # to split the data properly + + total_devices = 1 + if is_initialized(): + total_devices = get_world_size() + + worker_info = get_worker_info() + if worker_info is not None: + total_devices *= worker_info.num_workers + + if len(files) < total_devices: + # Repeat the files N times to match the number of devices + files = files * (total_devices // len(files) + 1) + + # DDP + if is_initialized(): + files = files[get_rank() :: get_world_size()] + + # Split by worker + if worker_info is not None: + files = files[worker_info.id :: worker_info.num_workers] + + return files + + +class AutoTextSemanticInstructionDataset(IterableDataset): + """ + Auto Augment Dataset by Speaker + + 1. Random concatenate multiple sentences from the same speaker to form a longer sentence + 2. Automatically normalize the text + + For interactive mode, we use the following format (multiple sequences): + [INST] [SPK: speaker] text [/INST] ... [INST] text [/INST] + + For non-interactive mode, we use the following format (one long sequence): + [INST] text [/INST] ... + """ + + def __init__( + self, + proto_files: list[str], + seed: int = 42, + interactive_prob: float = 0.5, + max_length: int = 1024, + tokenizer: AutoTokenizer = None, + use_speaker: bool | float = True, + causal: bool = True, + num_codebooks: Optional[int] = None, + skip_text_prob: float = 0.0, + ): + """ + Args: + proto_files: proto buf files if using local data + seed: random seed + interactive_prob: probability to use interactive mode + max_length: max length of the text + tokenizer: tokenizer + use_speaker: include speaker information in the prompt + causal: use causal sampling when using local data, disable will lead to random sampling + num_codebooks: number of codebooks, if None, it will be automatically detected + skip_text_prob: probability to skip the text (audio only), this only applies to interactive mode + """ + + super().__init__() + + assert 0 <= interactive_prob <= 1, "interactive_prob must be in [0, 1]" + + self.seed = seed + self.max_length = max_length + self.tokenizer = tokenizer + self.interactive_prob = interactive_prob + self.use_speaker = use_speaker + self.proto_files = proto_files + self.causal = causal + self.num_codebooks = num_codebooks + self.skip_text_prob = skip_text_prob + + self.semantic_token_id = self.tokenizer.convert_tokens_to_ids("<|semantic|>") + self.groups = None + + def init_mock_data_server(self): + if self.groups is not None: + return + + # Expand the proto files + expanded_proto_files = [] + for filename in self.proto_files: + for i in braceexpand(filename): + i = Path(i) + if i.is_file(): + expanded_proto_files.append(i) + elif i.is_dir(): + expanded_proto_files.extend(i.rglob("*.proto")) + expanded_proto_files.extend(i.rglob("*.protos")) + else: + raise ValueError(f"{i} is not a file or directory") + + expanded_proto_files = sorted(expanded_proto_files) + Random(self.seed).shuffle(expanded_proto_files) + + self.groups = [] + shard_proto_files = split_by_rank_worker(expanded_proto_files) + log.info( + f"Reading {len(shard_proto_files)} / {len(expanded_proto_files)} files" + ) + + count = 0 + for filename in shard_proto_files: + with open(filename, "rb") as f: + for text_data in read_pb_stream(f): + self.groups.append(text_data) + count += 1 + + log.info(f"Read total {count} groups of data") + + # Shuffle the lines + Random(self.seed).shuffle(self.groups) + self.group_weights = [len(i.sentences) for i in self.groups] + + def __iter__(self): + while True: + yield self.augment() + + def tokenize_sentence(self, sentence: str): + sentence = clean_text(sentence) + tokens = self.tokenizer.encode( + f"{sentence}", + max_length=10**6, + add_special_tokens=False, + truncation=False, + ) + return sentence, len(tokens) + + def sample_data(self): + if self.groups is None: + self.init_mock_data_server() + + # Shuffle unique lines, estimate that each sample is at least 20 tokens + num_samples = self.max_length // 20 + + # choice group based on their number of samples + group = random.choices(self.groups, weights=self.group_weights, k=1)[0] + + if self.causal: + # Sample in order + if num_samples >= len(group.sentences): + samples = group.sentences + else: + begin = random.randint(0, len(group.sentences) - num_samples) + samples = group.sentences[begin : begin + num_samples] + else: + samples = random.choices( + group.sentences, k=min(num_samples, len(group.sentences)) + ) + + return SampledData( + source=group.source, + name=group.name, + samples=samples, + ) + + def augment(self): + final_text, final_semantic = [], [] + response = self.sample_data() + if len(response.samples) == 0: + # Invalid group + return None + + samples = list(response.samples) + idx = 0 + use_interactive = random.random() < self.interactive_prob + + if use_interactive is False: + # Random sample based on speaker using a truncated normal distribution + a = torch.tensor([0], dtype=torch.float32) + torch.nn.init.trunc_normal_( + a, + mean=self.max_length // 2, + std=self.max_length // 4, + a=10, + b=self.max_length, + ) + remaining_tokens = a.long().item() - 4 + else: + remaining_tokens = self.max_length + + # Use speaker + if isinstance(self.use_speaker, float): + use_speaker = random.random() < self.use_speaker + else: + use_speaker = self.use_speaker + + all_tokens, all_labels = [], [] + while remaining_tokens > 0 and len(samples) > 0: + sentence = samples.pop(0) + + text = random.choice(sentence.texts) + text, length = self.tokenize_sentence(text) + remaining_tokens -= length + len(sentence.semantics[0].values) + + if use_interactive is False: + final_text.append(text) + final_semantic.append(sentence.semantics) + else: + # For interactive mode, we only apply speaker for the first sentence + # [INST] [SPK: speaker] text [/INST] ... [INST] text [/INST] + tokens, labels = self.pack_sentences( + sentences=[text], + semantics=[sentence.semantics], + speaker=response.name if use_speaker else None, + skip_text=random.random() < self.skip_text_prob, + ) + + all_tokens.append(tokens) + all_labels.append(labels) + + idx += 1 + + if use_interactive is False: + tokens, labels = self.pack_sentences( + final_text, + semantics=final_semantic, + speaker=response.name if use_speaker else None, + ) + all_tokens.append(tokens) + all_labels.append(labels) + + tokens = torch.cat(all_tokens, dim=1) + labels = torch.cat(all_labels, dim=1) + + # Verify that the length is correct + assert tokens.size(1) == labels.size(1), f"{tokens.size(1)} != {labels.size(1)}" + + data = {"tokens": tokens, "labels": labels} + + return data + + def pack_sentences( + self, + sentences: list[str], + semantics: list, + speaker: Optional[str] = None, + skip_text: bool = False, + ): + if speaker is None: + speaker = "assistant" + + cated_sentences = " ".join(sentences) + if skip_text: + cated_sentences = "<|skip_text|>" + + final_text = "<|im_start|>user\n" + cated_sentences + "<|im_end|>" + final_text = final_text + f"<|im_start|>{speaker}\n" + + encoded = self.tokenizer.encode( + final_text, + add_special_tokens=False, + truncation=False, + max_length=10**6, + ) + semantic_length = sum([len(i[0].values) for i in semantics]) + prompt_length = len(encoded) + num_codebooks = ( + len(semantics[0]) if self.num_codebooks is None else self.num_codebooks + ) + + # Pack the tokens and semantics (add and to semantic tokens) + tokens = ( + encoded + + [self.semantic_token_id] * semantic_length + + self.tokenizer.convert_tokens_to_ids(["<|im_end|>"]) + ) + + # Codebook bos/padding: 0, eos: 1 + codes = [[CODEBOOK_PAD_TOKEN_ID] * prompt_length for _ in range(num_codebooks)] + for segment in semantics: + for book_idx, book in zip(range(num_codebooks), segment): + for j in book.values: + codes[book_idx].append(int(j) + 1) + + for book in codes: + book.extend([CODEBOOK_PAD_TOKEN_ID] * 1) + + tokens = [tokens] + codes + + tokens = torch.tensor(tokens, dtype=torch.long) + labels = tokens.clone() + + if skip_text: + # If text is not provided, the sentence is used for condition only, all labels are -100 + torch.fill_(labels, -100) + return tokens, labels + + # Mask out the tokens for semantic, predict semantic tokens only + # Since we don't mask out the input tokens, the language modeling still works + labels[1:, :prompt_length] = -100 + + tokens = tokens[:, :-1] + labels = labels[:, 1:] + + # Verify the padding is correct, and the last token is eos + assert (tokens[1:, :prompt_length] == CODEBOOK_PAD_TOKEN_ID).all() + assert (labels[1:, -1:] == CODEBOOK_PAD_TOKEN_ID).all() + + return tokens, labels + + +@dataclass +class TextDataCollator: + tokenizer: AutoTokenizer + max_length: int = 1024 + + def __call__(self, examples): + if "negative_tokens" in examples: + positive_examples = [] + negative_examples = [] + + for i in examples: + positive_examples.append( + { + "tokens": i["tokens"], + "labels": i["labels"], + } + ) + negative_examples.append( + { + "tokens": i["negative_tokens"], + "labels": i["negative_labels"], + } + ) + + examples = positive_examples + negative_examples + + return self.batchify(examples) + + def batchify(self, examples, tokens_key="tokens", labels_key="labels"): + tokens, attention_masks, labels = [], [], [] + + # Calculate the max length + max_tokens_length = 0 + for example in examples: + max_tokens_length = max(max_tokens_length, example[tokens_key].size(1)) + max_tokens_length = min(max_tokens_length, self.max_length) + + for example in examples: + _tokens = example[tokens_key][:, :max_tokens_length] + _labels = example[labels_key][:, :max_tokens_length] + _attention_mask = torch.ones((max_tokens_length,), dtype=torch.bool) + tokens_length = _tokens.size(1) + _attention_mask[:tokens_length] = False + + assert tokens_length == _labels.size( + 1 + ), f"{tokens_length} != {_labels.size(1)}" + + if tokens_length < max_tokens_length: + _tokens = F.pad( + _tokens, + (0, max_tokens_length - tokens_length), + value=self.tokenizer.eos_token_id, + ) + _tokens[1:, tokens_length:] = CODEBOOK_PAD_TOKEN_ID + _labels = F.pad( + _labels, (0, max_tokens_length - _labels.size(1)), value=-100 + ) + + tokens.append(_tokens) + attention_masks.append(_attention_mask) + labels.append(_labels) + + tokens = torch.stack(tokens, dim=0) + attention_masks = torch.stack(attention_masks, dim=0) + labels = torch.stack(labels, dim=0) + + return { + "inputs": tokens, + "attention_masks": attention_masks, + "labels": labels, + } + + +class InterleaveDataset(IterableDataset): + def __init__( + self, + datasets: list[IterableDataset], + probabilities: list[float], + seed: int = 42, + ): + super().__init__() + + self.datasets = datasets + self.probabilities = probabilities + self.seed = seed + + def __iter__(self): + rng = np.random.default_rng(self.seed) + dataset_iterators = [iter(dataset) for dataset in self.datasets] + + while True: + # Random choice one + dataset_idx = rng.choice(len(self.datasets), p=self.probabilities) + dataset_iterator = dataset_iterators[dataset_idx] + + try: + yield next(dataset_iterator) + except StopIteration: + # Exhausted, create a new iterator + dataset_iterators[dataset_idx] = iter(self.datasets[dataset_idx]) + yield next(dataset_iterators[dataset_idx]) + + +class SemanticDataModule(LightningDataModule): + def __init__( + self, + train_dataset: Union[AutoTextSemanticInstructionDataset, InterleaveDataset], + val_dataset: Union[AutoTextSemanticInstructionDataset, InterleaveDataset], + batch_size: int = 32, + tokenizer: AutoTokenizer = None, + max_length: int = 1024, + num_workers: int = 4, + ): + super().__init__() + + self.train_dataset = train_dataset + self.val_dataset = val_dataset + self.batch_size = batch_size + self.tokenizer = tokenizer + self.max_length = max_length + self.num_workers = num_workers + + def train_dataloader(self): + return DataLoader( + self.train_dataset, + batch_size=self.batch_size, + collate_fn=TextDataCollator(self.tokenizer, self.max_length), + num_workers=self.num_workers, + persistent_workers=True, + ) + + def val_dataloader(self): + return DataLoader( + self.val_dataset, + batch_size=self.batch_size, + collate_fn=TextDataCollator(self.tokenizer, self.max_length), + num_workers=self.num_workers, + persistent_workers=True, + ) + + +if __name__ == "__main__": + from tqdm import tqdm + + ds = AutoTextSemanticInstructionDataset( + ["data/protos"], + tokenizer=AutoTokenizer.from_pretrained("fishaudio/fish-speech-1"), + use_speaker=False, + interactive_prob=1.0, + skip_text_prob=0.5, + ) + + for i in ds: + print(ds.tokenizer.decode(i["tokens"][0], skip_special_tokens=False)) + # i["labels"][0][i["labels"][0] == -100] = 0 + # print(ds.tokenizer.decode(i["labels"][0], skip_special_tokens=False)) + break diff --git a/xinference/thirdparty/fish_speech/fish_speech/datasets/vqgan.py b/xinference/thirdparty/fish_speech/fish_speech/datasets/vqgan.py new file mode 100644 index 0000000000..a45583d22e --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/datasets/vqgan.py @@ -0,0 +1,147 @@ +from dataclasses import dataclass +from pathlib import Path +from typing import Optional + +import librosa +import numpy as np +import torch +from lightning import LightningDataModule +from torch.utils.data import DataLoader, Dataset + +from fish_speech.utils import RankedLogger + +logger = RankedLogger(__name__, rank_zero_only=False) + + +class VQGANDataset(Dataset): + def __init__( + self, + filelist: str, + sample_rate: int = 32000, + hop_length: int = 640, + slice_frames: Optional[int] = None, + ): + super().__init__() + + filelist = Path(filelist) + root = filelist.parent + + self.files = [ + root / line.strip() + for line in filelist.read_text(encoding="utf-8").splitlines() + if line.strip() + ] + self.sample_rate = sample_rate + self.hop_length = hop_length + self.slice_frames = slice_frames + + def __len__(self): + return len(self.files) + + def get_item(self, idx): + file = self.files[idx] + + audio, _ = librosa.load(file, sr=self.sample_rate, mono=True) + + # Slice audio and features + if ( + self.slice_frames is not None + and audio.shape[0] > self.slice_frames * self.hop_length + ): + start = np.random.randint( + 0, audio.shape[0] - self.slice_frames * self.hop_length + ) + audio = audio[start : start + self.slice_frames * self.hop_length] + + if len(audio) == 0: + return None + + max_value = np.abs(audio).max() + if max_value > 1.0: + audio = audio / max_value + + return { + "audio": torch.from_numpy(audio), + } + + def __getitem__(self, idx): + try: + return self.get_item(idx) + except Exception as e: + import traceback + + traceback.print_exc() + logger.error(f"Error loading {self.files[idx]}: {e}") + return None + + +@dataclass +class VQGANCollator: + def __call__(self, batch): + batch = [x for x in batch if x is not None] + + audio_lengths = torch.tensor([len(x["audio"]) for x in batch]) + audio_maxlen = audio_lengths.max() + + # Rounds up to nearest multiple of 2 (audio_lengths) + audios = [] + for x in batch: + audios.append( + torch.nn.functional.pad(x["audio"], (0, audio_maxlen - len(x["audio"]))) + ) + + return { + "audios": torch.stack(audios), + "audio_lengths": audio_lengths, + } + + +class VQGANDataModule(LightningDataModule): + def __init__( + self, + train_dataset: VQGANDataset, + val_dataset: VQGANDataset, + batch_size: int = 32, + num_workers: int = 4, + val_batch_size: Optional[int] = None, + ): + super().__init__() + + self.train_dataset = train_dataset + self.val_dataset = val_dataset + self.batch_size = batch_size + self.val_batch_size = val_batch_size or batch_size + self.num_workers = num_workers + + def train_dataloader(self): + return DataLoader( + self.train_dataset, + batch_size=self.batch_size, + collate_fn=VQGANCollator(), + num_workers=self.num_workers, + shuffle=True, + persistent_workers=True, + ) + + def val_dataloader(self): + return DataLoader( + self.val_dataset, + batch_size=self.val_batch_size, + collate_fn=VQGANCollator(), + num_workers=self.num_workers, + persistent_workers=True, + ) + + +if __name__ == "__main__": + dataset = VQGANDataset("data/LibriTTS_R/vq_train_filelist.txt") + dataloader = DataLoader( + dataset, batch_size=4, shuffle=False, collate_fn=VQGANCollator() + ) + + for batch in dataloader: + print(batch["audios"].shape) + print(batch["features"].shape) + print(batch["audio_lengths"]) + print(batch["feature_lengths"]) + break diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/README.md b/xinference/thirdparty/fish_speech/fish_speech/i18n/README.md new file mode 100644 index 0000000000..700902b09d --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/README.md @@ -0,0 +1,27 @@ +## i18n Folder Attribution + +The `i18n` folder within the `fish_speech` directory contains files initially sourced from the RVC project. In compliance with the MIT license under which these files were released, we acknowledge the original authors and sources below: + +### fish_speech/i18n/core.py + +**Related code from RVC:** +[https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/83d6a64e675d9bbd6e92ee450c5f807ed2bb54d8/i18n/i18n.py](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/83d6a64e675d9bbd6e92ee450c5f807ed2bb54d8/i18n/i18n.py) + +**Initial commit:** +add localization(添加本地化) [RVC-Project/Retrieval-based-Voice-Conversion-WebUI#35](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/pull/35) + +**Initial author:** +[@L4Ph](https://github.com/L4Ph) + +### fish_speech/i18n/scan.py + +**Related code from RVC:** +[https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/83d6a64e675d9bbd6e92ee450c5f807ed2bb54d8/i18n/scan_i18n.py](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/blob/83d6a64e675d9bbd6e92ee450c5f807ed2bb54d8/i18n/scan_i18n.py) + +**Initial commit:** +File for detecting i18n missing keys [RVC-Project/Retrieval-based-Voice-Conversion-WebUI#1058](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/pull/1058) + +**Initial author:** +[@towzeur](https://github.com/towzeur) + +We appreciate the contributions of the RVC project and its authors. diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/i18n/__init__.py new file mode 100644 index 0000000000..981dbb3b3e --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/__init__.py @@ -0,0 +1,3 @@ +from .core import i18n + +__all__ = ["i18n"] diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/core.py b/xinference/thirdparty/fish_speech/fish_speech/i18n/core.py new file mode 100644 index 0000000000..9f793ec956 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/core.py @@ -0,0 +1,40 @@ +import json +import locale +from pathlib import Path + +I18N_FILE_PATH = Path(__file__).parent / "locale" +DEFAULT_LANGUAGE = "en_US" + + +def load_language_list(language): + with open(I18N_FILE_PATH / f"{language}.json", "r", encoding="utf-8") as f: + language_list = json.load(f) + + return language_list + + +class I18nAuto: + def __init__(self): + i18n_file = Path(".locale") + + if i18n_file.exists(): + with open(i18n_file, "r", encoding="utf-8") as f: + language = f.read().strip() + else: + # getlocale can't identify the system's language ((None, None)) + language = locale.getdefaultlocale()[0] + + if (I18N_FILE_PATH / f"{language}.json").exists() is False: + language = DEFAULT_LANGUAGE + + self.language = language + self.language_map = load_language_list(language) + + def __call__(self, key): + return self.language_map.get(key, key) + + def __repr__(self): + return "Use Language: " + self.language + + +i18n = I18nAuto() diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/en_US.json b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/en_US.json new file mode 100644 index 0000000000..cf6ad6ca1e --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/en_US.json @@ -0,0 +1,122 @@ +{ + "16-mixed is recommended for 10+ series GPU": "16-mixed is recommended for 10+ series GPU", + "5 to 10 seconds of reference audio, useful for specifying speaker.": "5 to 10 seconds of reference audio, useful for specifying speaker.", + "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).": "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).", + "Accumulate Gradient Batches": "Accumulate Gradient Batches", + "Add to Processing Area": "Add to Processing Area", + "Added path successfully!": "Added path successfully!", + "Advanced Config": "Advanced Config", + "Base LLAMA Model": "Base LLAMA Model", + "Batch Inference": "Batch Inference", + "Batch Size": "Batch Size", + "Changing with the Model Path": "Changing with the Model Path", + "Chinese": "Chinese", + "Compile Model": "Compile Model", + "Compile the model can significantly reduce the inference time, but will increase cold start time": "Compile the model can significantly reduce the inference time, but will increase cold start time", + "Copy": "Copy", + "Data Preprocessing": "Data Preprocessing", + "Data Preprocessing Path": "Data Preprocessing Path", + "Data Source": "Data Source", + "Decoder Model Config": "Decoder Model Config", + "Decoder Model Path": "Decoder Model Path", + "Disabled": "Disabled", + "Enable Reference Audio": "Enable Reference Audio", + "English": "English", + "Error Message": "Error Message", + "File Preprocessing": "File Preprocessing", + "Generate": "Generate", + "Generated Audio": "Generated Audio", + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format": "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format", + "Infer interface is closed": "Infer interface is closed", + "Inference Configuration": "Inference Configuration", + "Inference Server Configuration": "Inference Server Configuration", + "Inference Server Error": "Inference Server Error", + "Inferring interface is launched at {}": "Inferring interface is launched at {}", + "Initial Learning Rate": "Initial Learning Rate", + "Input Audio & Source Path for Transcription": "Input Audio & Source Path for Transcription", + "Input Text": "Input Text", + "Invalid path: {}": "Invalid path: {}", + "It is recommended to use CUDA, if you have low configuration, use CPU": "It is recommended to use CUDA, if you have low configuration, use CPU", + "Iterative Prompt Length, 0 means off": "Iterative Prompt Length, 0 means off", + "Japanese": "Japanese", + "LLAMA Configuration": "LLAMA Configuration", + "LLAMA Model Config": "LLAMA Model Config", + "LLAMA Model Path": "LLAMA Model Path", + "Labeling Device": "Labeling Device", + "LoRA Model to be merged": "LoRA Model to be merged", + "Maximum Audio Duration": "Maximum Audio Duration", + "Maximum Length per Sample": "Maximum Length per Sample", + "Maximum Training Steps": "Maximum Training Steps", + "Maximum tokens per batch, 0 means no limit": "Maximum tokens per batch, 0 means no limit", + "Merge": "Merge", + "Merge LoRA": "Merge LoRA", + "Merge successfully": "Merge successfully", + "Minimum Audio Duration": "Minimum Audio Duration", + "Model Output Path": "Model Output Path", + "Model Size": "Model Size", + "Move": "Move", + "Move files successfully": "Move files successfully", + "No audio generated, please check the input text.": "No audio generated, please check the input text.", + "No selected options": "No selected options", + "Number of Workers": "Number of Workers", + "Open Inference Server": "Open Inference Server", + "Open Labeler WebUI": "Open Labeler WebUI", + "Open Tensorboard": "Open Tensorboard", + "Opened labeler in browser": "Opened labeler in browser", + "Optional Label Language": "Optional Label Language", + "Optional online ver": "Optional online ver", + "Output Path": "Output Path", + "Path error, please check the model file exists in the corresponding path": "Path error, please check the model file exists in the corresponding path", + "Precision": "Precision", + "Probability of applying Speaker Condition": "Probability of applying Speaker Condition", + "Put your text here.": "Put your text here.", + "Reference Audio": "Reference Audio", + "Reference Text": "Reference Text", + "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.": "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.", + "Remove Selected Data": "Remove Selected Data", + "Removed path successfully!": "Removed path successfully!", + "Repetition Penalty": "Repetition Penalty", + "Save model every n steps": "Save model every n steps", + "Select LLAMA ckpt": "Select LLAMA ckpt", + "Select VITS ckpt": "Select VITS ckpt", + "Select VQGAN ckpt": "Select VQGAN ckpt", + "Select source file processing method": "Select source file processing method", + "Select the model to be trained (Depending on the Tab page you are on)": "Select the model to be trained (Depending on the Tab page you are on)", + "Selected: {}": "Selected: {}", + "Speaker": "Speaker", + "Speaker is identified by the folder name": "Speaker is identified by the folder name", + "Start Training": "Start Training", + "Streaming Audio": "Streaming Audio", + "Streaming Generate": "Streaming Generate", + "Tensorboard Host": "Tensorboard Host", + "Tensorboard Log Path": "Tensorboard Log Path", + "Tensorboard Port": "Tensorboard Port", + "Tensorboard interface is closed": "Tensorboard interface is closed", + "Tensorboard interface is launched at {}": "Tensorboard interface is launched at {}", + "Text is too long, please keep it under {} characters.": "Text is too long, please keep it under {} characters.", + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.": "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.", + "Training Configuration": "Training Configuration", + "Training Error": "Training Error", + "Training stopped": "Training stopped", + "Type name of the speaker": "Type name of the speaker", + "Type the path or select from the dropdown": "Type the path or select from the dropdown", + "Use LoRA": "Use LoRA", + "Use LoRA can save GPU memory, but may reduce the quality of the model": "Use LoRA can save GPU memory, but may reduce the quality of the model", + "Use filelist": "Use filelist", + "Use large for 10G+ GPU, medium for 5G, small for 2G": "Use large for 10G+ GPU, medium for 5G, small for 2G", + "VITS Configuration": "VITS Configuration", + "VQGAN Configuration": "VQGAN Configuration", + "Validation Batch Size": "Validation Batch Size", + "View the status of the preprocessing folder (use the slider to control the depth of the tree)": "View the status of the preprocessing folder (use the slider to control the depth of the tree)", + "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.": "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.", + "WebUI Host": "WebUI Host", + "WebUI Port": "WebUI Port", + "Whisper Model": "Whisper Model", + "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).": "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).", + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU": "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU", + "latest": "latest", + "new": "new", + "Realtime Transform Text": "Realtime Transform Text", + "Normalization Result Preview (Currently Only Chinese)": "Normalization Result Preview (Currently Only Chinese)", + "Text Normalization": "Text Normalization" +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/es_ES.json b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/es_ES.json new file mode 100644 index 0000000000..1ea5988213 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/es_ES.json @@ -0,0 +1,122 @@ +{ + "16-mixed is recommended for 10+ series GPU": "se recomienda 16-mixed para GPU de la serie 10+", + "5 to 10 seconds of reference audio, useful for specifying speaker.": "5 a 10 segundos de audio de referencia, útil para especificar el hablante.", + "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).": "Un modelo de texto a voz basado en VQ-GAN y Llama desarrollado por [Fish Audio](https://fish.audio).", + "Accumulate Gradient Batches": "Acumular lotes de gradientes", + "Add to Processing Area": "Agregar al Área de Procesamiento", + "Added path successfully!": "¡Ruta agregada exitosamente!", + "Advanced Config": "Configuración Avanzada", + "Base LLAMA Model": "Modelo Base LLAMA", + "Batch Inference": "Inferencia por Lote", + "Batch Size": "Tamaño del Lote", + "Changing with the Model Path": "Cambiando con la Ruta del Modelo", + "Chinese": "Chino", + "Compile Model": "Compilar Modelo", + "Compile the model can significantly reduce the inference time, but will increase cold start time": "Compilar el modelo puede reducir significativamente el tiempo de inferencia, pero aumentará el tiempo de inicio en frío", + "Copy": "Copiar", + "Data Preprocessing": "Preprocesamiento de Datos", + "Data Preprocessing Path": "Ruta de Preprocesamiento de Datos", + "Data Source": "Fuente de Datos", + "Decoder Model Config": "Configuración del modelo decodificador", + "Decoder Model Path": "Ruta del modelo decodificador", + "Disabled": "Desactivado", + "Enable Reference Audio": "Habilitar Audio de Referencia", + "English": "Inglés", + "Error Message": "Mensaje de Error", + "File Preprocessing": "Preprocesamiento de Archivos", + "Generate": "Generar", + "Generated Audio": "Audio Generado", + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format": "Si no hay texto correspondiente para el audio, aplique ASR para asistencia, soporte para formato .txt o .lab", + "Infer interface is closed": "La interfaz de inferencia está cerrada", + "Inference Configuration": "Configuración de Inferencia", + "Inference Server Configuration": "Configuración del Servidor de Inferencia", + "Inference Server Error": "Error del Servidor de Inferencia", + "Inferring interface is launched at {}": "La interfaz de inferencia se ha lanzado en {}", + "Initial Learning Rate": "Tasa de Aprendizaje Inicial", + "Input Audio & Source Path for Transcription": "Audio de Entrada y Ruta de Origen para Transcripción", + "Input Text": "Texto de Entrada", + "Invalid path: {}": "Ruta inválida: {}", + "It is recommended to use CUDA, if you have low configuration, use CPU": "Se recomienda usar CUDA, si tiene una configuración baja, use CPU", + "Iterative Prompt Length, 0 means off": "Longitud de la Indicación Iterativa, 0 significa apagado", + "Japanese": "Japonés", + "LLAMA Configuration": "Configuración de LLAMA", + "LLAMA Model Config": "Configuración del Modelo LLAMA", + "LLAMA Model Path": "Ruta del Modelo LLAMA", + "Labeling Device": "Dispositivo de Etiquetado", + "LoRA Model to be merged": "Modelo LoRA a fusionar", + "Maximum Audio Duration": "Duración máxima de audio", + "Maximum Length per Sample": "Longitud Máxima por Muestra", + "Maximum Training Steps": "Pasos Máximos de Entrenamiento", + "Maximum tokens per batch, 0 means no limit": "Máximo de tokens por lote, 0 significa sin límite", + "Merge": "Fusionar", + "Merge LoRA": "Fusionar LoRA", + "Merge successfully": "Fusionado exitosamente", + "Minimum Audio Duration": "Duración mínima de audio", + "Model Output Path": "Ruta de Salida del Modelo", + "Model Size": "Tamaño del Modelo", + "Move": "Mover", + "Move files successfully": "Archivos movidos exitosamente", + "No audio generated, please check the input text.": "No se generó audio, por favor verifique el texto de entrada.", + "No selected options": "No hay opciones seleccionadas", + "Number of Workers": "Número de Trabajadores", + "Open Inference Server": "Abrir Servidor de Inferencia", + "Open Labeler WebUI": "Abrir Interfaz Web del Etiquetador", + "Open Tensorboard": "Abrir Tensorboard", + "Opened labeler in browser": "Se abrió el etiquetador en el navegador", + "Optional Label Language": "Idioma de Etiquetado Opcional", + "Optional online ver": "Ver en línea opcional", + "Output Path": "Ruta de Salida", + "Path error, please check the model file exists in the corresponding path": "Error de ruta, por favor verifique que el archivo del modelo exista en la ruta correspondiente", + "Precision": "Precisión", + "Probability of applying Speaker Condition": "Probabilidad de aplicar Condición de Hablante", + "Put your text here.": "Ponga su texto aquí.", + "Reference Audio": "Audio de Referencia", + "Reference Text": "Texto de Referencia", + "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.": "El código relacionado se publica bajo la Licencia BSD-3-Clause, y los pesos se publican bajo la Licencia CC BY-NC-SA 4.0.", + "Remove Selected Data": "Eliminar Datos Seleccionados", + "Removed path successfully!": "¡Ruta eliminada exitosamente!", + "Repetition Penalty": "Penalización por Repetición", + "Save model every n steps": "Guardar modelo cada n pasos", + "Select LLAMA ckpt": "Seleccionar punto de control LLAMA", + "Select VITS ckpt": "Seleccionar punto de control VITS", + "Select VQGAN ckpt": "Seleccionar punto de control VQGAN", + "Select source file processing method": "Seleccione el método de procesamiento de archivos fuente", + "Select the model to be trained (Depending on the Tab page you are on)": "Seleccione el modelo a entrenar (Dependiendo de la pestaña en la que se encuentre)", + "Selected: {}": "Seleccionado: {}", + "Speaker": "Hablante", + "Speaker is identified by the folder name": "El hablante se identifica por el nombre de la carpeta", + "Start Training": "Iniciar Entrenamiento", + "Streaming Audio": "transmisión de audio", + "Streaming Generate": "síntesis en flujo", + "Tensorboard Host": "Host de Tensorboard", + "Tensorboard Log Path": "Ruta de Registro de Tensorboard", + "Tensorboard Port": "Puerto de Tensorboard", + "Tensorboard interface is closed": "La interfaz de Tensorboard está cerrada", + "Tensorboard interface is launched at {}": "La interfaz de Tensorboard se ha lanzado en {}", + "Text is too long, please keep it under {} characters.": "El texto es demasiado largo, por favor manténgalo por debajo de {} caracteres.", + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.": "La ruta de la carpeta de entrada a la izquierda o la lista de archivos. Ya sea que esté marcado o no, se utilizará para el entrenamiento posterior en esta lista.", + "Training Configuration": "Configuración de Entrenamiento", + "Training Error": "Error de Entrenamiento", + "Training stopped": "Entrenamiento detenido", + "Type name of the speaker": "Escriba el nombre del hablante", + "Type the path or select from the dropdown": "Escriba la ruta o seleccione de la lista desplegable", + "Use LoRA": "Usar LoRA", + "Use LoRA can save GPU memory, but may reduce the quality of the model": "Usar LoRA puede ahorrar memoria GPU, pero puede reducir la calidad del modelo", + "Use filelist": "Usar lista de archivos", + "Use large for 10G+ GPU, medium for 5G, small for 2G": "Use grande para GPU de 10G+, mediano para 5G, pequeño para 2G", + "VITS Configuration": "Configuración de VITS", + "VQGAN Configuration": "Configuración de VQGAN", + "Validation Batch Size": "Tamaño del Lote de Validación", + "View the status of the preprocessing folder (use the slider to control the depth of the tree)": "Vea el estado de la carpeta de preprocesamiento (use el control deslizante para controlar la profundidad del árbol)", + "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.": "No somos responsables de ningún mal uso del modelo, por favor considere sus leyes y regulaciones locales antes de usarlo.", + "WebUI Host": "Host de WebUI", + "WebUI Port": "Puerto de WebUI", + "Whisper Model": "Modelo Whisper", + "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).": "Puede encontrar el código fuente [aquí](https://github.com/fishaudio/fish-speech) y los modelos [aquí](https://huggingface.co/fishaudio/fish-speech-1).", + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU": "Se recomienda bf16-true para GPU de la serie 30+, se recomienda 16-mixed para GPU de la serie 10+", + "latest": "más reciente", + "new": "nuevo", + "Realtime Transform Text": "Transformación de Texto en Tiempo Real", + "Normalization Result Preview (Currently Only Chinese)": "Vista Previa del Resultado de Normalización (Actualmente Solo Chino)", + "Text Normalization": "Normalización de Texto" +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/ja_JP.json b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/ja_JP.json new file mode 100644 index 0000000000..e7817eb0c5 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/ja_JP.json @@ -0,0 +1,123 @@ +{ + "16-mixed is recommended for 10+ series GPU": "10シリーズ以降のGPUには16-mixedをお勧めします", + "5 to 10 seconds of reference audio, useful for specifying speaker.": "話者を指定するのに役立つ、5~10秒のリファレンスオーディオ。", + "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).": "[Fish Audio](https://fish.audio)が開発したVQ-GANとLlamaに基づくテキスト音声合成モデル。", + "Accumulate Gradient Batches": "勾配バッチの累積", + "Add to Processing Area": "処理エリアに追加", + "Added path successfully!": "パスの追加に成功しました!", + "Advanced Config": "詳細設定", + "Base LLAMA Model": "基本LLAMAモデル", + "Batch Inference": "バッチ推論", + "Batch Size": "バッチサイズ", + "Changing with the Model Path": "モデルのパスに伴って変化する", + "Chinese": "中国語", + "Compile Model": "モデルのコンパイル", + "Compile the model can significantly reduce the inference time, but will increase cold start time": "モデルをコンパイルすると推論時間を大幅に短縮できますが、コールドスタート時間が長くなります", + "Copy": "コピー", + "Data Preprocessing": "データ前処理", + "Data Preprocessing Path": "データ前処理パス", + "Data Source": "データソース", + "Decoder Model Config": "デコーダーモデルの構成", + "Decoder Model Path": "デコーダーモデルのパス", + "Disabled": "無効", + "Enable Reference Audio": "リファレンスオーディオを有効にする", + "English": "英語", + "Error Message": "エラーメッセージ", + "File Preprocessing": "文書前处理", + "Generate": "生成", + "Generated Audio": "生成されたオーディオ", + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format": "音声に対応するテキストがない場合は、ASRを適用してサポートします。.txtまたは.lab形式をサポートしています", + "Infer interface is closed": "推論インターフェースが閉じられています", + "Inference Configuration": "推論設定", + "Inference Server Configuration": "推論サーバー設定", + "Inference Server Error": "推論サーバーエラー", + "Inferring interface is launched at {}": "推論インターフェースが{}で起動しました", + "Initial Learning Rate": "初期学習率", + "Input Audio & Source Path for Transcription": "入力オーディオと文字起こしのソースパス", + "Input Text": "入力テキスト", + "Invalid path: {}": "無効なパス: {}", + "It is recommended to use CUDA, if you have low configuration, use CPU": "CUDAの使用をお勧めします。低い構成の場合はCPUを使用してください", + "Iterative Prompt Length, 0 means off": "反復プロンプト長。0はオフを意味します", + "Japanese": "日本語", + "LLAMA Configuration": "LLAMA設定", + "LLAMA Model Config": "LLAMAモデル設定", + "LLAMA Model Path": "LLAMAモデルパス", + "Labeling Device": "ラベリングデバイス", + "LoRA Model to be merged": "マージするLoRAモデル", + "Maximum Audio Duration": "最大オーディオの長さ", + "Maximum Length per Sample": "サンプルあたりの最大長", + "Maximum Training Steps": "最大トレーニングステップ数", + "Maximum tokens per batch, 0 means no limit": "バッチあたりの最大トークン数。0は制限なしを意味します", + "Merge": "マージ", + "Merge LoRA": "LoRAのマージ", + "Merge successfully": "マージに成功しました", + "Minimum Audio Duration": "最小オーディオの長さ", + "Model Output Path": "モデル出力パス", + "Model Size": "モデルサイズ", + "Move": "移動", + "Move files successfully": "ファイルの移動に成功しました", + "No audio generated, please check the input text.": "オーディオが生成されていません。入力テキストを確認してください。", + "No selected options": "選択されたオプションはありません", + "Number of Workers": "ワーカー数", + "Open Inference Server": "推論サーバーを開く", + "Open Labeler WebUI": "ラベラーWebUIを開く", + "Open Tensorboard": "Tensorboardを開く", + "Opened labeler in browser": "ブラウザでラベラーを開きました", + "Optional Label Language": "オプションのラベル言語", + "Optional online ver": "オプションのオンラインバージョン", + "Output Path": "出力パス", + "Path error, please check the model file exists in the corresponding path": "パスエラー。対応するパスにモデルファイルが存在するか確認してください", + "Precision": "精度", + "Probability of applying Speaker Condition": "話者条件を適用する確率", + "Put your text here.": "ここにテキストを入力してください。", + "Reference Audio": "リファレンスオーディオ", + "Reference Text": "リファレンステキスト", + "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.": "関連コードはBSD-3-Clauseライセンスの下でリリースされ、重みはCC BY-NC-SA 4.0ライセンスの下でリリースされます。", + "Remove Selected Data": "選択したデータを削除", + "Removed path successfully!": "パスの削除に成功しました!", + "Repetition Penalty": "反復ペナルティ", + "Save model every n steps": "nステップごとにモデルを保存", + "Select LLAMA ckpt": " LLAMA チェックポイントを選択", + "Select VITS ckpt": "VITS チェックポイントを選択", + "Select VQGAN ckpt": "VQGAN チェックポイントを選択", + "Select source file processing method": "ソースファイルの処理方法を選択", + "Select the model to be trained (Depending on the Tab page you are on)": "タブページに応じてトレーニングするモデルを選択してください", + "Selected: {}": "選択済み: {}", + "Speaker": "話者", + "Speaker is identified by the folder name": "話者はフォルダ名で識別されます", + "Start Training": "トレーニング開始", + "Streaming Audio": "ストリーミングオーディオ", + "Streaming Generate": "ストリーミング合成", + "Tensorboard Host": "Tensorboardホスト", + "Tensorboard Log Path": "Tensorboardログパス", + "Tensorboard Port": "Tensorboardポート", + "Tensorboard interface is closed": "Tensorboardインターフェースが閉じられています", + "Tensorboard interface is launched at {}": "Tensorboardインターフェースが{}で起動されました", + "Text is too long, please keep it under {} characters.": "テキストが長すぎます。{}文字以内に抑えてください。", + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.": "左側の入力フォルダまたはファイルリストのパス。チェックの有無にかかわらず、このリストの後続のトレーニングに使用されます。", + "Training Configuration": "トレーニング設定", + "Training Error": "トレーニングエラー", + "Training stopped": "トレーニングが停止しました", + "Type name of the speaker": "話者の名前を入力", + "Type the path or select from the dropdown": "パスを入力するか、ドロップダウンから選択してください", + "Use LoRA": "LoRAを使用", + "Use LoRA can save GPU memory, but may reduce the quality of the model": "LoRAを使用するとGPUメモリを節約できますが、モデルの品質が低下する可能性があります", + "Use filelist": "ファイルリストを使用", + "Use large for 10G+ GPU, medium for 5G, small for 2G": "10G以上のGPUには大、5Gには中、2Gには小を使用してください", + "VITS Configuration": "VITS の構成", + "VQGAN Configuration": "VQGAN の構成", + "Validation Batch Size": "検証バッチサイズ", + "View the status of the preprocessing folder (use the slider to control the depth of the tree)": "前処理フォルダの状態を表示(スライダーを使用してツリーの深さを制御)", + "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.": "モデルの誤用については一切責任を負いません。使用する前に、現地の法律と規制を考慮してください。", + "WebUI Host": "WebUIホスト", + "WebUI Port": "WebUIポート", + "Whisper Model": "Whisperモデル", + "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).": "ソースコードは[こちら](https://github.com/fishaudio/fish-speech)、モデルは[こちら](https://huggingface.co/fishaudio/fish-speech-1)にあります。", + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU": "30シリーズ以降のGPUにはbf16-trueを、10シリーズ以降のGPUには16-mixedをお勧めします", + "latest": "最新", + "new": "新規", + "Realtime Transform Text": "リアルタイム変換テキスト", + "Normalization Result Preview (Currently Only Chinese)": "正規化結果プレビュー(現在は中国語のみ)", + "Text Normalization": "テキスト正規化" + +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/pt_BR.json b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/pt_BR.json new file mode 100644 index 0000000000..c3df431a40 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/pt_BR.json @@ -0,0 +1,133 @@ +{ + "5 to 10 seconds of reference audio, useful for specifying speaker.": "5 a 10 segundos de áudio de referência, útil para especificar o orador.", + "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).": "Um modelo de texto para fala baseado em VQ-GAN e Llama desenvolvido por [Fish Audio](https://fish.audio).", + "Accumulate Gradient Batches": "Acumular Lotes de Gradiente", + "Add to Processing Area": "Adicionar à Área de Processamento", + "Added path successfully!": "Caminho adicionado com sucesso!", + "Advanced Config": "Configuração Avançada", + "Base LLAMA Model": "Modelo LLAMA Base", + "Batch Inference": "Inferência em Lote", + "Batch Size": "Tamanho do Lote", + "Changing with the Model Path": "Alterando com o Caminho do Modelo", + + "Compile Model": "Compilar Modelo", + "Compile the model can significantly reduce the inference time, but will increase cold start time": "Compilar o modelo pode reduzir significativamente o tempo de inferência, mas aumentará a latência inicial", + "Copy": "Copiar", + "Data Preprocessing": "Pré-processamento de Dados", + "Data Preprocessing Path": "Caminho de Pré-processamento de Dados", + "Data Source": "Fonte de Dados", + "Decoder Model Config": "Configuração do Modelo Decodificador", + "Decoder Model Path": "Caminho do Modelo Decodificador", + "Disabled": "Desativado", + "Enable Initial Prompt": "Habilitar Prompt Inicial", + "Enable Reference Audio": "Habilitar Áudio de Referência", + "English": "Inglês", + "Japanese": "Japonês", + "Chinese": "Chinês", + "Portuguese": "Português", + "Spanish": "Espanhol", + "Error Message": "Mensagem de Erro", + "Faster Whisper, Up to 5g GPU memory usage": "Faster Whisper (Usa até 5 GB de vRAM)", + "File Preprocessing": "Pré-processamento de Arquivos", + "Generate": "Gerar", + "Generated Audio": "Áudio Gerado", + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format": "Se não houver texto correspondente ao áudio, utilize o ASR para assistência (formatos .txt ou .lab)", + "Infer interface is closed": "A interface de inferência foi fechada", + "Inference Configuration": "Configuração de Inferência", + "Inference Server Configuration": "Configuração do Servidor de Inferência", + "Inference Server Error": "Erro do Servidor de Inferência", + "Inferring interface is launched at {}": "A interface de inferência foi iniciada em {}", + "Initial Learning Rate": "Taxa de Aprendizagem Inicial", + "Initial Prompt": "Prompt Inicial", + "Initial prompt can provide contextual or vocabulary-specific guidance to the model.": "O prompt inicial pode fornecer orientação contextual ou específica de vocabulário para o modelo.", + "Input Audio & Source Path for Transcription": "Entrada de Áudio/Caminho de Origem para Transcrição", + "Input Text": "Texto de Entrada", + "Invalid path: {}": "Caminho inválido: {}", + "It is recommended to use CUDA, if you have low configuration, use CPU": "Para GPUs Nvidia é recomendado usar CUDA. Se não tiver uma GPU Nvidia, use CPU", + "Iterative Prompt Length, 0 means off": "Comprimento do Prompt Iterativo (0 = desativado)", + "LLAMA Configuration": "Configuração do LLAMA", + "LLAMA Model Config": "Configuração do Modelo LLAMA", + "LLAMA Model Path": "Caminho do Modelo LLAMA", + "Labeling Device": "Dispositivo de Rotulagem", + "LoRA Model to be merged": "Modelo LoRA para mesclagem", + "Maximum Length per Sample": "Comprimento Máximo por Amostra", + "Maximum Training Steps": "Etapas Máximas de Treinamento", + "Maximum tokens per batch, 0 means no limit": "Número máximo de tokens por lote, 0 significa sem limite", + "Merge": "Mesclar", + "Merge LoRA": "Mesclar LoRA", + "Merge successfully": "Mesclado com sucesso", + "Model Output Path": "Caminho de Saída do Modelo", + "Model Quantization": "Quantização do Modelo", + "Model Size": "Tamanho do Modelo", + "Move": "Mover", + "Move files successfully": "Arquivos movidos com sucesso", + "No audio generated, please check the input text.": "Nenhum áudio gerado, verifique o texto de entrada.", + "No selected options": "Nenhuma opção selecionada", + "Normalization Result Preview (Currently Only Chinese)": "Pré-visualização do Resultado da Normalização (Atualmente Apenas Chinês)", + "Number of Workers": "Número de Processos", + "Open Inference Server": "Abrir Servidor de Inferência", + "Open Labeler WebUI": "Abrir WebUI de Rotulagem", + "Open Tensorboard": "Abrir Tensorboard", + "Opened labeler in browser": "WebUI de rotulagem aberta no navegador", + "Optional Label Language": "Idioma do Rótulo (Opcional)", + "Optional online ver": "Versão online (opcional)", + "Output Path": "Caminho de Saída", + "Path error, please check the model file exists in the corresponding path": "Erro de caminho, verifique se o arquivo do modelo existe no caminho correspondente", + "Post-quantification Precision": "Precisão Pós-quantização", + "Precision": "Precisão", + "Probability of applying Speaker Condition": "Probabilidade de Aplicar Condição de Orador", + "Put your text here.": "Insira seu texto aqui.", + "Quantify": "Quantizar", + "Quantify successfully": "Quantizado com sucesso", + "Realtime Transform Text": "Transformar Texto em Tempo Real", + "Reference Audio": "Áudio de Referência", + "Reference Text": "Texto de Referência", + "warning": "Aviso", + "Pre-processing begins...": "O pré-processamento começou!", + "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.": "O código relacionado é licenciado sob a Licença BSD-3-Clause, e os pesos sob a Licença CC BY-NC-SA 4.0.", + "Remove Selected Data": "Remover Dados Selecionados", + "Removed path successfully!": "Caminho removido com sucesso!", + "Repetition Penalty": "Penalidade de Repetição", + "Save model every n steps": "Salvar modelo a cada n etapas", + "Select LLAMA ckpt": "Selecionar .ckpt do LLAMA", + "Select source file processing method": "Escolha como processar o arquivo de origem", + "Select the model to be trained (Depending on the Tab page you are on)": "Selecione o modelo para o treinamento (dependendo da aba em que você está)", + "Selected: {}": "Selecionado: {}", + "Speaker is identified by the folder name": "O orador é identificado pelo nome da pasta", + "Start Training": "Iniciar Treinamento", + "Streaming Audio": "Áudio em Streaming", + "Streaming Generate": "Geração em Streaming", + "Tensorboard Host": "Host do Tensorboard", + "Tensorboard Log Path": "Caminho de Log do Tensorboard", + "Tensorboard Port": "Porta do Tensorboard", + "Tensorboard interface is closed": "A interface do Tensorboard está fechada", + "Tensorboard interface is launched at {}": "A interface do Tensorboard foi iniciada em {}", + "Text Normalization": "Normalização de Texto", + "Text is too long, please keep it under {} characters.": "O texto é muito longo. Mantenha-o com menos de {} caracteres.", + "The lower the quantitative precision, the more the effectiveness may decrease, but the greater the efficiency will increase": "Quanto menor a precisão quantitativa, mais a eficácia pode diminuir, mas maior será o aumento da eficiência", + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.": "O caminho da pasta de entrada à esquerda ou a lista de arquivos. Independentemente de estar marcada ou não, ela será utilizada para o treinamento subsequente nesta lista.", + "Training Configuration": "Configuração de Treinamento", + "Training Error": "Erro de Treinamento", + "Training stopped": "Treinamento interrompido!", + "Type the path or select from the dropdown": "Digite o caminho ou selecione no menu suspenso", + "Use LoRA": "Usar LoRA", + "Use LoRA can save GPU memory, but may reduce the quality of the model": "O uso de LoRAs pode economizar memória da GPU, mas também pode reduzir a qualidade", + "Use filelist": "Usar lista de arquivos", + "VQGAN Configuration": "Configuração do VQGAN", + "View the status of the preprocessing folder (use the slider to control the depth of the tree)": "Visualizar o status da pasta de pré-processamento (use o controle deslizante para controlar a profundidade da árvore)", + "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.": "Não nos responsabilizamos por qualquer uso indevido do modelo. Por favor, considere as leis e regulamentações locais antes de usá-lo.", + "WebUI Host": "Host da WebUI", + "WebUI Port": "Porta da WebUI", + "Whisper Model": "Modelo Whisper", + "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).": "Você pode encontrar o código fonte [aqui](https://github.com/fishaudio/fish-speech) e os modelos [aqui](https://huggingface.co/fishaudio/fish-speech-1).", + "auto": "automático", + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU": "bf16-true é recomendado para GPUs da série 30+, 16-mixed é recomendado para GPUs da série 10+", + "latest": "mais recente", + "new": "novo", + "This audio introduces the basic concepts and applications of artificial intelligence and machine learning.": "Este áudio introduz os conceitos básicos e aplicações de inteligência artificial e aprendizado de máquina.", + "You don't need to train this model!": "Não é necessário treinar este modelo!", + "Yes": "Sim", + "No": "Não", + "version:": "versão:", + "author:": "autor:" +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/zh_CN.json b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/zh_CN.json new file mode 100644 index 0000000000..da81eef1cf --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/locale/zh_CN.json @@ -0,0 +1,122 @@ +{ + "16-mixed is recommended for 10+ series GPU": "10+ 系列 GPU 建议使用 16-mixed", + "5 to 10 seconds of reference audio, useful for specifying speaker.": "5 到 10 秒的参考音频,适用于指定音色。", + "A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).": "由 [Fish Audio](https://fish.audio) 研发的基于 VQ-GAN 和 Llama 的多语种语音合成.", + "Accumulate Gradient Batches": "梯度累积批次", + "Add to Processing Area": "加入处理区", + "Added path successfully!": "添加路径成功!", + "Advanced Config": "高级参数", + "Base LLAMA Model": "基础 LLAMA 模型", + "Batch Inference": "批量推理", + "Batch Size": "批次大小", + "Changing with the Model Path": "随模型路径变化", + "Chinese": "中文", + "Compile Model": "编译模型", + "Compile the model can significantly reduce the inference time, but will increase cold start time": "编译模型可以显著减少推理时间,但会增加冷启动时间", + "Copy": "复制", + "Data Preprocessing": "数据预处理", + "Data Preprocessing Path": "数据预处理路径", + "Data Source": "数据源", + "Decoder Model Config": "解码器模型配置", + "Decoder Model Path": "解码器模型路径", + "Disabled": "禁用", + "Enable Reference Audio": "启用参考音频", + "English": "英文", + "Error Message": "错误信息", + "File Preprocessing": "文件预处理", + "Generate": "生成", + "Generated Audio": "音频", + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format": "如果音频没有对应的文本,可以应用 ASR 辅助,支持 .txt 或 .lab 格式", + "Infer interface is closed": "推理界面已关闭", + "Inference Configuration": "推理配置", + "Inference Server Configuration": "推理服务器配置", + "Inference Server Error": "推理服务器错误", + "Inferring interface is launched at {}": "推理界面已在 {} 上启动", + "Initial Learning Rate": "初始学习率", + "Input Audio & Source Path for Transcription": "输入音频和转录源路径", + "Input Text": "输入文本", + "Invalid path: {}": "无效路径: {}", + "It is recommended to use CUDA, if you have low configuration, use CPU": "建议使用 CUDA,如果配置较低,使用 CPU", + "Iterative Prompt Length, 0 means off": "迭代提示长度,0 表示关闭", + "Japanese": "日文", + "LLAMA Configuration": "LLAMA 配置", + "LLAMA Model Config": "LLAMA 模型配置", + "LLAMA Model Path": "LLAMA 模型路径", + "Labeling Device": "标注加速设备", + "LoRA Model to be merged": "要合并的 LoRA 模型", + "Maximum Audio Duration": "最大音频时长", + "Maximum Length per Sample": "每个样本的最大长度", + "Maximum Training Steps": "最大训练步数", + "Maximum tokens per batch, 0 means no limit": "每批最大令牌数,0 表示无限制", + "Merge": "合并", + "Merge LoRA": "合并 LoRA", + "Merge successfully": "合并成功", + "Minimum Audio Duration": "最小音频时长", + "Model Output Path": "模型输出路径", + "Model Size": "模型规模", + "Move": "移动", + "Move files successfully": "移动文件成功", + "No audio generated, please check the input text.": "没有生成音频,请检查输入文本.", + "No selected options": "没有选择的选项", + "Number of Workers": "数据加载进程数", + "Open Inference Server": "打开推理服务器", + "Open Labeler WebUI": "打开标注工具", + "Open Tensorboard": "打开 Tensorboard", + "Opened labeler in browser": "在浏览器中打开标注工具", + "Optional Label Language": "[可选] 标注语言", + "Optional online ver": "[可选] 使用在线版", + "Output Path": "输出路径", + "Path error, please check the model file exists in the corresponding path": "路径错误,请检查模型文件是否存在于相应路径", + "Precision": "精度", + "Probability of applying Speaker Condition": "应用说话人条件的概率", + "Put your text here.": "在此处输入文本.", + "Reference Audio": "参考音频", + "Reference Text": "参考文本", + "Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.": "相关代码使用 BSD-3-Clause 许可证发布,权重使用 CC BY-NC-SA 4.0 许可证发布.", + "Remove Selected Data": "移除选中数据", + "Removed path successfully!": "移除路径成功!", + "Repetition Penalty": "重复惩罚", + "Save model every n steps": "每 n 步保存模型", + "Select LLAMA ckpt": "选择 LLAMA 检查点", + "Select VITS ckpt": "选择 VITS 检查点", + "Select VQGAN ckpt": "选择 VQGAN 检查点", + "Select source file processing method": "选择源文件处理方法", + "Select the model to be trained (Depending on the Tab page you are on)": "根据您所在的选项卡页面选择要训练的模型", + "Selected: {}": "已选择: {}", + "Speaker": "说话人", + "Speaker is identified by the folder name": "自动根据父目录名称识别说话人", + "Start Training": "开始训练", + "Streaming Audio": "流式音频", + "Streaming Generate": "流式合成", + "Tensorboard Host": "Tensorboard 监听地址", + "Tensorboard Log Path": "Tensorboard 日志路径", + "Tensorboard Port": "Tensorboard 端口", + "Tensorboard interface is closed": "Tensorboard 界面已关闭", + "Tensorboard interface is launched at {}": "Tensorboard 界面已在 {} 上启动", + "Text is too long, please keep it under {} characters.": "文本太长,请保持在 {} 个字符以内.", + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list.": "左侧输入文件夹的路径或文件列表。无论是否选中,都将在此列表中用于后续训练.", + "Training Configuration": "训练配置", + "Training Error": "训练错误", + "Training stopped": "训练已停止", + "Type name of the speaker": "输入说话人的名称", + "Type the path or select from the dropdown": "输入路径或从下拉菜单中选择", + "Use LoRA": "使用 LoRA", + "Use LoRA can save GPU memory, but may reduce the quality of the model": "使用 LoRA 可以节省 GPU 内存,但可能会降低模型质量", + "Use filelist": "使用文件列表", + "Use large for 10G+ GPU, medium for 5G, small for 2G": "10G+ GPU 使用 large, 5G 使用 medium, 2G 使用 small", + "VITS Configuration": "VITS 配置", + "VQGAN Configuration": "VQGAN 配置", + "Validation Batch Size": "验证批次大小", + "View the status of the preprocessing folder (use the slider to control the depth of the tree)": "查看预处理文件夹的状态 (使用滑块控制树的深度)", + "We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.": "我们不对模型的任何滥用负责,请在使用之前考虑您当地的法律法规.", + "WebUI Host": "WebUI 监听地址", + "WebUI Port": "WebUI 端口", + "Whisper Model": "Whisper 模型", + "You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).": "你可以在 [这里](https://github.com/fishaudio/fish-speech) 找到源代码和 [这里](https://huggingface.co/fishaudio/fish-speech-1) 找到模型.", + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU": "30+ 系列 GPU 建议使用 bf16-true, 10+ 系列 GPU 建议使用 16-mixed", + "latest": "最近的检查点", + "new": "创建新的检查点", + "Realtime Transform Text": "实时规范化文本", + "Normalization Result Preview (Currently Only Chinese)": "规范化结果预览", + "Text Normalization": "文本规范化" +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/i18n/scan.py b/xinference/thirdparty/fish_speech/fish_speech/i18n/scan.py new file mode 100644 index 0000000000..d0194c0f1a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/i18n/scan.py @@ -0,0 +1,122 @@ +import ast +import glob +import json +from collections import OrderedDict +from pathlib import Path + +from loguru import logger + +from .core import DEFAULT_LANGUAGE, I18N_FILE_PATH + + +def extract_i18n_strings(node): + i18n_strings = [] + + if ( + isinstance(node, ast.Call) + and isinstance(node.func, ast.Name) + and node.func.id == "i18n" + ): + for arg in node.args: + if isinstance(arg, ast.Str): + i18n_strings.append(arg.s) + + for child_node in ast.iter_child_nodes(node): + i18n_strings.extend(extract_i18n_strings(child_node)) + + return i18n_strings + + +# scan the directory for all .py files (recursively) +# for each file, parse the code into an AST +# for each AST, extract the i18n strings + +strings = [] +folders = ["fish_speech", "tools"] +# for filename in glob.iglob("**/*.py", recursive=True): +for folder in folders: + for f in Path(folder).rglob("*.py"): + code = f.read_text(encoding="utf-8") + if "i18n(" in code: + tree = ast.parse(code) + i18n_strings = extract_i18n_strings(tree) + logger.info(f"Found {len(i18n_strings)} i18n strings in {f}") + strings.extend(i18n_strings) + +code_keys = set(strings) +logger.info(f"Total unique: {len(code_keys)}") + + +standard_file = I18N_FILE_PATH / f"{DEFAULT_LANGUAGE}.json" +with open(standard_file, "r", encoding="utf-8") as f: + standard_data = json.load(f, object_pairs_hook=OrderedDict) +standard_keys = set(standard_data.keys()) + +# Define the standard file name +unused_keys = standard_keys - code_keys +logger.info(f"Found {len(unused_keys)} unused keys in {standard_file}") +for unused_key in unused_keys: + logger.info(f"\t{unused_key}") + +missing_keys = code_keys - standard_keys +logger.info(f"Found {len(missing_keys)} missing keys in {standard_file}") +for missing_key in missing_keys: + logger.info(f"\t{missing_key}") + +code_keys_dict = OrderedDict() +for s in strings: + code_keys_dict[s] = s + +# write back +with open(standard_file, "w", encoding="utf-8") as f: + json.dump(code_keys_dict, f, ensure_ascii=False, indent=4, sort_keys=True) + f.write("\n") + +logger.info(f"Updated {standard_file}") + + +# Define the standard file name +standard_file = I18N_FILE_PATH / f"{DEFAULT_LANGUAGE}.json" + +# Find all JSON files in the directory +dir_path = I18N_FILE_PATH +languages = [f for f in dir_path.glob("*.json") if f.stem != DEFAULT_LANGUAGE] + +# Load the standard file +with open(standard_file, "r", encoding="utf-8") as f: + standard_data = json.load(f, object_pairs_hook=OrderedDict) + +# Loop through each language file +for lang_file in languages: + # Load the language file + with open(lang_file, "r", encoding="utf-8") as f: + lang_data = json.load(f, object_pairs_hook=OrderedDict) + + # Find the difference between the language file and the standard file + diff = set(standard_data.keys()) - set(lang_data.keys()) + + miss = set(lang_data.keys()) - set(standard_data.keys()) + + # Add any missing keys to the language file + for key in diff: + lang_data[key] = "#!" + key + logger.info(f"Added missing key: {key} to {lang_file}") + + # Del any extra keys to the language file + for key in miss: + del lang_data[key] + logger.info(f"Del extra key: {key} from {lang_file}") + + # Sort the keys of the language file to match the order of the standard file + lang_data = OrderedDict( + sorted(lang_data.items(), key=lambda x: list(standard_data.keys()).index(x[0])) + ) + + # Save the updated language file + with open(lang_file, "w", encoding="utf-8") as f: + json.dump(lang_data, f, ensure_ascii=False, indent=4, sort_keys=True) + f.write("\n") + + logger.info(f"Updated {lang_file}") + +logger.info("Done") diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lit_module.py b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lit_module.py new file mode 100644 index 0000000000..df970400f8 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lit_module.py @@ -0,0 +1,202 @@ +from typing import Any, Optional + +import lightning as L +import torch +import torch.nn.functional as F +from lightning.pytorch.utilities.types import OptimizerLRScheduler + +import fish_speech.utils as utils +from fish_speech.conversation import CODEBOOK_PAD_TOKEN_ID +from fish_speech.models.text2semantic.llama import NaiveTransformer + +log = utils.RankedLogger(__name__, rank_zero_only=True) + + +class TextToSemantic(L.LightningModule): + def __init__( + self, + model: NaiveTransformer, + optimizer: Any, + lr_scheduler: Any, + ): + super().__init__() + + self.model = model + self.optimizer_builder = optimizer + self.lr_scheduler_builder = lr_scheduler + + def forward(self, x): + return self.model(x) + + def on_save_checkpoint(self, checkpoint): + # Save only LoRA parameters + state_dict = checkpoint["state_dict"] + use_lora = any("lora" in name for name in state_dict.keys()) + if not use_lora: + return + + for name in list(state_dict.keys()): + if "lora" not in name: + state_dict.pop(name) + + def configure_optimizers(self) -> OptimizerLRScheduler: + # Get weight decay parameters + weight_decay_parameters, other_parameters = [], [] + for name, param in self.named_parameters(): + if ".bias" in name or "norm.weight" in name or ".embeddings." in name: + other_parameters.append(param) + else: + weight_decay_parameters.append(param) + + optimizer = self.optimizer_builder( + [ + {"params": weight_decay_parameters}, + {"params": other_parameters, "weight_decay": 0.0}, + ] + ) + + # Print the parameters and their weight decay + for i in optimizer.param_groups: + log.info( + f"Set weight decay: {i['weight_decay']} for {len(i['params'])} parameters" + ) + + lr_scheduler = self.lr_scheduler_builder(optimizer) + + return { + "optimizer": optimizer, + "lr_scheduler": { + "scheduler": lr_scheduler, + "interval": "step", + }, + } + + # Copied from https://github.com/eric-mitchell/direct-preference-optimization/blob/main/trainers.py#L90 + def get_batch_logps( + self, + logits: torch.FloatTensor, + labels: torch.LongTensor, + average_log_prob: bool = False, + ) -> torch.FloatTensor: + """Compute the log probabilities of the given labels under the given logits. + + Args: + logits: Logits of the model (unnormalized). Shape: (batch_size, sequence_length, codebook_size, vocab_size) + labels: Labels for which to compute the log probabilities. Label tokens with a value of -100 are ignored. Shape: (batch_size, sequence_length, codebook_size) + average_log_prob: If True, return the average log probability per (non-masked) token. Otherwise, return the sum of the log probabilities of the (non-masked) tokens. + + Returns: + A tensor of shape (batch_size,) containing the average/sum log probabilities of the given labels under the given logits. + """ + assert logits.shape[:-1] == labels.shape + + labels = labels.clone() + loss_mask = labels != -100 + + # dummy token; we'll ignore the losses on these tokens later + labels[labels == -100] = 0 + + per_token_logps = torch.gather( + logits.log_softmax(-1), dim=-1, index=labels.unsqueeze(-1) + ).squeeze(-1) + + if average_log_prob: + return (per_token_logps * loss_mask).sum(-1) / loss_mask.sum(-1) + else: + return (per_token_logps * loss_mask).sum(-1) + + def _step(self, batch, batch_idx, stage: str): + is_train = stage == "train" + + if is_train: + # Key part to make lora work + # Otherwise the parameters are merged, which lead to incorrect gradients + self.model.train() + + # Do positive and negative samples in the same batch to speed up training + labels = batch["labels"] + outputs = self.model( + inp=batch["inputs"], + key_padding_mask=batch["attention_masks"], + ) + token_logits = outputs.token_logits + codebook_logits = outputs.codebook_logits + + # Generate labels + base_loss = F.cross_entropy( + token_logits.view(-1, token_logits.size(-1)), + labels[:, 0].reshape(-1), + ignore_index=-100, + ) + + codebook_labels = labels[:, 1 : 1 + self.model.config.num_codebooks].mT + semantic_loss = F.cross_entropy( + codebook_logits.view(-1, codebook_logits.size(-1)), + codebook_labels.reshape(-1), + ignore_index=-100, + ) + + loss = base_loss + semantic_loss + + self.log( + f"{stage}/loss", + loss, + on_step=is_train, + on_epoch=not is_train, + prog_bar=True, + logger=True, + sync_dist=not is_train, + ) + + self.log( + f"{stage}/base_loss", + base_loss, + on_step=is_train, + on_epoch=not is_train, + prog_bar=False, + logger=True, + sync_dist=not is_train, + ) + + self.log( + f"{stage}/semantic_loss", + semantic_loss, + on_step=is_train, + on_epoch=not is_train, + prog_bar=False, + logger=True, + sync_dist=not is_train, + ) + + # Top-5 accuracy + accuracy = self.get_accuracy(codebook_logits, codebook_labels) + self.log( + f"{stage}/top_5_accuracy", + accuracy, + on_step=is_train, + on_epoch=not is_train, + prog_bar=True, + logger=True, + sync_dist=not is_train, + ) + + return loss + + def get_accuracy(self, logits, labels): + mask = (labels != -100) & (labels != CODEBOOK_PAD_TOKEN_ID) + if mask.sum() == 0: + return torch.tensor(0.0, device=logits.device) + + _, indices = logits.topk(5, dim=-1) + correct = indices.eq(labels.unsqueeze(-1)) + correct[~mask] = 0 + correct = correct.sum() + accuracy = correct / mask.sum() + + return accuracy + + def training_step(self, batch, batch_idx): + return self._step(batch, batch_idx, "train") + + def validation_step(self, batch, batch_idx): + return self._step(batch, batch_idx, "val") diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/llama.py b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/llama.py new file mode 100644 index 0000000000..4eef92b0ba --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/llama.py @@ -0,0 +1,779 @@ +import json +import math +from collections import OrderedDict +from dataclasses import dataclass +from pathlib import Path +from typing import Optional + +import torch +import torch.nn as nn +from einops import rearrange +from loguru import logger +from torch import Tensor +from torch.nn import functional as F +from torch.nn.attention import SDPBackend, sdpa_kernel +from torch.utils.checkpoint import checkpoint +from transformers import AutoTokenizer + +from fish_speech.conversation import SEMANTIC_TOKEN +from fish_speech.utils import RankedLogger + +from .lora import LoraConfig, setup_lora + +log = RankedLogger(__name__, rank_zero_only=True) + + +def find_multiple(n: int, k: int) -> int: + if n % k == 0: + return n + return n + k - (n % k) + + +@dataclass +class BaseModelArgs: + model_type: str = "base" + + vocab_size: int = 32000 + n_layer: int = 32 + n_head: int = 32 + dim: int = 4096 + intermediate_size: int = None + n_local_heads: int = -1 + head_dim: int = 64 + rope_base: float = 10000 + norm_eps: float = 1e-5 + max_seq_len: int = 2048 + dropout: float = 0.0 + tie_word_embeddings: bool = True + attention_qkv_bias: bool = False + + # Codebook configs + codebook_size: int = 160 + num_codebooks: int = 4 + + # Gradient checkpointing + use_gradient_checkpointing: bool = True + + # Initialize the model + initializer_range: float = 0.02 + + def __post_init__(self): + if self.n_local_heads == -1: + self.n_local_heads = self.n_head + if self.intermediate_size is None: + hidden_dim = 4 * self.dim + n_hidden = int(2 * hidden_dim / 3) + self.intermediate_size = find_multiple(n_hidden, 256) + self.head_dim = self.dim // self.n_head + + @staticmethod + def from_pretrained(path: str): + path = Path(path) + + if path.is_dir(): + path = path / "config.json" + + with open(path, "r", encoding="utf-8") as f: + data = json.load(f) + + match data["model_type"]: + case "naive": + cls = NaiveModelArgs + case "dual_ar": + cls = DualARModelArgs + case _: + raise ValueError(f"Unknown model type: {data['model_type']}") + + return cls(**data) + + def save(self, path: str): + with open(path, "w") as f: + json.dump(self.__dict__, f, indent=4, sort_keys=True, ensure_ascii=False) + + +@dataclass +class NaiveModelArgs(BaseModelArgs): + model_type: str = "naive" + + +@dataclass +class DualARModelArgs(BaseModelArgs): + model_type: str = "dual_ar" + n_fast_layer: int = 4 + + +class KVCache(nn.Module): + def __init__( + self, max_batch_size, max_seq_len, n_heads, head_dim, dtype=torch.bfloat16 + ): + super().__init__() + cache_shape = (max_batch_size, n_heads, max_seq_len, head_dim) + self.register_buffer("k_cache", torch.zeros(cache_shape, dtype=dtype)) + self.register_buffer("v_cache", torch.zeros(cache_shape, dtype=dtype)) + + def update(self, input_pos, k_val, v_val): + # input_pos: [S], k_val: [B, H, S, D] + assert input_pos.shape[0] == k_val.shape[2] + + k_out = self.k_cache + v_out = self.v_cache + k_out[:, :, input_pos] = k_val + v_out[:, :, input_pos] = v_val + + return k_out, v_out + + +@dataclass +class TransformerForwardResult: + token_logits: Tensor + codebook_logits: Tensor + + +@dataclass +class BaseTransformerForwardResult: + logits: Tensor + hidden_states: Tensor + + +class BaseTransformer(nn.Module): + def __init__( + self, config: BaseModelArgs, tokenizer: AutoTokenizer, init_weights: bool = True + ) -> None: + super().__init__() + self.config = config + self.tokenizer = tokenizer + + self.semantic_token_id = tokenizer.convert_tokens_to_ids(SEMANTIC_TOKEN) + + # Slow transformer + self.embeddings = nn.Embedding( + config.vocab_size, + config.dim, + ) + self.codebook_embeddings = nn.Embedding( + config.codebook_size * config.num_codebooks, + config.dim, + ) + self.layers = nn.ModuleList( + TransformerBlock(config, use_sdpa=True) for _ in range(config.n_layer) + ) + self.norm = RMSNorm(config.dim, eps=config.norm_eps) + + if self.config.tie_word_embeddings is False: + self.output = nn.Linear( + config.dim, + config.vocab_size, + bias=False, + ) + + self.register_buffer( + "freqs_cis", + precompute_freqs_cis( + config.max_seq_len, + config.dim // config.n_head, + config.rope_base, + ), + persistent=False, + ) + self.register_buffer( + "causal_mask", + torch.tril( + torch.ones( + config.max_seq_len, + config.max_seq_len, + dtype=torch.bool, + ) + ), + persistent=False, + ) + + # For kv cache + self.max_batch_size = -1 + self.max_seq_len = -1 + + if init_weights: + self.apply(self._init_weights) + + def setup_caches( + self, max_batch_size: int, max_seq_len: int, dtype: torch.dtype = torch.bfloat16 + ): + if self.max_seq_len >= max_seq_len and self.max_batch_size >= max_batch_size: + return + + head_dim = self.config.dim // self.config.n_head + max_seq_len = find_multiple(max_seq_len, 8) + self.max_seq_len = max_seq_len + self.max_batch_size = max_batch_size + + for b in self.layers: + b.attention.kv_cache = KVCache( + max_batch_size, + max_seq_len, + self.config.n_local_heads, + head_dim, + dtype=dtype, + ) + + def embed(self, x: Tensor) -> Tensor: + vocab_embeds = [self.embeddings(x[:, 0])] + for i in range(self.config.num_codebooks): + emb = self.codebook_embeddings(x[:, i + 1] + i * self.config.codebook_size) + emb[x[:, 0] != self.semantic_token_id] = 0 + vocab_embeds.append(emb) + + x = torch.stack(vocab_embeds, dim=3) + x = x.sum(dim=3) + + return x + + def forward( + self, + inp: Tensor, + key_padding_mask: Optional[Tensor] = None, + ) -> BaseTransformerForwardResult: + seq_len = inp.size(2) + + # Here we want to merge the embeddings of the codebooks + x = self.embed(inp) + + freqs_cis = self.freqs_cis[:seq_len] + + # Not that the causal mask here follows the definition of scaled_dot_product_attention + # That is, FALSE means masked out + # To maintain consistency, key_padding_mask use TRUE to mask out + mask = None + if key_padding_mask is not None: + mask = self.causal_mask[None, None, :seq_len, :seq_len] # (B, N, Q, K) + mask = mask & key_padding_mask[:, None, None, :].logical_not() + + for layer in self.layers: + if self.config.use_gradient_checkpointing and self.training: + x = checkpoint(layer, x, freqs_cis, mask, use_reentrant=True) + else: + x = layer(x, freqs_cis, mask) + + # We got slow_out here + slow_out = self.norm(x) + + if self.config.tie_word_embeddings: + token_logits = F.linear(slow_out, self.embeddings.weight) + else: + token_logits = self.output(slow_out) + + return BaseTransformerForwardResult( + logits=token_logits, + hidden_states=x, + ) + + def forward_generate( + self, + x: Tensor, + input_pos: Optional[Tensor] = None, + return_all: bool = False, + ) -> BaseTransformerForwardResult: + # This is used for generation, optimized for torch compile + assert ( + self.max_seq_len != -1 and self.max_batch_size != -1 + ), "Please call setup_caches before forward_generate" + + x = self.embed(x) + + mask = self.causal_mask[ + None, None, input_pos, : self.max_seq_len + ] # (B, N, Q, K) + freqs_cis = self.freqs_cis[input_pos] + + for layer in self.layers: + x = layer(x, freqs_cis, mask, input_pos=input_pos) + + # If prefill, we only calculate the logits of last token + if x.size(1) > 1 and not return_all: + x = x[:, -1:] + + # We got slow_out here + slow_out = self.norm(x) + + if self.config.tie_word_embeddings: + token_logits = F.linear(slow_out, self.embeddings.weight) + else: + token_logits = self.output(slow_out) + + return BaseTransformerForwardResult( + logits=token_logits, + hidden_states=x, + ) + + def _init_weights(self, module): + std = self.config.initializer_range + if isinstance(module, nn.Linear): + module.weight.data.normal_(mean=0.0, std=std) + if module.bias is not None: + module.bias.data.zero_() + elif isinstance(module, nn.Embedding): + module.weight.data.normal_(mean=0.0, std=std) + if module.padding_idx is not None: + module.weight.data[module.padding_idx].zero_() + + @staticmethod + def from_pretrained( + path: str, + load_weights: bool = False, + max_length: int | None = None, + lora_config: LoraConfig | None = None, + rope_base: int | None = None, + ) -> "BaseTransformer": + config = BaseModelArgs.from_pretrained(str(path)) + if max_length is not None: + config.max_seq_len = max_length + log.info(f"Override max_seq_len to {max_length}") + + if rope_base is not None: + config.rope_base = rope_base + log.info(f"Override rope_base to {rope_base}") + + match config.model_type: + case "naive": + model_cls = NaiveTransformer + case "dual_ar": + model_cls = DualARTransformer + case _: + raise ValueError(f"Unknown model type: {config.model_type}") + + tokenizer = AutoTokenizer.from_pretrained(str(path)) + log.info(f"Loading model from {path}, config: {config}") + model = model_cls(config, tokenizer=tokenizer) + + if lora_config is not None: + setup_lora(model, lora_config) + log.info(f"LoRA setup: {lora_config}") + + if load_weights is False: + log.info("Randomly initialized model") + else: + + if "int8" in str(Path(path)): + logger.info("Using int8 weight-only quantization!") + from ...tools.llama.quantize import WeightOnlyInt8QuantHandler + + simple_quantizer = WeightOnlyInt8QuantHandler(model) + model = simple_quantizer.convert_for_runtime() + + if "int4" in str(Path(path)): + logger.info("Using int4 quantization!") + path_comps = path.name.split("-") + assert path_comps[-2].startswith("g") + groupsize = int(path_comps[-2][1:]) + from ...tools.llama.quantize import WeightOnlyInt4QuantHandler + + simple_quantizer = WeightOnlyInt4QuantHandler(model, groupsize) + model = simple_quantizer.convert_for_runtime() + + weights = torch.load( + Path(path) / "model.pth", map_location="cpu", mmap=True + ) + + if "state_dict" in weights: + logger.warning( + "Using a TextToSemantic LightningModule checkpoint, " + "please make sure it is a full model, not a LoRA model." + ) + weights = weights["state_dict"] + + if next(iter(weights.keys())).startswith("model."): + logger.info( + f"Remove prefix 'model.' created by TextToSemantic LightningModule from keys" + ) + new_weights = OrderedDict() + for k, v in weights.items(): + new_weights[k.replace("model.", "")] = v + weights = new_weights + + # Verify the name and shape of parameters since strict=False in load_state_dict. + for k, v in model.named_parameters(): + if k not in weights: + logger.warning(f"No weight for {k}") + elif v.shape != weights[k].shape: + logger.warning( + f"Shape mismatch for {k}: {v.shape} vs {weights[k].shape}" + ) + + err = model.load_state_dict(weights, strict=False, assign=True) + log.info(f"Loaded weights with error: {err}") + + return model + + def save_pretrained(self, path: str, drop_lora: bool = False): + path = Path(path) + path.mkdir(parents=True, exist_ok=True) + + self.config.save(path / "config.json") + state_dict = self.state_dict() + + if drop_lora: + for key in list(state_dict.keys()): + if "lora" not in key: + continue + + state_dict.pop(key) + log.info(f"Drop LoRA parameter: {key}") + + torch.save(state_dict, path / "model.pth") + self.tokenizer.save_pretrained(path) + + +class NaiveTransformer(BaseTransformer): + def __init__(self, config: NaiveModelArgs, tokenizer: AutoTokenizer) -> None: + super().__init__(config, init_weights=False, tokenizer=tokenizer) + + self.codebook_norm = RMSNorm(config.dim, eps=config.norm_eps) + self.codebook_output = nn.Linear( + config.dim, + config.codebook_size * config.num_codebooks, + bias=False, + ) + + self.apply(self._init_weights) + + def decode(self, result: BaseTransformerForwardResult) -> TransformerForwardResult: + token_logits = result.logits + x = result.hidden_states + + # Codebook + codebook_logits = self.codebook_output(self.codebook_norm(x)) + codebook_logits = rearrange( + codebook_logits, "b n (c d) -> b n c d", c=self.config.num_codebooks + ) + + return TransformerForwardResult( + token_logits=token_logits, + codebook_logits=codebook_logits, + ) + + def forward( + self, + inp: Tensor, + key_padding_mask: Optional[Tensor] = None, + ) -> TransformerForwardResult: + result = super().forward( + inp=inp, + key_padding_mask=key_padding_mask, + ) + return self.decode(result) + + def forward_generate( + self, x: Tensor, input_pos: Optional[Tensor] = None + ) -> TransformerForwardResult: + result = super().forward_generate(x, input_pos) + return self.decode(result) + + +class DualARTransformer(BaseTransformer): + def __init__(self, config: NaiveModelArgs, tokenizer: AutoTokenizer) -> None: + super().__init__(config, init_weights=False, tokenizer=tokenizer) + + # Fast transformer + self.fast_embeddings = nn.Embedding(config.codebook_size, config.dim) + + # The equivalent bs is so large that sdpa doesn't work + self.fast_layers = nn.ModuleList( + TransformerBlock(config, use_sdpa=False) for _ in range(config.n_fast_layer) + ) + self.fast_norm = RMSNorm(config.dim, eps=config.norm_eps) + self.fast_output = nn.Linear( + config.dim, + config.codebook_size, + bias=False, + ) + + self.apply(self._init_weights) + + def setup_caches( + self, max_batch_size: int, max_seq_len: int, dtype: torch.dtype = torch.bfloat16 + ): + super().setup_caches(max_batch_size, max_seq_len, dtype) + + head_dim = self.config.dim // self.config.n_head + + # Fast transformer + # The max seq len here is the number of codebooks + for b in self.fast_layers: + b.attention.kv_cache = KVCache( + max_batch_size, + self.config.num_codebooks, + self.config.n_local_heads, + head_dim, + dtype=dtype, + ) + + def forward( + self, + inp: Tensor, + key_padding_mask: Optional[Tensor] = None, + ) -> TransformerForwardResult: + parent_result = super().forward(inp, key_padding_mask) + token_logits = parent_result.logits + x = parent_result.hidden_states + + # Fast transformer + fast_seq_len = self.config.num_codebooks + fast_mask = self.causal_mask[ + None, None, :fast_seq_len, :fast_seq_len + ] # (B, N, Q, K) + fast_freqs_cis = self.freqs_cis[:fast_seq_len] + + # Drop the last token and rotate left + codebooks = inp[:, 1:-1, 1:] + codebooks = F.pad(codebooks, (0, 1), value=0) + codebook_embeddings = self.fast_embeddings(codebooks) + x = torch.cat([x[:, None], codebook_embeddings], dim=1) + b, s = x.size(0), x.size(2) + x = rearrange(x, "b n s d -> (b s) n d") # flatten the batch and seq_len + + # Remove padded part + codebooks = rearrange(codebooks, "b n s -> (b s) n") + codebook_mask = (codebooks == 0).all(dim=-1) + + if torch.all(codebook_mask): + # If all codebooks are padded, we keep first 8 to make sure the model runs + codebook_mask[:8] = False + + x_bs, x_len = x.size(0), x.size(1) + x = x[~codebook_mask] + + for layer in self.fast_layers: + if self.config.use_gradient_checkpointing and self.training: + x = checkpoint(layer, x, fast_freqs_cis, fast_mask, use_reentrant=True) + else: + x = layer(x, fast_freqs_cis, fast_mask) + + # unflatten the batch and num_codebooks + fast_out = self.fast_norm(x) + codebook_logits = self.fast_output(fast_out) + + # Re-pad the codebook_logits + buffer = torch.zeros( + x_bs, + x_len, + codebook_logits.size(-1), + device=codebook_logits.device, + dtype=codebook_logits.dtype, + ) + buffer[~codebook_mask] = codebook_logits + codebook_logits = buffer + + assert codebook_logits.shape[1] == self.config.num_codebooks + codebook_logits = rearrange( + codebook_logits, + "(b s) n d -> b s n d", + b=b, + s=s, + n=self.config.num_codebooks, + ) + + return TransformerForwardResult( + token_logits=token_logits, + codebook_logits=codebook_logits, + ) + + def forward_generate_fast( + self, x: Tensor, input_pos: Optional[Tensor] = None + ) -> Tensor: + # Fast transformer + x = x.view(1, 1, -1) + + fast_mask = self.causal_mask[ + None, None, input_pos, : self.config.num_codebooks + ] # (B, N, Q, K) + fast_freqs_cis = self.freqs_cis[input_pos] + + for layer in self.fast_layers: + x = layer(x, fast_freqs_cis, fast_mask, input_pos=input_pos) + + # unflatten the batch and num_codebooks + fast_out = self.fast_norm(x) # only take the last token + codebook_logits = self.fast_output(fast_out) + + return codebook_logits + + +class TransformerBlock(nn.Module): + def __init__(self, config: BaseModelArgs, use_sdpa: bool = True) -> None: + super().__init__() + self.attention = Attention(config, use_sdpa=use_sdpa) + self.feed_forward = FeedForward(config) + self.ffn_norm = RMSNorm(config.dim, config.norm_eps) + self.attention_norm = RMSNorm(config.dim, config.norm_eps) + + def forward( + self, x: Tensor, freqs_cis: Tensor, mask: Tensor, input_pos: Tensor = None + ) -> Tensor: + h = x + self.attention(self.attention_norm(x), freqs_cis, mask, input_pos) + out = h + self.feed_forward(self.ffn_norm(h)) + return out + + +class Attention(nn.Module): + def __init__(self, config: BaseModelArgs, use_sdpa: bool = True): + super().__init__() + assert config.dim % config.n_head == 0 + + total_head_dim = (config.n_head + 2 * config.n_local_heads) * config.head_dim + # key, query, value projections for all heads, but in a batch + self.wqkv = nn.Linear( + config.dim, total_head_dim, bias=config.attention_qkv_bias + ) + self.wo = nn.Linear(config.dim, config.dim, bias=False) + self.kv_cache = None + + self.dropout = config.dropout + self.n_head = config.n_head + self.head_dim = config.head_dim + self.n_local_heads = config.n_local_heads + self.dim = config.dim + self.use_sdpa = use_sdpa + self._register_load_state_dict_pre_hook(self.load_hook) + + def load_hook(self, state_dict, prefix, *args): + if prefix + "wq.weight" in state_dict: + wq = state_dict.pop(prefix + "wq.weight") + wk = state_dict.pop(prefix + "wk.weight") + wv = state_dict.pop(prefix + "wv.weight") + state_dict[prefix + "wqkv.weight"] = torch.cat([wq, wk, wv]) + + def forward( + self, + x: Tensor, + freqs_cis: Tensor, + mask: Tensor, + input_pos: Optional[Tensor] = None, + ) -> Tensor: + bsz, seqlen, _ = x.shape + + kv_size = self.n_local_heads * self.head_dim + q, k, v = self.wqkv(x).split([self.dim, kv_size, kv_size], dim=-1) + + q = q.view(bsz, seqlen, self.n_head, self.head_dim) + k = k.view(bsz, seqlen, self.n_local_heads, self.head_dim) + v = v.view(bsz, seqlen, self.n_local_heads, self.head_dim) + + q = apply_rotary_emb(q, freqs_cis) + k = apply_rotary_emb(k, freqs_cis) + + q, k, v = map(lambda x: x.transpose(1, 2), (q, k, v)) + + if self.kv_cache is not None: + k, v = self.kv_cache.update(input_pos, k, v) + + k = k.repeat_interleave(self.n_head // self.n_local_heads, dim=1) + v = v.repeat_interleave(self.n_head // self.n_local_heads, dim=1) + + if self.use_sdpa: + if mask is None: + with sdpa_kernel(SDPBackend.FLASH_ATTENTION): + y = F.scaled_dot_product_attention( + q, + k, + v, + dropout_p=self.dropout if self.training else 0.0, + is_causal=True, + # No third party attn_mask here to use flash_attention + ) + else: + y = F.scaled_dot_product_attention( + q, + k, + v, + attn_mask=mask, + dropout_p=self.dropout if self.training else 0.0, + ) + else: + y = self.eq_scaled_dot_product_attention( + q, + k, + v, + attn_mask=mask, + dropout_p=self.dropout if self.training else 0.0, + ) + + y = y.transpose(1, 2).contiguous().view(bsz, seqlen, self.dim) + + return self.wo(y) + + def eq_scaled_dot_product_attention( + self, + query, + key, + value, + attn_mask=None, + dropout_p=0.0, + ) -> torch.Tensor: + # This is a standard scaled dot product attention + # It's low efficient, but it doesn't raise cuda error + + L, S = query.size(-2), key.size(-2) + scale_factor = 1 / math.sqrt(query.size(-1)) + attn_bias = torch.zeros(1, 1, L, S, dtype=query.dtype, device=query.device) + + if attn_mask is not None: + if attn_mask.dtype == torch.bool: + attn_bias.masked_fill_(attn_mask.logical_not(), float("-inf")) + else: + attn_bias += attn_mask + + attn_weight = query @ key.transpose(-2, -1) * scale_factor + attn_weight += attn_bias + attn_weight = torch.softmax(attn_weight, dim=-1) + attn_weight = torch.dropout(attn_weight, dropout_p, train=True) + + return attn_weight @ value + + +class FeedForward(nn.Module): + def __init__(self, config: BaseModelArgs) -> None: + super().__init__() + self.w1 = nn.Linear(config.dim, config.intermediate_size, bias=False) + self.w3 = nn.Linear(config.dim, config.intermediate_size, bias=False) + self.w2 = nn.Linear(config.intermediate_size, config.dim, bias=False) + + def forward(self, x: Tensor) -> Tensor: + return self.w2(F.silu(self.w1(x)) * self.w3(x)) + + +class RMSNorm(nn.Module): + def __init__(self, dim: int, eps: float = 1e-5): + super().__init__() + self.eps = eps + self.weight = nn.Parameter(torch.ones(dim)) + + def _norm(self, x): + return x * torch.rsqrt(torch.mean(x * x, dim=-1, keepdim=True) + self.eps) + + def forward(self, x: Tensor) -> Tensor: + output = self._norm(x.float()).type_as(x) + return output * self.weight + + +def precompute_freqs_cis(seq_len: int, n_elem: int, base: int = 10000) -> Tensor: + freqs = 1.0 / ( + base ** (torch.arange(0, n_elem, 2)[: (n_elem // 2)].float() / n_elem) + ) + t = torch.arange(seq_len, device=freqs.device) + freqs = torch.outer(t, freqs) + freqs_cis = torch.polar(torch.ones_like(freqs), freqs) + cache = torch.stack([freqs_cis.real, freqs_cis.imag], dim=-1) + return cache.to(dtype=torch.bfloat16) + + +def apply_rotary_emb(x: Tensor, freqs_cis: Tensor) -> Tensor: + xshaped = x.float().reshape(*x.shape[:-1], -1, 2) + freqs_cis = freqs_cis.view(1, xshaped.size(1), 1, xshaped.size(3), 2) + x_out2 = torch.stack( + [ + xshaped[..., 0] * freqs_cis[..., 0] - xshaped[..., 1] * freqs_cis[..., 1], + xshaped[..., 1] * freqs_cis[..., 0] + xshaped[..., 0] * freqs_cis[..., 1], + ], + -1, + ) + + x_out2 = x_out2.flatten(3) + return x_out2.type_as(x) diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lora.py b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lora.py new file mode 100644 index 0000000000..647ca6fccc --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/text2semantic/lora.py @@ -0,0 +1,92 @@ +from dataclasses import dataclass + +import loralib as lora + + +@dataclass +class LoraConfig: + r: int + lora_alpha: float + lora_dropout: float = 0.0 + + +def setup_lora(model, lora_config): + # Replace the embedding layer with a LoRA layer + model.embeddings = lora.Embedding( + num_embeddings=model.embeddings.num_embeddings, + embedding_dim=model.embeddings.embedding_dim, + padding_idx=model.embeddings.padding_idx, + r=lora_config.r, + lora_alpha=lora_config.lora_alpha, + ) + + model.codebook_embeddings = lora.Embedding( + num_embeddings=model.codebook_embeddings.num_embeddings, + embedding_dim=model.codebook_embeddings.embedding_dim, + padding_idx=model.codebook_embeddings.padding_idx, + r=lora_config.r, + lora_alpha=lora_config.lora_alpha, + ) + + # Replace output layer with a LoRA layer + linears = [(model, "output")] + + # Replace all linear layers with LoRA layers + for layer in model.layers: + linears.extend([(layer.attention, "wqkv"), (layer.attention, "wo")]) + linears.extend( + [ + (layer.feed_forward, "w1"), + (layer.feed_forward, "w2"), + (layer.feed_forward, "w3"), + ] + ) + + if hasattr(model, "fast_layers"): + model.fast_embeddings = lora.Embedding( + num_embeddings=model.fast_embeddings.num_embeddings, + embedding_dim=model.fast_embeddings.embedding_dim, + padding_idx=model.fast_embeddings.padding_idx, + r=lora_config.r, + lora_alpha=lora_config.lora_alpha, + ) + + # Dual-AR model + linears.append((model, "fast_output")) + + for layer in model.fast_layers: + linears.extend([(layer.attention, "wqkv"), (layer.attention, "wo")]) + linears.extend( + [ + (layer.feed_forward, "w1"), + (layer.feed_forward, "w2"), + (layer.feed_forward, "w3"), + ] + ) + + for module, layer in linears: + updated_linear = lora.Linear( + in_features=getattr(module, layer).in_features, + out_features=getattr(module, layer).out_features, + bias=getattr(module, layer).bias, + r=lora_config.r, + lora_alpha=lora_config.lora_alpha, + lora_dropout=lora_config.lora_dropout, + ) + setattr(module, layer, updated_linear) + + # Mark only the LoRA layers as trainable + lora.mark_only_lora_as_trainable(model, bias="none") + + +def get_merged_state_dict(model): + # This line will merge the state dict of the model and the LoRA parameters + model.eval() + + # Then we need to remove the LoRA parameters from the state dict + state_dict = model.state_dict() + for name in list(state_dict.keys()): + if "lora" in name: + state_dict.pop(name) + + return state_dict diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/__init__.py new file mode 100644 index 0000000000..401c6df468 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/__init__.py @@ -0,0 +1,3 @@ +from .lit_module import VQGAN + +__all__ = ["VQGAN"] diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/lit_module.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/lit_module.py new file mode 100644 index 0000000000..d5fa2ccabb --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/lit_module.py @@ -0,0 +1,442 @@ +import itertools +import math +from typing import Any, Callable + +import lightning as L +import torch +import torch.nn.functional as F +# import wandb +from lightning.pytorch.loggers import TensorBoardLogger, WandbLogger +from matplotlib import pyplot as plt +from torch import nn + +from fish_speech.models.vqgan.modules.discriminator import Discriminator +from fish_speech.models.vqgan.modules.wavenet import WaveNet +from fish_speech.models.vqgan.utils import avg_with_mask, plot_mel, sequence_mask + + +class VQGAN(L.LightningModule): + def __init__( + self, + optimizer: Callable, + lr_scheduler: Callable, + encoder: WaveNet, + quantizer: nn.Module, + decoder: WaveNet, + discriminator: Discriminator, + vocoder: nn.Module, + encode_mel_transform: nn.Module, + gt_mel_transform: nn.Module, + weight_adv: float = 1.0, + weight_vq: float = 1.0, + weight_mel: float = 1.0, + sampling_rate: int = 44100, + freeze_encoder: bool = False, + ): + super().__init__() + + # Model parameters + self.optimizer_builder = optimizer + self.lr_scheduler_builder = lr_scheduler + + # Modules + self.encoder = encoder + self.quantizer = quantizer + self.decoder = decoder + self.vocoder = vocoder + self.discriminator = discriminator + self.encode_mel_transform = encode_mel_transform + self.gt_mel_transform = gt_mel_transform + + # A simple linear layer to project quality to condition channels + self.quality_projection = nn.Linear(1, 768) + + # Freeze vocoder + for param in self.vocoder.parameters(): + param.requires_grad = False + + # Loss weights + self.weight_adv = weight_adv + self.weight_vq = weight_vq + self.weight_mel = weight_mel + + # Other parameters + self.sampling_rate = sampling_rate + + # Disable strict loading + self.strict_loading = False + + # If encoder is frozen + if freeze_encoder: + for param in self.encoder.parameters(): + param.requires_grad = False + + for param in self.quantizer.parameters(): + param.requires_grad = False + + self.automatic_optimization = False + + def on_save_checkpoint(self, checkpoint): + # Do not save vocoder + state_dict = checkpoint["state_dict"] + for name in list(state_dict.keys()): + if "vocoder" in name: + state_dict.pop(name) + + def configure_optimizers(self): + optimizer_generator = self.optimizer_builder( + itertools.chain( + self.encoder.parameters(), + self.quantizer.parameters(), + self.decoder.parameters(), + self.quality_projection.parameters(), + ) + ) + optimizer_discriminator = self.optimizer_builder( + self.discriminator.parameters() + ) + + lr_scheduler_generator = self.lr_scheduler_builder(optimizer_generator) + lr_scheduler_discriminator = self.lr_scheduler_builder(optimizer_discriminator) + + return ( + { + "optimizer": optimizer_generator, + "lr_scheduler": { + "scheduler": lr_scheduler_generator, + "interval": "step", + "name": "optimizer/generator", + }, + }, + { + "optimizer": optimizer_discriminator, + "lr_scheduler": { + "scheduler": lr_scheduler_discriminator, + "interval": "step", + "name": "optimizer/discriminator", + }, + }, + ) + + def training_step(self, batch, batch_idx): + optim_g, optim_d = self.optimizers() + + audios, audio_lengths = batch["audios"], batch["audio_lengths"] + + audios = audios.float() + audios = audios[:, None, :] + + with torch.no_grad(): + encoded_mels = self.encode_mel_transform(audios) + gt_mels = self.gt_mel_transform(audios) + quality = ((gt_mels.mean(-1) > -8).sum(-1) - 90) / 10 + quality = quality.unsqueeze(-1) + + mel_lengths = audio_lengths // self.gt_mel_transform.hop_length + mel_masks = sequence_mask(mel_lengths, gt_mels.shape[2]) + mel_masks_float_conv = mel_masks[:, None, :].float() + gt_mels = gt_mels * mel_masks_float_conv + encoded_mels = encoded_mels * mel_masks_float_conv + + # Encode + encoded_features = self.encoder(encoded_mels) * mel_masks_float_conv + + # Quantize + vq_result = self.quantizer(encoded_features) + loss_vq = getattr("vq_result", "loss", 0.0) + vq_recon_features = vq_result.z * mel_masks_float_conv + vq_recon_features = ( + vq_recon_features + self.quality_projection(quality)[:, :, None] + ) + + # VQ Decode + gen_mel = ( + self.decoder( + torch.randn_like(vq_recon_features) * mel_masks_float_conv, + condition=vq_recon_features, + ) + * mel_masks_float_conv + ) + + # Discriminator + real_logits = self.discriminator(gt_mels) + fake_logits = self.discriminator(gen_mel.detach()) + d_mask = F.interpolate( + mel_masks_float_conv, size=(real_logits.shape[2],), mode="nearest" + ) + + loss_real = avg_with_mask((real_logits - 1) ** 2, d_mask) + loss_fake = avg_with_mask(fake_logits**2, d_mask) + + loss_d = loss_real + loss_fake + + self.log( + "train/discriminator/loss", + loss_d, + on_step=True, + on_epoch=False, + prog_bar=True, + logger=True, + ) + + # Discriminator backward + optim_d.zero_grad() + self.manual_backward(loss_d) + self.clip_gradients( + optim_d, gradient_clip_val=1000.0, gradient_clip_algorithm="norm" + ) + optim_d.step() + + # Mel Loss, applying l1, using a weighted sum + mel_distance = ( + gen_mel - gt_mels + ).abs() # * 0.5 + self.ssim(gen_mel, gt_mels) * 0.5 + loss_mel_low_freq = avg_with_mask(mel_distance[:, :40, :], mel_masks_float_conv) + loss_mel_mid_freq = avg_with_mask( + mel_distance[:, 40:70, :], mel_masks_float_conv + ) + loss_mel_high_freq = avg_with_mask( + mel_distance[:, 70:, :], mel_masks_float_conv + ) + loss_mel = ( + loss_mel_low_freq * 0.6 + loss_mel_mid_freq * 0.3 + loss_mel_high_freq * 0.1 + ) + + # Adversarial Loss + fake_logits = self.discriminator(gen_mel) + loss_adv = avg_with_mask((fake_logits - 1) ** 2, d_mask) + + # Total loss + loss = ( + self.weight_vq * loss_vq + + self.weight_mel * loss_mel + + self.weight_adv * loss_adv + ) + + # Log losses + self.log( + "train/generator/loss", + loss, + on_step=True, + on_epoch=False, + prog_bar=True, + logger=True, + ) + self.log( + "train/generator/loss_vq", + loss_vq, + on_step=True, + on_epoch=False, + prog_bar=False, + logger=True, + ) + self.log( + "train/generator/loss_mel", + loss_mel, + on_step=True, + on_epoch=False, + prog_bar=False, + logger=True, + ) + self.log( + "train/generator/loss_adv", + loss_adv, + on_step=True, + on_epoch=False, + prog_bar=False, + logger=True, + ) + + # Generator backward + optim_g.zero_grad() + self.manual_backward(loss) + self.clip_gradients( + optim_g, gradient_clip_val=1000.0, gradient_clip_algorithm="norm" + ) + optim_g.step() + + scheduler_g, scheduler_d = self.lr_schedulers() + scheduler_g.step() + scheduler_d.step() + + def validation_step(self, batch: Any, batch_idx: int): + audios, audio_lengths = batch["audios"], batch["audio_lengths"] + + audios = audios.float() + audios = audios[:, None, :] + + encoded_mels = self.encode_mel_transform(audios) + gt_mels = self.gt_mel_transform(audios) + + mel_lengths = audio_lengths // self.gt_mel_transform.hop_length + mel_masks = sequence_mask(mel_lengths, gt_mels.shape[2]) + mel_masks_float_conv = mel_masks[:, None, :].float() + gt_mels = gt_mels * mel_masks_float_conv + encoded_mels = encoded_mels * mel_masks_float_conv + + # Encode + encoded_features = self.encoder(encoded_mels) * mel_masks_float_conv + + # Quantize + vq_recon_features = self.quantizer(encoded_features).z * mel_masks_float_conv + vq_recon_features = ( + vq_recon_features + + self.quality_projection( + torch.ones( + vq_recon_features.shape[0], 1, device=vq_recon_features.device + ) + * 2 + )[:, :, None] + ) + + # VQ Decode + gen_aux_mels = ( + self.decoder( + torch.randn_like(vq_recon_features) * mel_masks_float_conv, + condition=vq_recon_features, + ) + * mel_masks_float_conv + ) + loss_mel = avg_with_mask((gen_aux_mels - gt_mels).abs(), mel_masks_float_conv) + + self.log( + "val/loss_mel", + loss_mel, + on_step=False, + on_epoch=True, + prog_bar=False, + logger=True, + sync_dist=True, + ) + + recon_audios = self.vocoder(gt_mels) + gen_aux_audios = self.vocoder(gen_aux_mels) + + # only log the first batch + if batch_idx != 0: + return + + for idx, ( + gt_mel, + gen_aux_mel, + audio, + gen_aux_audio, + recon_audio, + audio_len, + ) in enumerate( + zip( + gt_mels, + gen_aux_mels, + audios.cpu().float(), + gen_aux_audios.cpu().float(), + recon_audios.cpu().float(), + audio_lengths, + ) + ): + if idx > 4: + break + + mel_len = audio_len // self.gt_mel_transform.hop_length + + image_mels = plot_mel( + [ + gt_mel[:, :mel_len], + gen_aux_mel[:, :mel_len], + ], + [ + "Ground-Truth", + "Auxiliary", + ], + ) + + if isinstance(self.logger, WandbLogger): + self.logger.experiment.log( + { + "reconstruction_mel": wandb.Image(image_mels, caption="mels"), + "wavs": [ + wandb.Audio( + audio[0, :audio_len], + sample_rate=self.sampling_rate, + caption="gt", + ), + wandb.Audio( + gen_aux_audio[0, :audio_len], + sample_rate=self.sampling_rate, + caption="aux", + ), + wandb.Audio( + recon_audio[0, :audio_len], + sample_rate=self.sampling_rate, + caption="recon", + ), + ], + }, + ) + + if isinstance(self.logger, TensorBoardLogger): + self.logger.experiment.add_figure( + f"sample-{idx}/mels", + image_mels, + global_step=self.global_step, + ) + self.logger.experiment.add_audio( + f"sample-{idx}/wavs/gt", + audio[0, :audio_len], + self.global_step, + sample_rate=self.sampling_rate, + ) + self.logger.experiment.add_audio( + f"sample-{idx}/wavs/gen", + gen_aux_audio[0, :audio_len], + self.global_step, + sample_rate=self.sampling_rate, + ) + self.logger.experiment.add_audio( + f"sample-{idx}/wavs/recon", + recon_audio[0, :audio_len], + self.global_step, + sample_rate=self.sampling_rate, + ) + + plt.close(image_mels) + + def encode(self, audios, audio_lengths): + audios = audios.float() + + mels = self.encode_mel_transform(audios) + mel_lengths = audio_lengths // self.encode_mel_transform.hop_length + mel_masks = sequence_mask(mel_lengths, mels.shape[2]) + mel_masks_float_conv = mel_masks[:, None, :].float() + mels = mels * mel_masks_float_conv + + # Encode + encoded_features = self.encoder(mels) * mel_masks_float_conv + feature_lengths = mel_lengths // math.prod(self.quantizer.downsample_factor) + + return self.quantizer.encode(encoded_features), feature_lengths + + def decode(self, indices, feature_lengths, return_audios=False): + factor = math.prod(self.quantizer.downsample_factor) + mel_masks = sequence_mask(feature_lengths * factor, indices.shape[2] * factor) + mel_masks_float_conv = mel_masks[:, None, :].float() + + z = self.quantizer.decode(indices) * mel_masks_float_conv + z = ( + z + + self.quality_projection(torch.ones(z.shape[0], 1, device=z.device) * 2)[ + :, :, None + ] + ) + + gen_mel = ( + self.decoder( + torch.randn_like(z) * mel_masks_float_conv, + condition=z, + ) + * mel_masks_float_conv + ) + + if return_audios: + return self.vocoder(gen_mel) + + return gen_mel diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/discriminator.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/discriminator.py new file mode 100644 index 0000000000..69c7df4103 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/discriminator.py @@ -0,0 +1,44 @@ +import torch +from torch import nn +from torch.nn.utils.parametrizations import weight_norm + + +class Discriminator(nn.Module): + def __init__(self): + super().__init__() + + blocks = [] + convs = [ + (1, 64, (3, 9), 1, (1, 4)), + (64, 128, (3, 9), (1, 2), (1, 4)), + (128, 256, (3, 9), (1, 2), (1, 4)), + (256, 512, (3, 9), (1, 2), (1, 4)), + (512, 1024, (3, 3), 1, (1, 1)), + (1024, 1, (3, 3), 1, (1, 1)), + ] + + for idx, (in_channels, out_channels, kernel_size, stride, padding) in enumerate( + convs + ): + blocks.append( + weight_norm( + nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding) + ) + ) + + if idx != len(convs) - 1: + blocks.append(nn.SiLU(inplace=True)) + + self.blocks = nn.Sequential(*blocks) + + def forward(self, x): + return self.blocks(x[:, None])[:, 0] + + +if __name__ == "__main__": + model = Discriminator() + print(sum(p.numel() for p in model.parameters()) / 1_000_000) + x = torch.randn(1, 128, 1024) + y = model(x) + print(y.shape) + print(y) diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/firefly.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/firefly.py new file mode 100644 index 0000000000..4ca0ff5882 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/firefly.py @@ -0,0 +1,625 @@ +# A inference only version of the FireflyGAN model + +import math +from functools import partial +from math import prod +from typing import Callable + +import numpy as np +import torch +import torch.nn.functional as F +from torch import nn +from torch.nn import Conv1d +from torch.nn.utils.parametrizations import weight_norm +from torch.nn.utils.parametrize import remove_parametrizations +from torch.utils.checkpoint import checkpoint + +from fish_speech.models.vqgan.utils import sequence_mask + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) + + +def get_padding(kernel_size, dilation=1): + return (kernel_size * dilation - dilation) // 2 + + +class ResBlock1(torch.nn.Module): + def __init__(self, channels, kernel_size=3, dilation=(1, 3, 5)): + super().__init__() + + self.convs1 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[2], + padding=get_padding(kernel_size, dilation[2]), + ) + ), + ] + ) + self.convs1.apply(init_weights) + + self.convs2 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + ] + ) + self.convs2.apply(init_weights) + + def forward(self, x): + for c1, c2 in zip(self.convs1, self.convs2): + xt = F.silu(x) + xt = c1(xt) + xt = F.silu(xt) + xt = c2(xt) + x = xt + x + return x + + def remove_parametrizations(self): + for conv in self.convs1: + remove_parametrizations(conv, tensor_name="weight") + for conv in self.convs2: + remove_parametrizations(conv, tensor_name="weight") + + +class ParralelBlock(nn.Module): + def __init__( + self, + channels: int, + kernel_sizes: tuple[int] = (3, 7, 11), + dilation_sizes: tuple[tuple[int]] = ((1, 3, 5), (1, 3, 5), (1, 3, 5)), + ): + super().__init__() + + assert len(kernel_sizes) == len(dilation_sizes) + + self.blocks = nn.ModuleList() + for k, d in zip(kernel_sizes, dilation_sizes): + self.blocks.append(ResBlock1(channels, k, d)) + + def forward(self, x): + return torch.stack([block(x) for block in self.blocks], dim=0).mean(dim=0) + + def remove_parametrizations(self): + for block in self.blocks: + block.remove_parametrizations() + + +class HiFiGANGenerator(nn.Module): + def __init__( + self, + *, + hop_length: int = 512, + upsample_rates: tuple[int] = (8, 8, 2, 2, 2), + upsample_kernel_sizes: tuple[int] = (16, 16, 8, 2, 2), + resblock_kernel_sizes: tuple[int] = (3, 7, 11), + resblock_dilation_sizes: tuple[tuple[int]] = ((1, 3, 5), (1, 3, 5), (1, 3, 5)), + num_mels: int = 128, + upsample_initial_channel: int = 512, + use_template: bool = True, + pre_conv_kernel_size: int = 7, + post_conv_kernel_size: int = 7, + post_activation: Callable = partial(nn.SiLU, inplace=True), + ): + super().__init__() + + assert ( + prod(upsample_rates) == hop_length + ), f"hop_length must be {prod(upsample_rates)}" + + self.conv_pre = weight_norm( + nn.Conv1d( + num_mels, + upsample_initial_channel, + pre_conv_kernel_size, + 1, + padding=get_padding(pre_conv_kernel_size), + ) + ) + + self.num_upsamples = len(upsample_rates) + self.num_kernels = len(resblock_kernel_sizes) + + self.noise_convs = nn.ModuleList() + self.use_template = use_template + self.ups = nn.ModuleList() + + for i, (u, k) in enumerate(zip(upsample_rates, upsample_kernel_sizes)): + c_cur = upsample_initial_channel // (2 ** (i + 1)) + self.ups.append( + weight_norm( + nn.ConvTranspose1d( + upsample_initial_channel // (2**i), + upsample_initial_channel // (2 ** (i + 1)), + k, + u, + padding=(k - u) // 2, + ) + ) + ) + + if not use_template: + continue + + if i + 1 < len(upsample_rates): + stride_f0 = np.prod(upsample_rates[i + 1 :]) + self.noise_convs.append( + Conv1d( + 1, + c_cur, + kernel_size=stride_f0 * 2, + stride=stride_f0, + padding=stride_f0 // 2, + ) + ) + else: + self.noise_convs.append(Conv1d(1, c_cur, kernel_size=1)) + + self.resblocks = nn.ModuleList() + for i in range(len(self.ups)): + ch = upsample_initial_channel // (2 ** (i + 1)) + self.resblocks.append( + ParralelBlock(ch, resblock_kernel_sizes, resblock_dilation_sizes) + ) + + self.activation_post = post_activation() + self.conv_post = weight_norm( + nn.Conv1d( + ch, + 1, + post_conv_kernel_size, + 1, + padding=get_padding(post_conv_kernel_size), + ) + ) + self.ups.apply(init_weights) + self.conv_post.apply(init_weights) + + def forward(self, x, template=None): + x = self.conv_pre(x) + + for i in range(self.num_upsamples): + x = F.silu(x, inplace=True) + x = self.ups[i](x) + + if self.use_template: + x = x + self.noise_convs[i](template) + + if self.training: + x = checkpoint( + self.resblocks[i], + x, + use_reentrant=False, + ) + else: + x = self.resblocks[i](x) + + x = self.activation_post(x) + x = self.conv_post(x) + x = torch.tanh(x) + + return x + + def remove_parametrizations(self): + for up in self.ups: + remove_parametrizations(up, tensor_name="weight") + for block in self.resblocks: + block.remove_parametrizations() + remove_parametrizations(self.conv_pre, tensor_name="weight") + remove_parametrizations(self.conv_post, tensor_name="weight") + + +# DropPath copied from timm library +def drop_path( + x, drop_prob: float = 0.0, training: bool = False, scale_by_keep: bool = True +): + """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks). + + This is the same as the DropConnect impl I created for EfficientNet, etc networks, however, + the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper... + See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for + changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use + 'survival rate' as the argument. + + """ # noqa: E501 + + if drop_prob == 0.0 or not training: + return x + keep_prob = 1 - drop_prob + shape = (x.shape[0],) + (1,) * ( + x.ndim - 1 + ) # work with diff dim tensors, not just 2D ConvNets + random_tensor = x.new_empty(shape).bernoulli_(keep_prob) + if keep_prob > 0.0 and scale_by_keep: + random_tensor.div_(keep_prob) + return x * random_tensor + + +class DropPath(nn.Module): + """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).""" # noqa: E501 + + def __init__(self, drop_prob: float = 0.0, scale_by_keep: bool = True): + super(DropPath, self).__init__() + self.drop_prob = drop_prob + self.scale_by_keep = scale_by_keep + + def forward(self, x): + return drop_path(x, self.drop_prob, self.training, self.scale_by_keep) + + def extra_repr(self): + return f"drop_prob={round(self.drop_prob,3):0.3f}" + + +class LayerNorm(nn.Module): + r"""LayerNorm that supports two data formats: channels_last (default) or channels_first. + The ordering of the dimensions in the inputs. channels_last corresponds to inputs with + shape (batch_size, height, width, channels) while channels_first corresponds to inputs + with shape (batch_size, channels, height, width). + """ # noqa: E501 + + def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"): + super().__init__() + self.weight = nn.Parameter(torch.ones(normalized_shape)) + self.bias = nn.Parameter(torch.zeros(normalized_shape)) + self.eps = eps + self.data_format = data_format + if self.data_format not in ["channels_last", "channels_first"]: + raise NotImplementedError + self.normalized_shape = (normalized_shape,) + + def forward(self, x): + if self.data_format == "channels_last": + return F.layer_norm( + x, self.normalized_shape, self.weight, self.bias, self.eps + ) + elif self.data_format == "channels_first": + u = x.mean(1, keepdim=True) + s = (x - u).pow(2).mean(1, keepdim=True) + x = (x - u) / torch.sqrt(s + self.eps) + x = self.weight[:, None] * x + self.bias[:, None] + return x + + +# ConvNeXt Block copied from https://github.com/fishaudio/fish-diffusion/blob/main/fish_diffusion/modules/convnext.py +class ConvNeXtBlock(nn.Module): + r"""ConvNeXt Block. There are two equivalent implementations: + (1) DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W) + (2) DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back + We use (2) as we find it slightly faster in PyTorch + + Args: + dim (int): Number of input channels. + drop_path (float): Stochastic depth rate. Default: 0.0 + layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6. + mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4.0. + kernel_size (int): Kernel size for depthwise conv. Default: 7. + dilation (int): Dilation for depthwise conv. Default: 1. + """ # noqa: E501 + + def __init__( + self, + dim: int, + drop_path: float = 0.0, + layer_scale_init_value: float = 1e-6, + mlp_ratio: float = 4.0, + kernel_size: int = 7, + dilation: int = 1, + ): + super().__init__() + + self.dwconv = nn.Conv1d( + dim, + dim, + kernel_size=kernel_size, + padding=int(dilation * (kernel_size - 1) / 2), + groups=dim, + ) # depthwise conv + self.norm = LayerNorm(dim, eps=1e-6) + self.pwconv1 = nn.Linear( + dim, int(mlp_ratio * dim) + ) # pointwise/1x1 convs, implemented with linear layers + self.act = nn.GELU() + self.pwconv2 = nn.Linear(int(mlp_ratio * dim), dim) + self.gamma = ( + nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True) + if layer_scale_init_value > 0 + else None + ) + self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + + def forward(self, x, apply_residual: bool = True): + input = x + + x = self.dwconv(x) + x = x.permute(0, 2, 1) # (N, C, L) -> (N, L, C) + x = self.norm(x) + x = self.pwconv1(x) + x = self.act(x) + x = self.pwconv2(x) + + if self.gamma is not None: + x = self.gamma * x + + x = x.permute(0, 2, 1) # (N, L, C) -> (N, C, L) + x = self.drop_path(x) + + if apply_residual: + x = input + x + + return x + + +class ConvNeXtEncoder(nn.Module): + def __init__( + self, + input_channels: int = 3, + depths: list[int] = [3, 3, 9, 3], + dims: list[int] = [96, 192, 384, 768], + drop_path_rate: float = 0.0, + layer_scale_init_value: float = 1e-6, + kernel_size: int = 7, + ): + super().__init__() + assert len(depths) == len(dims) + + self.downsample_layers = nn.ModuleList() + stem = nn.Sequential( + nn.Conv1d( + input_channels, + dims[0], + kernel_size=kernel_size, + padding=kernel_size // 2, + padding_mode="zeros", + ), + LayerNorm(dims[0], eps=1e-6, data_format="channels_first"), + ) + self.downsample_layers.append(stem) + + for i in range(len(depths) - 1): + mid_layer = nn.Sequential( + LayerNorm(dims[i], eps=1e-6, data_format="channels_first"), + nn.Conv1d(dims[i], dims[i + 1], kernel_size=1), + ) + self.downsample_layers.append(mid_layer) + + self.stages = nn.ModuleList() + dp_rates = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] + + cur = 0 + for i in range(len(depths)): + stage = nn.Sequential( + *[ + ConvNeXtBlock( + dim=dims[i], + drop_path=dp_rates[cur + j], + layer_scale_init_value=layer_scale_init_value, + kernel_size=kernel_size, + ) + for j in range(depths[i]) + ] + ) + self.stages.append(stage) + cur += depths[i] + + self.norm = LayerNorm(dims[-1], eps=1e-6, data_format="channels_first") + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, (nn.Conv1d, nn.Linear)): + nn.init.trunc_normal_(m.weight, std=0.02) + nn.init.constant_(m.bias, 0) + + def forward( + self, + x: torch.Tensor, + ) -> torch.Tensor: + for i in range(len(self.downsample_layers)): + x = self.downsample_layers[i](x) + x = self.stages[i](x) + + return self.norm(x) + + +class FireflyArchitecture(nn.Module): + def __init__( + self, + backbone: nn.Module, + head: nn.Module, + quantizer: nn.Module, + spec_transform: nn.Module, + ): + super().__init__() + + self.backbone = backbone + self.head = head + self.quantizer = quantizer + self.spec_transform = spec_transform + + def forward(self, x: torch.Tensor, template=None, mask=None) -> torch.Tensor: + if self.spec_transform is not None: + x = self.spec_transform(x) + + x = self.backbone(x) + if mask is not None: + x = x * mask + + if self.quantizer is not None: + vq_result = self.quantizer(x) + x = vq_result.z + + if mask is not None: + x = x * mask + + x = self.head(x, template=template) + + if x.ndim == 2: + x = x[:, None, :] + + if self.quantizer is not None: + return x, vq_result + + return x + + def encode(self, audios, audio_lengths): + audios = audios.float() + + mels = self.spec_transform(audios) + mel_lengths = audio_lengths // self.spec_transform.hop_length + mel_masks = sequence_mask(mel_lengths, mels.shape[2]) + mel_masks_float_conv = mel_masks[:, None, :].float() + mels = mels * mel_masks_float_conv + + # Encode + encoded_features = self.backbone(mels) * mel_masks_float_conv + feature_lengths = mel_lengths // math.prod(self.quantizer.downsample_factor) + + return self.quantizer.encode(encoded_features), feature_lengths + + def decode(self, indices, feature_lengths) -> torch.Tensor: + factor = math.prod(self.quantizer.downsample_factor) + mel_masks = sequence_mask(feature_lengths * factor, indices.shape[2] * factor) + mel_masks_float_conv = mel_masks[:, None, :].float() + + audio_masks = sequence_mask( + feature_lengths * factor * self.spec_transform.hop_length, + indices.shape[2] * factor * self.spec_transform.hop_length, + ) + audio_masks_float_conv = audio_masks[:, None, :].float() + + z = self.quantizer.decode(indices) * mel_masks_float_conv + x = self.head(z) * audio_masks_float_conv + + return x + + def remove_parametrizations(self): + if hasattr(self.backbone, "remove_parametrizations"): + self.backbone.remove_parametrizations() + + if hasattr(self.head, "remove_parametrizations"): + self.head.remove_parametrizations() + + @property + def device(self): + return next(self.parameters()).device + + +class FireflyBase(nn.Module): + def __init__(self, ckpt_path: str = None, pretrained: bool = True): + super().__init__() + + self.backbone = ConvNeXtEncoder( + input_channels=128, + depths=[3, 3, 9, 3], + dims=[128, 256, 384, 512], + drop_path_rate=0.2, + kernel_size=7, + ) + + self.head = HiFiGANGenerator( + hop_length=512, + upsample_rates=[8, 8, 2, 2, 2], + upsample_kernel_sizes=[16, 16, 4, 4, 4], + resblock_kernel_sizes=[3, 7, 11], + resblock_dilation_sizes=[[1, 3, 5], [1, 3, 5], [1, 3, 5]], + num_mels=512, + upsample_initial_channel=512, + use_template=False, + pre_conv_kernel_size=13, + post_conv_kernel_size=13, + ) + + if ckpt_path is not None: + state_dict = torch.load(ckpt_path, map_location="cpu") + elif pretrained: + state_dict = torch.hub.load_state_dict_from_url( + "https://github.com/fishaudio/vocoder/releases/download/1.0.0/firefly-gan-base-generator.ckpt", + map_location="cpu", + model_dir="checkpoints", + ) + + if "state_dict" in state_dict: + state_dict = state_dict["state_dict"] + + if any("generator." in k for k in state_dict): + state_dict = { + k.replace("generator.", ""): v + for k, v in state_dict.items() + if "generator." in k + } + + self.load_state_dict(state_dict, strict=True) + self.head.remove_parametrizations() + + @torch.no_grad() + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.backbone(x) + x = self.head(x) + if x.ndim == 2: + x = x[:, None, :] + return x + + +if __name__ == "__main__": + model = FireflyBase() + model.eval() + x = torch.randn(1, 128, 128) + with torch.no_grad(): + y = model(x) + print(y.shape) diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/fsq.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/fsq.py new file mode 100644 index 0000000000..c837d6aee5 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/fsq.py @@ -0,0 +1,139 @@ +from dataclasses import dataclass + +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange +from vector_quantize_pytorch import GroupedResidualFSQ + +from .firefly import ConvNeXtBlock + + +@dataclass +class FSQResult: + z: torch.Tensor + codes: torch.Tensor + latents: torch.Tensor + + +class DownsampleFiniteScalarQuantize(nn.Module): + def __init__( + self, + input_dim: int = 512, + n_codebooks: int = 1, + n_groups: int = 1, + levels: tuple[int] = (8, 5, 5, 5), # Approximate 2**10 + downsample_factor: tuple[int] = (2, 2), + downsample_dims: tuple[int] | None = None, + ): + super().__init__() + + if downsample_dims is None: + downsample_dims = [input_dim for _ in range(len(downsample_factor))] + + all_dims = (input_dim,) + tuple(downsample_dims) + + self.residual_fsq = GroupedResidualFSQ( + dim=all_dims[-1], + levels=levels, + num_quantizers=n_codebooks, + groups=n_groups, + ) + + self.downsample_factor = downsample_factor + self.downsample_dims = downsample_dims + + self.downsample = nn.Sequential( + *[ + nn.Sequential( + nn.Conv1d( + all_dims[idx], + all_dims[idx + 1], + kernel_size=factor, + stride=factor, + ), + ConvNeXtBlock(dim=all_dims[idx + 1]), + ) + for idx, factor in enumerate(downsample_factor) + ] + ) + + self.upsample = nn.Sequential( + *[ + nn.Sequential( + nn.ConvTranspose1d( + all_dims[idx + 1], + all_dims[idx], + kernel_size=factor, + stride=factor, + ), + ConvNeXtBlock(dim=all_dims[idx]), + ) + for idx, factor in reversed(list(enumerate(downsample_factor))) + ] + ) + + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, (nn.Conv1d, nn.Linear)): + nn.init.trunc_normal_(m.weight, std=0.02) + nn.init.constant_(m.bias, 0) + + def forward(self, z) -> FSQResult: + original_shape = z.shape + z = self.downsample(z) + quantized, indices = self.residual_fsq(z.mT) + result = FSQResult( + z=quantized.mT, + codes=indices.mT, + latents=z, + ) + result.z = self.upsample(result.z) + + # Pad or crop z to match original shape + diff = original_shape[-1] - result.z.shape[-1] + left = diff // 2 + right = diff - left + + if diff > 0: + result.z = F.pad(result.z, (left, right)) + elif diff < 0: + result.z = result.z[..., left:-right] + + return result + + def encode(self, z): + z = self.downsample(z) + _, indices = self.residual_fsq(z.mT) + indices = rearrange(indices, "g b l r -> b (g r) l") + return indices + + def decode(self, indices: torch.Tensor): + indices = rearrange(indices, "b (g r) l -> g b l r", g=self.residual_fsq.groups) + z_q = self.residual_fsq.get_output_from_indices(indices) + z_q = self.upsample(z_q.mT) + return z_q + + # def from_latents(self, latents: torch.Tensor): + # z_q, z_p, codes = super().from_latents(latents) + # z_q = self.upsample(z_q) + # return z_q, z_p, codes + + +if __name__ == "__main__": + rvq = DownsampleFiniteScalarQuantize( + n_codebooks=1, + downsample_factor=(2, 2), + ) + x = torch.randn(16, 512, 80) + + result = rvq(x) + print(rvq) + print(result.latents.shape, result.codes.shape, result.z.shape) + + # y = rvq.from_codes(result.codes) + # print(y[0].shape) + + # y = rvq.from_latents(result.latents) + # print(y[0].shape) diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/reference.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/reference.py new file mode 100644 index 0000000000..0d9c8c8359 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/reference.py @@ -0,0 +1,115 @@ +from typing import Optional + +import torch +import torch.nn.functional as F +from torch import nn + +from fish_speech.utils import autocast_exclude_mps + +from .wavenet import WaveNet + + +class ReferenceEncoder(WaveNet): + def __init__( + self, + input_channels: Optional[int] = None, + output_channels: Optional[int] = None, + residual_channels: int = 512, + residual_layers: int = 20, + dilation_cycle: Optional[int] = 4, + num_heads: int = 8, + latent_len: int = 4, + ): + super().__init__( + input_channels=input_channels, + residual_channels=residual_channels, + residual_layers=residual_layers, + dilation_cycle=dilation_cycle, + ) + + self.head_dim = residual_channels // num_heads + self.num_heads = num_heads + + self.latent_len = latent_len + self.latent = nn.Parameter(torch.zeros(1, self.latent_len, residual_channels)) + + self.q = nn.Linear(residual_channels, residual_channels, bias=True) + self.kv = nn.Linear(residual_channels, residual_channels * 2, bias=True) + self.q_norm = nn.LayerNorm(self.head_dim) + self.k_norm = nn.LayerNorm(self.head_dim) + self.proj = nn.Linear(residual_channels, residual_channels) + self.proj_drop = nn.Dropout(0.1) + + self.norm = nn.LayerNorm(residual_channels) + self.mlp = nn.Sequential( + nn.Linear(residual_channels, residual_channels * 4), + nn.SiLU(), + nn.Linear(residual_channels * 4, residual_channels), + ) + self.output_projection_attn = nn.Linear(residual_channels, output_channels) + + torch.nn.init.trunc_normal_(self.latent, std=0.02) + self.apply(self.init_weights) + + def init_weights(self, m): + if isinstance(m, nn.Linear): + torch.nn.init.trunc_normal_(m.weight, std=0.02) + if m.bias is not None: + torch.nn.init.constant_(m.bias, 0) + + def forward(self, x, attn_mask=None): + x = super().forward(x).mT + B, N, C = x.shape + + # Calculate mask + if attn_mask is not None: + assert attn_mask.shape == (B, N) and attn_mask.dtype == torch.bool + + attn_mask = attn_mask[:, None, None, :].expand( + B, self.num_heads, self.latent_len, N + ) + + q_latent = self.latent.expand(B, -1, -1) + q = ( + self.q(q_latent) + .reshape(B, self.latent_len, self.num_heads, self.head_dim) + .transpose(1, 2) + ) + + kv = ( + self.kv(x) + .reshape(B, N, 2, self.num_heads, self.head_dim) + .permute(2, 0, 3, 1, 4) + ) + k, v = kv.unbind(0) + + q, k = self.q_norm(q), self.k_norm(k) + x = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask) + + x = x.transpose(1, 2).reshape(B, self.latent_len, C) + x = self.proj(x) + x = self.proj_drop(x) + + x = x + self.mlp(self.norm(x)) + x = self.output_projection_attn(x) + x = x.mean(1) + + return x + + +if __name__ == "__main__": + with autocast_exclude_mps(device_type="cpu", dtype=torch.bfloat16): + model = ReferenceEncoder( + input_channels=128, + output_channels=64, + residual_channels=384, + residual_layers=20, + dilation_cycle=4, + num_heads=8, + ) + x = torch.randn(4, 128, 64) + mask = torch.ones(4, 64, dtype=torch.bool) + y = model(x, mask) + print(y.shape) + loss = F.mse_loss(y, torch.randn(4, 64)) + loss.backward() diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/wavenet.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/wavenet.py new file mode 100644 index 0000000000..e7cc011c3e --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/modules/wavenet.py @@ -0,0 +1,225 @@ +import math +from typing import Optional + +import torch +import torch.nn.functional as F +from torch import nn + + +class Mish(nn.Module): + def forward(self, x): + return x * torch.tanh(F.softplus(x)) + + +class DiffusionEmbedding(nn.Module): + """Diffusion Step Embedding""" + + def __init__(self, d_denoiser): + super(DiffusionEmbedding, self).__init__() + self.dim = d_denoiser + + def forward(self, x): + device = x.device + half_dim = self.dim // 2 + emb = math.log(10000) / (half_dim - 1) + emb = torch.exp(torch.arange(half_dim, device=device) * -emb) + emb = x[:, None] * emb[None, :] + emb = torch.cat((emb.sin(), emb.cos()), dim=-1) + return emb + + +class LinearNorm(nn.Module): + """LinearNorm Projection""" + + def __init__(self, in_features, out_features, bias=False): + super(LinearNorm, self).__init__() + self.linear = nn.Linear(in_features, out_features, bias) + + nn.init.xavier_uniform_(self.linear.weight) + if bias: + nn.init.constant_(self.linear.bias, 0.0) + + def forward(self, x): + x = self.linear(x) + return x + + +class ConvNorm(nn.Module): + """1D Convolution""" + + def __init__( + self, + in_channels, + out_channels, + kernel_size=1, + stride=1, + padding=None, + dilation=1, + bias=True, + w_init_gain="linear", + ): + super(ConvNorm, self).__init__() + + if padding is None: + assert kernel_size % 2 == 1 + padding = int(dilation * (kernel_size - 1) / 2) + + self.conv = nn.Conv1d( + in_channels, + out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias, + ) + nn.init.kaiming_normal_(self.conv.weight) + + def forward(self, signal): + conv_signal = self.conv(signal) + + return conv_signal + + +class ResidualBlock(nn.Module): + """Residual Block""" + + def __init__( + self, + residual_channels, + use_linear_bias=False, + dilation=1, + condition_channels=None, + ): + super(ResidualBlock, self).__init__() + self.conv_layer = ConvNorm( + residual_channels, + 2 * residual_channels, + kernel_size=3, + stride=1, + padding=dilation, + dilation=dilation, + ) + + if condition_channels is not None: + self.diffusion_projection = LinearNorm( + residual_channels, residual_channels, use_linear_bias + ) + self.condition_projection = ConvNorm( + condition_channels, 2 * residual_channels, kernel_size=1 + ) + + self.output_projection = ConvNorm( + residual_channels, 2 * residual_channels, kernel_size=1 + ) + + def forward(self, x, condition=None, diffusion_step=None): + y = x + + if diffusion_step is not None: + diffusion_step = self.diffusion_projection(diffusion_step).unsqueeze(-1) + y = y + diffusion_step + + y = self.conv_layer(y) + + if condition is not None: + condition = self.condition_projection(condition) + y = y + condition + + gate, filter = torch.chunk(y, 2, dim=1) + y = torch.sigmoid(gate) * torch.tanh(filter) + + y = self.output_projection(y) + residual, skip = torch.chunk(y, 2, dim=1) + + return (x + residual) / math.sqrt(2.0), skip + + +class WaveNet(nn.Module): + def __init__( + self, + input_channels: Optional[int] = None, + output_channels: Optional[int] = None, + residual_channels: int = 512, + residual_layers: int = 20, + dilation_cycle: Optional[int] = 4, + is_diffusion: bool = False, + condition_channels: Optional[int] = None, + ): + super().__init__() + + # Input projection + self.input_projection = None + if input_channels is not None and input_channels != residual_channels: + self.input_projection = ConvNorm( + input_channels, residual_channels, kernel_size=1 + ) + + if input_channels is None: + input_channels = residual_channels + + self.input_channels = input_channels + + # Residual layers + self.residual_layers = nn.ModuleList( + [ + ResidualBlock( + residual_channels=residual_channels, + use_linear_bias=False, + dilation=2 ** (i % dilation_cycle) if dilation_cycle else 1, + condition_channels=condition_channels, + ) + for i in range(residual_layers) + ] + ) + + # Skip projection + self.skip_projection = ConvNorm( + residual_channels, residual_channels, kernel_size=1 + ) + + # Output projection + self.output_projection = None + if output_channels is not None and output_channels != residual_channels: + self.output_projection = ConvNorm( + residual_channels, output_channels, kernel_size=1 + ) + + if is_diffusion: + self.diffusion_embedding = DiffusionEmbedding(residual_channels) + self.mlp = nn.Sequential( + LinearNorm(residual_channels, residual_channels * 4, False), + Mish(), + LinearNorm(residual_channels * 4, residual_channels, False), + ) + + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, (nn.Conv1d, nn.Linear)): + nn.init.trunc_normal_(m.weight, std=0.02) + if getattr(m, "bias", None) is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x, t=None, condition=None): + if self.input_projection is not None: + x = self.input_projection(x) + x = F.silu(x) + + if t is not None: + t = self.diffusion_embedding(t) + t = self.mlp(t) + + skip = [] + for layer in self.residual_layers: + x, skip_connection = layer(x, condition, t) + skip.append(skip_connection) + + x = torch.sum(torch.stack(skip), dim=0) / math.sqrt(len(self.residual_layers)) + x = self.skip_projection(x) + + if self.output_projection is not None: + x = F.silu(x) + x = self.output_projection(x) + + return x diff --git a/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/utils.py b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/utils.py new file mode 100644 index 0000000000..b90c131d21 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/models/vqgan/utils.py @@ -0,0 +1,94 @@ +import matplotlib +import torch +from matplotlib import pyplot as plt + +matplotlib.use("Agg") + + +def convert_pad_shape(pad_shape): + l = pad_shape[::-1] + pad_shape = [item for sublist in l for item in sublist] + return pad_shape + + +def sequence_mask(length, max_length=None): + if max_length is None: + max_length = length.max() + x = torch.arange(max_length, dtype=length.dtype, device=length.device) + return x.unsqueeze(0) < length.unsqueeze(1) + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) + + +def get_padding(kernel_size, dilation=1): + return int((kernel_size * dilation - dilation) / 2) + + +def plot_mel(data, titles=None): + fig, axes = plt.subplots(len(data), 1, squeeze=False) + + if titles is None: + titles = [None for i in range(len(data))] + + plt.tight_layout() + + for i in range(len(data)): + mel = data[i] + + if isinstance(mel, torch.Tensor): + mel = mel.float().detach().cpu().numpy() + + axes[i][0].imshow(mel, origin="lower") + axes[i][0].set_aspect(2.5, adjustable="box") + axes[i][0].set_ylim(0, mel.shape[0]) + axes[i][0].set_title(titles[i], fontsize="medium") + axes[i][0].tick_params(labelsize="x-small", left=False, labelleft=False) + axes[i][0].set_anchor("W") + + return fig + + +def slice_segments(x, ids_str, segment_size=4): + ret = torch.zeros_like(x[:, :, :segment_size]) + for i in range(x.size(0)): + idx_str = ids_str[i] + idx_end = idx_str + segment_size + ret[i] = x[i, :, idx_str:idx_end] + + return ret + + +def rand_slice_segments(x, x_lengths=None, segment_size=4): + b, d, t = x.size() + if x_lengths is None: + x_lengths = t + ids_str_max = torch.clamp(x_lengths - segment_size + 1, min=0) + ids_str = (torch.rand([b], device=x.device) * ids_str_max).to(dtype=torch.long) + ret = slice_segments(x, ids_str, segment_size) + return ret, ids_str + + +@torch.jit.script +def fused_add_tanh_sigmoid_multiply(in_act, n_channels): + n_channels_int = n_channels[0] + t_act = torch.tanh(in_act[:, :n_channels_int, :]) + s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) + acts = t_act * s_act + + return acts + + +def avg_with_mask(x, mask): + assert mask.dtype == torch.float, "Mask should be float" + + if mask.ndim == 2: + mask = mask.unsqueeze(1) + + if mask.shape[1] == 1: + mask = mask.expand_as(x) + + return (x * mask).sum() / mask.sum() diff --git a/xinference/thirdparty/fish_speech/fish_speech/scheduler.py b/xinference/thirdparty/fish_speech/fish_speech/scheduler.py new file mode 100644 index 0000000000..43bed6a221 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/scheduler.py @@ -0,0 +1,40 @@ +import math + + +def get_cosine_schedule_with_warmup_lr_lambda( + current_step: int, + *, + num_warmup_steps: int | float, + num_training_steps: int, + num_cycles: float = 0.5, + final_lr_ratio: float = 0.0, +): + if 0 < num_warmup_steps < 1: # float mode + num_warmup_steps = int(num_warmup_steps * num_training_steps) + + if current_step < num_warmup_steps: + return float(current_step) / float(max(1, num_warmup_steps)) + + progress = float(current_step - num_warmup_steps) / float( + max(1, num_training_steps - num_warmup_steps) + ) + + return max( + final_lr_ratio, + 0.5 * (1.0 + math.cos(math.pi * float(num_cycles) * 2.0 * progress)), + ) + + +def get_constant_schedule_with_warmup_lr_lambda( + current_step: int, + *, + num_warmup_steps: int | float, + num_training_steps: int | None = None, +): + if 0 < num_warmup_steps < 1: # float mode + num_warmup_steps = int(num_warmup_steps * num_training_steps) + + if current_step < num_warmup_steps: + return float(current_step) / float(max(1, num_warmup_steps)) + + return 1.0 diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/text/__init__.py new file mode 100644 index 0000000000..d740bd8eed --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/__init__.py @@ -0,0 +1,4 @@ +from .clean import clean_text +from .spliter import split_text + +__all__ = ["clean_text", "split_text"] diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/.gitignore b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/.gitignore new file mode 100644 index 0000000000..75ea58fa4a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/.gitignore @@ -0,0 +1,114 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# JetBrains PyCharm +.idea + +# Customize +references +url.txt + +# Git +.git diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/README.md b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/README.md new file mode 100644 index 0000000000..8450a2c6c0 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/README.md @@ -0,0 +1,36 @@ +# This account is no longer in use, see [Atomicoo](https://github.com/atomicoo) for my latest works. + +# Chn Text Norm + +this is a repository for chinese text normalization (no longer maintained). + +## Quick Start ## + +### Git Clone Repo ### + +git clone this repo to the root directory of your project which need to use it. + + cd /path/to/proj + git clone https://github.com/Joee1995/chn-text-norm.git + +after that, your doc tree should be: +``` +proj # root of your project +|--- chn_text_norm # this chn-text-norm tool + |--- text.py + |--- ... +|--- text_normalize.py # your text normalization code +|--- ... +``` + +### How to Use ? ### + + # text_normalize.py + from chn_text_norm.text import * + + raw_text = 'your raw text' + text = Text(raw_text=raw_text).normalize() + +### How to add quantums ### + +打开test.py,然后你就知道怎么做了。 diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_class.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_class.py new file mode 100644 index 0000000000..58d8f8eb7f --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_class.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- +"""基本类 +中文字符类 +中文数字/数位类 +中文数字类 +中文数位类 +中文数字系统类 +中文数学符号类 +*中文其他符号类 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-02" + +from fish_speech.text.chn_text_norm.basic_constant import NUMBERING_TYPES + + +class ChineseChar(object): + """ + 中文字符 + 每个字符对应简体和繁体, + e.g. 简体 = '负', 繁体 = '負' + 转换时可转换为简体或繁体 + """ + + def __init__(self, simplified, traditional): + self.simplified = simplified + self.traditional = traditional + self.__repr__ = self.__str__ + + def __str__(self): + return self.simplified or self.traditional or None + + def __repr__(self): + return self.__str__() + + +class ChineseNumberUnit(ChineseChar): + """ + 中文数字/数位字符 + 每个字符除繁简体外还有一个额外的大写字符 + e.g. '陆' 和 '陸' + """ + + def __init__(self, power, simplified, traditional, big_s, big_t): + super(ChineseNumberUnit, self).__init__(simplified, traditional) + self.power = power + self.big_s = big_s + self.big_t = big_t + + def __str__(self): + return "10^{}".format(self.power) + + @classmethod + def create(cls, index, value, numbering_type=NUMBERING_TYPES[1], small_unit=False): + + if small_unit: + return ChineseNumberUnit( + power=index + 1, + simplified=value[0], + traditional=value[1], + big_s=value[1], + big_t=value[1], + ) + elif numbering_type == NUMBERING_TYPES[0]: + return ChineseNumberUnit( + power=index + 8, + simplified=value[0], + traditional=value[1], + big_s=value[0], + big_t=value[1], + ) + elif numbering_type == NUMBERING_TYPES[1]: + return ChineseNumberUnit( + power=(index + 2) * 4, + simplified=value[0], + traditional=value[1], + big_s=value[0], + big_t=value[1], + ) + elif numbering_type == NUMBERING_TYPES[2]: + return ChineseNumberUnit( + power=pow(2, index + 3), + simplified=value[0], + traditional=value[1], + big_s=value[0], + big_t=value[1], + ) + else: + raise ValueError( + "Counting type should be in {0} ({1} provided).".format( + NUMBERING_TYPES, numbering_type + ) + ) + + +class ChineseNumberDigit(ChineseChar): + """ + 中文数字字符 + """ + + def __init__( + self, value, simplified, traditional, big_s, big_t, alt_s=None, alt_t=None + ): + super(ChineseNumberDigit, self).__init__(simplified, traditional) + self.value = value + self.big_s = big_s + self.big_t = big_t + self.alt_s = alt_s + self.alt_t = alt_t + + def __str__(self): + return str(self.value) + + @classmethod + def create(cls, i, v): + return ChineseNumberDigit(i, v[0], v[1], v[2], v[3]) + + +class ChineseMath(ChineseChar): + """ + 中文数位字符 + """ + + def __init__(self, simplified, traditional, symbol, expression=None): + super(ChineseMath, self).__init__(simplified, traditional) + self.symbol = symbol + self.expression = expression + self.big_s = simplified + self.big_t = traditional + + +CC, CNU, CND, CM = ChineseChar, ChineseNumberUnit, ChineseNumberDigit, ChineseMath + + +class NumberSystem(object): + """ + 中文数字系统 + """ + + pass + + +class MathSymbol(object): + """ + 用于中文数字系统的数学符号 (繁/简体), e.g. + positive = ['正', '正'] + negative = ['负', '負'] + point = ['点', '點'] + """ + + def __init__(self, positive, negative, point): + self.positive = positive + self.negative = negative + self.point = point + + def __iter__(self): + for v in self.__dict__.values(): + yield v + + +# class OtherSymbol(object): +# """ +# 其他符号 +# """ +# +# def __init__(self, sil): +# self.sil = sil +# +# def __iter__(self): +# for v in self.__dict__.values(): +# yield v diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_constant.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_constant.py new file mode 100644 index 0000000000..9a65991b9a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_constant.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +"""基本常量 +中文数字/数位/符号字符常量 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-02" + +CHINESE_DIGIS = "零一二三四五六七八九" +BIG_CHINESE_DIGIS_SIMPLIFIED = "零壹贰叁肆伍陆柒捌玖" +BIG_CHINESE_DIGIS_TRADITIONAL = "零壹貳參肆伍陸柒捌玖" +SMALLER_BIG_CHINESE_UNITS_SIMPLIFIED = "十百千万" +SMALLER_BIG_CHINESE_UNITS_TRADITIONAL = "拾佰仟萬" +LARGER_CHINESE_NUMERING_UNITS_SIMPLIFIED = "亿兆京垓秭穰沟涧正载" +LARGER_CHINESE_NUMERING_UNITS_TRADITIONAL = "億兆京垓秭穰溝澗正載" +SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED = "十百千万" +SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL = "拾佰仟萬" + +ZERO_ALT = "〇" +ONE_ALT = "幺" +TWO_ALTS = ["两", "兩"] + +POSITIVE = ["正", "正"] +NEGATIVE = ["负", "負"] +POINT = ["点", "點"] +# PLUS = [u'加', u'加'] +# SIL = [u'杠', u'槓'] + +# 中文数字系统类型 +NUMBERING_TYPES = ["low", "mid", "high"] diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_util.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_util.py new file mode 100644 index 0000000000..dbf6130be8 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/basic_util.py @@ -0,0 +1,342 @@ +# -*- coding: utf-8 -*- +"""基本方法 +创建中文数字系统 方法 +中文字符串 <=> 数字串 方法 +数字串 <=> 中文字符串 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-02" + +from fish_speech.text.chn_text_norm.basic_class import * +from fish_speech.text.chn_text_norm.basic_constant import * + + +def create_system(numbering_type=NUMBERING_TYPES[1]): + """ + 根据数字系统类型返回创建相应的数字系统,默认为 mid + NUMBERING_TYPES = ['low', 'mid', 'high']: 中文数字系统类型 + low: '兆' = '亿' * '十' = $10^{9}$, '京' = '兆' * '十', etc. + mid: '兆' = '亿' * '万' = $10^{12}$, '京' = '兆' * '万', etc. + high: '兆' = '亿' * '亿' = $10^{16}$, '京' = '兆' * '兆', etc. + 返回对应的数字系统 + """ + + # chinese number units of '亿' and larger + all_larger_units = zip( + LARGER_CHINESE_NUMERING_UNITS_SIMPLIFIED, + LARGER_CHINESE_NUMERING_UNITS_TRADITIONAL, + ) + larger_units = [ + CNU.create(i, v, numbering_type, False) for i, v in enumerate(all_larger_units) + ] + # chinese number units of '十, 百, 千, 万' + all_smaller_units = zip( + SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED, + SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL, + ) + smaller_units = [ + CNU.create(i, v, small_unit=True) for i, v in enumerate(all_smaller_units) + ] + # digis + chinese_digis = zip( + CHINESE_DIGIS, + CHINESE_DIGIS, + BIG_CHINESE_DIGIS_SIMPLIFIED, + BIG_CHINESE_DIGIS_TRADITIONAL, + ) + digits = [CND.create(i, v) for i, v in enumerate(chinese_digis)] + digits[0].alt_s, digits[0].alt_t = ZERO_ALT, ZERO_ALT + digits[1].alt_s, digits[1].alt_t = ONE_ALT, ONE_ALT + digits[2].alt_s, digits[2].alt_t = TWO_ALTS[0], TWO_ALTS[1] + + # symbols + positive_cn = CM(POSITIVE[0], POSITIVE[1], "+", lambda x: x) + negative_cn = CM(NEGATIVE[0], NEGATIVE[1], "-", lambda x: -x) + point_cn = CM(POINT[0], POINT[1], ".", lambda x, y: float(str(x) + "." + str(y))) + # sil_cn = CM(SIL[0], SIL[1], '-', lambda x, y: float(str(x) + '-' + str(y))) + system = NumberSystem() + system.units = smaller_units + larger_units + system.digits = digits + system.math = MathSymbol(positive_cn, negative_cn, point_cn) + # system.symbols = OtherSymbol(sil_cn) + return system + + +def chn2num(chinese_string, numbering_type=NUMBERING_TYPES[1]): + + def get_symbol(char, system): + for u in system.units: + if char in [u.traditional, u.simplified, u.big_s, u.big_t]: + return u + for d in system.digits: + if char in [ + d.traditional, + d.simplified, + d.big_s, + d.big_t, + d.alt_s, + d.alt_t, + ]: + return d + for m in system.math: + if char in [m.traditional, m.simplified]: + return m + + def string2symbols(chinese_string, system): + int_string, dec_string = chinese_string, "" + for p in [system.math.point.simplified, system.math.point.traditional]: + if p in chinese_string: + int_string, dec_string = chinese_string.split(p) + break + return [get_symbol(c, system) for c in int_string], [ + get_symbol(c, system) for c in dec_string + ] + + def correct_symbols(integer_symbols, system): + """ + 一百八 to 一百八十 + 一亿一千三百万 to 一亿 一千万 三百万 + """ + + if integer_symbols and isinstance(integer_symbols[0], CNU): + if integer_symbols[0].power == 1: + integer_symbols = [system.digits[1]] + integer_symbols + + if len(integer_symbols) > 1: + if isinstance(integer_symbols[-1], CND) and isinstance( + integer_symbols[-2], CNU + ): + integer_symbols.append( + CNU(integer_symbols[-2].power - 1, None, None, None, None) + ) + + result = [] + unit_count = 0 + for s in integer_symbols: + if isinstance(s, CND): + result.append(s) + unit_count = 0 + elif isinstance(s, CNU): + current_unit = CNU(s.power, None, None, None, None) + unit_count += 1 + + if unit_count == 1: + result.append(current_unit) + elif unit_count > 1: + for i in range(len(result)): + if ( + isinstance(result[-i - 1], CNU) + and result[-i - 1].power < current_unit.power + ): + result[-i - 1] = CNU( + result[-i - 1].power + current_unit.power, + None, + None, + None, + None, + ) + return result + + def compute_value(integer_symbols): + """ + Compute the value. + When current unit is larger than previous unit, current unit * all previous units will be used as all previous units. + e.g. '两千万' = 2000 * 10000 not 2000 + 10000 + """ + value = [0] + last_power = 0 + for s in integer_symbols: + if isinstance(s, CND): + value[-1] = s.value + elif isinstance(s, CNU): + value[-1] *= pow(10, s.power) + if s.power > last_power: + value[:-1] = list(map(lambda v: v * pow(10, s.power), value[:-1])) + last_power = s.power + value.append(0) + return sum(value) + + system = create_system(numbering_type) + int_part, dec_part = string2symbols(chinese_string, system) + int_part = correct_symbols(int_part, system) + int_str = str(compute_value(int_part)) + dec_str = "".join([str(d.value) for d in dec_part]) + if dec_part: + return "{0}.{1}".format(int_str, dec_str) + else: + return int_str + + +def num2chn( + number_string, + numbering_type=NUMBERING_TYPES[1], + big=False, + traditional=False, + alt_zero=False, + alt_one=False, + alt_two=True, + use_zeros=True, + use_units=True, +): + + def get_value(value_string, use_zeros=True): + + striped_string = value_string.lstrip("0") + + # record nothing if all zeros + if not striped_string: + return [] + + # record one digits + elif len(striped_string) == 1: + if use_zeros and len(value_string) != len(striped_string): + return [system.digits[0], system.digits[int(striped_string)]] + else: + return [system.digits[int(striped_string)]] + + # recursively record multiple digits + else: + result_unit = next( + u for u in reversed(system.units) if u.power < len(striped_string) + ) + result_string = value_string[: -result_unit.power] + return ( + get_value(result_string) + + [result_unit] + + get_value(striped_string[-result_unit.power :]) + ) + + system = create_system(numbering_type) + + int_dec = number_string.split(".") + if len(int_dec) == 1: + int_string = int_dec[0] + dec_string = "" + elif len(int_dec) == 2: + int_string = int_dec[0] + dec_string = int_dec[1] + else: + raise ValueError( + "invalid input num string with more than one dot: {}".format(number_string) + ) + + if use_units and len(int_string) > 1: + result_symbols = get_value(int_string) + else: + result_symbols = [system.digits[int(c)] for c in int_string] + dec_symbols = [system.digits[int(c)] for c in dec_string] + if dec_string: + result_symbols += [system.math.point] + dec_symbols + + if alt_two: + liang = CND( + 2, + system.digits[2].alt_s, + system.digits[2].alt_t, + system.digits[2].big_s, + system.digits[2].big_t, + ) + for i, v in enumerate(result_symbols): + if isinstance(v, CND) and v.value == 2: + next_symbol = ( + result_symbols[i + 1] if i < len(result_symbols) - 1 else None + ) + previous_symbol = result_symbols[i - 1] if i > 0 else None + if isinstance(next_symbol, CNU) and isinstance( + previous_symbol, (CNU, type(None)) + ): + if next_symbol.power != 1 and ( + (previous_symbol is None) or (previous_symbol.power != 1) + ): + result_symbols[i] = liang + + # if big is True, '两' will not be used and `alt_two` has no impact on output + if big: + attr_name = "big_" + if traditional: + attr_name += "t" + else: + attr_name += "s" + else: + if traditional: + attr_name = "traditional" + else: + attr_name = "simplified" + + result = "".join([getattr(s, attr_name) for s in result_symbols]) + + # if not use_zeros: + # result = result.strip(getattr(system.digits[0], attr_name)) + + if alt_zero: + result = result.replace( + getattr(system.digits[0], attr_name), system.digits[0].alt_s + ) + + if alt_one: + result = result.replace( + getattr(system.digits[1], attr_name), system.digits[1].alt_s + ) + + for i, p in enumerate(POINT): + if result.startswith(p): + return CHINESE_DIGIS[0] + result + + # ^10, 11, .., 19 + if ( + len(result) >= 2 + and result[1] + in [ + SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED[0], + SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL[0], + ] + and result[0] + in [ + CHINESE_DIGIS[1], + BIG_CHINESE_DIGIS_SIMPLIFIED[1], + BIG_CHINESE_DIGIS_TRADITIONAL[1], + ] + ): + result = result[1:] + + return result + + +if __name__ == "__main__": + + # 测试程序 + all_chinese_number_string = ( + CHINESE_DIGIS + + BIG_CHINESE_DIGIS_SIMPLIFIED + + BIG_CHINESE_DIGIS_TRADITIONAL + + LARGER_CHINESE_NUMERING_UNITS_SIMPLIFIED + + LARGER_CHINESE_NUMERING_UNITS_TRADITIONAL + + SMALLER_CHINESE_NUMERING_UNITS_SIMPLIFIED + + SMALLER_CHINESE_NUMERING_UNITS_TRADITIONAL + + ZERO_ALT + + ONE_ALT + + "".join(TWO_ALTS + POSITIVE + NEGATIVE + POINT) + ) + + print("num:", chn2num("一万零四百零三点八零五")) + print("num:", chn2num("一亿六点三")) + print("num:", chn2num("一亿零六点三")) + print("num:", chn2num("两千零一亿六点三")) + # print('num:', chn2num('一零零八六')) + print("txt:", num2chn("10260.03", alt_zero=True)) + print("txt:", num2chn("20037.090", numbering_type="low", traditional=True)) + print("txt:", num2chn("100860001.77", numbering_type="high", big=True)) + print( + "txt:", + num2chn( + "059523810880", + alt_one=True, + alt_two=False, + use_lzeros=True, + use_rzeros=True, + use_units=False, + ), + ) + + print(all_chinese_number_string) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/cardinal.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/cardinal.py new file mode 100644 index 0000000000..ace9f5ad8e --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/cardinal.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +"""CARDINAL类 (包含小数DECIMAL类) +纯数 <=> 中文字符串 方法 +中文字符串 <=> 纯数 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-03" + +from fish_speech.text.chn_text_norm.basic_util import * + + +class Cardinal: + """ + CARDINAL类 + """ + + def __init__(self, cardinal=None, chntext=None): + self.cardinal = cardinal + self.chntext = chntext + + def chntext2cardinal(self): + return chn2num(self.chntext) + + def cardinal2chntext(self): + return num2chn(self.cardinal) + + +if __name__ == "__main__": + + # 测试程序 + print(Cardinal(cardinal="21357.230").cardinal2chntext()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/date.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/date.py new file mode 100644 index 0000000000..77acfdb9a9 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/date.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +"""DATE类 +日期 <=> 中文字符串 方法 +中文字符串 <=> 日期 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-07" + +from fish_speech.text.chn_text_norm.cardinal import Cardinal +from fish_speech.text.chn_text_norm.digit import Digit + + +class Date: + """ + DATE类 + """ + + def __init__(self, date=None, chntext=None): + self.date = date + self.chntext = chntext + + # def chntext2date(self): + # chntext = self.chntext + # try: + # year, other = chntext.strip().split('年', maxsplit=1) + # year = Digit(chntext=year).digit2chntext() + '年' + # except ValueError: + # other = chntext + # year = '' + # if other: + # try: + # month, day = other.strip().split('月', maxsplit=1) + # month = Cardinal(chntext=month).chntext2cardinal() + '月' + # except ValueError: + # day = chntext + # month = '' + # if day: + # day = Cardinal(chntext=day[:-1]).chntext2cardinal() + day[-1] + # else: + # month = '' + # day = '' + # date = year + month + day + # self.date = date + # return self.date + + def date2chntext(self): + date = self.date + try: + year, other = date.strip().split("年", maxsplit=1) + year = Digit(digit=year).digit2chntext() + "年" + except ValueError: + other = date + year = "" + if other: + try: + month, day = other.strip().split("月", maxsplit=1) + month = Cardinal(cardinal=month).cardinal2chntext() + "月" + except ValueError: + day = date + month = "" + if day: + day = Cardinal(cardinal=day[:-1]).cardinal2chntext() + day[-1] + else: + month = "" + day = "" + chntext = year + month + day + self.chntext = chntext + return self.chntext + + +if __name__ == "__main__": + + # 测试 + print(Date(date="09年3月16日").date2chntext()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/digit.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/digit.py new file mode 100644 index 0000000000..47c0cd4ad0 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/digit.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +"""DIGIT类 +数字串 <=> 中文字符串 方法 +中文字符串 <=> 数字串 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-03" + +from fish_speech.text.chn_text_norm.basic_util import * + + +class Digit: + """ + DIGIT类 + """ + + def __init__(self, digit=None, chntext=None): + self.digit = digit + self.chntext = chntext + + # def chntext2digit(self): + # return chn2num(self.chntext) + + def digit2chntext(self): + return num2chn(self.digit, alt_two=False, use_units=False) + + +if __name__ == "__main__": + + # 测试程序 + print(Digit(digit="2016").digit2chntext()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/fraction.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/fraction.py new file mode 100644 index 0000000000..b43b6a7feb --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/fraction.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +"""FRACTION类 +分数 <=> 中文字符串 方法 +中文字符串 <=> 分数 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-03" + +from fish_speech.text.chn_text_norm.basic_util import * + + +class Fraction: + """ + FRACTION类 + """ + + def __init__(self, fraction=None, chntext=None): + self.fraction = fraction + self.chntext = chntext + + def chntext2fraction(self): + denominator, numerator = self.chntext.split("分之") + return chn2num(numerator) + "/" + chn2num(denominator) + + def fraction2chntext(self): + numerator, denominator = self.fraction.split("/") + return num2chn(denominator) + "分之" + num2chn(numerator) + + +if __name__ == "__main__": + + # 测试程序 + print(Fraction(fraction="2135/7230").fraction2chntext()) + print(Fraction(chntext="五百八十一分之三百六十九").chntext2fraction()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/money.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/money.py new file mode 100644 index 0000000000..b4c980d321 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/money.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +"""MONEY类 +金钱 <=> 中文字符串 方法 +中文字符串 <=> 金钱 方法 +""" +import re + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-08" + +from fish_speech.text.chn_text_norm.cardinal import Cardinal + + +class Money: + """ + MONEY类 + """ + + def __init__(self, money=None, chntext=None): + self.money = money + self.chntext = chntext + + # def chntext2money(self): + # return self.money + + def money2chntext(self): + money = self.money + pattern = re.compile(r"(\d+(\.\d+)?)") + matchers = pattern.findall(money) + if matchers: + for matcher in matchers: + money = money.replace( + matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext() + ) + self.chntext = money + return self.chntext + + +if __name__ == "__main__": + + # 测试 + print(Money(money="21.5万元").money2chntext()) + print(Money(money="230块5毛").money2chntext()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/percentage.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/percentage.py new file mode 100644 index 0000000000..46abbf545a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/percentage.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +"""PERCENTAGE类 +百分数 <=> 中文字符串 方法 +中文字符串 <=> 百分数 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-06" + +from fish_speech.text.chn_text_norm.basic_util import * + + +class Percentage: + """ + PERCENTAGE类 + """ + + def __init__(self, percentage=None, chntext=None): + self.percentage = percentage + self.chntext = chntext + + def chntext2percentage(self): + return chn2num(self.chntext.strip().strip("百分之")) + "%" + + def percentage2chntext(self): + return "百分之" + num2chn(self.percentage.strip().strip("%")) + + +if __name__ == "__main__": + + # 测试程序 + print(Percentage(chntext="百分之五十六点零三").chntext2percentage()) + print(Percentage(percentage="65.3%").percentage2chntext()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/telephone.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/telephone.py new file mode 100644 index 0000000000..e72b546db6 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/telephone.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +"""TELEPHONE类 +电话号码 <=> 中文字符串 方法 +中文字符串 <=> 电话号码 方法 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-03" + +from fish_speech.text.chn_text_norm.basic_util import * + + +class TelePhone: + """ + TELEPHONE类 + """ + + def __init__(self, telephone=None, raw_chntext=None, chntext=None): + self.telephone = telephone + self.raw_chntext = raw_chntext + self.chntext = chntext + + # def chntext2telephone(self): + # sil_parts = self.raw_chntext.split('') + # self.telephone = '-'.join([ + # str(chn2num(p)) for p in sil_parts + # ]) + # return self.telephone + + def telephone2chntext(self, fixed=False): + + if fixed: + sil_parts = self.telephone.split("-") + self.raw_chntext = "".join( + [num2chn(part, alt_two=False, use_units=False) for part in sil_parts] + ) + self.chntext = self.raw_chntext.replace("", "") + else: + sp_parts = self.telephone.strip("+").split() + self.raw_chntext = "".join( + [num2chn(part, alt_two=False, use_units=False) for part in sp_parts] + ) + self.chntext = self.raw_chntext.replace("", "") + return self.chntext + + +if __name__ == "__main__": + + # 测试程序 + print(TelePhone(telephone="0595-23980880").telephone2chntext()) + # print(TelePhone(raw_chntext='零五九五杠二三八六五零九八').chntext2telephone()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/text.py b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/text.py new file mode 100644 index 0000000000..54086fd933 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/chn_text_norm/text.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +""" +TEXT类 +""" + +__author__ = "Zhiyang Zhou " +__data__ = "2019-05-03" + +import re + +from fish_speech.text.chn_text_norm.cardinal import Cardinal +from fish_speech.text.chn_text_norm.date import Date +from fish_speech.text.chn_text_norm.digit import Digit +from fish_speech.text.chn_text_norm.fraction import Fraction +from fish_speech.text.chn_text_norm.money import Money +from fish_speech.text.chn_text_norm.percentage import Percentage +from fish_speech.text.chn_text_norm.telephone import TelePhone + +CURRENCY_NAMES = ( + "(人民币|美元|日元|英镑|欧元|马克|法郎|加拿大元|澳元|港币|先令|芬兰马克|爱尔兰镑|" + "里拉|荷兰盾|埃斯库多|比塞塔|印尼盾|林吉特|新西兰元|比索|卢布|新加坡元|韩元|泰铢)" +) +CURRENCY_UNITS = "((亿|千万|百万|万|千|百)|(亿|千万|百万|万|千|百|)元|(亿|千万|百万|万|千|百|)块|角|毛|分)" +COM_QUANTIFIERS = ( + "(匹|张|座|回|场|尾|条|个|首|阙|阵|网|炮|顶|丘|棵|只|支|袭|辆|挑|担|颗|壳|窠|曲|墙|群|腔|" + "砣|座|客|贯|扎|捆|刀|令|打|手|罗|坡|山|岭|江|溪|钟|队|单|双|对|出|口|头|脚|板|跳|枝|件|贴|" + "针|线|管|名|位|身|堂|课|本|页|家|户|层|丝|毫|厘|分|钱|两|斤|担|铢|石|钧|锱|忽|(千|毫|微)克|" + "毫|厘|分|寸|尺|丈|里|寻|常|铺|程|(千|分|厘|毫|微)米|撮|勺|合|升|斗|石|盘|碗|碟|叠|桶|笼|盆|" + "盒|杯|钟|斛|锅|簋|篮|盘|桶|罐|瓶|壶|卮|盏|箩|箱|煲|啖|袋|钵|年|月|日|季|刻|时|周|天|秒|分|旬|" + "纪|岁|世|更|夜|春|夏|秋|冬|代|伏|辈|丸|泡|粒|颗|幢|堆|条|根|支|道|面|片|张|颗|块|人|抽)" +) + + +class Text: + """ + Text类 + """ + + def __init__(self, raw_text, norm_text=None): + self.raw_text = "^" + raw_text + "$" + self.norm_text = norm_text + + def _particular(self): + text = self.norm_text + pattern = re.compile(r"(([a-zA-Z]+)二([a-zA-Z]+))") + matchers = pattern.findall(text) + if matchers: + # print('particular') + for matcher in matchers: + text = text.replace(matcher[0], matcher[1] + "2" + matcher[2], 1) + self.norm_text = text + return self.norm_text + + def normalize(self): + text = self.raw_text + + # 规范化日期 + pattern = re.compile( + r"\D+((([089]\d|(19|20)\d{2})年)?(\d{1,2}月(\d{1,2}[日号])?)?)" + ) + matchers = pattern.findall(text) + if matchers: + # print('date') + for matcher in matchers: + text = text.replace(matcher[0], Date(date=matcher[0]).date2chntext(), 1) + + # 规范化金钱 + pattern = re.compile( + r"\D+((\d+(\.\d+)?)[多余几]?" + + CURRENCY_UNITS + + "(\d" + + CURRENCY_UNITS + + "?)?)" + ) + matchers = pattern.findall(text) + if matchers: + # print('money') + for matcher in matchers: + text = text.replace( + matcher[0], Money(money=matcher[0]).money2chntext(), 1 + ) + + # 规范化固话/手机号码 + # 手机 + # http://www.jihaoba.com/news/show/13680 + # 移动:139、138、137、136、135、134、159、158、157、150、151、152、188、187、182、183、184、178、198 + # 联通:130、131、132、156、155、186、185、176 + # 电信:133、153、189、180、181、177 + pattern = re.compile(r"\D((\+?86 ?)?1([38]\d|5[0-35-9]|7[678]|9[89])\d{8})\D") + matchers = pattern.findall(text) + if matchers: + # print('telephone') + for matcher in matchers: + text = text.replace( + matcher[0], TelePhone(telephone=matcher[0]).telephone2chntext(), 1 + ) + # 固话 + pattern = re.compile(r"\D((0(10|2[1-3]|[3-9]\d{2})-?)?[1-9]\d{6,7})\D") + matchers = pattern.findall(text) + if matchers: + # print('fixed telephone') + for matcher in matchers: + text = text.replace( + matcher[0], + TelePhone(telephone=matcher[0]).telephone2chntext(fixed=True), + 1, + ) + + # 规范化分数 + pattern = re.compile(r"(\d+/\d+)") + matchers = pattern.findall(text) + if matchers: + # print('fraction') + for matcher in matchers: + text = text.replace( + matcher, Fraction(fraction=matcher).fraction2chntext(), 1 + ) + + # 规范化百分数 + text = text.replace("%", "%") + pattern = re.compile(r"(\d+(\.\d+)?%)") + matchers = pattern.findall(text) + if matchers: + # print('percentage') + for matcher in matchers: + text = text.replace( + matcher[0], + Percentage(percentage=matcher[0]).percentage2chntext(), + 1, + ) + + # 规范化纯数+量词 + pattern = re.compile(r"(\d+(\.\d+)?)[多余几]?" + COM_QUANTIFIERS) + matchers = pattern.findall(text) + if matchers: + # print('cardinal+quantifier') + for matcher in matchers: + text = text.replace( + matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext(), 1 + ) + + # 规范化数字编号 + pattern = re.compile(r"(\d{4,32})") + matchers = pattern.findall(text) + if matchers: + # print('digit') + for matcher in matchers: + text = text.replace(matcher, Digit(digit=matcher).digit2chntext(), 1) + + # 规范化纯数 + pattern = re.compile(r"(\d+(\.\d+)?)") + matchers = pattern.findall(text) + if matchers: + # print('cardinal') + for matcher in matchers: + text = text.replace( + matcher[0], Cardinal(cardinal=matcher[0]).cardinal2chntext(), 1 + ) + + self.norm_text = text + self._particular() + + return self.norm_text.lstrip("^").rstrip("$") + + +if __name__ == "__main__": + + # 测试程序 + print(Text(raw_text="固话:0595-23865596或23880880。").normalize()) + print(Text(raw_text="手机:+86 19859213959或15659451527。").normalize()) + print(Text(raw_text="分数:32477/76391。").normalize()) + print(Text(raw_text="百分数:80.03%。").normalize()) + print(Text(raw_text="编号:31520181154418。").normalize()) + print(Text(raw_text="纯数:2983.07克或12345.60米。").normalize()) + print(Text(raw_text="日期:1999年2月20日或09年3月15号。").normalize()) + print(Text(raw_text="金钱:12块5,34.5元,20.1万").normalize()) + print(Text(raw_text="特殊:O2O或B2C。").normalize()) diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/clean.py b/xinference/thirdparty/fish_speech/fish_speech/text/clean.py new file mode 100644 index 0000000000..76d9dc9033 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/clean.py @@ -0,0 +1,69 @@ +import itertools +import re + +LANGUAGE_UNICODE_RANGE_MAP = { + "ZH": [(0x4E00, 0x9FFF)], + "JP": [(0x4E00, 0x9FFF), (0x3040, 0x309F), (0x30A0, 0x30FF), (0x31F0, 0x31FF)], + "EN": [(0x0000, 0x007F)], +} + +SYMBOLS_MAPPING = { + ":": ",", + ";": ",", + ",": ",", + "。": ".", + "!": "!", + "?": "?", + "\n": ".", + "·": ",", + "、": ",", + "...": "…", + "“": "'", + "”": "'", + "‘": "'", + "’": "'", + "(": "'", + ")": "'", + "(": "'", + ")": "'", + "《": "'", + "》": "'", + "【": "'", + "】": "'", + "[": "'", + "]": "'", + "—": "-", + "~": "-", + "~": "-", + "・": "-", + "「": "'", + "」": "'", + ";": ",", + ":": ",", +} + +REPLACE_SYMBOL_REGEX = re.compile( + "|".join(re.escape(p) for p in SYMBOLS_MAPPING.keys()) +) +ALL_KNOWN_UTF8_RANGE = list( + itertools.chain.from_iterable(LANGUAGE_UNICODE_RANGE_MAP.values()) +) +REMOVE_UNKNOWN_SYMBOL_REGEX = re.compile( + "[^" + + "".join( + f"{re.escape(chr(start))}-{re.escape(chr(end))}" + for start, end in ALL_KNOWN_UTF8_RANGE + ) + + "]" +) + + +def clean_text(text): + # Clean the text + text = text.strip() + + # Replace all chinese symbols with their english counterparts + text = REPLACE_SYMBOL_REGEX.sub(lambda x: SYMBOLS_MAPPING[x.group()], text) + text = REMOVE_UNKNOWN_SYMBOL_REGEX.sub("", text) + + return text diff --git a/xinference/thirdparty/fish_speech/fish_speech/text/spliter.py b/xinference/thirdparty/fish_speech/fish_speech/text/spliter.py new file mode 100644 index 0000000000..5528cd3a63 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/text/spliter.py @@ -0,0 +1,130 @@ +import re +import string + +from fish_speech.text.clean import clean_text + + +def utf_8_len(text): + return len(text.encode("utf-8")) + + +def break_text(texts, length, splits: set): + for text in texts: + if utf_8_len(text) <= length: + yield text + continue + + curr = "" + for char in text: + curr += char + + if char in splits: + yield curr + curr = "" + + if curr: + yield curr + + +def break_text_by_length(texts, length): + for text in texts: + if utf_8_len(text) <= length: + yield text + continue + + curr = "" + for char in text: + curr += char + + if utf_8_len(curr) >= length: + yield curr + curr = "" + + if curr: + yield curr + + +def add_cleaned(curr, segments): + curr = curr.strip() + if curr and not all(c.isspace() or c in string.punctuation for c in curr): + segments.append(curr) + + +def protect_float(text): + # Turns 3.14 into <3_f_14> to prevent splitting + return re.sub(r"(\d+)\.(\d+)", r"<\1_f_\2>", text) + + +def unprotect_float(text): + # Turns <3_f_14> into 3.14 + return re.sub(r"<(\d+)_f_(\d+)>", r"\1.\2", text) + + +def split_text(text, length): + text = clean_text(text) + + # Break the text into pieces with following rules: + # 1. Split the text at ".", "!", "?" if text is NOT a float + # 2. If the text is longer than length, split at "," + # 3. If the text is still longer than length, split at " " + # 4. If the text is still longer than length, split at any character to length + + texts = [text] + texts = map(protect_float, texts) + texts = break_text(texts, length, {".", "!", "?"}) + texts = map(unprotect_float, texts) + texts = break_text(texts, length, {","}) + texts = break_text(texts, length, {" "}) + texts = list(break_text_by_length(texts, length)) + + # Then, merge the texts into segments with length <= length + segments = [] + curr = "" + + for text in texts: + if utf_8_len(curr) + utf_8_len(text) <= length: + curr += text + else: + add_cleaned(curr, segments) + curr = text + + if curr: + add_cleaned(curr, segments) + + return segments + + +if __name__ == "__main__": + # Test the split_text function + + text = "This is a test sentence. This is another test sentence. And a third one." + + assert split_text(text, 50) == [ + "This is a test sentence.", + "This is another test sentence. And a third one.", + ] + assert split_text("a,aaaaaa3.14", 10) == ["a,", "aaaaaa3.14"] + assert split_text(" ", 10) == [] + assert split_text("a", 10) == ["a"] + + text = "This is a test sentence with only commas, and no dots, and no exclamation marks, and no question marks, and no newlines." + assert split_text(text, 50) == [ + "This is a test sentence with only commas,", + "and no dots, and no exclamation marks,", + "and no question marks, and no newlines.", + ] + + text = "This is a test sentence This is a test sentence This is a test sentence. This is a test sentence, This is a test sentence, This is a test sentence." + # First half split at " ", second half split at "," + assert split_text(text, 50) == [ + "This is a test sentence This is a test sentence", + "This is a test sentence. This is a test sentence,", + "This is a test sentence, This is a test sentence.", + ] + + text = "这是一段很长的中文文本,而且没有句号,也没有感叹号,也没有问号,也没有换行符。" + assert split_text(text, 50) == [ + "这是一段很长的中文文本,", + "而且没有句号,也没有感叹号,", + "也没有问号,也没有换行符.", + ] diff --git a/xinference/thirdparty/fish_speech/fish_speech/train.py b/xinference/thirdparty/fish_speech/fish_speech/train.py new file mode 100644 index 0000000000..a6a344097a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/train.py @@ -0,0 +1,139 @@ +import os +import sys +from typing import Optional + +import hydra +import lightning as L +# import pyrootutils +import torch +from lightning import Callback, LightningDataModule, LightningModule, Trainer +from lightning.pytorch.loggers import Logger +from lightning.pytorch.strategies import DDPStrategy +from omegaconf import DictConfig, OmegaConf + +os.environ.pop("SLURM_NTASKS", None) +os.environ.pop("SLURM_JOB_NAME", None) +os.environ.pop("SLURM_NTASKS_PER_NODE", None) + +# register eval resolver and root +# pyrootutils.setup_root(__file__, indicator=".project-root", pythonpath=True) + +# Allow TF32 on Ampere GPUs +torch.set_float32_matmul_precision("high") +torch.backends.cudnn.allow_tf32 = True + +# register eval resolver +OmegaConf.register_new_resolver("eval", eval) + +import fish_speech.utils as utils + +log = utils.RankedLogger(__name__, rank_zero_only=True) + + +@utils.task_wrapper +def train(cfg: DictConfig) -> tuple[dict, dict]: + """Trains the model. Can additionally evaluate on a testset, using best weights obtained during + training. + This method is wrapped in optional @task_wrapper decorator, that controls the behavior during + failure. Useful for multiruns, saving info about the crash, etc. + Args: + cfg (DictConfig): Configuration composed by Hydra. + Returns: + Tuple[dict, dict]: Dict with metrics and dict with all instantiated objects. + """ # noqa: E501 + + # set seed for random number generators in pytorch, numpy and python.random + if cfg.get("seed"): + L.seed_everything(cfg.seed, workers=False) + + if cfg.get("deterministic"): + torch.use_deterministic_algorithms(True) + + log.info(f"Instantiating datamodule <{cfg.data._target_}>") + datamodule: LightningDataModule = hydra.utils.instantiate(cfg.data) + + log.info(f"Instantiating model <{cfg.model._target_}>") + model: LightningModule = hydra.utils.instantiate(cfg.model) + + log.info("Instantiating callbacks...") + callbacks: list[Callback] = utils.instantiate_callbacks(cfg.get("callbacks")) + + log.info("Instantiating loggers...") + logger: list[Logger] = utils.instantiate_loggers(cfg.get("logger")) + + log.info(f"Instantiating trainer <{cfg.trainer._target_}>") + trainer: Trainer = hydra.utils.instantiate( + cfg.trainer, + callbacks=callbacks, + logger=logger, + ) + + object_dict = { + "cfg": cfg, + "datamodule": datamodule, + "model": model, + "callbacks": callbacks, + "logger": logger, + "trainer": trainer, + } + + if logger: + log.info("Logging hyperparameters!") + utils.log_hyperparameters(object_dict) + + if cfg.get("train"): + log.info("Starting training!") + + ckpt_path = cfg.get("ckpt_path") + auto_resume = False + + resume_ckpt_path = utils.get_latest_checkpoint(cfg.paths.ckpt_dir) + if resume_ckpt_path is not None: + ckpt_path = resume_ckpt_path + auto_resume = True + + if ckpt_path is not None: + log.info(f"Resuming from checkpoint: {ckpt_path}") + + # resume weights only is disabled for auto-resume + if cfg.get("resume_weights_only") and auto_resume is False: + log.info("Resuming weights only!") + ckpt = torch.load(ckpt_path, map_location=model.device) + if "state_dict" in ckpt: + ckpt = ckpt["state_dict"] + err = model.load_state_dict(ckpt, strict=False) + log.info(f"Error loading state dict: {err}") + ckpt_path = None + + trainer.fit(model=model, datamodule=datamodule, ckpt_path=ckpt_path) + + train_metrics = trainer.callback_metrics + + if cfg.get("test"): + log.info("Starting testing!") + ckpt_path = trainer.checkpoint_callback.best_model_path + if ckpt_path == "": + log.warning("Best ckpt not found! Using current weights for testing...") + ckpt_path = cfg.get("ckpt_path") + + trainer.test(model=model, datamodule=datamodule, ckpt_path=ckpt_path) + log.info(f"Best ckpt path: {ckpt_path}") + + test_metrics = trainer.callback_metrics + + # merge train and test metrics + metric_dict = {**train_metrics, **test_metrics} + + return metric_dict, object_dict + + +@hydra.main( + version_base="1.3", config_path="./configs", config_name="llama_pretrain.yaml" +) +def main(cfg: DictConfig) -> Optional[float]: + # train the model + train(cfg) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/utils/__init__.py new file mode 100644 index 0000000000..05378519db --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/__init__.py @@ -0,0 +1,23 @@ +from .braceexpand import braceexpand +from .context import autocast_exclude_mps +from .file import get_latest_checkpoint +from .instantiators import instantiate_callbacks, instantiate_loggers +from .logger import RankedLogger +from .logging_utils import log_hyperparameters +from .rich_utils import enforce_tags, print_config_tree +from .utils import extras, get_metric_value, task_wrapper + +__all__ = [ + "enforce_tags", + "extras", + "get_metric_value", + "RankedLogger", + "instantiate_callbacks", + "instantiate_loggers", + "log_hyperparameters", + "print_config_tree", + "task_wrapper", + "braceexpand", + "get_latest_checkpoint", + "autocast_exclude_mps", +] diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/braceexpand.py b/xinference/thirdparty/fish_speech/fish_speech/utils/braceexpand.py new file mode 100644 index 0000000000..f3ac739f01 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/braceexpand.py @@ -0,0 +1,217 @@ +""" +Bash-style brace expansion +Copied from: https://github.com/trendels/braceexpand/blob/main/src/braceexpand/__init__.py +License: MIT +""" + +import re +import string +from itertools import chain, product +from typing import Iterable, Iterator, Optional + +__all__ = ["braceexpand", "alphabet", "UnbalancedBracesError"] + + +class UnbalancedBracesError(ValueError): + pass + + +alphabet = string.ascii_uppercase + string.ascii_lowercase + +int_range_re = re.compile(r"^(-?\d+)\.\.(-?\d+)(?:\.\.-?(\d+))?$") +char_range_re = re.compile(r"^([A-Za-z])\.\.([A-Za-z])(?:\.\.-?(\d+))?$") +escape_re = re.compile(r"\\(.)") + + +def braceexpand(pattern: str, escape: bool = True) -> Iterator[str]: + """braceexpand(pattern) -> iterator over generated strings + + Returns an iterator over the strings resulting from brace expansion + of pattern. This function implements Brace Expansion as described in + bash(1), with the following limitations: + + * A pattern containing unbalanced braces will raise an + UnbalancedBracesError exception. In bash, unbalanced braces will either + be partly expanded or ignored. + + * A mixed-case character range like '{Z..a}' or '{a..Z}' will not + include the characters '[]^_`' between 'Z' and 'a'. + + When escape is True (the default), characters in pattern can be + prefixed with a backslash to cause them not to be interpreted as + special characters for brace expansion (such as '{', '}', ','). + To pass through a a literal backslash, double it ('\\\\'). + + When escape is False, backslashes in pattern have no special + meaning and will be preserved in the output. + + Examples: + + >>> from braceexpand import braceexpand + + # Integer range + >>> list(braceexpand('item{1..3}')) + ['item1', 'item2', 'item3'] + + # Character range + >>> list(braceexpand('{a..c}')) + ['a', 'b', 'c'] + + # Sequence + >>> list(braceexpand('index.html{,.backup}')) + ['index.html', 'index.html.backup'] + + # Nested patterns + >>> list(braceexpand('python{2.{5..7},3.{2,3}}')) + ['python2.5', 'python2.6', 'python2.7', 'python3.2', 'python3.3'] + + # Prefixing an integer with zero causes all numbers to be padded to + # the same width. + >>> list(braceexpand('{07..10}')) + ['07', '08', '09', '10'] + + # An optional increment can be specified for ranges. + >>> list(braceexpand('{a..g..2}')) + ['a', 'c', 'e', 'g'] + + # Ranges can go in both directions. + >>> list(braceexpand('{4..1}')) + ['4', '3', '2', '1'] + + # Numbers can be negative + >>> list(braceexpand('{2..-1}')) + ['2', '1', '0', '-1'] + + # Unbalanced braces raise an exception. + >>> list(braceexpand('{1{2,3}')) + Traceback (most recent call last): + ... + UnbalancedBracesError: Unbalanced braces: '{1{2,3}' + + # By default, the backslash is the escape character. + >>> list(braceexpand(r'{1\\{2,3}')) + ['1{2', '3'] + + # Setting 'escape' to False disables backslash escaping. + >>> list(braceexpand(r'\\{1,2}', escape=False)) + ['\\\\1', '\\\\2'] + + """ + return ( + escape_re.sub(r"\1", s) if escape else s for s in parse_pattern(pattern, escape) + ) + + +def parse_pattern(pattern: str, escape: bool) -> Iterator[str]: + start = 0 + pos = 0 + bracketdepth = 0 + items: list[Iterable[str]] = [] + + # print 'pattern:', pattern + while pos < len(pattern): + if escape and pattern[pos] == "\\": + pos += 2 + continue + elif pattern[pos] == "{": + if bracketdepth == 0 and pos > start: + # print 'literal:', pattern[start:pos] + items.append([pattern[start:pos]]) + start = pos + bracketdepth += 1 + elif pattern[pos] == "}": + bracketdepth -= 1 + if bracketdepth == 0: + # print 'expression:', pattern[start+1:pos] + expr = pattern[start + 1 : pos] + item = parse_expression(expr, escape) + if item is None: # not a range or sequence + items.extend([["{"], parse_pattern(expr, escape), ["}"]]) + else: + items.append(item) + start = pos + 1 # skip the closing brace + pos += 1 + + if bracketdepth != 0: # unbalanced braces + raise UnbalancedBracesError("Unbalanced braces: '%s'" % pattern) + + if start < pos: + items.append([pattern[start:]]) + + return ("".join(item) for item in product(*items)) + + +def parse_expression(expr: str, escape: bool) -> Optional[Iterable[str]]: + int_range_match = int_range_re.match(expr) + if int_range_match: + return make_int_range(*int_range_match.groups()) + + char_range_match = char_range_re.match(expr) + if char_range_match: + return make_char_range(*char_range_match.groups()) + + return parse_sequence(expr, escape) + + +def parse_sequence(seq: str, escape: bool) -> Optional[Iterator[str]]: + # sequence -> chain(*sequence_items) + start = 0 + pos = 0 + bracketdepth = 0 + items: list[Iterable[str]] = [] + + # print 'sequence:', seq + while pos < len(seq): + if escape and seq[pos] == "\\": + pos += 2 + continue + elif seq[pos] == "{": + bracketdepth += 1 + elif seq[pos] == "}": + bracketdepth -= 1 + elif seq[pos] == "," and bracketdepth == 0: + items.append(parse_pattern(seq[start:pos], escape)) + start = pos + 1 # skip the comma + pos += 1 + + if bracketdepth != 0: + raise UnbalancedBracesError + if not items: + return None + + # part after the last comma (may be the empty string) + items.append(parse_pattern(seq[start:], escape)) + return chain(*items) + + +def make_int_range(left: str, right: str, incr: Optional[str] = None) -> Iterator[str]: + if any([s.startswith(("0", "-0")) for s in (left, right) if s not in ("0", "-0")]): + padding = max(len(left), len(right)) + else: + padding = 0 + step = (int(incr) or 1) if incr else 1 + start = int(left) + end = int(right) + r = range(start, end + 1, step) if start < end else range(start, end - 1, -step) + fmt = "%0{}d".format(padding) + return (fmt % i for i in r) + + +def make_char_range(left: str, right: str, incr: Optional[str] = None) -> str: + step = (int(incr) or 1) if incr else 1 + start = alphabet.index(left) + end = alphabet.index(right) + if start < end: + return alphabet[start : end + 1 : step] + else: + end = end or -len(alphabet) + return alphabet[start : end - 1 : -step] + + +if __name__ == "__main__": + import doctest + import sys + + failed, _ = doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL) + if failed: + sys.exit(1) diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/context.py b/xinference/thirdparty/fish_speech/fish_speech/utils/context.py new file mode 100644 index 0000000000..f04a99290a --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/context.py @@ -0,0 +1,13 @@ +from contextlib import nullcontext + +import torch + + +def autocast_exclude_mps( + device_type: str, dtype: torch.dtype +) -> nullcontext | torch.autocast: + return ( + nullcontext() + if torch.backends.mps.is_available() + else torch.autocast(device_type, dtype) + ) diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/file.py b/xinference/thirdparty/fish_speech/fish_speech/utils/file.py new file mode 100644 index 0000000000..78c82640a9 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/file.py @@ -0,0 +1,16 @@ +import os +from pathlib import Path + + +def get_latest_checkpoint(path: Path | str) -> Path | None: + # Find the latest checkpoint + ckpt_dir = Path(path) + + if ckpt_dir.exists() is False: + return None + + ckpts = sorted(ckpt_dir.glob("*.ckpt"), key=os.path.getmtime) + if len(ckpts) == 0: + return None + + return ckpts[-1] diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/instantiators.py b/xinference/thirdparty/fish_speech/fish_speech/utils/instantiators.py new file mode 100644 index 0000000000..f6ee463924 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/instantiators.py @@ -0,0 +1,50 @@ +from typing import List + +import hydra +from omegaconf import DictConfig +from pytorch_lightning import Callback +from pytorch_lightning.loggers import Logger + +from .logger import RankedLogger + +log = RankedLogger(__name__, rank_zero_only=True) + + +def instantiate_callbacks(callbacks_cfg: DictConfig) -> List[Callback]: + """Instantiates callbacks from config.""" + + callbacks: List[Callback] = [] + + if not callbacks_cfg: + log.warning("No callback configs found! Skipping..") + return callbacks + + if not isinstance(callbacks_cfg, DictConfig): + raise TypeError("Callbacks config must be a DictConfig!") + + for _, cb_conf in callbacks_cfg.items(): + if isinstance(cb_conf, DictConfig) and "_target_" in cb_conf: + log.info(f"Instantiating callback <{cb_conf._target_}>") + callbacks.append(hydra.utils.instantiate(cb_conf)) + + return callbacks + + +def instantiate_loggers(logger_cfg: DictConfig) -> List[Logger]: + """Instantiates loggers from config.""" + + logger: List[Logger] = [] + + if not logger_cfg: + log.warning("No logger configs found! Skipping...") + return logger + + if not isinstance(logger_cfg, DictConfig): + raise TypeError("Logger config must be a DictConfig!") + + for _, lg_conf in logger_cfg.items(): + if isinstance(lg_conf, DictConfig) and "_target_" in lg_conf: + log.info(f"Instantiating logger <{lg_conf._target_}>") + logger.append(hydra.utils.instantiate(lg_conf)) + + return logger diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/logger.py b/xinference/thirdparty/fish_speech/fish_speech/utils/logger.py new file mode 100644 index 0000000000..94f94f738d --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/logger.py @@ -0,0 +1,55 @@ +import logging +from typing import Mapping, Optional + +from lightning_utilities.core.rank_zero import rank_prefixed_message, rank_zero_only + + +class RankedLogger(logging.LoggerAdapter): + """A multi-GPU-friendly python command line logger.""" + + def __init__( + self, + name: str = __name__, + rank_zero_only: bool = True, + extra: Optional[Mapping[str, object]] = None, + ) -> None: + """Initializes a multi-GPU-friendly python command line logger that logs on all processes + with their rank prefixed in the log message. + + :param name: The name of the logger. Default is ``__name__``. + :param rank_zero_only: Whether to force all logs to only occur on the rank zero process. Default is `False`. + :param extra: (Optional) A dict-like object which provides contextual information. See `logging.LoggerAdapter`. + """ + logger = logging.getLogger(name) + super().__init__(logger=logger, extra=extra) + self.rank_zero_only = rank_zero_only + + def log( + self, level: int, msg: str, rank: Optional[int] = None, *args, **kwargs + ) -> None: + """Delegate a log call to the underlying logger, after prefixing its message with the rank + of the process it's being logged from. If `'rank'` is provided, then the log will only + occur on that rank/process. + + :param level: The level to log at. Look at `logging.__init__.py` for more information. + :param msg: The message to log. + :param rank: The rank to log at. + :param args: Additional args to pass to the underlying logging function. + :param kwargs: Any additional keyword args to pass to the underlying logging function. + """ + if self.isEnabledFor(level): + msg, kwargs = self.process(msg, kwargs) + current_rank = getattr(rank_zero_only, "rank", None) + if current_rank is None: + raise RuntimeError( + "The `rank_zero_only.rank` needs to be set before use" + ) + msg = rank_prefixed_message(msg, current_rank) + if self.rank_zero_only: + if current_rank == 0: + self.logger.log(level, msg, *args, **kwargs) + else: + if rank is None: + self.logger.log(level, msg, *args, **kwargs) + elif current_rank == rank: + self.logger.log(level, msg, *args, **kwargs) diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/logging_utils.py b/xinference/thirdparty/fish_speech/fish_speech/utils/logging_utils.py new file mode 100644 index 0000000000..8e3b0a2519 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/logging_utils.py @@ -0,0 +1,48 @@ +from lightning.pytorch.utilities import rank_zero_only + +from fish_speech.utils import logger as log + + +@rank_zero_only +def log_hyperparameters(object_dict: dict) -> None: + """Controls which config parts are saved by lightning loggers. + + Additionally saves: + - Number of model parameters + """ + + hparams = {} + + cfg = object_dict["cfg"] + model = object_dict["model"] + trainer = object_dict["trainer"] + + if not trainer.logger: + log.warning("Logger not found! Skipping hyperparameter logging...") + return + + hparams["model"] = cfg["model"] + + # save number of model parameters + hparams["model/params/total"] = sum(p.numel() for p in model.parameters()) + hparams["model/params/trainable"] = sum( + p.numel() for p in model.parameters() if p.requires_grad + ) + hparams["model/params/non_trainable"] = sum( + p.numel() for p in model.parameters() if not p.requires_grad + ) + + hparams["data"] = cfg["data"] + hparams["trainer"] = cfg["trainer"] + + hparams["callbacks"] = cfg.get("callbacks") + hparams["extras"] = cfg.get("extras") + + hparams["task_name"] = cfg.get("task_name") + hparams["tags"] = cfg.get("tags") + hparams["ckpt_path"] = cfg.get("ckpt_path") + hparams["seed"] = cfg.get("seed") + + # send hparams to all loggers + for logger in trainer.loggers: + logger.log_hyperparams(hparams) diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/rich_utils.py b/xinference/thirdparty/fish_speech/fish_speech/utils/rich_utils.py new file mode 100644 index 0000000000..6a465f54d6 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/rich_utils.py @@ -0,0 +1,100 @@ +from pathlib import Path +from typing import Sequence + +import rich +import rich.syntax +import rich.tree +from hydra.core.hydra_config import HydraConfig +from lightning.pytorch.utilities import rank_zero_only +from omegaconf import DictConfig, OmegaConf, open_dict +from rich.prompt import Prompt + +from fish_speech.utils import logger as log + + +@rank_zero_only +def print_config_tree( + cfg: DictConfig, + print_order: Sequence[str] = ( + "data", + "model", + "callbacks", + "logger", + "trainer", + "paths", + "extras", + ), + resolve: bool = False, + save_to_file: bool = False, +) -> None: + """Prints content of DictConfig using Rich library and its tree structure. + + Args: + cfg (DictConfig): Configuration composed by Hydra. + print_order (Sequence[str], optional): Determines in what order config components are printed. + resolve (bool, optional): Whether to resolve reference fields of DictConfig. + save_to_file (bool, optional): Whether to export config to the hydra output folder. + """ # noqa: E501 + + style = "dim" + tree = rich.tree.Tree("CONFIG", style=style, guide_style=style) + + queue = [] + + # add fields from `print_order` to queue + for field in print_order: + ( + queue.append(field) + if field in cfg + else log.warning( + f"Field '{field}' not found in config. " + + f"Skipping '{field}' config printing..." + ) + ) + + # add all the other fields to queue (not specified in `print_order`) + for field in cfg: + if field not in queue: + queue.append(field) + + # generate config tree from queue + for field in queue: + branch = tree.add(field, style=style, guide_style=style) + + config_group = cfg[field] + if isinstance(config_group, DictConfig): + branch_content = OmegaConf.to_yaml(config_group, resolve=resolve) + else: + branch_content = str(config_group) + + branch.add(rich.syntax.Syntax(branch_content, "yaml")) + + # print config tree + rich.print(tree) + + # save config tree to file + if save_to_file: + with open(Path(cfg.paths.output_dir, "config_tree.log"), "w") as file: + rich.print(tree, file=file) + + +@rank_zero_only +def enforce_tags(cfg: DictConfig, save_to_file: bool = False) -> None: + """Prompts user to input tags from command line if no tags are provided in config.""" # noqa: E501 + + if not cfg.get("tags"): + if "id" in HydraConfig().cfg.hydra.job: + raise ValueError("Specify tags before launching a multirun!") + + log.warning("No tags provided in config. Prompting user to input tags...") + tags = Prompt.ask("Enter a list of comma separated tags", default="dev") + tags = [t.strip() for t in tags.split(",") if t != ""] + + with open_dict(cfg): + cfg.tags = tags + + log.info(f"Tags: {cfg.tags}") + + if save_to_file: + with open(Path(cfg.paths.output_dir, "tags.log"), "w") as file: + rich.print(cfg.tags, file=file) diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/spectrogram.py b/xinference/thirdparty/fish_speech/fish_speech/utils/spectrogram.py new file mode 100644 index 0000000000..01c3d7a2ab --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/spectrogram.py @@ -0,0 +1,122 @@ +import torch +import torchaudio.functional as F +from torch import Tensor, nn +from torchaudio.transforms import MelScale + + +class LinearSpectrogram(nn.Module): + def __init__( + self, + n_fft=2048, + win_length=2048, + hop_length=512, + center=False, + mode="pow2_sqrt", + ): + super().__init__() + + self.n_fft = n_fft + self.win_length = win_length + self.hop_length = hop_length + self.center = center + self.mode = mode + + self.register_buffer("window", torch.hann_window(win_length), persistent=False) + + def forward(self, y: Tensor) -> Tensor: + if y.ndim == 3: + y = y.squeeze(1) + + y = torch.nn.functional.pad( + y.unsqueeze(1), + ( + (self.win_length - self.hop_length) // 2, + (self.win_length - self.hop_length + 1) // 2, + ), + mode="reflect", + ).squeeze(1) + + spec = torch.stft( + y, + self.n_fft, + hop_length=self.hop_length, + win_length=self.win_length, + window=self.window, + center=self.center, + pad_mode="reflect", + normalized=False, + onesided=True, + return_complex=True, + ) + + spec = torch.view_as_real(spec) + + if self.mode == "pow2_sqrt": + spec = torch.sqrt(spec.pow(2).sum(-1) + 1e-6) + + return spec + + +class LogMelSpectrogram(nn.Module): + def __init__( + self, + sample_rate=44100, + n_fft=2048, + win_length=2048, + hop_length=512, + n_mels=128, + center=False, + f_min=0.0, + f_max=None, + ): + super().__init__() + + self.sample_rate = sample_rate + self.n_fft = n_fft + self.win_length = win_length + self.hop_length = hop_length + self.center = center + self.n_mels = n_mels + self.f_min = f_min + self.f_max = f_max or float(sample_rate // 2) + + self.spectrogram = LinearSpectrogram(n_fft, win_length, hop_length, center) + + fb = F.melscale_fbanks( + n_freqs=self.n_fft // 2 + 1, + f_min=self.f_min, + f_max=self.f_max, + n_mels=self.n_mels, + sample_rate=self.sample_rate, + norm="slaney", + mel_scale="slaney", + ) + self.register_buffer( + "fb", + fb, + persistent=False, + ) + + def compress(self, x: Tensor) -> Tensor: + return torch.log(torch.clamp(x, min=1e-5)) + + def decompress(self, x: Tensor) -> Tensor: + return torch.exp(x) + + def apply_mel_scale(self, x: Tensor) -> Tensor: + return torch.matmul(x.transpose(-1, -2), self.fb).transpose(-1, -2) + + def forward( + self, x: Tensor, return_linear: bool = False, sample_rate: int = None + ) -> Tensor: + if sample_rate is not None and sample_rate != self.sample_rate: + x = F.resample(x, orig_freq=sample_rate, new_freq=self.sample_rate) + + linear = self.spectrogram(x) + x = self.apply_mel_scale(linear) + x = self.compress(x) + + if return_linear: + return x, self.compress(linear) + + return x diff --git a/xinference/thirdparty/fish_speech/fish_speech/utils/utils.py b/xinference/thirdparty/fish_speech/fish_speech/utils/utils.py new file mode 100644 index 0000000000..c546bfa1ed --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/utils/utils.py @@ -0,0 +1,114 @@ +import warnings +from importlib.util import find_spec +from typing import Callable + +from omegaconf import DictConfig + +from .logger import RankedLogger +from .rich_utils import enforce_tags, print_config_tree + +log = RankedLogger(__name__, rank_zero_only=True) + + +def extras(cfg: DictConfig) -> None: + """Applies optional utilities before the task is started. + + Utilities: + - Ignoring python warnings + - Setting tags from command line + - Rich config printing + """ + + # return if no `extras` config + if not cfg.get("extras"): + log.warning("Extras config not found! ") + return + + # disable python warnings + if cfg.extras.get("ignore_warnings"): + log.info("Disabling python warnings! ") + warnings.filterwarnings("ignore") + + # prompt user to input tags from command line if none are provided in the config + if cfg.extras.get("enforce_tags"): + log.info("Enforcing tags! ") + enforce_tags(cfg, save_to_file=True) + + # pretty print config tree using Rich library + if cfg.extras.get("print_config"): + log.info("Printing config tree with Rich! ") + print_config_tree(cfg, resolve=True, save_to_file=True) + + +def task_wrapper(task_func: Callable) -> Callable: + """Optional decorator that controls the failure behavior when executing the task function. + + This wrapper can be used to: + - make sure loggers are closed even if the task function raises an exception (prevents multirun failure) + - save the exception to a `.log` file + - mark the run as failed with a dedicated file in the `logs/` folder (so we can find and rerun it later) + - etc. (adjust depending on your needs) + + Example: + ``` + @utils.task_wrapper + def train(cfg: DictConfig) -> Tuple[dict, dict]: + + ... + + return metric_dict, object_dict + ``` + """ # noqa: E501 + + def wrap(cfg: DictConfig): + # execute the task + try: + metric_dict, object_dict = task_func(cfg=cfg) + + # things to do if exception occurs + except Exception as ex: + # save exception to `.log` file + log.exception("") + + # some hyperparameter combinations might be invalid or + # cause out-of-memory errors so when using hparam search + # plugins like Optuna, you might want to disable + # raising the below exception to avoid multirun failure + raise ex + + # things to always do after either success or exception + finally: + # display output dir path in terminal + log.info(f"Output dir: {cfg.paths.run_dir}") + + # always close wandb run (even if exception occurs so multirun won't fail) + if find_spec("wandb"): # check if wandb is installed + import wandb + + if wandb.run: + log.info("Closing wandb!") + wandb.finish() + + return metric_dict, object_dict + + return wrap + + +def get_metric_value(metric_dict: dict, metric_name: str) -> float: + """Safely retrieves value of the metric logged in LightningModule.""" + + if not metric_name: + log.info("Metric name is None! Skipping metric value retrieval...") + return None + + if metric_name not in metric_dict: + raise Exception( + f"Metric value not found! \n" + "Make sure metric name logged in LightningModule is correct!\n" + "Make sure `optimized_metric` name in `hparams_search` config is correct!" + ) + + metric_value = metric_dict[metric_name].item() + log.info(f"Retrieved metric value! <{metric_name}={metric_value}>") + + return metric_value diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/__init__.py b/xinference/thirdparty/fish_speech/fish_speech/webui/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/css/style.css b/xinference/thirdparty/fish_speech/fish_speech/webui/css/style.css new file mode 100644 index 0000000000..3c7a22ecc3 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/webui/css/style.css @@ -0,0 +1,161 @@ +:root { + --my-200: #80eeee; + --my-50: #ecfdf5; + --water-width: 300px; + --water-heigh: 300px; +} + + +/* general styled components */ +.tools { + align-items: center; + justify-content: center; +} + +.gradio-button { + max-width: 2.2em; + min-width: 2.2em !important; + height: 2.4em; + align-self: end; + line-height: 1em; + border-radius: 0.5em; + +} + +.gradio-button.secondary-down, .gradio-button.secondary-down:hover{ + box-shadow: 1px 1px 1px rgba(0,0,0,0.25) inset, 0px 0px 3px rgba(0,0,0,0.15) inset; +} + +/* replace original footer with ours */ +a{ + font-weight: bold; + cursor: pointer; + color: #030C14 !important; +} + +footer { + display: none !important; +} + +#footer{ + text-align: center; +} + +#footer div{ + display: inline-block; +} + +#footer .versions{ + font-size: 85%; + opacity: 0.85; +} + +/*@keyframes moveBackground {*/ +/* 0% {*/ +/* background-position: 0 0;*/ +/* }*/ +/* 100% {*/ +/* background-position: -100px 100px;*/ +/* }*/ +/*}*/ +@keyframes moveJellyBackground { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +.gradio-container { + position: absolute; + z-index: 10; +} + + +.quan { + position: absolute; + bottom: 0; + width: var(--water-width); + height: var(--water-heigh); + border-radius: 0; + /*border: 3px solid rgb(246, 247, 248);*/ + /*box-shadow: 0 0 0 3px rgb(41, 134, 196);*/ + z-index: 0; + +} + +.quan:last-child { + margin-right: 0; +} + +.shui { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgb(23, 106, 201); + border-radius: 0; + overflow: hidden; + z-index: 0; +} + +.shui::after { + + content: ''; + position: absolute; + top: 20%; + left: 50%; + width: 150%; + height: 150%; + border-radius: 40%; + background-image: radial-gradient(circle at 0% 50%, #dcfcf1, var(--my-50) 50%); + animation: shi 5s linear infinite; +} + +@keyframes shi { + 0% { + transform: translate(-50%, -65%) rotate(0deg); + } + 100% { + transform: translate(-50%, -65%) rotate(360deg); + } +} + +.shui::before { + content: ''; + position: absolute; + top: 20%; + left: 50%; + width: 150%; + height: 150%; + border-radius: 42%; + background-color: rgb(240, 228, 228, 0.2); + animation: xu 7s linear infinite; +} + +@keyframes xu { + 0% { + transform: translate(-50%, -60%) rotate(0deg); + } + 100% { + transform: translate(-50%, -60%) rotate(360deg); + } +} + +fieldset.data_src div.wrap label { + background: #f8bffee0 !important; +} + +.scrollable-component { + max-height: 100px; + overflow-y: auto; +} + +#file_accordion { + max-height: 220px !important; +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/html/footer.html b/xinference/thirdparty/fish_speech/fish_speech/webui/html/footer.html new file mode 100644 index 0000000000..ac1745aa6f --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/webui/html/footer.html @@ -0,0 +1,11 @@ +
+ API +  •  + Github +  •  + Gradio +
+
+
+{versions} +
diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/js/animate.js b/xinference/thirdparty/fish_speech/fish_speech/webui/js/animate.js new file mode 100644 index 0000000000..0637a541a8 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/webui/js/animate.js @@ -0,0 +1,69 @@ + +function createGradioAnimation() { + const params = new URLSearchParams(window.location.search); + if (!params.has('__theme')) { + params.set('__theme', 'light'); + window.location.search = params.toString(); + } + + var gradioApp = document.querySelector('gradio-app'); + if (gradioApp) { + + document.documentElement.style.setProperty('--my-200', '#80eeee'); + document.documentElement.style.setProperty('--my-50', '#ecfdf5'); + + // gradioApp.style.position = 'relative'; + // gradioApp.style.backgroundSize = '200% 200%'; + // gradioApp.style.animation = 'moveJellyBackground 10s ease infinite'; + // gradioApp.style.backgroundImage = 'radial-gradient(circle at 0% 50%, var(--my-200), var(--my-50) 50%)'; + // gradioApp.style.display = 'flex'; + // gradioApp.style.justifyContent = 'flex-start'; + // gradioApp.style.flexWrap = 'nowrap'; + // gradioApp.style.overflowX = 'auto'; + + // for (let i = 0; i < 6; i++) { + // var quan = document.createElement('div'); + // quan.className = 'quan'; + // gradioApp.insertBefore(quan, gradioApp.firstChild); + // quan.id = 'quan' + i.toString(); + // quan.style.left = 'calc(var(--water-width) * ' + i.toString() + ')'; + // var quanContainer = document.querySelector('.quan'); + // if (quanContainer) { + // var shui = document.createElement('div'); + // shui.className = 'shui'; + // quanContainer.insertBefore(shui, quanContainer.firstChild) + // } + // } + } + + var container = document.createElement('div'); + container.id = 'gradio-animation'; + container.style.fontSize = '2em'; + container.style.fontFamily = 'Maiandra GD, ui-monospace, monospace'; + container.style.fontWeight = 'bold'; + container.style.textAlign = 'center'; + container.style.marginBottom = '20px'; + + var text = 'Welcome to Fish-Speech!'; + for (var i = 0; i < text.length; i++) { + (function(i){ + setTimeout(function(){ + var letter = document.createElement('span'); + letter.style.opacity = '0'; + letter.style.transition = 'opacity 0.5s'; + letter.innerText = text[i]; + + container.appendChild(letter); + + setTimeout(function() { + letter.style.opacity = '1'; + }, 50); + }, i * 200); + })(i); + } + + var gradioContainer = document.querySelector('.gradio-container'); + gradioContainer.insertBefore(container, gradioContainer.firstChild); + + return 'Animation created'; +} diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/launch_utils.py b/xinference/thirdparty/fish_speech/fish_speech/webui/launch_utils.py new file mode 100644 index 0000000000..2f57b595a2 --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/webui/launch_utils.py @@ -0,0 +1,120 @@ +import importlib.util +import os +import subprocess +import sys +from functools import lru_cache +from pathlib import Path +from typing import Iterable + +import gradio as gr +from gradio.themes.base import Base +from gradio.themes.utils import colors, fonts, sizes + +GIT = ( + (Path(os.environ.get("GIT_HOME", "")) / "git").resolve() + if sys.platform == "win32" + else "git" +) +GIT = str(GIT) + + +def is_module_installed(module_name: str) -> bool: + spec = importlib.util.find_spec(module_name) + return spec is not None + + +@lru_cache() +def commit_hash(): + try: + return subprocess.check_output( + [GIT, "log", "-1", "--format='%h %s'"], shell=False, encoding="utf8" + ).strip() + except Exception: + return "" + + +def versions_html(): + import torch + + python_version = ".".join([str(x) for x in sys.version_info[0:3]]) + commit = commit_hash() + hash = commit.strip("'").split(" ")[0] + + return f""" +version: {hash} + •  +python: {python_version} + •  +torch: {getattr(torch, '__long_version__',torch.__version__)} + •  +gradio: {gr.__version__} + •  +author: fishaudio +""" + + +def version_check(commit): + try: + import requests + + commits = requests.get( + "https://api.github.com/repos/fishaudio/fish-speech/branches/main" + ).json() + if commit != "" and commits["commit"]["sha"] != commit: + print("--------------------------------------------------------") + print("| You are not up to date with the most recent release. |") + print("| Consider running `git pull` to update. |") + print("--------------------------------------------------------") + elif commits["commit"]["sha"] == commit: + print("You are up to date with the most recent release.") + else: + print("Not a git clone, can't perform version check.") + except Exception as e: + print("version check failed", e) + + +class Seafoam(Base): + def __init__( + self, + *, + primary_hue: colors.Color | str = colors.emerald, + secondary_hue: colors.Color | str = colors.blue, + neutral_hue: colors.Color | str = colors.blue, + spacing_size: sizes.Size | str = sizes.spacing_md, + radius_size: sizes.Size | str = sizes.radius_md, + text_size: sizes.Size | str = sizes.text_lg, + font: fonts.Font | str | Iterable[fonts.Font | str] = ( + fonts.GoogleFont("Quicksand"), + "ui-sans-serif", + "sans-serif", + ), + font_mono: fonts.Font | str | Iterable[fonts.Font | str] = ( + fonts.GoogleFont("IBM Plex Mono"), + "ui-monospace", + "monospace", + ), + ): + super().__init__( + primary_hue=primary_hue, + secondary_hue=secondary_hue, + neutral_hue=neutral_hue, + spacing_size=spacing_size, + radius_size=radius_size, + text_size=text_size, + font=font, + font_mono=font_mono, + ) + super().set( + button_primary_background_fill="linear-gradient(90deg, *primary_300, *secondary_400)", + button_primary_background_fill_hover="linear-gradient(90deg, *primary_200, *secondary_300)", + button_primary_text_color="white", + button_primary_background_fill_dark="linear-gradient(90deg, *primary_600, *secondary_800)", + slider_color="*secondary_300", + slider_color_dark="*secondary_600", + block_title_text_weight="600", + block_border_width="3px", + block_shadow="*shadow_drop_lg", + button_shadow="*shadow_drop_lg", + button_small_padding="0px", + button_large_padding="3px", + ) diff --git a/xinference/thirdparty/fish_speech/fish_speech/webui/manage.py b/xinference/thirdparty/fish_speech/fish_speech/webui/manage.py new file mode 100644 index 0000000000..9c183acd7c --- /dev/null +++ b/xinference/thirdparty/fish_speech/fish_speech/webui/manage.py @@ -0,0 +1,1237 @@ +from __future__ import annotations + +import datetime +import html +import json +import os +import platform +import shutil +import signal +import subprocess +import sys +from pathlib import Path + +import gradio as gr +import psutil +import yaml +from loguru import logger +from tqdm import tqdm + +PYTHON = os.path.join(os.environ.get("PYTHON_FOLDERPATH", ""), "python") +sys.path.insert(0, "") +print(sys.path) +cur_work_dir = Path(os.getcwd()).resolve() +print("You are in ", str(cur_work_dir)) + +from fish_speech.i18n import i18n +from fish_speech.webui.launch_utils import Seafoam, is_module_installed, versions_html + +config_path = cur_work_dir / "fish_speech" / "configs" +vqgan_yml_path = config_path / "firefly_gan_vq.yaml" +llama_yml_path = config_path / "text2semantic_finetune.yaml" + +env = os.environ.copy() +env["no_proxy"] = "127.0.0.1, localhost, 0.0.0.0" + +seafoam = Seafoam() + + +def build_html_error_message(error): + return f""" +
+ {html.escape(error)} +
+ """ + + +def build_html_ok_message(msg): + return f""" +
+ {html.escape(msg)} +
+ """ + + +def build_html_href(link, desc, msg): + return f""" + + {html.escape(msg)} + {desc} + + """ + + +def load_data_in_raw(path): + with open(path, "r", encoding="utf-8") as file: + data = file.read() + return str(data) + + +def kill_proc_tree(pid, including_parent=True): + try: + parent = psutil.Process(pid) + except psutil.NoSuchProcess: + # Process already terminated + return + + children = parent.children(recursive=True) + for child in children: + try: + os.kill(child.pid, signal.SIGTERM) # or signal.SIGKILL + except OSError: + pass + if including_parent: + try: + os.kill(parent.pid, signal.SIGTERM) # or signal.SIGKILL + except OSError: + pass + + +system = platform.system() +p_label = None +p_infer = None +p_tensorboard = None + + +def kill_process(pid): + if system == "Windows": + cmd = "taskkill /t /f /pid %s" % pid + # os.system(cmd) + subprocess.run(cmd) + else: + kill_proc_tree(pid) + + +def change_label(if_label): + global p_label + if if_label == True and p_label is None: + url = "http://localhost:3000" + remote_url = "https://text-labeler.pages.dev/" + try: + p_label = subprocess.Popen( + [ + ( + "asr-label-linux-x64" + if sys.platform == "linux" + else "asr-label-win-x64.exe" + ) + ] + ) + except FileNotFoundError: + logger.warning("asr-label execution not found!") + + yield build_html_href( + link=remote_url, + desc=i18n("Optional online ver"), + msg=i18n("Opened labeler in browser"), + ) + + elif if_label == False and p_label is not None: + kill_process(p_label.pid) + p_label = None + yield build_html_ok_message("Nothing") + + +def clean_infer_cache(): + import tempfile + + temp_dir = Path(tempfile.gettempdir()) + gradio_dir = str(temp_dir / "gradio") + try: + shutil.rmtree(gradio_dir) + logger.info(f"Deleted cached audios: {gradio_dir}") + except PermissionError: + logger.info(f"Permission denied: Unable to delete {gradio_dir}") + except FileNotFoundError: + logger.info(f"{gradio_dir} was not found") + except Exception as e: + logger.info(f"An error occurred: {e}") + + +def change_infer( + if_infer, + host, + port, + infer_decoder_model, + infer_decoder_config, + infer_llama_model, + infer_compile, +): + global p_infer + if if_infer == True and p_infer == None: + env = os.environ.copy() + + env["GRADIO_SERVER_NAME"] = host + env["GRADIO_SERVER_PORT"] = port + # 启动第二个进程 + url = f"http://{host}:{port}" + yield build_html_ok_message( + i18n("Inferring interface is launched at {}").format(url) + ) + + clean_infer_cache() + + p_infer = subprocess.Popen( + [ + PYTHON, + "tools/webui.py", + "--decoder-checkpoint-path", + infer_decoder_model, + "--decoder-config-name", + infer_decoder_config, + "--llama-checkpoint-path", + infer_llama_model, + ] + + (["--compile"] if infer_compile == "Yes" else []), + env=env, + ) + + elif if_infer == False and p_infer is not None: + kill_process(p_infer.pid) + p_infer = None + yield build_html_error_message(i18n("Infer interface is closed")) + + +js = load_data_in_raw("fish_speech/webui/js/animate.js") +css = load_data_in_raw("fish_speech/webui/css/style.css") + +data_pre_output = (cur_work_dir / "data").resolve() +default_model_output = (cur_work_dir / "results").resolve() +default_filelist = data_pre_output / "detect.list" +data_pre_output.mkdir(parents=True, exist_ok=True) + +items = [] +dict_items = {} + + +def load_yaml_data_in_fact(yml_path): + with open(yml_path, "r", encoding="utf-8") as file: + yml = yaml.safe_load(file) + return yml + + +def write_yaml_data_in_fact(yml, yml_path): + with open(yml_path, "w", encoding="utf-8") as file: + yaml.safe_dump(yml, file, allow_unicode=True) + return yml + + +def generate_tree(directory, depth=0, max_depth=None, prefix=""): + if max_depth is not None and depth > max_depth: + return "" + + tree_str = "" + files = [] + directories = [] + for item in os.listdir(directory): + if os.path.isdir(os.path.join(directory, item)): + directories.append(item) + else: + files.append(item) + + entries = directories + files + for i, entry in enumerate(entries): + connector = "├── " if i < len(entries) - 1 else "└── " + tree_str += f"{prefix}{connector}{entry}
" + if i < len(directories): + extension = "│ " if i < len(entries) - 1 else " " + tree_str += generate_tree( + os.path.join(directory, entry), + depth + 1, + max_depth, + prefix=prefix + extension, + ) + return tree_str + + +def new_explorer(data_path, max_depth): + return gr.Markdown( + elem_classes=["scrollable-component"], + value=generate_tree(data_path, max_depth=max_depth), + ) + + +def add_item( + folder: str, + method: str, + label_lang: str, + if_initial_prompt: bool, + initial_prompt: str | None, +): + folder = folder.strip(" ").strip('"') + + folder_path = Path(folder) + + if folder and folder not in items and data_pre_output not in folder_path.parents: + if folder_path.is_dir(): + items.append(folder) + dict_items[folder] = dict( + type="folder", + method=method, + label_lang=label_lang, + initial_prompt=initial_prompt if if_initial_prompt else None, + ) + elif folder: + err = folder + return gr.Checkboxgroup(choices=items), build_html_error_message( + i18n("Invalid path: {}").format(err) + ) + + formatted_data = json.dumps(dict_items, ensure_ascii=False, indent=4) + logger.info("After Adding: " + formatted_data) + gr.Info(formatted_data) + return gr.Checkboxgroup(choices=items), build_html_ok_message( + i18n("Added path successfully!") + ) + + +def remove_items(selected_items): + global items, dict_items + to_remove = [item for item in items if item in selected_items] + for item in to_remove: + del dict_items[item] + items = [item for item in items if item in dict_items.keys()] + formatted_data = json.dumps(dict_items, ensure_ascii=False, indent=4) + logger.info(formatted_data) + gr.Warning("After Removing: " + formatted_data) + return gr.Checkboxgroup(choices=items, value=[]), build_html_ok_message( + i18n("Removed path successfully!") + ) + + +def show_selected(options): + selected_options = ", ".join(options) + + if options: + return i18n("Selected: {}").format(selected_options) + else: + return i18n("No selected options") + + +from pydub import AudioSegment + + +def convert_to_mono_in_place(audio_path: Path): + audio = AudioSegment.from_file(audio_path) + if audio.channels > 1: + mono_audio = audio.set_channels(1) + mono_audio.export(audio_path, format=audio_path.suffix[1:]) + logger.info(f"Convert {audio_path} successfully") + + +def list_copy(list_file_path, method): + wav_root = data_pre_output + lst = [] + with list_file_path.open("r", encoding="utf-8") as file: + for line in tqdm(file, desc="Processing audio/transcript"): + wav_path, speaker_name, language, text = line.strip().split("|") + original_wav_path = Path(wav_path) + target_wav_path = ( + wav_root / original_wav_path.parent.name / original_wav_path.name + ) + lst.append(f"{target_wav_path}|{speaker_name}|{language}|{text}") + if target_wav_path.is_file(): + continue + target_wav_path.parent.mkdir(parents=True, exist_ok=True) + if method == i18n("Copy"): + shutil.copy(original_wav_path, target_wav_path) + else: + shutil.move(original_wav_path, target_wav_path.parent) + convert_to_mono_in_place(target_wav_path) + original_lab_path = original_wav_path.with_suffix(".lab") + target_lab_path = ( + wav_root + / original_wav_path.parent.name + / original_wav_path.with_suffix(".lab").name + ) + if target_lab_path.is_file(): + continue + if method == i18n("Copy"): + shutil.copy(original_lab_path, target_lab_path) + else: + shutil.move(original_lab_path, target_lab_path.parent) + + if method == i18n("Move"): + with list_file_path.open("w", encoding="utf-8") as file: + file.writelines("\n".join(lst)) + + del lst + return build_html_ok_message(i18n("Use filelist")) + + +def check_files(data_path: str, max_depth: int, label_model: str, label_device: str): + global dict_items + data_path = Path(data_path) + gr.Warning("Pre-processing begins...") + for item, content in dict_items.items(): + item_path = Path(item) + tar_path = data_path / item_path.name + + if content["type"] == "folder" and item_path.is_dir(): + if content["method"] == i18n("Copy"): + os.makedirs(tar_path, exist_ok=True) + shutil.copytree( + src=str(item_path), dst=str(tar_path), dirs_exist_ok=True + ) + elif not tar_path.is_dir(): + shutil.move(src=str(item_path), dst=str(tar_path)) + + for suf in ["wav", "flac", "mp3"]: + for audio_path in tar_path.glob(f"**/*.{suf}"): + convert_to_mono_in_place(audio_path) + + cur_lang = content["label_lang"] + initial_prompt = content["initial_prompt"] + + transcribe_cmd = [ + PYTHON, + "tools/whisper_asr.py", + "--model-size", + label_model, + "--device", + label_device, + "--audio-dir", + tar_path, + "--save-dir", + tar_path, + "--language", + cur_lang, + ] + + if initial_prompt is not None: + transcribe_cmd += ["--initial-prompt", initial_prompt] + + if cur_lang != "IGNORE": + try: + gr.Warning("Begin To Transcribe") + subprocess.run( + transcribe_cmd, + env=env, + ) + except Exception: + print("Transcription error occurred") + + elif content["type"] == "file" and item_path.is_file(): + list_copy(item_path, content["method"]) + + return build_html_ok_message(i18n("Move files successfully")), new_explorer( + data_path, max_depth=max_depth + ) + + +def generate_folder_name(): + now = datetime.datetime.now() + folder_name = now.strftime("%Y%m%d_%H%M%S") + return folder_name + + +def train_process( + data_path: str, + option: str, + # llama config + llama_ckpt, + llama_base_config, + llama_lr, + llama_maxsteps, + llama_data_num_workers, + llama_data_batch_size, + llama_data_max_length, + llama_precision, + llama_check_interval, + llama_grad_batches, + llama_use_speaker, + llama_use_lora, +): + + backend = "nccl" if sys.platform == "linux" else "gloo" + + new_project = generate_folder_name() + print("New Project Name: ", new_project) + + if option == "VQGAN": + msg = "Skipped VQGAN Training." + gr.Warning(msg) + logger.info(msg) + + if option == "LLAMA": + msg = "LLAMA Training begins..." + gr.Warning(msg) + logger.info(msg) + subprocess.run( + [ + PYTHON, + "tools/vqgan/extract_vq.py", + str(data_pre_output), + "--num-workers", + "1", + "--batch-size", + "16", + "--config-name", + "firefly_gan_vq", + "--checkpoint-path", + "checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + ] + ) + + subprocess.run( + [ + PYTHON, + "tools/llama/build_dataset.py", + "--input", + str(data_pre_output), + "--text-extension", + ".lab", + "--num-workers", + "16", + ] + ) + ckpt_path = "checkpoints/fish-speech-1.2-sft/model.pth" + lora_prefix = "lora_" if llama_use_lora else "" + llama_name = lora_prefix + "text2semantic_" + new_project + latest = next( + iter( + sorted( + [ + str(p.relative_to("results")) + for p in Path("results").glob(lora_prefix + "text2sem*/") + ], + reverse=True, + ) + ), + llama_name, + ) + project = ( + llama_name + if llama_ckpt == i18n("new") + else ( + latest + if llama_ckpt == i18n("latest") + else Path(llama_ckpt).relative_to("results") + ) + ) + logger.info(project) + + if llama_check_interval > llama_maxsteps: + llama_check_interval = llama_maxsteps + + train_cmd = [ + PYTHON, + "fish_speech/train.py", + "--config-name", + "text2semantic_finetune", + f"project={project}", + f"trainer.strategy.process_group_backend={backend}", + f"train_dataset.proto_files={str(['data/quantized-dataset-ft'])}", + f"val_dataset.proto_files={str(['data/quantized-dataset-ft'])}", + f"model.optimizer.lr={llama_lr}", + f"trainer.max_steps={llama_maxsteps}", + f"data.num_workers={llama_data_num_workers}", + f"data.batch_size={llama_data_batch_size}", + f"max_length={llama_data_max_length}", + f"trainer.precision={llama_precision}", + f"trainer.val_check_interval={llama_check_interval}", + f"trainer.accumulate_grad_batches={llama_grad_batches}", + f"train_dataset.interactive_prob={llama_use_speaker}", + ] + ([f"+lora@model.model.lora_config=r_8_alpha_16"] if llama_use_lora else []) + logger.info(train_cmd) + subprocess.run(train_cmd) + + return build_html_ok_message(i18n("Training stopped")) + + +def tensorboard_process( + if_tensorboard: bool, + tensorboard_dir: str, + host: str, + port: str, +): + global p_tensorboard + if if_tensorboard == True and p_tensorboard == None: + url = f"http://{host}:{port}" + yield build_html_ok_message( + i18n("Tensorboard interface is launched at {}").format(url) + ) + prefix = ["tensorboard"] + if Path("fishenv").exists(): + prefix = ["fishenv/env/python.exe", "fishenv/env/Scripts/tensorboard.exe"] + + p_tensorboard = subprocess.Popen( + prefix + + [ + "--logdir", + tensorboard_dir, + "--host", + host, + "--port", + port, + "--reload_interval", + "120", + ] + ) + elif if_tensorboard == False and p_tensorboard != None: + kill_process(p_tensorboard.pid) + p_tensorboard = None + yield build_html_error_message(i18n("Tensorboard interface is closed")) + + +def fresh_tb_dir(): + return gr.Dropdown( + choices=[str(p) for p in Path("results").glob("**/tensorboard/")] + ) + + +def list_decoder_models(): + paths = [str(p) for p in Path("checkpoints").glob("fish*/firefly*.pth")] + if not paths: + logger.warning("No decoder model found") + return paths + + +def list_llama_models(): + choices = [str(p.parent) for p in Path("checkpoints").glob("merged*/*model*.pth")] + choices += [str(p.parent) for p in Path("checkpoints").glob("fish*/*model*.pth")] + choices += [str(p.parent) for p in Path("checkpoints").glob("fs*/*model*.pth")] + choices = sorted(choices, reverse=True) + if not choices: + logger.warning("No LLaMA model found") + return choices + + +def list_lora_llama_models(): + choices = sorted( + [str(p) for p in Path("results").glob("lora*/**/*.ckpt")], reverse=True + ) + if not choices: + logger.warning("No LoRA LLaMA model found") + return choices + + +def fresh_decoder_model(): + return gr.Dropdown(choices=list_decoder_models()) + + +def fresh_llama_ckpt(llama_use_lora): + return gr.Dropdown( + choices=[i18n("latest"), i18n("new")] + + ( + [str(p) for p in Path("results").glob("text2sem*/")] + if not llama_use_lora + else [str(p) for p in Path("results").glob("lora_*/")] + ) + ) + + +def fresh_llama_model(): + return gr.Dropdown(choices=list_llama_models()) + + +def llama_lora_merge(llama_weight, lora_llama_config, lora_weight, llama_lora_output): + if ( + lora_weight is None + or not Path(lora_weight).exists() + or not Path(llama_weight).exists() + ): + return build_html_error_message( + i18n( + "Path error, please check the model file exists in the corresponding path" + ) + ) + gr.Warning("Merging begins...") + merge_cmd = [ + PYTHON, + "tools/llama/merge_lora.py", + "--lora-config", + "r_8_alpha_16", + "--lora-weight", + lora_weight, + "--output", + llama_lora_output + "_" + generate_folder_name(), + ] + logger.info(merge_cmd) + subprocess.run(merge_cmd) + return build_html_ok_message(i18n("Merge successfully")) + + +def llama_quantify(llama_weight, quantify_mode): + if llama_weight is None or not Path(llama_weight).exists(): + return build_html_error_message( + i18n( + "Path error, please check the model file exists in the corresponding path" + ) + ) + + gr.Warning("Quantifying begins...") + + now = generate_folder_name() + quantify_cmd = [ + PYTHON, + "tools/llama/quantize.py", + "--checkpoint-path", + llama_weight, + "--mode", + quantify_mode, + "--timestamp", + now, + ] + logger.info(quantify_cmd) + subprocess.run(quantify_cmd) + if quantify_mode == "int8": + quantize_path = str( + Path(os.getcwd()) / "checkpoints" / f"fs-1.2-{quantify_mode}-{now}" + ) + else: + quantize_path = str( + Path(os.getcwd()) / "checkpoints" / f"fs-1.2-{quantify_mode}-g128-{now}" + ) + return build_html_ok_message( + i18n("Quantify successfully") + f"Path: {quantize_path}" + ) + + +init_vqgan_yml = load_yaml_data_in_fact(vqgan_yml_path) +init_llama_yml = load_yaml_data_in_fact(llama_yml_path) + +with gr.Blocks( + head="", + js=js, + theme=seafoam, + analytics_enabled=False, + title="Fish Speech", +) as demo: + with gr.Row(): + with gr.Column(): + with gr.Tab("\U0001F4D6 " + i18n("Data Preprocessing")): + with gr.Row(): + textbox = gr.Textbox( + label="\U0000270F " + + i18n("Input Audio & Source Path for Transcription"), + info=i18n("Speaker is identified by the folder name"), + interactive=True, + ) + with gr.Row(equal_height=False): + with gr.Column(): + output_radio = gr.Radio( + label="\U0001F4C1 " + + i18n("Select source file processing method"), + choices=[i18n("Copy"), i18n("Move")], + value=i18n("Copy"), + interactive=True, + ) + with gr.Column(): + error = gr.HTML(label=i18n("Error Message")) + if_label = gr.Checkbox( + label=i18n("Open Labeler WebUI"), scale=0, show_label=True + ) + + with gr.Row(): + label_device = gr.Dropdown( + label=i18n("Labeling Device"), + info=i18n( + "It is recommended to use CUDA, if you have low configuration, use CPU" + ), + choices=["cpu", "cuda"], + value="cuda", + interactive=True, + ) + label_model = gr.Dropdown( + label=i18n("Whisper Model"), + info=i18n("Faster Whisper, Up to 5g GPU memory usage"), + choices=["large-v3", "medium"], + value="large-v3", + interactive=True, + ) + label_radio = gr.Dropdown( + label=i18n("Optional Label Language"), + info=i18n( + "If there is no corresponding text for the audio, apply ASR for assistance, support .txt or .lab format" + ), + choices=[ + (i18n("Chinese"), "zh"), + (i18n("English"), "en"), + (i18n("Japanese"), "ja"), + (i18n("Disabled"), "IGNORE"), + (i18n("auto"), "auto"), + ], + value="IGNORE", + interactive=True, + ) + + with gr.Row(): + if_initial_prompt = gr.Checkbox( + value=False, + label=i18n("Enable Initial Prompt"), + min_width=120, + scale=0, + ) + initial_prompt = gr.Textbox( + label=i18n("Initial Prompt"), + info=i18n( + "Initial prompt can provide contextual or vocabulary-specific guidance to the model." + ), + placeholder="This audio introduces the basic concepts and applications of artificial intelligence and machine learning.", + interactive=False, + ) + + with gr.Row(): + add_button = gr.Button( + "\U000027A1 " + i18n("Add to Processing Area"), + variant="primary", + ) + remove_button = gr.Button( + "\U000026D4 " + i18n("Remove Selected Data") + ) + + with gr.Tab("\U0001F6E0 " + i18n("Training Configuration")): + with gr.Row(): + model_type_radio = gr.Radio( + label=i18n( + "Select the model to be trained (Depending on the Tab page you are on)" + ), + interactive=False, + choices=["VQGAN", "LLAMA"], + value="VQGAN", + ) + with gr.Row(): + with gr.Tabs(): + with gr.Tab(label=i18n("VQGAN Configuration")) as vqgan_page: + gr.HTML("You don't need to train this model!") + + with gr.Tab(label=i18n("LLAMA Configuration")) as llama_page: + with gr.Row(equal_height=False): + llama_use_lora = gr.Checkbox( + label=i18n("Use LoRA"), + info=i18n( + "Use LoRA can save GPU memory, but may reduce the quality of the model" + ), + value=True, + interactive=True, + ) + llama_ckpt = gr.Dropdown( + label=i18n("Select LLAMA ckpt"), + choices=[i18n("latest"), i18n("new")] + + [ + str(p) + for p in Path("results").glob("text2sem*/") + ] + + [str(p) for p in Path("results").glob("lora*/")], + value=i18n("latest"), + interactive=True, + ) + with gr.Row(equal_height=False): + llama_lr_slider = gr.Slider( + label=i18n("Initial Learning Rate"), + info=i18n( + "lr smaller -> usually train slower but more stable" + ), + interactive=True, + minimum=1e-5, + maximum=1e-4, + step=1e-5, + value=5e-5, + ) + llama_maxsteps_slider = gr.Slider( + label=i18n("Maximum Training Steps"), + info=i18n( + "recommend: max_steps = num_audios // batch_size * (2 to 5)" + ), + interactive=True, + minimum=1, + maximum=10000, + step=1, + value=50, + ) + with gr.Row(equal_height=False): + llama_base_config = gr.Dropdown( + label=i18n("Model Size"), + choices=[ + "text2semantic_finetune", + ], + value="text2semantic_finetune", + ) + llama_data_num_workers_slider = gr.Slider( + label=i18n("Number of Workers"), + minimum=1, + maximum=32, + step=1, + value=4, + ) + with gr.Row(equal_height=False): + llama_data_batch_size_slider = gr.Slider( + label=i18n("Batch Size"), + interactive=True, + minimum=1, + maximum=32, + step=1, + value=4, + ) + llama_data_max_length_slider = gr.Slider( + label=i18n("Maximum Length per Sample"), + interactive=True, + minimum=1024, + maximum=4096, + step=128, + value=1024, + ) + with gr.Row(equal_height=False): + llama_precision_dropdown = gr.Dropdown( + label=i18n("Precision"), + info=i18n( + "bf16-true is recommended for 30+ series GPU, 16-mixed is recommended for 10+ series GPU" + ), + interactive=True, + choices=["32", "bf16-true", "16-mixed"], + value="bf16-true", + ) + llama_check_interval_slider = gr.Slider( + label=i18n("Save model every n steps"), + info=i18n( + "make sure that it's not greater than max_steps" + ), + interactive=True, + minimum=1, + maximum=1000, + step=1, + value=50, + ) + with gr.Row(equal_height=False): + llama_grad_batches = gr.Slider( + label=i18n("Accumulate Gradient Batches"), + interactive=True, + minimum=1, + maximum=20, + step=1, + value=init_llama_yml["trainer"][ + "accumulate_grad_batches" + ], + ) + llama_use_speaker = gr.Slider( + label=i18n( + "Probability of applying Speaker Condition" + ), + interactive=True, + minimum=0.1, + maximum=1.0, + step=0.05, + value=init_llama_yml["train_dataset"][ + "interactive_prob" + ], + ) + + with gr.Tab(label=i18n("Merge LoRA"), id=4): + with gr.Row(equal_height=False): + llama_weight = gr.Dropdown( + label=i18n("Base LLAMA Model"), + info=i18n( + "Type the path or select from the dropdown" + ), + choices=[ + "checkpoints/fish-speech-1.2-sft/model.pth", + ], + value="checkpoints/fish-speech-1.2-sft/model.pth", + allow_custom_value=True, + interactive=True, + ) + with gr.Row(equal_height=False): + lora_weight = gr.Dropdown( + label=i18n("LoRA Model to be merged"), + info=i18n( + "Type the path or select from the dropdown" + ), + choices=[ + str(p) + for p in Path("results").glob("lora*/**/*.ckpt") + ], + allow_custom_value=True, + interactive=True, + ) + lora_llama_config = gr.Dropdown( + label=i18n("LLAMA Model Config"), + info=i18n( + "Type the path or select from the dropdown" + ), + choices=[ + "text2semantic_finetune", + ], + value="text2semantic_finetune", + allow_custom_value=True, + ) + with gr.Row(equal_height=False): + llama_lora_output = gr.Dropdown( + label=i18n("Output Path"), + info=i18n( + "Type the path or select from the dropdown" + ), + value="checkpoints/merged", + choices=["checkpoints/merged"], + allow_custom_value=True, + interactive=True, + ) + with gr.Row(equal_height=False): + llama_lora_merge_btn = gr.Button( + value=i18n("Merge"), variant="primary" + ) + + with gr.Tab(label=i18n("Model Quantization"), id=5): + with gr.Row(equal_height=False): + llama_weight_to_quantify = gr.Dropdown( + label=i18n("Base LLAMA Model"), + info=i18n( + "Type the path or select from the dropdown" + ), + choices=list_llama_models(), + value="checkpoints/fish-speech-1.2-sft", + allow_custom_value=True, + interactive=True, + ) + quantify_mode = gr.Dropdown( + label=i18n("Post-quantification Precision"), + info=i18n( + "The lower the quantitative precision, the more the effectiveness may decrease, but the greater the efficiency will increase" + ), + choices=["int8", "int4"], + value="int8", + allow_custom_value=False, + interactive=True, + ) + with gr.Row(equal_height=False): + llama_quantify_btn = gr.Button( + value=i18n("Quantify"), variant="primary" + ) + + with gr.Tab(label="Tensorboard", id=6): + with gr.Row(equal_height=False): + tb_host = gr.Textbox( + label=i18n("Tensorboard Host"), value="127.0.0.1" + ) + tb_port = gr.Textbox( + label=i18n("Tensorboard Port"), value="11451" + ) + with gr.Row(equal_height=False): + tb_dir = gr.Dropdown( + label=i18n("Tensorboard Log Path"), + allow_custom_value=True, + choices=[ + str(p) + for p in Path("results").glob("**/tensorboard/") + ], + ) + with gr.Row(equal_height=False): + if_tb = gr.Checkbox( + label=i18n("Open Tensorboard"), + ) + + with gr.Tab("\U0001F9E0 " + i18n("Inference Configuration")): + with gr.Column(): + with gr.Row(): + with gr.Accordion( + label="\U0001F5A5 " + + i18n("Inference Server Configuration"), + open=False, + ): + with gr.Row(): + infer_host_textbox = gr.Textbox( + label=i18n("WebUI Host"), value="127.0.0.1" + ) + infer_port_textbox = gr.Textbox( + label=i18n("WebUI Port"), value="7862" + ) + with gr.Row(): + infer_decoder_model = gr.Dropdown( + label=i18n("Decoder Model Path"), + info=i18n( + "Type the path or select from the dropdown" + ), + choices=list_decoder_models(), + value="checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + allow_custom_value=True, + ) + infer_decoder_config = gr.Dropdown( + label=i18n("Decoder Model Config"), + info=i18n("Changing with the Model Path"), + value="firefly_gan_vq", + choices=[ + "firefly_gan_vq", + ], + allow_custom_value=True, + ) + with gr.Row(): + infer_llama_model = gr.Dropdown( + label=i18n("LLAMA Model Path"), + info=i18n( + "Type the path or select from the dropdown" + ), + value="checkpoints/fish-speech-1.2-sft", + choices=list_llama_models(), + allow_custom_value=True, + ) + + with gr.Row(): + infer_compile = gr.Radio( + label=i18n("Compile Model"), + info=i18n( + "Compile the model can significantly reduce the inference time, but will increase cold start time" + ), + choices=["Yes", "No"], + value=( + "Yes" if (sys.platform == "linux") else "No" + ), + interactive=is_module_installed("triton"), + ) + + with gr.Row(): + infer_checkbox = gr.Checkbox( + label=i18n("Open Inference Server") + ) + infer_error = gr.HTML(label=i18n("Inference Server Error")) + + with gr.Column(): + train_error = gr.HTML(label=i18n("Training Error")) + checkbox_group = gr.CheckboxGroup( + label="\U0001F4CA " + i18n("Data Source"), + info=i18n( + "The path of the input folder on the left or the filelist. Whether checked or not, it will be used for subsequent training in this list." + ), + elem_classes=["data_src"], + ) + train_box = gr.Textbox( + label=i18n("Data Preprocessing Path"), + value=str(data_pre_output), + interactive=False, + ) + model_box = gr.Textbox( + label="\U0001F4BE " + i18n("Model Output Path"), + value=str(default_model_output), + interactive=False, + ) + + with gr.Accordion( + i18n( + "View the status of the preprocessing folder (use the slider to control the depth of the tree)" + ), + elem_classes=["scrollable-component"], + elem_id="file_accordion", + ): + tree_slider = gr.Slider( + minimum=0, + maximum=3, + value=0, + step=1, + show_label=False, + container=False, + ) + file_markdown = new_explorer(str(data_pre_output), 0) + with gr.Row(equal_height=False): + admit_btn = gr.Button( + "\U00002705 " + i18n("File Preprocessing"), + variant="primary", + ) + fresh_btn = gr.Button("\U0001F503", scale=0, min_width=80) + help_button = gr.Button("\U00002753", scale=0, min_width=80) # question + train_btn = gr.Button(i18n("Start Training"), variant="primary") + + footer = load_data_in_raw("fish_speech/webui/html/footer.html") + footer = footer.format( + versions=versions_html(), + api_docs="https://speech.fish.audio/inference/#http-api", + ) + gr.HTML(footer, elem_id="footer") + vqgan_page.select(lambda: "VQGAN", None, model_type_radio) + llama_page.select(lambda: "LLAMA", None, model_type_radio) + add_button.click( + fn=add_item, + inputs=[textbox, output_radio, label_radio, if_initial_prompt, initial_prompt], + outputs=[checkbox_group, error], + ) + remove_button.click( + fn=remove_items, inputs=[checkbox_group], outputs=[checkbox_group, error] + ) + checkbox_group.change(fn=show_selected, inputs=checkbox_group, outputs=[error]) + help_button.click( + fn=None, + js='() => { window.open("https://speech.fish.audio/", "newwindow", "height=100, width=400, ' + 'toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no")}', + ) + if_label.change(fn=change_label, inputs=[if_label], outputs=[error]) + if_initial_prompt.change( + fn=lambda x: gr.Textbox(value="", interactive=x), + inputs=[if_initial_prompt], + outputs=[initial_prompt], + ) + train_btn.click( + fn=train_process, + inputs=[ + train_box, + model_type_radio, + # llama config + llama_ckpt, + llama_base_config, + llama_lr_slider, + llama_maxsteps_slider, + llama_data_num_workers_slider, + llama_data_batch_size_slider, + llama_data_max_length_slider, + llama_precision_dropdown, + llama_check_interval_slider, + llama_grad_batches, + llama_use_speaker, + llama_use_lora, + ], + outputs=[train_error], + ) + if_tb.change( + fn=tensorboard_process, + inputs=[if_tb, tb_dir, tb_host, tb_port], + outputs=[train_error], + ) + tb_dir.change(fn=fresh_tb_dir, inputs=[], outputs=[tb_dir]) + infer_decoder_model.change( + fn=fresh_decoder_model, inputs=[], outputs=[infer_decoder_model] + ) + infer_llama_model.change( + fn=fresh_llama_model, inputs=[], outputs=[infer_llama_model] + ) + llama_weight.change(fn=fresh_llama_model, inputs=[], outputs=[llama_weight]) + admit_btn.click( + fn=check_files, + inputs=[train_box, tree_slider, label_model, label_device], + outputs=[error, file_markdown], + ) + fresh_btn.click( + fn=new_explorer, inputs=[train_box, tree_slider], outputs=[file_markdown] + ) + llama_use_lora.change( + fn=fresh_llama_ckpt, inputs=[llama_use_lora], outputs=[llama_ckpt] + ) + llama_ckpt.change( + fn=fresh_llama_ckpt, inputs=[llama_use_lora], outputs=[llama_ckpt] + ) + lora_weight.change( + fn=lambda: gr.Dropdown(choices=list_lora_llama_models()), + inputs=[], + outputs=[lora_weight], + ) + llama_lora_merge_btn.click( + fn=llama_lora_merge, + inputs=[llama_weight, lora_llama_config, lora_weight, llama_lora_output], + outputs=[train_error], + ) + llama_quantify_btn.click( + fn=llama_quantify, + inputs=[llama_weight_to_quantify, quantify_mode], + outputs=[train_error], + ) + infer_checkbox.change( + fn=change_infer, + inputs=[ + infer_checkbox, + infer_host_textbox, + infer_port_textbox, + infer_decoder_model, + infer_decoder_config, + infer_llama_model, + infer_compile, + ], + outputs=[infer_error], + ) + +demo.launch(inbrowser=True) diff --git a/xinference/thirdparty/fish_speech/tools/__init__.py b/xinference/thirdparty/fish_speech/tools/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/tools/api.py b/xinference/thirdparty/fish_speech/tools/api.py new file mode 100644 index 0000000000..29869b267f --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/api.py @@ -0,0 +1,495 @@ +import base64 +import io +import json +import queue +import random +import sys +import traceback +import wave +from argparse import ArgumentParser +from http import HTTPStatus +from pathlib import Path +from typing import Annotated, Literal, Optional + +import numpy as np +# import pyrootutils +import soundfile as sf +import torch +import torchaudio +# from kui.asgi import ( +# Body, +# HTTPException, +# HttpView, +# JSONResponse, +# Kui, +# OpenAPI, +# StreamResponse, +# ) +# from kui.asgi.routing import MultimethodRoutes +from loguru import logger +from pydantic import BaseModel, Field + +# pyrootutils.setup_root(__file__, indicator=".project-root", pythonpath=True) + +# from fish_speech.models.vqgan.lit_module import VQGAN +from fish_speech.models.vqgan.modules.firefly import FireflyArchitecture +from fish_speech.utils import autocast_exclude_mps +# from tools.auto_rerank import batch_asr, calculate_wer, is_chinese, load_model +from tools.llama.generate import ( + GenerateRequest, + GenerateResponse, + WrappedGenerateResponse, + launch_thread_safe_queue, +) +from tools.vqgan.inference import load_model as load_decoder_model + + +def wav_chunk_header(sample_rate=44100, bit_depth=16, channels=1): + buffer = io.BytesIO() + + with wave.open(buffer, "wb") as wav_file: + wav_file.setnchannels(channels) + wav_file.setsampwidth(bit_depth // 8) + wav_file.setframerate(sample_rate) + + wav_header_bytes = buffer.getvalue() + buffer.close() + return wav_header_bytes + + +# Define utils for web server +# async def http_execption_handler(exc: HTTPException): +# return JSONResponse( +# dict( +# statusCode=exc.status_code, +# message=exc.content, +# error=HTTPStatus(exc.status_code).phrase, +# ), +# exc.status_code, +# exc.headers, +# ) + + +async def other_exception_handler(exc: "Exception"): + traceback.print_exc() + + status = HTTPStatus.INTERNAL_SERVER_ERROR + return JSONResponse( + dict(statusCode=status, message=str(exc), error=status.phrase), + status, + ) + + +def load_audio(reference_audio, sr): + if len(reference_audio) > 255 or not Path(reference_audio).exists(): + try: + audio_data = base64.b64decode(reference_audio) + reference_audio = io.BytesIO(audio_data) + except base64.binascii.Error: + raise ValueError("Invalid path or base64 string") + + waveform, original_sr = torchaudio.load( + reference_audio, backend="sox" if sys.platform == "linux" else "soundfile" + ) + + if waveform.shape[0] > 1: + waveform = torch.mean(waveform, dim=0, keepdim=True) + + if original_sr != sr: + resampler = torchaudio.transforms.Resample(orig_freq=original_sr, new_freq=sr) + waveform = resampler(waveform) + + audio = waveform.squeeze().numpy() + return audio + + +def encode_reference(*, decoder_model, reference_audio, enable_reference_audio): + if enable_reference_audio and reference_audio is not None: + # Load audios, and prepare basic info here + reference_audio_content = load_audio( + reference_audio, decoder_model.spec_transform.sample_rate + ) + + audios = torch.from_numpy(reference_audio_content).to(decoder_model.device)[ + None, None, : + ] + audio_lengths = torch.tensor( + [audios.shape[2]], device=decoder_model.device, dtype=torch.long + ) + logger.info( + f"Loaded audio with {audios.shape[2] / decoder_model.spec_transform.sample_rate:.2f} seconds" + ) + + # VQ Encoder + if isinstance(decoder_model, FireflyArchitecture): + prompt_tokens = decoder_model.encode(audios, audio_lengths)[0][0] + + logger.info(f"Encoded prompt: {prompt_tokens.shape}") + else: + prompt_tokens = None + logger.info("No reference audio provided") + + return prompt_tokens + + +def decode_vq_tokens( + *, + decoder_model, + codes, +): + feature_lengths = torch.tensor([codes.shape[1]], device=decoder_model.device) + logger.info(f"VQ features: {codes.shape}") + + if isinstance(decoder_model, FireflyArchitecture): + # VQGAN Inference + return decoder_model.decode( + indices=codes[None], + feature_lengths=feature_lengths, + ).squeeze() + + raise ValueError(f"Unknown model type: {type(decoder_model)}") + + +# routes = MultimethodRoutes(base_class=HttpView) + + +def get_random_paths(base_path, data, speaker, emotion): + if base_path and data and speaker and emotion and (Path(base_path).exists()): + if speaker in data and emotion in data[speaker]: + files = data[speaker][emotion] + lab_files = [f for f in files if f.endswith(".lab")] + wav_files = [f for f in files if f.endswith(".wav")] + + if lab_files and wav_files: + selected_lab = random.choice(lab_files) + selected_wav = random.choice(wav_files) + + lab_path = Path(base_path) / speaker / emotion / selected_lab + wav_path = Path(base_path) / speaker / emotion / selected_wav + if lab_path.exists() and wav_path.exists(): + return lab_path, wav_path + + return None, None + + +def load_json(json_file): + if not json_file: + logger.info("Not using a json file") + return None + try: + with open(json_file, "r", encoding="utf-8") as file: + data = json.load(file) + except FileNotFoundError: + logger.warning(f"ref json not found: {json_file}") + data = None + except Exception as e: + logger.warning(f"Loading json failed: {e}") + data = None + return data + + +class InvokeRequest(BaseModel): + text: str = "你说的对, 但是原神是一款由米哈游自主研发的开放世界手游." + reference_text: Optional[str] = None + reference_audio: Optional[str] = None + max_new_tokens: int = 1024 + chunk_length: Annotated[int, Field(ge=0, le=500, strict=True)] = 100 + top_p: Annotated[float, Field(ge=0.1, le=1.0, strict=True)] = 0.7 + repetition_penalty: Annotated[float, Field(ge=0.9, le=2.0, strict=True)] = 1.2 + temperature: Annotated[float, Field(ge=0.1, le=1.0, strict=True)] = 0.7 + emotion: Optional[str] = None + format: Literal["wav", "mp3", "flac"] = "wav" + streaming: bool = False + ref_json: Optional[str] = "ref_data.json" + ref_base: Optional[str] = "ref_data" + speaker: Optional[str] = None + + +def get_content_type(audio_format): + if audio_format == "wav": + return "audio/wav" + elif audio_format == "flac": + return "audio/flac" + elif audio_format == "mp3": + return "audio/mpeg" + else: + return "application/octet-stream" + + +@torch.inference_mode() +def inference(req: InvokeRequest): + # Parse reference audio aka prompt + prompt_tokens = None + + ref_data = load_json(req.ref_json) + ref_base = req.ref_base + + lab_path, wav_path = get_random_paths(ref_base, ref_data, req.speaker, req.emotion) + + if lab_path and wav_path: + with open(lab_path, "r", encoding="utf-8") as lab_file: + ref_text = lab_file.read() + req.reference_audio = wav_path + req.reference_text = ref_text + logger.info("ref_path: " + str(wav_path)) + logger.info("ref_text: " + ref_text) + + # Parse reference audio aka prompt + prompt_tokens = encode_reference( + decoder_model=decoder_model, + reference_audio=req.reference_audio, + enable_reference_audio=req.reference_audio is not None, + ) + logger.info(f"ref_text: {req.reference_text}") + # LLAMA Inference + request = dict( + device=decoder_model.device, + max_new_tokens=req.max_new_tokens, + text=req.text, + top_p=req.top_p, + repetition_penalty=req.repetition_penalty, + temperature=req.temperature, + compile=args.compile, + iterative_prompt=req.chunk_length > 0, + chunk_length=req.chunk_length, + max_length=2048, + prompt_tokens=prompt_tokens, + prompt_text=req.reference_text, + ) + + response_queue = queue.Queue() + llama_queue.put( + GenerateRequest( + request=request, + response_queue=response_queue, + ) + ) + + if req.streaming: + yield wav_chunk_header() + + segments = [] + while True: + result: WrappedGenerateResponse = response_queue.get() + if result.status == "error": + raise result.response + break + + result: GenerateResponse = result.response + if result.action == "next": + break + + with autocast_exclude_mps( + device_type=decoder_model.device.type, dtype=args.precision + ): + fake_audios = decode_vq_tokens( + decoder_model=decoder_model, + codes=result.codes, + ) + + fake_audios = fake_audios.float().cpu().numpy() + + if req.streaming: + yield (fake_audios * 32768).astype(np.int16).tobytes() + else: + segments.append(fake_audios) + + if req.streaming: + return + + if len(segments) == 0: + raise HTTPException( + HTTPStatus.INTERNAL_SERVER_ERROR, + content="No audio generated, please check the input text.", + ) + + fake_audios = np.concatenate(segments, axis=0) + yield fake_audios + + +def auto_rerank_inference(req: InvokeRequest, use_auto_rerank: bool = True): + if not use_auto_rerank: + # 如果不使用 auto_rerank,直接调用原始的 inference 函数 + return inference(req) + + zh_model, en_model = load_model() + max_attempts = 5 + best_wer = float("inf") + best_audio = None + + for attempt in range(max_attempts): + # 调用原始的 inference 函数 + audio_generator = inference(req) + fake_audios = next(audio_generator) + + asr_result = batch_asr( + zh_model if is_chinese(req.text) else en_model, [fake_audios], 44100 + )[0] + wer = calculate_wer(req.text, asr_result["text"]) + + if wer <= 0.1 and not asr_result["huge_gap"]: + return fake_audios + + if wer < best_wer: + best_wer = wer + best_audio = fake_audios + + if attempt == max_attempts - 1: + break + + return best_audio + + +async def inference_async(req: InvokeRequest): + for chunk in inference(req): + yield chunk + + +async def buffer_to_async_generator(buffer): + yield buffer + + +# @routes.http.post("/v1/invoke") +# async def api_invoke_model( +# req: Annotated[InvokeRequest, Body(exclusive=True)], +# ): +# """ +# Invoke model and generate audio +# """ +# +# if args.max_text_length > 0 and len(req.text) > args.max_text_length: +# raise HTTPException( +# HTTPStatus.BAD_REQUEST, +# content=f"Text is too long, max length is {args.max_text_length}", +# ) +# +# if req.streaming and req.format != "wav": +# raise HTTPException( +# HTTPStatus.BAD_REQUEST, +# content="Streaming only supports WAV format", +# ) +# +# if req.streaming: +# return StreamResponse( +# iterable=inference_async(req), +# headers={ +# "Content-Disposition": f"attachment; filename=audio.{req.format}", +# }, +# content_type=get_content_type(req.format), +# ) +# else: +# fake_audios = next(inference(req)) +# buffer = io.BytesIO() +# sf.write( +# buffer, +# fake_audios, +# decoder_model.spec_transform.sample_rate, +# format=req.format, +# ) +# +# return StreamResponse( +# iterable=buffer_to_async_generator(buffer.getvalue()), +# headers={ +# "Content-Disposition": f"attachment; filename=audio.{req.format}", +# }, +# content_type=get_content_type(req.format), +# ) +# +# +# @routes.http.post("/v1/health") +# async def api_health(): +# """ +# Health check +# """ +# +# return JSONResponse({"status": "ok"}) + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument( + "--llama-checkpoint-path", + type=str, + default="checkpoints/fish-speech-1.2-sft", + ) + parser.add_argument( + "--decoder-checkpoint-path", + type=str, + default="checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + ) + parser.add_argument("--decoder-config-name", type=str, default="firefly_gan_vq") + parser.add_argument("--device", type=str, default="cuda") + parser.add_argument("--half", action="store_true") + parser.add_argument("--compile", action="store_true") + parser.add_argument("--max-text-length", type=int, default=0) + parser.add_argument("--listen", type=str, default="127.0.0.1:8000") + parser.add_argument("--workers", type=int, default=1) + parser.add_argument("--use-auto-rerank", type=bool, default=True) + + return parser.parse_args() + + +# Define Kui app +# openapi = OpenAPI( +# { +# "title": "Fish Speech API", +# }, +# ).routes +# +# app = Kui( +# routes=routes + openapi[1:], # Remove the default route +# exception_handlers={ +# HTTPException: http_execption_handler, +# Exception: other_exception_handler, +# }, +# cors_config={}, +# ) + + +if __name__ == "__main__": + import threading + + import uvicorn + + args = parse_args() + args.precision = torch.half if args.half else torch.bfloat16 + + logger.info("Loading Llama model...") + llama_queue = launch_thread_safe_queue( + checkpoint_path=args.llama_checkpoint_path, + device=args.device, + precision=args.precision, + compile=args.compile, + ) + logger.info("Llama model loaded, loading VQ-GAN model...") + + decoder_model = load_decoder_model( + config_name=args.decoder_config_name, + checkpoint_path=args.decoder_checkpoint_path, + device=args.device, + ) + + logger.info("VQ-GAN model loaded, warming up...") + + # Dry run to check if the model is loaded correctly and avoid the first-time latency + list( + inference( + InvokeRequest( + text="Hello world.", + reference_text=None, + reference_audio=None, + max_new_tokens=0, + top_p=0.7, + repetition_penalty=1.2, + temperature=0.7, + emotion=None, + format="wav", + ref_base=None, + ref_json=None, + ) + ) + ) + + logger.info(f"Warming up done, starting server at http://{args.listen}") + host, port = args.listen.split(":") + uvicorn.run(app, host=host, port=int(port), workers=args.workers, log_level="info") diff --git a/xinference/thirdparty/fish_speech/tools/auto_rerank.py b/xinference/thirdparty/fish_speech/tools/auto_rerank.py new file mode 100644 index 0000000000..0297d63d77 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/auto_rerank.py @@ -0,0 +1,159 @@ +import os + +os.environ["MODELSCOPE_CACHE"] = ".cache/" + +import string +import time +from threading import Lock + +import librosa +import numpy as np +import opencc +import torch +from faster_whisper import WhisperModel + +t2s_converter = opencc.OpenCC("t2s") + + +def load_model(*, device="cuda"): + model = WhisperModel( + "medium", + device=device, + compute_type="float16", + download_root="faster_whisper", + ) + print("faster_whisper loaded!") + return model + + +@torch.no_grad() +def batch_asr_internal(model: WhisperModel, audios, sr): + resampled_audios = [] + for audio in audios: + + if isinstance(audio, np.ndarray): + audio = torch.from_numpy(audio).float() + + if audio.dim() > 1: + audio = audio.squeeze() + + assert audio.dim() == 1 + audio_np = audio.numpy() + resampled_audio = librosa.resample(audio_np, orig_sr=sr, target_sr=16000) + resampled_audios.append(resampled_audio) + + trans_results = [] + + for resampled_audio in resampled_audios: + segments, info = model.transcribe( + resampled_audio, + language=None, + beam_size=5, + initial_prompt="Punctuation is needed in any language.", + ) + trans_results.append(list(segments)) + + results = [] + for trans_res, audio in zip(trans_results, audios): + + duration = len(audio) / sr * 1000 + huge_gap = False + max_gap = 0.0 + + text = None + last_tr = None + + for tr in trans_res: + delta = tr.text.strip() + if tr.id > 1: + max_gap = max(tr.start - last_tr.end, max_gap) + text += delta + else: + text = delta + + last_tr = tr + if max_gap > 3.0: + huge_gap = True + break + + sim_text = t2s_converter.convert(text) + results.append( + { + "text": sim_text, + "duration": duration, + "huge_gap": huge_gap, + } + ) + + return results + + +global_lock = Lock() + + +def batch_asr(model, audios, sr): + return batch_asr_internal(model, audios, sr) + + +def is_chinese(text): + return True + + +def calculate_wer(text1, text2, debug=False): + chars1 = remove_punctuation(text1) + chars2 = remove_punctuation(text2) + + m, n = len(chars1), len(chars2) + + if m > n: + chars1, chars2 = chars2, chars1 + m, n = n, m + + prev = list(range(m + 1)) # row 0 distance: [0, 1, 2, ...] + curr = [0] * (m + 1) + + for j in range(1, n + 1): + curr[0] = j + for i in range(1, m + 1): + if chars1[i - 1] == chars2[j - 1]: + curr[i] = prev[i - 1] + else: + curr[i] = min(prev[i], curr[i - 1], prev[i - 1]) + 1 + prev, curr = curr, prev + + edits = prev[m] + tot = max(len(chars1), len(chars2)) + wer = edits / tot + + if debug: + print(" gt: ", chars1) + print(" pred: ", chars2) + print(" edits/tot = wer: ", edits, "/", tot, "=", wer) + + return wer + + +def remove_punctuation(text): + chinese_punctuation = ( + " \n\t”“!?。。"#$%&'()*+,-/:;<=>@[\]^_`{|}~⦅⦆「」、、〃《》「」『』【】〔〕〖〗〘〙〚〛〜〝〞〟〰〾〿–—" + '‛""„‟…‧﹏' + ) + all_punctuation = string.punctuation + chinese_punctuation + translator = str.maketrans("", "", all_punctuation) + text_without_punctuation = text.translate(translator) + return text_without_punctuation + + +if __name__ == "__main__": + model = load_model() + audios = [ + librosa.load("44100.wav", sr=44100)[0], + librosa.load("lengyue.wav", sr=44100)[0], + ] + print(np.array(audios[0])) + print(batch_asr(model, audios, 44100)) + + start_time = time.time() + for _ in range(10): + print(batch_asr(model, audios, 44100)) + print("Time taken:", time.time() - start_time) diff --git a/xinference/thirdparty/fish_speech/tools/download_models.py b/xinference/thirdparty/fish_speech/tools/download_models.py new file mode 100644 index 0000000000..480f3be0f4 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/download_models.py @@ -0,0 +1,55 @@ +import os + +from huggingface_hub import hf_hub_download + + +# Download +def check_and_download_files(repo_id, file_list, local_dir): + os.makedirs(local_dir, exist_ok=True) + for file in file_list: + file_path = os.path.join(local_dir, file) + if not os.path.exists(file_path): + print(f"{file} 不存在,从 Hugging Face 仓库下载...") + hf_hub_download( + repo_id=repo_id, + filename=file, + resume_download=True, + local_dir=local_dir, + local_dir_use_symlinks=False, + ) + else: + print(f"{file} 已存在,跳过下载。") + + +# 1st +repo_id_1 = "fishaudio/fish-speech-1.2-sft" +local_dir_1 = "./checkpoints/fish-speech-1.2-sft" +files_1 = [ + "model.pth", + "README.md", + "special_tokens_map.json", + "tokenizer_config.json", + "tokenizer.json", + "config.json", + "firefly-gan-vq-fsq-4x1024-42hz-generator.pth", +] + +# 3rd +repo_id_3 = "fishaudio/fish-speech-1" +local_dir_3 = "./" +files_3 = [ + "ffmpeg.exe", + "ffprobe.exe", +] + +# 4th +repo_id_4 = "SpicyqSama007/fish-speech-packed" +local_dir_4 = "./" +files_4 = [ + "asr-label-win-x64.exe", +] + +check_and_download_files(repo_id_1, files_1, local_dir_1) + +check_and_download_files(repo_id_3, files_3, local_dir_3) +check_and_download_files(repo_id_4, files_4, local_dir_4) diff --git a/xinference/thirdparty/fish_speech/tools/extract_model.py b/xinference/thirdparty/fish_speech/tools/extract_model.py new file mode 100644 index 0000000000..97fe62507b --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/extract_model.py @@ -0,0 +1,21 @@ +import click +import torch +from loguru import logger + + +@click.command() +@click.argument("model_path") +@click.argument("output_path") +def main(model_path, output_path): + if model_path == output_path: + logger.error("Model path and output path are the same") + return + + logger.info(f"Loading model from {model_path}") + state_dict = torch.load(model_path, map_location="cpu")["state_dict"] + torch.save(state_dict, output_path) + logger.info(f"Model saved to {output_path}") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/file.py b/xinference/thirdparty/fish_speech/tools/file.py new file mode 100644 index 0000000000..b4b8051d6f --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/file.py @@ -0,0 +1,108 @@ +from pathlib import Path +from typing import Union + +from loguru import logger +from natsort import natsorted + +AUDIO_EXTENSIONS = { + ".mp3", + ".wav", + ".flac", + ".ogg", + ".m4a", + ".wma", + ".aac", + ".aiff", + ".aif", + ".aifc", +} + +VIDEO_EXTENSIONS = { + ".mp4", + ".avi", +} + + +def list_files( + path: Union[Path, str], + extensions: set[str] = None, + recursive: bool = False, + sort: bool = True, +) -> list[Path]: + """List files in a directory. + + Args: + path (Path): Path to the directory. + extensions (set, optional): Extensions to filter. Defaults to None. + recursive (bool, optional): Whether to search recursively. Defaults to False. + sort (bool, optional): Whether to sort the files. Defaults to True. + + Returns: + list: List of files. + """ + + if isinstance(path, str): + path = Path(path) + + if not path.exists(): + raise FileNotFoundError(f"Directory {path} does not exist.") + + files = [file for ext in extensions for file in path.rglob(f"*{ext}")] + + if sort: + files = natsorted(files) + + return files + + +def load_filelist(path: Path | str) -> list[tuple[Path, str, str, str]]: + """ + Load a Bert-VITS2 style filelist. + """ + + files = set() + results = [] + count_duplicated, count_not_found = 0, 0 + + LANGUAGE_TO_LANGUAGES = { + "zh": ["zh", "en"], + "jp": ["jp", "en"], + "en": ["en"], + } + + with open(path, "r", encoding="utf-8") as f: + for line in f.readlines(): + splits = line.strip().split("|", maxsplit=3) + if len(splits) != 4: + logger.warning(f"Invalid line: {line}") + continue + + filename, speaker, language, text = splits + file = Path(filename) + language = language.strip().lower() + + if language == "ja": + language = "jp" + + assert language in ["zh", "jp", "en"], f"Invalid language {language}" + languages = LANGUAGE_TO_LANGUAGES[language] + + if file in files: + logger.warning(f"Duplicated file: {file}") + count_duplicated += 1 + continue + + if not file.exists(): + logger.warning(f"File not found: {file}") + count_not_found += 1 + continue + + results.append((file, speaker, languages, text)) + + if count_duplicated > 0: + logger.warning(f"Total duplicated files: {count_duplicated}") + + if count_not_found > 0: + logger.warning(f"Total files not found: {count_not_found}") + + return results diff --git a/xinference/thirdparty/fish_speech/tools/gen_ref.py b/xinference/thirdparty/fish_speech/tools/gen_ref.py new file mode 100644 index 0000000000..a771903b02 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/gen_ref.py @@ -0,0 +1,36 @@ +import json +from pathlib import Path + + +def scan_folder(base_path): + wav_lab_pairs = {} + + base = Path(base_path) + for suf in ["wav", "lab"]: + for f in base.rglob(f"*.{suf}"): + relative_path = f.relative_to(base) + parts = relative_path.parts + print(parts) + if len(parts) >= 3: + character = parts[0] + emotion = parts[1] + + if character not in wav_lab_pairs: + wav_lab_pairs[character] = {} + if emotion not in wav_lab_pairs[character]: + wav_lab_pairs[character][emotion] = [] + wav_lab_pairs[character][emotion].append(str(f.name)) + + return wav_lab_pairs + + +def save_to_json(data, output_file): + with open(output_file, "w", encoding="utf-8") as file: + json.dump(data, file, ensure_ascii=False, indent=2) + + +base_path = "ref_data" +out_ref_file = "ref_data.json" + +wav_lab_pairs = scan_folder(base_path) +save_to_json(wav_lab_pairs, out_ref_file) diff --git a/xinference/thirdparty/fish_speech/tools/llama/__init__.py b/xinference/thirdparty/fish_speech/tools/llama/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/tools/llama/build_dataset.py b/xinference/thirdparty/fish_speech/tools/llama/build_dataset.py new file mode 100644 index 0000000000..20e2219956 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/build_dataset.py @@ -0,0 +1,169 @@ +import itertools +import os +import re +from collections import defaultdict +from functools import partial +from multiprocessing import Pool +from pathlib import Path + +import click +import numpy as np +from loguru import logger +from tqdm import tqdm + +from fish_speech.datasets.protos.text_data_pb2 import Semantics, Sentence, TextData +from fish_speech.datasets.protos.text_data_stream import pack_pb_stream +from fish_speech.utils.file import load_filelist + +# To avoid CPU overload +os.environ["MKL_NUM_THREADS"] = "1" +os.environ["OMP_NUM_THREADS"] = "1" + + +def task_generator_folder(root: Path, text_extension: str): + files = list(tqdm(Path(root).rglob("*.npy"), desc=f"Loading {root}")) + files = sorted(files) + + grouped_files = defaultdict(list) + for file in tqdm(files, desc=f"Grouping {root}"): + p = str(file.parent) + speaker = file.parent.name + + try: + if isinstance(text_extension, str): + texts = [file.with_suffix(text_extension).read_text(encoding="utf-8")] + else: + texts = [ + file.with_suffix(ext).read_text(encoding="utf-8") + for ext in text_extension + ] + except Exception as e: + logger.error(f"Failed to read text {file}: {e}") + continue + + grouped_files[p].append((speaker, file, texts)) + + logger.info( + f"Found {len(grouped_files)} groups in {root}, {list(grouped_files.keys())[:5]}..." + ) + + for i in grouped_files.values(): + subset = [(f, t) for _, f, t in i] + yield i[0][0], subset, "folder" + + +def task_generator_filelist(filelist): + grouped_files = defaultdict(list) + for filename, speaker, _, text in load_filelist(filelist): + grouped_files[speaker].append((Path(filename), [text])) + + logger.info(f"Found {len(grouped_files)} groups in {filelist}") + for speaker, values in grouped_files.items(): + yield speaker, values, "filelist" + + +def run_task(task): + name, subset, source = task + + # Parse the files + sentences = [] + for file, texts in subset: + np_file = file.with_suffix(".npy") + if np_file.exists() is False: + logger.warning(f"Can't find {np_file}") + continue + + new_texts = [] + + for text in texts: + # Simple cleaning: replace { xxx } and < xxx > with space + text = re.sub(r"\{.*?\}", " ", text) + text = re.sub(r"<.*?>", " ", text) + text = re.sub(r"\s+", " ", text) + new_texts.append(text) + + try: + semantics = np.load(np_file) + except Exception as e: + logger.error(f"Failed to parse {file}: {e}") + continue + + if isinstance(semantics, np.ndarray): + semantics = semantics.tolist() + + sentences.append( + Sentence( + texts=new_texts, + semantics=[Semantics(values=s) for s in semantics], + ) + ) + + # Pack the sentences + return pack_pb_stream( + TextData( + source=source, + name=name, + sentences=sentences, + ) + ) + + +@click.command() +@click.option( + "--input", + type=click.Path(path_type=Path), + required=True, + help="A folder containing the dataset or a filelist", + multiple=True, +) +@click.option( + "--output", type=click.Path(path_type=Path), default="data/quantized-dataset-ft" +) +@click.option("--num-workers", type=int, default=16) +@click.option("--text-extension", type=str, default=[".txt"], multiple=True) +@click.option( + "--shard-size", type=int, default=10, help="The maximum size of each shard in mb" +) +def main(input, output, num_workers, text_extension, shard_size): + generator_fns = [] + + for f in input: + assert f.exists(), f"{f} not found" + + if f.is_dir(): + generator_fn = task_generator_folder(f, text_extension) + else: + generator_fn = task_generator_filelist(f) + + generator_fns.append(generator_fn) + + generator_fn = itertools.chain(*generator_fns) + output.mkdir(parents=True, exist_ok=True) + + dataset_fp = None + tar_idx = 0 + written_size = 0 + + with Pool(num_workers) as p: + for result in tqdm(p.imap_unordered(run_task, generator_fn)): + if dataset_fp is None: + dataset_fp = open(Path(output) / f"{tar_idx:08d}.protos", "wb") + + dataset_fp.write(result) + written_size += len(result) + + if written_size > shard_size * 1024 * 1024: + logger.info(f"Finished writing {tar_idx} shards to {output}") + dataset_fp.close() + dataset_fp = None + written_size = 0 + tar_idx += 1 + + if dataset_fp is not None: + dataset_fp.close() + + logger.info(f"Finished writing {tar_idx + 1} shards to {output}") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/llama/eval_in_context.py b/xinference/thirdparty/fish_speech/tools/llama/eval_in_context.py new file mode 100644 index 0000000000..f3fb3f969e --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/eval_in_context.py @@ -0,0 +1,171 @@ +# import pyrootutils +import torch +import torch.nn.functional as F +from matplotlib import pyplot as plt +from transformers import AutoTokenizer + +# register eval resolver and root +# pyrootutils.setup_root(__file__, indicator=".project-root", pythonpath=True) + +from torch.utils.data import DataLoader + +from fish_speech.datasets.semantic import AutoAugTextDataset, TextDataCollator +from tools.llama.generate import load_model + + +def smooth( + scalars: list[float], weight: float +) -> list[float]: # Weight between 0 and 1 + last = scalars[0] # First value in the plot (first timestep) + smoothed = list() + for point in scalars: + smoothed_val = last * weight + (1 - weight) * point # Calculate smoothed value + smoothed.append(smoothed_val) # Save it + last = smoothed_val # Anchor the last smoothed value + + return smoothed + + +@torch.inference_mode() +def analyze_one_model(loader, config, weight, max_length): + device = "cuda" if torch.cuda.is_available() else "cpu" + model = load_model( + config, + weight, + device, + torch.bfloat16, + max_length, + compile=False, + )[0] + + current_step = 0 + model.eval() + + semantic_loss_sum = torch.zeros( + max_length, + dtype=torch.float32, + device=device, + ) + counter = torch.zeros( + max_length, + dtype=torch.long, + device=device, + ) + + for batch in loader: + batch = {k: v.to(device) for k, v in batch.items()} + + labels = batch["labels"] + outputs = model( + inp=batch["inputs"], + key_padding_mask=batch["attention_masks"], + ) + + token_logits = outputs.token_logits + codebook_logits = outputs.codebook_logits + + # Generate labels + base_loss = F.cross_entropy( + token_logits.reshape(-1, token_logits.size(-1)), + labels[:, 0].reshape(-1), + ignore_index=-100, + reduction="none", + ) + + codebook_labels = labels[:, 1 : 1 + model.config.num_codebooks].mT + semantic_loss = F.cross_entropy( + codebook_logits.reshape(-1, codebook_logits.size(-1)), + codebook_labels.reshape(-1), + ignore_index=-100, + reduction="none", + ) + + base_loss = base_loss.reshape(labels[:, 0].shape) + semantic_loss = semantic_loss.reshape(codebook_labels.shape) + + semantic_loss_frame = semantic_loss.mean(-1) + pad_pos = codebook_labels.sum(-1) == -100 * model.config.num_codebooks + + for loss_sample, pad in zip(semantic_loss_frame, pad_pos): + semantic_loss_sum[~pad] += loss_sample[~pad] + counter[~pad] += 1 + + current_step += 1 + if current_step == 10: + break + + semantic_loss = semantic_loss.cpu() + counter = counter.cpu() + xs, ys = [], [] + + for i, (loss, count) in enumerate(zip(semantic_loss_sum, counter)): + if count > 0: + xs.append(i) + ys.append((loss / count).item()) # for better loss visualization + + smoothed_ys = smooth(ys, 0.95) + + # Unload model + del model + torch.cuda.empty_cache() + + return xs, ys, smoothed_ys + + +def main(): + tokenizer = AutoTokenizer.from_pretrained("fishaudio/fish-speech-1") + max_length = 4096 + + ds = AutoAugTextDataset( + ["data/protos/sft/云天河"], + tokenizer=tokenizer, + use_speaker=False, + interactive_prob=1.0, + max_length=max_length, + ) + + loader = DataLoader( + ds, + batch_size=8, + collate_fn=TextDataCollator(tokenizer, max_length=max_length), + num_workers=0, + shuffle=False, + ) + + plt.figure(figsize=(10, 5), dpi=200) + + plt.xlabel("Frame") + plt.ylabel("Loss") + plt.yscale("log") + plt.title("Semantic Loss") + plt.grid(which="both", axis="both") + plt.xlim(0, max_length) + + tests = [ + ( + "pertrain-medium", + "dual_ar_2_codebook_medium", + "checkpoints/text2semantic-pretrain-medium-2k-v1.pth", + ), + ( + "sft-medium", + "dual_ar_2_codebook_medium", + "checkpoints/text2semantic-sft-medium-v1.1-4k.pth", + ), + ( + "sft-large", + "dual_ar_2_codebook_large", + "checkpoints/text2semantic-sft-large-v1.1-4k.pth", + ), + ] + + for name, config, weight in tests: + xs, _, smoothed_ys = analyze_one_model(loader, config, weight, max_length) + plt.plot(xs, smoothed_ys, label=name) + + plt.legend() + plt.savefig("semantic_loss.png") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/llama/generate.py b/xinference/thirdparty/fish_speech/tools/llama/generate.py new file mode 100644 index 0000000000..934c185145 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/generate.py @@ -0,0 +1,698 @@ +import os +import queue +import threading +import time +from dataclasses import dataclass +from pathlib import Path +from typing import Literal, Optional, Tuple, Union + +import click +import hydra +import numpy as np +import torch +import torch._dynamo.config +import torch._inductor.config +from loguru import logger +from tqdm import tqdm + +from fish_speech.conversation import CODEBOOK_PAD_TOKEN_ID +from fish_speech.text import clean_text, split_text + +os.environ["TOKENIZERS_PARALLELISM"] = "false" +torch._inductor.config.coordinate_descent_tuning = True +torch._inductor.config.triton.unique_kernel_names = True + +if hasattr(torch._inductor.config, "fx_graph_cache"): + # Experimental feature to reduce compilation times, will be on by default in future + torch._inductor.config.fx_graph_cache = True + + +from fish_speech.models.text2semantic.llama import ( + BaseTransformer, + DualARTransformer, + NaiveTransformer, +) + + +def multinomial_sample_one_no_sync( + probs_sort, +): # Does multinomial sampling without a cuda synchronization + q = torch.empty_like(probs_sort).exponential_(1) + return torch.argmax(probs_sort / q, dim=-1, keepdim=True).to(dtype=torch.int) + + +def logits_to_probs( + logits, + previous_tokens: Optional[torch.Tensor] = None, + temperature: torch.Tensor = 1.0, + top_p: torch.Tensor = 1.0, + repetition_penalty: torch.Tensor = 1.0, +) -> torch.Tensor: + # Apply repetition penalty + if previous_tokens is not None: + previous_tokens = previous_tokens.long() + score = torch.gather(logits, dim=0, index=previous_tokens) + score = torch.where( + score < 0, score * repetition_penalty, score / repetition_penalty + ) + logits.scatter_(dim=0, index=previous_tokens, src=score) + + # Apply top-p sampling + sorted_logits, sorted_indices = torch.sort(logits, descending=True) + cum_probs = torch.cumsum(torch.nn.functional.softmax(sorted_logits, dim=-1), dim=-1) + sorted_indices_to_remove = cum_probs > top_p + sorted_indices_to_remove[0] = False # keep at least one option + indices_to_remove = sorted_indices_to_remove.scatter( + dim=0, index=sorted_indices, src=sorted_indices_to_remove + ) + logits = logits.masked_fill(indices_to_remove, -float("Inf")) + + logits = logits / max(temperature, 1e-5) + + probs = torch.nn.functional.softmax(logits, dim=-1) + return probs + + +def sample( + logits, + previous_tokens: Optional[torch.Tensor] = None, + **sampling_kwargs, +) -> Tuple[torch.Tensor, torch.Tensor]: + probs = logits_to_probs( + logits=logits[0, -1], previous_tokens=previous_tokens, **sampling_kwargs + ) + idx_next = multinomial_sample_one_no_sync(probs) + return idx_next, probs + + +def decode_one_token_ar( + model: DualARTransformer, + x: torch.Tensor, + input_pos: torch.Tensor, + previous_tokens: torch.Tensor = None, + **sampling_kwargs, +) -> torch.Tensor: + x = model.forward_generate(x, input_pos) + codebooks = [ + sample( + x.logits, + previous_tokens=( + previous_tokens[0] if previous_tokens is not None else None + ), # Disable repetition penalty for the token codebook + **sampling_kwargs, + )[0] + ] + x = x.hidden_states + + # Cleanup the cache + for layer in model.fast_layers: + layer.attention.kv_cache.k_cache.fill_(0) + layer.attention.kv_cache.v_cache.fill_(0) + + for codebook_idx in range(model.config.num_codebooks): + input_pos = torch.tensor([codebook_idx], device=x.device, dtype=torch.long) + logits = model.forward_generate_fast(x, input_pos) + a = sample( + logits, + previous_tokens=( + previous_tokens[codebook_idx + 1] + if previous_tokens is not None + else None + ), + **sampling_kwargs, + )[0] + x = model.fast_embeddings(a) + codebooks.append(a) + + return torch.stack(codebooks, dim=0) + + +def decode_one_token_naive( + model: NaiveTransformer, + x: torch.Tensor, + input_pos: torch.Tensor, + previous_tokens: torch.Tensor = None, + **sampling_kwargs, +) -> torch.Tensor: + x = model.forward_generate(x, input_pos) + + codebooks = [ + sample( + x.token_logits, + previous_tokens=None, # Disable repetition penalty for the token codebook + **sampling_kwargs, + )[0] + ] + + for i in range(model.config.num_codebooks): + codebooks.append( + sample( + x.codebook_logits[:, :, i], + previous_tokens=( + previous_tokens[i + 1] if previous_tokens is not None else None + ), + **sampling_kwargs, + )[0] + ) + + return torch.stack(codebooks, dim=0) + + +def decode_n_tokens( + model: NaiveTransformer, + cur_token: torch.Tensor, + input_pos: torch.Tensor, + num_new_tokens: int, + im_end_id: int = 4, + decode_one_token=decode_one_token_naive, + **sampling_kwargs, +): + previous_tokens = torch.zeros( + (model.config.num_codebooks + 1, model.config.max_seq_len), + dtype=torch.int, + device=cur_token.device, + ) + + for i in tqdm(range(num_new_tokens)): + # We need to get windowed repeat penalty + win_size = 16 + if i < win_size: + window = previous_tokens[:, :win_size] + else: + window = previous_tokens[:, i - win_size : i] + + with torch.backends.cuda.sdp_kernel( + enable_flash=False, enable_mem_efficient=False, enable_math=True + ): # Actually better for Inductor to codegen attention here + next_token = decode_one_token( + model=model, + x=cur_token, + input_pos=input_pos, + previous_tokens=window, + **sampling_kwargs, + ) + + input_pos += 1 + cur_token = next_token.view(1, model.config.num_codebooks + 1, -1) + previous_tokens[:, i : i + 1] = next_token.view( + model.config.num_codebooks + 1, -1 + ) + + if cur_token[0, 0, -1] == im_end_id: + break + + return previous_tokens[:, : i + 1] + + +@torch.no_grad() +@torch.inference_mode() +def generate( + *, + model: NaiveTransformer, + prompt: torch.Tensor, + max_new_tokens: int, + im_end_id: int = 4, + decode_one_token=decode_one_token_naive, + **sampling_kwargs, +) -> torch.Tensor: + """ + Takes a conditioning sequence (prompt) as input and continues to generate as many tokens as requested. + """ + + # create an empty tensor of the expected final shape and fill in the current tokens + T = prompt.size(1) + + if max_new_tokens: + if T + max_new_tokens > model.config.max_seq_len: + max_new_tokens = model.config.max_seq_len - T + logger.info(f"Truncating max_new_tokens to {max_new_tokens}") + + T_new = T + max_new_tokens + else: + T_new = model.config.max_seq_len + max_new_tokens = T_new - T + + device, dtype = prompt.device, prompt.dtype + with torch.device(device): + model.setup_caches( + max_batch_size=1, max_seq_len=T_new, dtype=next(model.parameters()).dtype + ) + + codebook_dim = 1 + model.config.num_codebooks + # create an empty tensor of the expected final shape and fill in the current tokens + empty = torch.empty((codebook_dim, T_new), dtype=dtype, device=device) + empty[:, :T] = prompt + seq = empty + input_pos = torch.arange(0, T, device=device) + + # Use non-accelerated version for now, to avoid compilation overhead + prefill_decode = ( + decode_one_token_naive + if isinstance(model, NaiveTransformer) + else decode_one_token_ar + ) + + next_token = prefill_decode( + model, prompt.view(1, codebook_dim, -1), input_pos, **sampling_kwargs + ) + seq[:, T : T + 1] = next_token + + input_pos = torch.tensor([T], device=device, dtype=torch.int) + x = decode_n_tokens( + model, + next_token.view(1, codebook_dim, -1), + input_pos, + max_new_tokens - 1, + im_end_id=im_end_id, + decode_one_token=decode_one_token, + **sampling_kwargs, + ) + # x = torch.cat(generated_tokens, dim=1) + seq = seq[:, : T + 1 + x.size(1)] + seq[:, T + 1 :] = x + + return seq + + +def encode_tokens( + tokenizer, + string, + device="cuda", + prompt_tokens=None, + num_codebooks=4, +): + string = clean_text(string) + string = f"<|im_start|>user\n{string}<|im_end|><|im_start|>assistant\n" + + new_tokens = tokenizer.encode( + string, + add_special_tokens=False, + max_length=10**6, + truncation=False, + ) + tokens = torch.tensor([new_tokens], dtype=torch.int, device=device) + + # Codebooks + zeros = ( + torch.ones((num_codebooks, tokens.size(1)), dtype=torch.int, device=device) + * CODEBOOK_PAD_TOKEN_ID + ) + prompt = torch.cat((tokens, zeros), dim=0) + + if prompt_tokens is None: + return prompt + + # Get prompt tokens + if prompt_tokens.ndim == 3: + assert ( + prompt_tokens.shape[0] == 1 + ), f"3 dim prompt tokens should have shape (1, num_codebooks, seq_len)" + prompt_tokens = prompt_tokens[0] + + assert prompt_tokens.ndim == 2 + data = prompt_tokens + 1 + + if prompt_tokens.shape[0] > num_codebooks: + logger.warning( + f"Prompt tokens shape {prompt_tokens.shape} is larger than num_codebooks {num_codebooks}, getting first {num_codebooks} codebooks" + ) + data = data[:num_codebooks] + + # Add pad token for each codebook + data = torch.cat( + (data, torch.zeros((data.size(0), 1), dtype=torch.int, device=device)), + dim=1, + ) + + # Since 1.0, we use <|semantic|> + s0_token_id = tokenizer.convert_tokens_to_ids("<|semantic|>") + end_token_id = tokenizer.convert_tokens_to_ids("<|im_end|>") + main_token_ids = ( + torch.ones((1, data.size(1)), dtype=torch.int, device=device) * s0_token_id + ) + main_token_ids[0, -1] = end_token_id + + data = torch.cat((main_token_ids, data), dim=0) + prompt = torch.cat((prompt, data), dim=1) + + return prompt + + +def load_model(checkpoint_path, device, precision, compile=False): + model: Union[NaiveTransformer, DualARTransformer] = BaseTransformer.from_pretrained( + checkpoint_path, load_weights=True + ) + + model = model.to(device=device, dtype=precision) + logger.info(f"Restored model from checkpoint") + + if isinstance(model, DualARTransformer): + decode_one_token = decode_one_token_ar + logger.info("Using DualARTransformer") + else: + decode_one_token = decode_one_token_naive + logger.info("Using NaiveTransformer") + + if compile: + logger.info("Compiling function...") + decode_one_token = torch.compile( + decode_one_token, + fullgraph=True, + backend="inductor" if torch.cuda.is_available() else "aot_eager", + mode="reduce-overhead" if torch.cuda.is_available() else None, + ) + + return model.eval(), decode_one_token + + +@dataclass +class GenerateResponse: + action: Literal["sample", "next"] + codes: Optional[torch.Tensor] = None + text: Optional[str] = None + + +def generate_long( + *, + model, + device: str | torch.device, + decode_one_token: callable, + text: str, + num_samples: int = 1, + max_new_tokens: int = 0, + top_p: int = 0.7, + repetition_penalty: float = 1.5, + temperature: float = 0.7, + compile: bool = False, + iterative_prompt: bool = True, + max_length: int = 2048, + chunk_length: int = 150, + prompt_text: Optional[str | list[str]] = None, + prompt_tokens: Optional[torch.Tensor | list[torch.Tensor]] = None, +): + assert 0 < top_p <= 1, "top_p must be in (0, 1]" + assert 0 < repetition_penalty < 2, "repetition_penalty must be in (0, 2)" + assert 0 < temperature < 2, "temperature must be in (0, 2)" + + use_prompt = prompt_text is not None and prompt_tokens is not None + if use_prompt and isinstance(prompt_text, str): + prompt_text = [prompt_text] + prompt_tokens = [prompt_tokens] + + assert use_prompt is False or len(prompt_text) == len( + prompt_tokens + ), "Prompt text and tokens must have the same length" + + model_size = sum(p.numel() for p in model.parameters() if p.requires_grad) + tokenizer = model.tokenizer + im_end_id = tokenizer.convert_tokens_to_ids("<|im_end|>") + + encoded = [] + texts = split_text(text, chunk_length) if iterative_prompt else [text] + encoded_prompts = [] + + if use_prompt: + for idx, (t, c) in enumerate(zip(prompt_text, prompt_tokens)): + encoded_prompts.append( + encode_tokens( + tokenizer, + string=t, + device=device, + prompt_tokens=c, + num_codebooks=model.config.num_codebooks, + ) + ) + + for idx, text in enumerate(texts): + encoded.append( + encode_tokens( + tokenizer, + string=text, + device=device, + num_codebooks=model.config.num_codebooks, + ) + ) + logger.info(f"Encoded text: {text}") + + # Move temperature, top_p, repetition_penalty to device + # This is important so that changing params doesn't trigger recompile + temperature = torch.tensor(temperature, device=device, dtype=torch.float) + top_p = torch.tensor(top_p, device=device, dtype=torch.float) + repetition_penalty = torch.tensor( + repetition_penalty, device=device, dtype=torch.float + ) + + for sample_idx in range(num_samples): + if torch.cuda.is_available(): + torch.cuda.synchronize() + + global_encoded = [] + seg_idx = 0 + + while seg_idx < len(encoded): + logger.info( + f"Generating sentence {seg_idx + 1}/{len(encoded)} of sample {sample_idx + 1}/{num_samples}" + ) + + seg = encoded[seg_idx] + global_encoded.append(seg) + + lengths = reversed([seg.size(1) for seg in global_encoded]) + + # Pick last 2000 tokens + count = 0 + for i, length in enumerate(lengths): + count += length + if count + length > max_length - 1024 - sum( + t.shape[1] for t in encoded_prompts + ): + break + + if i != 0 and i % 2 == 0: + i -= 1 + + # Rotate the list, always make sure first segment is included to avoid drift + if i < len(global_encoded) - 2: + partial_encoded = global_encoded[:2] + global_encoded[-i:] + else: + partial_encoded = global_encoded + + if use_prompt: + partial_encoded = encoded_prompts + partial_encoded + + cat_encoded = torch.cat(partial_encoded, dim=1) + prompt_length = cat_encoded.size(1) + + t0 = time.perf_counter() + y = generate( + model=model, + prompt=cat_encoded, + max_new_tokens=max_new_tokens, + im_end_id=im_end_id, + decode_one_token=decode_one_token, + temperature=temperature, + top_p=top_p, + repetition_penalty=repetition_penalty, + ) + + if sample_idx == 0 and seg_idx == 0 and compile: + logger.info(f"Compilation time: {time.perf_counter() - t0:.2f} seconds") + + if torch.cuda.is_available(): + torch.cuda.synchronize() + + t = time.perf_counter() - t0 + + tokens_generated = y.size(1) - prompt_length + tokens_sec = tokens_generated / t + logger.info( + f"Generated {tokens_generated} tokens in {t:.02f} seconds, {tokens_sec:.02f} tokens/sec" + ) + logger.info( + f"Bandwidth achieved: {model_size * tokens_sec / 1e9:.02f} GB/s" + ) + + if torch.cuda.is_available(): + logger.info( + f"GPU Memory used: {torch.cuda.max_memory_reserved() / 1e9:.02f} GB" + ) + + # Put the generated tokens + # since there is and tokens, we remove last 2 tokens + codes = y[1:, prompt_length:-1].clone() + codes = codes - 1 + assert (codes >= 0).all(), f"Negative code found" + + decoded = y[:, prompt_length:-1].clone() + # But for global encoding, we should keep the token + + global_encoded.append(decoded) + assert (codes >= 0).all(), f"Negative code found: {codes}" + yield GenerateResponse(action="sample", codes=codes, text=texts[seg_idx]) + seg_idx += 1 + + # This indicates the end of the current sample + yield GenerateResponse(action="next") + + +@dataclass +class WrappedGenerateResponse: + status: Literal["success", "error"] + response: Optional[GenerateResponse | Exception] = None + + +@dataclass +class GenerateRequest: + request: dict + response_queue: queue.Queue + + +def launch_thread_safe_queue( + checkpoint_path, + device, + precision, + compile: bool = False, +): + input_queue = queue.Queue() + init_event = threading.Event() + + def worker(): + model, decode_one_token = load_model( + checkpoint_path, device, precision, compile=compile + ) + init_event.set() + + while True: + item: GenerateRequest | None = input_queue.get() + if item is None: + break + + kwargs = item.request + response_queue = item.response_queue + + try: + for chunk in generate_long( + model=model, decode_one_token=decode_one_token, **kwargs + ): + response_queue.put( + WrappedGenerateResponse(status="success", response=chunk) + ) + except Exception as e: + response_queue.put(WrappedGenerateResponse(status="error", response=e)) + + threading.Thread(target=worker, daemon=True).start() + init_event.wait() + + return input_queue + + +@click.command() +@click.option( + "--text", + type=str, + default="你说的对, 但是原神是一款由米哈游自主研发的开放世界手游.", +) +@click.option("--prompt-text", type=str, default=None, multiple=True) +@click.option( + "--prompt-tokens", + type=click.Path(path_type=Path, exists=True), + default=None, + multiple=True, +) +@click.option("--num-samples", type=int, default=1) +@click.option("--max-new-tokens", type=int, default=0) +@click.option("--top-p", type=float, default=0.7) +@click.option("--repetition-penalty", type=float, default=1.2) +@click.option("--temperature", type=float, default=0.7) +@click.option( + "--checkpoint-path", + type=click.Path(path_type=Path, exists=True), + default="checkpoints/fish-speech-1.2-sft", +) +@click.option("--device", type=str, default="cuda") +@click.option("--compile/--no-compile", default=False) +@click.option("--seed", type=int, default=42) +@click.option("--half/--no-half", default=False) +@click.option("--iterative-prompt/--no-iterative-prompt", default=True) +@click.option("--chunk-length", type=int, default=100) +def main( + text: str, + prompt_text: Optional[list[str]], + prompt_tokens: Optional[list[Path]], + num_samples: int, + max_new_tokens: int, + top_p: int, + repetition_penalty: float, + temperature: float, + checkpoint_path: Path, + device: str, + compile: bool, + seed: int, + half: bool, + iterative_prompt: bool, + chunk_length: int, +) -> None: + + precision = torch.half if half else torch.bfloat16 + + if prompt_text is not None and len(prompt_text) != len(prompt_tokens): + raise ValueError( + f"Number of prompt text ({len(prompt_text)}) and prompt tokens ({len(prompt_tokens)}) should be the same" + ) + + logger.info("Loading model ...") + t0 = time.time() + model, decode_one_token = load_model( + checkpoint_path, device, precision, compile=compile + ) + + if torch.cuda.is_available(): + torch.cuda.synchronize() + + logger.info(f"Time to load model: {time.time() - t0:.02f} seconds") + + if prompt_tokens is not None: + prompt_tokens = [torch.from_numpy(np.load(p)).to(device) for p in prompt_tokens] + + torch.manual_seed(seed) + + if torch.cuda.is_available(): + torch.cuda.manual_seed(seed) + + generator = generate_long( + model=model, + device=device, + decode_one_token=decode_one_token, + text=text, + num_samples=num_samples, + max_new_tokens=max_new_tokens, + top_p=top_p, + repetition_penalty=repetition_penalty, + temperature=temperature, + compile=compile, + iterative_prompt=iterative_prompt, + chunk_length=chunk_length, + prompt_text=prompt_text, + prompt_tokens=prompt_tokens, + ) + + idx = 0 + codes = [] + + for response in generator: + if response.action == "sample": + codes.append(response.codes) + logger.info(f"Sampled text: {response.text}") + elif response.action == "next": + if codes: + np.save(f"codes_{idx}.npy", torch.cat(codes, dim=1).cpu().numpy()) + logger.info(f"Saved codes to codes_{idx}.npy") + logger.info(f"Next sample") + codes = [] + idx += 1 + else: + logger.error(f"Error: {response}") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/llama/merge_lora.py b/xinference/thirdparty/fish_speech/tools/llama/merge_lora.py new file mode 100644 index 0000000000..f12eece8d2 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/merge_lora.py @@ -0,0 +1,95 @@ +import shutil +from copy import deepcopy +from pathlib import Path + +import click +import hydra +import torch +from hydra import compose, initialize +from hydra.utils import instantiate +from loguru import logger + +from fish_speech.models.text2semantic.llama import BaseTransformer +from fish_speech.models.text2semantic.lora import get_merged_state_dict + + +@click.command() +@click.option("--lora-config", type=str, default="r_8_alpha_16") +@click.option("--base-weight", type=str, default="checkpoints/fish-speech-1.2-sft") +@click.option("--lora-weight", type=str, required=True) +@click.option("--output", type=str, required=True) +def merge(lora_config, base_weight, lora_weight, output): + output = Path(output) + logger.info( + f"Merging {base_weight} and {lora_weight} into {output} with {lora_config}" + ) + + with initialize(version_base="1.3", config_path="../../fish_speech/configs/lora"): + cfg = compose(config_name=lora_config) + + lora_config = instantiate(cfg) + logger.info(f"Loaded lora model with config {lora_config}") + + llama_model = BaseTransformer.from_pretrained( + path=base_weight, + load_weights=True, + lora_config=lora_config, + ) + logger.info(f"Loaded llama model") + + llama_state_dict = llama_model.state_dict() + llama_state_dict = {k: v for k, v in llama_state_dict.items() if "lora" not in k} + llama_state_dict_copy = deepcopy(llama_state_dict) + lora_state_dict = torch.load(lora_weight, map_location="cpu") + + if "state_dict" in llama_state_dict: + llama_state_dict = llama_state_dict["state_dict"] + + if "state_dict" in lora_state_dict: + lora_state_dict = lora_state_dict["state_dict"] + + # remove prefix model. + if any(k.startswith("model.") for k in llama_state_dict.keys()): + llama_state_dict = { + k.replace("model.", ""): v + for k, v in llama_state_dict.items() + if k.startswith("model.") + } + if any(k.startswith("model.") for k in lora_state_dict.keys()): + lora_state_dict = { + k.replace("model.", ""): v + for k, v in lora_state_dict.items() + if k.startswith("model.") + } + + logger.info(f"Found {len(llama_state_dict)} keys in llama model") + logger.info(f"Found {len(lora_state_dict)} keys in lora model") + + merged_state_dict = llama_state_dict | lora_state_dict + llama_model.load_state_dict(merged_state_dict, strict=True) + logger.info(f"Merged model loaded") + + # Trigger eval mode to merge lora + llama_model.eval() + llama_model.save_pretrained(output, drop_lora=True) + logger.info(f"Saved merged model to {output}, validating") + + new_state_dict = torch.load(output / "model.pth", map_location="cpu") + original_keys = set(llama_state_dict_copy.keys()) + merged_keys = set(new_state_dict.keys()) + + assert original_keys == merged_keys, "Keys should be same" + + for key in original_keys: + diff_l1 = (new_state_dict[key] - llama_state_dict_copy[key]).abs().sum().item() + if diff_l1 != 0: + break + else: + logger.error("Merged model is same as the original model") + exit(1) + + logger.info("Merged model is different from the original model, check passed") + + +if __name__ == "__main__": + merge() diff --git a/xinference/thirdparty/fish_speech/tools/llama/quantize.py b/xinference/thirdparty/fish_speech/tools/llama/quantize.py new file mode 100644 index 0000000000..aae32fcce7 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/quantize.py @@ -0,0 +1,497 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +import datetime +import shutil + +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +import time +from pathlib import Path + +import click +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fish_speech.models.text2semantic.llama import find_multiple +from tools.llama.generate import load_model + +##### Quantization Primitives ###### + + +def dynamically_quantize_per_channel(x, quant_min, quant_max, target_dtype): + # assumes symmetric quantization + # assumes axis == 0 + # assumes dense memory format + # TODO(future): relax ^ as needed + + # default setup for affine quantization of activations + eps = torch.finfo(torch.float32).eps + + # get min and max + min_val, max_val = torch.aminmax(x, dim=1) + + # calculate scales and zero_points based on min and max + # reference: https://fburl.com/code/srbiybme + min_val_neg = torch.min(min_val, torch.zeros_like(min_val)) + max_val_pos = torch.max(max_val, torch.zeros_like(max_val)) + device = min_val_neg.device + + # reference: https://fburl.com/code/4wll53rk + max_val_pos = torch.max(-min_val_neg, max_val_pos) + scales = max_val_pos / (float(quant_max - quant_min) / 2) + # ensure scales is the same dtype as the original tensor + scales = torch.clamp(scales, min=eps).to(x.dtype) + zero_points = torch.zeros(min_val_neg.size(), dtype=torch.int64, device=device) + + # quantize based on qmin/qmax/scales/zp + # reference: https://www.internalfb.com/code/fbsource/[8edc275012b1]/fbcode/caffe2/torch/ao/quantization/fx/_decomposed.py?lines=63 + x_div = x / scales.unsqueeze(-1) + x_round = torch.round(x_div) + x_zp = x_round + zero_points.unsqueeze(-1) + quant = torch.clamp(x_zp, quant_min, quant_max).to(target_dtype) + + return quant, scales, zero_points + + +def get_group_qparams(w, n_bit=4, groupsize=128): + # needed for GPTQ with padding + if groupsize > w.shape[-1]: + groupsize = w.shape[-1] + assert groupsize > 1 + assert w.shape[-1] % groupsize == 0 + assert w.dim() == 2 + + to_quant = w.reshape(-1, groupsize) + assert torch.isnan(to_quant).sum() == 0 + + max_val = to_quant.amax(dim=1, keepdim=True) + min_val = to_quant.amin(dim=1, keepdim=True) + max_int = 2**n_bit - 1 + scales = (max_val - min_val).clamp(min=1e-6) / max_int + zeros = min_val + scales * (2 ** (n_bit - 1)) + return scales.to(torch.bfloat16).reshape(w.shape[0], -1), zeros.to( + torch.bfloat16 + ).reshape(w.shape[0], -1) + + +def pack_scales_and_zeros(scales, zeros): + assert scales.shape == zeros.shape + assert scales.dtype == torch.bfloat16 + assert zeros.dtype == torch.bfloat16 + return ( + torch.cat( + [ + scales.reshape(scales.size(0), scales.size(1), 1), + zeros.reshape(zeros.size(0), zeros.size(1), 1), + ], + 2, + ) + .transpose(0, 1) + .contiguous() + ) + + +def unpack_scales_and_zeros(scales_and_zeros): + assert len(scales_and_zeros.shape) == 3 and scales_and_zeros.shape[2] == 2 + assert scales_and_zeros.dtype == torch.float + return torch.split(scales_and_zeros.transpose(0, 1), 1, 2) + + +def group_quantize_tensor_from_qparams(w, scales, zeros, n_bit=4, groupsize=128): + assert groupsize > 1 + # needed for GPTQ single column quantize + if groupsize > w.shape[-1] and scales.shape[-1] == 1: + groupsize = w.shape[-1] + + assert w.shape[-1] % groupsize == 0 + assert w.dim() == 2 + + to_quant = w.reshape(-1, groupsize) + assert torch.isnan(to_quant).sum() == 0 + + scales = scales.reshape(-1, 1) + zeros = zeros.reshape(-1, 1) + min_val = zeros - scales * (2 ** (n_bit - 1)) + max_int = 2**n_bit - 1 + min_int = 0 + w_int32 = ( + to_quant.sub(min_val) + .div(scales) + .round() + .clamp_(min_int, max_int) + .to(torch.int32) + .reshape_as(w) + ) + + return w_int32 + + +def group_quantize_tensor(w, n_bit=4, groupsize=128): + scales, zeros = get_group_qparams(w, n_bit, groupsize) + w_int32 = group_quantize_tensor_from_qparams(w, scales, zeros, n_bit, groupsize) + scales_and_zeros = pack_scales_and_zeros(scales, zeros) + return w_int32, scales_and_zeros + + +def group_dequantize_tensor_from_qparams( + w_int32, scales, zeros, n_bit=4, groupsize=128 +): + assert groupsize > 1 + # needed for GPTQ single column dequantize + if groupsize > w_int32.shape[-1] and scales.shape[-1] == 1: + groupsize = w_int32.shape[-1] + assert w_int32.shape[-1] % groupsize == 0 + assert w_int32.dim() == 2 + + w_int32_grouped = w_int32.reshape(-1, groupsize) + scales = scales.reshape(-1, 1) + zeros = zeros.reshape(-1, 1) + + w_dq = ( + w_int32_grouped.sub(2 ** (n_bit - 1)).mul(scales).add(zeros).reshape_as(w_int32) + ) + return w_dq + + +def group_dequantize_tensor(w_int32, scales_and_zeros, n_bit=4, groupsize=128): + scales, zeros = unpack_scales_and_zeros(scales_and_zeros) + return group_dequantize_tensor_from_qparams( + w_int32, scales, zeros, n_bit, groupsize + ) + + +class QuantHandler: + def __init__(self, mod): + self.mod = mod + + def create_quantized_state_dict(self) -> "StateDict": + pass + + def convert_for_runtime(self) -> "nn.Module": + pass + + +##### Weight-only int8 per-channel quantized code ###### + + +def replace_linear_weight_only_int8_per_channel(module): + for name, child in module.named_children(): + if isinstance(child, nn.Linear): + setattr( + module, + name, + WeightOnlyInt8Linear(child.in_features, child.out_features), + ) + else: + replace_linear_weight_only_int8_per_channel(child) + + +class WeightOnlyInt8QuantHandler: + def __init__(self, mod): + self.mod = mod + + @torch.no_grad() + def create_quantized_state_dict(self): + cur_state_dict = self.mod.state_dict() + for fqn, mod in self.mod.named_modules(): + if isinstance(mod, torch.nn.Linear): + int8_weight, scales, _ = dynamically_quantize_per_channel( + mod.weight.float(), -128, 127, torch.int8 + ) + cur_state_dict[f"{fqn}.weight"] = int8_weight + cur_state_dict[f"{fqn}.scales"] = scales.to(mod.weight.dtype) + + return cur_state_dict + + def convert_for_runtime(self): + replace_linear_weight_only_int8_per_channel(self.mod) + return self.mod + + +class WeightOnlyInt8Linear(torch.nn.Module): + __constants__ = ["in_features", "out_features"] + in_features: int + out_features: int + weight: torch.Tensor + + def __init__( + self, + in_features: int, + out_features: int, + bias: bool = True, + device=None, + dtype=None, + ) -> None: + factory_kwargs = {"device": device, "dtype": dtype} + super().__init__() + self.in_features = in_features + self.out_features = out_features + self.register_buffer( + "weight", torch.empty((out_features, in_features), dtype=torch.int8) + ) + self.register_buffer("scales", torch.ones(out_features, dtype=torch.bfloat16)) + + def forward(self, input: torch.Tensor) -> torch.Tensor: + return F.linear(input, self.weight.to(dtype=input.dtype)) * self.scales + + +##### weight only int4 per channel groupwise quantized code ###### + + +def prepare_int4_weight_and_scales_and_zeros(weight_bf16, groupsize, inner_k_tiles): + weight_int32, scales_and_zeros = group_quantize_tensor( + weight_bf16, n_bit=4, groupsize=groupsize + ) + weight_int4pack = torch.ops.aten._convert_weight_to_int4pack( + weight_int32, inner_k_tiles + ) + return weight_int4pack, scales_and_zeros + + +def linear_forward_int4(x, weight_int4pack, scales_and_zeros, out_features, groupsize): + origin_x_size = x.size() + x = x.reshape(-1, origin_x_size[-1]) + c = torch.ops.aten._weight_int4pack_mm( + x, weight_int4pack, groupsize, scales_and_zeros + ) + new_shape = origin_x_size[:-1] + (out_features,) + c = c.reshape(new_shape) + return c + + +def _check_linear_int4_k(k, groupsize=1, inner_k_tiles=1): + return k % groupsize == 0 and k % (inner_k_tiles * 16) == 0 + + +def replace_linear_int4(module, groupsize, inner_k_tiles, padding): + for name, child in module.named_children(): + if isinstance(child, nn.Linear): + if _check_linear_int4_k(child.in_features, groupsize, inner_k_tiles): + setattr( + module, + name, + WeightOnlyInt4Linear( + child.in_features, + child.out_features, + bias=False, + groupsize=groupsize, + inner_k_tiles=inner_k_tiles, + padding=False, + ), + ) + elif padding: + setattr( + module, + name, + WeightOnlyInt4Linear( + child.in_features, + child.out_features, + bias=False, + groupsize=groupsize, + inner_k_tiles=inner_k_tiles, + padding=True, + ), + ) + else: + replace_linear_int4(child, groupsize, inner_k_tiles, padding) + + +class WeightOnlyInt4QuantHandler: + def __init__(self, mod, groupsize=128, inner_k_tiles=8, padding=True): + self.mod = mod + self.groupsize = groupsize + self.inner_k_tiles = inner_k_tiles + self.padding = padding + assert groupsize in [32, 64, 128, 256] + assert inner_k_tiles in [2, 4, 8] + + @torch.no_grad() + def create_quantized_state_dict(self): + cur_state_dict = self.mod.state_dict() + for fqn, mod in self.mod.named_modules(): + if isinstance(mod, torch.nn.Linear): + assert not mod.bias + out_features = mod.out_features + in_features = mod.in_features + assert out_features % 8 == 0, "require out_features % 8 == 0" + print(f"linear: {fqn}, in={in_features}, out={out_features}") + + weight = mod.weight.data + if not _check_linear_int4_k( + in_features, self.groupsize, self.inner_k_tiles + ): + if self.padding: + import torch.nn.functional as F + + print( + f"warning: {fqn} is padded to satisfy in_features % 1024 == 0" + ) + padded_in_features = find_multiple(in_features, 1024) + weight = F.pad( + weight, pad=(0, padded_in_features - in_features) + ) + else: + print( + f"warning: {fqn} is skipped, int4 requires that in_features is 32, 64, or is divisible by 1024, " + + "and that groupsize and inner_k_tiles*16 evenly divide into it" + ) + continue + ( + weight_int4pack, + scales_and_zeros, + ) = prepare_int4_weight_and_scales_and_zeros( + weight.to(torch.bfloat16).to("cuda"), + self.groupsize, + self.inner_k_tiles, + ) + cur_state_dict[f"{fqn}.weight"] = weight_int4pack.to("cpu") + cur_state_dict[f"{fqn}.scales_and_zeros"] = scales_and_zeros.to("cpu") + + return cur_state_dict + + def convert_for_runtime(self): + replace_linear_int4(self.mod, self.groupsize, self.inner_k_tiles, self.padding) + return self.mod + + +class WeightOnlyInt4Linear(torch.nn.Module): + __constants__ = ["in_features", "out_features"] + in_features: int + out_features: int + weight: torch.Tensor + + def __init__( + self, + in_features: int, + out_features: int, + bias=True, + device=None, + dtype=None, + groupsize: int = 128, + inner_k_tiles: int = 8, + padding: bool = True, + ) -> None: + super().__init__() + self.padding = padding + if padding: + self.origin_in_features = in_features + in_features = find_multiple(in_features, 1024) + + self.in_features = in_features + self.out_features = out_features + assert not bias, "require bias=False" + self.groupsize = groupsize + self.inner_k_tiles = inner_k_tiles + + assert out_features % 8 == 0, "require out_features % 8 == 0" + assert ( + in_features % (inner_k_tiles * 16) == 0 + ), "require in_features % (innerKTiles * 16) == 0" + self.register_buffer( + "weight", + torch.empty( + ( + out_features // 8, + in_features // (inner_k_tiles * 16), + 32, + inner_k_tiles // 2, + ), + dtype=torch.int32, + ), + ) + self.register_buffer( + "scales_and_zeros", + torch.empty( + (in_features // groupsize, out_features, 2), dtype=torch.bfloat16 + ), + ) + + def forward(self, input: torch.Tensor) -> torch.Tensor: + input = input.to(torch.bfloat16) + if self.padding: + import torch.nn.functional as F + + input = F.pad(input, pad=(0, self.in_features - self.origin_in_features)) + return linear_forward_int4( + input, self.weight, self.scales_and_zeros, self.out_features, self.groupsize + ) + + +def generate_folder_name(): + now = datetime.datetime.now() + folder_name = now.strftime("%Y%m%d_%H%M%S") + return folder_name + + +@click.command() +@click.option( + "--checkpoint-path", + type=click.Path(path_type=Path, exists=True), + default="checkpoints/fish-speech-1.2-sft", +) +@click.option( + "--mode", type=str, default="int8", help="type of quantization to perform" +) +@click.option( + "--groupsize", type=int, default=128, help="Group size for int4 quantization." +) +@click.option("--timestamp", type=str, default="None", help="When to do quantization") +def quantize(checkpoint_path: Path, mode: str, groupsize: int, timestamp: str) -> None: + + device = "cpu" + precision = torch.bfloat16 + + print("Loading model ...") + t0 = time.time() + + model, _ = load_model( + checkpoint_path=checkpoint_path, + device=device, + precision=precision, + compile=False, + ) + vq_model = "firefly-gan-vq-fsq-4x1024-42hz-generator.pth" + now = timestamp if timestamp != "None" else generate_folder_name() + + if mode == "int8": + print( + "Quantizing model weights for int8 weight-only symmetric per-channel quantization" + ) + quant_handler = WeightOnlyInt8QuantHandler(model) + quantized_state_dict = quant_handler.create_quantized_state_dict() + + dir_name = checkpoint_path + dst_name = Path(f"checkpoints/fs-1.2-int8-{now}") + shutil.copytree(str(dir_name.resolve()), str(dst_name.resolve())) + if (dst_name / vq_model).exists(): + (dst_name / vq_model).unlink() + quantize_path = dst_name / "model.pth" + + elif mode == "int4": + print( + "Quantizing model weights for int4 weight-only affine per-channel groupwise quantization" + ) + quant_handler = WeightOnlyInt4QuantHandler(model, groupsize) + quantized_state_dict = quant_handler.create_quantized_state_dict() + + dir_name = checkpoint_path + dst_name = Path(f"checkpoints/fs-1.2-int4-g{groupsize}-{now}") + shutil.copytree(str(dir_name.resolve()), str(dst_name.resolve())) + if (dst_name / vq_model).exists(): + (dst_name / vq_model).unlink() + quantize_path = dst_name / "model.pth" + + else: + raise ValueError( + f"Invalid quantization mode {mode} needs to be one of [int8, int4, int4-gpptq]" + ) + + print(f"Writing quantized weights to {quantize_path}") + quantize_path.unlink(missing_ok=True) # remove existing file if one already there + torch.save(quantized_state_dict, quantize_path) + print(f"Quantization complete took {time.time() - t0:.02f} seconds") + + +if __name__ == "__main__": + quantize() diff --git a/xinference/thirdparty/fish_speech/tools/llama/rebuild_tokenizer.py b/xinference/thirdparty/fish_speech/tools/llama/rebuild_tokenizer.py new file mode 100644 index 0000000000..ea64fa6788 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/llama/rebuild_tokenizer.py @@ -0,0 +1,57 @@ +from tokenizers import Tokenizer, decoders, models, pre_tokenizers, processors, trainers +from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast + +# Initialize a tokenizer +tokenizer = Tokenizer(models.BPE()) + +# Customize pre-tokenization and decoding +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +tokenizer.decoder = decoders.ByteLevel() +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) + +# Don't train the tokenizer +trainer = trainers.BpeTrainer( + vocab_size=0, + min_frequency=2, + initial_alphabet=pre_tokenizers.ByteLevel.alphabet(), + special_tokens=[ + "<|begin_of_sequence|>", + "<|end_of_sequence|>", + "<|im_start|>", + "<|im_sep|>", # system, user, assistant, etc. + "<|im_end|>", + "<|semantic|>", # audio features + "<|pad|>", + ], +) + +# <|im_start|>user<|im_sep|>...<|im_end|> +# <|im_start|>assistant<|im_sep|><|semantic|><|semantic|><|semantic|><|semantic|><|semantic|><|im_end|> +tokenizer.train_from_iterator([], trainer=trainer) + +print(len(tokenizer.get_vocab())) +x = tokenizer.encode( + "Hello, how are you? dfgnviadfjoiviouajeiodfjv 你好世界 🈶<|semantic|>" +).ids +print(x, len(x)) +print(tokenizer.decode(x, skip_special_tokens=True)) + + +tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + pad_token="<|pad|>", + bos_token="<|begin_of_sequence|>", + eos_token="<|end_of_sequence|>", +) + +# Try tokenizing a new sequence +sequence = "All around, too, lay vast quantities of the costliest merchandise, and treasures were heaped in every cranny of the rocks, but all these things only added to the desolation of the scene. 测试中文, 你好世界 🈶<|semantic|>" +encoded = tokenizer(sequence).input_ids + +print("Test encoding....") +print(f"\tSentence: {sequence}") +print(f"\tEncoded: {encoded}") +print(f"\tDecoded: {tokenizer.batch_decode(encoded)}") +print(f"\tDecoded: {tokenizer.decode(encoded)}") + +tokenizer.push_to_hub("fishaudio/fish-speech-1", private=True) diff --git a/xinference/thirdparty/fish_speech/tools/merge_asr_files.py b/xinference/thirdparty/fish_speech/tools/merge_asr_files.py new file mode 100644 index 0000000000..cc12062095 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/merge_asr_files.py @@ -0,0 +1,55 @@ +import os +from pathlib import Path + +from pydub import AudioSegment +from tqdm import tqdm + +from tools.file import AUDIO_EXTENSIONS, list_files + + +def merge_and_delete_files(save_dir, original_files): + save_path = Path(save_dir) + audio_slice_files = list_files( + path=save_dir, extensions=AUDIO_EXTENSIONS.union([".lab"]), recursive=True + ) + audio_files = {} + label_files = {} + for file_path in tqdm(audio_slice_files, desc="Merging audio files"): + rel_path = Path(file_path).relative_to(save_path) + (save_path / rel_path.parent).mkdir(parents=True, exist_ok=True) + if file_path.suffix == ".wav": + prefix = rel_path.parent / file_path.stem.rsplit("-", 1)[0] + if prefix == rel_path.parent / file_path.stem: + continue + audio = AudioSegment.from_wav(file_path) + if prefix in audio_files.keys(): + audio_files[prefix] = audio_files[prefix] + audio + else: + audio_files[prefix] = audio + + elif file_path.suffix == ".lab": + prefix = rel_path.parent / file_path.stem.rsplit("-", 1)[0] + if prefix == rel_path.parent / file_path.stem: + continue + with open(file_path, "r", encoding="utf-8") as f: + label = f.read() + if prefix in label_files.keys(): + label_files[prefix] = label_files[prefix] + ", " + label + else: + label_files[prefix] = label + + for prefix, audio in audio_files.items(): + output_audio_path = save_path / f"{prefix}.wav" + audio.export(output_audio_path, format="wav") + + for prefix, label in label_files.items(): + output_label_path = save_path / f"{prefix}.lab" + with open(output_label_path, "w", encoding="utf-8") as f: + f.write(label) + + for file_path in original_files: + os.remove(file_path) + + +if __name__ == "__main__": + merge_and_delete_files("/made/by/spicysama/laziman", [__file__]) diff --git a/xinference/thirdparty/fish_speech/tools/post_api.py b/xinference/thirdparty/fish_speech/tools/post_api.py new file mode 100644 index 0000000000..153893078e --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/post_api.py @@ -0,0 +1,164 @@ +import argparse +import base64 +import json +import wave +from pathlib import Path + +import pyaudio +import requests + + +def wav_to_base64(file_path): + if not file_path or not Path(file_path).exists(): + return None + with open(file_path, "rb") as wav_file: + wav_content = wav_file.read() + base64_encoded = base64.b64encode(wav_content) + return base64_encoded.decode("utf-8") + + +def read_ref_text(ref_text): + path = Path(ref_text) + if path.exists() and path.is_file(): + with path.open("r", encoding="utf-8") as file: + return file.read() + return ref_text + + +def play_audio(audio_content, format, channels, rate): + p = pyaudio.PyAudio() + stream = p.open(format=format, channels=channels, rate=rate, output=True) + stream.write(audio_content) + stream.stop_stream() + stream.close() + p.terminate() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Send a WAV file and text to a server and receive synthesized audio." + ) + + parser.add_argument( + "--url", + "-u", + type=str, + default="http://127.0.0.1:8080/v1/invoke", + help="URL of the server", + ) + parser.add_argument( + "--text", "-t", type=str, required=True, help="Text to be synthesized" + ) + parser.add_argument( + "--reference_audio", + "-ra", + type=str, + default=None, + help="Path to the WAV file", + ) + parser.add_argument( + "--reference_text", + "-rt", + type=str, + default=None, + help="Reference text for voice synthesis", + ) + parser.add_argument( + "--max_new_tokens", + type=int, + default=1024, + help="Maximum new tokens to generate", + ) + parser.add_argument( + "--chunk_length", type=int, default=100, help="Chunk length for synthesis" + ) + parser.add_argument( + "--top_p", type=float, default=0.7, help="Top-p sampling for synthesis" + ) + parser.add_argument( + "--repetition_penalty", + type=float, + default=1.2, + help="Repetition penalty for synthesis", + ) + parser.add_argument( + "--temperature", type=float, default=0.7, help="Temperature for sampling" + ) + parser.add_argument( + "--speaker", type=str, default=None, help="Speaker ID for voice synthesis" + ) + parser.add_argument("--emotion", type=str, default=None, help="Speaker's Emotion") + parser.add_argument("--format", type=str, default="wav", help="Audio format") + parser.add_argument( + "--streaming", type=bool, default=False, help="Enable streaming response" + ) + parser.add_argument( + "--channels", type=int, default=1, help="Number of audio channels" + ) + parser.add_argument("--rate", type=int, default=44100, help="Sample rate for audio") + + args = parser.parse_args() + + base64_audio = wav_to_base64(args.reference_audio) + + ref_text = args.reference_text + if ref_text: + ref_text = read_ref_text(ref_text) + + data = { + "text": args.text, + "reference_text": ref_text, + "reference_audio": base64_audio, + "max_new_tokens": args.max_new_tokens, + "chunk_length": args.chunk_length, + "top_p": args.top_p, + "repetition_penalty": args.repetition_penalty, + "temperature": args.temperature, + "speaker": args.speaker, + "emotion": args.emotion, + "format": args.format, + "streaming": args.streaming, + } + + response = requests.post(args.url, json=data, stream=args.streaming) + + audio_format = pyaudio.paInt16 # Assuming 16-bit PCM format + + if response.status_code == 200: + if args.streaming: + p = pyaudio.PyAudio() + stream = p.open( + format=audio_format, channels=args.channels, rate=args.rate, output=True + ) + + wf = wave.open("generated_audio.wav", "wb") + wf.setnchannels(args.channels) + wf.setsampwidth(p.get_sample_size(audio_format)) + wf.setframerate(args.rate) + + stream_stopped_flag = False + + try: + for chunk in response.iter_content(chunk_size=1024): + if chunk: + stream.write(chunk) + wf.writeframesraw(chunk) + else: + if not stream_stopped_flag: + stream.stop_stream() + stream_stopped_flag = True + finally: + stream.close() + p.terminate() + wf.close() + else: + audio_content = response.content + + with open("generated_audio.wav", "wb") as audio_file: + audio_file.write(audio_content) + + play_audio(audio_content, audio_format, args.channels, args.rate) + print("Audio has been saved to 'generated_audio.wav'.") + else: + print(f"Request failed with status code {response.status_code}") + print(response.json()) diff --git a/xinference/thirdparty/fish_speech/tools/sensevoice/README.md b/xinference/thirdparty/fish_speech/tools/sensevoice/README.md new file mode 100644 index 0000000000..9a2078aa2d --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/sensevoice/README.md @@ -0,0 +1,59 @@ +# FunASR Command Line Interface + +This tool provides a command-line interface for separating vocals from instrumental tracks, converting videos to audio, and performing speech-to-text transcription on the resulting audio files. + +## Requirements + +- Python >= 3.10 +- PyTorch <= 2.3.1 +- ffmpeg, pydub, audio-separator[gpu]. + +## Installation + +Install the required packages: + +```bash +pip install -e .[stable] +``` + +Make sure you have `ffmpeg` installed and available in your `PATH`. + +## Usage + +### Basic Usage + +To run the tool with default settings: + +```bash +python tools/sensevoice/fun_asr.py --audio-dir --save-dir +``` + +## Options + +| Option | Description | +| :-----------------------: | :---------------------------------------------------------------------------: | +| --audio-dir | Directory containing audio or video files. | +| --save-dir | Directory to save processed audio files. | +| --device | Device to use for processing. Options: cuda (default) or cpu. | +| --language | Language of the transcription. Default is auto. | +| --max_single_segment_time | Maximum duration of a single audio segment in milliseconds. Default is 20000. | +| --punc | Enable punctuation prediction. | +| --denoise | Enable noise reduction (vocal separation). | + +## Example + +To process audio files in the directory `path/to/audio` and save the output to `path/to/output`, with punctuation and noise reduction enabled: + +```bash +python tools/sensevoice/fun_asr.py --audio-dir path/to/audio --save-dir path/to/output --punc --denoise +``` + +## Additional Notes + +- The tool supports `both audio and video files`. Videos will be converted to audio automatically. +- If the `--denoise` option is used, the tool will perform vocal separation to isolate the vocals from the instrumental tracks. +- The script will automatically create necessary directories in the `--save-dir`. + +## Troubleshooting + +If you encounter any issues, make sure all dependencies are correctly installed and configured. For more detailed troubleshooting, refer to the documentation of each dependency. diff --git a/xinference/thirdparty/fish_speech/tools/sensevoice/__init__.py b/xinference/thirdparty/fish_speech/tools/sensevoice/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/tools/sensevoice/auto_model.py b/xinference/thirdparty/fish_speech/tools/sensevoice/auto_model.py new file mode 100644 index 0000000000..dd2e186617 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/sensevoice/auto_model.py @@ -0,0 +1,573 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8 -*- +# Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved. +# MIT License (https://opensource.org/licenses/MIT) + +import copy +import json +import logging +import os.path +import random +import re +import string +import time + +import numpy as np +import torch +from funasr.download.download_model_from_hub import download_model +from funasr.download.file import download_from_url +from funasr.register import tables +from funasr.train_utils.load_pretrained_model import load_pretrained_model +from funasr.train_utils.set_all_random_seed import set_all_random_seed +from funasr.utils import export_utils, misc +from funasr.utils.load_utils import load_audio_text_image_video, load_bytes +from funasr.utils.misc import deep_update +from funasr.utils.timestamp_tools import timestamp_sentence, timestamp_sentence_en +from tqdm import tqdm + +from .vad_utils import merge_vad, slice_padding_audio_samples + +try: + from funasr.models.campplus.cluster_backend import ClusterBackend + from funasr.models.campplus.utils import distribute_spk, postprocess, sv_chunk +except: + pass + + +def prepare_data_iterator(data_in, input_len=None, data_type=None, key=None): + """ """ + data_list = [] + key_list = [] + filelist = [".scp", ".txt", ".json", ".jsonl", ".text"] + + chars = string.ascii_letters + string.digits + if isinstance(data_in, str): + if data_in.startswith("http://") or data_in.startswith("https://"): # url + data_in = download_from_url(data_in) + + if isinstance(data_in, str) and os.path.exists( + data_in + ): # wav_path; filelist: wav.scp, file.jsonl;text.txt; + _, file_extension = os.path.splitext(data_in) + file_extension = file_extension.lower() + if file_extension in filelist: # filelist: wav.scp, file.jsonl;text.txt; + with open(data_in, encoding="utf-8") as fin: + for line in fin: + key = "rand_key_" + "".join(random.choice(chars) for _ in range(13)) + if data_in.endswith( + ".jsonl" + ): # file.jsonl: json.dumps({"source": data}) + lines = json.loads(line.strip()) + data = lines["source"] + key = data["key"] if "key" in data else key + else: # filelist, wav.scp, text.txt: id \t data or data + lines = line.strip().split(maxsplit=1) + data = lines[1] if len(lines) > 1 else lines[0] + key = lines[0] if len(lines) > 1 else key + + data_list.append(data) + key_list.append(key) + else: + if key is None: + # key = "rand_key_" + "".join(random.choice(chars) for _ in range(13)) + key = misc.extract_filename_without_extension(data_in) + data_list = [data_in] + key_list = [key] + elif isinstance(data_in, (list, tuple)): + if data_type is not None and isinstance( + data_type, (list, tuple) + ): # mutiple inputs + data_list_tmp = [] + for data_in_i, data_type_i in zip(data_in, data_type): + key_list, data_list_i = prepare_data_iterator( + data_in=data_in_i, data_type=data_type_i + ) + data_list_tmp.append(data_list_i) + data_list = [] + for item in zip(*data_list_tmp): + data_list.append(item) + else: + # [audio sample point, fbank, text] + data_list = data_in + key_list = [] + for data_i in data_in: + if isinstance(data_i, str) and os.path.exists(data_i): + key = misc.extract_filename_without_extension(data_i) + else: + if key is None: + key = "rand_key_" + "".join( + random.choice(chars) for _ in range(13) + ) + key_list.append(key) + + else: # raw text; audio sample point, fbank; bytes + if isinstance(data_in, bytes): # audio bytes + data_in = load_bytes(data_in) + if key is None: + key = "rand_key_" + "".join(random.choice(chars) for _ in range(13)) + data_list = [data_in] + key_list = [key] + + return key_list, data_list + + +class AutoModel: + + def __init__(self, **kwargs): + + try: + from funasr.utils.version_checker import check_for_update + + print( + "Check update of funasr, and it would cost few times. You may disable it by set `disable_update=True` in AutoModel" + ) + check_for_update(disable=kwargs.get("disable_update", False)) + except: + pass + + log_level = getattr(logging, kwargs.get("log_level", "INFO").upper()) + logging.basicConfig(level=log_level) + + model, kwargs = self.build_model(**kwargs) + + # if vad_model is not None, build vad model else None + vad_model = kwargs.get("vad_model", None) + vad_kwargs = ( + {} if kwargs.get("vad_kwargs", {}) is None else kwargs.get("vad_kwargs", {}) + ) + if vad_model is not None: + logging.info("Building VAD model.") + vad_kwargs["model"] = vad_model + vad_kwargs["model_revision"] = kwargs.get("vad_model_revision", "master") + vad_kwargs["device"] = kwargs["device"] + vad_model, vad_kwargs = self.build_model(**vad_kwargs) + + # if punc_model is not None, build punc model else None + punc_model = kwargs.get("punc_model", None) + punc_kwargs = ( + {} + if kwargs.get("punc_kwargs", {}) is None + else kwargs.get("punc_kwargs", {}) + ) + if punc_model is not None: + logging.info("Building punc model.") + punc_kwargs["model"] = punc_model + punc_kwargs["model_revision"] = kwargs.get("punc_model_revision", "master") + punc_kwargs["device"] = kwargs["device"] + punc_model, punc_kwargs = self.build_model(**punc_kwargs) + + # if spk_model is not None, build spk model else None + spk_model = kwargs.get("spk_model", None) + spk_kwargs = ( + {} if kwargs.get("spk_kwargs", {}) is None else kwargs.get("spk_kwargs", {}) + ) + if spk_model is not None: + logging.info("Building SPK model.") + spk_kwargs["model"] = spk_model + spk_kwargs["model_revision"] = kwargs.get("spk_model_revision", "master") + spk_kwargs["device"] = kwargs["device"] + spk_model, spk_kwargs = self.build_model(**spk_kwargs) + self.cb_model = ClusterBackend().to(kwargs["device"]) + spk_mode = kwargs.get("spk_mode", "punc_segment") + if spk_mode not in ["default", "vad_segment", "punc_segment"]: + logging.error( + "spk_mode should be one of default, vad_segment and punc_segment." + ) + self.spk_mode = spk_mode + + self.kwargs = kwargs + self.model = model + self.vad_model = vad_model + self.vad_kwargs = vad_kwargs + self.punc_model = punc_model + self.punc_kwargs = punc_kwargs + self.spk_model = spk_model + self.spk_kwargs = spk_kwargs + self.model_path = kwargs.get("model_path") + + @staticmethod + def build_model(**kwargs): + assert "model" in kwargs + if "model_conf" not in kwargs: + logging.info( + "download models from model hub: {}".format(kwargs.get("hub", "ms")) + ) + kwargs = download_model(**kwargs) + + set_all_random_seed(kwargs.get("seed", 0)) + + device = kwargs.get("device", "cuda") + if not torch.cuda.is_available() or kwargs.get("ngpu", 1) == 0: + device = "cpu" + kwargs["batch_size"] = 1 + kwargs["device"] = device + + torch.set_num_threads(kwargs.get("ncpu", 4)) + + # build tokenizer + tokenizer = kwargs.get("tokenizer", None) + if tokenizer is not None: + tokenizer_class = tables.tokenizer_classes.get(tokenizer) + tokenizer = tokenizer_class(**kwargs.get("tokenizer_conf", {})) + kwargs["token_list"] = ( + tokenizer.token_list if hasattr(tokenizer, "token_list") else None + ) + kwargs["token_list"] = ( + tokenizer.get_vocab() + if hasattr(tokenizer, "get_vocab") + else kwargs["token_list"] + ) + vocab_size = ( + len(kwargs["token_list"]) if kwargs["token_list"] is not None else -1 + ) + if vocab_size == -1 and hasattr(tokenizer, "get_vocab_size"): + vocab_size = tokenizer.get_vocab_size() + else: + vocab_size = -1 + kwargs["tokenizer"] = tokenizer + + # build frontend + frontend = kwargs.get("frontend", None) + kwargs["input_size"] = None + if frontend is not None: + frontend_class = tables.frontend_classes.get(frontend) + frontend = frontend_class(**kwargs.get("frontend_conf", {})) + kwargs["input_size"] = ( + frontend.output_size() if hasattr(frontend, "output_size") else None + ) + kwargs["frontend"] = frontend + # build model + model_class = tables.model_classes.get(kwargs["model"]) + assert model_class is not None, f'{kwargs["model"]} is not registered' + model_conf = {} + deep_update(model_conf, kwargs.get("model_conf", {})) + deep_update(model_conf, kwargs) + model = model_class(**model_conf, vocab_size=vocab_size) + + # init_param + init_param = kwargs.get("init_param", None) + if init_param is not None: + if os.path.exists(init_param): + logging.info(f"Loading pretrained params from {init_param}") + load_pretrained_model( + model=model, + path=init_param, + ignore_init_mismatch=kwargs.get("ignore_init_mismatch", True), + oss_bucket=kwargs.get("oss_bucket", None), + scope_map=kwargs.get("scope_map", []), + excludes=kwargs.get("excludes", None), + ) + else: + print(f"error, init_param does not exist!: {init_param}") + + # fp16 + if kwargs.get("fp16", False): + model.to(torch.float16) + elif kwargs.get("bf16", False): + model.to(torch.bfloat16) + model.to(device) + + if not kwargs.get("disable_log", True): + tables.print() + + return model, kwargs + + def __call__(self, *args, **cfg): + kwargs = self.kwargs + deep_update(kwargs, cfg) + res = self.model(*args, kwargs) + return res + + def generate(self, input, input_len=None, **cfg): + if self.vad_model is None: + return self.inference(input, input_len=input_len, **cfg) + + else: + return self.inference_with_vad(input, input_len=input_len, **cfg) + + def inference( + self, input, input_len=None, model=None, kwargs=None, key=None, **cfg + ): + kwargs = self.kwargs if kwargs is None else kwargs + if "cache" in kwargs: + kwargs.pop("cache") + deep_update(kwargs, cfg) + model = self.model if model is None else model + model.eval() + + batch_size = kwargs.get("batch_size", 1) + # if kwargs.get("device", "cpu") == "cpu": + # batch_size = 1 + + key_list, data_list = prepare_data_iterator( + input, input_len=input_len, data_type=kwargs.get("data_type", None), key=key + ) + + speed_stats = {} + asr_result_list = [] + num_samples = len(data_list) + disable_pbar = self.kwargs.get("disable_pbar", False) + pbar = ( + tqdm(colour="blue", total=num_samples, dynamic_ncols=True) + if not disable_pbar + else None + ) + time_speech_total = 0.0 + time_escape_total = 0.0 + for beg_idx in range(0, num_samples, batch_size): + end_idx = min(num_samples, beg_idx + batch_size) + data_batch = data_list[beg_idx:end_idx] + key_batch = key_list[beg_idx:end_idx] + batch = {"data_in": data_batch, "key": key_batch} + + if (end_idx - beg_idx) == 1 and kwargs.get( + "data_type", None + ) == "fbank": # fbank + batch["data_in"] = data_batch[0] + batch["data_lengths"] = input_len + + time1 = time.perf_counter() + with torch.no_grad(): + res = model.inference(**batch, **kwargs) + if isinstance(res, (list, tuple)): + results = res[0] if len(res) > 0 else [{"text": ""}] + meta_data = res[1] if len(res) > 1 else {} + time2 = time.perf_counter() + + asr_result_list.extend(results) + + # batch_data_time = time_per_frame_s * data_batch_i["speech_lengths"].sum().item() + batch_data_time = meta_data.get("batch_data_time", -1) + time_escape = time2 - time1 + speed_stats["load_data"] = meta_data.get("load_data", 0.0) + speed_stats["extract_feat"] = meta_data.get("extract_feat", 0.0) + speed_stats["forward"] = f"{time_escape:0.3f}" + speed_stats["batch_size"] = f"{len(results)}" + speed_stats["rtf"] = f"{(time_escape) / batch_data_time:0.3f}" + description = f"{speed_stats}, " + if pbar: + pbar.update(end_idx - beg_idx) + pbar.set_description(description) + time_speech_total += batch_data_time + time_escape_total += time_escape + + if pbar: + # pbar.update(1) + pbar.set_description(f"rtf_avg: {time_escape_total/time_speech_total:0.3f}") + torch.cuda.empty_cache() + return asr_result_list + + def vad(self, input, input_len=None, **cfg): + kwargs = self.kwargs + # step.1: compute the vad model + deep_update(self.vad_kwargs, cfg) + beg_vad = time.time() + res = self.inference( + input, + input_len=input_len, + model=self.vad_model, + kwargs=self.vad_kwargs, + **cfg, + ) + end_vad = time.time() + # FIX(gcf): concat the vad clips for sense vocie model for better aed + if cfg.get("merge_vad", False): + for i in range(len(res)): + res[i]["value"] = merge_vad( + res[i]["value"], kwargs.get("merge_length_s", 15) * 1000 + ) + elapsed = end_vad - beg_vad + return elapsed, res + + def inference_with_vadres(self, input, vad_res, input_len=None, **cfg): + + kwargs = self.kwargs + + # step.2 compute asr model + model = self.model + deep_update(kwargs, cfg) + batch_size = max(int(kwargs.get("batch_size_s", 300)) * 1000, 1) + batch_size_threshold_ms = int(kwargs.get("batch_size_threshold_s", 60)) * 1000 + kwargs["batch_size"] = batch_size + + key_list, data_list = prepare_data_iterator( + input, input_len=input_len, data_type=kwargs.get("data_type", None) + ) + results_ret_list = [] + time_speech_total_all_samples = 1e-6 + + beg_total = time.time() + pbar_total = ( + tqdm(colour="red", total=len(vad_res), dynamic_ncols=True) + if not kwargs.get("disable_pbar", False) + else None + ) + + for i in range(len(vad_res)): + key = vad_res[i]["key"] + vadsegments = vad_res[i]["value"] + input_i = data_list[i] + fs = kwargs["frontend"].fs if hasattr(kwargs["frontend"], "fs") else 16000 + speech = load_audio_text_image_video( + input_i, fs=fs, audio_fs=kwargs.get("fs", 16000) + ) + speech_lengths = len(speech) + n = len(vadsegments) + data_with_index = [(vadsegments[i], i) for i in range(n)] + sorted_data = sorted(data_with_index, key=lambda x: x[0][1] - x[0][0]) + results_sorted = [] + + if not len(sorted_data): + results_ret_list.append({"key": key, "text": "", "timestamp": []}) + logging.info("decoding, utt: {}, empty speech".format(key)) + continue + + if len(sorted_data) > 0 and len(sorted_data[0]) > 0: + batch_size = max( + batch_size, sorted_data[0][0][1] - sorted_data[0][0][0] + ) + + if kwargs["device"] == "cpu": + batch_size = 0 + + beg_idx = 0 + beg_asr_total = time.time() + time_speech_total_per_sample = speech_lengths / 16000 + time_speech_total_all_samples += time_speech_total_per_sample + + # pbar_sample = tqdm(colour="blue", total=n, dynamic_ncols=True) + + all_segments = [] + max_len_in_batch = 0 + end_idx = 1 + + for j, _ in enumerate(range(0, n)): + # pbar_sample.update(1) + sample_length = sorted_data[j][0][1] - sorted_data[j][0][0] + potential_batch_length = max(max_len_in_batch, sample_length) * ( + j + 1 - beg_idx + ) + # batch_size_ms_cum += sorted_data[j][0][1] - sorted_data[j][0][0] + if ( + j < n - 1 + and sample_length < batch_size_threshold_ms + and potential_batch_length < batch_size + ): + max_len_in_batch = max(max_len_in_batch, sample_length) + end_idx += 1 + continue + + speech_j, speech_lengths_j, intervals = slice_padding_audio_samples( + speech, speech_lengths, sorted_data[beg_idx:end_idx] + ) + results = self.inference( + speech_j, input_len=None, model=model, kwargs=kwargs, **cfg + ) + + for _b in range(len(speech_j)): + results[_b]["interval"] = intervals[_b] + + if self.spk_model is not None: + # compose vad segments: [[start_time_sec, end_time_sec, speech], [...]] + for _b in range(len(speech_j)): + vad_segments = [ + [ + sorted_data[beg_idx:end_idx][_b][0][0] / 1000.0, + sorted_data[beg_idx:end_idx][_b][0][1] / 1000.0, + np.array(speech_j[_b]), + ] + ] + segments = sv_chunk(vad_segments) + all_segments.extend(segments) + speech_b = [i[2] for i in segments] + spk_res = self.inference( + speech_b, + input_len=None, + model=self.spk_model, + kwargs=kwargs, + **cfg, + ) + results[_b]["spk_embedding"] = spk_res[0]["spk_embedding"] + + beg_idx = end_idx + end_idx += 1 + max_len_in_batch = sample_length + if len(results) < 1: + continue + results_sorted.extend(results) + + # end_asr_total = time.time() + # time_escape_total_per_sample = end_asr_total - beg_asr_total + # pbar_sample.update(1) + # pbar_sample.set_description(f"rtf_avg_per_sample: {time_escape_total_per_sample / time_speech_total_per_sample:0.3f}, " + # f"time_speech_total_per_sample: {time_speech_total_per_sample: 0.3f}, " + # f"time_escape_total_per_sample: {time_escape_total_per_sample:0.3f}") + + restored_data = [0] * n + for j in range(n): + index = sorted_data[j][1] + cur = results_sorted[j] + pattern = r"<\|([^|]+)\|>" + emotion_string = re.findall(pattern, cur["text"]) + cur["text"] = re.sub(pattern, "", cur["text"]) + cur["emo"] = "".join([f"<|{t}|>" for t in emotion_string]) + if self.punc_model is not None and len(cur["text"].strip()) > 0: + deep_update(self.punc_kwargs, cfg) + punc_res = self.inference( + cur["text"], + model=self.punc_model, + kwargs=self.punc_kwargs, + **cfg, + ) + cur["text"] = punc_res[0]["text"] + + restored_data[index] = cur + + end_asr_total = time.time() + time_escape_total_per_sample = end_asr_total - beg_asr_total + if pbar_total: + pbar_total.update(1) + pbar_total.set_description( + f"rtf_avg: {time_escape_total_per_sample / time_speech_total_per_sample:0.3f}, " + f"time_speech: {time_speech_total_per_sample: 0.3f}, " + f"time_escape: {time_escape_total_per_sample:0.3f}" + ) + + # end_total = time.time() + # time_escape_total_all_samples = end_total - beg_total + # print(f"rtf_avg_all: {time_escape_total_all_samples / time_speech_total_all_samples:0.3f}, " + # f"time_speech_all: {time_speech_total_all_samples: 0.3f}, " + # f"time_escape_all: {time_escape_total_all_samples:0.3f}") + return restored_data + + def export(self, input=None, **cfg): + """ + + :param input: + :param type: + :param quantize: + :param fallback_num: + :param calib_num: + :param opset_version: + :param cfg: + :return: + """ + + device = cfg.get("device", "cpu") + model = self.model.to(device=device) + kwargs = self.kwargs + deep_update(kwargs, cfg) + kwargs["device"] = device + del kwargs["model"] + model.eval() + + type = kwargs.get("type", "onnx") + + key_list, data_list = prepare_data_iterator( + input, input_len=None, data_type=kwargs.get("data_type", None), key=None + ) + + with torch.no_grad(): + export_dir = export_utils.export(model=model, data_in=data_list, **kwargs) + + return export_dir diff --git a/xinference/thirdparty/fish_speech/tools/sensevoice/fun_asr.py b/xinference/thirdparty/fish_speech/tools/sensevoice/fun_asr.py new file mode 100644 index 0000000000..02c15a5976 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/sensevoice/fun_asr.py @@ -0,0 +1,332 @@ +import gc +import os +import re + +from audio_separator.separator import Separator + +os.environ["MODELSCOPE_CACHE"] = "./.cache/funasr" +os.environ["UVR5_CACHE"] = "./.cache/uvr5-models" +import json +import subprocess +from pathlib import Path + +import click +import torch +from loguru import logger +from pydub import AudioSegment +from silero_vad import get_speech_timestamps, load_silero_vad, read_audio +from tqdm import tqdm + +from tools.file import AUDIO_EXTENSIONS, VIDEO_EXTENSIONS, list_files +from tools.sensevoice.auto_model import AutoModel + + +def uvr5_cli( + audio_dir: Path, + output_folder: Path, + audio_files: list[Path] | None = None, + output_format: str = "flac", + model: str = "BS-Roformer-Viperx-1296.ckpt", +): + # ["BS-Roformer-Viperx-1297.ckpt", "BS-Roformer-Viperx-1296.ckpt", "BS-Roformer-Viperx-1053.ckpt", "Mel-Roformer-Viperx-1143.ckpt"] + sepr = Separator( + model_file_dir=os.environ["UVR5_CACHE"], + output_dir=output_folder, + output_format=output_format, + ) + dictmodel = { + "BS-Roformer-Viperx-1297.ckpt": "model_bs_roformer_ep_317_sdr_12.9755.ckpt", + "BS-Roformer-Viperx-1296.ckpt": "model_bs_roformer_ep_368_sdr_12.9628.ckpt", + "BS-Roformer-Viperx-1053.ckpt": "model_bs_roformer_ep_937_sdr_10.5309.ckpt", + "Mel-Roformer-Viperx-1143.ckpt": "model_mel_band_roformer_ep_3005_sdr_11.4360.ckpt", + } + roformer_model = dictmodel[model] + sepr.load_model(roformer_model) + if audio_files is None: + audio_files = list_files( + path=audio_dir, extensions=AUDIO_EXTENSIONS, recursive=True + ) + total_files = len(audio_files) + + print(f"{total_files} audio files found") + + res = [] + for audio in tqdm(audio_files, desc="Denoising: "): + file_path = str(audio_dir / audio) + sep_out = sepr.separate(file_path) + if isinstance(sep_out, str): + res.append(sep_out) + elif isinstance(sep_out, list): + res.extend(sep_out) + del sepr + gc.collect() + if torch.cuda.is_available(): + torch.cuda.empty_cache() + + return res, roformer_model + + +def get_sample_rate(media_path: Path): + result = subprocess.run( + [ + "ffprobe", + "-v", + "quiet", + "-print_format", + "json", + "-show_streams", + str(media_path), + ], + capture_output=True, + text=True, + check=True, + ) + media_info = json.loads(result.stdout) + for stream in media_info.get("streams", []): + if stream.get("codec_type") == "audio": + return stream.get("sample_rate") + return "44100" # Default sample rate if not found + + +def convert_to_mono(src_path: Path, out_path: Path, out_fmt: str = "wav"): + sr = get_sample_rate(src_path) + out_path.parent.mkdir(parents=True, exist_ok=True) + if src_path.resolve() == out_path.resolve(): + output = str(out_path.with_stem(out_path.stem + f"_{sr}")) + else: + output = str(out_path) + subprocess.run( + [ + "ffmpeg", + "-loglevel", + "error", + "-i", + str(src_path), + "-acodec", + "pcm_s16le" if out_fmt == "wav" else "flac", + "-ar", + sr, + "-ac", + "1", + "-y", + output, + ], + check=True, + ) + return out_path + + +def convert_video_to_audio(video_path: Path, audio_dir: Path): + cur_dir = audio_dir / video_path.relative_to(audio_dir).parent + vocals = [ + p + for p in cur_dir.glob(f"{video_path.stem}_(Vocals)*.*") + if p.suffix in AUDIO_EXTENSIONS + ] + if len(vocals) > 0: + return vocals[0] + audio_path = cur_dir / f"{video_path.stem}.wav" + convert_to_mono(video_path, audio_path) + return audio_path + + +@click.command() +@click.option("--audio-dir", required=True, help="Directory containing audio files") +@click.option( + "--save-dir", required=True, help="Directory to save processed audio files" +) +@click.option("--device", default="cuda", help="Device to use [cuda / cpu]") +@click.option("--language", default="auto", help="Language of the transcription") +@click.option( + "--max_single_segment_time", + default=20000, + type=int, + help="Maximum of Output single audio duration(ms)", +) +@click.option("--fsmn-vad/--silero-vad", default=False) +@click.option("--punc/--no-punc", default=False) +@click.option("--denoise/--no-denoise", default=False) +@click.option("--save_emo/--no_save_emo", default=False) +def main( + audio_dir: str, + save_dir: str, + device: str, + language: str, + max_single_segment_time: int, + fsmn_vad: bool, + punc: bool, + denoise: bool, + save_emo: bool, +): + + audios_path = Path(audio_dir) + save_path = Path(save_dir) + save_path.mkdir(parents=True, exist_ok=True) + + video_files = list_files( + path=audio_dir, extensions=VIDEO_EXTENSIONS, recursive=True + ) + v2a_files = [convert_video_to_audio(p, audio_dir) for p in video_files] + + if denoise: + VOCAL = "_(Vocals)" + original_files = [ + p + for p in audios_path.glob("**/*") + if p.suffix in AUDIO_EXTENSIONS and VOCAL not in p.stem + ] + + _, cur_model = uvr5_cli( + audio_dir=audio_dir, output_folder=audio_dir, audio_files=original_files + ) + need_remove = [p for p in audios_path.glob("**/*(Instrumental)*")] + need_remove.extend(original_files) + for _ in need_remove: + _.unlink() + vocal_files = [ + p + for p in audios_path.glob("**/*") + if p.suffix in AUDIO_EXTENSIONS and VOCAL in p.stem + ] + for f in vocal_files: + fn, ext = f.stem, f.suffix + + v_pos = fn.find(VOCAL + "_" + cur_model.split(".")[0]) + if v_pos != -1: + new_fn = fn[: v_pos + len(VOCAL)] + new_f = f.with_name(new_fn + ext) + f = f.rename(new_f) + convert_to_mono(f, f, "flac") + f.unlink() + + audio_files = list_files( + path=audio_dir, extensions=AUDIO_EXTENSIONS, recursive=True + ) + + logger.info("Loading / Downloading Funasr model...") + + model_dir = "iic/SenseVoiceSmall" + + vad_model = "fsmn-vad" if fsmn_vad else None + vad_kwargs = {"max_single_segment_time": max_single_segment_time} + punc_model = "ct-punc" if punc else None + + manager = AutoModel( + model=model_dir, + trust_remote_code=False, + vad_model=vad_model, + vad_kwargs=vad_kwargs, + punc_model=punc_model, + device=device, + ) + + if not fsmn_vad and vad_model is None: + vad_model = load_silero_vad() + + logger.info("Model loaded.") + + pattern = re.compile(r"_\d{3}\.") + + for file_path in tqdm(audio_files, desc="Processing audio file"): + + if pattern.search(file_path.name): + # logger.info(f"Skipping {file_path} as it has already been processed.") + continue + + file_stem = file_path.stem + file_suffix = file_path.suffix + + rel_path = Path(file_path).relative_to(audio_dir) + (save_path / rel_path.parent).mkdir(parents=True, exist_ok=True) + + audio = AudioSegment.from_file(file_path) + + cfg = dict( + cache={}, + language=language, # "zh", "en", "yue", "ja", "ko", "nospeech" + use_itn=False, + batch_size_s=60, + ) + + if fsmn_vad: + elapsed, vad_res = manager.vad(input=str(file_path), **cfg) + else: + wav = read_audio( + str(file_path) + ) # backend (sox, soundfile, or ffmpeg) required! + audio_key = file_path.stem + audio_val = [] + speech_timestamps = get_speech_timestamps( + wav, + vad_model, + max_speech_duration_s=max_single_segment_time // 1000, + return_seconds=True, + ) + + audio_val = [ + [int(timestamp["start"] * 1000), int(timestamp["end"] * 1000)] + for timestamp in speech_timestamps + ] + vad_res = [] + vad_res.append(dict(key=audio_key, value=audio_val)) + + res = manager.inference_with_vadres( + input=str(file_path), vad_res=vad_res, **cfg + ) + + for i, info in enumerate(res): + [start_ms, end_ms] = info["interval"] + text = info["text"] + emo = info["emo"] + sliced_audio = audio[start_ms:end_ms] + audio_save_path = ( + save_path / rel_path.parent / f"{file_stem}_{i:03d}{file_suffix}" + ) + sliced_audio.export(audio_save_path, format=file_suffix[1:]) + print(f"Exported {audio_save_path}: {text}") + + transcript_save_path = ( + save_path / rel_path.parent / f"{file_stem}_{i:03d}.lab" + ) + with open( + transcript_save_path, + "w", + encoding="utf-8", + ) as f: + f.write(text) + + if save_emo: + emo_save_path = save_path / rel_path.parent / f"{file_stem}_{i:03d}.emo" + with open( + emo_save_path, + "w", + encoding="utf-8", + ) as f: + f.write(emo) + + if audios_path.resolve() == save_path.resolve(): + file_path.unlink() + + +if __name__ == "__main__": + main() + exit(0) + from funasr.utils.postprocess_utils import rich_transcription_postprocess + + # Load the audio file + audio_path = Path(r"D:\PythonProject\ok\1_output_(Vocals).wav") + model_dir = "iic/SenseVoiceSmall" + m, kwargs = SenseVoiceSmall.from_pretrained(model=model_dir, device="cuda:0") + m.eval() + + res = m.inference( + data_in=f"{kwargs['model_path']}/example/zh.mp3", + language="auto", # "zh", "en", "yue", "ja", "ko", "nospeech" + use_itn=False, + ban_emo_unk=False, + **kwargs, + ) + + print(res) + text = rich_transcription_postprocess(res[0][0]["text"]) + print(text) diff --git a/xinference/thirdparty/fish_speech/tools/sensevoice/vad_utils.py b/xinference/thirdparty/fish_speech/tools/sensevoice/vad_utils.py new file mode 100644 index 0000000000..3bef75ed8c --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/sensevoice/vad_utils.py @@ -0,0 +1,61 @@ +import torch +from torch.nn.utils.rnn import pad_sequence + + +def slice_padding_fbank(speech, speech_lengths, vad_segments): + speech_list = [] + speech_lengths_list = [] + for i, segment in enumerate(vad_segments): + + bed_idx = int(segment[0][0] * 16) + end_idx = min(int(segment[0][1] * 16), speech_lengths[0]) + speech_i = speech[0, bed_idx:end_idx] + speech_lengths_i = end_idx - bed_idx + speech_list.append(speech_i) + speech_lengths_list.append(speech_lengths_i) + feats_pad = pad_sequence(speech_list, batch_first=True, padding_value=0.0) + speech_lengths_pad = torch.Tensor(speech_lengths_list).int() + return feats_pad, speech_lengths_pad + + +def slice_padding_audio_samples(speech, speech_lengths, vad_segments): + speech_list = [] + speech_lengths_list = [] + intervals = [] + for i, segment in enumerate(vad_segments): + bed_idx = int(segment[0][0] * 16) + end_idx = min(int(segment[0][1] * 16), speech_lengths) + speech_i = speech[bed_idx:end_idx] + speech_lengths_i = end_idx - bed_idx + speech_list.append(speech_i) + speech_lengths_list.append(speech_lengths_i) + intervals.append([bed_idx // 16, end_idx // 16]) + + return speech_list, speech_lengths_list, intervals + + +def merge_vad(vad_result, max_length=15000, min_length=0): + new_result = [] + if len(vad_result) <= 1: + return vad_result + time_step = [t[0] for t in vad_result] + [t[1] for t in vad_result] + time_step = sorted(list(set(time_step))) + if len(time_step) == 0: + return [] + bg = 0 + for i in range(len(time_step) - 1): + time = time_step[i] + if time_step[i + 1] - bg < max_length: + continue + if time - bg > min_length: + new_result.append([bg, time]) + # if time - bg < max_length * 1.5: + # new_result.append([bg, time]) + # else: + # split_num = int(time - bg) // max_length + 1 + # spl_l = int(time - bg) // split_num + # for j in range(split_num): + # new_result.append([bg + j * spl_l, bg + (j + 1) * spl_l]) + bg = time + new_result.append([bg, time_step[-1]]) + return new_result diff --git a/xinference/thirdparty/fish_speech/tools/smart_pad.py b/xinference/thirdparty/fish_speech/tools/smart_pad.py new file mode 100644 index 0000000000..9772168f51 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/smart_pad.py @@ -0,0 +1,47 @@ +import random +from multiprocessing import Pool +from pathlib import Path + +import click +import librosa +import torch.nn.functional as F +import torchaudio +from tqdm import tqdm + +from tools.file import AUDIO_EXTENSIONS, list_files + +threshold = 10 ** (-50 / 20.0) + + +def process(file): + waveform, sample_rate = torchaudio.load(str(file), backend="sox") + loudness = librosa.feature.rms( + y=waveform.numpy().squeeze(), frame_length=2048, hop_length=512, center=True + )[0] + for i in range(len(loudness) - 1, 0, -1): + if loudness[i] > threshold: + break + + silent_time = (len(loudness) - i) * 512 / sample_rate + + if silent_time <= 0.3: + random_time = random.uniform(0.3, 0.7) + waveform = F.pad( + waveform, (0, int(random_time * sample_rate)), mode="constant", value=0 + ) + + torchaudio.save(uri=str(file), src=waveform, sample_rate=sample_rate) + + +@click.command() +@click.argument("source", type=Path) +@click.option("--num-workers", type=int, default=12) +def main(source, num_workers): + files = list(list_files(source, AUDIO_EXTENSIONS, recursive=True)) + + with Pool(num_workers) as p: + list(tqdm(p.imap_unordered(process, files), total=len(files))) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/vqgan/__init__.py b/xinference/thirdparty/fish_speech/tools/vqgan/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/fish_speech/tools/vqgan/create_train_split.py b/xinference/thirdparty/fish_speech/tools/vqgan/create_train_split.py new file mode 100644 index 0000000000..d24a5f3956 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/vqgan/create_train_split.py @@ -0,0 +1,83 @@ +import math +from pathlib import Path +from random import Random + +import click +from loguru import logger +from pydub import AudioSegment +from tqdm import tqdm + +from tools.file import AUDIO_EXTENSIONS, list_files, load_filelist + + +@click.command() +@click.argument("root", type=click.Path(exists=True, path_type=Path)) +@click.option("--val-ratio", type=float, default=None) +@click.option("--val-count", type=int, default=None) +@click.option("--filelist", default=None, type=Path) +@click.option("--min-duration", default=None, type=float) +@click.option("--max-duration", default=None, type=float) +def main(root, val_ratio, val_count, filelist, min_duration, max_duration): + if filelist: + files = [i[0] for i in load_filelist(filelist)] + else: + files = list_files(root, AUDIO_EXTENSIONS, recursive=True, sort=True) + + if min_duration is None and max_duration is None: + filtered_files = list(map(str, [file.relative_to(root) for file in files])) + else: + filtered_files = [] + for file in tqdm(files): + try: + audio = AudioSegment.from_file(str(file)) + duration = len(audio) / 1000.0 + + if min_duration is not None and duration < min_duration: + logger.info( + f"Skipping {file} due to duration {duration:.2f} < {min_duration:.2f}" + ) + continue + + if max_duration is not None and duration > max_duration: + logger.info( + f"Skipping {file} due to duration {duration:.2f} > {max_duration:.2f}" + ) + continue + + filtered_files.append(str(file.relative_to(root))) + except Exception as e: + logger.info(f"Error processing {file}: {e}") + + logger.info( + f"Found {len(files)} files, remaining {len(filtered_files)} files after filtering" + ) + + Random(42).shuffle(filtered_files) + + if val_count is None and val_ratio is None: + logger.info("Validation ratio and count not specified, using min(20%, 100)") + val_size = min(100, math.ceil(len(filtered_files) * 0.2)) + elif val_count is not None and val_ratio is not None: + logger.error("Cannot specify both val_count and val_ratio") + return + elif val_count is not None: + if val_count < 1 or val_count > len(filtered_files): + logger.error("val_count must be between 1 and number of files") + return + val_size = val_count + else: + val_size = math.ceil(len(filtered_files) * val_ratio) + + logger.info(f"Using {val_size} files for validation") + + with open(root / "vq_train_filelist.txt", "w", encoding="utf-8") as f: + f.write("\n".join(filtered_files[val_size:])) + + with open(root / "vq_val_filelist.txt", "w", encoding="utf-8") as f: + f.write("\n".join(filtered_files[:val_size])) + + logger.info("Done") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/vqgan/extract_vq.py b/xinference/thirdparty/fish_speech/tools/vqgan/extract_vq.py new file mode 100644 index 0000000000..bc6bc40830 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/vqgan/extract_vq.py @@ -0,0 +1,227 @@ +import os +import subprocess as sp +import sys +import time +from datetime import timedelta +from functools import lru_cache +from pathlib import Path +from random import Random + +import click +import numpy as np +import torch +import torchaudio +from hydra import compose, initialize +from hydra.utils import instantiate +from lightning import LightningModule +from loguru import logger +from omegaconf import OmegaConf + +from tools.file import AUDIO_EXTENSIONS, list_files, load_filelist + +# register eval resolver +OmegaConf.register_new_resolver("eval", eval) +# This file is used to convert the audio files to text files using the Whisper model. +# It's mainly used to generate the training data for the VQ model. + + +RANK = int(os.environ.get("SLURM_PROCID", 0)) +WORLD_SIZE = int(os.environ.get("SLURM_NTASKS", 1)) + +logger_format = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | " + "{level: <8} | " + "{name}:{function}:{line} | " + "{extra[rank]} - {message}" +) +logger.configure(extra={"rank": f"RANK: {RANK} / {WORLD_SIZE}"}) +logger.remove() +logger.add(sys.stderr, format=logger_format) + + +@lru_cache(maxsize=1) +def get_model( + config_name: str = "firefly_gan_vq", + checkpoint_path: str = "checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + device: str | torch.device = "cuda", +): + with initialize(version_base="1.3", config_path="../../fish_speech/configs"): + cfg = compose(config_name=config_name) + + model = instantiate(cfg) + state_dict = torch.load( + checkpoint_path, + map_location=device, + ) + if "state_dict" in state_dict: + state_dict = state_dict["state_dict"] + + if any("generator" in k for k in state_dict): + state_dict = { + k.replace("generator.", ""): v + for k, v in state_dict.items() + if "generator." in k + } + + model.load_state_dict(state_dict, strict=False) + model.eval() + model.to(device) + + logger.info(f"Loaded model") + return model + + +@torch.inference_mode() +def process_batch(files: list[Path], model) -> float: + wavs = [] + audio_lengths = [] + new_files = [] + max_length = total_time = 0 + + for file in files: + try: + wav, sr = torchaudio.load( + str(file), backend="sox" if sys.platform == "linux" else "soundfile" + ) # Need to install libsox-dev + except Exception as e: + logger.error(f"Error reading {file}: {e}") + continue + + if wav.shape[0] > 1: + wav = wav.mean(dim=0, keepdim=True) + + wav = torchaudio.functional.resample( + wav.cuda(), sr, model.spec_transform.sample_rate + )[0] + total_time += len(wav) / model.spec_transform.sample_rate + max_length = max(max_length, len(wav)) + + wavs.append(wav) + audio_lengths.append(len(wav)) + new_files.append(file) + + files = new_files + + # Pad to max length + for i, wav in enumerate(wavs): + wavs[i] = torch.nn.functional.pad(wav, (0, max_length - len(wav)), "constant") + + audios = torch.stack(wavs, dim=0)[:, None] + audio_lengths = torch.tensor(audio_lengths, device=model.device, dtype=torch.long) + + # Calculate lengths + indices, feature_lengths = model.encode(audios, audio_lengths) + + # Save to disk + outputs = indices.cpu().numpy() + + for file, length, feature, audio_length in zip( + files, feature_lengths, outputs, audio_lengths + ): + feature = feature[:, :length] + + # (T,) + with open(file.with_suffix(".npy"), "wb") as f: + np.save(f, feature) + + return total_time + + +@click.command() +@click.argument("folder") +@click.option("--num-workers", default=1) +@click.option("--config-name", default="firefly_gan_vq") +@click.option( + "--checkpoint-path", + default="checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", +) +@click.option("--batch-size", default=64) +@click.option("--filelist", default=None, type=Path) +def main( + folder: str, + num_workers: int, + config_name: str, + checkpoint_path: str, + batch_size: int, + filelist: Path, +): + if num_workers > 1 and WORLD_SIZE != num_workers: + assert WORLD_SIZE == 1, "You should either use SLURM or this launcher, not both" + + logger.info(f"Spawning {num_workers} workers") + + if torch.cuda.is_available(): + visible_devices = os.environ.get("CUDA_VISIBLE_DEVICES", None) + if visible_devices is None: + visible_devices = list(range(torch.cuda.device_count())) + else: + visible_devices = visible_devices.split(",") + else: + # Set to empty string to avoid using GPU + visible_devices = [""] + + processes = [] + for i in range(num_workers): + env = os.environ.copy() + env["CUDA_VISIBLE_DEVICES"] = str(visible_devices[i % len(visible_devices)]) + env["SLURM_PROCID"] = str(i) + env["SLURM_NTASKS"] = str(num_workers) + + processes.append( + sp.Popen( + [sys.executable] + sys.argv.copy(), + env=env, + ) + ) + + for p in processes: + p.wait() + + logger.info(f"All workers finished") + return + + # This is a worker + logger.info(f"Starting worker") + if filelist: + files = [i[0] for i in load_filelist(filelist)] + else: + files = list_files(folder, AUDIO_EXTENSIONS, recursive=True, sort=False) + + print(f"Found {len(files)} files") + files = [Path(f) for f in files if not Path(f).with_suffix(".npy").exists()] + + total_files = len(files) + files = files[RANK::WORLD_SIZE] + logger.info(f"Processing {len(files)}/{total_files} files") + + # Batch processing + total_time = 0 + begin_time = time.time() + processed_files = 0 + model = get_model(config_name, checkpoint_path) + + for n_batch, idx in enumerate(range(0, len(files), batch_size)): + batch = files[idx : idx + batch_size] + batch_time = process_batch(batch, model) + + total_time += batch_time + processed_files += len(batch) + + if (n_batch + 1) % 10 == 0: + eta = ( + (time.time() - begin_time) + / processed_files + * (len(files) - processed_files) + ) + logger.info( + f"Processed {processed_files} files, {total_time / 3600:.2f} hours of audio, " + + f"ETA: {timedelta(seconds=round(eta))}s" + ) + + logger.info( + f"Finished processing {len(files)} files, {total_time / 3600:.2f} hours of audio" + ) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/vqgan/inference.py b/xinference/thirdparty/fish_speech/tools/vqgan/inference.py new file mode 100644 index 0000000000..17c9034d7b --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/vqgan/inference.py @@ -0,0 +1,120 @@ +from pathlib import Path + +import click +import hydra +import numpy as np +import soundfile as sf +import torch +import torchaudio +from hydra import compose, initialize +from hydra.utils import instantiate +from loguru import logger +from omegaconf import OmegaConf + +from tools.file import AUDIO_EXTENSIONS + +# register eval resolver +OmegaConf.register_new_resolver("eval", eval) + + +def load_model(config_name, checkpoint_path, device="cuda"): + hydra.core.global_hydra.GlobalHydra.instance().clear() + with initialize(version_base="1.3", config_path="../../fish_speech/configs"): + cfg = compose(config_name=config_name) + + model = instantiate(cfg) + state_dict = torch.load( + checkpoint_path, + map_location=device, + ) + if "state_dict" in state_dict: + state_dict = state_dict["state_dict"] + + if any("generator" in k for k in state_dict): + state_dict = { + k.replace("generator.", ""): v + for k, v in state_dict.items() + if "generator." in k + } + + result = model.load_state_dict(state_dict, strict=False) + model.eval() + model.to(device) + + logger.info(f"Loaded model: {result}") + return model + + +@torch.no_grad() +@click.command() +@click.option( + "--input-path", + "-i", + default="test.wav", + type=click.Path(exists=True, path_type=Path), +) +@click.option( + "--output-path", "-o", default="fake.wav", type=click.Path(path_type=Path) +) +@click.option("--config-name", default="firefly_gan_vq") +@click.option( + "--checkpoint-path", + default="checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", +) +@click.option( + "--device", + "-d", + default="cuda", +) +def main(input_path, output_path, config_name, checkpoint_path, device): + model = load_model(config_name, checkpoint_path, device=device) + + if input_path.suffix in AUDIO_EXTENSIONS: + logger.info(f"Processing in-place reconstruction of {input_path}") + + # Load audio + audio, sr = torchaudio.load(str(input_path)) + if audio.shape[0] > 1: + audio = audio.mean(0, keepdim=True) + audio = torchaudio.functional.resample( + audio, sr, model.spec_transform.sample_rate + ) + + audios = audio[None].to(device) + logger.info( + f"Loaded audio with {audios.shape[2] / model.spec_transform.sample_rate:.2f} seconds" + ) + + # VQ Encoder + audio_lengths = torch.tensor([audios.shape[2]], device=device, dtype=torch.long) + indices = model.encode(audios, audio_lengths)[0][0] + + logger.info(f"Generated indices of shape {indices.shape}") + + # Save indices + np.save(output_path.with_suffix(".npy"), indices.cpu().numpy()) + elif input_path.suffix == ".npy": + logger.info(f"Processing precomputed indices from {input_path}") + indices = np.load(input_path) + indices = torch.from_numpy(indices).to(device).long() + assert indices.ndim == 2, f"Expected 2D indices, got {indices.ndim}" + else: + raise ValueError(f"Unknown input type: {input_path}") + + # Restore + feature_lengths = torch.tensor([indices.shape[1]], device=device) + fake_audios = model.decode(indices=indices[None], feature_lengths=feature_lengths) + audio_time = fake_audios.shape[-1] / model.spec_transform.sample_rate + + logger.info( + f"Generated audio of shape {fake_audios.shape}, equivalent to {audio_time:.2f} seconds from {indices.shape[1]} features, features/second: {indices.shape[1] / audio_time:.2f}" + ) + + # Save audio + fake_audio = fake_audios[0, 0].float().cpu().numpy() + sf.write(output_path, fake_audio, model.spec_transform.sample_rate) + logger.info(f"Saved audio to {output_path}") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/fish_speech/tools/webui.py b/xinference/thirdparty/fish_speech/tools/webui.py new file mode 100644 index 0000000000..f64ff923b0 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/webui.py @@ -0,0 +1,619 @@ +import gc +import html +import io +import os +import queue +import wave +from argparse import ArgumentParser +from functools import partial +from pathlib import Path + +import gradio as gr +import librosa +import numpy as np +# import pyrootutils +import torch +from loguru import logger +from transformers import AutoTokenizer + +# pyrootutils.setup_root(__file__, indicator=".project-root", pythonpath=True) + + +from fish_speech.i18n import i18n +from fish_speech.text.chn_text_norm.text import Text as ChnNormedText +from fish_speech.utils import autocast_exclude_mps +from tools.api import decode_vq_tokens, encode_reference +from tools.auto_rerank import batch_asr, calculate_wer, is_chinese, load_model +from tools.llama.generate import ( + GenerateRequest, + GenerateResponse, + WrappedGenerateResponse, + launch_thread_safe_queue, +) +from tools.vqgan.inference import load_model as load_decoder_model + +# Make einx happy +os.environ["EINX_FILTER_TRACEBACK"] = "false" + + +HEADER_MD = f"""# Fish Speech + +{i18n("A text-to-speech model based on VQ-GAN and Llama developed by [Fish Audio](https://fish.audio).")} + +{i18n("You can find the source code [here](https://github.com/fishaudio/fish-speech) and models [here](https://huggingface.co/fishaudio/fish-speech-1).")} + +{i18n("Related code are released under BSD-3-Clause License, and weights are released under CC BY-NC-SA 4.0 License.")} + +{i18n("We are not responsible for any misuse of the model, please consider your local laws and regulations before using it.")} +""" + +TEXTBOX_PLACEHOLDER = i18n("Put your text here.") +SPACE_IMPORTED = False + + +def build_html_error_message(error): + return f""" +
+ {html.escape(str(error))} +
+ """ + + +@torch.inference_mode() +def inference( + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + streaming=False, +): + if args.max_gradio_length > 0 and len(text) > args.max_gradio_length: + return ( + None, + None, + i18n("Text is too long, please keep it under {} characters.").format( + args.max_gradio_length + ), + ) + + # Parse reference audio aka prompt + prompt_tokens = encode_reference( + decoder_model=decoder_model, + reference_audio=reference_audio, + enable_reference_audio=enable_reference_audio, + ) + + # LLAMA Inference + request = dict( + device=decoder_model.device, + max_new_tokens=max_new_tokens, + text=text, + top_p=top_p, + repetition_penalty=repetition_penalty, + temperature=temperature, + compile=args.compile, + iterative_prompt=chunk_length > 0, + chunk_length=chunk_length, + max_length=2048, + prompt_tokens=prompt_tokens if enable_reference_audio else None, + prompt_text=reference_text if enable_reference_audio else None, + ) + + response_queue = queue.Queue() + llama_queue.put( + GenerateRequest( + request=request, + response_queue=response_queue, + ) + ) + + if streaming: + yield wav_chunk_header(), None, None + + segments = [] + + while True: + result: WrappedGenerateResponse = response_queue.get() + if result.status == "error": + yield None, None, build_html_error_message(result.response) + break + + result: GenerateResponse = result.response + if result.action == "next": + break + + with autocast_exclude_mps( + device_type=decoder_model.device.type, dtype=args.precision + ): + fake_audios = decode_vq_tokens( + decoder_model=decoder_model, + codes=result.codes, + ) + + fake_audios = fake_audios.float().cpu().numpy() + segments.append(fake_audios) + + if streaming: + yield (fake_audios * 32768).astype(np.int16).tobytes(), None, None + + if len(segments) == 0: + return ( + None, + None, + build_html_error_message( + i18n("No audio generated, please check the input text.") + ), + ) + + # No matter streaming or not, we need to return the final audio + audio = np.concatenate(segments, axis=0) + yield None, (decoder_model.spec_transform.sample_rate, audio), None + + if torch.cuda.is_available(): + torch.cuda.empty_cache() + gc.collect() + + +def inference_with_auto_rerank( + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + use_auto_rerank, + streaming=False, +): + + max_attempts = 2 if use_auto_rerank else 1 + best_wer = float("inf") + best_audio = None + best_sample_rate = None + + for attempt in range(max_attempts): + audio_generator = inference( + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + streaming=False, + ) + + # 获取音频数据 + for _ in audio_generator: + pass + _, (sample_rate, audio), message = _ + + if audio is None: + return None, None, message + + if not use_auto_rerank: + return None, (sample_rate, audio), None + + asr_result = batch_asr(asr_model, [audio], sample_rate)[0] + wer = calculate_wer(text, asr_result["text"]) + if wer <= 0.3 and not asr_result["huge_gap"]: + return None, (sample_rate, audio), None + + if wer < best_wer: + best_wer = wer + best_audio = audio + best_sample_rate = sample_rate + + if attempt == max_attempts - 1: + break + + return None, (best_sample_rate, best_audio), None + + +inference_stream = partial(inference, streaming=True) + +n_audios = 4 + +global_audio_list = [] +global_error_list = [] + + +def inference_wrapper( + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + batch_infer_num, + if_load_asr_model, +): + audios = [] + errors = [] + + for _ in range(batch_infer_num): + result = inference_with_auto_rerank( + text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + if_load_asr_model, + ) + + _, audio_data, error_message = result + + audios.append( + gr.Audio(value=audio_data if audio_data else None, visible=True), + ) + errors.append( + gr.HTML(value=error_message if error_message else None, visible=True), + ) + + for _ in range(batch_infer_num, n_audios): + audios.append( + gr.Audio(value=None, visible=False), + ) + errors.append( + gr.HTML(value=None, visible=False), + ) + + return None, *audios, *errors + + +def wav_chunk_header(sample_rate=44100, bit_depth=16, channels=1): + buffer = io.BytesIO() + + with wave.open(buffer, "wb") as wav_file: + wav_file.setnchannels(channels) + wav_file.setsampwidth(bit_depth // 8) + wav_file.setframerate(sample_rate) + + wav_header_bytes = buffer.getvalue() + buffer.close() + return wav_header_bytes + + +def normalize_text(user_input, use_normalization): + if use_normalization: + return ChnNormedText(raw_text=user_input).normalize() + else: + return user_input + + +asr_model = None + + +def change_if_load_asr_model(if_load): + global asr_model + + if if_load: + gr.Warning("Loading faster whisper model...") + if asr_model is None: + asr_model = load_model() + return gr.Checkbox(label="Unload faster whisper model", value=if_load) + + if if_load is False: + gr.Warning("Unloading faster whisper model...") + del asr_model + asr_model = None + if torch.cuda.is_available(): + torch.cuda.empty_cache() + gc.collect() + return gr.Checkbox(label="Load faster whisper model", value=if_load) + + +def change_if_auto_label(if_load, if_auto_label, enable_ref, ref_audio, ref_text): + if if_load and asr_model is not None: + if ( + if_auto_label + and enable_ref + and ref_audio is not None + and ref_text.strip() == "" + ): + data, sample_rate = librosa.load(ref_audio) + res = batch_asr(asr_model, [data], sample_rate)[0] + ref_text = res["text"] + else: + gr.Warning("Whisper model not loaded!") + + return gr.Textbox(value=ref_text) + + +def build_app(): + with gr.Blocks(theme=gr.themes.Base()) as app: + gr.Markdown(HEADER_MD) + + # Use light theme by default + app.load( + None, + None, + js="() => {const params = new URLSearchParams(window.location.search);if (!params.has('__theme')) {params.set('__theme', '%s');window.location.search = params.toString();}}" + % args.theme, + ) + + # Inference + with gr.Row(): + with gr.Column(scale=3): + text = gr.Textbox( + label=i18n("Input Text"), placeholder=TEXTBOX_PLACEHOLDER, lines=10 + ) + refined_text = gr.Textbox( + label=i18n("Realtime Transform Text"), + placeholder=i18n( + "Normalization Result Preview (Currently Only Chinese)" + ), + lines=5, + interactive=False, + ) + + with gr.Row(): + if_refine_text = gr.Checkbox( + label=i18n("Text Normalization"), + value=True, + scale=1, + ) + + if_load_asr_model = gr.Checkbox( + label=i18n("Load / Unload ASR model for auto-reranking"), + value=False, + scale=3, + ) + + with gr.Row(): + with gr.Tab(label=i18n("Advanced Config")): + chunk_length = gr.Slider( + label=i18n("Iterative Prompt Length, 0 means off"), + minimum=0, + maximum=500, + value=100, + step=8, + ) + + max_new_tokens = gr.Slider( + label=i18n("Maximum tokens per batch, 0 means no limit"), + minimum=0, + maximum=2048, + value=1024, # 0 means no limit + step=8, + ) + + top_p = gr.Slider( + label="Top-P", + minimum=0.6, + maximum=0.9, + value=0.7, + step=0.01, + ) + + repetition_penalty = gr.Slider( + label=i18n("Repetition Penalty"), + minimum=1, + maximum=1.5, + value=1.2, + step=0.01, + ) + + temperature = gr.Slider( + label="Temperature", + minimum=0.6, + maximum=0.9, + value=0.7, + step=0.01, + ) + + with gr.Tab(label=i18n("Reference Audio")): + gr.Markdown( + i18n( + "5 to 10 seconds of reference audio, useful for specifying speaker." + ) + ) + + enable_reference_audio = gr.Checkbox( + label=i18n("Enable Reference Audio"), + ) + reference_audio = gr.Audio( + label=i18n("Reference Audio"), + type="filepath", + ) + with gr.Row(): + if_auto_label = gr.Checkbox( + label=i18n("Auto Labeling"), + min_width=100, + scale=0, + value=False, + ) + reference_text = gr.Textbox( + label=i18n("Reference Text"), + lines=1, + placeholder="在一无所知中,梦里的一天结束了,一个新的「轮回」便会开始。", + value="", + ) + with gr.Tab(label=i18n("Batch Inference")): + batch_infer_num = gr.Slider( + label="Batch infer nums", + minimum=1, + maximum=n_audios, + step=1, + value=1, + ) + + with gr.Column(scale=3): + for _ in range(n_audios): + with gr.Row(): + error = gr.HTML( + label=i18n("Error Message"), + visible=True if _ == 0 else False, + ) + global_error_list.append(error) + with gr.Row(): + audio = gr.Audio( + label=i18n("Generated Audio"), + type="numpy", + interactive=False, + visible=True if _ == 0 else False, + ) + global_audio_list.append(audio) + + with gr.Row(): + stream_audio = gr.Audio( + label=i18n("Streaming Audio"), + streaming=True, + autoplay=True, + interactive=False, + show_download_button=True, + ) + with gr.Row(): + with gr.Column(scale=3): + generate = gr.Button( + value="\U0001F3A7 " + i18n("Generate"), variant="primary" + ) + generate_stream = gr.Button( + value="\U0001F3A7 " + i18n("Streaming Generate"), + variant="primary", + ) + + text.input( + fn=normalize_text, inputs=[text, if_refine_text], outputs=[refined_text] + ) + + if_load_asr_model.change( + fn=change_if_load_asr_model, + inputs=[if_load_asr_model], + outputs=[if_load_asr_model], + ) + + if_auto_label.change( + fn=lambda: gr.Textbox(value=""), + inputs=[], + outputs=[reference_text], + ).then( + fn=change_if_auto_label, + inputs=[ + if_load_asr_model, + if_auto_label, + enable_reference_audio, + reference_audio, + reference_text, + ], + outputs=[reference_text], + ) + + # # Submit + generate.click( + inference_wrapper, + [ + refined_text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + batch_infer_num, + if_load_asr_model, + ], + [stream_audio, *global_audio_list, *global_error_list], + concurrency_limit=1, + ) + + generate_stream.click( + inference_stream, + [ + refined_text, + enable_reference_audio, + reference_audio, + reference_text, + max_new_tokens, + chunk_length, + top_p, + repetition_penalty, + temperature, + ], + [stream_audio, global_audio_list[0], global_error_list[0]], + concurrency_limit=10, + ) + return app + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument( + "--llama-checkpoint-path", + type=Path, + default="checkpoints/fish-speech-1.2-sft", + ) + parser.add_argument( + "--decoder-checkpoint-path", + type=Path, + default="checkpoints/fish-speech-1.2-sft/firefly-gan-vq-fsq-4x1024-42hz-generator.pth", + ) + parser.add_argument("--decoder-config-name", type=str, default="firefly_gan_vq") + parser.add_argument("--device", type=str, default="cuda") + parser.add_argument("--half", action="store_true") + parser.add_argument("--compile", action="store_true") + parser.add_argument("--max-gradio-length", type=int, default=0) + parser.add_argument("--theme", type=str, default="light") + + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + args.precision = torch.half if args.half else torch.bfloat16 + + logger.info("Loading Llama model...") + llama_queue = launch_thread_safe_queue( + checkpoint_path=args.llama_checkpoint_path, + device=args.device, + precision=args.precision, + compile=args.compile, + ) + logger.info("Llama model loaded, loading VQ-GAN model...") + + decoder_model = load_decoder_model( + config_name=args.decoder_config_name, + checkpoint_path=args.decoder_checkpoint_path, + device=args.device, + ) + + logger.info("Decoder model loaded, warming up...") + + # Dry run to check if the model is loaded correctly and avoid the first-time latency + list( + inference( + text="Hello, world!", + enable_reference_audio=False, + reference_audio=None, + reference_text="", + max_new_tokens=0, + chunk_length=100, + top_p=0.7, + repetition_penalty=1.2, + temperature=0.7, + ) + ) + + logger.info("Warming up done, launching the web UI...") + + app = build_app() + app.launch(show_api=True) diff --git a/xinference/thirdparty/fish_speech/tools/whisper_asr.py b/xinference/thirdparty/fish_speech/tools/whisper_asr.py new file mode 100644 index 0000000000..42e7de8a18 --- /dev/null +++ b/xinference/thirdparty/fish_speech/tools/whisper_asr.py @@ -0,0 +1,176 @@ +""" +Used to transcribe all audio files in one folder into another folder. +e.g. +Directory structure: +--pre_data_root +----SP_1 +------01.wav +------02.wav +------...... +----SP_2 +------01.wav +------02.wav +------...... +Use +python tools/whisper_asr.py --audio-dir pre_data_root/SP_1 --save-dir data/SP_1 +to transcribe the first speaker. + +Use +python tools/whisper_asr.py --audio-dir pre_data_root/SP_2 --save-dir data/SP_2 +to transcribe the second speaker. + +Note: Be aware of your audio sample rate, which defaults to 44.1kHz. +""" + +import re +from pathlib import Path + +import click +import soundfile as sf +from faster_whisper import WhisperModel +from loguru import logger +from pydub import AudioSegment +from tqdm import tqdm + +from tools.file import AUDIO_EXTENSIONS, list_files + + +@click.command() +@click.option("--model-size", default="large-v3", help="Size of the Whisper model") +@click.option( + "--compute-type", + default="float16", + help="Computation Precision of the Whisper model [float16 / int8_float16 / int8]", +) +@click.option("--audio-dir", required=True, help="Directory containing audio files") +@click.option( + "--save-dir", required=True, help="Directory to save processed audio files" +) +@click.option( + "--sample-rate", + default=44100, + type=int, + help="Output sample rate, default to input sample rate", +) +@click.option("--device", default="cuda", help="Device to use [cuda / cpu]") +@click.option("--language", default="auto", help="Language of the transcription") +@click.option("--initial-prompt", default=None, help="Initial prompt for transcribing") +def main( + model_size, + compute_type, + audio_dir, + save_dir, + sample_rate, + device, + language, + initial_prompt, +): + logger.info("Loading / Downloading Faster Whisper model...") + + model = WhisperModel( + model_size, + device=device, + compute_type=compute_type, + download_root="faster_whisper", + ) + + logger.info("Model loaded.") + + save_path = Path(save_dir) + save_path.mkdir(parents=True, exist_ok=True) + + audio_files = list_files( + path=audio_dir, extensions=AUDIO_EXTENSIONS, recursive=True + ) + + for file_path in tqdm(audio_files, desc="Processing audio file"): + file_stem = file_path.stem + file_suffix = file_path.suffix + + rel_path = Path(file_path).relative_to(audio_dir) + (save_path / rel_path.parent).mkdir(parents=True, exist_ok=True) + + audio = AudioSegment.from_file(file_path) + + segments, info = model.transcribe( + file_path, + beam_size=5, + language=None if language == "auto" else language, + initial_prompt=initial_prompt, + ) + + print( + "Detected language '%s' with probability %f" + % (info.language, info.language_probability) + ) + print("Total len(ms): ", len(audio)) + + whole_text = None + for segment in segments: + id, start, end, text = ( + segment.id, + segment.start, + segment.end, + segment.text, + ) + print("Segment %03d [%.2fs -> %.2fs] %s" % (id, start, end, text)) + if not whole_text: + whole_text = text + else: + whole_text += ", " + text + + whole_text += "." + + audio_save_path = save_path / rel_path.parent / f"{file_stem}{file_suffix}" + audio.export(audio_save_path, format=file_suffix[1:]) + print(f"Exported {audio_save_path}") + + transcript_save_path = save_path / rel_path.parent / f"{file_stem}.lab" + with open( + transcript_save_path, + "w", + encoding="utf-8", + ) as f: + f.write(whole_text) + + +if __name__ == "__main__": + main() + exit(0) + + audio = AudioSegment.from_wav( + r"D:\PythonProject\原神语音中文\胡桃\vo_hutao_draw_appear.wav" + ) + + model_size = "large-v3" + + model = WhisperModel( + model_size, + device="cuda", + compute_type="float16", + download_root="faster_whisper", + ) + + segments, info = model.transcribe( + r"D:\PythonProject\原神语音中文\胡桃\vo_hutao_draw_appear.wav", + beam_size=5, + ) + + print( + "Detected language '%s' with probability %f" + % (info.language, info.language_probability) + ) + print("Total len(ms): ", len(audio)) + + for i, segment in enumerate(segments): + print( + "Segment %03d [%.2fs -> %.2fs] %s" + % (i, segment.start, segment.end, segment.text) + ) + start_ms = int(segment.start * 1000) + end_ms = int(segment.end * 1000) + segment_audio = audio[start_ms:end_ms] + segment_audio.export(f"segment_{i:03d}.wav", format="wav") + print(f"Exported segment_{i:03d}.wav") + + print("All segments have been exported.") diff --git a/xinference/thirdparty/internvl/__init__.py b/xinference/thirdparty/internvl/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/internvl/conversation.py b/xinference/thirdparty/internvl/conversation.py new file mode 100644 index 0000000000..2fe37ad08c --- /dev/null +++ b/xinference/thirdparty/internvl/conversation.py @@ -0,0 +1,393 @@ +""" +Conversation prompt templates. + +We kindly request that you import fastchat instead of copying this file if you wish to use it. +If you have changes in mind, please contribute back so the community can benefit collectively and continue to maintain these valuable templates. +""" + +import dataclasses +from enum import IntEnum, auto +from typing import Any, Dict, List, Tuple, Union + + +class SeparatorStyle(IntEnum): + """Separator styles.""" + + ADD_COLON_SINGLE = auto() + ADD_COLON_TWO = auto() + ADD_COLON_SPACE_SINGLE = auto() + NO_COLON_SINGLE = auto() + NO_COLON_TWO = auto() + ADD_NEW_LINE_SINGLE = auto() + LLAMA2 = auto() + CHATGLM = auto() + CHATML = auto() + CHATINTERN = auto() + DOLLY = auto() + RWKV = auto() + PHOENIX = auto() + ROBIN = auto() + FALCON_CHAT = auto() + CHATGLM3 = auto() + INTERNVL_ZH = auto() + MPT = auto() + + +@dataclasses.dataclass +class Conversation: + """A class that manages prompt templates and keeps all conversation history.""" + + # The name of this template + name: str + # The template of the system prompt + system_template: str = '{system_message}' + # The system message + system_message: str = '' + # The names of two roles + roles: Tuple[str] = ('USER', 'ASSISTANT') + # All messages. Each item is (role, message). + messages: List[List[str]] = () + # The number of few shot examples + offset: int = 0 + # The separator style and configurations + sep_style: SeparatorStyle = SeparatorStyle.ADD_COLON_SINGLE + sep: str = '\n' + sep2: str = None + # Stop criteria (the default one is EOS token) + stop_str: Union[str, List[str]] = None + # Stops generation if meeting any token in this list + stop_token_ids: List[int] = None + + def get_prompt(self) -> str: + """Get the prompt for generation.""" + system_prompt = self.system_template.format(system_message=self.system_message) + if self.sep_style == SeparatorStyle.ADD_COLON_SINGLE: + ret = system_prompt + self.sep + for role, message in self.messages: + if message: + ret += role + ': ' + message + self.sep + else: + ret += role + ':' + return ret + elif self.sep_style == SeparatorStyle.ADD_COLON_TWO: + seps = [self.sep, self.sep2] + ret = system_prompt + seps[0] + for i, (role, message) in enumerate(self.messages): + if message: + ret += role + ': ' + message + seps[i % 2] + else: + ret += role + ':' + return ret + elif self.sep_style == SeparatorStyle.ADD_COLON_SPACE_SINGLE: + ret = system_prompt + self.sep + for role, message in self.messages: + if message: + ret += role + ': ' + message + self.sep + else: + ret += role + ': ' # must be end with a space + return ret + elif self.sep_style == SeparatorStyle.ADD_NEW_LINE_SINGLE: + ret = '' if system_prompt == '' else system_prompt + self.sep + for role, message in self.messages: + if message: + ret += role + '\n' + message + self.sep + else: + ret += role + '\n' + return ret + elif self.sep_style == SeparatorStyle.NO_COLON_SINGLE: + ret = system_prompt + for role, message in self.messages: + if message: + ret += role + message + self.sep + else: + ret += role + return ret + elif self.sep_style == SeparatorStyle.NO_COLON_TWO: + seps = [self.sep, self.sep2] + ret = system_prompt + for i, (role, message) in enumerate(self.messages): + if message: + ret += role + message + seps[i % 2] + else: + ret += role + return ret + elif self.sep_style == SeparatorStyle.RWKV: + ret = system_prompt + for i, (role, message) in enumerate(self.messages): + if message: + ret += ( + role + + ': ' + + message.replace('\r\n', '\n').replace('\n\n', '\n') + ) + ret += '\n\n' + else: + ret += role + ':' + return ret + elif self.sep_style == SeparatorStyle.LLAMA2: + seps = [self.sep, self.sep2] + if self.system_message: + ret = system_prompt + else: + ret = '[INST] ' + for i, (role, message) in enumerate(self.messages): + tag = self.roles[i % 2] + if message: + if i == 0: + ret += message + ' ' + else: + ret += tag + ' ' + message + seps[i % 2] + else: + ret += tag + return ret + elif self.sep_style == SeparatorStyle.CHATGLM: + # source: https://huggingface.co/THUDM/chatglm-6b/blob/1d240ba371910e9282298d4592532d7f0f3e9f3e/modeling_chatglm.py#L1302-L1308 + # source2: https://huggingface.co/THUDM/chatglm2-6b/blob/e186c891cf64310ac66ef10a87e6635fa6c2a579/modeling_chatglm.py#L926 + round_add_n = 1 if self.name == 'chatglm2' else 0 + if system_prompt: + ret = system_prompt + self.sep + else: + ret = '' + + for i, (role, message) in enumerate(self.messages): + if i % 2 == 0: + ret += f'[Round {i//2 + round_add_n}]{self.sep}' + + if message: + ret += f'{role}:{message}{self.sep}' + else: + ret += f'{role}:' + return ret + elif self.sep_style == SeparatorStyle.CHATML: + ret = '' if system_prompt == '' else system_prompt + self.sep + '\n' + for role, message in self.messages: + if message: + ret += role + '\n' + message + self.sep + '\n' + else: + ret += role + '\n' + return ret + elif self.sep_style == SeparatorStyle.CHATGLM3: + ret = '' + if self.system_message: + ret += system_prompt + for role, message in self.messages: + if message: + ret += role + '\n' + ' ' + message + else: + ret += role + return ret + elif self.sep_style == SeparatorStyle.CHATINTERN: + # source: https://huggingface.co/internlm/internlm-chat-7b-8k/blob/bd546fa984b4b0b86958f56bf37f94aa75ab8831/modeling_internlm.py#L771 + seps = [self.sep, self.sep2] + ret = system_prompt + for i, (role, message) in enumerate(self.messages): + # if i % 2 == 0: + # ret += "" + if message: + ret += role + ':' + message + seps[i % 2] + '\n' + else: + ret += role + ':' + return ret + elif self.sep_style == SeparatorStyle.DOLLY: + seps = [self.sep, self.sep2] + ret = system_prompt + for i, (role, message) in enumerate(self.messages): + if message: + ret += role + ':\n' + message + seps[i % 2] + if i % 2 == 1: + ret += '\n\n' + else: + ret += role + ':\n' + return ret + elif self.sep_style == SeparatorStyle.PHOENIX: + ret = system_prompt + for role, message in self.messages: + if message: + ret += role + ': ' + '' + message + '' + else: + ret += role + ': ' + '' + return ret + elif self.sep_style == SeparatorStyle.ROBIN: + ret = system_prompt + self.sep + for role, message in self.messages: + if message: + ret += role + ':\n' + message + self.sep + else: + ret += role + ':\n' + return ret + elif self.sep_style == SeparatorStyle.FALCON_CHAT: + ret = '' + if self.system_message: + ret += system_prompt + self.sep + for role, message in self.messages: + if message: + ret += role + ': ' + message + self.sep + else: + ret += role + ':' + + return ret + elif self.sep_style == SeparatorStyle.INTERNVL_ZH: + seps = [self.sep, self.sep2] + ret = self.system_message + seps[0] + for i, (role, message) in enumerate(self.messages): + if message: + ret += role + ': ' + message + seps[i % 2] + else: + ret += role + ':' + return ret + elif self.sep_style == SeparatorStyle.MPT: + ret = system_prompt + self.sep + for role, message in self.messages: + if message: + if type(message) is tuple: + message, _, _ = message + ret += role + message + self.sep + else: + ret += role + return ret + else: + raise ValueError(f'Invalid style: {self.sep_style}') + + def set_system_message(self, system_message: str): + """Set the system message.""" + self.system_message = system_message + + def append_message(self, role: str, message: str): + """Append a new message.""" + self.messages.append([role, message]) + + def update_last_message(self, message: str): + """Update the last output. + + The last message is typically set to be None when constructing the prompt, + so we need to update it in-place after getting the response from a model. + """ + self.messages[-1][1] = message + + def to_gradio_chatbot(self): + """Convert the conversation to gradio chatbot format.""" + ret = [] + for i, (role, msg) in enumerate(self.messages[self.offset :]): + if i % 2 == 0: + ret.append([msg, None]) + else: + ret[-1][-1] = msg + return ret + + def to_openai_api_messages(self): + """Convert the conversation to OpenAI chat completion format.""" + ret = [{'role': 'system', 'content': self.system_message}] + + for i, (_, msg) in enumerate(self.messages[self.offset :]): + if i % 2 == 0: + ret.append({'role': 'user', 'content': msg}) + else: + if msg is not None: + ret.append({'role': 'assistant', 'content': msg}) + return ret + + def copy(self): + return Conversation( + name=self.name, + system_template=self.system_template, + system_message=self.system_message, + roles=self.roles, + messages=[[x, y] for x, y in self.messages], + offset=self.offset, + sep_style=self.sep_style, + sep=self.sep, + sep2=self.sep2, + stop_str=self.stop_str, + stop_token_ids=self.stop_token_ids, + ) + + def dict(self): + return { + 'template_name': self.name, + 'system_message': self.system_message, + 'roles': self.roles, + 'messages': self.messages, + 'offset': self.offset, + } + + +# A global registry for all conversation templates +conv_templates: Dict[str, Conversation] = {} + + +def register_conv_template(template: Conversation, override: bool = False): + """Register a new conversation template.""" + if not override: + assert ( + template.name not in conv_templates + ), f'{template.name} has been registered.' + + conv_templates[template.name] = template + + +def get_conv_template(name: str) -> Conversation: + """Get a conversation template.""" + return conv_templates[name].copy() + + +# Both Hermes-2 and internlm2-chat are chatml-format conversation templates. The difference +# is that during training, the preprocessing function for the Hermes-2 template doesn't add +# at the beginning of the tokenized sequence, while the internlm2-chat template does. +# Therefore, they are completely equivalent during inference. +register_conv_template( + Conversation( + name='Hermes-2', + system_template='<|im_start|>system\n{system_message}', + # note: The new system prompt was not used here to avoid changes in benchmark performance. + # system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。', + system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。', + roles=('<|im_start|>user\n', '<|im_start|>assistant\n'), + sep_style=SeparatorStyle.MPT, + sep='<|im_end|>', + stop_token_ids=[ + 2, + 6, + 7, + 8, + ], + stop_str='<|endoftext|>', + ) +) + + +register_conv_template( + Conversation( + name='internlm2-chat', + system_template='<|im_start|>system\n{system_message}', + # note: The new system prompt was not used here to avoid changes in benchmark performance. + # system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。', + system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。', + roles=('<|im_start|>user\n', '<|im_start|>assistant\n'), + sep_style=SeparatorStyle.MPT, + sep='<|im_end|>', + stop_token_ids=[ + 2, + 92543, + 92542 + ] + ) +) + + +register_conv_template( + Conversation( + name='phi3-chat', + system_template='<|system|>\n{system_message}', + # note: The new system prompt was not used here to avoid changes in benchmark performance. + # system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。', + system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。', + roles=('<|user|>\n', '<|assistant|>\n'), + sep_style=SeparatorStyle.MPT, + sep='<|end|>', + stop_token_ids=[ + 2, + 32000, + 32007 + ] + ) +) diff --git a/xinference/thirdparty/llava/mm_utils.py b/xinference/thirdparty/llava/mm_utils.py index 0a9783b665..9882a955d5 100644 --- a/xinference/thirdparty/llava/mm_utils.py +++ b/xinference/thirdparty/llava/mm_utils.py @@ -2,11 +2,12 @@ from io import BytesIO import torch -from .model import LlavaLlamaForCausalLM -from .model.constants import IMAGE_TOKEN_INDEX from PIL import Image from transformers import AutoTokenizer, StoppingCriteria +from .model import LlavaLlamaForCausalLM +from .model.constants import IMAGE_TOKEN_INDEX + def load_image_from_base64(image): return Image.open(BytesIO(base64.b64decode(image))) diff --git a/xinference/thirdparty/llava/model/llava_arch.py b/xinference/thirdparty/llava/model/llava_arch.py index 7dc3325fa1..c1b3e04d42 100644 --- a/xinference/thirdparty/llava/model/llava_arch.py +++ b/xinference/thirdparty/llava/model/llava_arch.py @@ -17,9 +17,9 @@ from abc import ABC, abstractmethod import torch -from .constants import IGNORE_INDEX, IMAGE_TOKEN_INDEX, key_info from .clip_encoder.builder import build_vision_tower +from .constants import IGNORE_INDEX, IMAGE_TOKEN_INDEX, key_info from .multimodal_projector.builder import build_vision_projector diff --git a/xinference/thirdparty/matcha/VERSION b/xinference/thirdparty/matcha/VERSION new file mode 100644 index 0000000000..ea5abc8f95 --- /dev/null +++ b/xinference/thirdparty/matcha/VERSION @@ -0,0 +1 @@ +0.0.7.0 diff --git a/xinference/thirdparty/matcha/__init__.py b/xinference/thirdparty/matcha/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/app.py b/xinference/thirdparty/matcha/app.py new file mode 100644 index 0000000000..d68fbaa2d1 --- /dev/null +++ b/xinference/thirdparty/matcha/app.py @@ -0,0 +1,357 @@ +import tempfile +from argparse import Namespace +from pathlib import Path + +import gradio as gr +import soundfile as sf +import torch + +from matcha.cli import ( + MATCHA_URLS, + VOCODER_URLS, + assert_model_downloaded, + get_device, + load_matcha, + load_vocoder, + process_text, + to_waveform, +) +from matcha.utils.utils import get_user_data_dir, plot_tensor + +LOCATION = Path(get_user_data_dir()) + +args = Namespace( + cpu=False, + model="matcha_vctk", + vocoder="hifigan_univ_v1", + spk=0, +) + +CURRENTLY_LOADED_MODEL = args.model + + +def MATCHA_TTS_LOC(x): + return LOCATION / f"{x}.ckpt" + + +def VOCODER_LOC(x): + return LOCATION / f"{x}" + + +LOGO_URL = "https://shivammehta25.github.io/Matcha-TTS/images/logo.png" +RADIO_OPTIONS = { + "Multi Speaker (VCTK)": { + "model": "matcha_vctk", + "vocoder": "hifigan_univ_v1", + }, + "Single Speaker (LJ Speech)": { + "model": "matcha_ljspeech", + "vocoder": "hifigan_T2_v1", + }, +} + +# Ensure all the required models are downloaded +assert_model_downloaded(MATCHA_TTS_LOC("matcha_ljspeech"), MATCHA_URLS["matcha_ljspeech"]) +assert_model_downloaded(VOCODER_LOC("hifigan_T2_v1"), VOCODER_URLS["hifigan_T2_v1"]) +assert_model_downloaded(MATCHA_TTS_LOC("matcha_vctk"), MATCHA_URLS["matcha_vctk"]) +assert_model_downloaded(VOCODER_LOC("hifigan_univ_v1"), VOCODER_URLS["hifigan_univ_v1"]) + +device = get_device(args) + +# Load default model +model = load_matcha(args.model, MATCHA_TTS_LOC(args.model), device) +vocoder, denoiser = load_vocoder(args.vocoder, VOCODER_LOC(args.vocoder), device) + + +def load_model(model_name, vocoder_name): + model = load_matcha(model_name, MATCHA_TTS_LOC(model_name), device) + vocoder, denoiser = load_vocoder(vocoder_name, VOCODER_LOC(vocoder_name), device) + return model, vocoder, denoiser + + +def load_model_ui(model_type, textbox): + model_name, vocoder_name = RADIO_OPTIONS[model_type]["model"], RADIO_OPTIONS[model_type]["vocoder"] + + global model, vocoder, denoiser, CURRENTLY_LOADED_MODEL # pylint: disable=global-statement + if CURRENTLY_LOADED_MODEL != model_name: + model, vocoder, denoiser = load_model(model_name, vocoder_name) + CURRENTLY_LOADED_MODEL = model_name + + if model_name == "matcha_ljspeech": + spk_slider = gr.update(visible=False, value=-1) + single_speaker_examples = gr.update(visible=True) + multi_speaker_examples = gr.update(visible=False) + length_scale = gr.update(value=0.95) + else: + spk_slider = gr.update(visible=True, value=0) + single_speaker_examples = gr.update(visible=False) + multi_speaker_examples = gr.update(visible=True) + length_scale = gr.update(value=0.85) + + return ( + textbox, + gr.update(interactive=True), + spk_slider, + single_speaker_examples, + multi_speaker_examples, + length_scale, + ) + + +@torch.inference_mode() +def process_text_gradio(text): + output = process_text(1, text, device) + return output["x_phones"][1::2], output["x"], output["x_lengths"] + + +@torch.inference_mode() +def synthesise_mel(text, text_length, n_timesteps, temperature, length_scale, spk): + spk = torch.tensor([spk], device=device, dtype=torch.long) if spk >= 0 else None + output = model.synthesise( + text, + text_length, + n_timesteps=n_timesteps, + temperature=temperature, + spks=spk, + length_scale=length_scale, + ) + output["waveform"] = to_waveform(output["mel"], vocoder, denoiser) + with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as fp: + sf.write(fp.name, output["waveform"], 22050, "PCM_24") + + return fp.name, plot_tensor(output["mel"].squeeze().cpu().numpy()) + + +def multispeaker_example_cacher(text, n_timesteps, mel_temp, length_scale, spk): + global CURRENTLY_LOADED_MODEL # pylint: disable=global-statement + if CURRENTLY_LOADED_MODEL != "matcha_vctk": + global model, vocoder, denoiser # pylint: disable=global-statement + model, vocoder, denoiser = load_model("matcha_vctk", "hifigan_univ_v1") + CURRENTLY_LOADED_MODEL = "matcha_vctk" + + phones, text, text_lengths = process_text_gradio(text) + audio, mel_spectrogram = synthesise_mel(text, text_lengths, n_timesteps, mel_temp, length_scale, spk) + return phones, audio, mel_spectrogram + + +def ljspeech_example_cacher(text, n_timesteps, mel_temp, length_scale, spk=-1): + global CURRENTLY_LOADED_MODEL # pylint: disable=global-statement + if CURRENTLY_LOADED_MODEL != "matcha_ljspeech": + global model, vocoder, denoiser # pylint: disable=global-statement + model, vocoder, denoiser = load_model("matcha_ljspeech", "hifigan_T2_v1") + CURRENTLY_LOADED_MODEL = "matcha_ljspeech" + + phones, text, text_lengths = process_text_gradio(text) + audio, mel_spectrogram = synthesise_mel(text, text_lengths, n_timesteps, mel_temp, length_scale, spk) + return phones, audio, mel_spectrogram + + +def main(): + description = """# 🍵 Matcha-TTS: A fast TTS architecture with conditional flow matching + ### [Shivam Mehta](https://www.kth.se/profile/smehta), [Ruibo Tu](https://www.kth.se/profile/ruibo), [Jonas Beskow](https://www.kth.se/profile/beskow), [Éva Székely](https://www.kth.se/profile/szekely), and [Gustav Eje Henter](https://people.kth.se/~ghe/) + We propose 🍵 Matcha-TTS, a new approach to non-autoregressive neural TTS, that uses conditional flow matching (similar to rectified flows) to speed up ODE-based speech synthesis. Our method: + + + * Is probabilistic + * Has compact memory footprint + * Sounds highly natural + * Is very fast to synthesise from + + + Check out our [demo page](https://shivammehta25.github.io/Matcha-TTS). Read our [arXiv preprint for more details](https://arxiv.org/abs/2309.03199). + Code is available in our [GitHub repository](https://github.com/shivammehta25/Matcha-TTS), along with pre-trained models. + + Cached examples are available at the bottom of the page. + """ + + with gr.Blocks(title="🍵 Matcha-TTS: A fast TTS architecture with conditional flow matching") as demo: + processed_text = gr.State(value=None) + processed_text_len = gr.State(value=None) + + with gr.Box(): + with gr.Row(): + gr.Markdown(description, scale=3) + with gr.Column(): + gr.Image(LOGO_URL, label="Matcha-TTS logo", height=50, width=50, scale=1, show_label=False) + html = '
' + gr.HTML(html) + + with gr.Box(): + radio_options = list(RADIO_OPTIONS.keys()) + model_type = gr.Radio( + radio_options, value=radio_options[0], label="Choose a Model", interactive=True, container=False + ) + + with gr.Row(): + gr.Markdown("# Text Input") + with gr.Row(): + text = gr.Textbox(value="", lines=2, label="Text to synthesise", scale=3) + spk_slider = gr.Slider( + minimum=0, maximum=107, step=1, value=args.spk, label="Speaker ID", interactive=True, scale=1 + ) + + with gr.Row(): + gr.Markdown("### Hyper parameters") + with gr.Row(): + n_timesteps = gr.Slider( + label="Number of ODE steps", + minimum=1, + maximum=100, + step=1, + value=10, + interactive=True, + ) + length_scale = gr.Slider( + label="Length scale (Speaking rate)", + minimum=0.5, + maximum=1.5, + step=0.05, + value=1.0, + interactive=True, + ) + mel_temp = gr.Slider( + label="Sampling temperature", + minimum=0.00, + maximum=2.001, + step=0.16675, + value=0.667, + interactive=True, + ) + + synth_btn = gr.Button("Synthesise") + + with gr.Box(): + with gr.Row(): + gr.Markdown("### Phonetised text") + phonetised_text = gr.Textbox(interactive=False, scale=10, label="Phonetised text") + + with gr.Box(): + with gr.Row(): + mel_spectrogram = gr.Image(interactive=False, label="mel spectrogram") + + # with gr.Row(): + audio = gr.Audio(interactive=False, label="Audio") + + with gr.Row(visible=False) as example_row_lj_speech: + examples = gr.Examples( # pylint: disable=unused-variable + examples=[ + [ + "We propose Matcha-TTS, a new approach to non-autoregressive neural TTS, that uses conditional flow matching (similar to rectified flows) to speed up O D E-based speech synthesis.", + 50, + 0.677, + 0.95, + ], + [ + "The Secret Service believed that it was very doubtful that any President would ride regularly in a vehicle with a fixed top, even though transparent.", + 2, + 0.677, + 0.95, + ], + [ + "The Secret Service believed that it was very doubtful that any President would ride regularly in a vehicle with a fixed top, even though transparent.", + 4, + 0.677, + 0.95, + ], + [ + "The Secret Service believed that it was very doubtful that any President would ride regularly in a vehicle with a fixed top, even though transparent.", + 10, + 0.677, + 0.95, + ], + [ + "The Secret Service believed that it was very doubtful that any President would ride regularly in a vehicle with a fixed top, even though transparent.", + 50, + 0.677, + 0.95, + ], + [ + "The narrative of these events is based largely on the recollections of the participants.", + 10, + 0.677, + 0.95, + ], + [ + "The jury did not believe him, and the verdict was for the defendants.", + 10, + 0.677, + 0.95, + ], + ], + fn=ljspeech_example_cacher, + inputs=[text, n_timesteps, mel_temp, length_scale], + outputs=[phonetised_text, audio, mel_spectrogram], + cache_examples=True, + ) + + with gr.Row() as example_row_multispeaker: + multi_speaker_examples = gr.Examples( # pylint: disable=unused-variable + examples=[ + [ + "Hello everyone! I am speaker 0 and I am here to tell you that Matcha-TTS is amazing!", + 10, + 0.677, + 0.85, + 0, + ], + [ + "Hello everyone! I am speaker 16 and I am here to tell you that Matcha-TTS is amazing!", + 10, + 0.677, + 0.85, + 16, + ], + [ + "Hello everyone! I am speaker 44 and I am here to tell you that Matcha-TTS is amazing!", + 50, + 0.677, + 0.85, + 44, + ], + [ + "Hello everyone! I am speaker 45 and I am here to tell you that Matcha-TTS is amazing!", + 50, + 0.677, + 0.85, + 45, + ], + [ + "Hello everyone! I am speaker 58 and I am here to tell you that Matcha-TTS is amazing!", + 4, + 0.677, + 0.85, + 58, + ], + ], + fn=multispeaker_example_cacher, + inputs=[text, n_timesteps, mel_temp, length_scale, spk_slider], + outputs=[phonetised_text, audio, mel_spectrogram], + cache_examples=True, + label="Multi Speaker Examples", + ) + + model_type.change(lambda x: gr.update(interactive=False), inputs=[synth_btn], outputs=[synth_btn]).then( + load_model_ui, + inputs=[model_type, text], + outputs=[text, synth_btn, spk_slider, example_row_lj_speech, example_row_multispeaker, length_scale], + ) + + synth_btn.click( + fn=process_text_gradio, + inputs=[ + text, + ], + outputs=[phonetised_text, processed_text, processed_text_len], + api_name="matcha_tts", + queue=True, + ).then( + fn=synthesise_mel, + inputs=[processed_text, processed_text_len, n_timesteps, mel_temp, length_scale, spk_slider], + outputs=[audio, mel_spectrogram], + ) + + demo.queue().launch(share=True) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/matcha/cli.py b/xinference/thirdparty/matcha/cli.py new file mode 100644 index 0000000000..7daf13073a --- /dev/null +++ b/xinference/thirdparty/matcha/cli.py @@ -0,0 +1,419 @@ +import argparse +import datetime as dt +import os +import warnings +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np +import soundfile as sf +import torch + +from matcha.hifigan.config import v1 +from matcha.hifigan.denoiser import Denoiser +from matcha.hifigan.env import AttrDict +from matcha.hifigan.models import Generator as HiFiGAN +from matcha.models.matcha_tts import MatchaTTS +from matcha.text import sequence_to_text, text_to_sequence +from matcha.utils.utils import assert_model_downloaded, get_user_data_dir, intersperse + +MATCHA_URLS = { + "matcha_ljspeech": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/matcha_ljspeech.ckpt", + "matcha_vctk": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/matcha_vctk.ckpt", +} + +VOCODER_URLS = { + "hifigan_T2_v1": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/generator_v1", # Old url: https://drive.google.com/file/d/14NENd4equCBLyyCSke114Mv6YR_j_uFs/view?usp=drive_link + "hifigan_univ_v1": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/g_02500000", # Old url: https://drive.google.com/file/d/1qpgI41wNXFcH-iKq1Y42JlBC9j0je8PW/view?usp=drive_link +} + +MULTISPEAKER_MODEL = { + "matcha_vctk": {"vocoder": "hifigan_univ_v1", "speaking_rate": 0.85, "spk": 0, "spk_range": (0, 107)} +} + +SINGLESPEAKER_MODEL = {"matcha_ljspeech": {"vocoder": "hifigan_T2_v1", "speaking_rate": 0.95, "spk": None}} + + +def plot_spectrogram_to_numpy(spectrogram, filename): + fig, ax = plt.subplots(figsize=(12, 3)) + im = ax.imshow(spectrogram, aspect="auto", origin="lower", interpolation="none") + plt.colorbar(im, ax=ax) + plt.xlabel("Frames") + plt.ylabel("Channels") + plt.title("Synthesised Mel-Spectrogram") + fig.canvas.draw() + plt.savefig(filename) + + +def process_text(i: int, text: str, device: torch.device): + print(f"[{i}] - Input text: {text}") + x = torch.tensor( + intersperse(text_to_sequence(text, ["english_cleaners2"])[0], 0), + dtype=torch.long, + device=device, + )[None] + x_lengths = torch.tensor([x.shape[-1]], dtype=torch.long, device=device) + x_phones = sequence_to_text(x.squeeze(0).tolist()) + print(f"[{i}] - Phonetised text: {x_phones[1::2]}") + + return {"x_orig": text, "x": x, "x_lengths": x_lengths, "x_phones": x_phones} + + +def get_texts(args): + if args.text: + texts = [args.text] + else: + with open(args.file, encoding="utf-8") as f: + texts = f.readlines() + return texts + + +def assert_required_models_available(args): + save_dir = get_user_data_dir() + if not hasattr(args, "checkpoint_path") and args.checkpoint_path is None: + model_path = args.checkpoint_path + else: + model_path = save_dir / f"{args.model}.ckpt" + assert_model_downloaded(model_path, MATCHA_URLS[args.model]) + + vocoder_path = save_dir / f"{args.vocoder}" + assert_model_downloaded(vocoder_path, VOCODER_URLS[args.vocoder]) + return {"matcha": model_path, "vocoder": vocoder_path} + + +def load_hifigan(checkpoint_path, device): + h = AttrDict(v1) + hifigan = HiFiGAN(h).to(device) + hifigan.load_state_dict(torch.load(checkpoint_path, map_location=device)["generator"]) + _ = hifigan.eval() + hifigan.remove_weight_norm() + return hifigan + + +def load_vocoder(vocoder_name, checkpoint_path, device): + print(f"[!] Loading {vocoder_name}!") + vocoder = None + if vocoder_name in ("hifigan_T2_v1", "hifigan_univ_v1"): + vocoder = load_hifigan(checkpoint_path, device) + else: + raise NotImplementedError( + f"Vocoder {vocoder_name} not implemented! define a load_<> method for it" + ) + + denoiser = Denoiser(vocoder, mode="zeros") + print(f"[+] {vocoder_name} loaded!") + return vocoder, denoiser + + +def load_matcha(model_name, checkpoint_path, device): + print(f"[!] Loading {model_name}!") + model = MatchaTTS.load_from_checkpoint(checkpoint_path, map_location=device) + _ = model.eval() + + print(f"[+] {model_name} loaded!") + return model + + +def to_waveform(mel, vocoder, denoiser=None): + audio = vocoder(mel).clamp(-1, 1) + if denoiser is not None: + audio = denoiser(audio.squeeze(), strength=0.00025).cpu().squeeze() + + return audio.cpu().squeeze() + + +def save_to_folder(filename: str, output: dict, folder: str): + folder = Path(folder) + folder.mkdir(exist_ok=True, parents=True) + plot_spectrogram_to_numpy(np.array(output["mel"].squeeze().float().cpu()), f"{filename}.png") + np.save(folder / f"{filename}", output["mel"].cpu().numpy()) + sf.write(folder / f"{filename}.wav", output["waveform"], 22050, "PCM_24") + return folder.resolve() / f"{filename}.wav" + + +def validate_args(args): + assert ( + args.text or args.file + ), "Either text or file must be provided Matcha-T(ea)TTS need sometext to whisk the waveforms." + assert args.temperature >= 0, "Sampling temperature cannot be negative" + assert args.steps > 0, "Number of ODE steps must be greater than 0" + + if args.checkpoint_path is None: + # When using pretrained models + if args.model in SINGLESPEAKER_MODEL: + args = validate_args_for_single_speaker_model(args) + + if args.model in MULTISPEAKER_MODEL: + args = validate_args_for_multispeaker_model(args) + else: + # When using a custom model + if args.vocoder != "hifigan_univ_v1": + warn_ = "[-] Using custom model checkpoint! I would suggest passing --vocoder hifigan_univ_v1, unless the custom model is trained on LJ Speech." + warnings.warn(warn_, UserWarning) + if args.speaking_rate is None: + args.speaking_rate = 1.0 + + if args.batched: + assert args.batch_size > 0, "Batch size must be greater than 0" + assert args.speaking_rate > 0, "Speaking rate must be greater than 0" + + return args + + +def validate_args_for_multispeaker_model(args): + if args.vocoder is not None: + if args.vocoder != MULTISPEAKER_MODEL[args.model]["vocoder"]: + warn_ = f"[-] Using {args.model} model! I would suggest passing --vocoder {MULTISPEAKER_MODEL[args.model]['vocoder']}" + warnings.warn(warn_, UserWarning) + else: + args.vocoder = MULTISPEAKER_MODEL[args.model]["vocoder"] + + if args.speaking_rate is None: + args.speaking_rate = MULTISPEAKER_MODEL[args.model]["speaking_rate"] + + spk_range = MULTISPEAKER_MODEL[args.model]["spk_range"] + if args.spk is not None: + assert ( + args.spk >= spk_range[0] and args.spk <= spk_range[-1] + ), f"Speaker ID must be between {spk_range} for this model." + else: + available_spk_id = MULTISPEAKER_MODEL[args.model]["spk"] + warn_ = f"[!] Speaker ID not provided! Using speaker ID {available_spk_id}" + warnings.warn(warn_, UserWarning) + args.spk = available_spk_id + + return args + + +def validate_args_for_single_speaker_model(args): + if args.vocoder is not None: + if args.vocoder != SINGLESPEAKER_MODEL[args.model]["vocoder"]: + warn_ = f"[-] Using {args.model} model! I would suggest passing --vocoder {SINGLESPEAKER_MODEL[args.model]['vocoder']}" + warnings.warn(warn_, UserWarning) + else: + args.vocoder = SINGLESPEAKER_MODEL[args.model]["vocoder"] + + if args.speaking_rate is None: + args.speaking_rate = SINGLESPEAKER_MODEL[args.model]["speaking_rate"] + + if args.spk != SINGLESPEAKER_MODEL[args.model]["spk"]: + warn_ = f"[-] Ignoring speaker id {args.spk} for {args.model}" + warnings.warn(warn_, UserWarning) + args.spk = SINGLESPEAKER_MODEL[args.model]["spk"] + + return args + + +@torch.inference_mode() +def cli(): + parser = argparse.ArgumentParser( + description=" 🍵 Matcha-TTS: A fast TTS architecture with conditional flow matching" + ) + parser.add_argument( + "--model", + type=str, + default="matcha_ljspeech", + help="Model to use", + choices=MATCHA_URLS.keys(), + ) + + parser.add_argument( + "--checkpoint_path", + type=str, + default=None, + help="Path to the custom model checkpoint", + ) + + parser.add_argument( + "--vocoder", + type=str, + default=None, + help="Vocoder to use (default: will use the one suggested with the pretrained model))", + choices=VOCODER_URLS.keys(), + ) + parser.add_argument("--text", type=str, default=None, help="Text to synthesize") + parser.add_argument("--file", type=str, default=None, help="Text file to synthesize") + parser.add_argument("--spk", type=int, default=None, help="Speaker ID") + parser.add_argument( + "--temperature", + type=float, + default=0.667, + help="Variance of the x0 noise (default: 0.667)", + ) + parser.add_argument( + "--speaking_rate", + type=float, + default=None, + help="change the speaking rate, a higher value means slower speaking rate (default: 1.0)", + ) + parser.add_argument("--steps", type=int, default=10, help="Number of ODE steps (default: 10)") + parser.add_argument("--cpu", action="store_true", help="Use CPU for inference (default: use GPU if available)") + parser.add_argument( + "--denoiser_strength", + type=float, + default=0.00025, + help="Strength of the vocoder bias denoiser (default: 0.00025)", + ) + parser.add_argument( + "--output_folder", + type=str, + default=os.getcwd(), + help="Output folder to save results (default: current dir)", + ) + parser.add_argument("--batched", action="store_true", help="Batched inference (default: False)") + parser.add_argument( + "--batch_size", type=int, default=32, help="Batch size only useful when --batched (default: 32)" + ) + + args = parser.parse_args() + + args = validate_args(args) + device = get_device(args) + print_config(args) + paths = assert_required_models_available(args) + + if args.checkpoint_path is not None: + print(f"[🍵] Loading custom model from {args.checkpoint_path}") + paths["matcha"] = args.checkpoint_path + args.model = "custom_model" + + model = load_matcha(args.model, paths["matcha"], device) + vocoder, denoiser = load_vocoder(args.vocoder, paths["vocoder"], device) + + texts = get_texts(args) + + spk = torch.tensor([args.spk], device=device, dtype=torch.long) if args.spk is not None else None + if len(texts) == 1 or not args.batched: + unbatched_synthesis(args, device, model, vocoder, denoiser, texts, spk) + else: + batched_synthesis(args, device, model, vocoder, denoiser, texts, spk) + + +class BatchedSynthesisDataset(torch.utils.data.Dataset): + def __init__(self, processed_texts): + self.processed_texts = processed_texts + + def __len__(self): + return len(self.processed_texts) + + def __getitem__(self, idx): + return self.processed_texts[idx] + + +def batched_collate_fn(batch): + x = [] + x_lengths = [] + + for b in batch: + x.append(b["x"].squeeze(0)) + x_lengths.append(b["x_lengths"]) + + x = torch.nn.utils.rnn.pad_sequence(x, batch_first=True) + x_lengths = torch.concat(x_lengths, dim=0) + return {"x": x, "x_lengths": x_lengths} + + +def batched_synthesis(args, device, model, vocoder, denoiser, texts, spk): + total_rtf = [] + total_rtf_w = [] + processed_text = [process_text(i, text, "cpu") for i, text in enumerate(texts)] + dataloader = torch.utils.data.DataLoader( + BatchedSynthesisDataset(processed_text), + batch_size=args.batch_size, + collate_fn=batched_collate_fn, + num_workers=8, + ) + for i, batch in enumerate(dataloader): + i = i + 1 + start_t = dt.datetime.now() + b = batch["x"].shape[0] + output = model.synthesise( + batch["x"].to(device), + batch["x_lengths"].to(device), + n_timesteps=args.steps, + temperature=args.temperature, + spks=spk.expand(b) if spk is not None else spk, + length_scale=args.speaking_rate, + ) + + output["waveform"] = to_waveform(output["mel"], vocoder, denoiser) + t = (dt.datetime.now() - start_t).total_seconds() + rtf_w = t * 22050 / (output["waveform"].shape[-1]) + print(f"[🍵-Batch: {i}] Matcha-TTS RTF: {output['rtf']:.4f}") + print(f"[🍵-Batch: {i}] Matcha-TTS + VOCODER RTF: {rtf_w:.4f}") + total_rtf.append(output["rtf"]) + total_rtf_w.append(rtf_w) + for j in range(output["mel"].shape[0]): + base_name = f"utterance_{j:03d}_speaker_{args.spk:03d}" if args.spk is not None else f"utterance_{j:03d}" + length = output["mel_lengths"][j] + new_dict = {"mel": output["mel"][j][:, :length], "waveform": output["waveform"][j][: length * 256]} + location = save_to_folder(base_name, new_dict, args.output_folder) + print(f"[🍵-{j}] Waveform saved: {location}") + + print("".join(["="] * 100)) + print(f"[🍵] Average Matcha-TTS RTF: {np.mean(total_rtf):.4f} ± {np.std(total_rtf)}") + print(f"[🍵] Average Matcha-TTS + VOCODER RTF: {np.mean(total_rtf_w):.4f} ± {np.std(total_rtf_w)}") + print("[🍵] Enjoy the freshly whisked 🍵 Matcha-TTS!") + + +def unbatched_synthesis(args, device, model, vocoder, denoiser, texts, spk): + total_rtf = [] + total_rtf_w = [] + for i, text in enumerate(texts): + i = i + 1 + base_name = f"utterance_{i:03d}_speaker_{args.spk:03d}" if args.spk is not None else f"utterance_{i:03d}" + + print("".join(["="] * 100)) + text = text.strip() + text_processed = process_text(i, text, device) + + print(f"[🍵] Whisking Matcha-T(ea)TS for: {i}") + start_t = dt.datetime.now() + output = model.synthesise( + text_processed["x"], + text_processed["x_lengths"], + n_timesteps=args.steps, + temperature=args.temperature, + spks=spk, + length_scale=args.speaking_rate, + ) + output["waveform"] = to_waveform(output["mel"], vocoder, denoiser) + # RTF with HiFiGAN + t = (dt.datetime.now() - start_t).total_seconds() + rtf_w = t * 22050 / (output["waveform"].shape[-1]) + print(f"[🍵-{i}] Matcha-TTS RTF: {output['rtf']:.4f}") + print(f"[🍵-{i}] Matcha-TTS + VOCODER RTF: {rtf_w:.4f}") + total_rtf.append(output["rtf"]) + total_rtf_w.append(rtf_w) + + location = save_to_folder(base_name, output, args.output_folder) + print(f"[+] Waveform saved: {location}") + + print("".join(["="] * 100)) + print(f"[🍵] Average Matcha-TTS RTF: {np.mean(total_rtf):.4f} ± {np.std(total_rtf)}") + print(f"[🍵] Average Matcha-TTS + VOCODER RTF: {np.mean(total_rtf_w):.4f} ± {np.std(total_rtf_w)}") + print("[🍵] Enjoy the freshly whisked 🍵 Matcha-TTS!") + + +def print_config(args): + print("[!] Configurations: ") + print(f"\t- Model: {args.model}") + print(f"\t- Vocoder: {args.vocoder}") + print(f"\t- Temperature: {args.temperature}") + print(f"\t- Speaking rate: {args.speaking_rate}") + print(f"\t- Number of ODE steps: {args.steps}") + print(f"\t- Speaker: {args.spk}") + + +def get_device(args): + if torch.cuda.is_available() and not args.cpu: + print("[+] GPU Available! Using GPU") + device = torch.device("cuda") + else: + print("[-] GPU not available or forced CPU run! Using CPU") + device = torch.device("cpu") + return device + + +if __name__ == "__main__": + cli() diff --git a/xinference/thirdparty/matcha/data/__init__.py b/xinference/thirdparty/matcha/data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/data/components/__init__.py b/xinference/thirdparty/matcha/data/components/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/data/text_mel_datamodule.py b/xinference/thirdparty/matcha/data/text_mel_datamodule.py new file mode 100644 index 0000000000..e10dfcb8bb --- /dev/null +++ b/xinference/thirdparty/matcha/data/text_mel_datamodule.py @@ -0,0 +1,274 @@ +import random +from pathlib import Path +from typing import Any, Dict, Optional + +import numpy as np +import torch +import torchaudio as ta +from lightning import LightningDataModule +from torch.utils.data.dataloader import DataLoader + +from matcha.text import text_to_sequence +from matcha.utils.audio import mel_spectrogram +from matcha.utils.model import fix_len_compatibility, normalize +from matcha.utils.utils import intersperse + + +def parse_filelist(filelist_path, split_char="|"): + with open(filelist_path, encoding="utf-8") as f: + filepaths_and_text = [line.strip().split(split_char) for line in f] + return filepaths_and_text + + +class TextMelDataModule(LightningDataModule): + def __init__( # pylint: disable=unused-argument + self, + name, + train_filelist_path, + valid_filelist_path, + batch_size, + num_workers, + pin_memory, + cleaners, + add_blank, + n_spks, + n_fft, + n_feats, + sample_rate, + hop_length, + win_length, + f_min, + f_max, + data_statistics, + seed, + load_durations, + ): + super().__init__() + + # this line allows to access init params with 'self.hparams' attribute + # also ensures init params will be stored in ckpt + self.save_hyperparameters(logger=False) + + def setup(self, stage: Optional[str] = None): # pylint: disable=unused-argument + """Load data. Set variables: `self.data_train`, `self.data_val`, `self.data_test`. + + This method is called by lightning with both `trainer.fit()` and `trainer.test()`, so be + careful not to execute things like random split twice! + """ + # load and split datasets only if not loaded already + + self.trainset = TextMelDataset( # pylint: disable=attribute-defined-outside-init + self.hparams.train_filelist_path, + self.hparams.n_spks, + self.hparams.cleaners, + self.hparams.add_blank, + self.hparams.n_fft, + self.hparams.n_feats, + self.hparams.sample_rate, + self.hparams.hop_length, + self.hparams.win_length, + self.hparams.f_min, + self.hparams.f_max, + self.hparams.data_statistics, + self.hparams.seed, + self.hparams.load_durations, + ) + self.validset = TextMelDataset( # pylint: disable=attribute-defined-outside-init + self.hparams.valid_filelist_path, + self.hparams.n_spks, + self.hparams.cleaners, + self.hparams.add_blank, + self.hparams.n_fft, + self.hparams.n_feats, + self.hparams.sample_rate, + self.hparams.hop_length, + self.hparams.win_length, + self.hparams.f_min, + self.hparams.f_max, + self.hparams.data_statistics, + self.hparams.seed, + self.hparams.load_durations, + ) + + def train_dataloader(self): + return DataLoader( + dataset=self.trainset, + batch_size=self.hparams.batch_size, + num_workers=self.hparams.num_workers, + pin_memory=self.hparams.pin_memory, + shuffle=True, + collate_fn=TextMelBatchCollate(self.hparams.n_spks), + ) + + def val_dataloader(self): + return DataLoader( + dataset=self.validset, + batch_size=self.hparams.batch_size, + num_workers=self.hparams.num_workers, + pin_memory=self.hparams.pin_memory, + shuffle=False, + collate_fn=TextMelBatchCollate(self.hparams.n_spks), + ) + + def teardown(self, stage: Optional[str] = None): + """Clean up after fit or test.""" + pass # pylint: disable=unnecessary-pass + + def state_dict(self): + """Extra things to save to checkpoint.""" + return {} + + def load_state_dict(self, state_dict: Dict[str, Any]): + """Things to do when loading checkpoint.""" + pass # pylint: disable=unnecessary-pass + + +class TextMelDataset(torch.utils.data.Dataset): + def __init__( + self, + filelist_path, + n_spks, + cleaners, + add_blank=True, + n_fft=1024, + n_mels=80, + sample_rate=22050, + hop_length=256, + win_length=1024, + f_min=0.0, + f_max=8000, + data_parameters=None, + seed=None, + load_durations=False, + ): + self.filepaths_and_text = parse_filelist(filelist_path) + self.n_spks = n_spks + self.cleaners = cleaners + self.add_blank = add_blank + self.n_fft = n_fft + self.n_mels = n_mels + self.sample_rate = sample_rate + self.hop_length = hop_length + self.win_length = win_length + self.f_min = f_min + self.f_max = f_max + self.load_durations = load_durations + + if data_parameters is not None: + self.data_parameters = data_parameters + else: + self.data_parameters = {"mel_mean": 0, "mel_std": 1} + random.seed(seed) + random.shuffle(self.filepaths_and_text) + + def get_datapoint(self, filepath_and_text): + if self.n_spks > 1: + filepath, spk, text = ( + filepath_and_text[0], + int(filepath_and_text[1]), + filepath_and_text[2], + ) + else: + filepath, text = filepath_and_text[0], filepath_and_text[1] + spk = None + + text, cleaned_text = self.get_text(text, add_blank=self.add_blank) + mel = self.get_mel(filepath) + + durations = self.get_durations(filepath, text) if self.load_durations else None + + return {"x": text, "y": mel, "spk": spk, "filepath": filepath, "x_text": cleaned_text, "durations": durations} + + def get_durations(self, filepath, text): + filepath = Path(filepath) + data_dir, name = filepath.parent.parent, filepath.stem + + try: + dur_loc = data_dir / "durations" / f"{name}.npy" + durs = torch.from_numpy(np.load(dur_loc).astype(int)) + + except FileNotFoundError as e: + raise FileNotFoundError( + f"Tried loading the durations but durations didn't exist at {dur_loc}, make sure you've generate the durations first using: python matcha/utils/get_durations_from_trained_model.py \n" + ) from e + + assert len(durs) == len(text), f"Length of durations {len(durs)} and text {len(text)} do not match" + + return durs + + def get_mel(self, filepath): + audio, sr = ta.load(filepath) + assert sr == self.sample_rate + mel = mel_spectrogram( + audio, + self.n_fft, + self.n_mels, + self.sample_rate, + self.hop_length, + self.win_length, + self.f_min, + self.f_max, + center=False, + ).squeeze() + mel = normalize(mel, self.data_parameters["mel_mean"], self.data_parameters["mel_std"]) + return mel + + def get_text(self, text, add_blank=True): + text_norm, cleaned_text = text_to_sequence(text, self.cleaners) + if self.add_blank: + text_norm = intersperse(text_norm, 0) + text_norm = torch.IntTensor(text_norm) + return text_norm, cleaned_text + + def __getitem__(self, index): + datapoint = self.get_datapoint(self.filepaths_and_text[index]) + return datapoint + + def __len__(self): + return len(self.filepaths_and_text) + + +class TextMelBatchCollate: + def __init__(self, n_spks): + self.n_spks = n_spks + + def __call__(self, batch): + B = len(batch) + y_max_length = max([item["y"].shape[-1] for item in batch]) + y_max_length = fix_len_compatibility(y_max_length) + x_max_length = max([item["x"].shape[-1] for item in batch]) + n_feats = batch[0]["y"].shape[-2] + + y = torch.zeros((B, n_feats, y_max_length), dtype=torch.float32) + x = torch.zeros((B, x_max_length), dtype=torch.long) + durations = torch.zeros((B, x_max_length), dtype=torch.long) + + y_lengths, x_lengths = [], [] + spks = [] + filepaths, x_texts = [], [] + for i, item in enumerate(batch): + y_, x_ = item["y"], item["x"] + y_lengths.append(y_.shape[-1]) + x_lengths.append(x_.shape[-1]) + y[i, :, : y_.shape[-1]] = y_ + x[i, : x_.shape[-1]] = x_ + spks.append(item["spk"]) + filepaths.append(item["filepath"]) + x_texts.append(item["x_text"]) + if item["durations"] is not None: + durations[i, : item["durations"].shape[-1]] = item["durations"] + + y_lengths = torch.tensor(y_lengths, dtype=torch.long) + x_lengths = torch.tensor(x_lengths, dtype=torch.long) + spks = torch.tensor(spks, dtype=torch.long) if self.n_spks > 1 else None + + return { + "x": x, + "x_lengths": x_lengths, + "y": y, + "y_lengths": y_lengths, + "spks": spks, + "filepaths": filepaths, + "x_texts": x_texts, + "durations": durations if not torch.eq(durations, 0).all() else None, + } diff --git a/xinference/thirdparty/matcha/hifigan/LICENSE b/xinference/thirdparty/matcha/hifigan/LICENSE new file mode 100644 index 0000000000..91751daed8 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Jungil Kong + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/xinference/thirdparty/matcha/hifigan/README.md b/xinference/thirdparty/matcha/hifigan/README.md new file mode 100644 index 0000000000..5db2585045 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/README.md @@ -0,0 +1,101 @@ +# HiFi-GAN: Generative Adversarial Networks for Efficient and High Fidelity Speech Synthesis + +### Jungil Kong, Jaehyeon Kim, Jaekyoung Bae + +In our [paper](https://arxiv.org/abs/2010.05646), +we proposed HiFi-GAN: a GAN-based model capable of generating high fidelity speech efficiently.
+We provide our implementation and pretrained models as open source in this repository. + +**Abstract :** +Several recent work on speech synthesis have employed generative adversarial networks (GANs) to produce raw waveforms. +Although such methods improve the sampling efficiency and memory usage, +their sample quality has not yet reached that of autoregressive and flow-based generative models. +In this work, we propose HiFi-GAN, which achieves both efficient and high-fidelity speech synthesis. +As speech audio consists of sinusoidal signals with various periods, +we demonstrate that modeling periodic patterns of an audio is crucial for enhancing sample quality. +A subjective human evaluation (mean opinion score, MOS) of a single speaker dataset indicates that our proposed method +demonstrates similarity to human quality while generating 22.05 kHz high-fidelity audio 167.9 times faster than +real-time on a single V100 GPU. We further show the generality of HiFi-GAN to the mel-spectrogram inversion of unseen +speakers and end-to-end speech synthesis. Finally, a small footprint version of HiFi-GAN generates samples 13.4 times +faster than real-time on CPU with comparable quality to an autoregressive counterpart. + +Visit our [demo website](https://jik876.github.io/hifi-gan-demo/) for audio samples. + +## Pre-requisites + +1. Python >= 3.6 +2. Clone this repository. +3. Install python requirements. Please refer [requirements.txt](requirements.txt) +4. Download and extract the [LJ Speech dataset](https://keithito.com/LJ-Speech-Dataset/). + And move all wav files to `LJSpeech-1.1/wavs` + +## Training + +``` +python train.py --config config_v1.json +``` + +To train V2 or V3 Generator, replace `config_v1.json` with `config_v2.json` or `config_v3.json`.
+Checkpoints and copy of the configuration file are saved in `cp_hifigan` directory by default.
+You can change the path by adding `--checkpoint_path` option. + +Validation loss during training with V1 generator.
+![validation loss](./validation_loss.png) + +## Pretrained Model + +You can also use pretrained models we provide.
+[Download pretrained models](https://drive.google.com/drive/folders/1-eEYTB5Av9jNql0WGBlRoi-WH2J7bp5Y?usp=sharing)
+Details of each folder are as in follows: + +| Folder Name | Generator | Dataset | Fine-Tuned | +| ------------ | --------- | --------- | ------------------------------------------------------ | +| LJ_V1 | V1 | LJSpeech | No | +| LJ_V2 | V2 | LJSpeech | No | +| LJ_V3 | V3 | LJSpeech | No | +| LJ_FT_T2_V1 | V1 | LJSpeech | Yes ([Tacotron2](https://github.com/NVIDIA/tacotron2)) | +| LJ_FT_T2_V2 | V2 | LJSpeech | Yes ([Tacotron2](https://github.com/NVIDIA/tacotron2)) | +| LJ_FT_T2_V3 | V3 | LJSpeech | Yes ([Tacotron2](https://github.com/NVIDIA/tacotron2)) | +| VCTK_V1 | V1 | VCTK | No | +| VCTK_V2 | V2 | VCTK | No | +| VCTK_V3 | V3 | VCTK | No | +| UNIVERSAL_V1 | V1 | Universal | No | + +We provide the universal model with discriminator weights that can be used as a base for transfer learning to other datasets. + +## Fine-Tuning + +1. Generate mel-spectrograms in numpy format using [Tacotron2](https://github.com/NVIDIA/tacotron2) with teacher-forcing.
+ The file name of the generated mel-spectrogram should match the audio file and the extension should be `.npy`.
+ Example: + ` Audio File : LJ001-0001.wav +Mel-Spectrogram File : LJ001-0001.npy` +2. Create `ft_dataset` folder and copy the generated mel-spectrogram files into it.
+3. Run the following command. + ``` + python train.py --fine_tuning True --config config_v1.json + ``` + For other command line options, please refer to the training section. + +## Inference from wav file + +1. Make `test_files` directory and copy wav files into the directory. +2. Run the following command. + ` python inference.py --checkpoint_file [generator checkpoint file path]` + Generated wav files are saved in `generated_files` by default.
+ You can change the path by adding `--output_dir` option. + +## Inference for end-to-end speech synthesis + +1. Make `test_mel_files` directory and copy generated mel-spectrogram files into the directory.
+ You can generate mel-spectrograms using [Tacotron2](https://github.com/NVIDIA/tacotron2), + [Glow-TTS](https://github.com/jaywalnut310/glow-tts) and so forth. +2. Run the following command. + ` python inference_e2e.py --checkpoint_file [generator checkpoint file path]` + Generated wav files are saved in `generated_files_from_mel` by default.
+ You can change the path by adding `--output_dir` option. + +## Acknowledgements + +We referred to [WaveGlow](https://github.com/NVIDIA/waveglow), [MelGAN](https://github.com/descriptinc/melgan-neurips) +and [Tacotron2](https://github.com/NVIDIA/tacotron2) to implement this. diff --git a/xinference/thirdparty/matcha/hifigan/__init__.py b/xinference/thirdparty/matcha/hifigan/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/hifigan/config.py b/xinference/thirdparty/matcha/hifigan/config.py new file mode 100644 index 0000000000..b3abea9e15 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/config.py @@ -0,0 +1,28 @@ +v1 = { + "resblock": "1", + "num_gpus": 0, + "batch_size": 16, + "learning_rate": 0.0004, + "adam_b1": 0.8, + "adam_b2": 0.99, + "lr_decay": 0.999, + "seed": 1234, + "upsample_rates": [8, 8, 2, 2], + "upsample_kernel_sizes": [16, 16, 4, 4], + "upsample_initial_channel": 512, + "resblock_kernel_sizes": [3, 7, 11], + "resblock_dilation_sizes": [[1, 3, 5], [1, 3, 5], [1, 3, 5]], + "resblock_initial_channel": 256, + "segment_size": 8192, + "num_mels": 80, + "num_freq": 1025, + "n_fft": 1024, + "hop_size": 256, + "win_size": 1024, + "sampling_rate": 22050, + "fmin": 0, + "fmax": 8000, + "fmax_loss": None, + "num_workers": 4, + "dist_config": {"dist_backend": "nccl", "dist_url": "tcp://localhost:54321", "world_size": 1}, +} diff --git a/xinference/thirdparty/matcha/hifigan/denoiser.py b/xinference/thirdparty/matcha/hifigan/denoiser.py new file mode 100644 index 0000000000..9fd33312a0 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/denoiser.py @@ -0,0 +1,64 @@ +# Code modified from Rafael Valle's implementation https://github.com/NVIDIA/waveglow/blob/5bc2a53e20b3b533362f974cfa1ea0267ae1c2b1/denoiser.py + +"""Waveglow style denoiser can be used to remove the artifacts from the HiFiGAN generated audio.""" +import torch + + +class Denoiser(torch.nn.Module): + """Removes model bias from audio produced with waveglow""" + + def __init__(self, vocoder, filter_length=1024, n_overlap=4, win_length=1024, mode="zeros"): + super().__init__() + self.filter_length = filter_length + self.hop_length = int(filter_length / n_overlap) + self.win_length = win_length + + dtype, device = next(vocoder.parameters()).dtype, next(vocoder.parameters()).device + self.device = device + if mode == "zeros": + mel_input = torch.zeros((1, 80, 88), dtype=dtype, device=device) + elif mode == "normal": + mel_input = torch.randn((1, 80, 88), dtype=dtype, device=device) + else: + raise Exception(f"Mode {mode} if not supported") + + def stft_fn(audio, n_fft, hop_length, win_length, window): + spec = torch.stft( + audio, + n_fft=n_fft, + hop_length=hop_length, + win_length=win_length, + window=window, + return_complex=True, + ) + spec = torch.view_as_real(spec) + return torch.sqrt(spec.pow(2).sum(-1)), torch.atan2(spec[..., -1], spec[..., 0]) + + self.stft = lambda x: stft_fn( + audio=x, + n_fft=self.filter_length, + hop_length=self.hop_length, + win_length=self.win_length, + window=torch.hann_window(self.win_length, device=device), + ) + self.istft = lambda x, y: torch.istft( + torch.complex(x * torch.cos(y), x * torch.sin(y)), + n_fft=self.filter_length, + hop_length=self.hop_length, + win_length=self.win_length, + window=torch.hann_window(self.win_length, device=device), + ) + + with torch.no_grad(): + bias_audio = vocoder(mel_input).float().squeeze(0) + bias_spec, _ = self.stft(bias_audio) + + self.register_buffer("bias_spec", bias_spec[:, :, 0][:, :, None]) + + @torch.inference_mode() + def forward(self, audio, strength=0.0005): + audio_spec, audio_angles = self.stft(audio) + audio_spec_denoised = audio_spec - self.bias_spec.to(audio.device) * strength + audio_spec_denoised = torch.clamp(audio_spec_denoised, 0.0) + audio_denoised = self.istft(audio_spec_denoised, audio_angles) + return audio_denoised diff --git a/xinference/thirdparty/matcha/hifigan/env.py b/xinference/thirdparty/matcha/hifigan/env.py new file mode 100644 index 0000000000..9ea4f948a3 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/env.py @@ -0,0 +1,17 @@ +""" from https://github.com/jik876/hifi-gan """ + +import os +import shutil + + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.__dict__ = self + + +def build_env(config, config_name, path): + t_path = os.path.join(path, config_name) + if config != t_path: + os.makedirs(path, exist_ok=True) + shutil.copyfile(config, os.path.join(path, config_name)) diff --git a/xinference/thirdparty/matcha/hifigan/meldataset.py b/xinference/thirdparty/matcha/hifigan/meldataset.py new file mode 100644 index 0000000000..8b43ea7965 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/meldataset.py @@ -0,0 +1,217 @@ +""" from https://github.com/jik876/hifi-gan """ + +import math +import os +import random + +import numpy as np +import torch +import torch.utils.data +from librosa.filters import mel as librosa_mel_fn +from librosa.util import normalize +from scipy.io.wavfile import read + +MAX_WAV_VALUE = 32768.0 + + +def load_wav(full_path): + sampling_rate, data = read(full_path) + return data, sampling_rate + + +def dynamic_range_compression(x, C=1, clip_val=1e-5): + return np.log(np.clip(x, a_min=clip_val, a_max=None) * C) + + +def dynamic_range_decompression(x, C=1): + return np.exp(x) / C + + +def dynamic_range_compression_torch(x, C=1, clip_val=1e-5): + return torch.log(torch.clamp(x, min=clip_val) * C) + + +def dynamic_range_decompression_torch(x, C=1): + return torch.exp(x) / C + + +def spectral_normalize_torch(magnitudes): + output = dynamic_range_compression_torch(magnitudes) + return output + + +def spectral_de_normalize_torch(magnitudes): + output = dynamic_range_decompression_torch(magnitudes) + return output + + +mel_basis = {} +hann_window = {} + + +def mel_spectrogram(y, n_fft, num_mels, sampling_rate, hop_size, win_size, fmin, fmax, center=False): + if torch.min(y) < -1.0: + print("min value is ", torch.min(y)) + if torch.max(y) > 1.0: + print("max value is ", torch.max(y)) + + global mel_basis, hann_window # pylint: disable=global-statement + if fmax not in mel_basis: + mel = librosa_mel_fn(sampling_rate, n_fft, num_mels, fmin, fmax) + mel_basis[str(fmax) + "_" + str(y.device)] = torch.from_numpy(mel).float().to(y.device) + hann_window[str(y.device)] = torch.hann_window(win_size).to(y.device) + + y = torch.nn.functional.pad( + y.unsqueeze(1), (int((n_fft - hop_size) / 2), int((n_fft - hop_size) / 2)), mode="reflect" + ) + y = y.squeeze(1) + + spec = torch.view_as_real( + torch.stft( + y, + n_fft, + hop_length=hop_size, + win_length=win_size, + window=hann_window[str(y.device)], + center=center, + pad_mode="reflect", + normalized=False, + onesided=True, + return_complex=True, + ) + ) + + spec = torch.sqrt(spec.pow(2).sum(-1) + (1e-9)) + + spec = torch.matmul(mel_basis[str(fmax) + "_" + str(y.device)], spec) + spec = spectral_normalize_torch(spec) + + return spec + + +def get_dataset_filelist(a): + with open(a.input_training_file, encoding="utf-8") as fi: + training_files = [ + os.path.join(a.input_wavs_dir, x.split("|")[0] + ".wav") for x in fi.read().split("\n") if len(x) > 0 + ] + + with open(a.input_validation_file, encoding="utf-8") as fi: + validation_files = [ + os.path.join(a.input_wavs_dir, x.split("|")[0] + ".wav") for x in fi.read().split("\n") if len(x) > 0 + ] + return training_files, validation_files + + +class MelDataset(torch.utils.data.Dataset): + def __init__( + self, + training_files, + segment_size, + n_fft, + num_mels, + hop_size, + win_size, + sampling_rate, + fmin, + fmax, + split=True, + shuffle=True, + n_cache_reuse=1, + device=None, + fmax_loss=None, + fine_tuning=False, + base_mels_path=None, + ): + self.audio_files = training_files + random.seed(1234) + if shuffle: + random.shuffle(self.audio_files) + self.segment_size = segment_size + self.sampling_rate = sampling_rate + self.split = split + self.n_fft = n_fft + self.num_mels = num_mels + self.hop_size = hop_size + self.win_size = win_size + self.fmin = fmin + self.fmax = fmax + self.fmax_loss = fmax_loss + self.cached_wav = None + self.n_cache_reuse = n_cache_reuse + self._cache_ref_count = 0 + self.device = device + self.fine_tuning = fine_tuning + self.base_mels_path = base_mels_path + + def __getitem__(self, index): + filename = self.audio_files[index] + if self._cache_ref_count == 0: + audio, sampling_rate = load_wav(filename) + audio = audio / MAX_WAV_VALUE + if not self.fine_tuning: + audio = normalize(audio) * 0.95 + self.cached_wav = audio + if sampling_rate != self.sampling_rate: + raise ValueError(f"{sampling_rate} SR doesn't match target {self.sampling_rate} SR") + self._cache_ref_count = self.n_cache_reuse + else: + audio = self.cached_wav + self._cache_ref_count -= 1 + + audio = torch.FloatTensor(audio) + audio = audio.unsqueeze(0) + + if not self.fine_tuning: + if self.split: + if audio.size(1) >= self.segment_size: + max_audio_start = audio.size(1) - self.segment_size + audio_start = random.randint(0, max_audio_start) + audio = audio[:, audio_start : audio_start + self.segment_size] + else: + audio = torch.nn.functional.pad(audio, (0, self.segment_size - audio.size(1)), "constant") + + mel = mel_spectrogram( + audio, + self.n_fft, + self.num_mels, + self.sampling_rate, + self.hop_size, + self.win_size, + self.fmin, + self.fmax, + center=False, + ) + else: + mel = np.load(os.path.join(self.base_mels_path, os.path.splitext(os.path.split(filename)[-1])[0] + ".npy")) + mel = torch.from_numpy(mel) + + if len(mel.shape) < 3: + mel = mel.unsqueeze(0) + + if self.split: + frames_per_seg = math.ceil(self.segment_size / self.hop_size) + + if audio.size(1) >= self.segment_size: + mel_start = random.randint(0, mel.size(2) - frames_per_seg - 1) + mel = mel[:, :, mel_start : mel_start + frames_per_seg] + audio = audio[:, mel_start * self.hop_size : (mel_start + frames_per_seg) * self.hop_size] + else: + mel = torch.nn.functional.pad(mel, (0, frames_per_seg - mel.size(2)), "constant") + audio = torch.nn.functional.pad(audio, (0, self.segment_size - audio.size(1)), "constant") + + mel_loss = mel_spectrogram( + audio, + self.n_fft, + self.num_mels, + self.sampling_rate, + self.hop_size, + self.win_size, + self.fmin, + self.fmax_loss, + center=False, + ) + + return (mel.squeeze(), audio.squeeze(0), filename, mel_loss.squeeze()) + + def __len__(self): + return len(self.audio_files) diff --git a/xinference/thirdparty/matcha/hifigan/models.py b/xinference/thirdparty/matcha/hifigan/models.py new file mode 100644 index 0000000000..d209d9a4e9 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/models.py @@ -0,0 +1,368 @@ +""" from https://github.com/jik876/hifi-gan """ + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import AvgPool1d, Conv1d, Conv2d, ConvTranspose1d +from torch.nn.utils import remove_weight_norm, spectral_norm, weight_norm + +from .xutils import get_padding, init_weights + +LRELU_SLOPE = 0.1 + + +class ResBlock1(torch.nn.Module): + def __init__(self, h, channels, kernel_size=3, dilation=(1, 3, 5)): + super().__init__() + self.h = h + self.convs1 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[2], + padding=get_padding(kernel_size, dilation[2]), + ) + ), + ] + ) + self.convs1.apply(init_weights) + + self.convs2 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + ] + ) + self.convs2.apply(init_weights) + + def forward(self, x): + for c1, c2 in zip(self.convs1, self.convs2): + xt = F.leaky_relu(x, LRELU_SLOPE) + xt = c1(xt) + xt = F.leaky_relu(xt, LRELU_SLOPE) + xt = c2(xt) + x = xt + x + return x + + def remove_weight_norm(self): + for l in self.convs1: + remove_weight_norm(l) + for l in self.convs2: + remove_weight_norm(l) + + +class ResBlock2(torch.nn.Module): + def __init__(self, h, channels, kernel_size=3, dilation=(1, 3)): + super().__init__() + self.h = h + self.convs = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]), + ) + ), + ] + ) + self.convs.apply(init_weights) + + def forward(self, x): + for c in self.convs: + xt = F.leaky_relu(x, LRELU_SLOPE) + xt = c(xt) + x = xt + x + return x + + def remove_weight_norm(self): + for l in self.convs: + remove_weight_norm(l) + + +class Generator(torch.nn.Module): + def __init__(self, h): + super().__init__() + self.h = h + self.num_kernels = len(h.resblock_kernel_sizes) + self.num_upsamples = len(h.upsample_rates) + self.conv_pre = weight_norm(Conv1d(80, h.upsample_initial_channel, 7, 1, padding=3)) + resblock = ResBlock1 if h.resblock == "1" else ResBlock2 + + self.ups = nn.ModuleList() + for i, (u, k) in enumerate(zip(h.upsample_rates, h.upsample_kernel_sizes)): + self.ups.append( + weight_norm( + ConvTranspose1d( + h.upsample_initial_channel // (2**i), + h.upsample_initial_channel // (2 ** (i + 1)), + k, + u, + padding=(k - u) // 2, + ) + ) + ) + + self.resblocks = nn.ModuleList() + for i in range(len(self.ups)): + ch = h.upsample_initial_channel // (2 ** (i + 1)) + for _, (k, d) in enumerate(zip(h.resblock_kernel_sizes, h.resblock_dilation_sizes)): + self.resblocks.append(resblock(h, ch, k, d)) + + self.conv_post = weight_norm(Conv1d(ch, 1, 7, 1, padding=3)) + self.ups.apply(init_weights) + self.conv_post.apply(init_weights) + + def forward(self, x): + x = self.conv_pre(x) + for i in range(self.num_upsamples): + x = F.leaky_relu(x, LRELU_SLOPE) + x = self.ups[i](x) + xs = None + for j in range(self.num_kernels): + if xs is None: + xs = self.resblocks[i * self.num_kernels + j](x) + else: + xs += self.resblocks[i * self.num_kernels + j](x) + x = xs / self.num_kernels + x = F.leaky_relu(x) + x = self.conv_post(x) + x = torch.tanh(x) + + return x + + def remove_weight_norm(self): + print("Removing weight norm...") + for l in self.ups: + remove_weight_norm(l) + for l in self.resblocks: + l.remove_weight_norm() + remove_weight_norm(self.conv_pre) + remove_weight_norm(self.conv_post) + + +class DiscriminatorP(torch.nn.Module): + def __init__(self, period, kernel_size=5, stride=3, use_spectral_norm=False): + super().__init__() + self.period = period + norm_f = weight_norm if use_spectral_norm is False else spectral_norm + self.convs = nn.ModuleList( + [ + norm_f(Conv2d(1, 32, (kernel_size, 1), (stride, 1), padding=(get_padding(5, 1), 0))), + norm_f(Conv2d(32, 128, (kernel_size, 1), (stride, 1), padding=(get_padding(5, 1), 0))), + norm_f(Conv2d(128, 512, (kernel_size, 1), (stride, 1), padding=(get_padding(5, 1), 0))), + norm_f(Conv2d(512, 1024, (kernel_size, 1), (stride, 1), padding=(get_padding(5, 1), 0))), + norm_f(Conv2d(1024, 1024, (kernel_size, 1), 1, padding=(2, 0))), + ] + ) + self.conv_post = norm_f(Conv2d(1024, 1, (3, 1), 1, padding=(1, 0))) + + def forward(self, x): + fmap = [] + + # 1d to 2d + b, c, t = x.shape + if t % self.period != 0: # pad first + n_pad = self.period - (t % self.period) + x = F.pad(x, (0, n_pad), "reflect") + t = t + n_pad + x = x.view(b, c, t // self.period, self.period) + + for l in self.convs: + x = l(x) + x = F.leaky_relu(x, LRELU_SLOPE) + fmap.append(x) + x = self.conv_post(x) + fmap.append(x) + x = torch.flatten(x, 1, -1) + + return x, fmap + + +class MultiPeriodDiscriminator(torch.nn.Module): + def __init__(self): + super().__init__() + self.discriminators = nn.ModuleList( + [ + DiscriminatorP(2), + DiscriminatorP(3), + DiscriminatorP(5), + DiscriminatorP(7), + DiscriminatorP(11), + ] + ) + + def forward(self, y, y_hat): + y_d_rs = [] + y_d_gs = [] + fmap_rs = [] + fmap_gs = [] + for _, d in enumerate(self.discriminators): + y_d_r, fmap_r = d(y) + y_d_g, fmap_g = d(y_hat) + y_d_rs.append(y_d_r) + fmap_rs.append(fmap_r) + y_d_gs.append(y_d_g) + fmap_gs.append(fmap_g) + + return y_d_rs, y_d_gs, fmap_rs, fmap_gs + + +class DiscriminatorS(torch.nn.Module): + def __init__(self, use_spectral_norm=False): + super().__init__() + norm_f = weight_norm if use_spectral_norm is False else spectral_norm + self.convs = nn.ModuleList( + [ + norm_f(Conv1d(1, 128, 15, 1, padding=7)), + norm_f(Conv1d(128, 128, 41, 2, groups=4, padding=20)), + norm_f(Conv1d(128, 256, 41, 2, groups=16, padding=20)), + norm_f(Conv1d(256, 512, 41, 4, groups=16, padding=20)), + norm_f(Conv1d(512, 1024, 41, 4, groups=16, padding=20)), + norm_f(Conv1d(1024, 1024, 41, 1, groups=16, padding=20)), + norm_f(Conv1d(1024, 1024, 5, 1, padding=2)), + ] + ) + self.conv_post = norm_f(Conv1d(1024, 1, 3, 1, padding=1)) + + def forward(self, x): + fmap = [] + for l in self.convs: + x = l(x) + x = F.leaky_relu(x, LRELU_SLOPE) + fmap.append(x) + x = self.conv_post(x) + fmap.append(x) + x = torch.flatten(x, 1, -1) + + return x, fmap + + +class MultiScaleDiscriminator(torch.nn.Module): + def __init__(self): + super().__init__() + self.discriminators = nn.ModuleList( + [ + DiscriminatorS(use_spectral_norm=True), + DiscriminatorS(), + DiscriminatorS(), + ] + ) + self.meanpools = nn.ModuleList([AvgPool1d(4, 2, padding=2), AvgPool1d(4, 2, padding=2)]) + + def forward(self, y, y_hat): + y_d_rs = [] + y_d_gs = [] + fmap_rs = [] + fmap_gs = [] + for i, d in enumerate(self.discriminators): + if i != 0: + y = self.meanpools[i - 1](y) + y_hat = self.meanpools[i - 1](y_hat) + y_d_r, fmap_r = d(y) + y_d_g, fmap_g = d(y_hat) + y_d_rs.append(y_d_r) + fmap_rs.append(fmap_r) + y_d_gs.append(y_d_g) + fmap_gs.append(fmap_g) + + return y_d_rs, y_d_gs, fmap_rs, fmap_gs + + +def feature_loss(fmap_r, fmap_g): + loss = 0 + for dr, dg in zip(fmap_r, fmap_g): + for rl, gl in zip(dr, dg): + loss += torch.mean(torch.abs(rl - gl)) + + return loss * 2 + + +def discriminator_loss(disc_real_outputs, disc_generated_outputs): + loss = 0 + r_losses = [] + g_losses = [] + for dr, dg in zip(disc_real_outputs, disc_generated_outputs): + r_loss = torch.mean((1 - dr) ** 2) + g_loss = torch.mean(dg**2) + loss += r_loss + g_loss + r_losses.append(r_loss.item()) + g_losses.append(g_loss.item()) + + return loss, r_losses, g_losses + + +def generator_loss(disc_outputs): + loss = 0 + gen_losses = [] + for dg in disc_outputs: + l = torch.mean((1 - dg) ** 2) + gen_losses.append(l) + loss += l + + return loss, gen_losses diff --git a/xinference/thirdparty/matcha/hifigan/xutils.py b/xinference/thirdparty/matcha/hifigan/xutils.py new file mode 100644 index 0000000000..eefadcb7a1 --- /dev/null +++ b/xinference/thirdparty/matcha/hifigan/xutils.py @@ -0,0 +1,60 @@ +""" from https://github.com/jik876/hifi-gan """ + +import glob +import os + +import matplotlib +import torch +from torch.nn.utils import weight_norm + +matplotlib.use("Agg") +import matplotlib.pylab as plt + + +def plot_spectrogram(spectrogram): + fig, ax = plt.subplots(figsize=(10, 2)) + im = ax.imshow(spectrogram, aspect="auto", origin="lower", interpolation="none") + plt.colorbar(im, ax=ax) + + fig.canvas.draw() + plt.close() + + return fig + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) + + +def apply_weight_norm(m): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + weight_norm(m) + + +def get_padding(kernel_size, dilation=1): + return int((kernel_size * dilation - dilation) / 2) + + +def load_checkpoint(filepath, device): + assert os.path.isfile(filepath) + print(f"Loading '{filepath}'") + checkpoint_dict = torch.load(filepath, map_location=device) + print("Complete.") + return checkpoint_dict + + +def save_checkpoint(filepath, obj): + print(f"Saving checkpoint to {filepath}") + torch.save(obj, filepath) + print("Complete.") + + +def scan_checkpoint(cp_dir, prefix): + pattern = os.path.join(cp_dir, prefix + "????????") + cp_list = glob.glob(pattern) + if len(cp_list) == 0: + return None + return sorted(cp_list)[-1] diff --git a/xinference/thirdparty/matcha/models/__init__.py b/xinference/thirdparty/matcha/models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/models/baselightningmodule.py b/xinference/thirdparty/matcha/models/baselightningmodule.py new file mode 100644 index 0000000000..f8abe7b44f --- /dev/null +++ b/xinference/thirdparty/matcha/models/baselightningmodule.py @@ -0,0 +1,210 @@ +""" +This is a base lightning module that can be used to train a model. +The benefit of this abstraction is that all the logic outside of model definition can be reused for different models. +""" +import inspect +from abc import ABC +from typing import Any, Dict + +import torch +from lightning import LightningModule +from lightning.pytorch.utilities import grad_norm + +from matcha import utils +from matcha.utils.utils import plot_tensor + +log = utils.get_pylogger(__name__) + + +class BaseLightningClass(LightningModule, ABC): + def update_data_statistics(self, data_statistics): + if data_statistics is None: + data_statistics = { + "mel_mean": 0.0, + "mel_std": 1.0, + } + + self.register_buffer("mel_mean", torch.tensor(data_statistics["mel_mean"])) + self.register_buffer("mel_std", torch.tensor(data_statistics["mel_std"])) + + def configure_optimizers(self) -> Any: + optimizer = self.hparams.optimizer(params=self.parameters()) + if self.hparams.scheduler not in (None, {}): + scheduler_args = {} + # Manage last epoch for exponential schedulers + if "last_epoch" in inspect.signature(self.hparams.scheduler.scheduler).parameters: + if hasattr(self, "ckpt_loaded_epoch"): + current_epoch = self.ckpt_loaded_epoch - 1 + else: + current_epoch = -1 + + scheduler_args.update({"optimizer": optimizer}) + scheduler = self.hparams.scheduler.scheduler(**scheduler_args) + scheduler.last_epoch = current_epoch + return { + "optimizer": optimizer, + "lr_scheduler": { + "scheduler": scheduler, + "interval": self.hparams.scheduler.lightning_args.interval, + "frequency": self.hparams.scheduler.lightning_args.frequency, + "name": "learning_rate", + }, + } + + return {"optimizer": optimizer} + + def get_losses(self, batch): + x, x_lengths = batch["x"], batch["x_lengths"] + y, y_lengths = batch["y"], batch["y_lengths"] + spks = batch["spks"] + + dur_loss, prior_loss, diff_loss, *_ = self( + x=x, + x_lengths=x_lengths, + y=y, + y_lengths=y_lengths, + spks=spks, + out_size=self.out_size, + durations=batch["durations"], + ) + return { + "dur_loss": dur_loss, + "prior_loss": prior_loss, + "diff_loss": diff_loss, + } + + def on_load_checkpoint(self, checkpoint: Dict[str, Any]) -> None: + self.ckpt_loaded_epoch = checkpoint["epoch"] # pylint: disable=attribute-defined-outside-init + + def training_step(self, batch: Any, batch_idx: int): + loss_dict = self.get_losses(batch) + self.log( + "step", + float(self.global_step), + on_step=True, + prog_bar=True, + logger=True, + sync_dist=True, + ) + + self.log( + "sub_loss/train_dur_loss", + loss_dict["dur_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + self.log( + "sub_loss/train_prior_loss", + loss_dict["prior_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + self.log( + "sub_loss/train_diff_loss", + loss_dict["diff_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + + total_loss = sum(loss_dict.values()) + self.log( + "loss/train", + total_loss, + on_step=True, + on_epoch=True, + logger=True, + prog_bar=True, + sync_dist=True, + ) + + return {"loss": total_loss, "log": loss_dict} + + def validation_step(self, batch: Any, batch_idx: int): + loss_dict = self.get_losses(batch) + self.log( + "sub_loss/val_dur_loss", + loss_dict["dur_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + self.log( + "sub_loss/val_prior_loss", + loss_dict["prior_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + self.log( + "sub_loss/val_diff_loss", + loss_dict["diff_loss"], + on_step=True, + on_epoch=True, + logger=True, + sync_dist=True, + ) + + total_loss = sum(loss_dict.values()) + self.log( + "loss/val", + total_loss, + on_step=True, + on_epoch=True, + logger=True, + prog_bar=True, + sync_dist=True, + ) + + return total_loss + + def on_validation_end(self) -> None: + if self.trainer.is_global_zero: + one_batch = next(iter(self.trainer.val_dataloaders)) + if self.current_epoch == 0: + log.debug("Plotting original samples") + for i in range(2): + y = one_batch["y"][i].unsqueeze(0).to(self.device) + self.logger.experiment.add_image( + f"original/{i}", + plot_tensor(y.squeeze().cpu()), + self.current_epoch, + dataformats="HWC", + ) + + log.debug("Synthesising...") + for i in range(2): + x = one_batch["x"][i].unsqueeze(0).to(self.device) + x_lengths = one_batch["x_lengths"][i].unsqueeze(0).to(self.device) + spks = one_batch["spks"][i].unsqueeze(0).to(self.device) if one_batch["spks"] is not None else None + output = self.synthesise(x[:, :x_lengths], x_lengths, n_timesteps=10, spks=spks) + y_enc, y_dec = output["encoder_outputs"], output["decoder_outputs"] + attn = output["attn"] + self.logger.experiment.add_image( + f"generated_enc/{i}", + plot_tensor(y_enc.squeeze().cpu()), + self.current_epoch, + dataformats="HWC", + ) + self.logger.experiment.add_image( + f"generated_dec/{i}", + plot_tensor(y_dec.squeeze().cpu()), + self.current_epoch, + dataformats="HWC", + ) + self.logger.experiment.add_image( + f"alignment/{i}", + plot_tensor(attn.squeeze().cpu()), + self.current_epoch, + dataformats="HWC", + ) + + def on_before_optimizer_step(self, optimizer): + self.log_dict({f"grad_norm/{k}": v for k, v in grad_norm(self, norm_type=2).items()}) diff --git a/xinference/thirdparty/matcha/models/components/__init__.py b/xinference/thirdparty/matcha/models/components/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/models/components/decoder.py b/xinference/thirdparty/matcha/models/components/decoder.py new file mode 100644 index 0000000000..1137cd7008 --- /dev/null +++ b/xinference/thirdparty/matcha/models/components/decoder.py @@ -0,0 +1,443 @@ +import math +from typing import Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F +from conformer import ConformerBlock +from diffusers.models.activations import get_activation +from einops import pack, rearrange, repeat + +from matcha.models.components.transformer import BasicTransformerBlock + + +class SinusoidalPosEmb(torch.nn.Module): + def __init__(self, dim): + super().__init__() + self.dim = dim + assert self.dim % 2 == 0, "SinusoidalPosEmb requires dim to be even" + + def forward(self, x, scale=1000): + if x.ndim < 1: + x = x.unsqueeze(0) + device = x.device + half_dim = self.dim // 2 + emb = math.log(10000) / (half_dim - 1) + emb = torch.exp(torch.arange(half_dim, device=device).float() * -emb) + emb = scale * x.unsqueeze(1) * emb.unsqueeze(0) + emb = torch.cat((emb.sin(), emb.cos()), dim=-1) + return emb + + +class Block1D(torch.nn.Module): + def __init__(self, dim, dim_out, groups=8): + super().__init__() + self.block = torch.nn.Sequential( + torch.nn.Conv1d(dim, dim_out, 3, padding=1), + torch.nn.GroupNorm(groups, dim_out), + nn.Mish(), + ) + + def forward(self, x, mask): + output = self.block(x * mask) + return output * mask + + +class ResnetBlock1D(torch.nn.Module): + def __init__(self, dim, dim_out, time_emb_dim, groups=8): + super().__init__() + self.mlp = torch.nn.Sequential(nn.Mish(), torch.nn.Linear(time_emb_dim, dim_out)) + + self.block1 = Block1D(dim, dim_out, groups=groups) + self.block2 = Block1D(dim_out, dim_out, groups=groups) + + self.res_conv = torch.nn.Conv1d(dim, dim_out, 1) + + def forward(self, x, mask, time_emb): + h = self.block1(x, mask) + h += self.mlp(time_emb).unsqueeze(-1) + h = self.block2(h, mask) + output = h + self.res_conv(x * mask) + return output + + +class Downsample1D(nn.Module): + def __init__(self, dim): + super().__init__() + self.conv = torch.nn.Conv1d(dim, dim, 3, 2, 1) + + def forward(self, x): + return self.conv(x) + + +class TimestepEmbedding(nn.Module): + def __init__( + self, + in_channels: int, + time_embed_dim: int, + act_fn: str = "silu", + out_dim: int = None, + post_act_fn: Optional[str] = None, + cond_proj_dim=None, + ): + super().__init__() + + self.linear_1 = nn.Linear(in_channels, time_embed_dim) + + if cond_proj_dim is not None: + self.cond_proj = nn.Linear(cond_proj_dim, in_channels, bias=False) + else: + self.cond_proj = None + + self.act = get_activation(act_fn) + + if out_dim is not None: + time_embed_dim_out = out_dim + else: + time_embed_dim_out = time_embed_dim + self.linear_2 = nn.Linear(time_embed_dim, time_embed_dim_out) + + if post_act_fn is None: + self.post_act = None + else: + self.post_act = get_activation(post_act_fn) + + def forward(self, sample, condition=None): + if condition is not None: + sample = sample + self.cond_proj(condition) + sample = self.linear_1(sample) + + if self.act is not None: + sample = self.act(sample) + + sample = self.linear_2(sample) + + if self.post_act is not None: + sample = self.post_act(sample) + return sample + + +class Upsample1D(nn.Module): + """A 1D upsampling layer with an optional convolution. + + Parameters: + channels (`int`): + number of channels in the inputs and outputs. + use_conv (`bool`, default `False`): + option to use a convolution. + use_conv_transpose (`bool`, default `False`): + option to use a convolution transpose. + out_channels (`int`, optional): + number of output channels. Defaults to `channels`. + """ + + def __init__(self, channels, use_conv=False, use_conv_transpose=True, out_channels=None, name="conv"): + super().__init__() + self.channels = channels + self.out_channels = out_channels or channels + self.use_conv = use_conv + self.use_conv_transpose = use_conv_transpose + self.name = name + + self.conv = None + if use_conv_transpose: + self.conv = nn.ConvTranspose1d(channels, self.out_channels, 4, 2, 1) + elif use_conv: + self.conv = nn.Conv1d(self.channels, self.out_channels, 3, padding=1) + + def forward(self, inputs): + assert inputs.shape[1] == self.channels + if self.use_conv_transpose: + return self.conv(inputs) + + outputs = F.interpolate(inputs, scale_factor=2.0, mode="nearest") + + if self.use_conv: + outputs = self.conv(outputs) + + return outputs + + +class ConformerWrapper(ConformerBlock): + def __init__( # pylint: disable=useless-super-delegation + self, + *, + dim, + dim_head=64, + heads=8, + ff_mult=4, + conv_expansion_factor=2, + conv_kernel_size=31, + attn_dropout=0, + ff_dropout=0, + conv_dropout=0, + conv_causal=False, + ): + super().__init__( + dim=dim, + dim_head=dim_head, + heads=heads, + ff_mult=ff_mult, + conv_expansion_factor=conv_expansion_factor, + conv_kernel_size=conv_kernel_size, + attn_dropout=attn_dropout, + ff_dropout=ff_dropout, + conv_dropout=conv_dropout, + conv_causal=conv_causal, + ) + + def forward( + self, + hidden_states, + attention_mask, + encoder_hidden_states=None, + encoder_attention_mask=None, + timestep=None, + ): + return super().forward(x=hidden_states, mask=attention_mask.bool()) + + +class Decoder(nn.Module): + def __init__( + self, + in_channels, + out_channels, + channels=(256, 256), + dropout=0.05, + attention_head_dim=64, + n_blocks=1, + num_mid_blocks=2, + num_heads=4, + act_fn="snake", + down_block_type="transformer", + mid_block_type="transformer", + up_block_type="transformer", + ): + super().__init__() + channels = tuple(channels) + self.in_channels = in_channels + self.out_channels = out_channels + + self.time_embeddings = SinusoidalPosEmb(in_channels) + time_embed_dim = channels[0] * 4 + self.time_mlp = TimestepEmbedding( + in_channels=in_channels, + time_embed_dim=time_embed_dim, + act_fn="silu", + ) + + self.down_blocks = nn.ModuleList([]) + self.mid_blocks = nn.ModuleList([]) + self.up_blocks = nn.ModuleList([]) + + output_channel = in_channels + for i in range(len(channels)): # pylint: disable=consider-using-enumerate + input_channel = output_channel + output_channel = channels[i] + is_last = i == len(channels) - 1 + resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim) + transformer_blocks = nn.ModuleList( + [ + self.get_block( + down_block_type, + output_channel, + attention_head_dim, + num_heads, + dropout, + act_fn, + ) + for _ in range(n_blocks) + ] + ) + downsample = ( + Downsample1D(output_channel) if not is_last else nn.Conv1d(output_channel, output_channel, 3, padding=1) + ) + + self.down_blocks.append(nn.ModuleList([resnet, transformer_blocks, downsample])) + + for i in range(num_mid_blocks): + input_channel = channels[-1] + out_channels = channels[-1] + + resnet = ResnetBlock1D(dim=input_channel, dim_out=output_channel, time_emb_dim=time_embed_dim) + + transformer_blocks = nn.ModuleList( + [ + self.get_block( + mid_block_type, + output_channel, + attention_head_dim, + num_heads, + dropout, + act_fn, + ) + for _ in range(n_blocks) + ] + ) + + self.mid_blocks.append(nn.ModuleList([resnet, transformer_blocks])) + + channels = channels[::-1] + (channels[0],) + for i in range(len(channels) - 1): + input_channel = channels[i] + output_channel = channels[i + 1] + is_last = i == len(channels) - 2 + + resnet = ResnetBlock1D( + dim=2 * input_channel, + dim_out=output_channel, + time_emb_dim=time_embed_dim, + ) + transformer_blocks = nn.ModuleList( + [ + self.get_block( + up_block_type, + output_channel, + attention_head_dim, + num_heads, + dropout, + act_fn, + ) + for _ in range(n_blocks) + ] + ) + upsample = ( + Upsample1D(output_channel, use_conv_transpose=True) + if not is_last + else nn.Conv1d(output_channel, output_channel, 3, padding=1) + ) + + self.up_blocks.append(nn.ModuleList([resnet, transformer_blocks, upsample])) + + self.final_block = Block1D(channels[-1], channels[-1]) + self.final_proj = nn.Conv1d(channels[-1], self.out_channels, 1) + + self.initialize_weights() + # nn.init.normal_(self.final_proj.weight) + + @staticmethod + def get_block(block_type, dim, attention_head_dim, num_heads, dropout, act_fn): + if block_type == "conformer": + block = ConformerWrapper( + dim=dim, + dim_head=attention_head_dim, + heads=num_heads, + ff_mult=1, + conv_expansion_factor=2, + ff_dropout=dropout, + attn_dropout=dropout, + conv_dropout=dropout, + conv_kernel_size=31, + ) + elif block_type == "transformer": + block = BasicTransformerBlock( + dim=dim, + num_attention_heads=num_heads, + attention_head_dim=attention_head_dim, + dropout=dropout, + activation_fn=act_fn, + ) + else: + raise ValueError(f"Unknown block type {block_type}") + + return block + + def initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv1d): + nn.init.kaiming_normal_(m.weight, nonlinearity="relu") + + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + elif isinstance(m, nn.GroupNorm): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + + elif isinstance(m, nn.Linear): + nn.init.kaiming_normal_(m.weight, nonlinearity="relu") + + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x, mask, mu, t, spks=None, cond=None): + """Forward pass of the UNet1DConditional model. + + Args: + x (torch.Tensor): shape (batch_size, in_channels, time) + mask (_type_): shape (batch_size, 1, time) + t (_type_): shape (batch_size) + spks (_type_, optional): shape: (batch_size, condition_channels). Defaults to None. + cond (_type_, optional): placeholder for future use. Defaults to None. + + Raises: + ValueError: _description_ + ValueError: _description_ + + Returns: + _type_: _description_ + """ + + t = self.time_embeddings(t) + t = self.time_mlp(t) + + x = pack([x, mu], "b * t")[0] + + if spks is not None: + spks = repeat(spks, "b c -> b c t", t=x.shape[-1]) + x = pack([x, spks], "b * t")[0] + + hiddens = [] + masks = [mask] + for resnet, transformer_blocks, downsample in self.down_blocks: + mask_down = masks[-1] + x = resnet(x, mask_down, t) + x = rearrange(x, "b c t -> b t c") + mask_down = rearrange(mask_down, "b 1 t -> b t") + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=mask_down, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t") + mask_down = rearrange(mask_down, "b t -> b 1 t") + hiddens.append(x) # Save hidden states for skip connections + x = downsample(x * mask_down) + masks.append(mask_down[:, :, ::2]) + + masks = masks[:-1] + mask_mid = masks[-1] + + for resnet, transformer_blocks in self.mid_blocks: + x = resnet(x, mask_mid, t) + x = rearrange(x, "b c t -> b t c") + mask_mid = rearrange(mask_mid, "b 1 t -> b t") + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=mask_mid, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t") + mask_mid = rearrange(mask_mid, "b t -> b 1 t") + + for resnet, transformer_blocks, upsample in self.up_blocks: + mask_up = masks.pop() + x = resnet(pack([x, hiddens.pop()], "b * t")[0], mask_up, t) + x = rearrange(x, "b c t -> b t c") + mask_up = rearrange(mask_up, "b 1 t -> b t") + for transformer_block in transformer_blocks: + x = transformer_block( + hidden_states=x, + attention_mask=mask_up, + timestep=t, + ) + x = rearrange(x, "b t c -> b c t") + mask_up = rearrange(mask_up, "b t -> b 1 t") + x = upsample(x * mask_up) + + x = self.final_block(x, mask_up) + output = self.final_proj(x * mask_up) + + return output * mask diff --git a/xinference/thirdparty/matcha/models/components/flow_matching.py b/xinference/thirdparty/matcha/models/components/flow_matching.py new file mode 100644 index 0000000000..5cad7431ef --- /dev/null +++ b/xinference/thirdparty/matcha/models/components/flow_matching.py @@ -0,0 +1,132 @@ +from abc import ABC + +import torch +import torch.nn.functional as F + +from matcha.models.components.decoder import Decoder +from matcha.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class BASECFM(torch.nn.Module, ABC): + def __init__( + self, + n_feats, + cfm_params, + n_spks=1, + spk_emb_dim=128, + ): + super().__init__() + self.n_feats = n_feats + self.n_spks = n_spks + self.spk_emb_dim = spk_emb_dim + self.solver = cfm_params.solver + if hasattr(cfm_params, "sigma_min"): + self.sigma_min = cfm_params.sigma_min + else: + self.sigma_min = 1e-4 + + self.estimator = None + + @torch.inference_mode() + def forward(self, mu, mask, n_timesteps, temperature=1.0, spks=None, cond=None): + """Forward diffusion + + Args: + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): output_mask + shape: (batch_size, 1, mel_timesteps) + n_timesteps (int): number of diffusion steps + temperature (float, optional): temperature for scaling noise. Defaults to 1.0. + spks (torch.Tensor, optional): speaker ids. Defaults to None. + shape: (batch_size, spk_emb_dim) + cond: Not used but kept for future purposes + + Returns: + sample: generated mel-spectrogram + shape: (batch_size, n_feats, mel_timesteps) + """ + z = torch.randn_like(mu) * temperature + t_span = torch.linspace(0, 1, n_timesteps + 1, device=mu.device) + return self.solve_euler(z, t_span=t_span, mu=mu, mask=mask, spks=spks, cond=cond) + + def solve_euler(self, x, t_span, mu, mask, spks, cond): + """ + Fixed euler solver for ODEs. + Args: + x (torch.Tensor): random noise + t_span (torch.Tensor): n_timesteps interpolated + shape: (n_timesteps + 1,) + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): output_mask + shape: (batch_size, 1, mel_timesteps) + spks (torch.Tensor, optional): speaker ids. Defaults to None. + shape: (batch_size, spk_emb_dim) + cond: Not used but kept for future purposes + """ + t, _, dt = t_span[0], t_span[-1], t_span[1] - t_span[0] + + # I am storing this because I can later plot it by putting a debugger here and saving it to a file + # Or in future might add like a return_all_steps flag + sol = [] + + for step in range(1, len(t_span)): + dphi_dt = self.estimator(x, mask, mu, t, spks, cond) + + x = x + dt * dphi_dt + t = t + dt + sol.append(x) + if step < len(t_span) - 1: + dt = t_span[step + 1] - t + + return sol[-1] + + def compute_loss(self, x1, mask, mu, spks=None, cond=None): + """Computes diffusion loss + + Args: + x1 (torch.Tensor): Target + shape: (batch_size, n_feats, mel_timesteps) + mask (torch.Tensor): target mask + shape: (batch_size, 1, mel_timesteps) + mu (torch.Tensor): output of encoder + shape: (batch_size, n_feats, mel_timesteps) + spks (torch.Tensor, optional): speaker embedding. Defaults to None. + shape: (batch_size, spk_emb_dim) + + Returns: + loss: conditional flow matching loss + y: conditional flow + shape: (batch_size, n_feats, mel_timesteps) + """ + b, _, t = mu.shape + + # random timestep + t = torch.rand([b, 1, 1], device=mu.device, dtype=mu.dtype) + # sample noise p(x_0) + z = torch.randn_like(x1) + + y = (1 - (1 - self.sigma_min) * t) * z + t * x1 + u = x1 - (1 - self.sigma_min) * z + + loss = F.mse_loss(self.estimator(y, mask, mu, t.squeeze(), spks), u, reduction="sum") / ( + torch.sum(mask) * u.shape[1] + ) + return loss, y + + +class CFM(BASECFM): + def __init__(self, in_channels, out_channel, cfm_params, decoder_params, n_spks=1, spk_emb_dim=64): + super().__init__( + n_feats=in_channels, + cfm_params=cfm_params, + n_spks=n_spks, + spk_emb_dim=spk_emb_dim, + ) + + in_channels = in_channels + (spk_emb_dim if n_spks > 1 else 0) + # Just change the architecture of the estimator here + self.estimator = Decoder(in_channels=in_channels, out_channels=out_channel, **decoder_params) diff --git a/xinference/thirdparty/matcha/models/components/text_encoder.py b/xinference/thirdparty/matcha/models/components/text_encoder.py new file mode 100644 index 0000000000..a388d05d63 --- /dev/null +++ b/xinference/thirdparty/matcha/models/components/text_encoder.py @@ -0,0 +1,410 @@ +""" from https://github.com/jaywalnut310/glow-tts """ + +import math + +import torch +import torch.nn as nn +from einops import rearrange + +import matcha.utils as utils +from matcha.utils.model import sequence_mask + +log = utils.get_pylogger(__name__) + + +class LayerNorm(nn.Module): + def __init__(self, channels, eps=1e-4): + super().__init__() + self.channels = channels + self.eps = eps + + self.gamma = torch.nn.Parameter(torch.ones(channels)) + self.beta = torch.nn.Parameter(torch.zeros(channels)) + + def forward(self, x): + n_dims = len(x.shape) + mean = torch.mean(x, 1, keepdim=True) + variance = torch.mean((x - mean) ** 2, 1, keepdim=True) + + x = (x - mean) * torch.rsqrt(variance + self.eps) + + shape = [1, -1] + [1] * (n_dims - 2) + x = x * self.gamma.view(*shape) + self.beta.view(*shape) + return x + + +class ConvReluNorm(nn.Module): + def __init__(self, in_channels, hidden_channels, out_channels, kernel_size, n_layers, p_dropout): + super().__init__() + self.in_channels = in_channels + self.hidden_channels = hidden_channels + self.out_channels = out_channels + self.kernel_size = kernel_size + self.n_layers = n_layers + self.p_dropout = p_dropout + + self.conv_layers = torch.nn.ModuleList() + self.norm_layers = torch.nn.ModuleList() + self.conv_layers.append(torch.nn.Conv1d(in_channels, hidden_channels, kernel_size, padding=kernel_size // 2)) + self.norm_layers.append(LayerNorm(hidden_channels)) + self.relu_drop = torch.nn.Sequential(torch.nn.ReLU(), torch.nn.Dropout(p_dropout)) + for _ in range(n_layers - 1): + self.conv_layers.append( + torch.nn.Conv1d(hidden_channels, hidden_channels, kernel_size, padding=kernel_size // 2) + ) + self.norm_layers.append(LayerNorm(hidden_channels)) + self.proj = torch.nn.Conv1d(hidden_channels, out_channels, 1) + self.proj.weight.data.zero_() + self.proj.bias.data.zero_() + + def forward(self, x, x_mask): + x_org = x + for i in range(self.n_layers): + x = self.conv_layers[i](x * x_mask) + x = self.norm_layers[i](x) + x = self.relu_drop(x) + x = x_org + self.proj(x) + return x * x_mask + + +class DurationPredictor(nn.Module): + def __init__(self, in_channels, filter_channels, kernel_size, p_dropout): + super().__init__() + self.in_channels = in_channels + self.filter_channels = filter_channels + self.p_dropout = p_dropout + + self.drop = torch.nn.Dropout(p_dropout) + self.conv_1 = torch.nn.Conv1d(in_channels, filter_channels, kernel_size, padding=kernel_size // 2) + self.norm_1 = LayerNorm(filter_channels) + self.conv_2 = torch.nn.Conv1d(filter_channels, filter_channels, kernel_size, padding=kernel_size // 2) + self.norm_2 = LayerNorm(filter_channels) + self.proj = torch.nn.Conv1d(filter_channels, 1, 1) + + def forward(self, x, x_mask): + x = self.conv_1(x * x_mask) + x = torch.relu(x) + x = self.norm_1(x) + x = self.drop(x) + x = self.conv_2(x * x_mask) + x = torch.relu(x) + x = self.norm_2(x) + x = self.drop(x) + x = self.proj(x * x_mask) + return x * x_mask + + +class RotaryPositionalEmbeddings(nn.Module): + """ + ## RoPE module + + Rotary encoding transforms pairs of features by rotating in the 2D plane. + That is, it organizes the $d$ features as $\frac{d}{2}$ pairs. + Each pair can be considered a coordinate in a 2D plane, and the encoding will rotate it + by an angle depending on the position of the token. + """ + + def __init__(self, d: int, base: int = 10_000): + r""" + * `d` is the number of features $d$ + * `base` is the constant used for calculating $\Theta$ + """ + super().__init__() + + self.base = base + self.d = int(d) + self.cos_cached = None + self.sin_cached = None + + def _build_cache(self, x: torch.Tensor): + r""" + Cache $\cos$ and $\sin$ values + """ + # Return if cache is already built + if self.cos_cached is not None and x.shape[0] <= self.cos_cached.shape[0]: + return + + # Get sequence length + seq_len = x.shape[0] + + # $\Theta = {\theta_i = 10000^{-\frac{2(i-1)}{d}}, i \in [1, 2, ..., \frac{d}{2}]}$ + theta = 1.0 / (self.base ** (torch.arange(0, self.d, 2).float() / self.d)).to(x.device) + + # Create position indexes `[0, 1, ..., seq_len - 1]` + seq_idx = torch.arange(seq_len, device=x.device).float().to(x.device) + + # Calculate the product of position index and $\theta_i$ + idx_theta = torch.einsum("n,d->nd", seq_idx, theta) + + # Concatenate so that for row $m$ we have + # $[m \theta_0, m \theta_1, ..., m \theta_{\frac{d}{2}}, m \theta_0, m \theta_1, ..., m \theta_{\frac{d}{2}}]$ + idx_theta2 = torch.cat([idx_theta, idx_theta], dim=1) + + # Cache them + self.cos_cached = idx_theta2.cos()[:, None, None, :] + self.sin_cached = idx_theta2.sin()[:, None, None, :] + + def _neg_half(self, x: torch.Tensor): + # $\frac{d}{2}$ + d_2 = self.d // 2 + + # Calculate $[-x^{(\frac{d}{2} + 1)}, -x^{(\frac{d}{2} + 2)}, ..., -x^{(d)}, x^{(1)}, x^{(2)}, ..., x^{(\frac{d}{2})}]$ + return torch.cat([-x[:, :, :, d_2:], x[:, :, :, :d_2]], dim=-1) + + def forward(self, x: torch.Tensor): + """ + * `x` is the Tensor at the head of a key or a query with shape `[seq_len, batch_size, n_heads, d]` + """ + # Cache $\cos$ and $\sin$ values + x = rearrange(x, "b h t d -> t b h d") + + self._build_cache(x) + + # Split the features, we can choose to apply rotary embeddings only to a partial set of features. + x_rope, x_pass = x[..., : self.d], x[..., self.d :] + + # Calculate + # $[-x^{(\frac{d}{2} + 1)}, -x^{(\frac{d}{2} + 2)}, ..., -x^{(d)}, x^{(1)}, x^{(2)}, ..., x^{(\frac{d}{2})}]$ + neg_half_x = self._neg_half(x_rope) + + x_rope = (x_rope * self.cos_cached[: x.shape[0]]) + (neg_half_x * self.sin_cached[: x.shape[0]]) + + return rearrange(torch.cat((x_rope, x_pass), dim=-1), "t b h d -> b h t d") + + +class MultiHeadAttention(nn.Module): + def __init__( + self, + channels, + out_channels, + n_heads, + heads_share=True, + p_dropout=0.0, + proximal_bias=False, + proximal_init=False, + ): + super().__init__() + assert channels % n_heads == 0 + + self.channels = channels + self.out_channels = out_channels + self.n_heads = n_heads + self.heads_share = heads_share + self.proximal_bias = proximal_bias + self.p_dropout = p_dropout + self.attn = None + + self.k_channels = channels // n_heads + self.conv_q = torch.nn.Conv1d(channels, channels, 1) + self.conv_k = torch.nn.Conv1d(channels, channels, 1) + self.conv_v = torch.nn.Conv1d(channels, channels, 1) + + # from https://nn.labml.ai/transformers/rope/index.html + self.query_rotary_pe = RotaryPositionalEmbeddings(self.k_channels * 0.5) + self.key_rotary_pe = RotaryPositionalEmbeddings(self.k_channels * 0.5) + + self.conv_o = torch.nn.Conv1d(channels, out_channels, 1) + self.drop = torch.nn.Dropout(p_dropout) + + torch.nn.init.xavier_uniform_(self.conv_q.weight) + torch.nn.init.xavier_uniform_(self.conv_k.weight) + if proximal_init: + self.conv_k.weight.data.copy_(self.conv_q.weight.data) + self.conv_k.bias.data.copy_(self.conv_q.bias.data) + torch.nn.init.xavier_uniform_(self.conv_v.weight) + + def forward(self, x, c, attn_mask=None): + q = self.conv_q(x) + k = self.conv_k(c) + v = self.conv_v(c) + + x, self.attn = self.attention(q, k, v, mask=attn_mask) + + x = self.conv_o(x) + return x + + def attention(self, query, key, value, mask=None): + b, d, t_s, t_t = (*key.size(), query.size(2)) + query = rearrange(query, "b (h c) t-> b h t c", h=self.n_heads) + key = rearrange(key, "b (h c) t-> b h t c", h=self.n_heads) + value = rearrange(value, "b (h c) t-> b h t c", h=self.n_heads) + + query = self.query_rotary_pe(query) + key = self.key_rotary_pe(key) + + scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(self.k_channels) + + if self.proximal_bias: + assert t_s == t_t, "Proximal bias is only available for self-attention." + scores = scores + self._attention_bias_proximal(t_s).to(device=scores.device, dtype=scores.dtype) + if mask is not None: + scores = scores.masked_fill(mask == 0, -1e4) + p_attn = torch.nn.functional.softmax(scores, dim=-1) + p_attn = self.drop(p_attn) + output = torch.matmul(p_attn, value) + output = output.transpose(2, 3).contiguous().view(b, d, t_t) + return output, p_attn + + @staticmethod + def _attention_bias_proximal(length): + r = torch.arange(length, dtype=torch.float32) + diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1) + return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0) + + +class FFN(nn.Module): + def __init__(self, in_channels, out_channels, filter_channels, kernel_size, p_dropout=0.0): + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.filter_channels = filter_channels + self.kernel_size = kernel_size + self.p_dropout = p_dropout + + self.conv_1 = torch.nn.Conv1d(in_channels, filter_channels, kernel_size, padding=kernel_size // 2) + self.conv_2 = torch.nn.Conv1d(filter_channels, out_channels, kernel_size, padding=kernel_size // 2) + self.drop = torch.nn.Dropout(p_dropout) + + def forward(self, x, x_mask): + x = self.conv_1(x * x_mask) + x = torch.relu(x) + x = self.drop(x) + x = self.conv_2(x * x_mask) + return x * x_mask + + +class Encoder(nn.Module): + def __init__( + self, + hidden_channels, + filter_channels, + n_heads, + n_layers, + kernel_size=1, + p_dropout=0.0, + **kwargs, + ): + super().__init__() + self.hidden_channels = hidden_channels + self.filter_channels = filter_channels + self.n_heads = n_heads + self.n_layers = n_layers + self.kernel_size = kernel_size + self.p_dropout = p_dropout + + self.drop = torch.nn.Dropout(p_dropout) + self.attn_layers = torch.nn.ModuleList() + self.norm_layers_1 = torch.nn.ModuleList() + self.ffn_layers = torch.nn.ModuleList() + self.norm_layers_2 = torch.nn.ModuleList() + for _ in range(self.n_layers): + self.attn_layers.append(MultiHeadAttention(hidden_channels, hidden_channels, n_heads, p_dropout=p_dropout)) + self.norm_layers_1.append(LayerNorm(hidden_channels)) + self.ffn_layers.append( + FFN( + hidden_channels, + hidden_channels, + filter_channels, + kernel_size, + p_dropout=p_dropout, + ) + ) + self.norm_layers_2.append(LayerNorm(hidden_channels)) + + def forward(self, x, x_mask): + attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1) + for i in range(self.n_layers): + x = x * x_mask + y = self.attn_layers[i](x, x, attn_mask) + y = self.drop(y) + x = self.norm_layers_1[i](x + y) + y = self.ffn_layers[i](x, x_mask) + y = self.drop(y) + x = self.norm_layers_2[i](x + y) + x = x * x_mask + return x + + +class TextEncoder(nn.Module): + def __init__( + self, + encoder_type, + encoder_params, + duration_predictor_params, + n_vocab, + n_spks=1, + spk_emb_dim=128, + ): + super().__init__() + self.encoder_type = encoder_type + self.n_vocab = n_vocab + self.n_feats = encoder_params.n_feats + self.n_channels = encoder_params.n_channels + self.spk_emb_dim = spk_emb_dim + self.n_spks = n_spks + + self.emb = torch.nn.Embedding(n_vocab, self.n_channels) + torch.nn.init.normal_(self.emb.weight, 0.0, self.n_channels**-0.5) + + if encoder_params.prenet: + self.prenet = ConvReluNorm( + self.n_channels, + self.n_channels, + self.n_channels, + kernel_size=5, + n_layers=3, + p_dropout=0.5, + ) + else: + self.prenet = lambda x, x_mask: x + + self.encoder = Encoder( + encoder_params.n_channels + (spk_emb_dim if n_spks > 1 else 0), + encoder_params.filter_channels, + encoder_params.n_heads, + encoder_params.n_layers, + encoder_params.kernel_size, + encoder_params.p_dropout, + ) + + self.proj_m = torch.nn.Conv1d(self.n_channels + (spk_emb_dim if n_spks > 1 else 0), self.n_feats, 1) + self.proj_w = DurationPredictor( + self.n_channels + (spk_emb_dim if n_spks > 1 else 0), + duration_predictor_params.filter_channels_dp, + duration_predictor_params.kernel_size, + duration_predictor_params.p_dropout, + ) + + def forward(self, x, x_lengths, spks=None): + """Run forward pass to the transformer based encoder and duration predictor + + Args: + x (torch.Tensor): text input + shape: (batch_size, max_text_length) + x_lengths (torch.Tensor): text input lengths + shape: (batch_size,) + spks (torch.Tensor, optional): speaker ids. Defaults to None. + shape: (batch_size,) + + Returns: + mu (torch.Tensor): average output of the encoder + shape: (batch_size, n_feats, max_text_length) + logw (torch.Tensor): log duration predicted by the duration predictor + shape: (batch_size, 1, max_text_length) + x_mask (torch.Tensor): mask for the text input + shape: (batch_size, 1, max_text_length) + """ + x = self.emb(x) * math.sqrt(self.n_channels) + x = torch.transpose(x, 1, -1) + x_mask = torch.unsqueeze(sequence_mask(x_lengths, x.size(2)), 1).to(x.dtype) + + x = self.prenet(x, x_mask) + if self.n_spks > 1: + x = torch.cat([x, spks.unsqueeze(-1).repeat(1, 1, x.shape[-1])], dim=1) + x = self.encoder(x, x_mask) + mu = self.proj_m(x) * x_mask + + x_dp = torch.detach(x) + logw = self.proj_w(x_dp, x_mask) + + return mu, logw, x_mask diff --git a/xinference/thirdparty/matcha/models/components/transformer.py b/xinference/thirdparty/matcha/models/components/transformer.py new file mode 100644 index 0000000000..dd1afa3aff --- /dev/null +++ b/xinference/thirdparty/matcha/models/components/transformer.py @@ -0,0 +1,316 @@ +from typing import Any, Dict, Optional + +import torch +import torch.nn as nn +from diffusers.models.attention import ( + GEGLU, + GELU, + AdaLayerNorm, + AdaLayerNormZero, + ApproximateGELU, +) +from diffusers.models.attention_processor import Attention +from diffusers.models.lora import LoRACompatibleLinear +from diffusers.utils.torch_utils import maybe_allow_in_graph + + +class SnakeBeta(nn.Module): + """ + A modified Snake function which uses separate parameters for the magnitude of the periodic components + Shape: + - Input: (B, C, T) + - Output: (B, C, T), same shape as the input + Parameters: + - alpha - trainable parameter that controls frequency + - beta - trainable parameter that controls magnitude + References: + - This activation function is a modified version based on this paper by Liu Ziyin, Tilman Hartwig, Masahito Ueda: + https://arxiv.org/abs/2006.08195 + Examples: + >>> a1 = snakebeta(256) + >>> x = torch.randn(256) + >>> x = a1(x) + """ + + def __init__(self, in_features, out_features, alpha=1.0, alpha_trainable=True, alpha_logscale=True): + """ + Initialization. + INPUT: + - in_features: shape of the input + - alpha - trainable parameter that controls frequency + - beta - trainable parameter that controls magnitude + alpha is initialized to 1 by default, higher values = higher-frequency. + beta is initialized to 1 by default, higher values = higher-magnitude. + alpha will be trained along with the rest of your model. + """ + super().__init__() + self.in_features = out_features if isinstance(out_features, list) else [out_features] + self.proj = LoRACompatibleLinear(in_features, out_features) + + # initialize alpha + self.alpha_logscale = alpha_logscale + if self.alpha_logscale: # log scale alphas initialized to zeros + self.alpha = nn.Parameter(torch.zeros(self.in_features) * alpha) + self.beta = nn.Parameter(torch.zeros(self.in_features) * alpha) + else: # linear scale alphas initialized to ones + self.alpha = nn.Parameter(torch.ones(self.in_features) * alpha) + self.beta = nn.Parameter(torch.ones(self.in_features) * alpha) + + self.alpha.requires_grad = alpha_trainable + self.beta.requires_grad = alpha_trainable + + self.no_div_by_zero = 0.000000001 + + def forward(self, x): + """ + Forward pass of the function. + Applies the function to the input elementwise. + SnakeBeta ∶= x + 1/b * sin^2 (xa) + """ + x = self.proj(x) + if self.alpha_logscale: + alpha = torch.exp(self.alpha) + beta = torch.exp(self.beta) + else: + alpha = self.alpha + beta = self.beta + + x = x + (1.0 / (beta + self.no_div_by_zero)) * torch.pow(torch.sin(x * alpha), 2) + + return x + + +class FeedForward(nn.Module): + r""" + A feed-forward layer. + + Parameters: + dim (`int`): The number of channels in the input. + dim_out (`int`, *optional*): The number of channels in the output. If not given, defaults to `dim`. + mult (`int`, *optional*, defaults to 4): The multiplier to use for the hidden dimension. + dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. + activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. + final_dropout (`bool` *optional*, defaults to False): Apply a final dropout. + """ + + def __init__( + self, + dim: int, + dim_out: Optional[int] = None, + mult: int = 4, + dropout: float = 0.0, + activation_fn: str = "geglu", + final_dropout: bool = False, + ): + super().__init__() + inner_dim = int(dim * mult) + dim_out = dim_out if dim_out is not None else dim + + if activation_fn == "gelu": + act_fn = GELU(dim, inner_dim) + if activation_fn == "gelu-approximate": + act_fn = GELU(dim, inner_dim, approximate="tanh") + elif activation_fn == "geglu": + act_fn = GEGLU(dim, inner_dim) + elif activation_fn == "geglu-approximate": + act_fn = ApproximateGELU(dim, inner_dim) + elif activation_fn == "snakebeta": + act_fn = SnakeBeta(dim, inner_dim) + + self.net = nn.ModuleList([]) + # project in + self.net.append(act_fn) + # project dropout + self.net.append(nn.Dropout(dropout)) + # project out + self.net.append(LoRACompatibleLinear(inner_dim, dim_out)) + # FF as used in Vision Transformer, MLP-Mixer, etc. have a final dropout + if final_dropout: + self.net.append(nn.Dropout(dropout)) + + def forward(self, hidden_states): + for module in self.net: + hidden_states = module(hidden_states) + return hidden_states + + +@maybe_allow_in_graph +class BasicTransformerBlock(nn.Module): + r""" + A basic Transformer block. + + Parameters: + dim (`int`): The number of channels in the input and output. + num_attention_heads (`int`): The number of heads to use for multi-head attention. + attention_head_dim (`int`): The number of channels in each head. + dropout (`float`, *optional*, defaults to 0.0): The dropout probability to use. + cross_attention_dim (`int`, *optional*): The size of the encoder_hidden_states vector for cross attention. + only_cross_attention (`bool`, *optional*): + Whether to use only cross-attention layers. In this case two cross attention layers are used. + double_self_attention (`bool`, *optional*): + Whether to use two self-attention layers. In this case no cross attention layers are used. + activation_fn (`str`, *optional*, defaults to `"geglu"`): Activation function to be used in feed-forward. + num_embeds_ada_norm (: + obj: `int`, *optional*): The number of diffusion steps used during training. See `Transformer2DModel`. + attention_bias (: + obj: `bool`, *optional*, defaults to `False`): Configure if the attentions should contain a bias parameter. + """ + + def __init__( + self, + dim: int, + num_attention_heads: int, + attention_head_dim: int, + dropout=0.0, + cross_attention_dim: Optional[int] = None, + activation_fn: str = "geglu", + num_embeds_ada_norm: Optional[int] = None, + attention_bias: bool = False, + only_cross_attention: bool = False, + double_self_attention: bool = False, + upcast_attention: bool = False, + norm_elementwise_affine: bool = True, + norm_type: str = "layer_norm", + final_dropout: bool = False, + ): + super().__init__() + self.only_cross_attention = only_cross_attention + + self.use_ada_layer_norm_zero = (num_embeds_ada_norm is not None) and norm_type == "ada_norm_zero" + self.use_ada_layer_norm = (num_embeds_ada_norm is not None) and norm_type == "ada_norm" + + if norm_type in ("ada_norm", "ada_norm_zero") and num_embeds_ada_norm is None: + raise ValueError( + f"`norm_type` is set to {norm_type}, but `num_embeds_ada_norm` is not defined. Please make sure to" + f" define `num_embeds_ada_norm` if setting `norm_type` to {norm_type}." + ) + + # Define 3 blocks. Each block has its own normalization layer. + # 1. Self-Attn + if self.use_ada_layer_norm: + self.norm1 = AdaLayerNorm(dim, num_embeds_ada_norm) + elif self.use_ada_layer_norm_zero: + self.norm1 = AdaLayerNormZero(dim, num_embeds_ada_norm) + else: + self.norm1 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + self.attn1 = Attention( + query_dim=dim, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + cross_attention_dim=cross_attention_dim if only_cross_attention else None, + upcast_attention=upcast_attention, + ) + + # 2. Cross-Attn + if cross_attention_dim is not None or double_self_attention: + # We currently only use AdaLayerNormZero for self attention where there will only be one attention block. + # I.e. the number of returned modulation chunks from AdaLayerZero would not make sense if returned during + # the second cross attention block. + self.norm2 = ( + AdaLayerNorm(dim, num_embeds_ada_norm) + if self.use_ada_layer_norm + else nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + ) + self.attn2 = Attention( + query_dim=dim, + cross_attention_dim=cross_attention_dim if not double_self_attention else None, + heads=num_attention_heads, + dim_head=attention_head_dim, + dropout=dropout, + bias=attention_bias, + upcast_attention=upcast_attention, + # scale_qk=False, # uncomment this to not to use flash attention + ) # is self-attn if encoder_hidden_states is none + else: + self.norm2 = None + self.attn2 = None + + # 3. Feed-forward + self.norm3 = nn.LayerNorm(dim, elementwise_affine=norm_elementwise_affine) + self.ff = FeedForward(dim, dropout=dropout, activation_fn=activation_fn, final_dropout=final_dropout) + + # let chunk size default to None + self._chunk_size = None + self._chunk_dim = 0 + + def set_chunk_feed_forward(self, chunk_size: Optional[int], dim: int): + # Sets chunk feed-forward + self._chunk_size = chunk_size + self._chunk_dim = dim + + def forward( + self, + hidden_states: torch.FloatTensor, + attention_mask: Optional[torch.FloatTensor] = None, + encoder_hidden_states: Optional[torch.FloatTensor] = None, + encoder_attention_mask: Optional[torch.FloatTensor] = None, + timestep: Optional[torch.LongTensor] = None, + cross_attention_kwargs: Dict[str, Any] = None, + class_labels: Optional[torch.LongTensor] = None, + ): + # Notice that normalization is always applied before the real computation in the following blocks. + # 1. Self-Attention + if self.use_ada_layer_norm: + norm_hidden_states = self.norm1(hidden_states, timestep) + elif self.use_ada_layer_norm_zero: + norm_hidden_states, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.norm1( + hidden_states, timestep, class_labels, hidden_dtype=hidden_states.dtype + ) + else: + norm_hidden_states = self.norm1(hidden_states) + + cross_attention_kwargs = cross_attention_kwargs if cross_attention_kwargs is not None else {} + + attn_output = self.attn1( + norm_hidden_states, + encoder_hidden_states=encoder_hidden_states if self.only_cross_attention else None, + attention_mask=encoder_attention_mask if self.only_cross_attention else attention_mask, + **cross_attention_kwargs, + ) + if self.use_ada_layer_norm_zero: + attn_output = gate_msa.unsqueeze(1) * attn_output + hidden_states = attn_output + hidden_states + + # 2. Cross-Attention + if self.attn2 is not None: + norm_hidden_states = ( + self.norm2(hidden_states, timestep) if self.use_ada_layer_norm else self.norm2(hidden_states) + ) + + attn_output = self.attn2( + norm_hidden_states, + encoder_hidden_states=encoder_hidden_states, + attention_mask=encoder_attention_mask, + **cross_attention_kwargs, + ) + hidden_states = attn_output + hidden_states + + # 3. Feed-forward + norm_hidden_states = self.norm3(hidden_states) + + if self.use_ada_layer_norm_zero: + norm_hidden_states = norm_hidden_states * (1 + scale_mlp[:, None]) + shift_mlp[:, None] + + if self._chunk_size is not None: + # "feed_forward_chunk_size" can be used to save memory + if norm_hidden_states.shape[self._chunk_dim] % self._chunk_size != 0: + raise ValueError( + f"`hidden_states` dimension to be chunked: {norm_hidden_states.shape[self._chunk_dim]} has to be divisible by chunk size: {self._chunk_size}. Make sure to set an appropriate `chunk_size` when calling `unet.enable_forward_chunking`." + ) + + num_chunks = norm_hidden_states.shape[self._chunk_dim] // self._chunk_size + ff_output = torch.cat( + [self.ff(hid_slice) for hid_slice in norm_hidden_states.chunk(num_chunks, dim=self._chunk_dim)], + dim=self._chunk_dim, + ) + else: + ff_output = self.ff(norm_hidden_states) + + if self.use_ada_layer_norm_zero: + ff_output = gate_mlp.unsqueeze(1) * ff_output + + hidden_states = ff_output + hidden_states + + return hidden_states diff --git a/xinference/thirdparty/matcha/models/matcha_tts.py b/xinference/thirdparty/matcha/models/matcha_tts.py new file mode 100644 index 0000000000..07f95ad2e3 --- /dev/null +++ b/xinference/thirdparty/matcha/models/matcha_tts.py @@ -0,0 +1,244 @@ +import datetime as dt +import math +import random + +import torch + +import matcha.utils.monotonic_align as monotonic_align +from matcha import utils +from matcha.models.baselightningmodule import BaseLightningClass +from matcha.models.components.flow_matching import CFM +from matcha.models.components.text_encoder import TextEncoder +from matcha.utils.model import ( + denormalize, + duration_loss, + fix_len_compatibility, + generate_path, + sequence_mask, +) + +log = utils.get_pylogger(__name__) + + +class MatchaTTS(BaseLightningClass): # 🍵 + def __init__( + self, + n_vocab, + n_spks, + spk_emb_dim, + n_feats, + encoder, + decoder, + cfm, + data_statistics, + out_size, + optimizer=None, + scheduler=None, + prior_loss=True, + use_precomputed_durations=False, + ): + super().__init__() + + self.save_hyperparameters(logger=False) + + self.n_vocab = n_vocab + self.n_spks = n_spks + self.spk_emb_dim = spk_emb_dim + self.n_feats = n_feats + self.out_size = out_size + self.prior_loss = prior_loss + self.use_precomputed_durations = use_precomputed_durations + + if n_spks > 1: + self.spk_emb = torch.nn.Embedding(n_spks, spk_emb_dim) + + self.encoder = TextEncoder( + encoder.encoder_type, + encoder.encoder_params, + encoder.duration_predictor_params, + n_vocab, + n_spks, + spk_emb_dim, + ) + + self.decoder = CFM( + in_channels=2 * encoder.encoder_params.n_feats, + out_channel=encoder.encoder_params.n_feats, + cfm_params=cfm, + decoder_params=decoder, + n_spks=n_spks, + spk_emb_dim=spk_emb_dim, + ) + + self.update_data_statistics(data_statistics) + + @torch.inference_mode() + def synthesise(self, x, x_lengths, n_timesteps, temperature=1.0, spks=None, length_scale=1.0): + """ + Generates mel-spectrogram from text. Returns: + 1. encoder outputs + 2. decoder outputs + 3. generated alignment + + Args: + x (torch.Tensor): batch of texts, converted to a tensor with phoneme embedding ids. + shape: (batch_size, max_text_length) + x_lengths (torch.Tensor): lengths of texts in batch. + shape: (batch_size,) + n_timesteps (int): number of steps to use for reverse diffusion in decoder. + temperature (float, optional): controls variance of terminal distribution. + spks (bool, optional): speaker ids. + shape: (batch_size,) + length_scale (float, optional): controls speech pace. + Increase value to slow down generated speech and vice versa. + + Returns: + dict: { + "encoder_outputs": torch.Tensor, shape: (batch_size, n_feats, max_mel_length), + # Average mel spectrogram generated by the encoder + "decoder_outputs": torch.Tensor, shape: (batch_size, n_feats, max_mel_length), + # Refined mel spectrogram improved by the CFM + "attn": torch.Tensor, shape: (batch_size, max_text_length, max_mel_length), + # Alignment map between text and mel spectrogram + "mel": torch.Tensor, shape: (batch_size, n_feats, max_mel_length), + # Denormalized mel spectrogram + "mel_lengths": torch.Tensor, shape: (batch_size,), + # Lengths of mel spectrograms + "rtf": float, + # Real-time factor + """ + # For RTF computation + t = dt.datetime.now() + + if self.n_spks > 1: + # Get speaker embedding + spks = self.spk_emb(spks.long()) + + # Get encoder_outputs `mu_x` and log-scaled token durations `logw` + mu_x, logw, x_mask = self.encoder(x, x_lengths, spks) + + w = torch.exp(logw) * x_mask + w_ceil = torch.ceil(w) * length_scale + y_lengths = torch.clamp_min(torch.sum(w_ceil, [1, 2]), 1).long() + y_max_length = y_lengths.max() + y_max_length_ = fix_len_compatibility(y_max_length) + + # Using obtained durations `w` construct alignment map `attn` + y_mask = sequence_mask(y_lengths, y_max_length_).unsqueeze(1).to(x_mask.dtype) + attn_mask = x_mask.unsqueeze(-1) * y_mask.unsqueeze(2) + attn = generate_path(w_ceil.squeeze(1), attn_mask.squeeze(1)).unsqueeze(1) + + # Align encoded text and get mu_y + mu_y = torch.matmul(attn.squeeze(1).transpose(1, 2), mu_x.transpose(1, 2)) + mu_y = mu_y.transpose(1, 2) + encoder_outputs = mu_y[:, :, :y_max_length] + + # Generate sample tracing the probability flow + decoder_outputs = self.decoder(mu_y, y_mask, n_timesteps, temperature, spks) + decoder_outputs = decoder_outputs[:, :, :y_max_length] + + t = (dt.datetime.now() - t).total_seconds() + rtf = t * 22050 / (decoder_outputs.shape[-1] * 256) + + return { + "encoder_outputs": encoder_outputs, + "decoder_outputs": decoder_outputs, + "attn": attn[:, :, :y_max_length], + "mel": denormalize(decoder_outputs, self.mel_mean, self.mel_std), + "mel_lengths": y_lengths, + "rtf": rtf, + } + + def forward(self, x, x_lengths, y, y_lengths, spks=None, out_size=None, cond=None, durations=None): + """ + Computes 3 losses: + 1. duration loss: loss between predicted token durations and those extracted by Monotinic Alignment Search (MAS). + 2. prior loss: loss between mel-spectrogram and encoder outputs. + 3. flow matching loss: loss between mel-spectrogram and decoder outputs. + + Args: + x (torch.Tensor): batch of texts, converted to a tensor with phoneme embedding ids. + shape: (batch_size, max_text_length) + x_lengths (torch.Tensor): lengths of texts in batch. + shape: (batch_size,) + y (torch.Tensor): batch of corresponding mel-spectrograms. + shape: (batch_size, n_feats, max_mel_length) + y_lengths (torch.Tensor): lengths of mel-spectrograms in batch. + shape: (batch_size,) + out_size (int, optional): length (in mel's sampling rate) of segment to cut, on which decoder will be trained. + Should be divisible by 2^{num of UNet downsamplings}. Needed to increase batch size. + spks (torch.Tensor, optional): speaker ids. + shape: (batch_size,) + """ + if self.n_spks > 1: + # Get speaker embedding + spks = self.spk_emb(spks) + + # Get encoder_outputs `mu_x` and log-scaled token durations `logw` + mu_x, logw, x_mask = self.encoder(x, x_lengths, spks) + y_max_length = y.shape[-1] + + y_mask = sequence_mask(y_lengths, y_max_length).unsqueeze(1).to(x_mask) + attn_mask = x_mask.unsqueeze(-1) * y_mask.unsqueeze(2) + + if self.use_precomputed_durations: + attn = generate_path(durations.squeeze(1), attn_mask.squeeze(1)) + else: + # Use MAS to find most likely alignment `attn` between text and mel-spectrogram + with torch.no_grad(): + const = -0.5 * math.log(2 * math.pi) * self.n_feats + factor = -0.5 * torch.ones(mu_x.shape, dtype=mu_x.dtype, device=mu_x.device) + y_square = torch.matmul(factor.transpose(1, 2), y**2) + y_mu_double = torch.matmul(2.0 * (factor * mu_x).transpose(1, 2), y) + mu_square = torch.sum(factor * (mu_x**2), 1).unsqueeze(-1) + log_prior = y_square - y_mu_double + mu_square + const + + attn = monotonic_align.maximum_path(log_prior, attn_mask.squeeze(1)) + attn = attn.detach() # b, t_text, T_mel + + # Compute loss between predicted log-scaled durations and those obtained from MAS + # refered to as prior loss in the paper + logw_ = torch.log(1e-8 + torch.sum(attn.unsqueeze(1), -1)) * x_mask + dur_loss = duration_loss(logw, logw_, x_lengths) + + # Cut a small segment of mel-spectrogram in order to increase batch size + # - "Hack" taken from Grad-TTS, in case of Grad-TTS, we cannot train batch size 32 on a 24GB GPU without it + # - Do not need this hack for Matcha-TTS, but it works with it as well + if not isinstance(out_size, type(None)): + max_offset = (y_lengths - out_size).clamp(0) + offset_ranges = list(zip([0] * max_offset.shape[0], max_offset.cpu().numpy())) + out_offset = torch.LongTensor( + [torch.tensor(random.choice(range(start, end)) if end > start else 0) for start, end in offset_ranges] + ).to(y_lengths) + attn_cut = torch.zeros(attn.shape[0], attn.shape[1], out_size, dtype=attn.dtype, device=attn.device) + y_cut = torch.zeros(y.shape[0], self.n_feats, out_size, dtype=y.dtype, device=y.device) + + y_cut_lengths = [] + for i, (y_, out_offset_) in enumerate(zip(y, out_offset)): + y_cut_length = out_size + (y_lengths[i] - out_size).clamp(None, 0) + y_cut_lengths.append(y_cut_length) + cut_lower, cut_upper = out_offset_, out_offset_ + y_cut_length + y_cut[i, :, :y_cut_length] = y_[:, cut_lower:cut_upper] + attn_cut[i, :, :y_cut_length] = attn[i, :, cut_lower:cut_upper] + + y_cut_lengths = torch.LongTensor(y_cut_lengths) + y_cut_mask = sequence_mask(y_cut_lengths).unsqueeze(1).to(y_mask) + + attn = attn_cut + y = y_cut + y_mask = y_cut_mask + + # Align encoded text with mel-spectrogram and get mu_y segment + mu_y = torch.matmul(attn.squeeze(1).transpose(1, 2), mu_x.transpose(1, 2)) + mu_y = mu_y.transpose(1, 2) + + # Compute loss of the decoder + diff_loss, _ = self.decoder.compute_loss(x1=y, mask=y_mask, mu=mu_y, spks=spks, cond=cond) + + if self.prior_loss: + prior_loss = torch.sum(0.5 * ((y - mu_y) ** 2 + math.log(2 * math.pi)) * y_mask) + prior_loss = prior_loss / (torch.sum(y_mask) * self.n_feats) + else: + prior_loss = 0 + + return dur_loss, prior_loss, diff_loss, attn diff --git a/xinference/thirdparty/matcha/onnx/__init__.py b/xinference/thirdparty/matcha/onnx/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xinference/thirdparty/matcha/onnx/export.py b/xinference/thirdparty/matcha/onnx/export.py new file mode 100644 index 0000000000..9b79508615 --- /dev/null +++ b/xinference/thirdparty/matcha/onnx/export.py @@ -0,0 +1,181 @@ +import argparse +import random +from pathlib import Path + +import numpy as np +import torch +from lightning import LightningModule + +from matcha.cli import VOCODER_URLS, load_matcha, load_vocoder + +DEFAULT_OPSET = 15 + +SEED = 1234 +random.seed(SEED) +np.random.seed(SEED) +torch.manual_seed(SEED) +torch.cuda.manual_seed(SEED) +torch.backends.cudnn.deterministic = True +torch.backends.cudnn.benchmark = False + + +class MatchaWithVocoder(LightningModule): + def __init__(self, matcha, vocoder): + super().__init__() + self.matcha = matcha + self.vocoder = vocoder + + def forward(self, x, x_lengths, scales, spks=None): + mel, mel_lengths = self.matcha(x, x_lengths, scales, spks) + wavs = self.vocoder(mel).clamp(-1, 1) + lengths = mel_lengths * 256 + return wavs.squeeze(1), lengths + + +def get_exportable_module(matcha, vocoder, n_timesteps): + """ + Return an appropriate `LighteningModule` and output-node names + based on whether the vocoder is embedded in the final graph + """ + + def onnx_forward_func(x, x_lengths, scales, spks=None): + """ + Custom forward function for accepting + scaler parameters as tensors + """ + # Extract scaler parameters from tensors + temperature = scales[0] + length_scale = scales[1] + output = matcha.synthesise(x, x_lengths, n_timesteps, temperature, spks, length_scale) + return output["mel"], output["mel_lengths"] + + # Monkey-patch Matcha's forward function + matcha.forward = onnx_forward_func + + if vocoder is None: + model, output_names = matcha, ["mel", "mel_lengths"] + else: + model = MatchaWithVocoder(matcha, vocoder) + output_names = ["wav", "wav_lengths"] + return model, output_names + + +def get_inputs(is_multi_speaker): + """ + Create dummy inputs for tracing + """ + dummy_input_length = 50 + x = torch.randint(low=0, high=20, size=(1, dummy_input_length), dtype=torch.long) + x_lengths = torch.LongTensor([dummy_input_length]) + + # Scales + temperature = 0.667 + length_scale = 1.0 + scales = torch.Tensor([temperature, length_scale]) + + model_inputs = [x, x_lengths, scales] + input_names = [ + "x", + "x_lengths", + "scales", + ] + + if is_multi_speaker: + spks = torch.LongTensor([1]) + model_inputs.append(spks) + input_names.append("spks") + + return tuple(model_inputs), input_names + + +def main(): + parser = argparse.ArgumentParser(description="Export 🍵 Matcha-TTS to ONNX") + + parser.add_argument( + "checkpoint_path", + type=str, + help="Path to the model checkpoint", + ) + parser.add_argument("output", type=str, help="Path to output `.onnx` file") + parser.add_argument( + "--n-timesteps", type=int, default=5, help="Number of steps to use for reverse diffusion in decoder (default 5)" + ) + parser.add_argument( + "--vocoder-name", + type=str, + choices=list(VOCODER_URLS.keys()), + default=None, + help="Name of the vocoder to embed in the ONNX graph", + ) + parser.add_argument( + "--vocoder-checkpoint-path", + type=str, + default=None, + help="Vocoder checkpoint to embed in the ONNX graph for an `e2e` like experience", + ) + parser.add_argument("--opset", type=int, default=DEFAULT_OPSET, help="ONNX opset version to use (default 15") + + args = parser.parse_args() + + print(f"[🍵] Loading Matcha checkpoint from {args.checkpoint_path}") + print(f"Setting n_timesteps to {args.n_timesteps}") + + checkpoint_path = Path(args.checkpoint_path) + matcha = load_matcha(checkpoint_path.stem, checkpoint_path, "cpu") + + if args.vocoder_name or args.vocoder_checkpoint_path: + assert ( + args.vocoder_name and args.vocoder_checkpoint_path + ), "Both vocoder_name and vocoder-checkpoint are required when embedding the vocoder in the ONNX graph." + vocoder, _ = load_vocoder(args.vocoder_name, args.vocoder_checkpoint_path, "cpu") + else: + vocoder = None + + is_multi_speaker = matcha.n_spks > 1 + + dummy_input, input_names = get_inputs(is_multi_speaker) + model, output_names = get_exportable_module(matcha, vocoder, args.n_timesteps) + + # Set dynamic shape for inputs/outputs + dynamic_axes = { + "x": {0: "batch_size", 1: "time"}, + "x_lengths": {0: "batch_size"}, + } + + if vocoder is None: + dynamic_axes.update( + { + "mel": {0: "batch_size", 2: "time"}, + "mel_lengths": {0: "batch_size"}, + } + ) + else: + print("Embedding the vocoder in the ONNX graph") + dynamic_axes.update( + { + "wav": {0: "batch_size", 1: "time"}, + "wav_lengths": {0: "batch_size"}, + } + ) + + if is_multi_speaker: + dynamic_axes["spks"] = {0: "batch_size"} + + # Create the output directory (if not exists) + Path(args.output).parent.mkdir(parents=True, exist_ok=True) + + model.to_onnx( + args.output, + dummy_input, + input_names=input_names, + output_names=output_names, + dynamic_axes=dynamic_axes, + opset_version=args.opset, + export_params=True, + do_constant_folding=True, + ) + print(f"[🍵] ONNX model exported to {args.output}") + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/matcha/onnx/infer.py b/xinference/thirdparty/matcha/onnx/infer.py new file mode 100644 index 0000000000..89ca92559c --- /dev/null +++ b/xinference/thirdparty/matcha/onnx/infer.py @@ -0,0 +1,168 @@ +import argparse +import os +import warnings +from pathlib import Path +from time import perf_counter + +import numpy as np +import onnxruntime as ort +import soundfile as sf +import torch + +from matcha.cli import plot_spectrogram_to_numpy, process_text + + +def validate_args(args): + assert ( + args.text or args.file + ), "Either text or file must be provided Matcha-T(ea)TTS need sometext to whisk the waveforms." + assert args.temperature >= 0, "Sampling temperature cannot be negative" + assert args.speaking_rate >= 0, "Speaking rate must be greater than 0" + return args + + +def write_wavs(model, inputs, output_dir, external_vocoder=None): + if external_vocoder is None: + print("The provided model has the vocoder embedded in the graph.\nGenerating waveform directly") + t0 = perf_counter() + wavs, wav_lengths = model.run(None, inputs) + infer_secs = perf_counter() - t0 + mel_infer_secs = vocoder_infer_secs = None + else: + print("[🍵] Generating mel using Matcha") + mel_t0 = perf_counter() + mels, mel_lengths = model.run(None, inputs) + mel_infer_secs = perf_counter() - mel_t0 + print("Generating waveform from mel using external vocoder") + vocoder_inputs = {external_vocoder.get_inputs()[0].name: mels} + vocoder_t0 = perf_counter() + wavs = external_vocoder.run(None, vocoder_inputs)[0] + vocoder_infer_secs = perf_counter() - vocoder_t0 + wavs = wavs.squeeze(1) + wav_lengths = mel_lengths * 256 + infer_secs = mel_infer_secs + vocoder_infer_secs + + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + for i, (wav, wav_length) in enumerate(zip(wavs, wav_lengths)): + output_filename = output_dir.joinpath(f"output_{i + 1}.wav") + audio = wav[:wav_length] + print(f"Writing audio to {output_filename}") + sf.write(output_filename, audio, 22050, "PCM_24") + + wav_secs = wav_lengths.sum() / 22050 + print(f"Inference seconds: {infer_secs}") + print(f"Generated wav seconds: {wav_secs}") + rtf = infer_secs / wav_secs + if mel_infer_secs is not None: + mel_rtf = mel_infer_secs / wav_secs + print(f"Matcha RTF: {mel_rtf}") + if vocoder_infer_secs is not None: + vocoder_rtf = vocoder_infer_secs / wav_secs + print(f"Vocoder RTF: {vocoder_rtf}") + print(f"Overall RTF: {rtf}") + + +def write_mels(model, inputs, output_dir): + t0 = perf_counter() + mels, mel_lengths = model.run(None, inputs) + infer_secs = perf_counter() - t0 + + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + for i, mel in enumerate(mels): + output_stem = output_dir.joinpath(f"output_{i + 1}") + plot_spectrogram_to_numpy(mel.squeeze(), output_stem.with_suffix(".png")) + np.save(output_stem.with_suffix(".numpy"), mel) + + wav_secs = (mel_lengths * 256).sum() / 22050 + print(f"Inference seconds: {infer_secs}") + print(f"Generated wav seconds: {wav_secs}") + rtf = infer_secs / wav_secs + print(f"RTF: {rtf}") + + +def main(): + parser = argparse.ArgumentParser( + description=" 🍵 Matcha-TTS: A fast TTS architecture with conditional flow matching" + ) + parser.add_argument( + "model", + type=str, + help="ONNX model to use", + ) + parser.add_argument("--vocoder", type=str, default=None, help="Vocoder to use (defaults to None)") + parser.add_argument("--text", type=str, default=None, help="Text to synthesize") + parser.add_argument("--file", type=str, default=None, help="Text file to synthesize") + parser.add_argument("--spk", type=int, default=None, help="Speaker ID") + parser.add_argument( + "--temperature", + type=float, + default=0.667, + help="Variance of the x0 noise (default: 0.667)", + ) + parser.add_argument( + "--speaking-rate", + type=float, + default=1.0, + help="change the speaking rate, a higher value means slower speaking rate (default: 1.0)", + ) + parser.add_argument("--gpu", action="store_true", help="Use CPU for inference (default: use GPU if available)") + parser.add_argument( + "--output-dir", + type=str, + default=os.getcwd(), + help="Output folder to save results (default: current dir)", + ) + + args = parser.parse_args() + args = validate_args(args) + + if args.gpu: + providers = ["GPUExecutionProvider"] + else: + providers = ["CPUExecutionProvider"] + model = ort.InferenceSession(args.model, providers=providers) + + model_inputs = model.get_inputs() + model_outputs = list(model.get_outputs()) + + if args.text: + text_lines = args.text.splitlines() + else: + with open(args.file, encoding="utf-8") as file: + text_lines = file.read().splitlines() + + processed_lines = [process_text(0, line, "cpu") for line in text_lines] + x = [line["x"].squeeze() for line in processed_lines] + # Pad + x = torch.nn.utils.rnn.pad_sequence(x, batch_first=True) + x = x.detach().cpu().numpy() + x_lengths = np.array([line["x_lengths"].item() for line in processed_lines], dtype=np.int64) + inputs = { + "x": x, + "x_lengths": x_lengths, + "scales": np.array([args.temperature, args.speaking_rate], dtype=np.float32), + } + is_multi_speaker = len(model_inputs) == 4 + if is_multi_speaker: + if args.spk is None: + args.spk = 0 + warn = "[!] Speaker ID not provided! Using speaker ID 0" + warnings.warn(warn, UserWarning) + inputs["spks"] = np.repeat(args.spk, x.shape[0]).astype(np.int64) + + has_vocoder_embedded = model_outputs[0].name == "wav" + if has_vocoder_embedded: + write_wavs(model, inputs, args.output_dir) + elif args.vocoder: + external_vocoder = ort.InferenceSession(args.vocoder, providers=providers) + write_wavs(model, inputs, args.output_dir, external_vocoder=external_vocoder) + else: + warn = "[!] A vocoder is not embedded in the graph nor an external vocoder is provided. The mel output will be written as numpy arrays to `*.npy` files in the output directory" + warnings.warn(warn, UserWarning) + write_mels(model, inputs, args.output_dir) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/matcha/text/__init__.py b/xinference/thirdparty/matcha/text/__init__.py new file mode 100644 index 0000000000..8c75d6b571 --- /dev/null +++ b/xinference/thirdparty/matcha/text/__init__.py @@ -0,0 +1,53 @@ +""" from https://github.com/keithito/tacotron """ +from matcha.text import cleaners +from matcha.text.symbols import symbols + +# Mappings from symbol to numeric ID and vice versa: +_symbol_to_id = {s: i for i, s in enumerate(symbols)} +_id_to_symbol = {i: s for i, s in enumerate(symbols)} # pylint: disable=unnecessary-comprehension + + +def text_to_sequence(text, cleaner_names): + """Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + Args: + text: string to convert to a sequence + cleaner_names: names of the cleaner functions to run the text through + Returns: + List of integers corresponding to the symbols in the text + """ + sequence = [] + + clean_text = _clean_text(text, cleaner_names) + for symbol in clean_text: + symbol_id = _symbol_to_id[symbol] + sequence += [symbol_id] + return sequence, clean_text + + +def cleaned_text_to_sequence(cleaned_text): + """Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + Args: + text: string to convert to a sequence + Returns: + List of integers corresponding to the symbols in the text + """ + sequence = [_symbol_to_id[symbol] for symbol in cleaned_text] + return sequence + + +def sequence_to_text(sequence): + """Converts a sequence of IDs back to a string""" + result = "" + for symbol_id in sequence: + s = _id_to_symbol[symbol_id] + result += s + return result + + +def _clean_text(text, cleaner_names): + for name in cleaner_names: + cleaner = getattr(cleaners, name) + if not cleaner: + raise Exception("Unknown cleaner: %s" % name) + text = cleaner(text) + return text diff --git a/xinference/thirdparty/matcha/text/cleaners.py b/xinference/thirdparty/matcha/text/cleaners.py new file mode 100644 index 0000000000..36776e3552 --- /dev/null +++ b/xinference/thirdparty/matcha/text/cleaners.py @@ -0,0 +1,121 @@ +""" from https://github.com/keithito/tacotron + +Cleaners are transformations that run over the input text at both training and eval time. + +Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners" +hyperparameter. Some cleaners are English-specific. You'll typically want to use: + 1. "english_cleaners" for English text + 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using + the Unidecode library (https://pypi.python.org/pypi/Unidecode) + 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update + the symbols in symbols.py to match your data). +""" + +import logging +import re + +import phonemizer +from unidecode import unidecode + +# To avoid excessive logging we set the log level of the phonemizer package to Critical +critical_logger = logging.getLogger("phonemizer") +critical_logger.setLevel(logging.CRITICAL) + +# Intializing the phonemizer globally significantly reduces the speed +# now the phonemizer is not initialising at every call +# Might be less flexible, but it is much-much faster +global_phonemizer = phonemizer.backend.EspeakBackend( + language="en-us", + preserve_punctuation=True, + with_stress=True, + language_switch="remove-flags", + logger=critical_logger, +) + + +# Regular expression matching whitespace: +_whitespace_re = re.compile(r"\s+") + +# List of (regular expression, replacement) pairs for abbreviations: +_abbreviations = [ + (re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1]) + for x in [ + ("mrs", "misess"), + ("mr", "mister"), + ("dr", "doctor"), + ("st", "saint"), + ("co", "company"), + ("jr", "junior"), + ("maj", "major"), + ("gen", "general"), + ("drs", "doctors"), + ("rev", "reverend"), + ("lt", "lieutenant"), + ("hon", "honorable"), + ("sgt", "sergeant"), + ("capt", "captain"), + ("esq", "esquire"), + ("ltd", "limited"), + ("col", "colonel"), + ("ft", "fort"), + ] +] + + +def expand_abbreviations(text): + for regex, replacement in _abbreviations: + text = re.sub(regex, replacement, text) + return text + + +def lowercase(text): + return text.lower() + + +def collapse_whitespace(text): + return re.sub(_whitespace_re, " ", text) + + +def convert_to_ascii(text): + return unidecode(text) + + +def basic_cleaners(text): + """Basic pipeline that lowercases and collapses whitespace without transliteration.""" + text = lowercase(text) + text = collapse_whitespace(text) + return text + + +def transliteration_cleaners(text): + """Pipeline for non-English text that transliterates to ASCII.""" + text = convert_to_ascii(text) + text = lowercase(text) + text = collapse_whitespace(text) + return text + + +def english_cleaners2(text): + """Pipeline for English text, including abbreviation expansion. + punctuation + stress""" + text = convert_to_ascii(text) + text = lowercase(text) + text = expand_abbreviations(text) + phonemes = global_phonemizer.phonemize([text], strip=True, njobs=1)[0] + phonemes = collapse_whitespace(phonemes) + return phonemes + + +# I am removing this due to incompatibility with several version of python +# However, if you want to use it, you can uncomment it +# and install piper-phonemize with the following command: +# pip install piper-phonemize + +# import piper_phonemize +# def english_cleaners_piper(text): +# """Pipeline for English text, including abbreviation expansion. + punctuation + stress""" +# text = convert_to_ascii(text) +# text = lowercase(text) +# text = expand_abbreviations(text) +# phonemes = "".join(piper_phonemize.phonemize_espeak(text=text, voice="en-US")[0]) +# phonemes = collapse_whitespace(phonemes) +# return phonemes diff --git a/xinference/thirdparty/matcha/text/numbers.py b/xinference/thirdparty/matcha/text/numbers.py new file mode 100644 index 0000000000..f99a8686dc --- /dev/null +++ b/xinference/thirdparty/matcha/text/numbers.py @@ -0,0 +1,71 @@ +""" from https://github.com/keithito/tacotron """ + +import re + +import inflect + +_inflect = inflect.engine() +_comma_number_re = re.compile(r"([0-9][0-9\,]+[0-9])") +_decimal_number_re = re.compile(r"([0-9]+\.[0-9]+)") +_pounds_re = re.compile(r"£([0-9\,]*[0-9]+)") +_dollars_re = re.compile(r"\$([0-9\.\,]*[0-9]+)") +_ordinal_re = re.compile(r"[0-9]+(st|nd|rd|th)") +_number_re = re.compile(r"[0-9]+") + + +def _remove_commas(m): + return m.group(1).replace(",", "") + + +def _expand_decimal_point(m): + return m.group(1).replace(".", " point ") + + +def _expand_dollars(m): + match = m.group(1) + parts = match.split(".") + if len(parts) > 2: + return match + " dollars" + dollars = int(parts[0]) if parts[0] else 0 + cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0 + if dollars and cents: + dollar_unit = "dollar" if dollars == 1 else "dollars" + cent_unit = "cent" if cents == 1 else "cents" + return f"{dollars} {dollar_unit}, {cents} {cent_unit}" + elif dollars: + dollar_unit = "dollar" if dollars == 1 else "dollars" + return f"{dollars} {dollar_unit}" + elif cents: + cent_unit = "cent" if cents == 1 else "cents" + return f"{cents} {cent_unit}" + else: + return "zero dollars" + + +def _expand_ordinal(m): + return _inflect.number_to_words(m.group(0)) + + +def _expand_number(m): + num = int(m.group(0)) + if num > 1000 and num < 3000: + if num == 2000: + return "two thousand" + elif num > 2000 and num < 2010: + return "two thousand " + _inflect.number_to_words(num % 100) + elif num % 100 == 0: + return _inflect.number_to_words(num // 100) + " hundred" + else: + return _inflect.number_to_words(num, andword="", zero="oh", group=2).replace(", ", " ") + else: + return _inflect.number_to_words(num, andword="") + + +def normalize_numbers(text): + text = re.sub(_comma_number_re, _remove_commas, text) + text = re.sub(_pounds_re, r"\1 pounds", text) + text = re.sub(_dollars_re, _expand_dollars, text) + text = re.sub(_decimal_number_re, _expand_decimal_point, text) + text = re.sub(_ordinal_re, _expand_ordinal, text) + text = re.sub(_number_re, _expand_number, text) + return text diff --git a/xinference/thirdparty/matcha/text/symbols.py b/xinference/thirdparty/matcha/text/symbols.py new file mode 100644 index 0000000000..7018df549a --- /dev/null +++ b/xinference/thirdparty/matcha/text/symbols.py @@ -0,0 +1,17 @@ +""" from https://github.com/keithito/tacotron + +Defines the set of symbols used in text input to the model. +""" +_pad = "_" +_punctuation = ';:,.!?¡¿—…"«»“” ' +_letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +_letters_ipa = ( + "ɑɐɒæɓʙβɔɕçɗɖðʤəɘɚɛɜɝɞɟʄɡɠɢʛɦɧħɥʜɨɪʝɭɬɫɮʟɱɯɰŋɳɲɴøɵɸθœɶʘɹɺɾɻʀʁɽʂʃʈʧʉʊʋⱱʌɣɤʍχʎʏʑʐʒʔʡʕʢǀǁǂǃˈˌːˑʼʴʰʱʲʷˠˤ˞↓↑→↗↘'̩'ᵻ" +) + + +# Export all symbols: +symbols = [_pad] + list(_punctuation) + list(_letters) + list(_letters_ipa) + +# Special symbol ids +SPACE_ID = symbols.index(" ") diff --git a/xinference/thirdparty/matcha/train.py b/xinference/thirdparty/matcha/train.py new file mode 100644 index 0000000000..d1d64c6c44 --- /dev/null +++ b/xinference/thirdparty/matcha/train.py @@ -0,0 +1,122 @@ +from typing import Any, Dict, List, Optional, Tuple + +import hydra +import lightning as L +import rootutils +from lightning import Callback, LightningDataModule, LightningModule, Trainer +from lightning.pytorch.loggers import Logger +from omegaconf import DictConfig + +from matcha import utils + +rootutils.setup_root(__file__, indicator=".project-root", pythonpath=True) +# ------------------------------------------------------------------------------------ # +# the setup_root above is equivalent to: +# - adding project root dir to PYTHONPATH +# (so you don't need to force user to install project as a package) +# (necessary before importing any local modules e.g. `from src import utils`) +# - setting up PROJECT_ROOT environment variable +# (which is used as a base for paths in "configs/paths/default.yaml") +# (this way all filepaths are the same no matter where you run the code) +# - loading environment variables from ".env" in root dir +# +# you can remove it if you: +# 1. either install project as a package or move entry files to project root dir +# 2. set `root_dir` to "." in "configs/paths/default.yaml" +# +# more info: https://github.com/ashleve/rootutils +# ------------------------------------------------------------------------------------ # + + +log = utils.get_pylogger(__name__) + + +@utils.task_wrapper +def train(cfg: DictConfig) -> Tuple[Dict[str, Any], Dict[str, Any]]: + """Trains the model. Can additionally evaluate on a testset, using best weights obtained during + training. + + This method is wrapped in optional @task_wrapper decorator, that controls the behavior during + failure. Useful for multiruns, saving info about the crash, etc. + + :param cfg: A DictConfig configuration composed by Hydra. + :return: A tuple with metrics and dict with all instantiated objects. + """ + # set seed for random number generators in pytorch, numpy and python.random + if cfg.get("seed"): + L.seed_everything(cfg.seed, workers=True) + + log.info(f"Instantiating datamodule <{cfg.data._target_}>") # pylint: disable=protected-access + datamodule: LightningDataModule = hydra.utils.instantiate(cfg.data) + + log.info(f"Instantiating model <{cfg.model._target_}>") # pylint: disable=protected-access + model: LightningModule = hydra.utils.instantiate(cfg.model) + + log.info("Instantiating callbacks...") + callbacks: List[Callback] = utils.instantiate_callbacks(cfg.get("callbacks")) + + log.info("Instantiating loggers...") + logger: List[Logger] = utils.instantiate_loggers(cfg.get("logger")) + + log.info(f"Instantiating trainer <{cfg.trainer._target_}>") # pylint: disable=protected-access + trainer: Trainer = hydra.utils.instantiate(cfg.trainer, callbacks=callbacks, logger=logger) + + object_dict = { + "cfg": cfg, + "datamodule": datamodule, + "model": model, + "callbacks": callbacks, + "logger": logger, + "trainer": trainer, + } + + if logger: + log.info("Logging hyperparameters!") + utils.log_hyperparameters(object_dict) + + if cfg.get("train"): + log.info("Starting training!") + trainer.fit(model=model, datamodule=datamodule, ckpt_path=cfg.get("ckpt_path")) + + train_metrics = trainer.callback_metrics + + if cfg.get("test"): + log.info("Starting testing!") + ckpt_path = trainer.checkpoint_callback.best_model_path + if ckpt_path == "": + log.warning("Best ckpt not found! Using current weights for testing...") + ckpt_path = None + trainer.test(model=model, datamodule=datamodule, ckpt_path=ckpt_path) + log.info(f"Best ckpt path: {ckpt_path}") + + test_metrics = trainer.callback_metrics + + # merge train and test metrics + metric_dict = {**train_metrics, **test_metrics} + + return metric_dict, object_dict + + +@hydra.main(version_base="1.3", config_path="../configs", config_name="train.yaml") +def main(cfg: DictConfig) -> Optional[float]: + """Main entry point for training. + + :param cfg: DictConfig configuration composed by Hydra. + :return: Optional[float] with optimized metric value. + """ + # apply extra utilities + # (e.g. ask for tags if none are provided in cfg, print cfg tree, etc.) + utils.extras(cfg) + + # train the model + metric_dict, _ = train(cfg) + + # safely retrieve metric value for hydra-based hyperparameter optimization + metric_value = utils.get_metric_value(metric_dict=metric_dict, metric_name=cfg.get("optimized_metric")) + + # return optimized metric + return metric_value + + +if __name__ == "__main__": + main() # pylint: disable=no-value-for-parameter diff --git a/xinference/thirdparty/matcha/utils/__init__.py b/xinference/thirdparty/matcha/utils/__init__.py new file mode 100644 index 0000000000..074db64611 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/__init__.py @@ -0,0 +1,5 @@ +from matcha.utils.instantiators import instantiate_callbacks, instantiate_loggers +from matcha.utils.logging_utils import log_hyperparameters +from matcha.utils.pylogger import get_pylogger +from matcha.utils.rich_utils import enforce_tags, print_config_tree +from matcha.utils.utils import extras, get_metric_value, task_wrapper diff --git a/xinference/thirdparty/matcha/utils/audio.py b/xinference/thirdparty/matcha/utils/audio.py new file mode 100644 index 0000000000..0bcd74df47 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/audio.py @@ -0,0 +1,82 @@ +import numpy as np +import torch +import torch.utils.data +from librosa.filters import mel as librosa_mel_fn +from scipy.io.wavfile import read + +MAX_WAV_VALUE = 32768.0 + + +def load_wav(full_path): + sampling_rate, data = read(full_path) + return data, sampling_rate + + +def dynamic_range_compression(x, C=1, clip_val=1e-5): + return np.log(np.clip(x, a_min=clip_val, a_max=None) * C) + + +def dynamic_range_decompression(x, C=1): + return np.exp(x) / C + + +def dynamic_range_compression_torch(x, C=1, clip_val=1e-5): + return torch.log(torch.clamp(x, min=clip_val) * C) + + +def dynamic_range_decompression_torch(x, C=1): + return torch.exp(x) / C + + +def spectral_normalize_torch(magnitudes): + output = dynamic_range_compression_torch(magnitudes) + return output + + +def spectral_de_normalize_torch(magnitudes): + output = dynamic_range_decompression_torch(magnitudes) + return output + + +mel_basis = {} +hann_window = {} + + +def mel_spectrogram(y, n_fft, num_mels, sampling_rate, hop_size, win_size, fmin, fmax, center=False): + if torch.min(y) < -1.0: + print("min value is ", torch.min(y)) + if torch.max(y) > 1.0: + print("max value is ", torch.max(y)) + + global mel_basis, hann_window # pylint: disable=global-statement + if f"{str(fmax)}_{str(y.device)}" not in mel_basis: + mel = librosa_mel_fn(sr=sampling_rate, n_fft=n_fft, n_mels=num_mels, fmin=fmin, fmax=fmax) + mel_basis[str(fmax) + "_" + str(y.device)] = torch.from_numpy(mel).float().to(y.device) + hann_window[str(y.device)] = torch.hann_window(win_size).to(y.device) + + y = torch.nn.functional.pad( + y.unsqueeze(1), (int((n_fft - hop_size) / 2), int((n_fft - hop_size) / 2)), mode="reflect" + ) + y = y.squeeze(1) + + spec = torch.view_as_real( + torch.stft( + y, + n_fft, + hop_length=hop_size, + win_length=win_size, + window=hann_window[str(y.device)], + center=center, + pad_mode="reflect", + normalized=False, + onesided=True, + return_complex=True, + ) + ) + + spec = torch.sqrt(spec.pow(2).sum(-1) + (1e-9)) + + spec = torch.matmul(mel_basis[str(fmax) + "_" + str(y.device)], spec) + spec = spectral_normalize_torch(spec) + + return spec diff --git a/xinference/thirdparty/matcha/utils/generate_data_statistics.py b/xinference/thirdparty/matcha/utils/generate_data_statistics.py new file mode 100644 index 0000000000..49ed3c1b07 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/generate_data_statistics.py @@ -0,0 +1,112 @@ +r""" +The file creates a pickle file where the values needed for loading of dataset is stored and the model can load it +when needed. + +Parameters from hparam.py will be used +""" +import argparse +import json +import os +import sys +from pathlib import Path + +import rootutils +import torch +from hydra import compose, initialize +from omegaconf import open_dict +from tqdm.auto import tqdm + +from matcha.data.text_mel_datamodule import TextMelDataModule +from matcha.utils.logging_utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +def compute_data_statistics(data_loader: torch.utils.data.DataLoader, out_channels: int): + """Generate data mean and standard deviation helpful in data normalisation + + Args: + data_loader (torch.utils.data.Dataloader): _description_ + out_channels (int): mel spectrogram channels + """ + total_mel_sum = 0 + total_mel_sq_sum = 0 + total_mel_len = 0 + + for batch in tqdm(data_loader, leave=False): + mels = batch["y"] + mel_lengths = batch["y_lengths"] + + total_mel_len += torch.sum(mel_lengths) + total_mel_sum += torch.sum(mels) + total_mel_sq_sum += torch.sum(torch.pow(mels, 2)) + + data_mean = total_mel_sum / (total_mel_len * out_channels) + data_std = torch.sqrt((total_mel_sq_sum / (total_mel_len * out_channels)) - torch.pow(data_mean, 2)) + + return {"mel_mean": data_mean.item(), "mel_std": data_std.item()} + + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument( + "-i", + "--input-config", + type=str, + default="vctk.yaml", + help="The name of the yaml config file under configs/data", + ) + + parser.add_argument( + "-b", + "--batch-size", + type=int, + default="256", + help="Can have increased batch size for faster computation", + ) + + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + required=False, + help="force overwrite the file", + ) + args = parser.parse_args() + output_file = Path(args.input_config).with_suffix(".json") + + if os.path.exists(output_file) and not args.force: + print("File already exists. Use -f to force overwrite") + sys.exit(1) + + with initialize(version_base="1.3", config_path="../../configs/data"): + cfg = compose(config_name=args.input_config, return_hydra_config=True, overrides=[]) + + root_path = rootutils.find_root(search_from=__file__, indicator=".project-root") + + with open_dict(cfg): + del cfg["hydra"] + del cfg["_target_"] + cfg["data_statistics"] = None + cfg["seed"] = 1234 + cfg["batch_size"] = args.batch_size + cfg["train_filelist_path"] = str(os.path.join(root_path, cfg["train_filelist_path"])) + cfg["valid_filelist_path"] = str(os.path.join(root_path, cfg["valid_filelist_path"])) + cfg["load_durations"] = False + + text_mel_datamodule = TextMelDataModule(**cfg) + text_mel_datamodule.setup() + data_loader = text_mel_datamodule.train_dataloader() + log.info("Dataloader loaded! Now computing stats...") + params = compute_data_statistics(data_loader, cfg["n_feats"]) + print(params) + json.dump( + params, + open(output_file, "w"), + ) + + +if __name__ == "__main__": + main() diff --git a/xinference/thirdparty/matcha/utils/get_durations_from_trained_model.py b/xinference/thirdparty/matcha/utils/get_durations_from_trained_model.py new file mode 100644 index 0000000000..0fe2f35c42 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/get_durations_from_trained_model.py @@ -0,0 +1,195 @@ +r""" +The file creates a pickle file where the values needed for loading of dataset is stored and the model can load it +when needed. + +Parameters from hparam.py will be used +""" +import argparse +import json +import os +import sys +from pathlib import Path + +import lightning +import numpy as np +import rootutils +import torch +from hydra import compose, initialize +from omegaconf import open_dict +from torch import nn +from tqdm.auto import tqdm + +from matcha.cli import get_device +from matcha.data.text_mel_datamodule import TextMelDataModule +from matcha.models.matcha_tts import MatchaTTS +from matcha.utils.logging_utils import pylogger +from matcha.utils.utils import get_phoneme_durations + +log = pylogger.get_pylogger(__name__) + + +def save_durations_to_folder( + attn: torch.Tensor, x_length: int, y_length: int, filepath: str, output_folder: Path, text: str +): + durations = attn.squeeze().sum(1)[:x_length].numpy() + durations_json = get_phoneme_durations(durations, text) + output = output_folder / Path(filepath).name.replace(".wav", ".npy") + with open(output.with_suffix(".json"), "w", encoding="utf-8") as f: + json.dump(durations_json, f, indent=4, ensure_ascii=False) + + np.save(output, durations) + + +@torch.inference_mode() +def compute_durations(data_loader: torch.utils.data.DataLoader, model: nn.Module, device: torch.device, output_folder): + """Generate durations from the model for each datapoint and save it in a folder + + Args: + data_loader (torch.utils.data.DataLoader): Dataloader + model (nn.Module): MatchaTTS model + device (torch.device): GPU or CPU + """ + + for batch in tqdm(data_loader, desc="🍵 Computing durations 🍵:"): + x, x_lengths = batch["x"], batch["x_lengths"] + y, y_lengths = batch["y"], batch["y_lengths"] + spks = batch["spks"] + x = x.to(device) + y = y.to(device) + x_lengths = x_lengths.to(device) + y_lengths = y_lengths.to(device) + spks = spks.to(device) if spks is not None else None + + _, _, _, attn = model( + x=x, + x_lengths=x_lengths, + y=y, + y_lengths=y_lengths, + spks=spks, + ) + attn = attn.cpu() + for i in range(attn.shape[0]): + save_durations_to_folder( + attn[i], + x_lengths[i].item(), + y_lengths[i].item(), + batch["filepaths"][i], + output_folder, + batch["x_texts"][i], + ) + + +def main(): + parser = argparse.ArgumentParser() + + parser.add_argument( + "-i", + "--input-config", + type=str, + default="ljspeech.yaml", + help="The name of the yaml config file under configs/data", + ) + + parser.add_argument( + "-b", + "--batch-size", + type=int, + default="32", + help="Can have increased batch size for faster computation", + ) + + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + required=False, + help="force overwrite the file", + ) + parser.add_argument( + "-c", + "--checkpoint_path", + type=str, + required=True, + help="Path to the checkpoint file to load the model from", + ) + + parser.add_argument( + "-o", + "--output-folder", + type=str, + default=None, + help="Output folder to save the data statistics", + ) + + parser.add_argument( + "--cpu", action="store_true", help="Use CPU for inference, not recommended (default: use GPU if available)" + ) + + args = parser.parse_args() + + with initialize(version_base="1.3", config_path="../../configs/data"): + cfg = compose(config_name=args.input_config, return_hydra_config=True, overrides=[]) + + root_path = rootutils.find_root(search_from=__file__, indicator=".project-root") + + with open_dict(cfg): + del cfg["hydra"] + del cfg["_target_"] + cfg["seed"] = 1234 + cfg["batch_size"] = args.batch_size + cfg["train_filelist_path"] = str(os.path.join(root_path, cfg["train_filelist_path"])) + cfg["valid_filelist_path"] = str(os.path.join(root_path, cfg["valid_filelist_path"])) + cfg["load_durations"] = False + + if args.output_folder is not None: + output_folder = Path(args.output_folder) + else: + output_folder = Path(cfg["train_filelist_path"]).parent / "durations" + + print(f"Output folder set to: {output_folder}") + + if os.path.exists(output_folder) and not args.force: + print("Folder already exists. Use -f to force overwrite") + sys.exit(1) + + output_folder.mkdir(parents=True, exist_ok=True) + + print(f"Preprocessing: {cfg['name']} from training filelist: {cfg['train_filelist_path']}") + print("Loading model...") + device = get_device(args) + model = MatchaTTS.load_from_checkpoint(args.checkpoint_path, map_location=device) + + text_mel_datamodule = TextMelDataModule(**cfg) + text_mel_datamodule.setup() + try: + print("Computing stats for training set if exists...") + train_dataloader = text_mel_datamodule.train_dataloader() + compute_durations(train_dataloader, model, device, output_folder) + except lightning.fabric.utilities.exceptions.MisconfigurationException: + print("No training set found") + + try: + print("Computing stats for validation set if exists...") + val_dataloader = text_mel_datamodule.val_dataloader() + compute_durations(val_dataloader, model, device, output_folder) + except lightning.fabric.utilities.exceptions.MisconfigurationException: + print("No validation set found") + + try: + print("Computing stats for test set if exists...") + test_dataloader = text_mel_datamodule.test_dataloader() + compute_durations(test_dataloader, model, device, output_folder) + except lightning.fabric.utilities.exceptions.MisconfigurationException: + print("No test set found") + + print(f"[+] Done! Data statistics saved to: {output_folder}") + + +if __name__ == "__main__": + # Helps with generating durations for the dataset to train other architectures + # that cannot learn to align due to limited size of dataset + # Example usage: + # python python matcha/utils/get_durations_from_trained_model.py -i ljspeech.yaml -c pretrained_model + # This will create a folder in data/processed_data/durations/ljspeech with the durations + main() diff --git a/xinference/thirdparty/matcha/utils/instantiators.py b/xinference/thirdparty/matcha/utils/instantiators.py new file mode 100644 index 0000000000..5547b4ed61 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/instantiators.py @@ -0,0 +1,56 @@ +from typing import List + +import hydra +from lightning import Callback +from lightning.pytorch.loggers import Logger +from omegaconf import DictConfig + +from matcha.utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +def instantiate_callbacks(callbacks_cfg: DictConfig) -> List[Callback]: + """Instantiates callbacks from config. + + :param callbacks_cfg: A DictConfig object containing callback configurations. + :return: A list of instantiated callbacks. + """ + callbacks: List[Callback] = [] + + if not callbacks_cfg: + log.warning("No callback configs found! Skipping..") + return callbacks + + if not isinstance(callbacks_cfg, DictConfig): + raise TypeError("Callbacks config must be a DictConfig!") + + for _, cb_conf in callbacks_cfg.items(): + if isinstance(cb_conf, DictConfig) and "_target_" in cb_conf: + log.info(f"Instantiating callback <{cb_conf._target_}>") # pylint: disable=protected-access + callbacks.append(hydra.utils.instantiate(cb_conf)) + + return callbacks + + +def instantiate_loggers(logger_cfg: DictConfig) -> List[Logger]: + """Instantiates loggers from config. + + :param logger_cfg: A DictConfig object containing logger configurations. + :return: A list of instantiated loggers. + """ + logger: List[Logger] = [] + + if not logger_cfg: + log.warning("No logger configs found! Skipping...") + return logger + + if not isinstance(logger_cfg, DictConfig): + raise TypeError("Logger config must be a DictConfig!") + + for _, lg_conf in logger_cfg.items(): + if isinstance(lg_conf, DictConfig) and "_target_" in lg_conf: + log.info(f"Instantiating logger <{lg_conf._target_}>") # pylint: disable=protected-access + logger.append(hydra.utils.instantiate(lg_conf)) + + return logger diff --git a/xinference/thirdparty/matcha/utils/logging_utils.py b/xinference/thirdparty/matcha/utils/logging_utils.py new file mode 100644 index 0000000000..1a12d1ddaf --- /dev/null +++ b/xinference/thirdparty/matcha/utils/logging_utils.py @@ -0,0 +1,53 @@ +from typing import Any, Dict + +from lightning.pytorch.utilities import rank_zero_only +from omegaconf import OmegaConf + +from matcha.utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +@rank_zero_only +def log_hyperparameters(object_dict: Dict[str, Any]) -> None: + """Controls which config parts are saved by Lightning loggers. + + Additionally saves: + - Number of model parameters + + :param object_dict: A dictionary containing the following objects: + - `"cfg"`: A DictConfig object containing the main config. + - `"model"`: The Lightning model. + - `"trainer"`: The Lightning trainer. + """ + hparams = {} + + cfg = OmegaConf.to_container(object_dict["cfg"]) + model = object_dict["model"] + trainer = object_dict["trainer"] + + if not trainer.logger: + log.warning("Logger not found! Skipping hyperparameter logging...") + return + + hparams["model"] = cfg["model"] + + # save number of model parameters + hparams["model/params/total"] = sum(p.numel() for p in model.parameters()) + hparams["model/params/trainable"] = sum(p.numel() for p in model.parameters() if p.requires_grad) + hparams["model/params/non_trainable"] = sum(p.numel() for p in model.parameters() if not p.requires_grad) + + hparams["data"] = cfg["data"] + hparams["trainer"] = cfg["trainer"] + + hparams["callbacks"] = cfg.get("callbacks") + hparams["extras"] = cfg.get("extras") + + hparams["task_name"] = cfg.get("task_name") + hparams["tags"] = cfg.get("tags") + hparams["ckpt_path"] = cfg.get("ckpt_path") + hparams["seed"] = cfg.get("seed") + + # send hparams to all loggers + for logger in trainer.loggers: + logger.log_hyperparams(hparams) diff --git a/xinference/thirdparty/matcha/utils/model.py b/xinference/thirdparty/matcha/utils/model.py new file mode 100644 index 0000000000..869cc6092f --- /dev/null +++ b/xinference/thirdparty/matcha/utils/model.py @@ -0,0 +1,90 @@ +""" from https://github.com/jaywalnut310/glow-tts """ + +import numpy as np +import torch + + +def sequence_mask(length, max_length=None): + if max_length is None: + max_length = length.max() + x = torch.arange(max_length, dtype=length.dtype, device=length.device) + return x.unsqueeze(0) < length.unsqueeze(1) + + +def fix_len_compatibility(length, num_downsamplings_in_unet=2): + factor = torch.scalar_tensor(2).pow(num_downsamplings_in_unet) + length = (length / factor).ceil() * factor + if not torch.onnx.is_in_onnx_export(): + return length.int().item() + else: + return length + + +def convert_pad_shape(pad_shape): + inverted_shape = pad_shape[::-1] + pad_shape = [item for sublist in inverted_shape for item in sublist] + return pad_shape + + +def generate_path(duration, mask): + device = duration.device + + b, t_x, t_y = mask.shape + cum_duration = torch.cumsum(duration, 1) + path = torch.zeros(b, t_x, t_y, dtype=mask.dtype).to(device=device) + + cum_duration_flat = cum_duration.view(b * t_x) + path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype) + path = path.view(b, t_x, t_y) + path = path - torch.nn.functional.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1] + path = path * mask + return path + + +def duration_loss(logw, logw_, lengths): + loss = torch.sum((logw - logw_) ** 2) / torch.sum(lengths) + return loss + + +def normalize(data, mu, std): + if not isinstance(mu, (float, int)): + if isinstance(mu, list): + mu = torch.tensor(mu, dtype=data.dtype, device=data.device) + elif isinstance(mu, torch.Tensor): + mu = mu.to(data.device) + elif isinstance(mu, np.ndarray): + mu = torch.from_numpy(mu).to(data.device) + mu = mu.unsqueeze(-1) + + if not isinstance(std, (float, int)): + if isinstance(std, list): + std = torch.tensor(std, dtype=data.dtype, device=data.device) + elif isinstance(std, torch.Tensor): + std = std.to(data.device) + elif isinstance(std, np.ndarray): + std = torch.from_numpy(std).to(data.device) + std = std.unsqueeze(-1) + + return (data - mu) / std + + +def denormalize(data, mu, std): + if not isinstance(mu, float): + if isinstance(mu, list): + mu = torch.tensor(mu, dtype=data.dtype, device=data.device) + elif isinstance(mu, torch.Tensor): + mu = mu.to(data.device) + elif isinstance(mu, np.ndarray): + mu = torch.from_numpy(mu).to(data.device) + mu = mu.unsqueeze(-1) + + if not isinstance(std, float): + if isinstance(std, list): + std = torch.tensor(std, dtype=data.dtype, device=data.device) + elif isinstance(std, torch.Tensor): + std = std.to(data.device) + elif isinstance(std, np.ndarray): + std = torch.from_numpy(std).to(data.device) + std = std.unsqueeze(-1) + + return data * std + mu diff --git a/xinference/thirdparty/matcha/utils/monotonic_align/__init__.py b/xinference/thirdparty/matcha/utils/monotonic_align/__init__.py new file mode 100644 index 0000000000..eee6e0d47c --- /dev/null +++ b/xinference/thirdparty/matcha/utils/monotonic_align/__init__.py @@ -0,0 +1,22 @@ +import numpy as np +import torch + +from matcha.utils.monotonic_align.core import maximum_path_c + + +def maximum_path(value, mask): + """Cython optimised version. + value: [b, t_x, t_y] + mask: [b, t_x, t_y] + """ + value = value * mask + device = value.device + dtype = value.dtype + value = value.data.cpu().numpy().astype(np.float32) + path = np.zeros_like(value).astype(np.int32) + mask = mask.data.cpu().numpy() + + t_x_max = mask.sum(1)[:, 0].astype(np.int32) + t_y_max = mask.sum(2)[:, 0].astype(np.int32) + maximum_path_c(path, value, t_x_max, t_y_max) + return torch.from_numpy(path).to(device=device, dtype=dtype) diff --git a/xinference/thirdparty/matcha/utils/monotonic_align/core.pyx b/xinference/thirdparty/matcha/utils/monotonic_align/core.pyx new file mode 100644 index 0000000000..091fcc3a50 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/monotonic_align/core.pyx @@ -0,0 +1,47 @@ +import numpy as np + +cimport cython +cimport numpy as np + +from cython.parallel import prange + + +@cython.boundscheck(False) +@cython.wraparound(False) +cdef void maximum_path_each(int[:,::1] path, float[:,::1] value, int t_x, int t_y, float max_neg_val) nogil: + cdef int x + cdef int y + cdef float v_prev + cdef float v_cur + cdef float tmp + cdef int index = t_x - 1 + + for y in range(t_y): + for x in range(max(0, t_x + y - t_y), min(t_x, y + 1)): + if x == y: + v_cur = max_neg_val + else: + v_cur = value[x, y-1] + if x == 0: + if y == 0: + v_prev = 0. + else: + v_prev = max_neg_val + else: + v_prev = value[x-1, y-1] + value[x, y] = max(v_cur, v_prev) + value[x, y] + + for y in range(t_y - 1, -1, -1): + path[index, y] = 1 + if index != 0 and (index == y or value[index, y-1] < value[index-1, y-1]): + index = index - 1 + + +@cython.boundscheck(False) +@cython.wraparound(False) +cpdef void maximum_path_c(int[:,:,::1] paths, float[:,:,::1] values, int[::1] t_xs, int[::1] t_ys, float max_neg_val=-1e9) nogil: + cdef int b = values.shape[0] + + cdef int i + for i in prange(b, nogil=True): + maximum_path_each(paths[i], values[i], t_xs[i], t_ys[i], max_neg_val) diff --git a/xinference/thirdparty/matcha/utils/monotonic_align/setup.py b/xinference/thirdparty/matcha/utils/monotonic_align/setup.py new file mode 100644 index 0000000000..f22bc6a35a --- /dev/null +++ b/xinference/thirdparty/matcha/utils/monotonic_align/setup.py @@ -0,0 +1,7 @@ +# from distutils.core import setup +# from Cython.Build import cythonize +# import numpy + +# setup(name='monotonic_align', +# ext_modules=cythonize("core.pyx"), +# include_dirs=[numpy.get_include()]) diff --git a/xinference/thirdparty/matcha/utils/pylogger.py b/xinference/thirdparty/matcha/utils/pylogger.py new file mode 100644 index 0000000000..6160067802 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/pylogger.py @@ -0,0 +1,21 @@ +import logging + +from lightning.pytorch.utilities import rank_zero_only + + +def get_pylogger(name: str = __name__) -> logging.Logger: + """Initializes a multi-GPU-friendly python command line logger. + + :param name: The name of the logger, defaults to ``__name__``. + + :return: A logger object. + """ + logger = logging.getLogger(name) + + # this ensures all logging levels get marked with the rank zero decorator + # otherwise logs would get multiplied for each GPU process in multi-GPU setup + logging_levels = ("debug", "info", "warning", "error", "exception", "fatal", "critical") + for level in logging_levels: + setattr(logger, level, rank_zero_only(getattr(logger, level))) + + return logger diff --git a/xinference/thirdparty/matcha/utils/rich_utils.py b/xinference/thirdparty/matcha/utils/rich_utils.py new file mode 100644 index 0000000000..f602f6e935 --- /dev/null +++ b/xinference/thirdparty/matcha/utils/rich_utils.py @@ -0,0 +1,101 @@ +from pathlib import Path +from typing import Sequence + +import rich +import rich.syntax +import rich.tree +from hydra.core.hydra_config import HydraConfig +from lightning.pytorch.utilities import rank_zero_only +from omegaconf import DictConfig, OmegaConf, open_dict +from rich.prompt import Prompt + +from matcha.utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +@rank_zero_only +def print_config_tree( + cfg: DictConfig, + print_order: Sequence[str] = ( + "data", + "model", + "callbacks", + "logger", + "trainer", + "paths", + "extras", + ), + resolve: bool = False, + save_to_file: bool = False, +) -> None: + """Prints the contents of a DictConfig as a tree structure using the Rich library. + + :param cfg: A DictConfig composed by Hydra. + :param print_order: Determines in what order config components are printed. Default is ``("data", "model", + "callbacks", "logger", "trainer", "paths", "extras")``. + :param resolve: Whether to resolve reference fields of DictConfig. Default is ``False``. + :param save_to_file: Whether to export config to the hydra output folder. Default is ``False``. + """ + style = "dim" + tree = rich.tree.Tree("CONFIG", style=style, guide_style=style) + + queue = [] + + # add fields from `print_order` to queue + for field in print_order: + _ = ( + queue.append(field) + if field in cfg + else log.warning(f"Field '{field}' not found in config. Skipping '{field}' config printing...") + ) + + # add all the other fields to queue (not specified in `print_order`) + for field in cfg: + if field not in queue: + queue.append(field) + + # generate config tree from queue + for field in queue: + branch = tree.add(field, style=style, guide_style=style) + + config_group = cfg[field] + if isinstance(config_group, DictConfig): + branch_content = OmegaConf.to_yaml(config_group, resolve=resolve) + else: + branch_content = str(config_group) + + branch.add(rich.syntax.Syntax(branch_content, "yaml")) + + # print config tree + rich.print(tree) + + # save config tree to file + if save_to_file: + with open(Path(cfg.paths.output_dir, "config_tree.log"), "w") as file: + rich.print(tree, file=file) + + +@rank_zero_only +def enforce_tags(cfg: DictConfig, save_to_file: bool = False) -> None: + """Prompts user to input tags from command line if no tags are provided in config. + + :param cfg: A DictConfig composed by Hydra. + :param save_to_file: Whether to export tags to the hydra output folder. Default is ``False``. + """ + if not cfg.get("tags"): + if "id" in HydraConfig().cfg.hydra.job: + raise ValueError("Specify tags before launching a multirun!") + + log.warning("No tags provided in config. Prompting user to input tags...") + tags = Prompt.ask("Enter a list of comma separated tags", default="dev") + tags = [t.strip() for t in tags.split(",") if t != ""] + + with open_dict(cfg): + cfg.tags = tags + + log.info(f"Tags: {cfg.tags}") + + if save_to_file: + with open(Path(cfg.paths.output_dir, "tags.log"), "w") as file: + rich.print(cfg.tags, file=file) diff --git a/xinference/thirdparty/matcha/utils/utils.py b/xinference/thirdparty/matcha/utils/utils.py new file mode 100644 index 0000000000..fc3a48ec2b --- /dev/null +++ b/xinference/thirdparty/matcha/utils/utils.py @@ -0,0 +1,259 @@ +import os +import sys +import warnings +from importlib.util import find_spec +from math import ceil +from pathlib import Path +from typing import Any, Callable, Dict, Tuple + +import gdown +import matplotlib.pyplot as plt +import numpy as np +import torch +import wget +from omegaconf import DictConfig + +from matcha.utils import pylogger, rich_utils + +log = pylogger.get_pylogger(__name__) + + +def extras(cfg: DictConfig) -> None: + """Applies optional utilities before the task is started. + + Utilities: + - Ignoring python warnings + - Setting tags from command line + - Rich config printing + + :param cfg: A DictConfig object containing the config tree. + """ + # return if no `extras` config + if not cfg.get("extras"): + log.warning("Extras config not found! ") + return + + # disable python warnings + if cfg.extras.get("ignore_warnings"): + log.info("Disabling python warnings! ") + warnings.filterwarnings("ignore") + + # prompt user to input tags from command line if none are provided in the config + if cfg.extras.get("enforce_tags"): + log.info("Enforcing tags! ") + rich_utils.enforce_tags(cfg, save_to_file=True) + + # pretty print config tree using Rich library + if cfg.extras.get("print_config"): + log.info("Printing config tree with Rich! ") + rich_utils.print_config_tree(cfg, resolve=True, save_to_file=True) + + +def task_wrapper(task_func: Callable) -> Callable: + """Optional decorator that controls the failure behavior when executing the task function. + + This wrapper can be used to: + - make sure loggers are closed even if the task function raises an exception (prevents multirun failure) + - save the exception to a `.log` file + - mark the run as failed with a dedicated file in the `logs/` folder (so we can find and rerun it later) + - etc. (adjust depending on your needs) + + Example: + ``` + @utils.task_wrapper + def train(cfg: DictConfig) -> Tuple[Dict[str, Any], Dict[str, Any]]: + ... + return metric_dict, object_dict + ``` + + :param task_func: The task function to be wrapped. + + :return: The wrapped task function. + """ + + def wrap(cfg: DictConfig) -> Tuple[Dict[str, Any], Dict[str, Any]]: + # execute the task + try: + metric_dict, object_dict = task_func(cfg=cfg) + + # things to do if exception occurs + except Exception as ex: + # save exception to `.log` file + log.exception("") + + # some hyperparameter combinations might be invalid or cause out-of-memory errors + # so when using hparam search plugins like Optuna, you might want to disable + # raising the below exception to avoid multirun failure + raise ex + + # things to always do after either success or exception + finally: + # display output dir path in terminal + log.info(f"Output dir: {cfg.paths.output_dir}") + + # always close wandb run (even if exception occurs so multirun won't fail) + if find_spec("wandb"): # check if wandb is installed + import wandb + + if wandb.run: + log.info("Closing wandb!") + wandb.finish() + + return metric_dict, object_dict + + return wrap + + +def get_metric_value(metric_dict: Dict[str, Any], metric_name: str) -> float: + """Safely retrieves value of the metric logged in LightningModule. + + :param metric_dict: A dict containing metric values. + :param metric_name: The name of the metric to retrieve. + :return: The value of the metric. + """ + if not metric_name: + log.info("Metric name is None! Skipping metric value retrieval...") + return None + + if metric_name not in metric_dict: + raise ValueError( + f"Metric value not found! \n" + "Make sure metric name logged in LightningModule is correct!\n" + "Make sure `optimized_metric` name in `hparams_search` config is correct!" + ) + + metric_value = metric_dict[metric_name].item() + log.info(f"Retrieved metric value! <{metric_name}={metric_value}>") + + return metric_value + + +def intersperse(lst, item): + # Adds blank symbol + result = [item] * (len(lst) * 2 + 1) + result[1::2] = lst + return result + + +def save_figure_to_numpy(fig): + data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep="") + data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + return data + + +def plot_tensor(tensor): + plt.style.use("default") + fig, ax = plt.subplots(figsize=(12, 3)) + im = ax.imshow(tensor, aspect="auto", origin="lower", interpolation="none") + plt.colorbar(im, ax=ax) + plt.tight_layout() + fig.canvas.draw() + data = save_figure_to_numpy(fig) + plt.close() + return data + + +def save_plot(tensor, savepath): + plt.style.use("default") + fig, ax = plt.subplots(figsize=(12, 3)) + im = ax.imshow(tensor, aspect="auto", origin="lower", interpolation="none") + plt.colorbar(im, ax=ax) + plt.tight_layout() + fig.canvas.draw() + plt.savefig(savepath) + plt.close() + + +def to_numpy(tensor): + if isinstance(tensor, np.ndarray): + return tensor + elif isinstance(tensor, torch.Tensor): + return tensor.detach().cpu().numpy() + elif isinstance(tensor, list): + return np.array(tensor) + else: + raise TypeError("Unsupported type for conversion to numpy array") + + +def get_user_data_dir(appname="matcha_tts"): + """ + Args: + appname (str): Name of application + + Returns: + Path: path to user data directory + """ + + MATCHA_HOME = os.environ.get("MATCHA_HOME") + if MATCHA_HOME is not None: + ans = Path(MATCHA_HOME).expanduser().resolve(strict=False) + elif sys.platform == "win32": + import winreg # pylint: disable=import-outside-toplevel + + key = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", + ) + dir_, _ = winreg.QueryValueEx(key, "Local AppData") + ans = Path(dir_).resolve(strict=False) + elif sys.platform == "darwin": + ans = Path("~/Library/Application Support/").expanduser() + else: + ans = Path.home().joinpath(".local/share") + + final_path = ans.joinpath(appname) + final_path.mkdir(parents=True, exist_ok=True) + return final_path + + +def assert_model_downloaded(checkpoint_path, url, use_wget=True): + if Path(checkpoint_path).exists(): + log.debug(f"[+] Model already present at {checkpoint_path}!") + print(f"[+] Model already present at {checkpoint_path}!") + return + log.info(f"[-] Model not found at {checkpoint_path}! Will download it") + print(f"[-] Model not found at {checkpoint_path}! Will download it") + checkpoint_path = str(checkpoint_path) + if not use_wget: + gdown.download(url=url, output=checkpoint_path, quiet=False, fuzzy=True) + else: + wget.download(url=url, out=checkpoint_path) + + +def get_phoneme_durations(durations, phones): + prev = durations[0] + merged_durations = [] + # Convolve with stride 2 + for i in range(1, len(durations), 2): + if i == len(durations) - 2: + # if it is last take full value + next_half = durations[i + 1] + else: + next_half = ceil(durations[i + 1] / 2) + + curr = prev + durations[i] + next_half + prev = durations[i + 1] - next_half + merged_durations.append(curr) + + assert len(phones) == len(merged_durations) + assert len(merged_durations) == (len(durations) - 1) // 2 + + merged_durations = torch.cumsum(torch.tensor(merged_durations), 0, dtype=torch.long) + start = torch.tensor(0) + duration_json = [] + for i, duration in enumerate(merged_durations): + duration_json.append( + { + phones[i]: { + "starttime": start.item(), + "endtime": duration.item(), + "duration": duration.item() - start.item(), + } + } + ) + start = duration + + assert list(duration_json[-1].values())[0]["endtime"] == sum( + durations + ), f"{list(duration_json[-1].values())[0]['endtime'], sum(durations)}" + return duration_json diff --git a/xinference/thirdparty/omnilmm/chat.py b/xinference/thirdparty/omnilmm/chat.py index 3067ee4750..1505debaf5 100644 --- a/xinference/thirdparty/omnilmm/chat.py +++ b/xinference/thirdparty/omnilmm/chat.py @@ -4,15 +4,9 @@ import os import torch -from accelerate import init_empty_weights, load_checkpoint_and_dispatch from PIL import Image from transformers import AutoModel, AutoTokenizer -from .model.omnilmm import OmniLMMForCausalLM -from .model.utils import build_transform -from .train.train_utils import omni_preprocess -from .utils import disable_torch_init - DEFAULT_IMAGE_TOKEN = "" DEFAULT_IMAGE_PATCH_TOKEN = "" DEFAULT_IM_START_TOKEN = "" @@ -20,6 +14,12 @@ def init_omni_lmm(model_path, device_map): + from accelerate import init_empty_weights, load_checkpoint_and_dispatch + + from .model.omnilmm import OmniLMMForCausalLM + from .model.utils import build_transform + from .utils import disable_torch_init + torch.backends.cuda.matmul.allow_tf32 = True disable_torch_init() model_name = os.path.expanduser(model_path) @@ -97,6 +97,8 @@ def expand_question_into_multimodal( def wrap_question_for_omni_lmm(question, image_token_len, tokenizer): + from .train.train_utils import omni_preprocess + question = expand_question_into_multimodal( question, image_token_len, diff --git a/xinference/thirdparty/omnilmm/model/omnilmm.py b/xinference/thirdparty/omnilmm/model/omnilmm.py index cc54dc4f67..fa1bc8a1c5 100644 --- a/xinference/thirdparty/omnilmm/model/omnilmm.py +++ b/xinference/thirdparty/omnilmm/model/omnilmm.py @@ -2,7 +2,6 @@ import math from typing import List, Optional, Tuple, Union -import timm import torch import torch.nn as nn from torch import Tensor @@ -37,6 +36,8 @@ def forward(self, input: Tensor, **kwargs) -> Tensor: def create_vision_module(config): + import timm + vision_tower = timm.create_model( "eva02_enormous_patch14_clip_224.laion2b_plus", pretrained=False, diff --git a/xinference/thirdparty/omnilmm/model/utils.py b/xinference/thirdparty/omnilmm/model/utils.py index 9ec21a78f0..0df82e69d4 100644 --- a/xinference/thirdparty/omnilmm/model/utils.py +++ b/xinference/thirdparty/omnilmm/model/utils.py @@ -3,7 +3,6 @@ import pickle from io import BytesIO -import cv2 import numpy as np import torch import torch.distributed as dist @@ -75,6 +74,8 @@ def autocontrast_func(img, cutoff=0): """ same output as PIL.ImageOps.autocontrast """ + import cv2 + n_bins = 256 def tune_channel(ch): @@ -108,6 +109,8 @@ def equalize_func(img): same output as PIL.ImageOps.equalize PIL's implementation is different from cv2.equalize """ + import cv2 + n_bins = 256 def tune_channel(ch): @@ -131,6 +134,8 @@ def rotate_func(img, degree, fill=(0, 0, 0)): """ like PIL, rotate by degree, not radians """ + import cv2 + H, W = img.shape[0], img.shape[1] center = W / 2, H / 2 M = cv2.getRotationMatrix2D(center, degree, 1) @@ -194,6 +199,8 @@ def sharpness_func(img, factor): The differences the this result and PIL are all on the 4 boundaries, the center areas are same """ + import cv2 + kernel = np.ones((3, 3), dtype=np.float32) kernel[1][1] = 5 kernel /= 13 @@ -211,6 +218,8 @@ def sharpness_func(img, factor): def shear_x_func(img, factor, fill=(0, 0, 0)): + import cv2 + H, W = img.shape[0], img.shape[1] M = np.float32([[1, factor, 0], [0, 1, 0]]) out = cv2.warpAffine( @@ -223,6 +232,8 @@ def translate_x_func(img, offset, fill=(0, 0, 0)): """ same output as PIL.Image.transform """ + import cv2 + H, W = img.shape[0], img.shape[1] M = np.float32([[1, 0, -offset], [0, 1, 0]]) out = cv2.warpAffine( @@ -235,6 +246,8 @@ def translate_y_func(img, offset, fill=(0, 0, 0)): """ same output as PIL.Image.transform """ + import cv2 + H, W = img.shape[0], img.shape[1] M = np.float32([[1, 0, 0], [0, 1, -offset]]) out = cv2.warpAffine( @@ -252,6 +265,8 @@ def posterize_func(img, bits): def shear_y_func(img, factor, fill=(0, 0, 0)): + import cv2 + H, W = img.shape[0], img.shape[1] M = np.float32([[1, 0, 0], [factor, 1, 0]]) out = cv2.warpAffine( diff --git a/xinference/types.py b/xinference/types.py index f129daa223..3f636d94c3 100644 --- a/xinference/types.py +++ b/xinference/types.py @@ -33,6 +33,7 @@ stop_field, stream_field, stream_interval_field, + stream_option_field, temperature_field, top_k_field, top_p_field, @@ -51,6 +52,16 @@ class ImageList(TypedDict): data: List[Image] +class Video(TypedDict): + url: Optional[str] + b64_json: Optional[str] + + +class VideoList(TypedDict): + created: int + data: List[Video] + + class EmbeddingUsage(TypedDict): prompt_tokens: int total_tokens: int @@ -79,9 +90,37 @@ class DocumentObj(TypedDict): document: Optional[Document] +# Cohere API compatibility +class ApiVersion(TypedDict): + version: str + is_deprecated: bool + is_experimental: bool + + +# Cohere API compatibility +class BilledUnit(TypedDict): + input_tokens: int + output_tokens: int + search_units: int + classifications: int + + +class RerankTokens(TypedDict): + input_tokens: int + output_tokens: int + + +class Meta(TypedDict): + api_version: Optional[ApiVersion] + billed_units: Optional[BilledUnit] + tokens: RerankTokens + warnings: Optional[List[str]] + + class Rerank(TypedDict): id: str results: List[DocumentObj] + meta: Meta class CompletionLogprobs(TypedDict): @@ -91,11 +130,23 @@ class CompletionLogprobs(TypedDict): top_logprobs: List[Optional[Dict[str, float]]] +class ToolCallFunction(TypedDict): + name: str + arguments: str + + +class ToolCalls(TypedDict): + id: str + type: Literal["function"] + function: ToolCallFunction + + class CompletionChoice(TypedDict): text: str index: int logprobs: Optional[CompletionLogprobs] finish_reason: Optional[str] + tool_calls: NotRequired[List[ToolCalls]] class CompletionUsage(TypedDict): @@ -147,6 +198,7 @@ class ChatCompletion(TypedDict): class ChatCompletionChunkDelta(TypedDict): role: NotRequired[str] content: NotRequired[str] + tool_calls: NotRequired[List[ToolCalls]] class ChatCompletionChunkChoice(TypedDict): @@ -164,28 +216,6 @@ class ChatCompletionChunk(TypedDict): usage: NotRequired[CompletionUsage] -class ChatglmCppModelConfig(TypedDict, total=False): - pass - - -class ChatglmCppGenerateConfig(TypedDict, total=False): - max_tokens: int - top_p: float - temperature: float - stream: bool - - -class QWenCppModelConfig(TypedDict, total=False): - pass - - -class QWenCppGenerateConfig(TypedDict, total=False): - max_tokens: int - top_p: float - temperature: float - stream: bool - - StoppingCriteria = Callable[[List[int], List[float]], bool] @@ -217,6 +247,7 @@ class LlamaCppGenerateConfig(TypedDict, total=False): repetition_penalty: float top_k: int stream: bool + stream_options: Optional[Union[dict, None]] tfs_z: float mirostat_mode: int mirostat_tau: float @@ -232,13 +263,14 @@ class LlamaCppModelConfig(TypedDict, total=False): n_ctx: int n_parts: int n_gpu_layers: int + split_mode: int + main_gpu: int seed: int f16_kv: bool logits_all: bool vocab_only: bool use_mmap: bool use_mlock: bool - embedding: bool n_threads: Optional[int] n_batch: int last_n_tokens_size: int @@ -263,6 +295,9 @@ class PytorchGenerateConfig(TypedDict, total=False): stream_interval: int model: Optional[str] tools: Optional[List[Dict]] + lora_name: Optional[str] + stream_options: Optional[Union[dict, None]] + request_id: Optional[str] class PytorchModelConfig(TypedDict, total=False): @@ -276,6 +311,8 @@ class PytorchModelConfig(TypedDict, total=False): gptq_groupsize: int gptq_act_order: bool trust_remote_code: bool + max_num_seqs: int + enable_tensorizer: Optional[bool] def get_pydantic_model_from_method( @@ -334,10 +371,13 @@ class CreateCompletionTorch(BaseModel): stop: Optional[Union[str, List[str]]] = stop_field stop_token_ids: Optional[Union[int, List[int]]] = none_field stream: bool = stream_field + stream_options: Optional[Union[dict, None]] = stream_option_field stream_interval: int = stream_interval_field temperature: float = temperature_field top_p: float = top_p_field top_k: int = top_k_field + lora_name: Optional[str] + request_id: Optional[str] CreateCompletionLlamaCpp: BaseModel @@ -350,26 +390,13 @@ class CreateCompletionTorch(BaseModel): include_fields={ "grammar": (Optional[Any], None), "max_tokens": (Optional[int], max_tokens_field), + "lora_name": (Optional[str], None), + "stream_options": (Optional[Union[dict, None]], None), }, ) except ImportError: CreateCompletionLlamaCpp = create_model("CreateCompletionLlamaCpp") -CreateCompletionCTransformers: BaseModel -try: - from ctransformers.llm import LLM - - CreateCompletionCTransformers = get_pydantic_model_from_method( - LLM.generate, - exclude_fields=["tokens"], - include_fields={ - "max_tokens": (Optional[int], max_tokens_field), - "stream": (Optional[bool], stream_field), - }, - ) -except ImportError: - CreateCompletionCTransformers = create_model("CreateCompletionCTransformers") - # This type is for openai API compatibility CreateCompletionOpenAI: BaseModel @@ -392,6 +419,7 @@ class _CreateCompletionOpenAIFallback(BaseModel): seed: Optional[int] = none_field stop: Optional[Union[str, List[str]]] = stop_field stream: bool = stream_field + stream_options: Optional[Union[dict, None]] = stream_option_field suffix: Optional[str] = none_field temperature: float = temperature_field top_p: float = top_p_field @@ -415,7 +443,6 @@ class CreateCompletion( ModelAndPrompt, CreateCompletionTorch, CreateCompletionLlamaCpp, - CreateCompletionCTransformers, CreateCompletionOpenAI, ): pass @@ -428,8 +455,6 @@ class CreateChatModel(BaseModel): # Currently, chat calls generates, so the params share the same one. CreateChatCompletionTorch = CreateCompletionTorch CreateChatCompletionLlamaCpp: BaseModel = CreateCompletionLlamaCpp -CreateChatCompletionCTransformers: BaseModel = CreateCompletionCTransformers - # This type is for openai API compatibility CreateChatCompletionOpenAI: BaseModel @@ -450,7 +475,61 @@ class CreateChatCompletion( CreateChatModel, CreateChatCompletionTorch, CreateChatCompletionLlamaCpp, - CreateChatCompletionCTransformers, CreateChatCompletionOpenAI, ): pass + + +class LoRA: + def __init__(self, lora_name: str, local_path: str): + self.lora_name = lora_name + self.local_path = local_path + + def to_dict(self): + return { + "lora_name": self.lora_name, + "local_path": self.local_path, + } + + @classmethod + def from_dict(cls, data: Dict): + return cls( + lora_name=data["lora_name"], + local_path=data["local_path"], + ) + + +class PeftModelConfig: + def __init__( + self, + peft_model: Optional[List[LoRA]] = None, + image_lora_load_kwargs: Optional[Dict] = None, + image_lora_fuse_kwargs: Optional[Dict] = None, + ): + self.peft_model = peft_model + self.image_lora_load_kwargs = image_lora_load_kwargs + self.image_lora_fuse_kwargs = image_lora_fuse_kwargs + + def to_dict(self): + return { + "lora_list": [lora.to_dict() for lora in self.peft_model] + if self.peft_model + else None, + "image_lora_load_kwargs": self.image_lora_load_kwargs, + "image_lora_fuse_kwargs": self.image_lora_fuse_kwargs, + } + + @classmethod + def from_dict(cls, data: Dict): + peft_model_list = data.get("lora_list", None) + peft_model = ( + [LoRA.from_dict(lora_dict) for lora_dict in peft_model_list] + if peft_model_list is not None + else None + ) + + return cls( + peft_model=peft_model, + image_lora_load_kwargs=data.get("image_lora_load_kwargs"), + image_lora_fuse_kwargs=data.get("image_lora_fuse_kwargs"), + ) diff --git a/xinference/utils.py b/xinference/utils.py index 5b3741c222..79a46fde6d 100644 --- a/xinference/utils.py +++ b/xinference/utils.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + import torch diff --git a/xinference/web/ui/package-lock.json b/xinference/web/ui/package-lock.json index 4ae5037245..983c68dd2a 100644 --- a/xinference/web/ui/package-lock.json +++ b/xinference/web/ui/package-lock.json @@ -27,6 +27,7 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "clipboard": "^2.0.11", "formik": "^2.4.2", "prop-types": "^15.8.1", "react": "^18.2.0", @@ -59,9 +60,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz", - "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", + "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==" }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", @@ -87,11 +88,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -176,13 +178,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dependencies": { - "@babel/types": "^7.22.5", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -307,31 +309,34 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -451,28 +456,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "engines": { "node": ">=6.9.0" } @@ -512,22 +517,23 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2020,32 +2026,32 @@ "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", - "debug": "^4.1.0", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2053,12 +2059,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -3018,7 +3024,7 @@ "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^9.0.1", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", @@ -3356,13 +3362,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -3377,9 +3383,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -3399,19 +3405,14 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -6705,20 +6706,20 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", + "content-type": "~1.0.5", + "debug": "^4.0.1", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -6735,14 +6736,6 @@ "node": ">= 0.8" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/body-parser/node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6754,11 +6747,6 @@ "node": ">=0.10.0" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/bonjour-service": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", @@ -6785,11 +6773,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -7064,6 +7052,16 @@ "node": ">=0.10.0" } }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -7188,7 +7186,7 @@ "accepts": "~1.3.5", "bytes": "3.0.0", "compressible": "~2.0.16", - "debug": "2.6.9", + "debug": "^4.0.1", "on-headers": "~1.0.2", "safe-buffer": "5.1.2", "vary": "~1.1.2" @@ -7197,19 +7195,6 @@ "node": ">= 0.8.0" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7777,14 +7762,9 @@ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", "dependencies": { - "d3-color": "1 - 2" + "d3-color": "1 - 3" } }, - "node_modules/d3-interpolate/node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - }, "node_modules/d3-path": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", @@ -7807,15 +7787,10 @@ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz", "integrity": "sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==", "dependencies": { - "d3-color": "1 - 2", + "d3-color": "1 - 3", "d3-interpolate": "1 - 2" } }, - "node_modules/d3-scale-chromatic/node_modules/d3-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", - "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" - }, "node_modules/d3-scale/node_modules/d3-array": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", @@ -7999,6 +7974,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -8043,7 +8023,7 @@ "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", "dependencies": { "address": "^1.0.1", - "debug": "^2.6.0" + "debug": "^4.0.1" }, "bin": { "detect": "bin/detect-port", @@ -8053,19 +8033,6 @@ "node": ">= 4.2.1" } }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -8247,9 +8214,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dependencies": { "jake": "^10.8.5" }, @@ -9299,18 +9266,18 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", - "debug": "2.6.9", + "debug": "^4.0.1", "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -9344,19 +9311,14 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -9491,9 +9453,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9506,7 +9468,7 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { - "debug": "2.6.9", + "debug": "^4.0.1", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "2.4.1", @@ -9518,19 +9480,6 @@ "node": ">= 0.8" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", @@ -9585,9 +9534,9 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -9623,7 +9572,7 @@ "cosmiconfig": "^6.0.0", "deepmerge": "^4.2.2", "fs-extra": "^9.0.0", - "glob": "^7.1.6", + "glob": "^9.0.1", "memfs": "^3.1.2", "minimatch": "^3.0.4", "schema-utils": "2.7.0", @@ -9983,19 +9932,17 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -10017,6 +9964,28 @@ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -10093,6 +10062,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", + "dependencies": { + "delegate": "^3.1.2" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -10592,15 +10569,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -11497,7 +11465,7 @@ "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", + "glob": "^9.0.1", "graceful-fs": "^4.2.9", "jest-circus": "^27.5.1", "jest-environment-jsdom": "^27.5.1", @@ -12333,7 +12301,7 @@ "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", - "glob": "^7.1.3", + "glob": "^9.0.1", "graceful-fs": "^4.2.9", "jest-haste-map": "^27.5.1", "jest-message-util": "^27.5.1", @@ -13561,11 +13529,11 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -13709,6 +13677,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -13748,9 +13724,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -14042,14 +14018,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -14211,14 +14179,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -14232,6 +14192,37 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -14409,9 +14400,9 @@ } }, "node_modules/postcss": { - "version": "8.4.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz", - "integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -14427,9 +14418,9 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -15821,9 +15812,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -16726,7 +16717,7 @@ "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", "loader-utils": "^2.0.0", - "postcss": "^7.0.35", + "postcss": "^8.0.1", "source-map": "0.6.1" }, "engines": { @@ -16745,27 +16736,6 @@ } } }, - "node_modules/resolve-url-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/resolve-url-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, "node_modules/resolve-url-loader/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -16804,7 +16774,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dependencies": { - "glob": "^7.1.3" + "glob": "^9.0.1" }, "bin": { "rimraf": "bin.js" @@ -16835,7 +16805,7 @@ "dependencies": { "@babel/code-frame": "^7.10.4", "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", + "serialize-javascript": "^6.0.0", "terser": "^5.0.0" }, "peerDependencies": { @@ -16863,14 +16833,6 @@ "node": ">= 10.13.0" } }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/rollup-plugin-terser/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -17041,6 +17003,11 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -17092,7 +17059,7 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { - "debug": "2.6.9", + "debug": "^4.0.1", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", @@ -17110,18 +17077,11 @@ "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "extraneous": true }, "node_modules/send/node_modules/ms": { "version": "2.1.3", @@ -17129,9 +17089,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dependencies": { "randombytes": "^2.1.0" } @@ -17143,7 +17103,7 @@ "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", - "debug": "2.6.9", + "debug": "^4.0.1", "escape-html": "~1.0.3", "http-errors": "~1.6.2", "mime-types": "~2.1.17", @@ -17153,14 +17113,6 @@ "node": ">= 0.8.0" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/serve-index/node_modules/depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -17188,11 +17140,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -17388,9 +17335,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -17735,7 +17682,7 @@ "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "7.1.6", + "glob": "^9.0.1", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", @@ -17757,25 +17704,6 @@ "node": ">= 6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -17867,20 +17795,9 @@ "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^3.2.1", + "css-what": "^6.0.1", "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/svgo/node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "nth-check": "^2.0.1" } }, "node_modules/svgo/node_modules/dom-serializer": { @@ -17906,14 +17823,6 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" }, - "node_modules/svgo/node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dependencies": { - "boolbase": "~1.0.0" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -18110,7 +18019,7 @@ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", + "glob": "^9.0.1", "minimatch": "^3.0.4" }, "engines": { @@ -18156,6 +18065,11 @@ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -18739,9 +18653,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -19162,7 +19076,7 @@ "common-tags": "^1.8.0", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", - "glob": "^7.1.6", + "glob": "^9.0.1", "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", "rollup": "^2.43.1", @@ -19469,11 +19383,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", diff --git a/xinference/web/ui/package.json b/xinference/web/ui/package.json index 4dced5764d..ed0e6ea1f4 100644 --- a/xinference/web/ui/package.json +++ b/xinference/web/ui/package.json @@ -23,6 +23,7 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "clipboard": "^2.0.11", "formik": "^2.4.2", "prop-types": "^15.8.1", "react": "^18.2.0", diff --git a/xinference/web/ui/src/App.js b/xinference/web/ui/src/App.js index e689305f6b..53fa155fce 100644 --- a/xinference/web/ui/src/App.js +++ b/xinference/web/ui/src/App.js @@ -2,31 +2,21 @@ import { CssBaseline, ThemeProvider } from '@mui/material' import Snackbar from '@mui/material/Snackbar' import React, { useEffect, useState } from 'react' import { useCookies } from 'react-cookie' -import { HashRouter, Route, Routes } from 'react-router-dom' +import { HashRouter } from 'react-router-dom' import { Alert } from './components/alertComponent' import { ApiContextProvider } from './components/apiContext' import AuthAlertDialog from './components/authAlertDialog' -import { getEndpoint, isValidBearerToken } from './components/utils' -import Layout from './scenes/_layout' -import ClusterInfo from './scenes/cluster_info' -import LaunchModel from './scenes/launch_model' -import Login from './scenes/login/login' -import RegisterModel from './scenes/register_model' -import RunningModels from './scenes/running_models' +import { getEndpoint } from './components/utils' +import WraperRoutes from './router/index' import { useMode } from './theme' function App() { const [theme] = useMode() const [cookie, setCookie, removeCookie] = useCookies(['token']) const [msg, setMsg] = useState('') - const endPoint = getEndpoint() - const removeToken = () => { - removeCookie('token', { path: '/' }) - } - useEffect(() => { // token possible value: no_auth / need_auth / fetch(endPoint + '/v1/cluster/auth', { @@ -45,28 +35,21 @@ function App() { }) } else { res.json().then((data) => { - if (data['auth'] === false) { - if (cookie.token !== 'no_auth') { - setCookie('token', 'no_auth', { path: '/' }) - } - } else { - // TODO: validate bearer token - if ( - cookie.token === undefined || - !isValidBearerToken(cookie.token) - ) { - // not a bearer token, need a bearer token here - setCookie('token', 'need_auth', { path: '/' }) - } + if (!data.auth) { + setCookie('token', 'no_auth', { path: '/' }) + sessionStorage.setItem('token', 'no_auth') + } else if ( + data.auth && + sessionStorage.getItem('token') === 'no_auth' + ) { + removeCookie('token', { path: '/' }) + sessionStorage.removeItem('token') } + sessionStorage.setItem('auth', String(data.auth)) // sessionStorage only can set string value }) } }) - // return a function in useEffect means doing something on component unmount - return () => { - removeToken() - } - }, []) + }, [cookie]) const handleClose = (event, reason) => { if (reason === 'clickaway') { @@ -92,15 +75,7 @@ function App() { - - } /> - }> - } /> - } /> - } /> - } /> - - + diff --git a/xinference/web/ui/src/components/MenuSide.js b/xinference/web/ui/src/components/MenuSide.js index b904c79401..d8d763dfbe 100644 --- a/xinference/web/ui/src/components/MenuSide.js +++ b/xinference/web/ui/src/components/MenuSide.js @@ -138,7 +138,6 @@ const MenuSide = () => { } const link = text.toLowerCase().replace(' ', '_') - console.log(link) return ( @@ -151,12 +150,31 @@ const MenuSide = () => { 'noreferrer' ) } else if (link === 'launch_model') { - navigate(`/`) + sessionStorage.setItem('modelType', '/launch_model/llm') + navigate('/launch_model/llm') setActive(link) + sessionStorage.setItem('lastActiveUrl', link) console.log(active) } else if (link === 'cluster_information') { - navigate(`/cluster_info`) + navigate('/cluster_info') setActive(link) + } else if (link === 'running_models') { + navigate('/running_models/LLM') + sessionStorage.setItem( + 'runningModelType', + '/running_models/LLM' + ) + setActive(link) + sessionStorage.setItem('lastActiveUrl', link) + console.log(active) + } else if (link === 'register_model') { + sessionStorage.setItem( + 'registerModelType', + '/register_model/llm' + ) + navigate('/register_model/llm') + setActive(link) + sessionStorage.setItem('lastActiveUrl', link) console.log(active) } else { navigate(`/${link}`) diff --git a/xinference/web/ui/src/components/Title.js b/xinference/web/ui/src/components/Title.js index 05e124a281..77820db4cb 100644 --- a/xinference/web/ui/src/components/Title.js +++ b/xinference/web/ui/src/components/Title.js @@ -12,6 +12,12 @@ const Title = ({ title }) => { const handleLogout = () => { removeCookie('token', { path: '/' }) + sessionStorage.removeItem('token') + sessionStorage.removeItem('auth') + sessionStorage.removeItem('modelType') + sessionStorage.removeItem('lastActiveUrl') + sessionStorage.removeItem('runningModelType') + sessionStorage.removeItem('registerModelType') navigate('/login', { replace: true }) } @@ -26,7 +32,8 @@ const Title = ({ title }) => { > {title} - {isValidBearerToken(cookie.token) && ( + {(isValidBearerToken(cookie.token) || + isValidBearerToken(sessionStorage.getItem('token'))) && ( + + + + ) +} + +export default DeleteDialog diff --git a/xinference/web/ui/src/components/fetchWrapper.js b/xinference/web/ui/src/components/fetchWrapper.js new file mode 100644 index 0000000000..1182436c1f --- /dev/null +++ b/xinference/web/ui/src/components/fetchWrapper.js @@ -0,0 +1,135 @@ +import { Cookies } from 'react-cookie' + +const cookies = new Cookies() + +const getBaseUrl = () => { + let base_URL = '' + if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { + base_URL = 'http://127.0.0.1:9997' + } else { + const fullUrl = window.location.href + base_URL = fullUrl.split('/ui')[0] + } + return base_URL +} + +const apiBase = getBaseUrl() + +const fetchWrapper = { + get: async (endpoint, config = {}) => { + const url = `${apiBase}${endpoint}` + const headers = { + 'Content-Type': 'application/json', + ...config.headers, + } + if ( + cookies.get('token') !== 'no_auth' && + sessionStorage.getItem('token') !== 'no_auth' + ) { + headers.Authorization = 'Bearer ' + sessionStorage.getItem('token') + } + const response = await fetch(url, { + method: 'GET', + ...config, + headers, + }) + + return fetchWrapper.handleResponse(response) + }, + + post: async (endpoint, body, config = {}) => { + const url = `${apiBase}${endpoint}` + const headers = { + 'Content-Type': 'application/json', + ...config.headers, + } + if ( + cookies.get('token') !== 'no_auth' && + sessionStorage.getItem('token') !== 'no_auth' + ) { + headers.Authorization = 'Bearer ' + sessionStorage.getItem('token') + } + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify(body), + ...config, + headers, + }) + + return fetchWrapper.handleResponse(response) + }, + + put: async (endpoint, body, config = {}) => { + const url = `${apiBase}${endpoint}` + const headers = { + 'Content-Type': 'application/json', + ...config.headers, + } + if ( + cookies.get('token') !== 'no_auth' && + sessionStorage.getItem('token') !== 'no_auth' + ) { + headers.Authorization = 'Bearer ' + sessionStorage.getItem('token') + } + const response = await fetch(url, { + method: 'PUT', + body: JSON.stringify(body), + ...config, + headers, + }) + + return fetchWrapper.handleResponse(response) + }, + + delete: async (endpoint, config = {}) => { + const url = `${apiBase}${endpoint}` + const headers = { + 'Content-Type': 'application/json', + ...config.headers, + } + if ( + cookies.get('token') !== 'no_auth' && + sessionStorage.getItem('token') !== 'no_auth' + ) { + headers.Authorization = 'Bearer ' + sessionStorage.getItem('token') + } + const response = await fetch(url, { + method: 'DELETE', + ...config, + headers, + }) + + return fetchWrapper.handleResponse(response) + }, + + handleResponse: async (response) => { + if ( + response.status == 401 && + localStorage.getItem('authStatus') !== '401' + ) { + localStorage.setItem('authStatus', '401') + window.dispatchEvent(new Event('auth-status')) + } else if ( + response.status == 403 && + localStorage.getItem('authStatus') !== '403' + ) { + localStorage.setItem('authStatus', '403') + window.dispatchEvent(new Event('auth-status')) + } + + if (!response.ok) { + const errorData = await response.json() + const error = new Error( + `Server error: ${response.status} - ${ + errorData.detail || 'Unknown error' + }` + ) + error.response = response + throw error + } + const data = await response.json() + return data + }, +} + +export default fetchWrapper diff --git a/xinference/web/ui/src/components/fetcher.js b/xinference/web/ui/src/components/fetcher.js index 6d1544ebe0..9dbcf2a5d6 100644 --- a/xinference/web/ui/src/components/fetcher.js +++ b/xinference/web/ui/src/components/fetcher.js @@ -1,15 +1,16 @@ import { Cookies } from 'react-cookie' -import { isValidBearerToken } from './utils' - const cookies = new Cookies() const updateOptions = (url, options) => { const update = { ...options } - if (cookies.get('token') !== 'no_auth') { + if ( + cookies.get('token') !== 'no_auth' && + sessionStorage.getItem('token') !== 'no_auth' + ) { update.headers = { ...update.headers, - Authorization: 'Bearer ' + cookies.get('token'), + Authorization: 'Bearer ' + sessionStorage.getItem('token'), } } return update @@ -19,16 +20,15 @@ export default function fetcher(url, options) { return fetch(url, updateOptions(url, options)).then((res) => { // For the situation that server has already been restarted, the current token may become invalid, // which leads to UI hangs. - if (res.status === 401 && isValidBearerToken(cookies.get('token'))) { - if (localStorage.getItem('authStatus') !== '401') { - localStorage.setItem('authStatus', '401') - window.dispatchEvent(new Event('auth-status')) - } - } else if (res.status === 403 && isValidBearerToken(cookies.get('token'))) { - if (localStorage.getItem('authStatus') !== '403') { - localStorage.setItem('authStatus', '403') - window.dispatchEvent(new Event('auth-status')) - } + if (res.status == 401 && localStorage.getItem('authStatus') !== '401') { + localStorage.setItem('authStatus', '401') + window.dispatchEvent(new Event('auth-status')) + } else if ( + res.status == 403 && + localStorage.getItem('authStatus') !== '403' + ) { + localStorage.setItem('authStatus', '403') + window.dispatchEvent(new Event('auth-status')) } else { return res } diff --git a/xinference/web/ui/src/components/hotkeyFocusTextField.js b/xinference/web/ui/src/components/hotkeyFocusTextField.js new file mode 100644 index 0000000000..4a9c00bfe6 --- /dev/null +++ b/xinference/web/ui/src/components/hotkeyFocusTextField.js @@ -0,0 +1,58 @@ +import { TextField } from '@mui/material' +import InputAdornment from '@mui/material/InputAdornment' +import Typography from '@mui/material/Typography' +import React, { useEffect, useRef, useState } from 'react' + +const HotkeyFocusTextField = ({ + label, + value, + onChange, + hotkey = '/', + ...props +}) => { + const [isFocused, setIsFocused] = useState(false) + const textFieldRef = useRef(null) + const handleKeyDown = (event) => { + if ( + event.key === hotkey && + document.activeElement !== textFieldRef.current + ) { + event.preventDefault() + setIsFocused(true) + textFieldRef.current?.focus() + } + } + + useEffect(() => { + document.addEventListener('keydown', handleKeyDown) + + return () => { + document.removeEventListener('keydown', handleKeyDown) + } + }, [hotkey]) + + return ( + setIsFocused(false)} + onFocus={() => setIsFocused(true)} + InputProps={{ + endAdornment: + !isFocused && !value ? ( + + + Type {hotkey} to search + + + ) : null, + }} + /> + ) +} + +export default HotkeyFocusTextField diff --git a/xinference/web/ui/src/router/index.js b/xinference/web/ui/src/router/index.js new file mode 100644 index 0000000000..fb7a242b1e --- /dev/null +++ b/xinference/web/ui/src/router/index.js @@ -0,0 +1,83 @@ +import { useContext, useEffect, useState } from 'react' +import { Navigate, useRoutes } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' + +import { ApiContext } from '../components/apiContext' +import Layout from '../scenes/_layout' +import ClusterInfo from '../scenes/cluster_info' +import LaunchModel from '../scenes/launch_model' +import Login from '../scenes/login/login' +import RegisterModel from '../scenes/register_model' +import RunningModels from '../scenes/running_models' + +const LoginAuth = () => { + const [authority, setAuthority] = useState(true) + + const navigate = useNavigate() + const { endPoint } = useContext(ApiContext) + + useEffect(() => { + fetch(endPoint + '/v1/cluster/auth', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }).then((res) => { + if (res.ok) { + res.json().then((data) => { + setAuthority(data.auth) + sessionStorage.setItem('auth', String(data.auth)) // sessionStorage only can set string value + }) + } + }) + }, []) + + useEffect(() => { + if (!authority) navigate('/launch_model/llm') + }, [authority]) + + return +} + +const routes = [ + { + path: '/', + element: , + children: [ + { + path: '/', + element: , + }, + { + path: 'launch_model/:Modeltype/:subType?', + element: , + }, + { + path: 'running_models/:runningModelType', + element: , + }, + { + path: 'register_model/:registerModelType/:model_name?', + element: , + }, + { + path: 'cluster_info', + element: , + }, + ], + }, + { + path: '/login', + element: , + }, + { + path: '*', + element: , + }, +] +const WraperRoutes = () => { + let element = useRoutes(routes) + return element +} + +export default WraperRoutes diff --git a/xinference/web/ui/src/scenes/cluster_info/index.js b/xinference/web/ui/src/scenes/cluster_info/index.js index ecf1fa4eb8..47274ccfee 100644 --- a/xinference/web/ui/src/scenes/cluster_info/index.js +++ b/xinference/web/ui/src/scenes/cluster_info/index.js @@ -1,27 +1,54 @@ import { Box } from '@mui/material' import Paper from '@mui/material/Paper' import Grid from '@mui/material/Unstable_Grid2' -import React, { useContext } from 'react' +import React, { useContext, useEffect } from 'react' +import { useCookies } from 'react-cookie' +import { useNavigate } from 'react-router-dom' import { ApiContext } from '../../components/apiContext' import TableTitle from '../../components/tableTitle' import Title from '../../components/Title' +import { isValidBearerToken } from '../../components/utils' import NodeInfo from './nodeInfo' const ClusterInfo = () => { const endPoint = useContext(ApiContext).endPoint + const [cookie] = useCookies(['token']) + const navigate = useNavigate() + + useEffect(() => { + if ( + sessionStorage.getItem('auth') === 'true' && + !isValidBearerToken(sessionStorage.getItem('token')) && + !isValidBearerToken(cookie.token) + ) { + navigate('/login', { replace: true }) + } + }, [cookie.token]) + + const handleGoBack = () => { + const lastUrl = sessionStorage.getItem('lastActiveUrl') + if (lastUrl === 'launch_model') { + navigate(sessionStorage.getItem('modelType')) + } else if (lastUrl === 'running_models') { + navigate(sessionStorage.getItem('runningModelType')) + } else if (lastUrl === 'register_model') { + navigate(sessionStorage.getItem('registerModelType')) + } else { + navigate('/launch_model/llm') + } + } return ( - <Grid container spacing={3}> + <Grid container spacing={3} style={{ width: '100%' }}> <Grid item xs={12}> <Paper sx={{ @@ -32,7 +59,12 @@ const ClusterInfo = () => { }} > <TableTitle>Supervisor</TableTitle> - <NodeInfo nodeRole="Supervisor" endpoint={endPoint} /> + <NodeInfo + nodeRole="Supervisor" + endpoint={endPoint} + cookie={cookie} + handleGoBack={handleGoBack} + /> </Paper> </Grid> <Grid item xs={12}> @@ -45,7 +77,12 @@ const ClusterInfo = () => { }} > <TableTitle>Workers</TableTitle> - <NodeInfo nodeRole="Worker" endpoint={endPoint} /> + <NodeInfo + nodeRole="Worker" + endpoint={endPoint} + cookie={cookie} + handleGoBack={handleGoBack} + /> </Paper> </Grid> <Grid item xs={12}> @@ -58,7 +95,12 @@ const ClusterInfo = () => { }} > <TableTitle>Worker Details</TableTitle> - <NodeInfo nodeRole="Worker-Details" endpoint={endPoint} /> + <NodeInfo + nodeRole="Worker-Details" + endpoint={endPoint} + cookie={cookie} + handleGoBack={handleGoBack} + /> </Paper> </Grid> </Grid> diff --git a/xinference/web/ui/src/scenes/cluster_info/nodeInfo.js b/xinference/web/ui/src/scenes/cluster_info/nodeInfo.js index 9bd1093caa..826bef5c3a 100644 --- a/xinference/web/ui/src/scenes/cluster_info/nodeInfo.js +++ b/xinference/web/ui/src/scenes/cluster_info/nodeInfo.js @@ -6,6 +6,7 @@ import Grid from '@mui/material/Unstable_Grid2' import PropTypes from 'prop-types' import React from 'react' +import fetchWrapper from '../../components/fetchWrapper' import { toReadableSize } from '../../components/utils' import { StyledTableCell, StyledTableRow } from './style' @@ -21,27 +22,45 @@ class NodeInfo extends React.Component { } refreshInfo() { - fetch(`${this.endpoint}/v1/cluster/info?detailed=true`, { method: 'GET' }) - .then((res) => res.json()) - .then((res) => { + if ( + this.props.cookie.token === '' || + this.props.cookie.token === undefined || + (this.props.cookie.token !== 'no_auth' && + !sessionStorage.getItem('token')) + ) { + return + } + fetchWrapper + .get('/v1/cluster/info?detailed=true') + .then((data) => { const { state } = this - state['info'] = res + state['info'] = data this.setState(state) }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status == 403) { + this.props.handleGoBack() + } + }) if (JSON.stringify(this.state.version) === '{}') { - fetch(`${this.endpoint}/v1/cluster/version`, { - method: 'GET', - }) - .then((res) => res.json()) - .then((res) => { + fetchWrapper + .get('/v1/cluster/version') + .then((data) => { const { state } = this state['version'] = { - release: 'v' + res['version'], - commit: res['full-revisionid'], + release: 'v' + data['version'], + commit: data['full-revisionid'], } this.setState(state) }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status == 403) { + this.props.handleGoBack() + } + }) } } diff --git a/xinference/web/ui/src/scenes/launch_model/LaunchModelComponent.js b/xinference/web/ui/src/scenes/launch_model/LaunchModelComponent.js index 7603a394d8..a2cdd3645b 100644 --- a/xinference/web/ui/src/scenes/launch_model/LaunchModelComponent.js +++ b/xinference/web/ui/src/scenes/launch_model/LaunchModelComponent.js @@ -1,29 +1,69 @@ -import { Box, FormControl, TextField } from '@mui/material' +import { + Box, + Chip, + FormControl, + InputLabel, + MenuItem, + Select, +} from '@mui/material' import React, { useContext, useEffect, useState } from 'react' import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' +import fetchWrapper from '../../components/fetchWrapper' +import HotkeyFocusTextField from '../../components/hotkeyFocusTextField' import ModelCard from './modelCard' -import style from './styles/launchModelStyle' -const LaunchModelComponent = ({ modelType }) => { +const LaunchModelComponent = ({ modelType, gpuAvailable }) => { let endPoint = useContext(ApiContext).endPoint const [registrationData, setRegistrationData] = useState([]) const [searchTerm, setSearchTerm] = useState('') + const [status, setStatus] = useState('') + const [completeDeleteArr, setCompleteDeleteArr] = useState([]) + const [collectionArr, setCollectionArr] = useState([]) + const [filterArr, setFilterArr] = useState([]) const { isCallingApi, setIsCallingApi } = useContext(ApiContext) const { isUpdatingModel } = useContext(ApiContext) - const handleChange = (e) => { - setSearchTerm(e.target.value) + const filter = (registration) => { + if (searchTerm !== '') { + if (!registration || typeof searchTerm !== 'string') return false + const modelName = registration.model_name + ? registration.model_name.toLowerCase() + : '' + if (!modelName.includes(searchTerm.toLowerCase())) { + return false + } + } + + if (completeDeleteArr.includes(registration.model_name)) { + registration.cache_status = Array.isArray(registration.cache_status) + ? [false] + : false + } + + if (filterArr.length === 1) { + if (filterArr[0] === 'cached') { + return ( + registration.cache_status && + !completeDeleteArr.includes(registration.model_name) + ) + } else { + return collectionArr?.includes(registration.model_name) + } + } else if (filterArr.length > 1) { + return ( + registration.cache_status && + !completeDeleteArr.includes(registration.model_name) && + collectionArr?.includes(registration.model_name) + ) + } + + return true } - const filter = (registration) => { - if (!registration || typeof searchTerm !== 'string') return false - const modelName = registration.model_name - ? registration.model_name.toLowerCase() - : '' - return modelName.includes(searchTerm.toLowerCase()) + const handleCompleteDelete = (model_name) => { + setCompleteDeleteArr([...completeDeleteArr, model_name]) } const update = async () => { @@ -32,19 +72,18 @@ const LaunchModelComponent = ({ modelType }) => { try { setIsCallingApi(true) - const response = await fetcher( - `${endPoint}/v1/model_registrations/${modelType}?detailed=true`, - { - method: 'GET', - } - ) - - const registrations = await response.json() - - const builtinModels = registrations.filter((v) => { - return v.is_builtin - }) - setRegistrationData(builtinModels) + fetchWrapper + .get(`/v1/model_registrations/${modelType}?detailed=true`) + .then((data) => { + const builtinModels = data.filter((v) => { + return v.is_builtin + }) + setRegistrationData(builtinModels) + const collectionData = JSON.parse( + localStorage.getItem('collectionArr') + ) + setCollectionArr(collectionData) + }) } catch (error) { console.error('Error:', error) } finally { @@ -56,27 +95,89 @@ const LaunchModelComponent = ({ modelType }) => { update() }, []) + const getCollectionArr = (data) => { + setCollectionArr(data) + } + + const handleChangeFilter = (value) => { + setStatus(value) + const arr = [ + ...filterArr.filter((item) => { + return item !== value + }), + value, + ] + setFilterArr(arr) + } + + const handleDeleteChip = (item) => { + setFilterArr( + filterArr.filter((subItem) => { + return subItem !== item + }) + ) + + if (item === status) setStatus('') + } + return ( <Box m="20px"> <div style={{ display: 'grid', - gridTemplateColumns: '1fr', + gridTemplateColumns: '150px 1fr', + columnGap: '20px', margin: '30px 2rem', }} > + <FormControl sx={{ marginTop: 2, minWidth: 120 }} size="small"> + <InputLabel id="select-status">Status</InputLabel> + <Select + id="status" + labelId="select-status" + label="Status" + onChange={(e) => handleChangeFilter(e.target.value)} + value={status} + size="small" + sx={{ width: '150px' }} + > + <MenuItem value="cached">cached</MenuItem> + <MenuItem value="favorite">favorite</MenuItem> + </Select> + </FormControl> <FormControl variant="outlined" margin="normal"> - <TextField + <HotkeyFocusTextField id="search" type="search" label={`Search for ${modelType} model name`} value={searchTerm} - onChange={handleChange} + onChange={(e) => setSearchTerm(e.target.value)} size="small" + hotkey="/" /> </FormControl> </div> - <div style={style}> + <div style={{ margin: '0 0 30px 30px' }}> + {filterArr.map((item, index) => ( + <Chip + key={index} + label={item} + variant="outlined" + size="small" + color="primary" + style={{ marginRight: 10 }} + onDelete={() => handleDeleteChip(item)} + /> + ))} + </div> + <div + style={{ + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + paddingLeft: '2rem', + gridGap: '2rem 0rem', + }} + > {registrationData .filter((registration) => filter(registration)) .map((filteredRegistration) => ( @@ -85,6 +186,9 @@ const LaunchModelComponent = ({ modelType }) => { url={endPoint} modelData={filteredRegistration} modelType={modelType} + gpuAvailable={gpuAvailable} + onHandleCompleteDelete={handleCompleteDelete} + onGetCollectionArr={getCollectionArr} /> ))} </div> diff --git a/xinference/web/ui/src/scenes/launch_model/components/addPair.js b/xinference/web/ui/src/scenes/launch_model/components/addPair.js new file mode 100644 index 0000000000..b7f1c0923d --- /dev/null +++ b/xinference/web/ui/src/scenes/launch_model/components/addPair.js @@ -0,0 +1,145 @@ +import { AddCircle } from '@mui/icons-material' +import DeleteIcon from '@mui/icons-material/Delete' +import { Alert, Box, IconButton, Snackbar, TextField } from '@mui/material' +import React, { useEffect, useState } from 'react' + +const AddPair = ({ customData, pairData, onGetArr, onJudgeArr }) => { + const [openSnackbar, setOpenSnackbar] = useState(false) + const [arr, setArr] = useState([]) + const [arrId, setArrId] = useState(0) + const [defaultIndex, setDefaultIndex] = useState(-1) + const [isNotUniqueKey, setIsNotUniqueKey] = useState(false) + + useEffect(() => { + onGetArr(arr) + }, [arr]) + + useEffect(() => { + const dataArr = [] + pairData.forEach((item, index) => { + dataArr.push({ + id: index, + [customData.key]: item[customData.key], + [customData.value]: item[customData.value], + }) + }) + setArrId(pairData.length) + setArr(dataArr) + }, [pairData]) + + const updateArr = (index, type, newValue) => { + setArr( + arr.map((pair, subIndex) => { + if (subIndex === index) { + return { ...pair, [type]: newValue } + } + return pair + }) + ) + if (type === customData.key) { + setDefaultIndex(-1) + setIsNotUniqueKey(false) + arr.forEach((pair) => { + if (pair[customData.key] === newValue) { + setDefaultIndex(index) + setIsNotUniqueKey(true) + } + }) + } + } + + const handleDeleteArr = (index) => { + setDefaultIndex(-1) + setArr( + arr.filter((_, subIndex) => { + return index !== subIndex + }) + ) + onGetArr(arr) + } + + return ( + <div> + <Box> + <div + style={{ + display: 'flex', + alignItems: 'center', + margin: '20px 0 0 15px', + }} + > + <div>{customData.title}</div> + <IconButton + color="primary" + onClick={() => { + setArrId(arrId + 1) + let obj = { id: arrId } + obj[customData.key] = '' + obj[customData.value] = '' + onJudgeArr(arr, [customData.key, customData.value]) + ? setArr([...arr, obj]) + : setOpenSnackbar(true) + }} + > + <AddCircle /> + </IconButton> + </div> + <Box> + {arr.map((item, index) => { + return ( + <Box key={item.id}> + <div + style={{ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginTop: '10px', + marginLeft: '10px', + }} + > + <TextField + label={customData.key} + value={item[customData.key]} + onChange={(e) => { + updateArr(index, customData.key, e.target.value) + }} + style={{ width: '44%' }} + /> + <TextField + label={customData.value} + value={item[customData.value]} + onChange={(e) => { + updateArr(index, customData.value, e.target.value) + }} + style={{ width: '44%' }} + /> + <IconButton + aria-label="delete" + onClick={() => handleDeleteArr(index)} + style={{ marginLeft: '10px' }} + > + <DeleteIcon /> + </IconButton> + </div> + {isNotUniqueKey && defaultIndex === index && ( + <Alert severity="error"> + {customData.key} must be unique + </Alert> + )} + </Box> + ) + })} + </Box> + </Box> + <Snackbar + anchorOrigin={{ vertical: 'top', horizontal: 'center' }} + open={openSnackbar} + onClose={() => setOpenSnackbar(false)} + message="Please fill in the complete parameters before adding!!" + key={'top' + 'center'} + /> + </div> + ) +} + +export default AddPair diff --git a/xinference/web/ui/src/scenes/launch_model/index.js b/xinference/web/ui/src/scenes/launch_model/index.js index 29c0adee04..276ca0a4cd 100644 --- a/xinference/web/ui/src/scenes/launch_model/index.js +++ b/xinference/web/ui/src/scenes/launch_model/index.js @@ -6,14 +6,19 @@ import { useNavigate } from 'react-router-dom' import { ApiContext } from '../../components/apiContext' import ErrorMessageSnackBar from '../../components/errorMessageSnackBar' +import fetchWrapper from '../../components/fetchWrapper' import Title from '../../components/Title' +import { isValidBearerToken } from '../../components/utils' import LaunchCustom from './launchCustom' import LaunchLLM from './launchLLM' import LaunchModelComponent from './LaunchModelComponent' const LaunchModel = () => { - let endPoint = useContext(ApiContext).endPoint - const [value, setValue] = React.useState('1') + const [value, setValue] = React.useState( + sessionStorage.getItem('modelType') + ? sessionStorage.getItem('modelType') + : '/launch_model/llm' + ) const [gpuAvailable, setGPUAvailable] = useState(-1) const { setErrorMsg } = useContext(ApiContext) @@ -22,42 +27,36 @@ const LaunchModel = () => { const handleTabChange = (event, newValue) => { setValue(newValue) + navigate(newValue) + sessionStorage.setItem('modelType', newValue) + newValue === '/launch_model/custom/llm' + ? sessionStorage.setItem('subType', newValue) + : '' } useEffect(() => { - if (cookie.token === '' || cookie.token === undefined) { - return - } - if (cookie.token === 'need_auth') { + if ( + sessionStorage.getItem('auth') === 'true' && + !isValidBearerToken(sessionStorage.getItem('token')) && + !isValidBearerToken(cookie.token) + ) { navigate('/login', { replace: true }) - return } if (gpuAvailable === -1) { - fetch(endPoint + '/v1/cluster/devices', { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }).then((res) => { - if (!res.ok) { - // Usually, if some errors happen here, check if the cluster is available - res.json().then((errorData) => { - setErrorMsg( - `Server error: ${res.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - }) - } else { - res.json().then((data) => { - setGPUAvailable(parseInt(data, 10)) - }) - } - }) + fetchWrapper + .get('/v1/cluster/devices') + .then((data) => setGPUAvailable(parseInt(data, 10))) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403 && error.response.status !== 401) { + setErrorMsg(error.message) + } + }) } }, [cookie.token]) + useEffect(() => {}) return ( <Box m="20px"> <Title title="Launch Model" /> @@ -65,30 +64,40 @@ const LaunchModel = () => { <TabContext value={value}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <TabList value={value} onChange={handleTabChange} aria-label="tabs"> - <Tab label="Language Models" value="1" /> - <Tab label="Embedding Models" value="2" /> - <Tab label="Rerank Models" value="3" /> - <Tab label="Image Models" value="4" /> - <Tab label="Audio Models" value="5" /> - <Tab label="Custom Models" value="6" /> + <Tab label="Language Models" value="/launch_model/llm" /> + <Tab label="Embedding Models" value="/launch_model/embedding" /> + <Tab label="Rerank Models" value="/launch_model/rerank" /> + <Tab label="Image Models" value="/launch_model/image" /> + <Tab label="Audio Models" value="/launch_model/audio" /> + <Tab label="Video Models" value="/launch_model/video" /> + <Tab label="Custom Models" value="/launch_model/custom/llm" /> </TabList> </Box> - <TabPanel value="1" sx={{ padding: 0 }}> + <TabPanel value="/launch_model/llm" sx={{ padding: 0 }}> <LaunchLLM gpuAvailable={gpuAvailable} /> </TabPanel> - <TabPanel value="2" sx={{ padding: 0 }}> - <LaunchModelComponent modelType={'embedding'} /> + <TabPanel value="/launch_model/embedding" sx={{ padding: 0 }}> + <LaunchModelComponent + modelType={'embedding'} + gpuAvailable={gpuAvailable} + /> </TabPanel> - <TabPanel value="3" sx={{ padding: 0 }}> - <LaunchModelComponent modelType={'rerank'} /> + <TabPanel value="/launch_model/rerank" sx={{ padding: 0 }}> + <LaunchModelComponent + modelType={'rerank'} + gpuAvailable={gpuAvailable} + /> </TabPanel> - <TabPanel value="4" sx={{ padding: 0 }}> + <TabPanel value="/launch_model/image" sx={{ padding: 0 }}> <LaunchModelComponent modelType={'image'} /> </TabPanel> - <TabPanel value="5" sx={{ padding: 0 }}> + <TabPanel value="/launch_model/audio" sx={{ padding: 0 }}> <LaunchModelComponent modelType={'audio'} /> </TabPanel> - <TabPanel value="6" sx={{ padding: 0 }}> + <TabPanel value="/launch_model/video" sx={{ padding: 0 }}> + <LaunchModelComponent modelType={'video'} /> + </TabPanel> + <TabPanel value="/launch_model/custom/llm" sx={{ padding: 0 }}> <LaunchCustom gpuAvailable={gpuAvailable} /> </TabPanel> </TabContext> diff --git a/xinference/web/ui/src/scenes/launch_model/launchCustom.js b/xinference/web/ui/src/scenes/launch_model/launchCustom.js index 9d3a46f504..60b0355065 100644 --- a/xinference/web/ui/src/scenes/launch_model/launchCustom.js +++ b/xinference/web/ui/src/scenes/launch_model/launchCustom.js @@ -1,11 +1,15 @@ import { TabContext, TabList, TabPanel } from '@mui/lab' -import { Box, FormControl, Tab, TextField } from '@mui/material' +import { Box, FormControl, Tab } from '@mui/material' import React, { useContext, useEffect, useState } from 'react' +import { useNavigate } from 'react-router-dom' import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' +import fetchWrapper from '../../components/fetchWrapper' +import HotkeyFocusTextField from '../../components/hotkeyFocusTextField' import ModelCard from './modelCard' +const customType = ['llm', 'embedding', 'rerank', 'image', 'audio', 'flexible'] + const LaunchCustom = ({ gpuAvailable }) => { let endPoint = useContext(ApiContext).endPoint const [registrationData, setRegistrationData] = useState([]) @@ -14,14 +18,19 @@ const LaunchCustom = ({ gpuAvailable }) => { // States used for filtering const [searchTerm, setSearchTerm] = useState('') - const [value, setValue] = useState('1') + const [value, setValue] = useState(sessionStorage.getItem('subType')) - const handleTabChange = (event, newValue) => { + const navigate = useNavigate() + const handleTabChange = (_, newValue) => { + const type = + newValue.split('/')[3] === 'llm' ? 'LLM' : newValue.split('/')[3] + getData(type) setValue(newValue) - update() + navigate(newValue) + sessionStorage.setItem('subType', newValue) } - const handleChange = (event) => { + const handleSearchChange = (event) => { setSearchTerm(event.target.value) } @@ -33,97 +42,32 @@ const LaunchCustom = ({ gpuAvailable }) => { return modelName.includes(searchTerm.toLowerCase()) } - const update = async () => { - if (isCallingApi || isUpdatingModel) return + useEffect(() => { + const type = sessionStorage.getItem('subType').split('/')[3] + getData(type === 'llm' ? 'LLM' : type) + }, []) + const getData = async (type) => { + if (isCallingApi || isUpdatingModel) return try { setIsCallingApi(true) - const rerankResponse = await fetcher( - `${endPoint}/v1/model_registrations/rerank`, - { - method: 'GET', - } - ) - const rerankRegistrations = await rerankResponse.json() - const customRerankRegistrations = rerankRegistrations.filter( - (data) => !data.is_builtin - ) + const data = await fetchWrapper.get(`/v1/model_registrations/${type}`) + const customRegistrations = data.filter((data) => !data.is_builtin) - const embeddingResponse = await fetcher( - `${endPoint}/v1/model_registrations/embedding`, - { - method: 'GET', - } - ) - - const embeddingRegistrations = await embeddingResponse.json() - const customEmbeddingRegistrations = embeddingRegistrations.filter( - (data) => !data.is_builtin - ) - - const llmResponse = await fetcher( - `${endPoint}/v1/model_registrations/LLM`, - { - method: 'GET', - } - ) - const llmRegistrations = await llmResponse.json() - const customLLMRegistrations = llmRegistrations.filter( - (data) => !data.is_builtin - ) - - const newEmbeddingData = await Promise.all( - customEmbeddingRegistrations.map(async (registration) => { - const desc = await fetcher( - `${endPoint}/v1/model_registrations/embedding/${registration.model_name}`, - { - method: 'GET', - } + const newData = await Promise.all( + customRegistrations.map(async (registration) => { + const desc = await fetchWrapper.get( + `/v1/model_registrations/${type}/${registration.model_name}` ) return { - ...(await desc.json()), + ...desc, is_builtin: registration.is_builtin, } }) ) - - const newLLMData = await Promise.all( - customLLMRegistrations.map(async (registration) => { - const desc = await fetcher( - `${endPoint}/v1/model_registrations/LLM/${registration.model_name}`, - { - method: 'GET', - } - ) - - return { - ...(await desc.json()), - is_builtin: registration.is_builtin, - } - }) - ) - - const newRerankData = await Promise.all( - customRerankRegistrations.map(async (registration) => { - const desc = await fetcher( - `${endPoint}/v1/model_registrations/rerank/${registration.model_name}`, - { - method: 'GET', - } - ) - - return { - ...(await desc.json()), - is_builtin: registration.is_builtin, - } - }) - ) - - setRegistrationData( - newLLMData.concat(newEmbeddingData).concat(newRerankData) - ) + setRegistrationData(newData) } catch (error) { console.error('Error:', error) } finally { @@ -131,15 +75,19 @@ const LaunchCustom = ({ gpuAvailable }) => { } } - useEffect(() => { - update() - }, []) + const handlecustomDelete = (model_name) => { + setRegistrationData( + registrationData.filter((item) => { + return item.model_name !== model_name + }) + ) + } const style = { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', paddingLeft: '2rem', - paddingTop: '2rem', + paddingBottom: '2rem', gridGap: '2rem 0rem', } @@ -148,132 +96,62 @@ const LaunchCustom = ({ gpuAvailable }) => { <TabContext value={value}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <TabList value={value} onChange={handleTabChange} aria-label="tabs"> - <Tab label="Language Models" value="1" /> - <Tab label="Embedding Models" value="2" /> - <Tab label="Rerank Models" value="3" /> + <Tab label="Language Models" value="/launch_model/custom/llm" /> + <Tab + label="Embedding Models" + value="/launch_model/custom/embedding" + /> + <Tab label="Rerank Models" value="/launch_model/custom/rerank" /> + <Tab label="Image Models" value="/launch_model/custom/image" /> + <Tab label="Audio Models" value="/launch_model/custom/audio" /> + <Tab + label="Flexible Models" + value="/launch_model/custom/flexible" + /> </TabList> </Box> - <TabPanel value="1" sx={{ padding: 0 }}> - <div - style={{ - display: 'grid', - gridTemplateColumns: '1fr', - margin: '30px 2rem', - }} - > - <FormControl variant="outlined" margin="normal"> - <TextField - id="search" - type="search" - label="Search for custom model name" - value={searchTerm} - onChange={handleChange} - size="small" - /> - </FormControl> - </div> - <div style={style}> - {registrationData - .filter((registration) => filter(registration)) - .map((filteredRegistration) => { - if ( - !( - filteredRegistration.max_tokens && - filteredRegistration.dimensions - ) && - !( - filteredRegistration.model_type && - filteredRegistration.model_type === 'rerank' - ) - ) { - return ( - <ModelCard - url={endPoint} - modelData={filteredRegistration} - gpuAvailable={gpuAvailable} - is_custom={true} - /> - ) - } - })} - </div> - </TabPanel> - <TabPanel value="2" sx={{ padding: 0 }}> - <div - style={{ - display: 'grid', - gridTemplateColumns: '1fr', - margin: '30px 2rem', - }} - > - <FormControl variant="outlined" margin="normal"> - <TextField - id="search" - type="search" - label="Search for custom model name" - value={searchTerm} - onChange={handleChange} - size="small" - /> - </FormControl> - </div> - <div style={style}> - {registrationData - .filter((registration) => filter(registration)) - .map((filteredRegistration) => { - if ( - filteredRegistration.max_tokens && - filteredRegistration.dimensions - ) { - return ( - <ModelCard - url={endPoint} - modelData={filteredRegistration} - is_custom={true} - /> - ) - } - })} - </div> - </TabPanel> - <TabPanel value="3" sx={{ padding: 0 }}> - <div - style={{ - display: 'grid', - gridTemplateColumns: '1fr', - margin: '30px 2rem', - }} + {customType.map((item) => ( + <TabPanel + key={item} + value={`/launch_model/custom/${item}`} + sx={{ padding: 0 }} > - <FormControl variant="outlined" margin="normal"> - <TextField - id="search" - type="search" - label="Search for custom model name" - value={searchTerm} - onChange={handleChange} - size="small" - /> - </FormControl> - </div> - <div style={style}> - {registrationData - .filter((registration) => filter(registration)) - .map((filteredRegistration) => { - if ( - filteredRegistration.model_type && - filteredRegistration.model_type === 'rerank' - ) { - return ( - <ModelCard - url={endPoint} - modelData={filteredRegistration} - is_custom={true} - /> - ) - } - })} - </div> - </TabPanel> + <div + style={{ + display: 'grid', + gridTemplateColumns: '1fr', + margin: '30px 2rem', + }} + > + <FormControl variant="outlined" margin="normal"> + <HotkeyFocusTextField + id="search" + type="search" + label="Search for custom model name" + value={searchTerm} + onChange={handleSearchChange} + size="small" + hotkey="/" + /> + </FormControl> + </div> + <div style={style}> + {registrationData + .filter((registration) => filter(registration)) + .map((filteredRegistration) => ( + <ModelCard + key={filteredRegistration.model_name} + url={endPoint} + modelData={filteredRegistration} + gpuAvailable={gpuAvailable} + is_custom={true} + modelType={item === 'llm' ? 'LLM' : item} + onHandlecustomDelete={handlecustomDelete} + /> + ))} + </div> + </TabPanel> + ))} </TabContext> </Box> ) diff --git a/xinference/web/ui/src/scenes/launch_model/launchLLM.js b/xinference/web/ui/src/scenes/launch_model/launchLLM.js index a511670b11..79838b14e6 100644 --- a/xinference/web/ui/src/scenes/launch_model/launchLLM.js +++ b/xinference/web/ui/src/scenes/launch_model/launchLLM.js @@ -1,21 +1,23 @@ import { Box, + Chip, FormControl, InputLabel, MenuItem, Select, - TextField, } from '@mui/material' import React, { useContext, useEffect, useState } from 'react' import { useCookies } from 'react-cookie' import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' +import fetchWrapper from '../../components/fetchWrapper' +import HotkeyFocusTextField from '../../components/hotkeyFocusTextField' import ModelCard from './modelCard' +const modelAbilityArr = ['generate', 'chat', 'vision'] + const LaunchLLM = ({ gpuAvailable }) => { - let endPoint = useContext(ApiContext).endPoint - const { isCallingApi, setIsCallingApi } = useContext(ApiContext) + const { isCallingApi, setIsCallingApi, endPoint } = useContext(ApiContext) const { isUpdatingModel } = useContext(ApiContext) const { setErrorMsg } = useContext(ApiContext) const [cookie] = useCookies(['token']) @@ -23,72 +25,98 @@ const LaunchLLM = ({ gpuAvailable }) => { const [registrationData, setRegistrationData] = useState([]) // States used for filtering const [searchTerm, setSearchTerm] = useState('') - const [modelAbility, setModelAbility] = useState('all') - - const handleChange = (event) => { - setSearchTerm(event.target.value) - } - - const handleAbilityChange = (event) => { - setModelAbility(event.target.value) - } + const [modelAbility, setModelAbility] = useState('') + const [status, setStatus] = useState('') + const [statusArr, setStatusArr] = useState([]) + const [completeDeleteArr, setCompleteDeleteArr] = useState([]) + const [collectionArr, setCollectionArr] = useState([]) + const [filterArr, setFilterArr] = useState([]) const filter = (registration) => { - if (!registration || typeof searchTerm !== 'string') return false - const modelName = registration.model_name - ? registration.model_name.toLowerCase() - : '' - const modelDescription = registration.model_description - ? registration.model_description.toLowerCase() - : '' + if (searchTerm !== '') { + if (!registration || typeof searchTerm !== 'string') return false + const modelName = registration.model_name + ? registration.model_name.toLowerCase() + : '' + const modelDescription = registration.model_description + ? registration.model_description.toLowerCase() + : '' - if ( - !modelName.includes(searchTerm.toLowerCase()) && - !modelDescription.includes(searchTerm.toLowerCase()) - ) { + if ( + !modelName.includes(searchTerm.toLowerCase()) && + !modelDescription.includes(searchTerm.toLowerCase()) + ) { + return false + } + } + + if (modelAbility && registration.model_ability.indexOf(modelAbility) < 0) return false + + if (completeDeleteArr.includes(registration.model_name)) { + registration.model_specs.forEach((item) => { + item.cache_status = Array.isArray(item) ? [false] : false + }) } - if (modelAbility && modelAbility !== 'all') { - if (registration.model_ability.indexOf(modelAbility) < 0) { - return false + + if (statusArr.length === 1) { + if (statusArr[0] === 'cached') { + const judge = registration.model_specs.some((spec) => filterCache(spec)) + return judge && !completeDeleteArr.includes(registration.model_name) + } else { + return collectionArr?.includes(registration.model_name) } + } else if (statusArr.length > 1) { + const judge = registration.model_specs.some((spec) => filterCache(spec)) + return ( + judge && + !completeDeleteArr.includes(registration.model_name) && + collectionArr?.includes(registration.model_name) + ) } + return true } + const filterCache = (spec) => { + if (Array.isArray(spec.cache_status)) { + return spec.cache_status.some((cs) => cs) + } else { + return spec.cache_status === true + } + } + + const handleCompleteDelete = (model_name) => { + setCompleteDeleteArr([...completeDeleteArr, model_name]) + } + const update = () => { if ( isCallingApi || isUpdatingModel || - cookie.token === '' || - cookie.token === undefined || - cookie.token === 'need_auth' + (cookie.token !== 'no_auth' && !sessionStorage.getItem('token')) ) return try { setIsCallingApi(true) - fetcher(`${endPoint}/v1/model_registrations/LLM?detailed=true`, { - method: 'GET', - }).then((response) => { - if (!response.ok) { - response - .json() - .then((errData) => - setErrorMsg( - `Server error: ${response.status} - ${ - errData.detail || 'Unknown error' - }` - ) - ) - } else { - response.json().then((data) => { - const builtinRegistrations = data.filter((v) => v.is_builtin) - setRegistrationData(builtinRegistrations) - }) - } - }) + fetchWrapper + .get('/v1/model_registrations/LLM?detailed=true') + .then((data) => { + const builtinRegistrations = data.filter((v) => v.is_builtin) + setRegistrationData(builtinRegistrations) + const collectionData = JSON.parse( + localStorage.getItem('collectionArr') + ) + setCollectionArr(collectionData) + }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403 && error.response.status !== 401) { + setErrorMsg(error.message) + } + }) } catch (error) { console.error('Error:', error) } finally { @@ -100,11 +128,52 @@ const LaunchLLM = ({ gpuAvailable }) => { update() }, [cookie.token]) - const style = { - display: 'grid', - gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', - paddingLeft: '2rem', - gridGap: '2rem 0rem', + const getCollectionArr = (data) => { + setCollectionArr(data) + } + + const handleChangeFilter = (type, value) => { + if (type === 'modelAbility') { + setModelAbility(value) + setFilterArr([ + ...filterArr.filter((item) => { + return !modelAbilityArr.includes(item) + }), + value, + ]) + } else { + setStatus(value) + const arr = [ + ...filterArr.filter((item) => { + return item !== value + }), + value, + ] + setFilterArr(arr) + setStatusArr( + arr.filter((item) => { + return !modelAbilityArr.includes(item) + }) + ) + } + } + + const handleDeleteChip = (item) => { + setFilterArr( + filterArr.filter((subItem) => { + return subItem !== item + }) + ) + if (item === modelAbility) { + setModelAbility('') + } else { + setStatusArr( + statusArr.filter((subItem) => { + return subItem !== item + }) + ) + if (item === status) setStatus('') + } } return ( @@ -112,40 +181,76 @@ const LaunchLLM = ({ gpuAvailable }) => { <div style={{ display: 'grid', - gridTemplateColumns: '150px 1fr', + gridTemplateColumns: '150px 150px 1fr', columnGap: '20px', margin: '30px 2rem', }} > - <FormControl variant="outlined" margin="normal"> + <FormControl sx={{ marginTop: 2, minWidth: 120 }} size="small"> <InputLabel id="ability-select-label">Model Ability</InputLabel> <Select id="ability" labelId="ability-select-label" label="Model Ability" - onChange={handleAbilityChange} + onChange={(e) => handleChangeFilter('modelAbility', e.target.value)} value={modelAbility} size="small" sx={{ width: '150px' }} > - <MenuItem value="all">all</MenuItem> <MenuItem value="generate">generate</MenuItem> <MenuItem value="chat">chat</MenuItem> <MenuItem value="vision">vl-chat</MenuItem> </Select> </FormControl> + <FormControl sx={{ marginTop: 2, minWidth: 120 }} size="small"> + <InputLabel id="select-status">Status</InputLabel> + <Select + id="status" + labelId="select-status" + label="Status" + onChange={(e) => handleChangeFilter('status', e.target.value)} + value={status} + size="small" + sx={{ width: '150px' }} + > + <MenuItem value="cached">cached</MenuItem> + <MenuItem value="favorite">favorite</MenuItem> + </Select> + </FormControl> + <FormControl variant="outlined" margin="normal"> - <TextField + <HotkeyFocusTextField id="search" type="search" label="Search for model name and description" value={searchTerm} - onChange={handleChange} + onChange={(e) => setSearchTerm(e.target.value)} size="small" + hotkey="/" /> </FormControl> </div> - <div style={style}> + <div style={{ margin: '0 0 30px 30px' }}> + {filterArr.map((item, index) => ( + <Chip + key={index} + label={item} + variant="outlined" + size="small" + color="primary" + style={{ marginRight: 10 }} + onDelete={() => handleDeleteChip(item)} + /> + ))} + </div> + <div + style={{ + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', + paddingLeft: '2rem', + gridGap: '2rem 0rem', + }} + > {registrationData .filter((registration) => filter(registration)) .map((filteredRegistration) => ( @@ -155,6 +260,8 @@ const LaunchLLM = ({ gpuAvailable }) => { modelData={filteredRegistration} gpuAvailable={gpuAvailable} modelType={'LLM'} + onHandleCompleteDelete={handleCompleteDelete} + onGetCollectionArr={getCollectionArr} /> ))} </div> diff --git a/xinference/web/ui/src/scenes/launch_model/modelCard.js b/xinference/web/ui/src/scenes/launch_model/modelCard.js index 44246b714f..a4391f830a 100644 --- a/xinference/web/ui/src/scenes/launch_model/modelCard.js +++ b/xinference/web/ui/src/scenes/launch_model/modelCard.js @@ -1,17 +1,24 @@ +import './styles/modelCardStyle.css' + import { - AddCircle, ChatOutlined, + Close, + Delete, + EditNote, EditNoteOutlined, ExpandLess, ExpandMore, + Grade, HelpCenterOutlined, RocketLaunchOutlined, + StarBorder, UndoOutlined, } from '@mui/icons-material' -import DeleteIcon from '@mui/icons-material/Delete' import { Alert, + Backdrop, Box, + Button, Chip, CircularProgress, Collapse, @@ -23,18 +30,51 @@ import { ListItemButton, ListItemText, MenuItem, + Paper, Select, Snackbar, Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TablePagination, + TableRow, TextField, + Tooltip, } from '@mui/material' +import { styled } from '@mui/material/styles' import React, { useContext, useEffect, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' +import CopyComponent from '../../components/copyComponent/copyComponent' +import DeleteDialog from '../../components/deleteDialog' +import fetchWrapper from '../../components/fetchWrapper' import TitleTypography from '../../components/titleTypography' -import styles from './styles/modelCardStyle' +import AddPair from './components/addPair' + +const llmAllDataKey = [ + 'model_uid', + 'model_name', + 'model_type', + 'model_engine', + 'model_format', + 'model_size_in_billions', + 'quantization', + 'n_gpu', + 'n_gpu_layers', + 'replica', + 'request_limits', + 'worker_ip', + 'gpu_idx', + 'download_hub', + 'model_path', + 'peft_model_config', +] + +const csghubArr = ['qwen2-instruct'] const ModelCard = ({ url, @@ -42,15 +82,19 @@ const ModelCard = ({ gpuAvailable, modelType, is_custom = false, + onHandleCompleteDelete, + onHandlecustomDelete, + onGetCollectionArr, }) => { const [hover, setHover] = useState(false) const [selected, setSelected] = useState(false) const [requestLimitsAlert, setRequestLimitsAlert] = useState(false) const [GPUIdxAlert, setGPUIdxAlert] = useState(false) const [isOther, setIsOther] = useState(false) - const [isNotUnique, setisNotUnique] = useState(false) - const [defaultIndex, setDefaultIndex] = useState(-1) + const [isPeftModelConfig, setIsPeftModelConfig] = useState(false) const [openSnackbar, setOpenSnackbar] = useState(false) + const [openErrorSnackbar, setOpenErrorSnackbar] = useState(false) + const [errorSnackbarValue, setErrorSnackbarValue] = useState('') const { isCallingApi, setIsCallingApi } = useContext(ApiContext) const { isUpdatingModel } = useContext(ApiContext) const { setErrorMsg } = useContext(ApiContext) @@ -58,25 +102,44 @@ const ModelCard = ({ // Model parameter selections const [modelUID, setModelUID] = useState('') + const [modelEngine, setModelEngine] = useState('') const [modelFormat, setModelFormat] = useState('') const [modelSize, setModelSize] = useState('') const [quantization, setQuantization] = useState('') const [nGPU, setNGPU] = useState('auto') + const [nGpu, setNGpu] = useState(gpuAvailable === 0 ? 'CPU' : 'GPU') const [nGPULayers, setNGPULayers] = useState(-1) const [replica, setReplica] = useState(1) const [requestLimits, setRequestLimits] = useState('') - const [peftModelPath, setPeftModelPath] = useState('') - const [imageLoraLoadKwargs, setImageLoraLoadKwargs] = useState('') - const [imageLoraFuseKwargs, setImageLoraFuseKwargs] = useState('') const [workerIp, setWorkerIp] = useState('') const [GPUIdx, setGPUIdx] = useState('') + const [downloadHub, setDownloadHub] = useState('') + const [modelPath, setModelPath] = useState('') + const [enginesObj, setEnginesObj] = useState({}) + const [engineOptions, setEngineOptions] = useState([]) const [formatOptions, setFormatOptions] = useState([]) const [sizeOptions, setSizeOptions] = useState([]) const [quantizationOptions, setQuantizationOptions] = useState([]) const [customDeleted, setCustomDeleted] = useState(false) const [customParametersArr, setCustomParametersArr] = useState([]) - const [arrId, setArrId] = useState(0) + const [loraListArr, setLoraListArr] = useState([]) + const [imageLoraLoadKwargsArr, setImageLoraLoadKwargsArr] = useState([]) + const [imageLoraFuseKwargsArr, setImageLoraFuseKwargsArr] = useState([]) + const [isOpenCachedList, setIsOpenCachedList] = useState(false) + const [isDeleteCached, setIsDeleteCached] = useState(false) + const [cachedListArr, setCachedListArr] = useState([]) + const [cachedModelVersion, setCachedModelVersion] = useState('') + const [cachedRealPath, setCachedRealPath] = useState('') + const [page, setPage] = useState(0) + const [isDeleteCustomModel, setIsDeleteCustomModel] = useState(false) + const [isJsonShow, setIsJsonShow] = useState(false) + const [isHistory, setIsHistory] = useState(false) + const [customArr, setCustomArr] = useState([]) + const [loraArr, setLoraArr] = useState([]) + const [imageLoraLoadArr, setImageLoraLoadArr] = useState([]) + const [imageLoraFuseArr, setImageLoraFuseArr] = useState([]) + const [customParametersArrLength, setCustomParametersArrLength] = useState(0) const parentRef = useRef(null) @@ -85,10 +148,10 @@ const ModelCard = ({ } const isCached = (spec) => { - if (spec.model_format === 'pytorch') { - return spec.cache_status && spec.cache_status === true + if (Array.isArray(spec.cache_status)) { + return spec.cache_status.some((cs) => cs) } else { - return spec.cache_status && spec.cache_status.some((cs) => cs) + return spec.cache_status === true } } @@ -97,53 +160,83 @@ const ModelCard = ({ return size.toString().includes('_') ? size : parseInt(size, 10) } - // UseEffects for parameter selection, change options based on previous selections useEffect(() => { - if (modelData) { - if (modelData.model_specs) { - const modelFamily = modelData.model_specs - const formats = [ - ...new Set(modelFamily.map((spec) => spec.model_format)), - ] - setFormatOptions(formats) + let keyArr = [] + for (let key in enginesObj) { + keyArr.push(key) + } + if (keyArr.length) { + handleLlmHistory() + } + }, [enginesObj]) + + useEffect(() => { + if (modelEngine) { + const format = [ + ...new Set(enginesObj[modelEngine].map((item) => item.model_format)), + ] + setFormatOptions(format) + if (!isHistory || !format.includes(modelFormat)) { + setModelFormat('') + } + if (format.length === 1) { + setModelFormat(format[0]) } } - }, [modelData]) + }, [modelEngine]) useEffect(() => { - if (modelFormat && modelData) { - const modelFamily = modelData.model_specs + if (modelEngine && modelFormat) { const sizes = [ ...new Set( - modelFamily - .filter((spec) => spec.model_format === modelFormat) - .map((spec) => spec.model_size_in_billions) + enginesObj[modelEngine] + .filter((item) => item.model_format === modelFormat) + .map((item) => item.model_size_in_billions) ), ] setSizeOptions(sizes) + if ( + !isHistory || + (sizeOptions.length && + JSON.stringify(sizes) !== JSON.stringify(sizeOptions)) + ) { + setModelSize('') + } + if (sizes.length === 1) { + setModelSize(sizes[0]) + } } - }, [modelFormat, modelData]) + }, [modelEngine, modelFormat]) useEffect(() => { - if (modelFormat && modelSize && modelData) { - const modelFamily = modelData.model_specs + if (modelEngine && modelFormat && modelSize) { const quants = [ ...new Set( - modelFamily + enginesObj[modelEngine] .filter( - (spec) => - spec.model_format === modelFormat && - spec.model_size_in_billions === convertModelSize(modelSize) + (item) => + item.model_format === modelFormat && + item.model_size_in_billions === convertModelSize(modelSize) ) - .flatMap((spec) => spec.quantizations) + .flatMap((item) => item.quantizations) ), ] setQuantizationOptions(quants) + if (!isHistory || !quants.includes(quantization)) { + setQuantization('') + } + if (quants.length === 1) { + setQuantization(quants[0]) + } } - }, [modelFormat, modelSize, modelData]) + }, [modelEngine, modelFormat, modelSize]) useEffect(() => { - if (parentRef.current) { + setCustomParametersArrLength(customParametersArr.length) + if ( + parentRef.current && + customParametersArr.length > customParametersArrLength + ) { parentRef.current.scrollTo({ top: parentRef.current.scrollHeight, behavior: 'smooth', @@ -159,86 +252,152 @@ const ModelCard = ({ return ['auto', 'CPU'].concat(range(1, gpuAvailable)) } - const launchModel = (url) => { + const getNewNGPURange = () => { + if (gpuAvailable === 0) { + return ['CPU'] + } else { + return ['GPU', 'CPU'] + } + } + + const getModelEngine = (model_name) => { + fetchWrapper + .get(`/v1/engines/${model_name}`) + .then((data) => { + setEnginesObj(data) + setEngineOptions(Object.keys(data)) + setIsCallingApi(false) + }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403) { + setErrorMsg(error.message) + } + setIsCallingApi(false) + }) + } + + const launchModel = () => { if (isCallingApi || isUpdatingModel) { return } setIsCallingApi(true) - const modelDataWithID1 = { - // If user does not fill model_uid, pass null (None) to server and server generates it. - model_uid: modelUID.trim() === '' ? null : modelUID.trim(), - model_name: modelData.model_name, - model_type: modelType, - model_format: modelFormat, - model_size_in_billions: convertModelSize(modelSize), - quantization: quantization, - n_gpu: - parseInt(nGPU, 10) === 0 || nGPU === 'CPU' - ? null - : nGPU === 'auto' - ? 'auto' - : parseInt(nGPU, 10), - replica: replica, - request_limits: - requestLimits.trim() === '' ? null : Number(requestLimits.trim()), - peft_model_path: - peftModelPath.trim() === '' ? null : peftModelPath.trim(), - image_lora_load_kwargs: - imageLoraLoadKwargs.trim() === '' ? null : imageLoraLoadKwargs.trim(), - image_lora_fuse_kwargs: - imageLoraFuseKwargs.trim() === '' ? null : imageLoraFuseKwargs.trim(), - worker_ip: workerIp.trim() === '' ? null : workerIp.trim(), - gpu_idx: GPUIdx.trim() === '' ? null : handleGPUIdx(GPUIdx.trim()), - } + try { + const modelDataWithID_LLM = { + // If user does not fill model_uid, pass null (None) to server and server generates it. + model_uid: modelUID?.trim() === '' ? null : modelUID?.trim(), + model_name: modelData.model_name, + model_type: modelType, + model_engine: modelEngine, + model_format: modelFormat, + model_size_in_billions: convertModelSize(modelSize), + quantization: quantization, + n_gpu: + parseInt(nGPU, 10) === 0 || nGPU === 'CPU' + ? null + : nGPU === 'auto' + ? 'auto' + : parseInt(nGPU, 10), + replica: replica, + request_limits: + String(requestLimits)?.trim() === '' + ? null + : Number(String(requestLimits)?.trim()), + worker_ip: workerIp?.trim() === '' ? null : workerIp?.trim(), + gpu_idx: GPUIdx?.trim() === '' ? null : handleGPUIdx(GPUIdx?.trim()), + download_hub: downloadHub === '' ? null : downloadHub, + model_path: modelPath?.trim() === '' ? null : modelPath?.trim(), + } - const modelDataWithID2 = { - model_uid: modelUID.trim() === '' ? null : modelUID.trim(), - model_name: modelData.model_name, - model_type: modelType, - } + const modelDataWithID_other = { + model_uid: modelUID?.trim() === '' ? null : modelUID?.trim(), + model_name: modelData.model_name, + model_type: modelType, + replica: replica, + n_gpu: nGpu === 'GPU' ? 'auto' : null, + worker_ip: workerIp?.trim() === '' ? null : workerIp.trim(), + gpu_idx: GPUIdx?.trim() === '' ? null : handleGPUIdx(GPUIdx?.trim()), + download_hub: downloadHub === '' ? null : downloadHub, + model_path: modelPath?.trim() === '' ? null : modelPath?.trim(), + } - if (nGPULayers >= 0) { - modelDataWithID1.n_gpu_layers = nGPULayers - } + if (nGPULayers >= 0) { + modelDataWithID_LLM.n_gpu_layers = nGPULayers + } - if (customParametersArr.length) { - customParametersArr.forEach((item) => { - modelDataWithID1[item.key] = handleValueType(item.value) - }) - } + if ( + loraListArr.length || + imageLoraLoadKwargsArr.length || + imageLoraFuseKwargsArr.length + ) { + const peft_model_config = {} + if (imageLoraLoadKwargsArr.length) { + const image_lora_load_kwargs = {} + imageLoraLoadKwargsArr.forEach((item) => { + image_lora_load_kwargs[item.key] = handleValueType(item.value) + }) + peft_model_config['image_lora_load_kwargs'] = image_lora_load_kwargs + } + if (imageLoraFuseKwargsArr.length) { + const image_lora_fuse_kwargs = {} + imageLoraFuseKwargsArr.forEach((item) => { + image_lora_fuse_kwargs[item.key] = handleValueType(item.value) + }) + peft_model_config['image_lora_fuse_kwargs'] = image_lora_fuse_kwargs + } + if (loraListArr.length) { + const lora_list = loraListArr + lora_list.map((item) => { + delete item.id + }) + peft_model_config['lora_list'] = lora_list + } + modelDataWithID_LLM['peft_model_config'] = peft_model_config + } - const modelDataWithID = - modelType === 'LLM' ? modelDataWithID1 : modelDataWithID2 + const modelDataWithID = + modelType === 'LLM' ? modelDataWithID_LLM : modelDataWithID_other - // First fetcher request to initiate the model - fetcher(url + '/v1/models', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(modelDataWithID), - }) - .then((response) => { - if (!response.ok) { - // Assuming the server returns error details in JSON format - response.json().then((errorData) => { - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` + if (customParametersArr.length) { + customParametersArr.forEach((item) => { + modelDataWithID[item.key] = handleValueType(item.value) + }) + } + + // First fetcher request to initiate the model + fetchWrapper + .post('/v1/models', modelDataWithID) + .then(() => { + navigate(`/running_models/${modelType}`) + sessionStorage.setItem( + 'runningModelType', + `/running_models/${modelType}` + ) + let historyArr = JSON.parse(localStorage.getItem('historyArr')) || [] + if (!historyArr.some((item) => deepEqual(item, modelDataWithID))) { + historyArr = historyArr.filter( + (item) => item.model_name !== modelDataWithID.model_name ) - }) - } else { - navigate('/running_models') - } - setIsCallingApi(false) - }) - .catch((error) => { - console.error('Error:', error) - setIsCallingApi(false) - }) + historyArr.push(modelDataWithID) + } + localStorage.setItem('historyArr', JSON.stringify(historyArr)) + + setIsCallingApi(false) + }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403) { + setErrorMsg(error.message) + } + setIsCallingApi(false) + }) + } catch (error) { + setOpenErrorSnackbar(true) + setErrorSnackbarValue(`${error}`) + setIsCallingApi(false) + } } const handleGPUIdx = (data) => { @@ -251,63 +410,45 @@ const ModelCard = ({ const handeCustomDelete = (e) => { e.stopPropagation() - fetcher(url + `/v1/model_registrations/LLM/${modelData.model_name}`, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - }, - }) - .then(() => { - setCustomDeleted(true) - }) - .catch(console.error) - } - - const updateCustomParametersArr = (index, type, newValue) => { - setCustomParametersArr( - customParametersArr.map((pair, subIndex) => { - if (subIndex === index) { - return { ...pair, [type]: newValue } - } - return pair - }) - ) - if (type === 'key') { - setDefaultIndex(-1) - setisNotUnique(false) - customParametersArr.forEach((pair) => { - if (pair.key === newValue) { - setDefaultIndex(index) - setisNotUnique(true) - } - }) + const subType = sessionStorage.getItem('subType').split('/') + if (subType) { + subType[3] + fetchWrapper + .delete( + `/v1/model_registrations/${ + subType[3] === 'llm' ? 'LLM' : subType[3] + }/${modelData.model_name}` + ) + .then(() => { + setCustomDeleted(true) + onHandlecustomDelete(modelData.model_name) + setIsDeleteCustomModel(false) + }) + .catch((error) => { + console.error(error) + if (error.response.status !== 403) { + setErrorMsg(error.message) + } + }) } } - const judgeCustomParameters = () => { + const judgeArr = (arr, keysArr) => { if ( - customParametersArr.length && - customParametersArr[customParametersArr.length - 1].key !== '' && - customParametersArr[customParametersArr.length - 1].value !== '' + arr.length && + arr[arr.length - 1][keysArr[0]] !== '' && + arr[arr.length - 1][keysArr[1]] !== '' ) { return true - } else if (customParametersArr.length === 0) { + } else if (arr.length === 0) { return true } else { return false } } - const handleDeleteCustomParameters = (index) => { - setDefaultIndex(-1) - setCustomParametersArr( - customParametersArr.filter((pair, subIndex) => { - return index !== subIndex - }) - ) - } - const handleValueType = (str) => { + str = String(str) if (str.toLowerCase() === 'none') { return null } else if (str.toLowerCase() === 'true') { @@ -321,121 +462,373 @@ const ModelCard = ({ } } - // Set two different states based on mouse hover - return ( - <Box - style={hover ? styles.containerSelected : styles.container} - onMouseEnter={() => setHover(true)} - onMouseLeave={() => setHover(false)} - onClick={() => { - if (!selected && !customDeleted) { - setSelected(true) + const StyledTableRow = styled(TableRow)(({ theme }) => ({ + '&:nth-of-type(odd)': { + backgroundColor: theme.palette.action.hover, + }, + })) + + const emptyRows = + page >= 0 ? Math.max(0, (1 + page) * 5 - cachedListArr.length) : 0 + + const handleChangePage = (_, newPage) => { + setPage(newPage) + } + + const handleOpenCachedList = () => { + setIsOpenCachedList(true) + getCachedList() + document.body.style.overflow = 'hidden' + } + + const handleCloseCachedList = () => { + document.body.style.overflow = 'auto' + setHover(false) + setIsOpenCachedList(false) + if (cachedListArr.length === 0) { + onHandleCompleteDelete(modelData.model_name) + } + } + + const getCachedList = () => { + fetchWrapper + .get(`/v1/cache/models?model_name=${modelData.model_name}`) + .then((data) => setCachedListArr(data.list)) + .catch((error) => { + console.error(error) + if (error.response.status !== 403) { + setErrorMsg(error.message) } - }} - > - {modelType === 'LLM' ? ( - <Box style={styles.descriptionCard}> - {is_custom && ( - <Stack - direction="row" - justifyContent="space-evenly" - alignItems="center" - spacing={1} - > - <TitleTypography value={modelData.model_name} /> - <IconButton - aria-label="delete" - onClick={handeCustomDelete} - disabled={customDeleted} - > - <DeleteIcon /> - </IconButton> - </Stack> - )} - {!is_custom && <TitleTypography value={modelData.model_name} />} - <Stack - spacing={1} - direction="row" - useFlexGap - flexWrap="wrap" - sx={{ marginLeft: 1 }} - > - {(() => { - return modelData.model_lang.map((v) => { - return <Chip label={v} variant="outlined" size="small" /> - }) - })()} - {(() => { - if (modelData.model_specs.some((spec) => isCached(spec))) { - return <Chip label="Cached" variant="outlined" size="small" /> - } - })()} - {(() => { - if (is_custom && customDeleted) { - return <Chip label="Deleted" variant="outlined" size="small" /> - } - })()} - </Stack> - {modelData.model_description && ( - <p style={styles.p} title={modelData.model_description}> - {modelData.model_description} - </p> - )} + }) + } - <div style={styles.iconRow}> - <div style={styles.iconItem}> - <span style={styles.boldIconText}> - {Math.floor(modelData.context_length / 1000)}K - </span> - <small style={styles.smallText}>context length</small> - </div> - {(() => { - if (modelData.model_ability.includes('chat')) { - return ( - <div style={styles.iconItem}> - <ChatOutlined style={styles.muiIcon} /> - <small style={styles.smallText}>chat model</small> - </div> - ) - } else if (modelData.model_ability.includes('generate')) { - return ( - <div style={styles.iconItem}> - <EditNoteOutlined style={styles.muiIcon} /> - <small style={styles.smallText}>generate model</small> - </div> - ) - } else { - return ( - <div style={styles.iconItem}> - <HelpCenterOutlined style={styles.muiIcon} /> - <small style={styles.smallText}>other model</small> - </div> - ) - } - })()} - </div> - </Box> - ) : ( - <Box style={styles.descriptionCard}> - <div style={styles.titleContainer}> + const handleOpenDeleteCachedDialog = (real_path, model_version) => { + setCachedRealPath(real_path) + setCachedModelVersion(model_version) + setIsDeleteCached(true) + } + + const handleDeleteCached = () => { + fetchWrapper + .delete(`/v1/cache/models?model_version=${cachedModelVersion}`) + .then(() => { + const cachedArr = cachedListArr.filter( + (item) => item.real_path !== cachedRealPath + ) + setCachedListArr(cachedArr) + setIsDeleteCached(false) + if (cachedArr.length) { + if ( + (page + 1) * 5 >= cachedListArr.length && + cachedArr.length % 5 === 0 + ) { + setPage(cachedArr.length / 5 - 1) + } + } + }) + .catch((error) => { + console.error(error) + if (error.response.status !== 403) { + setErrorMsg(error.message) + } + }) + } + + const handleJsonDataPresentation = () => { + const arr = sessionStorage.getItem('subType').split('/') + sessionStorage.setItem( + 'registerModelType', + `/register_model/${arr[arr.length - 1]}` + ) + sessionStorage.setItem('customJsonData', JSON.stringify(modelData)) + navigate(`/register_model/${arr[arr.length - 1]}/${modelData.model_name}`) + } + + const handleGetHistory = () => { + const historyArr = JSON.parse(localStorage.getItem('historyArr')) || [] + return historyArr.filter((item) => item.model_name === modelData.model_name) + } + + const handleLlmHistory = () => { + const arr = handleGetHistory() + if (arr.length) { + const { + model_engine, + model_format, + model_size_in_billions, + quantization, + n_gpu, + n_gpu_layers, + replica, + model_uid, + request_limits, + worker_ip, + gpu_idx, + download_hub, + model_path, + peft_model_config, + } = arr[0] + + if (!engineOptions.includes(model_engine)) { + setModelEngine('') + } else { + setModelEngine(model_engine || '') + } + setModelFormat(model_format || '') + setModelSize(String(model_size_in_billions) || '') + setQuantization(quantization || '') + setNGPU(n_gpu || 'auto') + if (n_gpu_layers >= 0) { + setNGPULayers(n_gpu_layers) + } else { + setNGPULayers(-1) + } + setReplica(replica || 1) + setModelUID(model_uid || '') + setRequestLimits(request_limits || '') + setWorkerIp(worker_ip || '') + setGPUIdx(gpu_idx?.join(',') || '') + setDownloadHub(download_hub || '') + setModelPath(model_path || '') + + let loraData = [] + peft_model_config?.lora_list?.forEach((item) => { + loraData.push({ + lora_name: item.lora_name, + local_path: item.local_path, + }) + }) + setLoraArr(loraData) + + let ImageLoraLoadData = [] + for (let key in peft_model_config?.image_lora_load_kwargs) { + ImageLoraLoadData.push({ + key: key, + value: peft_model_config?.image_lora_load_kwargs[key], + }) + } + setImageLoraLoadArr(ImageLoraLoadData) + + let ImageLoraFuseData = [] + for (let key in peft_model_config?.image_lora_fuse_kwargs) { + ImageLoraFuseData.push({ + key: key, + value: peft_model_config?.image_lora_fuse_kwargs[key], + }) + } + setImageLoraFuseArr(ImageLoraFuseData) + + let customData = [] + for (let key in arr[0]) { + !llmAllDataKey.includes(key) && + customData.push({ key: key, value: arr[0][key] }) + } + setCustomArr(customData) + + if ( + model_uid || + request_limits || + worker_ip || + gpu_idx?.join(',') || + download_hub || + model_path + ) + setIsOther(true) + + if ( + loraData.length || + ImageLoraLoadData.length || + ImageLoraFuseData.length + ) { + setIsOther(true) + setIsPeftModelConfig(true) + } + } + } + + const handleOtherHistory = () => { + const arr = handleGetHistory() + if (arr.length) { + setModelUID(arr[0].model_uid || '') + setReplica(arr[0].replica || 1) + setNGpu(arr[0].n_gpu === 'auto' ? 'GPU' : 'CPU') + setGPUIdx(arr[0].gpu_idx?.join(',') || '') + setWorkerIp(arr[0].worker_ip || '') + setDownloadHub(arr[0].download_hub || '') + setModelPath(arr[0].model_path || '') + + let customData = [] + for (let key in arr[0]) { + !llmAllDataKey.includes(key) && + customData.push({ key: key, value: arr[0][key] }) + } + setCustomArr(customData) + } + } + + const deepEqual = (obj1, obj2) => { + if (obj1 === obj2) return true + if ( + typeof obj1 !== 'object' || + typeof obj2 !== 'object' || + obj1 == null || + obj2 == null + ) { + return false + } + + let keysA = Object.keys(obj1) + let keysB = Object.keys(obj2) + if (keysA.length !== keysB.length) return false + for (let key of keysA) { + if (!keysB.includes(key) || !deepEqual(obj1[key], obj2[key])) { + return false + } + } + return true + } + + const handleCollection = (bool) => { + setHover(false) + + let collectionArr = JSON.parse(localStorage.getItem('collectionArr')) || [] + if (bool) { + collectionArr.push(modelData.model_name) + } else { + collectionArr = collectionArr.filter( + (item) => item !== modelData.model_name + ) + } + localStorage.setItem('collectionArr', JSON.stringify(collectionArr)) + + onGetCollectionArr(collectionArr) + } + + const handleDeleteChip = () => { + const arr = JSON.parse(localStorage.getItem('historyArr')) + const newArr = arr.filter( + (item) => item.model_name !== modelData.model_name + ) + localStorage.setItem('historyArr', JSON.stringify(newArr)) + setIsHistory(false) + if (modelType === 'LLM') { + setModelEngine('') + setModelFormat('') + setModelSize('') + setQuantization('') + setNGPU('auto') + setReplica(1) + setModelUID('') + setRequestLimits('') + setWorkerIp('') + setGPUIdx('') + setDownloadHub('') + setModelPath('') + setLoraArr([]) + setImageLoraLoadArr([]) + setImageLoraFuseArr([]) + setCustomArr([]) + setIsOther(false) + setIsPeftModelConfig(false) + } else { + setModelUID('') + setReplica(1) + setNGpu(gpuAvailable === 0 ? 'CPU' : 'GPU') + setGPUIdx('') + setWorkerIp('') + setDownloadHub('') + setModelPath('') + } + } + + // Set two different states based on mouse hover + return ( + <> + <Paper + id={modelData.model_name} + className="container" + onMouseEnter={() => setHover(true)} + onMouseLeave={() => setHover(false)} + onClick={() => { + if (!selected && !customDeleted) { + const arr = handleGetHistory() + if (arr.length) setIsHistory(true) + setSelected(true) + if (modelType === 'LLM') { + getModelEngine(modelData.model_name) + } else { + handleOtherHistory() + } + } + }} + elevation={hover ? 24 : 4} + > + {modelType === 'LLM' ? ( + <Box className="descriptionCard"> {is_custom && ( - <Stack - direction="row" - justifyContent="space-evenly" - alignItems="center" - spacing={1} - > + <div className="cardTitle"> <TitleTypography value={modelData.model_name} /> - <IconButton - aria-label="delete" - onClick={handeCustomDelete} - disabled={customDeleted} - > - <DeleteIcon /> - </IconButton> - </Stack> + <div className="iconButtonBox"> + <Tooltip title={'Edit'} placement="top"> + <IconButton + aria-label="show" + onClick={(e) => { + e.stopPropagation() + setIsJsonShow(true) + }} + > + <EditNote /> + </IconButton> + </Tooltip> + <Tooltip title={'delete'} placement="top"> + <IconButton + aria-label="delete" + onClick={(e) => { + e.stopPropagation() + setIsDeleteCustomModel(true) + }} + > + <Delete /> + </IconButton> + </Tooltip> + </div> + </div> )} - {!is_custom && <TitleTypography value={modelData.model_name} />} + {!is_custom && ( + <div className="cardTitle"> + <TitleTypography value={modelData.model_name} /> + <div className="iconButtonBox"> + {JSON.parse(localStorage.getItem('collectionArr'))?.includes( + modelData.model_name + ) ? ( + <Tooltip title={'Unfavorite'} placement="top"> + <IconButton + aria-label="collection" + onClick={(e) => { + e.stopPropagation() + handleCollection(false) + }} + > + <Grade style={{ color: 'rgb(255, 206, 0)' }} /> + </IconButton> + </Tooltip> + ) : ( + <Tooltip title={'Favorite'} placement="top"> + <IconButton + aria-label="cancellation-of-collections" + onClick={(e) => { + e.stopPropagation() + handleCollection(true) + }} + > + <StarBorder /> + </IconButton> + </Tooltip> + )} + </div> + </div> + )} + <Stack spacing={1} direction="row" @@ -443,26 +836,30 @@ const ModelCard = ({ flexWrap="wrap" sx={{ marginLeft: 1 }} > - {(() => { - if (modelData.language) { - return modelData.language.map((v) => { - return <Chip label={v} variant="outlined" size="small" /> + {modelData.model_lang && + (() => { + return modelData.model_lang.map((v) => { + return ( + <Chip key={v} label={v} variant="outlined" size="small" /> + ) }) - } else if (modelData.model_family) { + })()} + {(() => { + if ( + modelData.model_specs && + modelData.model_specs.some((spec) => isCached(spec)) + ) { return ( <Chip - label={modelData.model_family} + label="Cached" variant="outlined" size="small" + deleteIcon={<EditNote />} + onDelete={handleOpenCachedList} /> ) } })()} - {(() => { - if (modelData.cache_status) { - return <Chip label="Cached" variant="outlined" size="small" /> - } - })()} {(() => { if (is_custom && customDeleted) { return ( @@ -471,37 +868,223 @@ const ModelCard = ({ } })()} </Stack> - </div> - {modelData.dimensions && ( - <div style={styles.iconRow}> - <div style={styles.iconItem}> - <span style={styles.boldIconText}>{modelData.dimensions}</span> - <small style={styles.smallText}>dimensions</small> - </div> - <div style={styles.iconItem}> - <span style={styles.boldIconText}>{modelData.max_tokens}</span> - <small style={styles.smallText}>max tokens</small> + {modelData.model_description && ( + <p className="p" title={modelData.model_description}> + {modelData.model_description} + </p> + )} + + <div className="iconRow"> + <div className="iconItem"> + <span className="boldIconText"> + {Math.floor(modelData.context_length / 1000)}K + </span> + <small className="smallText">context length</small> </div> + {(() => { + if ( + modelData.model_ability && + modelData.model_ability.includes('chat') + ) { + return ( + <div className="iconItem"> + <ChatOutlined className="muiIcon" /> + <small className="smallText">chat model</small> + </div> + ) + } else if ( + modelData.model_ability && + modelData.model_ability.includes('generate') + ) { + return ( + <div className="iconItem"> + <EditNoteOutlined className="muiIcon" /> + <small className="smallText">generate model</small> + </div> + ) + } else { + return ( + <div className="iconItem"> + <HelpCenterOutlined className="muiIcon" /> + <small className="smallText">other model</small> + </div> + ) + } + })()} </div> - )} - {!selected && hover && ( - <p style={styles.instructionText}> - Click with mouse to launch the model - </p> - )} - </Box> - )} + </Box> + ) : ( + <Box className="descriptionCard"> + <div className="titleContainer"> + {is_custom && ( + <div className="cardTitle"> + <TitleTypography value={modelData.model_name} /> + <div className="iconButtonBox"> + <Tooltip title={'Edit'} placement="top"> + <IconButton + aria-label="show" + onClick={(e) => { + e.stopPropagation() + setIsJsonShow(true) + }} + > + <EditNote /> + </IconButton> + </Tooltip> + <Tooltip title={'delete'} placement="top"> + <IconButton + aria-label="delete" + onClick={(e) => { + e.stopPropagation() + setIsDeleteCustomModel(true) + }} + disabled={customDeleted} + > + <Delete /> + </IconButton> + </Tooltip> + </div> + </div> + )} + {!is_custom && ( + <div className="cardTitle"> + <TitleTypography value={modelData.model_name} /> + <div className="iconButtonBox"> + {JSON.parse( + localStorage.getItem('collectionArr') + )?.includes(modelData.model_name) ? ( + <Tooltip title={'Unfavorite'} placement="top"> + <IconButton + aria-label="collection" + onClick={(e) => { + e.stopPropagation() + handleCollection(false) + }} + > + <Grade style={{ color: 'rgb(255, 206, 0)' }} /> + </IconButton> + </Tooltip> + ) : ( + <Tooltip title={'Favorite'} placement="top"> + <IconButton + aria-label="cancellation-of-collections" + onClick={(e) => { + e.stopPropagation() + handleCollection(true) + }} + > + <StarBorder /> + </IconButton> + </Tooltip> + )} + </div> + </div> + )} + + <Stack + spacing={1} + direction="row" + useFlexGap + flexWrap="wrap" + sx={{ marginLeft: 1 }} + > + {(() => { + if (modelData.language) { + return modelData.language.map((v) => { + return <Chip label={v} variant="outlined" size="small" /> + }) + } else if (modelData.model_family) { + return ( + <Chip + label={modelData.model_family} + variant="outlined" + size="small" + /> + ) + } + })()} + {(() => { + if (modelData.cache_status) { + return ( + <Chip + label="Cached" + variant="outlined" + size="small" + deleteIcon={<EditNote />} + onDelete={handleOpenCachedList} + /> + ) + } + })()} + {(() => { + if (is_custom && customDeleted) { + return ( + <Chip label="Deleted" variant="outlined" size="small" /> + ) + } + })()} + </Stack> + {modelData.model_description && ( + <p className="p" title={modelData.model_description}> + {modelData.model_description} + </p> + )} + </div> + {modelData.dimensions && ( + <div className="iconRow"> + <div className="iconItem"> + <span className="boldIconText">{modelData.dimensions}</span> + <small className="smallText">dimensions</small> + </div> + <div className="iconItem"> + <span className="boldIconText">{modelData.max_tokens}</span> + <small className="smallText">max tokens</small> + </div> + </div> + )} + {!selected && hover && ( + <p className="instructionText"> + Click with mouse to launch the model + </p> + )} + </Box> + )} + </Paper> + + <DeleteDialog + text={ + 'Are you sure to delete this custom model? This behavior is irreversible.' + } + isDelete={isDeleteCustomModel} + onHandleIsDelete={() => setIsDeleteCustomModel(false)} + onHandleDelete={handeCustomDelete} + /> <Drawer open={selected} - onClose={() => setSelected(false)} + onClose={() => { + setSelected(false) + setHover(false) + }} anchor={'right'} > - <div style={styles.drawerCard}> - <TitleTypography value={modelData.model_name} /> + <div className="drawerCard"> + <div style={{ display: 'flex', alignItems: 'center' }}> + <TitleTypography value={modelData.model_name} /> + {isHistory && ( + <Chip + label="Last Config" + variant="outlined" + size="small" + color="primary" + onDelete={handleDeleteChip} + /> + )} + </div> + {modelType === 'LLM' ? ( <Box ref={parentRef} - style={styles.formContainer} + className="formContainer" display="flex" flexDirection="column" width="100%" @@ -510,6 +1093,45 @@ const ModelCard = ({ <Grid rowSpacing={0} columnSpacing={1}> <Grid item xs={12}> <FormControl variant="outlined" margin="normal" fullWidth> + <InputLabel id="modelEngine-label">Model Engine</InputLabel> + <Select + labelId="modelEngine-label" + value={modelEngine} + onChange={(e) => setModelEngine(e.target.value)} + label="Model Engine" + > + {engineOptions.map((engine) => { + const subArr = [] + enginesObj[engine].forEach((item) => { + subArr.push(item.model_format) + }) + const arr = [...new Set(subArr)] + const specs = modelData.model_specs.filter((spec) => + arr.includes(spec.model_format) + ) + + const cached = specs.some((spec) => isCached(spec)) + + const displayedEngine = cached + ? engine + ' (cached)' + : engine + + return ( + <MenuItem key={engine} value={engine}> + {displayedEngine} + </MenuItem> + ) + })} + </Select> + </FormControl> + </Grid> + <Grid item xs={12}> + <FormControl + variant="outlined" + margin="normal" + fullWidth + disabled={!modelEngine} + > <InputLabel id="modelFormat-label">Model Format</InputLabel> <Select labelId="modelFormat-label" @@ -523,6 +1145,7 @@ const ModelCard = ({ ) const cached = specs.some((spec) => isCached(spec)) + const displayedFormat = cached ? format + ' (cached)' : format @@ -557,6 +1180,7 @@ const ModelCard = ({ (spec) => spec.model_size_in_billions === size ) const cached = specs.some((spec) => isCached(spec)) + const displayedSize = cached ? size + ' (cached)' : size return ( @@ -584,7 +1208,7 @@ const ModelCard = ({ onChange={(e) => setQuantization(e.target.value)} label="Quantization" > - {quantizationOptions.map((quant, index) => { + {quantizationOptions.map((quant) => { const specs = modelData.model_specs .filter((spec) => spec.model_format === modelFormat) .filter( @@ -593,10 +1217,15 @@ const ModelCard = ({ convertModelSize(modelSize) ) - const cached = - modelFormat === 'pytorch' - ? specs[0]?.cache_status ?? false === true - : specs[0]?.cache_status?.[index] ?? false === true + const spec = specs.find((s) => { + return s.quantizations.includes(quant) + }) + const cached = Array.isArray(spec?.cache_status) + ? spec?.cache_status[ + spec?.quantizations.indexOf(quant) + ] + : spec?.cache_status + const displayedQuant = cached ? quant + ' (cached)' : quant @@ -670,8 +1299,13 @@ const ModelCard = ({ </FormControl> </Grid> <ListItemButton onClick={() => setIsOther(!isOther)}> - <ListItemText primary="Optional Configurations" /> - {isOther ? <ExpandLess /> : <ExpandMore />} + <div style={{ display: 'flex', alignItems: 'center' }}> + <ListItemText + primary="Optional Configurations" + style={{ marginRight: 10 }} + /> + {isOther ? <ExpandLess /> : <ExpandMore />} + </div> </ListItemButton> <Collapse in={isOther} timeout="auto" unmountOnExit> <Grid item xs={12}> @@ -710,36 +1344,6 @@ const ModelCard = ({ )} </FormControl> </Grid> - <Grid item xs={12}> - <FormControl variant="outlined" margin="normal" fullWidth> - <TextField - variant="outlined" - value={peftModelPath} - label="(Optional) Peft Model Path, PEFT (Parameter-Efficient Fine-Tuning) model path" - onChange={(e) => setPeftModelPath(e.target.value)} - /> - </FormControl> - </Grid> - <Grid item xs={12}> - <FormControl variant="outlined" margin="normal" fullWidth> - <TextField - variant="outlined" - value={imageLoraLoadKwargs} - label="(Optional) Image Lora Load Kwargs, lora load parameters for image model" - onChange={(e) => setImageLoraLoadKwargs(e.target.value)} - /> - </FormControl> - </Grid> - <Grid item xs={12}> - <FormControl variant="outlined" margin="normal" fullWidth> - <TextField - variant="outlined" - value={imageLoraFuseKwargs} - label="(Optional) Image Lora Fuse Kwargs, lora fuse parameters for image model" - onChange={(e) => setImageLoraFuseKwargs(e.target.value)} - /> - </FormControl> - </Grid> <Grid item xs={12}> <FormControl variant="outlined" margin="normal" fullWidth> <TextField @@ -775,88 +1379,113 @@ const ModelCard = ({ )} </FormControl> </Grid> - </Collapse> - <Box> - <div - style={{ - display: 'flex', - alignItems: 'center', - margin: '10px 0 0 15px', - }} + <Grid item xs={12}> + <FormControl variant="outlined" margin="normal" fullWidth> + <InputLabel id="quantization-label"> + (Optional) Download_hub + </InputLabel> + <Select + labelId="download_hub-label" + value={downloadHub} + onChange={(e) => { + e.target.value === 'none' + ? setDownloadHub('') + : setDownloadHub(e.target.value) + }} + label="(Optional) Download_hub" + > + {(csghubArr.includes(modelData.model_name) + ? ['none', 'huggingface', 'modelscope', 'csghub'] + : ['none', 'huggingface', 'modelscope'] + ).map((item) => { + return ( + <MenuItem key={item} value={item}> + {item} + </MenuItem> + ) + })} + </Select> + </FormControl> + </Grid> + <Grid item xs={12}> + <FormControl variant="outlined" margin="normal" fullWidth> + <TextField + variant="outlined" + value={modelPath} + label="(Optional) Model Path, For PyTorch, provide the model directory. For GGML/GGUF, provide the model file path." + onChange={(e) => setModelPath(e.target.value)} + /> + </FormControl> + </Grid> + <ListItemButton + onClick={() => setIsPeftModelConfig(!isPeftModelConfig)} > - <div> - Additional parameters passed to the inference engine + <div style={{ display: 'flex', alignItems: 'center' }}> + <ListItemText + primary="Lora Config" + style={{ marginRight: 10 }} + /> + {isPeftModelConfig ? <ExpandLess /> : <ExpandMore />} </div> - <IconButton - color="primary" - onClick={() => { - setArrId(arrId + 1) - judgeCustomParameters() - ? setCustomParametersArr([ - ...customParametersArr, - { id: arrId, key: '', value: '' }, - ]) - : setOpenSnackbar(true) + </ListItemButton> + <Collapse + in={isPeftModelConfig} + timeout="auto" + unmountOnExit + style={{ marginLeft: '30px' }} + > + <AddPair + customData={{ + title: 'Lora Model Config', + key: 'lora_name', + value: 'local_path', }} - > - <AddCircle /> - </IconButton> - </div> - <Box> - {customParametersArr.map((item, index) => { - return ( - <Box> - <div - key={item.id} - style={{ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - marginTop: '10px', - }} - > - <TextField - label="key" - value={item.key} - onChange={(e) => { - updateCustomParametersArr( - index, - 'key', - e.target.value - ) - }} - style={{ width: '44%' }} - /> - <TextField - label="value" - value={item.value} - onChange={(e) => { - updateCustomParametersArr( - index, - 'value', - e.target.value - ) - }} - style={{ width: '44%' }} - /> - <IconButton - aria-label="delete" - onClick={() => - handleDeleteCustomParameters(index) - } - style={{ marginLeft: '10px' }} - > - <DeleteIcon /> - </IconButton> - </div> - {isNotUnique && defaultIndex === index && ( - <Alert severity="error">key must be unique</Alert> - )} - </Box> - ) - })} - </Box> - </Box> + onGetArr={(arr) => { + setLoraListArr(arr) + }} + onJudgeArr={judgeArr} + pairData={loraArr} + /> + <AddPair + customData={{ + title: 'Lora Load Kwargs for Image Model', + key: 'key', + value: 'value', + }} + onGetArr={(arr) => { + setImageLoraLoadKwargsArr(arr) + }} + onJudgeArr={judgeArr} + pairData={imageLoraLoadArr} + /> + <AddPair + customData={{ + title: 'Lora Fuse Kwargs for Image Model', + key: 'key', + value: 'value', + }} + onGetArr={(arr) => { + setImageLoraFuseKwargsArr(arr) + }} + onJudgeArr={judgeArr} + pairData={imageLoraFuseArr} + /> + </Collapse> + </Collapse> + <AddPair + customData={{ + title: `Additional parameters passed to the inference engine${ + modelEngine ? ': ' + modelEngine : '' + }`, + key: 'key', + value: 'value', + }} + onGetArr={(arr) => { + setCustomParametersArr(arr) + }} + onJudgeArr={judgeArr} + pairData={customArr} + /> </Grid> </Box> ) : ( @@ -867,36 +1496,145 @@ const ModelCard = ({ label="(Optional) Model UID, model name by default" onChange={(e) => setModelUID(e.target.value)} /> + <TextField + style={{ marginTop: '25px' }} + type="number" + InputProps={{ + inputProps: { + min: 1, + }, + }} + label="Replica" + value={replica} + onChange={(e) => setReplica(parseInt(e.target.value, 10))} + /> + <FormControl variant="outlined" margin="normal" fullWidth> + <InputLabel id="n-gpu-label">Device</InputLabel> + <Select + labelId="n-gpu-label" + value={nGpu} + onChange={(e) => setNGpu(e.target.value)} + label="N-GPU" + > + {getNewNGPURange().map((v) => { + return ( + <MenuItem key={v} value={v}> + {v} + </MenuItem> + ) + })} + </Select> + </FormControl> + {nGpu === 'GPU' && ( + <FormControl variant="outlined" margin="normal" fullWidth> + <TextField + value={GPUIdx} + label="GPU Idx, Specify the GPU index where the model is located" + onChange={(e) => { + setGPUIdxAlert(false) + setGPUIdx(e.target.value) + const regular = /^\d+(?:,\d+)*$/ + if ( + e.target.value !== '' && + !regular.test(e.target.value) + ) { + setGPUIdxAlert(true) + } + }} + /> + {GPUIdxAlert && ( + <Alert severity="error"> + Please enter numeric data separated by commas, for + example: 0,1,2 + </Alert> + )} + </FormControl> + )} + <FormControl variant="outlined" margin="normal" fullWidth> + <TextField + variant="outlined" + value={workerIp} + label="Worker Ip, specify the worker ip where the model is located in a distributed scenario" + onChange={(e) => setWorkerIp(e.target.value)} + /> + </FormControl> + <FormControl variant="outlined" margin="normal" fullWidth> + <InputLabel id="quantization-label"> + (Optional) Download_hub + </InputLabel> + <Select + labelId="download_hub-label" + value={downloadHub} + onChange={(e) => { + e.target.value === 'none' + ? setDownloadHub('') + : setDownloadHub(e.target.value) + }} + label="(Optional) Download_hub" + > + {['none', 'huggingface', 'modelscope'].map((item) => { + return ( + <MenuItem key={item} value={item}> + {item} + </MenuItem> + ) + })} + </Select> + </FormControl> + <FormControl variant="outlined" margin="normal" fullWidth> + <TextField + variant="outlined" + value={modelPath} + label="(Optional) Model Path, For PyTorch, provide the model directory. For GGML/GGUF, provide the model file path." + onChange={(e) => setModelPath(e.target.value)} + /> + </FormControl> + <AddPair + customData={{ + title: 'Additional parameters passed to the inference engine', + key: 'key', + value: 'value', + }} + onGetArr={(arr) => { + setCustomParametersArr(arr) + }} + onJudgeArr={judgeArr} + pairData={customArr} + /> </FormControl> )} - <Box style={styles.buttonsContainer}> + <Box className="buttonsContainer"> <button title="Launch" - style={styles.buttonContainer} + className="buttonContainer" onClick={() => launchModel(url, modelData)} disabled={ - modelType === 'LLM' && - (isCallingApi || - isUpdatingModel || - !( - modelFormat && - modelSize && - modelData && - (quantization || - (!modelData.is_builtin && modelFormat !== 'pytorch')) - ) || - !judgeCustomParameters() || - defaultIndex !== -1 || - requestLimitsAlert || - GPUIdxAlert) + (modelType === 'LLM' && + (isCallingApi || + isUpdatingModel || + !( + modelFormat && + modelSize && + modelData && + (quantization || + (!modelData.is_builtin && modelFormat !== 'pytorch')) + ) || + !judgeArr(loraListArr, ['lora_name', 'local_path']) || + !judgeArr(imageLoraLoadKwargsArr, ['key', 'value']) || + !judgeArr(imageLoraFuseKwargsArr, ['key', 'value']) || + requestLimitsAlert || + GPUIdxAlert)) || + ((modelType === 'embedding' || modelType === 'rerank') && + GPUIdxAlert) || + !judgeArr(customParametersArr, ['key', 'value']) } > {(() => { if (isCallingApi || isUpdatingModel) { return ( <Box + className="buttonItem" style={{ - ...styles.buttonItem, backgroundColor: '#f2f2f2', }} > @@ -919,8 +1657,8 @@ const ModelCard = ({ ) { return ( <Box + className="buttonItem" style={{ - ...styles.buttonItem, backgroundColor: '#f2f2f2', }} > @@ -929,7 +1667,7 @@ const ModelCard = ({ ) } else { return ( - <Box style={styles.buttonItem}> + <Box className="buttonItem"> <RocketLaunchOutlined color="#000000" size="20px" /> </Box> ) @@ -938,24 +1676,211 @@ const ModelCard = ({ </button> <button title="Go Back" - style={styles.buttonContainer} - onClick={() => setSelected(false)} + className="buttonContainer" + onClick={() => { + setSelected(false) + setHover(false) + }} > - <Box style={styles.buttonItem}> + <Box className="buttonItem"> <UndoOutlined color="#000000" size="20px" /> </Box> </button> </Box> </div> </Drawer> + <Backdrop + sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }} + open={isJsonShow} + > + <div className="jsonDialog"> + <div className="jsonDialog-title"> + <div className="title-name">{modelData.model_name}</div> + <CopyComponent + tip={'Copy Json'} + text={JSON.stringify(modelData, null, 4)} + /> + </div> + <div className="main-box"> + <textarea + readOnly + className="textarea-box" + value={JSON.stringify(modelData, null, 4)} + /> + </div> + <div className="but-box"> + <Button + onClick={() => { + setIsJsonShow(false) + }} + style={{ marginRight: 30 }} + > + Cancel + </Button> + <Button onClick={handleJsonDataPresentation}>Edit</Button> + </div> + </div> + </Backdrop> <Snackbar anchorOrigin={{ vertical: 'top', horizontal: 'center' }} open={openSnackbar} onClose={() => setOpenSnackbar(false)} - message="Please fill in the added custom parameters completely!" + message="Please fill in the complete parameters before adding!" key={'top' + 'center'} /> - </Box> + <Snackbar + anchorOrigin={{ vertical: 'top', horizontal: 'center' }} + open={openErrorSnackbar} + onClose={() => setOpenErrorSnackbar(false)} + key={'top' + 'center'} + > + <Alert severity="error" variant="filled" sx={{ width: '100%' }}> + {errorSnackbarValue} + </Alert> + </Snackbar> + + <Backdrop + sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }} + open={isOpenCachedList} + > + <div className="dialogBox"> + <div className="dialogTitle"> + <div className="dialogTitle-model_name">{modelData.model_name}</div> + <Close + style={{ cursor: 'pointer' }} + onClick={handleCloseCachedList} + /> + </div> + <TableContainer component={Paper}> + <Table + sx={{ minWidth: 500 }} + style={{ height: '500px', width: '100%' }} + stickyHeader + aria-label="simple pagination table" + > + <TableHead> + <TableRow> + {modelType === 'LLM' && ( + <> + <TableCell align="left">model_format</TableCell> + <TableCell align="left">model_size_in_billions</TableCell> + <TableCell align="left">quantizations</TableCell> + </> + )} + <TableCell align="left" style={{ width: 192 }}> + real_path + </TableCell> + <TableCell align="left" style={{ width: 46 }}></TableCell> + <TableCell align="left" style={{ width: 192 }}> + path + </TableCell> + <TableCell align="left" style={{ width: 46 }}></TableCell> + <TableCell + align="left" + style={{ whiteSpace: 'nowrap', minWidth: 116 }} + > + IP Address + </TableCell> + <TableCell align="left">operation</TableCell> + </TableRow> + </TableHead> + <TableBody style={{ position: 'relative' }}> + {cachedListArr.slice(page * 5, page * 5 + 5).map((row) => ( + <StyledTableRow + style={{ maxHeight: 90 }} + key={row.model_name} + > + {modelType === 'LLM' && ( + <> + <TableCell component="th" scope="row"> + {row.model_format === null ? '—' : row.model_format} + </TableCell> + <TableCell> + {row.model_size_in_billions === null + ? '—' + : row.model_size_in_billions} + </TableCell> + <TableCell> + {row.quantization === null ? '—' : row.quantization} + </TableCell> + </> + )} + <TableCell> + <Tooltip title={row.real_path}> + <div + className={ + modelType === 'LLM' ? 'pathBox' : 'pathBox pathBox2' + } + > + {row.real_path} + </div> + </Tooltip> + </TableCell> + <TableCell> + <CopyComponent + tip={'Copy real_path'} + text={row.real_path} + /> + </TableCell> + <TableCell> + <Tooltip title={row.path}> + <div + className={ + modelType === 'LLM' ? 'pathBox' : 'pathBox pathBox2' + } + > + {row.path} + </div> + </Tooltip> + </TableCell> + <TableCell> + <CopyComponent tip={'Copy path'} text={row.path} /> + </TableCell> + <TableCell>{row.actor_ip_address}</TableCell> + <TableCell align={modelType === 'LLM' ? 'center' : 'left'}> + <IconButton + aria-label="delete" + size="large" + onClick={() => + handleOpenDeleteCachedDialog( + row.real_path, + row.model_version + ) + } + > + <Delete /> + </IconButton> + </TableCell> + </StyledTableRow> + ))} + {emptyRows > 0 && ( + <TableRow style={{ height: 89.4 * emptyRows }}> + <TableCell /> + </TableRow> + )} + {cachedListArr.length === 0 && ( + <div className="empty">No cache for now !</div> + )} + </TableBody> + </Table> + </TableContainer> + <TablePagination + style={{ float: 'right' }} + rowsPerPageOptions={[5]} + count={cachedListArr.length} + rowsPerPage={5} + page={page} + onPageChange={handleChangePage} + /> + </div> + </Backdrop> + <DeleteDialog + text={'Confirm deletion of cache files? This action is irreversible.'} + isDelete={isDeleteCached} + onHandleIsDelete={() => setIsDeleteCached(false)} + onHandleDelete={handleDeleteCached} + /> + </> ) } diff --git a/xinference/web/ui/src/scenes/launch_model/styles/launchModelStyle.js b/xinference/web/ui/src/scenes/launch_model/styles/launchModelStyle.js deleted file mode 100644 index 7cb1f1c6f0..0000000000 --- a/xinference/web/ui/src/scenes/launch_model/styles/launchModelStyle.js +++ /dev/null @@ -1,8 +0,0 @@ -const style = { - display: 'grid', - gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', - paddingLeft: '2rem', - gridGap: '2rem 0rem', -} - -export default style diff --git a/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.css b/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.css new file mode 100644 index 0000000000..6674618cc7 --- /dev/null +++ b/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.css @@ -0,0 +1,179 @@ +.container { + display: block; + position: relative; + width: 300px; + height: 300px; + cursor: pointer; + border-radius: 20px; +} +.descriptionCard { + position: relative; + top: -1px; + left: -1px; + width: 300px; + height: 300px; + padding: 20px; + border-radius: 20px; +} +.cardTitle { + display: flex; + justify-content: space-between; +} +.iconButtonBox { + display: flex; + align-items: center; +} +.drawerCard { + position: relative; + padding: 20px 80px 0; + min-height: 100%; + width: 60vw; +} +.p { + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-word; + font-size: 14px; + padding: 0px 10px; +} +.formContainer { + height: 80%; + overflow: scroll; + padding: 0 10px; +} +.buttonsContainer { + position: absolute; + bottom: 50px; + left: 100px; + right: 100px; + display: flex; + justify-content: space-between; + align-items: center; +} +.buttonContainer { + width: 45%; + border-width: 0px; + background-color: transparent; +} +.buttonItem { + width: 100%; + padding: 5px; + border-radius: 4px; + border: 1px solid #e5e7eb; + border-width: 1px; + border-color: #e5e7eb; +} +.instructionText { + font-size: 12px; + color: #666666; + font-style: italic; + margin: 30px 0; + text-align: center; +} +.iconRow { + position: absolute; + bottom: 20px; + left: 20px; + right: 20px; + display: flex; + justify-content: space-between; + align-items: center; +} +.iconItem { + display: flex; + flex-direction: column; + align-items: center; + margin: 20px; +} +.boldIconText { + font-weight: bold; + font-size: 1.2em; +} +.muiIcon { + font-size: 1.5em; +} +.smallText { + font-size: 0.8em; +} +.dialogBox { + width: 1241px; + height: 607px; + background-color: #fff; + margin: 32px; + overflow-x: scroll; +} +.dialogTitle { + display: flex; + justify-content: space-between; + padding: 20px 20px 7px; + color: #000; +} +.dialogTitle-model_name { + font-size: 18px; + font-weight: 700; +} +.pathBox { + width: 160px; + cursor: pointer; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.pathBox2 { + width: 300px; +} +.empty { + position: absolute; + left: 50%; + top: 30%; + font-size: 20px; + color: #555; + transform: translate(-50%, 0); +} +.deleteDialog { + display: flex; + align-items: center; +} +.warningIcon { + margin-right: 10px; + color: rgb(237, 108, 2); +} +.jsonDialog { + display: flex; + flex-direction: column; + padding: 10px 30px; + background-color: #fff; + color: #000; + border-radius: 8px; +} +.jsonDialog-title { + display: flex; + justify-content: space-between; + align-items: center; + margin: 10px 0 20px 0; +} +.title-name { + font-size: 16px; + font-weight: 700; +} +.main-box { + width: 700px; + height: 500px; +} +.textarea-box { + width: 100%; + height: 100%; + padding: 5px 10px; + border: 1px solid #ddd; + border-radius: 5px; + resize: none; + color: #444; +} +.but-box { + display: flex; + justify-content: end; + margin-top: 20px; +} diff --git a/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.js b/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.js deleted file mode 100644 index c5c8195a08..0000000000 --- a/xinference/web/ui/src/scenes/launch_model/styles/modelCardStyle.js +++ /dev/null @@ -1,107 +0,0 @@ -const styles = { - container: { - display: 'block', - position: 'relative', - width: '300px', - height: '300px', - border: '1px solid #ddd', - borderRadius: '20px', - }, - containerSelected: { - cursor: 'pointer', - display: 'block', - position: 'relative', - width: '300px', - height: '300px', - border: '1px solid #ddd', - borderRadius: '20px', - boxShadow: '0 0 10px #ccc', - }, - descriptionCard: { - position: 'relative', - top: '-1px', - left: '-1px', - width: '300px', - height: '300px', - border: '1px solid #ddd', - padding: '20px', - borderRadius: '20px', - }, - drawerCard: { - position: 'relative', - padding: '20px 80px 0', - minHeight: '100%', - width: '60vw', - }, - p: { - 'display': '-webkit-box', - '-webkit-line-clamp': '4', - '-webkit-box-orient': 'vertical', - 'overflow': 'hidden', - 'textOverflow': 'ellipsis', - 'wordBreak': 'break-word', - 'fontSize': '14px', - 'padding': '0px 10px', - }, - formContainer: { - height: '80%', - overflow: 'scroll', - padding: '0 10px', - }, - buttonsContainer: { - position: 'absolute', - bottom: '50px', - left: '100px', - right: '100px', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - }, - buttonContainer: { - width: '45%', - borderWidth: '0px', - backgroundColor: 'transparent', - }, - buttonItem: { - width: '100%', - padding: '5px', - borderRadius: '4px', - border: '1px solid #e5e7eb', - borderWidth: '1px', - borderColor: '#e5e7eb', - }, - instructionText: { - fontSize: '12px', - color: '#666666', - fontStyle: 'italic', - margin: '30px 0', - textAlign: 'center', - }, - iconRow: { - position: 'absolute', - bottom: '20px', - left: '20px', - right: '20px', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - }, - iconItem: { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - margin: '20px', - }, - boldIconText: { - fontWeight: 'bold', - fontSize: '1.2em', - }, - muiIcon: { - fontSize: '1.5em', - }, - smallText: { - fontSize: '0.8em', - }, -} - -export default styles diff --git a/xinference/web/ui/src/scenes/login/login.js b/xinference/web/ui/src/scenes/login/login.js index 05a26b1b93..0dfe8b3966 100644 --- a/xinference/web/ui/src/scenes/login/login.js +++ b/xinference/web/ui/src/scenes/login/login.js @@ -43,7 +43,8 @@ function Login() { } else { res.json().then((data) => { setCookie('token', data['access_token'], { path: '/' }) - navigate('/') + sessionStorage.setItem('token', data['access_token']) + navigate('/launch_model/llm') }) } }) diff --git a/xinference/web/ui/src/scenes/register_model/components/addControlnet.js b/xinference/web/ui/src/scenes/register_model/components/addControlnet.js new file mode 100644 index 0000000000..4c65a730d2 --- /dev/null +++ b/xinference/web/ui/src/scenes/register_model/components/addControlnet.js @@ -0,0 +1,177 @@ +import AddIcon from '@mui/icons-material/Add' +import DeleteIcon from '@mui/icons-material/Delete' +import { + Box, + Button, + FormControlLabel, + Radio, + RadioGroup, + TextField, + Tooltip, +} from '@mui/material' +import React, { useEffect, useState } from 'react' + +const AddControlnet = ({ + controlnetDataArr, + onGetControlnetArr, + scrollRef, +}) => { + const [count, setCount] = useState(0) + const [controlnetArr, setControlnetArr] = useState([]) + const [isAdd, setIsAdd] = useState(false) + + useEffect(() => { + if (controlnetDataArr && controlnetDataArr.length) { + const dataArr = controlnetDataArr.map((item) => { + setCount(count + 1) + item.id = count + return item + }) + setControlnetArr(dataArr) + } + }, []) + + useEffect(() => { + const arr = controlnetArr.map((item) => { + const { model_name: name, model_uri: uri, model_family } = item + return { + model_name: name, + model_uri: uri, + model_family, + } + }) + onGetControlnetArr(arr) + isAdd && handleScrollBottom() + setIsAdd(false) + }, [controlnetArr]) + + const handleAddControlnet = () => { + setCount(count + 1) + const item = { + id: count, + model_name: 'custom-controlnet', + model_uri: '/path/to/controlnet-model', + model_family: 'controlnet', + } + setControlnetArr([...controlnetArr, item]) + setIsAdd(true) + } + + const handleUpdateSpecsArr = (index, type, newValue) => { + setControlnetArr( + controlnetArr.map((item, subIndex) => { + if (subIndex === index) { + return { ...item, [type]: newValue } + } + return item + }) + ) + } + + const handleDeleteControlnet = (index) => { + setControlnetArr(controlnetArr.filter((_, subIndex) => index !== subIndex)) + } + + const handleScrollBottom = () => { + scrollRef.current.scrollTo({ + top: scrollRef.current.scrollHeight, + behavior: 'smooth', + }) + } + + return ( + <> + <div> + <label style={{ marginBottom: '20px' }}>Controlnet</label> + <Button + variant="contained" + size="small" + endIcon={<AddIcon />} + className="addBtn" + onClick={handleAddControlnet} + > + more + </Button> + </div> + <div className="specs_container"> + {controlnetArr.map((item, index) => ( + <div className="item" key={item.id}> + <TextField + error={item.model_name !== '' ? false : true} + style={{ minWidth: '60%', marginTop: '10px' }} + label="Model Name" + size="small" + value={item.model_name} + onChange={(e) => { + handleUpdateSpecsArr(index, 'model_name', e.target.value) + }} + /> + <Box padding="15px"></Box> + + <TextField + error={item.model_uri !== '' ? false : true} + style={{ minWidth: '60%' }} + label="Model Path" + size="small" + value={item.model_uri} + onChange={(e) => { + handleUpdateSpecsArr(index, 'model_uri', e.target.value) + }} + /> + <Box padding="15px"></Box> + + <label + style={{ + paddingLeft: 5, + }} + > + Model Format + </label> + <RadioGroup + value={item.model_format} + onChange={(e) => { + handleUpdateSpecsArr(index, 'model_format', e.target.value) + }} + > + <Box sx={styles.checkboxWrapper}> + <Box key={item} sx={{ marginLeft: '10px' }}> + <FormControlLabel + value="controlnet" + checked + control={<Radio />} + label="controlnet" + /> + </Box> + </Box> + </RadioGroup> + + <Tooltip title="Delete specs" placement="top"> + <div + className="deleteBtn" + onClick={() => handleDeleteControlnet(index)} + > + <DeleteIcon className="deleteIcon" /> + </div> + </Tooltip> + </div> + ))} + </div> + </> + ) +} + +export default AddControlnet + +const styles = { + baseFormControl: { + width: '100%', + margin: 'normal', + size: 'small', + }, + checkboxWrapper: { + display: 'flex', + flexWrap: 'wrap', + alignItems: 'center', + width: '100%', + }, +} diff --git a/xinference/web/ui/src/scenes/register_model/components/addModelSpecs.js b/xinference/web/ui/src/scenes/register_model/components/addModelSpecs.js new file mode 100644 index 0000000000..df4120b932 --- /dev/null +++ b/xinference/web/ui/src/scenes/register_model/components/addModelSpecs.js @@ -0,0 +1,403 @@ +import AddIcon from '@mui/icons-material/Add' +import DeleteIcon from '@mui/icons-material/Delete' +import { + Alert, + Box, + Button, + FormControlLabel, + Radio, + RadioGroup, + TextField, + Tooltip, +} from '@mui/material' +import React, { useEffect, useState } from 'react' + +const modelFormatArr = [ + { value: 'pytorch', label: 'PyTorch' }, + { value: 'ggufv2', label: 'GGUF' }, + { value: 'gptq', label: 'GPTQ' }, + { value: 'awq', label: 'AWQ' }, + { value: 'fp8', label: 'FP8' }, +] + +const AddModelSpecs = ({ + isJump, + formData, + specsDataArr, + onGetArr, + scrollRef, +}) => { + const [count, setCount] = useState(0) + const [specsArr, setSpecsArr] = useState([]) + const [pathArr, setPathArr] = useState([]) + const [modelSizeAlertId, setModelSizeAlertId] = useState([]) + const [quantizationAlertId, setQuantizationAlertId] = useState([]) + const [isError, setIsError] = useState(false) + const [isAdd, setIsAdd] = useState(false) + + useEffect(() => { + if (isJump) { + const dataArr = specsDataArr.map((item, index) => { + const { + model_uri, + model_size_in_billions, + model_format, + quantizations, + model_file_name_template, + } = item + let size = model_size_in_billions + if (typeof size !== 'number') size = size.split('_').join('.') + + return { + id: index, + model_uri, + model_size_in_billions: size, + model_format, + quantizations, + model_file_name_template, + } + }) + setCount(dataArr.length) + setSpecsArr(dataArr) + + const subPathArr = [] + specsDataArr.forEach((item) => { + if (item.model_format !== 'ggufv2') { + subPathArr.push(item.model_uri) + } else { + subPathArr.push(item.model_uri + '/' + item.model_file_name_template) + } + }) + setPathArr(subPathArr) + } else { + setSpecsArr([ + { + id: count, + ...formData, + }, + ]) + setCount(count + 1) + setPathArr([formData.model_uri]) + } + }, []) + + useEffect(() => { + const arr = specsArr.map((item) => { + const { + model_uri: uri, + model_size_in_billions: size, + model_format: modelFormat, + quantizations, + model_file_name_template, + } = item + const handleSize = + parseInt(size) === parseFloat(size) + ? Number(size) + : size.split('.').join('_') + + let handleQuantization = quantizations + if (modelFormat === 'pytorch') { + handleQuantization = ['none'] + } else if (handleQuantization[0] === '' && modelFormat === 'ggufv2') { + handleQuantization = ['default'] + } + + return { + model_uri: uri, + model_size_in_billions: handleSize, + model_format: modelFormat, + quantizations: handleQuantization, + model_file_name_template, + } + }) + setIsError(true) + if (modelSizeAlertId.length === 0 && quantizationAlertId.length === 0) { + setIsError(false) + } + onGetArr(arr, isError) + isAdd && handleScrollBottom() + setIsAdd(false) + }, [specsArr, isError]) + + const handleAddSpecs = () => { + setCount(count + 1) + const item = { + id: count, + model_uri: '/path/to/llama-1', + model_size_in_billions: 7, + model_format: 'pytorch', + quantizations: [], + } + setSpecsArr([...specsArr, item]) + setIsAdd(true) + setPathArr([...pathArr, '/path/to/llama-1']) + } + + const handleUpdateSpecsArr = (index, type, newValue) => { + if (type === 'model_format') { + const subPathArr = [...pathArr] + if (specsArr[index].model_format !== 'ggufv2') { + pathArr[index] = specsArr[index].model_uri + } else { + pathArr[index] = + specsArr[index].model_uri + + '/' + + specsArr[index].model_file_name_template + } + setPathArr(subPathArr) + } + + setSpecsArr( + specsArr.map((item, subIndex) => { + if (subIndex === index) { + if (type === 'quantizations') { + return { ...item, [type]: [newValue] } + } else if (type === 'model_format') { + if (newValue === 'ggufv2') { + const { baseDir, filename } = getPathComponents(pathArr[index]) + const obj = { + ...item, + model_format: newValue, + quantizations: [''], + model_uri: baseDir, + model_file_name_template: filename, + } + return obj + } else { + const { id, model_size_in_billions, model_format } = item + return { + id, + model_uri: pathArr[index], + model_size_in_billions, + model_format, + [type]: newValue, + quantizations: [''], + } + } + } else if (type === 'model_uri') { + const subPathArr = [...pathArr] + subPathArr[index] = newValue + setPathArr(subPathArr) + if (item.model_format === 'ggufv2') { + const { baseDir, filename } = getPathComponents(newValue) + const obj = { + ...item, + model_uri: baseDir, + model_file_name_template: filename, + } + return obj + } else { + return { ...item, [type]: newValue } + } + } else { + return { ...item, [type]: newValue } + } + } + return item + }) + ) + } + + const handleDeleteSpecs = (index) => { + setSpecsArr(specsArr.filter((_, subIndex) => index !== subIndex)) + } + + const getPathComponents = (path) => { + const normalizedPath = path.replace(/\\/g, '/') + const baseDir = normalizedPath.substring(0, normalizedPath.lastIndexOf('/')) + const filename = normalizedPath.substring( + normalizedPath.lastIndexOf('/') + 1 + ) + return { baseDir, filename } + } + + const handleModelSize = (index, value, id) => { + setModelSizeAlertId(modelSizeAlertId.filter((item) => item !== id)) + handleUpdateSpecsArr(index, 'model_size_in_billions', value) + if (value !== '' && (!Number(value) || Number(value) <= 0)) { + const modelSizeAlertIdArr = Array.from(new Set([...modelSizeAlertId, id])) + setModelSizeAlertId(modelSizeAlertIdArr) + } + } + + const handleQuantization = (model_format, index, value, id) => { + setQuantizationAlertId(quantizationAlertId.filter((item) => item !== id)) + handleUpdateSpecsArr(index, 'quantizations', value) + if ( + (model_format === 'gptq' || + model_format === 'awq' || + model_format === 'fp8') && + value === '' + ) { + const quantizationAlertIdArr = Array.from( + new Set([...quantizationAlertId, id]) + ) + setQuantizationAlertId(quantizationAlertIdArr) + } + } + + const handleScrollBottom = () => { + scrollRef.current.scrollTo({ + top: scrollRef.current.scrollHeight, + behavior: 'smooth', + }) + } + + return ( + <> + <div> + <label style={{ marginBottom: '20px' }}>Model Specs</label> + <Button + variant="contained" + size="small" + endIcon={<AddIcon />} + className="addBtn" + onClick={handleAddSpecs} + > + more + </Button> + </div> + <div className="specs_container"> + {specsArr.map((item, index) => ( + <div className="item" key={item.id}> + <label + style={{ + paddingLeft: 5, + }} + > + Model Format + </label> + <RadioGroup + value={item.model_format} + onChange={(e) => { + handleUpdateSpecsArr(index, 'model_format', e.target.value) + if ( + e.target.value === 'gptq' || + e.target.value === 'awq' || + e.target.value === 'fp8' + ) { + const quantizationAlertIdArr = Array.from( + new Set([...quantizationAlertId, item.id]) + ) + setQuantizationAlertId(quantizationAlertIdArr) + } + }} + > + <Box sx={styles.checkboxWrapper}> + {modelFormatArr.map((item) => ( + <Box key={item.value} sx={{ marginLeft: '10px' }}> + <FormControlLabel + value={item.value} + control={<Radio />} + label={item.label} + /> + </Box> + ))} + </Box> + </RadioGroup> + <Box padding="15px"></Box> + + <TextField + error={item.model_uri !== '' ? false : true} + style={{ minWidth: '60%' }} + label="Model Path" + size="small" + value={ + item.model_format !== 'ggufv2' + ? item.model_uri + : item.model_uri + '/' + item.model_file_name_template + } + onChange={(e) => { + handleUpdateSpecsArr(index, 'model_uri', e.target.value) + }} + helperText="For PyTorch, provide the model directory. For GGUF, provide the model file path." + /> + <Box padding="15px"></Box> + + <TextField + error={Number(item.model_size_in_billions) > 0 ? false : true} + label="Model Size in Billions" + size="small" + value={item.model_size_in_billions} + onChange={(e) => { + handleModelSize(index, e.target.value, item.id) + }} + /> + {modelSizeAlertId.includes(item.id) && ( + <Alert severity="error"> + Please enter a number greater than 0. + </Alert> + )} + <Box padding="15px"></Box> + + {item.model_format !== 'pytorch' && ( + <> + <TextField + style={{ minWidth: '60%' }} + label={ + item.model_format === 'gptq' || + item.model_format === 'awq' || + item.model_format === 'fp8' + ? 'Quantization' + : 'Quantization (Optional)' + } + size="small" + value={item.quantizations[0]} + onChange={(e) => { + handleQuantization( + item.model_format, + index, + e.target.value, + item.id + ) + }} + helperText={ + item.model_format === 'gptq' || + item.model_format === 'awq' || + item.model_format === 'fp8' + ? 'For GPTQ/AWQ/FP8 models, please be careful to fill in the quantization corresponding to the model you want to register.' + : '' + } + /> + {item.model_format !== 'ggufv2' && + quantizationAlertId.includes(item.id) && + item.quantizations[0] == '' && ( + <Alert severity="error"> + Quantization cannot be left empty. + </Alert> + )} + </> + )} + + {specsArr.length > 1 && ( + <Tooltip title="Delete specs" placement="top"> + <div + className="deleteBtn" + onClick={() => handleDeleteSpecs(index)} + > + <DeleteIcon className="deleteIcon" /> + </div> + </Tooltip> + )} + </div> + ))} + </div> + </> + ) +} + +export default AddModelSpecs + +const styles = { + baseFormControl: { + width: '100%', + margin: 'normal', + size: 'small', + }, + checkboxWrapper: { + display: 'flex', + flexWrap: 'wrap', + alignItems: 'center', + width: '100%', + }, +} diff --git a/xinference/web/ui/src/scenes/register_model/data/languages.js b/xinference/web/ui/src/scenes/register_model/data/languages.js new file mode 100644 index 0000000000..a765da20c2 --- /dev/null +++ b/xinference/web/ui/src/scenes/register_model/data/languages.js @@ -0,0 +1,192 @@ +const languagesArr = [ + { code: 'ab', language: 'Abkhazian' }, + { code: 'aa', language: 'Afar' }, + { code: 'af', language: 'Afrikaans' }, + { code: 'ak', language: 'Akan' }, + { code: 'sq', language: 'Albanian' }, + { code: 'am', language: 'Amharic' }, + { code: 'ar', language: 'Arabic' }, + { code: 'an', language: 'Aragonese' }, + { code: 'hy', language: 'Armenian' }, + { code: 'as', language: 'Assamese' }, + { code: 'av', language: 'Avaric' }, + { code: 'ae', language: 'Avestan' }, + { code: 'ay', language: 'Aymara' }, + { code: 'az', language: 'Azerbaijani' }, + { code: 'bm', language: 'Bambara' }, + { code: 'ba', language: 'Bashkir' }, + { code: 'eu', language: 'Basque' }, + { code: 'be', language: 'Belarusian' }, + { code: 'bn', language: 'Bengali' }, + { code: 'bh', language: 'Bihari' }, + { code: 'bi', language: 'Bislama' }, + { code: 'bs', language: 'Bosnian' }, + { code: 'br', language: 'Breton' }, + { code: 'bg', language: 'Bulgarian' }, + { code: 'my', language: 'Burmese' }, + { code: 'ca', language: 'Catalan, Valencian' }, + { code: 'ch', language: 'Chamorro' }, + { code: 'ce', language: 'Chechen' }, + { code: 'ny', language: 'Chichewa, Chewa, Nyanja' }, + // { code: 'zh', language: 'Chinese' }, + { code: 'cv', language: 'Chuvash' }, + { code: 'kw', language: 'Cornish' }, + { code: 'co', language: 'Corsican' }, + { code: 'cr', language: 'Cree' }, + { code: 'hr', language: 'Croatian' }, + { code: 'cs', language: 'Czech' }, + { code: 'da', language: 'Danish' }, + { code: 'dv', language: 'Divehi, Dhivehi, Maldivian' }, + { code: 'nl', language: 'Dutch, Flemish' }, + { code: 'dz', language: 'Dzongkha' }, + // { code: 'en', language: 'English' }, + { code: 'eo', language: 'Esperanto' }, + { code: 'et', language: 'Estonian' }, + { code: 'ee', language: 'Ewe' }, + { code: 'fo', language: 'Faroese' }, + { code: 'fj', language: 'Fijian' }, + { code: 'fi', language: 'Finnish' }, + { code: 'fr', language: 'French' }, + { code: 'ff', language: 'Fulah' }, + { code: 'gl', language: 'Galician' }, + { code: 'ka', language: 'Georgian' }, + { code: 'de', language: 'German' }, + { code: 'el', language: 'Greek' }, + { code: 'gn', language: 'Guarani' }, + { code: 'gu', language: 'Gujarati' }, + { code: 'ht', language: 'Haitian, Haitian Creole' }, + { code: 'ha', language: 'Hausa' }, + { code: 'he', language: 'Hebrew' }, + { code: 'hz', language: 'Herero' }, + { code: 'hi', language: 'Hindi' }, + { code: 'ho', language: 'Hiri Motu' }, + { code: 'hu', language: 'Hungarian' }, + { code: 'ia', language: 'Interlingua' }, + { code: 'id', language: 'Indonesian' }, + { code: 'ie', language: 'Interlingue, Occidental' }, + { code: 'ga', language: 'Irish' }, + { code: 'ig', language: 'Igbo' }, + { code: 'ik', language: 'Inupiaq' }, + { code: 'io', language: 'Ido' }, + { code: 'is', language: 'Icelandic' }, + { code: 'it', language: 'Italian' }, + { code: 'iu', language: 'Inuktitut' }, + { code: 'ja', language: 'Japanese' }, + { code: 'jv', language: 'Javanese' }, + { code: 'kl', language: 'Kalaallisut, Greenlandic' }, + { code: 'kn', language: 'Kannada' }, + { code: 'kr', language: 'Kanuri' }, + { code: 'ks', language: 'Kashmiri' }, + { code: 'kk', language: 'Kazakh' }, + { code: 'km', language: 'Central Khmer' }, + { code: 'ki', language: 'Kikuyu, Gikuyu' }, + { code: 'rw', language: 'Kinyarwanda' }, + { code: 'ky', language: 'Kirghiz, Kyrgyz' }, + { code: 'kv', language: 'Komi' }, + { code: 'kg', language: 'Kongo' }, + { code: 'ko', language: 'Korean' }, + { code: 'ku', language: 'Kurdish' }, + { code: 'kj', language: 'Kuanyama, Kwanyama' }, + { code: 'la', language: 'Latin' }, + { code: 'lb', language: 'Luxembourgish, Letzeburgesch' }, + { code: 'lg', language: 'Ganda' }, + { code: 'li', language: 'Limburgan, Limburger, Limburgish' }, + { code: 'ln', language: 'Lingala' }, + { code: 'lo', language: 'Lao' }, + { code: 'lt', language: 'Lithuanian' }, + { code: 'lu', language: 'Luba-Katanga' }, + { code: 'lv', language: 'Latvian' }, + { code: 'gv', language: 'Manx' }, + { code: 'mk', language: 'Macedonian' }, + { code: 'mg', language: 'Malagasy' }, + { code: 'ms', language: 'Malay' }, + { code: 'ml', language: 'Malayalam' }, + { code: 'mt', language: 'Maltese' }, + { code: 'mi', language: 'Maori' }, + { code: 'mr', language: 'Marathi' }, + { code: 'mh', language: 'Marshallese' }, + { code: 'mn', language: 'Mongolian' }, + { code: 'na', language: 'Nauru' }, + { code: 'nv', language: 'Navajo, Navaho' }, + { code: 'nd', language: 'North Ndebele' }, + { code: 'ne', language: 'Nepali' }, + { code: 'ng', language: 'Ndonga' }, + { code: 'nb', language: 'Norwegian Bokmål' }, + { code: 'nn', language: 'Norwegian Nynorsk' }, + { code: 'no', language: 'Norwegian' }, + { code: 'ii', language: 'Sichuan Yi, Nuosu' }, + { code: 'nr', language: 'South Ndebele' }, + { code: 'oc', language: 'Occitan' }, + { code: 'oj', language: 'Ojibwa' }, + { + code: 'cu', + language: + 'Church Slavic, Old Slavonic, Church Slavonic, Old Bulgarian, Old Church Slavonic', + }, + { code: 'om', language: 'Oromo' }, + { code: 'or', language: 'Oriya' }, + { code: 'os', language: 'Ossetian, Ossetic' }, + { code: 'pa', language: 'Punjabi, Panjabi' }, + { code: 'pi', language: 'Pali' }, + { code: 'fa', language: 'Persian' }, + { code: 'pl', language: 'Polish' }, + { code: 'ps', language: 'Pashto, Pushto' }, + { code: 'pt', language: 'Portuguese' }, + { code: 'qu', language: 'Quechua' }, + { code: 'rm', language: 'Romansh' }, + { code: 'rn', language: 'Rundi' }, + { code: 'ro', language: 'Romanian, Moldavian, Moldovan' }, + { code: 'ru', language: 'Russian' }, + { code: 'sa', language: 'Sanskrit' }, + { code: 'sc', language: 'Sardinian' }, + { code: 'sd', language: 'Sindhi' }, + { code: 'se', language: 'Northern Sami' }, + { code: 'sm', language: 'Samoan' }, + { code: 'sg', language: 'Sango' }, + { code: 'sr', language: 'Serbian' }, + { code: 'gd', language: 'Gaelic, Scottish Gaelic' }, + { code: 'sn', language: 'Shona' }, + { code: 'si', language: 'Sinhala, Sinhalese' }, + { code: 'sk', language: 'Slovak' }, + { code: 'sl', language: 'Slovenian' }, + { code: 'so', language: 'Somali' }, + { code: 'st', language: 'Southern Sotho' }, + { code: 'es', language: 'Spanish, Castilian' }, + { code: 'su', language: 'Sundanese' }, + { code: 'sw', language: 'Swahili' }, + { code: 'ss', language: 'Swati' }, + { code: 'sv', language: 'Swedish' }, + { code: 'ta', language: 'Tamil' }, + { code: 'te', language: 'Telugu' }, + { code: 'tg', language: 'Tajik' }, + { code: 'th', language: 'Thai' }, + { code: 'ti', language: 'Tigrinya' }, + { code: 'bo', language: 'Tibetan' }, + { code: 'tk', language: 'Turkmen' }, + { code: 'tl', language: 'Tagalog' }, + { code: 'tn', language: 'Tswana' }, + { code: 'to', language: 'Tonga' }, + { code: 'tr', language: 'Turkish' }, + { code: 'ts', language: 'Tsonga' }, + { code: 'tt', language: 'Tatar' }, + { code: 'tw', language: 'Twi' }, + { code: 'ty', language: 'Tahitian' }, + { code: 'ug', language: 'Uighur, Uyghur' }, + { code: 'uk', language: 'Ukrainian' }, + { code: 'ur', language: 'Urdu' }, + { code: 'uz', language: 'Uzbek' }, + { code: 've', language: 'Venda' }, + { code: 'vi', language: 'Vietnamese' }, + { code: 'vo', language: 'Volapük' }, + { code: 'wa', language: 'Walloon' }, + { code: 'cy', language: 'Welsh' }, + { code: 'wo', language: 'Wolof' }, + { code: 'fy', language: 'West Frisian' }, + { code: 'xh', language: 'Xhosa' }, + { code: 'yi', language: 'Yiddish' }, + { code: 'yo', language: 'Yoruba' }, + { code: 'za', language: 'Zhuang, Chuang' }, + { code: 'zu', language: 'Zulu' }, +] + +export default languagesArr diff --git a/xinference/web/ui/src/scenes/register_model/index.js b/xinference/web/ui/src/scenes/register_model/index.js index de3c04dc43..eb5b0a9e77 100644 --- a/xinference/web/ui/src/scenes/register_model/index.js +++ b/xinference/web/ui/src/scenes/register_model/index.js @@ -1,625 +1,136 @@ import { TabContext, TabList, TabPanel } from '@mui/lab' -import { - Box, - Checkbox, - FormControl, - FormControlLabel, - FormHelperText, - Radio, - RadioGroup, - Tab, -} from '@mui/material' -import Alert from '@mui/material/Alert' -import AlertTitle from '@mui/material/AlertTitle' -import Button from '@mui/material/Button' -import TextField from '@mui/material/TextField' -import React, { useContext, useEffect, useState } from 'react' +import { Box, Tab } from '@mui/material' +import React, { useEffect } from 'react' import { useCookies } from 'react-cookie' import { useNavigate } from 'react-router-dom' -import { ApiContext } from '../../components/apiContext' import ErrorMessageSnackBar from '../../components/errorMessageSnackBar' -import fetcher from '../../components/fetcher' import Title from '../../components/Title' -import { useMode } from '../../theme' -import RegisterEmbeddingModel from './register_embedding' -import RegisterRerankModel from './register_rerank' - -const SUPPORTED_LANGUAGES_DICT = { en: 'English', zh: 'Chinese' } -const SUPPORTED_FEATURES = ['Generate', 'Chat'] - -// Convert dictionary of supported languages into list -const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT) +import { isValidBearerToken } from '../../components/utils' +import RegisterModelComponent from './registerModel' const RegisterModel = () => { - const ERROR_COLOR = useMode() - const endPoint = useContext(ApiContext).endPoint - const { setErrorMsg } = useContext(ApiContext) - const [successMsg, setSuccessMsg] = useState('') - const [modelFormat, setModelFormat] = useState('pytorch') - const [modelSize, setModelSize] = useState(7) - const [modelUri, setModelUri] = useState('/path/to/llama-2') - const [quantization, setQuantization] = useState('') - const [formData, setFormData] = useState({ - version: 1, - context_length: 2048, - model_name: 'custom-llama-2', - model_lang: ['en'], - model_ability: ['generate'], - model_description: 'This is a custom model description.', - model_family: '', - model_specs: [], - prompt_style: undefined, - }) - const [promptStyles, setPromptStyles] = useState([]) - const [family, setFamily] = useState({ - chat: [], - generate: [], - }) - const [familyLabel, setFamilyLabel] = useState('') - const [tabValue, setTabValue] = React.useState('1') + const [tabValue, setTabValue] = React.useState( + sessionStorage.getItem('registerModelType') + ? sessionStorage.getItem('registerModelType') + : '/register_model/llm' + ) const [cookie] = useCookies(['token']) const navigate = useNavigate() - const errorModelName = formData.model_name.trim().length <= 0 - const errorModelDescription = formData.model_description.length < 0 - const errorContextLength = formData.context_length === 0 - const errorLanguage = - formData.model_lang === undefined || formData.model_lang.length === 0 - const errorAbility = - formData.model_ability === undefined || formData.model_ability.length === 0 - const errorModelSize = - formData.model_specs && - formData.model_specs.some((spec) => { - return ( - spec.model_size_in_billions === undefined || - spec.model_size_in_billions === 0 - ) - }) - const errorFamily = familyLabel === '' - const errorAny = - errorModelName || - errorModelDescription || - errorContextLength || - errorLanguage || - errorAbility || - errorModelSize || - errorFamily - useEffect(() => { - if (cookie.token === '' || cookie.token === undefined) { - return - } - if (cookie.token === 'need_auth') { + if ( + sessionStorage.getItem('auth') === 'true' && + !isValidBearerToken(sessionStorage.getItem('token')) && + !isValidBearerToken(cookie.token) + ) { navigate('/login', { replace: true }) - return - } - - const getBuiltinFamilies = async () => { - const response = await fetch(endPoint + '/v1/models/families', { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) - if (!response.ok) { - const errorData = await response.json() // Assuming the server returns error details in JSON format - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - } else { - const data = await response.json() - data.chat.push('other') - data.generate.push('other') - setFamily(data) - } - } - - const getBuiltInPromptStyles = async () => { - const response = await fetch(endPoint + '/v1/models/prompts', { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - }) - if (!response.ok) { - const errorData = await response.json() // Assuming the server returns error details in JSON format - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - } else { - const data = await response.json() - let res = [] - for (const key in data) { - let v = data[key] - v['name'] = key - res.push(v) - } - setPromptStyles(res) - } - } - // avoid keep requesting backend to get prompts - if (promptStyles.length === 0) { - getBuiltInPromptStyles().catch((error) => { - setErrorMsg( - error.message || - 'An unexpected error occurred when getting builtin prompt styles.' - ) - console.error('Error: ', error) - }) - } - if (family.chat.length === 0) { - getBuiltinFamilies().catch((error) => { - setErrorMsg( - error.message || - 'An unexpected error occurred when getting builtin prompt styles.' - ) - console.error('Error: ', error) - }) } }, [cookie.token]) - const getFamilyByAbility = () => { - if (formData.model_ability.includes('chat')) { - return family.chat - } else { - return family.generate - } - } - - const isModelFormatPytorch = () => { - return modelFormat === 'pytorch' - } - - const isModelFormatGPTQ = () => { - return modelFormat === 'gptq' - } - - const isModelFormatAWQ = () => { - return modelFormat === 'awq' - } - - const getPathComponents = (path) => { - const normalizedPath = path.replace(/\\/g, '/') - const baseDir = normalizedPath.substring(0, normalizedPath.lastIndexOf('/')) - const filename = normalizedPath.substring( - normalizedPath.lastIndexOf('/') + 1 - ) - return { baseDir, filename } - } - - const handleClick = async () => { - if (isModelFormatGPTQ()) { - formData.model_specs = [ - { - model_format: modelFormat, - model_size_in_billions: modelSize, - quantizations: [quantization], - model_id: '', - model_uri: modelUri, - }, - ] - } else if (isModelFormatAWQ()) { - formData.model_specs = [ - { - model_format: modelFormat, - model_size_in_billions: modelSize, - quantizations: [quantization], - model_id: '', - model_uri: modelUri, - }, - ] - } else if (!isModelFormatPytorch()) { - const { baseDir, filename } = getPathComponents(modelUri) - formData.model_specs = [ - { - model_format: modelFormat, - model_size_in_billions: modelSize, - quantizations: [quantization], - model_id: '', - model_file_name_template: filename, - model_uri: baseDir, - }, - ] - } else { - formData.model_specs = [ - { - model_format: modelFormat, - model_size_in_billions: modelSize, - quantizations: ['4-bit', '8-bit', 'none'], - model_id: '', - model_uri: modelUri, - }, - ] - } - - formData.model_family = familyLabel - - if (formData.model_ability.includes('chat')) { - const ps = promptStyles.find((item) => item.name === familyLabel) - if (ps) { - formData.prompt_style = { - style_name: ps.style_name, - system_prompt: ps.system_prompt, - roles: ps.roles, - intra_message_sep: ps.intra_message_sep, - inter_message_sep: ps.inter_message_sep, - stop: ps.stop ?? null, - stop_token_ids: ps.stop_token_ids ?? null, - } - } - } - - if (errorAny) { - setErrorMsg('Please fill in valid value for all fields') - return - } - - try { - const response = await fetcher(endPoint + '/v1/model_registrations/LLM', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: JSON.stringify(formData), - persist: true, - }), - }) - if (!response.ok) { - const errorData = await response.json() // Assuming the server returns error details in JSON format - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - } else { - setSuccessMsg( - 'Model has been registered successfully! Navigate to launch model page to proceed.' - ) - } - } catch (error) { - console.error('There was a problem with the fetch operation:', error) - setErrorMsg(error.message || 'An unexpected error occurred.') - } - } - - const toggleLanguage = (lang) => { - if (formData.model_lang.includes(lang)) { - setFormData({ - ...formData, - model_lang: formData.model_lang.filter((l) => l !== lang), - }) - } else { - setFormData({ - ...formData, - model_lang: [...formData.model_lang, lang], - }) - } - } - - const toggleAbility = (ability) => { - setFamilyLabel('') - if (formData.model_ability.includes(ability)) { - setFormData({ - ...formData, - model_ability: formData.model_ability.filter((a) => a !== ability), - }) - } else { - setFormData({ - ...formData, - model_ability: [...formData.model_ability, ability], - }) - } + const handleTabChange = (_, newValue) => { + setTabValue(newValue) + navigate(newValue) + sessionStorage.setItem('registerModelType', newValue) } return ( - <Box m="20px"> + <Box m="20px" style={{ overflow: 'hidden' }}> <Title title="Register Model" /> <ErrorMessageSnackBar /> <TabContext value={tabValue}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <TabList value={tabValue} - onChange={(e, v) => { - setTabValue(v) - }} + onChange={handleTabChange} aria-label="tabs" > - <Tab label="Language Model" value="1" /> - <Tab label="Embedding Model" value="2" /> - <Tab label="Rerank Model" value="3" /> + <Tab label="Language Model" value="/register_model/llm" /> + <Tab label="Embedding Model" value="/register_model/embedding" /> + <Tab label="Rerank Model" value="/register_model/rerank" /> + <Tab label="Image Model" value="/register_model/image" /> + <Tab label="Audio Model" value="/register_model/audio" /> + <Tab label="Flexible Model" value="/register_model/flexible" /> </TabList> </Box> - <TabPanel value="1" sx={{ padding: 0 }}> - <Box padding="20px"></Box> - {/* Base Information */} - <FormControl sx={styles.baseFormControl}> - <TextField - label="Model Name" - error={errorModelName} - defaultValue={formData.model_name} - size="small" - helperText="Alphanumeric characters with properly placed hyphens and underscores. Must not match any built-in model names." - onChange={(event) => - setFormData({ ...formData, model_name: event.target.value }) - } - /> - <Box padding="15px"></Box> - - <label - style={{ - paddingLeft: 5, - }} - > - Model Format - </label> - - <RadioGroup - value={modelFormat} - onChange={(e) => { - setModelFormat(e.target.value) - }} - > - <Box sx={styles.checkboxWrapper}> - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel - value="pytorch" - control={<Radio />} - label="PyTorch" - /> - </Box> - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel - value="ggmlv3" - control={<Radio />} - label="GGML" - /> - </Box> - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel - value="ggufv2" - control={<Radio />} - label="GGUF" - /> - </Box> - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel - value="gptq" - control={<Radio />} - label="GPTQ" - /> - </Box> - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel - value="awq" - control={<Radio />} - label="AWQ" - /> - </Box> - </Box> - </RadioGroup> - <Box padding="15px"></Box> - - <TextField - error={errorContextLength} - label="Context Length" - value={formData.context_length} - size="small" - onChange={(event) => { - let value = event.target.value - // Remove leading zeros - if (/^0+/.test(value)) { - value = value.replace(/^0+/, '') || '0' - } - // Ensure it's a positive integer, if not set it to the minimum - if (!/^\d+$/.test(value) || parseInt(value) < 0) { - value = '0' - } - // Update with the processed value - setFormData({ - ...formData, - context_length: Number(value), - }) - }} - /> - <Box padding="15px"></Box> - - <TextField - label="Model Size in Billions" - size="small" - error={errorModelSize} - value={modelSize} - onChange={(e) => { - let value = e.target.value - // Remove leading zeros - if (/^0+/.test(value)) { - value = value.replace(/^0+/, '') || '0' - } - // Ensure it's a positive integer, if not set it to the minimum - if (!/^\d+$/.test(value) || parseInt(value) < 0) { - value = '0' - } - setModelSize(Number(value)) - }} - /> - <Box padding="15px"></Box> - - <TextField - label="Model Path" - size="small" - value={modelUri} - onChange={(e) => { - setModelUri(e.target.value) - }} - helperText="For PyTorch, provide the model directory. For GGML/GGUF, provide the model file path." - /> - <Box padding="15px"></Box> - - <TextField - label="Quantization (Optional)" - size="small" - value={quantization} - onChange={(e) => { - setQuantization(e.target.value) - }} - helperText="For GPTQ/AWQ models, please be careful to fill in the quantization corresponding to the model you want to register." - /> - <Box padding="15px"></Box> - - <TextField - label="Model Description (Optional)" - error={errorModelDescription} - defaultValue={formData.model_description} - size="small" - onChange={(event) => - setFormData({ - ...formData, - model_description: event.target.value, - }) - } - /> - <Box padding="15px"></Box> - - <label - style={{ - paddingLeft: 5, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - > - Model Languages - </label> - <Box sx={styles.checkboxWrapper}> - {SUPPORTED_LANGUAGES.map((lang) => ( - <Box key={lang} sx={{ marginRight: '10px' }}> - <FormControlLabel - control={ - <Checkbox - checked={formData.model_lang.includes(lang)} - onChange={() => toggleLanguage(lang)} - name={lang} - sx={ - errorLanguage - ? { - 'color': ERROR_COLOR, - '&.Mui-checked': { - color: ERROR_COLOR, - }, - } - : {} - } - /> - } - label={SUPPORTED_LANGUAGES_DICT[lang]} - style={{ - paddingLeft: 10, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - /> - </Box> - ))} - </Box> - <Box padding="15px"></Box> - - <label - style={{ - paddingLeft: 5, - color: errorAbility ? ERROR_COLOR : 'inherit', - }} - > - Model Abilities - </label> - <Box sx={styles.checkboxWrapper}> - {SUPPORTED_FEATURES.map((ability) => ( - <Box key={ability} sx={{ marginRight: '10px' }}> - <FormControlLabel - control={ - <Checkbox - checked={formData.model_ability.includes( - ability.toLowerCase() - )} - onChange={() => toggleAbility(ability.toLowerCase())} - name={ability} - sx={ - errorAbility - ? { - 'color': ERROR_COLOR, - '&.Mui-checked': { - color: ERROR_COLOR, - }, - } - : {} - } - /> - } - label={ability} - style={{ - paddingLeft: 10, - color: errorAbility ? ERROR_COLOR : 'inherit', - }} - /> - </Box> - ))} - </Box> - <Box padding="15px"></Box> - </FormControl> - - <FormControl sx={styles.baseFormControl}> - <label - style={{ - paddingLeft: 5, - color: errorAbility ? ERROR_COLOR : 'inherit', - }} - > - Model Family - </label> - <FormHelperText> - Please be careful to select the family name corresponding to the - model you want to register. If not found, please choose `other`. - </FormHelperText> - <RadioGroup - value={familyLabel} - onChange={(e) => { - setFamilyLabel(e.target.value) - }} - > - <Box sx={styles.checkboxWrapper}> - {getFamilyByAbility().map((v) => ( - <Box sx={{ marginLeft: '10px' }}> - <FormControlLabel value={v} control={<Radio />} label={v} /> - </Box> - ))} - </Box> - </RadioGroup> - <Box padding="15px"></Box> - </FormControl> - - <Box width={'100%'}> - {successMsg !== '' && ( - <Alert severity="success"> - <AlertTitle>Success</AlertTitle> - {successMsg} - </Alert> - )} - <Button - variant="contained" - color="primary" - type="submit" - onClick={handleClick} - > - Register Model - </Button> - </Box> + <TabPanel value="/register_model/llm" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="LLM" + customData={{ + version: 1, + model_name: 'custom-llm', + model_description: 'This is a custom model description.', + context_length: 2048, + model_lang: ['en'], + model_ability: ['generate'], + model_family: '', + model_specs: [ + { + model_uri: '/path/to/llama-1', + model_size_in_billions: 7, + model_format: 'pytorch', + quantizations: ['none'], + }, + ], + prompt_style: undefined, + }} + /> + </TabPanel> + <TabPanel value="/register_model/embedding" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="embedding" + customData={{ + model_name: 'custom-embedding', + dimensions: 768, + max_tokens: 512, + model_uri: '/path/to/embedding-model', + language: ['en'], + }} + /> + </TabPanel> + <TabPanel value="/register_model/rerank" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="rerank" + customData={{ + model_name: 'custom-rerank', + model_uri: '/path/to/rerank-model', + language: ['en'], + }} + /> </TabPanel> - <TabPanel value="2" sx={{ padding: 0 }}> - <RegisterEmbeddingModel /> + <TabPanel value="/register_model/image" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="image" + customData={{ + model_name: 'custom-image', + model_uri: '/path/to/image-model', + model_family: 'stable_diffusion', + controlnet: [], + }} + /> </TabPanel> - <TabPanel value="3" sx={{ padding: 0 }}> - <RegisterRerankModel /> + <TabPanel value="/register_model/audio" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="audio" + customData={{ + model_name: 'custom-audio', + model_uri: '/path/to/audio-model', + multilingual: false, + model_family: 'whisper', + }} + /> + </TabPanel> + <TabPanel value="/register_model/flexible" sx={{ padding: 0 }}> + <RegisterModelComponent + modelType="flexible" + customData={{ + model_name: 'flexible-model', + model_description: 'This is a model description.', + model_uri: '/path/to/model', + launcher: 'xinference.model.flexible.launchers.transformers', + launcher_args: '{}', + }} + /> </TabPanel> </TabContext> </Box> @@ -627,32 +138,3 @@ const RegisterModel = () => { } export default RegisterModel - -const styles = { - baseFormControl: { - width: '100%', - margin: 'normal', - size: 'small', - }, - checkboxWrapper: { - display: 'flex', - flexWrap: 'wrap', - maxWidth: '80%', - }, - labelPaddingLeft: { - paddingLeft: 5, - }, - formControlLabelPaddingLeft: { - paddingLeft: 10, - }, - buttonBox: { - width: '100%', - margin: '20px', - }, - error: { - fontWeight: 'bold', - margin: '5px 0', - padding: '1px', - borderRadius: '5px', - }, -} diff --git a/xinference/web/ui/src/scenes/register_model/registerModel.js b/xinference/web/ui/src/scenes/register_model/registerModel.js new file mode 100644 index 0000000000..06cc582927 --- /dev/null +++ b/xinference/web/ui/src/scenes/register_model/registerModel.js @@ -0,0 +1,1033 @@ +import './styles/registerModelStyle.css' + +import CheckIcon from '@mui/icons-material/Check' +import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight' +import NotesIcon from '@mui/icons-material/Notes' +import { + Alert, + Box, + Button, + Checkbox, + Chip, + FormControl, + FormControlLabel, + InputLabel, + MenuItem, + Radio, + RadioGroup, + Select, + Stack, + Switch, + TextField, + Tooltip, +} from '@mui/material' +import React, { useContext, useEffect, useRef, useState } from 'react' +import { useCookies } from 'react-cookie' +import { useNavigate, useParams } from 'react-router-dom' + +import { ApiContext } from '../../components/apiContext' +import CopyComponent from '../../components/copyComponent/copyComponent' +import fetchWrapper from '../../components/fetchWrapper' +import { isValidBearerToken } from '../../components/utils' +import AddControlnet from './components/addControlnet' +import AddModelSpecs from './components/addModelSpecs' +import languages from './data/languages' +const SUPPORTED_LANGUAGES_DICT = { en: 'English', zh: 'Chinese' } +const SUPPORTED_FEATURES = ['Generate', 'Chat', 'Vision'] + +// Convert dictionary of supported languages into list +const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT) + +const RegisterModelComponent = ({ modelType, customData }) => { + const endPoint = useContext(ApiContext).endPoint + const { setErrorMsg } = useContext(ApiContext) + const [formData, setFormData] = useState(customData) + const [promptStyles, setPromptStyles] = useState([]) + const [family, setFamily] = useState({ + chat: [], + generate: [], + }) + const [languagesArr, setLanguagesArr] = useState([]) + const [isContextLengthAlert, setIsContextLengthAlert] = useState(false) + const [isDimensionsAlert, setIsDimensionsAlert] = useState(false) + const [isMaxTokensAlert, setIsMaxTokensAlert] = useState(false) + const [jsonData, setJsonData] = useState('') + const [isSpecsArrError, setIsSpecsArrError] = useState(false) + const [isValidLauncherArgsAlert, setIsValidLauncherArgsAlert] = + useState(false) + const scrollRef = useRef(null) + const [cookie] = useCookies(['token']) + const navigate = useNavigate() + + const { registerModelType, model_name } = useParams() + const [isShow, setIsShow] = useState(model_name ? true : false) + const [specsArr, setSpecsArr] = useState( + model_name + ? JSON.parse(sessionStorage.getItem('customJsonData')).model_specs + : [] + ) + const [controlnetArr, setControlnetArr] = useState( + model_name + ? JSON.parse(sessionStorage.getItem('customJsonData')).controlnet + : [] + ) + const [contrastObj, setContrastObj] = useState({}) + const [isEqual, setIsEqual] = useState(true) + + useEffect(() => { + if (model_name) { + const data = JSON.parse(sessionStorage.getItem('customJsonData')) + + if (modelType === 'LLM') { + const lagArr = data.model_lang.filter( + (item) => item !== 'en' && item !== 'zh' + ) + setLanguagesArr(lagArr) + + const { + version, + model_name, + model_description, + context_length, + model_lang, + model_ability, + model_family, + model_specs, + prompt_style, + } = data + const specsDataArr = model_specs.map((item) => { + const { + model_uri, + model_size_in_billions, + model_format, + quantizations, + model_file_name_template, + } = item + return { + model_uri, + model_size_in_billions, + model_format, + quantizations, + model_file_name_template, + } + }) + const llmData = { + version, + model_name, + model_description, + context_length, + model_lang, + model_ability, + model_family, + model_specs: specsDataArr, + } + prompt_style ? (llmData.prompt_style = prompt_style) : '' + setFormData(llmData) + setContrastObj(llmData) + setSpecsArr(specsDataArr) + } else { + if (modelType === 'embedding') { + const lagArr = data.language.filter( + (item) => item !== 'en' && item !== 'zh' + ) + setLanguagesArr(lagArr) + + const { model_name, dimensions, max_tokens, model_uri, language } = + data + const embeddingData = { + model_name, + dimensions, + max_tokens, + model_uri, + language, + } + setFormData(embeddingData) + setContrastObj(embeddingData) + } else if (modelType === 'rerank') { + const lagArr = data.language.filter( + (item) => item !== 'en' && item !== 'zh' + ) + setLanguagesArr(lagArr) + + const { model_name, model_uri, language } = data + const rerankData = { + model_name, + model_uri, + language, + } + setFormData(rerankData) + setContrastObj(rerankData) + } else if (modelType === 'image') { + const { model_name, model_uri, model_family, controlnet } = data + const controlnetArr = controlnet.map((item) => { + const { model_name, model_uri, model_family } = item + return { + model_name, + model_uri, + model_family, + } + }) + const imageData = { + model_name, + model_uri, + model_family, + controlnet: controlnetArr, + } + setFormData(imageData) + setContrastObj(imageData) + setControlnetArr(controlnetArr) + } else if (modelType === 'audio') { + const { model_name, model_uri, multilingual, model_family } = data + const audioData = { + model_name, + model_uri, + multilingual, + model_family, + } + setFormData(audioData) + setContrastObj(audioData) + } else if (modelType === 'flexible') { + const { + model_name, + model_uri, + model_description, + launcher, + launcher_args, + } = data + const flexibleData = { + model_name, + model_uri, + model_description, + launcher, + launcher_args, + } + setFormData(flexibleData) + setContrastObj(flexibleData) + } + } + } + }, [model_name]) + + useEffect(() => { + if ( + sessionStorage.getItem('auth') === 'true' && + !isValidBearerToken(sessionStorage.getItem('token')) && + !isValidBearerToken(cookie.token) + ) { + navigate('/login', { replace: true }) + return + } + + const getBuiltinFamilies = async () => { + const response = await fetch(endPoint + '/v1/models/families', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + if (!response.ok) { + const errorData = await response.json() // Assuming the server returns error details in JSON format + setErrorMsg( + `Server error: ${response.status} - ${ + errorData.detail || 'Unknown error' + }` + ) + } else { + const data = await response.json() + data.chat.push('other') + data.generate.push('other') + setFamily(data) + } + } + + const getBuiltInPromptStyles = async () => { + const response = await fetch(endPoint + '/v1/models/prompts', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + if (!response.ok) { + const errorData = await response.json() // Assuming the server returns error details in JSON format + setErrorMsg( + `Server error: ${response.status} - ${ + errorData.detail || 'Unknown error' + }` + ) + } else { + const data = await response.json() + let res = [] + for (const key in data) { + let v = data[key] + v['name'] = key + res.push(v) + } + setPromptStyles(res) + } + } + + if ( + Object.prototype.hasOwnProperty.call(customData, 'model_ability') && + Object.prototype.hasOwnProperty.call(customData, 'model_family') + ) { + // avoid keep requesting backend to get prompts + if (promptStyles.length === 0) { + getBuiltInPromptStyles().catch((error) => { + setErrorMsg( + error.message || + 'An unexpected error occurred when getting builtin prompt styles.' + ) + console.error('Error: ', error) + }) + } + if (family.chat.length === 0) { + getBuiltinFamilies().catch((error) => { + setErrorMsg( + error.message || + 'An unexpected error occurred when getting builtin prompt styles.' + ) + console.error('Error: ', error) + }) + } + } + }, [cookie.token]) + + useEffect(() => { + setJsonData(JSON.stringify(formData, null, 4)) + if (contrastObj.model_name) { + deepEqual(contrastObj, formData) ? setIsEqual(true) : setIsEqual(false) + } + }, [formData]) + + const getFamilyByAbility = () => { + if ( + formData.model_ability.includes('chat') || + formData.model_ability.includes('vision') + ) { + return family.chat + } else { + return family.generate + } + } + + const sortStringsByFirstLetter = (arr) => { + return arr.sort((a, b) => { + const firstCharA = a.charAt(0).toLowerCase() + const firstCharB = b.charAt(0).toLowerCase() + if (firstCharA < firstCharB) { + return -1 + } + if (firstCharA > firstCharB) { + return 1 + } + return 0 + }) + } + + const handleClick = async () => { + console.log('formData', modelType, formData) + + for (let key in formData) { + const type = Object.prototype.toString.call(formData[key]).slice(8, -1) + if ( + key !== 'model_description' && + ((type === 'Array' && + key !== 'controlnet' && + formData[key].length === 0) || + (type === 'String' && formData[key] === '') || + (type === 'Number' && formData[key] <= 0)) + ) { + setErrorMsg('Please fill in valid value for all fields') + return + } + } + + if ( + isSpecsArrError || + isContextLengthAlert || + isDimensionsAlert || + isMaxTokensAlert + ) { + setErrorMsg('Please fill in valid value for all fields') + return + } + + try { + fetchWrapper + .post(`/v1/model_registrations/${modelType}`, { + model: JSON.stringify(formData), + persist: true, + }) + .then(() => { + navigate(`/launch_model/custom/${modelType.toLowerCase()}`) + sessionStorage.setItem('modelType', '/launch_model/custom/llm') + sessionStorage.setItem( + 'subType', + `/launch_model/custom/${modelType.toLowerCase()}` + ) + }) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403 && error.response.status !== 401) { + setErrorMsg(error.message) + } + }) + } catch (error) { + console.error('There was a problem with the fetch operation:', error) + setErrorMsg(error.message || 'An unexpected error occurred.') + } + } + + const handleNumber = (value, parameterName) => { + setIsContextLengthAlert(false) + setIsDimensionsAlert(false) + setIsMaxTokensAlert(false) + setFormData({ ...formData, [parameterName]: value }) + + if ( + value !== '' && + (!Number(value) || + Number(value) <= 0 || + parseInt(value) !== parseFloat(value)) + ) { + parameterName === 'context_length' ? setIsContextLengthAlert(true) : '' + parameterName === 'dimensions' ? setIsDimensionsAlert(true) : '' + parameterName === 'max_tokens' ? setIsMaxTokensAlert(true) : '' + } else if (value !== '') { + setFormData({ ...formData, [parameterName]: Number(value) }) + } + } + + const toggleLanguage = (lang) => { + if (modelType === 'LLM') { + if (formData.model_lang.includes(lang)) { + setFormData({ + ...formData, + model_lang: formData.model_lang.filter((l) => l !== lang), + }) + } else { + setFormData({ + ...formData, + model_lang: [...formData.model_lang, lang], + }) + } + } else { + if (formData.language.includes(lang)) { + setFormData({ + ...formData, + language: formData.language.filter((l) => l !== lang), + }) + } else { + setFormData({ + ...formData, + language: [...formData.language, lang], + }) + } + } + } + + const toggleAbility = (ability) => { + if (formData.model_ability.includes(ability)) { + const obj = JSON.parse(JSON.stringify(formData)) + if (ability === 'chat') { + delete obj.prompt_style + } + setFormData({ + ...obj, + model_ability: formData.model_ability.filter((a) => a !== ability), + model_family: '', + }) + } else { + setFormData({ + ...formData, + model_ability: [...formData.model_ability, ability], + model_family: '', + }) + } + } + + const toggleFamily = (value) => { + const ps = promptStyles.find((item) => item.name === value) + if (formData.model_ability.includes('chat') && ps) { + const prompt_style = { + style_name: ps.style_name, + system_prompt: ps.system_prompt, + roles: ps.roles, + intra_message_sep: ps.intra_message_sep, + inter_message_sep: ps.inter_message_sep, + stop: ps.stop ?? null, + stop_token_ids: ps.stop_token_ids ?? null, + } + setFormData({ + ...formData, + model_family: value, + prompt_style, + }) + } else { + const { + version, + model_name, + model_description, + context_length, + model_lang, + model_ability, + model_specs, + } = formData + setFormData({ + version, + model_name, + model_description, + context_length, + model_lang, + model_ability, + model_family: value, + model_specs, + }) + } + } + + const handleSelectLanguages = (value) => { + const arr = [...languagesArr, value] + setLanguagesArr(arr) + if (modelType === 'LLM') { + setFormData({ + ...formData, + model_lang: Array.from(new Set([...formData.model_lang, ...arr])), + }) + } else { + setFormData({ + ...formData, + language: Array.from(new Set([...formData.language, ...arr])), + }) + } + } + + const handleDeleteLanguages = (item) => { + const arr = languagesArr.filter((subItem) => subItem !== item) + setLanguagesArr(arr) + if (modelType === 'LLM') { + setFormData({ + ...formData, + model_lang: formData.model_lang.filter((subItem) => subItem !== item), + }) + } else { + setFormData({ + ...formData, + language: formData.language.filter((subItem) => subItem !== item), + }) + } + } + + const getSpecsArr = (arr, isSpecsArrError) => { + setFormData({ ...formData, model_specs: arr }) + setIsSpecsArrError(isSpecsArrError) + } + + const getControlnetArr = (arr) => { + setFormData({ ...formData, controlnet: arr }) + } + + const handleCancel = () => { + navigate(`/launch_model/custom/${registerModelType}`) + } + + const handleEdit = () => { + fetchWrapper + .delete( + `/v1/model_registrations/${ + registerModelType === 'llm' ? 'LLM' : registerModelType + }/${model_name}` + ) + .then(() => handleClick()) + .catch((error) => { + console.error('Error:', error) + if (error.response.status !== 403 && error.response.status !== 401) { + setErrorMsg(error.message) + } + }) + } + + const deepEqual = (obj1, obj2) => { + if (obj1 === obj2) return true + if ( + typeof obj1 !== 'object' || + typeof obj2 !== 'object' || + obj1 == null || + obj2 == null + ) { + return false + } + + let keysA = Object.keys(obj1) + let keysB = Object.keys(obj2) + if (keysA.length !== keysB.length) return false + for (let key of keysA) { + if (!keysB.includes(key) || !deepEqual(obj1[key], obj2[key])) { + return false + } + } + return true + } + + return ( + <Box style={{ display: 'flex', overFlow: 'hidden', maxWidth: '100%' }}> + <div className="show-json"> + <p>Show custom json config used by api</p> + {isShow ? ( + <Tooltip title="Pack up" placement="top"> + <KeyboardDoubleArrowRightIcon + className="icon arrow" + onClick={() => setIsShow(!isShow)} + /> + </Tooltip> + ) : ( + <Tooltip title="Unfold" placement="top"> + <NotesIcon + className="icon notes" + onClick={() => setIsShow(!isShow)} + /> + </Tooltip> + )} + </div> + <div ref={scrollRef} className={isShow ? 'formBox' : 'formBox broaden'}> + {/* Base Information */} + <FormControl style={{ width: '100%' }}> + {/* name */} + {customData.model_name && ( + <> + <TextField + label="Model Name" + error={formData.model_name ? false : true} + value={formData.model_name} + size="small" + helperText="Alphanumeric characters with properly placed hyphens and underscores. Must not match any built-in model names." + onChange={(event) => + setFormData({ ...formData, model_name: event.target.value }) + } + /> + <Box padding="15px"></Box> + </> + )} + + {/* description */} + {customData.model_description && ( + <> + <TextField + label="Model Description (Optional)" + value={formData.model_description} + size="small" + onChange={(event) => + setFormData({ + ...formData, + model_description: event.target.value, + }) + } + /> + <Box padding="15px"></Box> + </> + )} + + {/* Context Length */} + {customData.context_length && ( + <> + <TextField + error={Number(formData.context_length) > 0 ? false : true} + label="Context Length" + value={formData.context_length} + size="small" + onChange={(event) => { + handleNumber(event.target.value, 'context_length') + }} + /> + {isContextLengthAlert && ( + <Alert severity="error"> + Please enter an integer greater than 0. + </Alert> + )} + <Box padding="15px"></Box> + </> + )} + + {/* dimensions */} + {customData.dimensions && ( + <> + <TextField + label="Dimensions" + error={Number(formData.dimensions) > 0 ? false : true} + value={formData.dimensions} + size="small" + onChange={(event) => { + handleNumber(event.target.value, 'dimensions') + }} + /> + {isDimensionsAlert && ( + <Alert severity="error"> + Please enter an integer greater than 0. + </Alert> + )} + <Box padding="15px"></Box> + </> + )} + + {/* Max Tokens */} + {customData.max_tokens && ( + <> + <TextField + label="Max Tokens" + error={Number(formData.max_tokens) > 0 ? false : true} + value={formData.max_tokens} + size="small" + onChange={(event) => { + handleNumber(event.target.value, 'max_tokens') + }} + /> + {isMaxTokensAlert && ( + <Alert severity="error"> + Please enter an integer greater than 0. + </Alert> + )} + <Box padding="15px"></Box> + </> + )} + + {/* path */} + {customData.model_uri && ( + <> + <TextField + label="Model Path" + error={formData.model_uri ? false : true} + value={formData.model_uri} + size="small" + helperText="Provide the model directory path." + onChange={(event) => + setFormData({ ...formData, model_uri: event.target.value }) + } + /> + <Box padding="15px"></Box> + </> + )} + + {/* model_lang */} + {(customData.model_lang || customData.language) && ( + <> + <label + style={{ + paddingLeft: 5, + color: + modelType === 'LLM' + ? formData.model_lang.length === 0 + ? '#d32f2f' + : 'inherit' + : formData.language.length === 0 + ? '#d32f2f' + : 'inherit', + }} + > + Model Languages + </label> + <Box className="checkboxWrapper"> + {SUPPORTED_LANGUAGES.map((lang) => ( + <Box key={lang} sx={{ marginRight: '10px' }}> + <FormControlLabel + control={ + <Checkbox + checked={ + modelType === 'LLM' + ? formData.model_lang.includes(lang) + : formData.language.includes(lang) + } + onChange={() => toggleLanguage(lang)} + name={lang} + /> + } + label={SUPPORTED_LANGUAGES_DICT[lang]} + style={{ + paddingLeft: 10, + }} + /> + </Box> + ))} + <FormControl sx={{ m: 1, minWidth: 120 }} size="small"> + <InputLabel>Languages</InputLabel> + <Select + value={''} + label="Languages" + onChange={(e) => handleSelectLanguages(e.target.value)} + MenuProps={{ + PaperProps: { + style: { maxHeight: '20vh' }, + }, + }} + > + {languages + .filter((item) => !languagesArr.includes(item.code)) + .map((item) => ( + <MenuItem key={item.code} value={item.code}> + {item.code} + </MenuItem> + ))} + </Select> + </FormControl> + </Box> + <Stack direction="row" spacing={1} style={{ marginLeft: '10px' }}> + {languagesArr.map((item) => ( + <Chip + key={item} + label={item} + variant="outlined" + size="small" + color="primary" + onDelete={() => handleDeleteLanguages(item)} + /> + ))} + </Stack> + <Box padding="15px"></Box> + </> + )} + + {/* multilingual */} + {'multilingual' in customData && ( + <> + <label + style={{ + paddingLeft: 5, + }} + > + Multilingual + </label> + <FormControlLabel + style={{ marginLeft: 0, width: 50 }} + control={<Switch checked={formData.multilingual} />} + onChange={(e) => + setFormData({ ...formData, multilingual: e.target.checked }) + } + /> + <Box padding="15px"></Box> + </> + )} + + {/* abilities */} + {customData.model_ability && ( + <> + <label + style={{ + paddingLeft: 5, + color: + formData.model_ability.length == 0 ? '#d32f2f' : 'inherit', + }} + > + Model Abilities + </label> + <Box className="checkboxWrapper"> + {SUPPORTED_FEATURES.map((ability) => ( + <Box key={ability} sx={{ marginRight: '10px' }}> + <FormControlLabel + control={ + <Checkbox + checked={formData.model_ability.includes( + ability.toLowerCase() + )} + onChange={() => toggleAbility(ability.toLowerCase())} + name={ability} + /> + } + label={ability} + style={{ + paddingLeft: 10, + }} + /> + </Box> + ))} + </Box> + <Box padding="15px"></Box> + </> + )} + + {/* family */} + {(customData.model_family === '' || customData.model_family) && ( + <FormControl> + <label + style={{ + paddingLeft: 5, + color: 'inherit', + }} + > + Model Family + </label> + {modelType === 'LLM' && formData.model_family && ( + <Alert + icon={<CheckIcon fontSize="inherit" />} + severity="success" + > + Please be careful to select the family name corresponding to + the model you want to register. If not found, please choose + <i style={{ fontStyle: 'italic', fontWeight: 700 }}> other</i> + . + </Alert> + )} + {modelType === 'LLM' && !formData.model_family && ( + <Alert severity="error"> + Please be careful to select the family name corresponding to + the model you want to register. If not found, please choose + <i style={{ fontStyle: 'italic', fontWeight: 700 }}> other</i> + . + </Alert> + )} + <RadioGroup + value={formData.model_family} + onChange={(e) => { + toggleFamily(e.target.value) + }} + > + <Box + className="checkboxWrapper" + style={{ paddingLeft: '10px' }} + > + {modelType === 'LLM' && + sortStringsByFirstLetter(getFamilyByAbility()).map((v) => ( + <Box sx={{ width: '20%' }} key={v}> + <FormControlLabel + value={v} + control={<Radio />} + label={v} + /> + </Box> + ))} + {(modelType === 'image' || modelType === 'audio') && ( + <FormControlLabel + value={formData.model_family} + checked + control={<Radio />} + label={formData.model_family} + /> + )} + </Box> + </RadioGroup> + <Box padding="15px"></Box> + </FormControl> + )} + + {/* specs */} + {customData.model_specs && ( + <> + <AddModelSpecs + isJump={model_name ? true : false} + formData={customData.model_specs[0]} + specsDataArr={specsArr} + onGetArr={getSpecsArr} + scrollRef={scrollRef} + /> + <Box padding="15px"></Box> + </> + )} + + {/* controlnet */} + {customData.controlnet && ( + <> + <AddControlnet + controlnetDataArr={controlnetArr} + onGetControlnetArr={getControlnetArr} + scrollRef={scrollRef} + /> + <Box padding="15px"></Box> + </> + )} + + {/* launcher */} + {customData.launcher && ( + <> + <TextField + label="Launcher" + error={formData.launcher ? false : true} + value={formData.launcher} + size="small" + helperText="Provide the model launcher." + onChange={(event) => + setFormData({ ...formData, launcher: event.target.value }) + } + /> + <Box padding="15px"></Box> + </> + )} + + {/* launcher_args */} + {customData.launcher_args && ( + <> + <TextField + label="Launcher Arguments (Optional)" + value={formData.launcher_args} + size="small" + helperText="A JSON-formatted dictionary representing the arguments passed to the Launcher." + onChange={(event) => { + try { + JSON.parse(event.target.value) + setIsValidLauncherArgsAlert(false) + } catch { + setIsValidLauncherArgsAlert(true) + } + return setFormData({ + ...formData, + launcher_args: event.target.value, + }) + }} + multiline + rows={4} + /> + {isValidLauncherArgsAlert && ( + <Alert severity="error"> + Please enter the JSON-formatted dictionary. + </Alert> + )} + <Box padding="15px"></Box> + </> + )} + </FormControl> + + {model_name ? ( + <> + <Button + variant="contained" + color="primary" + type="submit" + onClick={handleEdit} + disabled={isEqual} + > + Edit + </Button> + <Button + style={{ marginLeft: 30 }} + variant="outlined" + color="primary" + type="submit" + onClick={handleCancel} + > + Cancel + </Button> + </> + ) : ( + <Box width={'100%'}> + <Button + variant="contained" + color="primary" + type="submit" + onClick={handleClick} + > + Register Model + </Button> + </Box> + )} + </div> + + {/* JSON */} + <div className={isShow ? 'jsonBox' : 'jsonBox hide'}> + <div className="jsonBox-header"> + <div className="jsonBox-title">JSON Format</div> + <CopyComponent tip={'Copy all'} text={jsonData} /> + </div> + <textarea readOnly className="textarea" value={jsonData} /> + </div> + </Box> + ) +} + +export default RegisterModelComponent diff --git a/xinference/web/ui/src/scenes/register_model/register_embedding.js b/xinference/web/ui/src/scenes/register_model/register_embedding.js deleted file mode 100644 index ac7ab8d4ae..0000000000 --- a/xinference/web/ui/src/scenes/register_model/register_embedding.js +++ /dev/null @@ -1,239 +0,0 @@ -import { Box, Checkbox, FormControl, FormControlLabel } from '@mui/material' -import Alert from '@mui/material/Alert' -import AlertTitle from '@mui/material/AlertTitle' -import Button from '@mui/material/Button' -import TextField from '@mui/material/TextField' -import React, { useContext, useState } from 'react' - -import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' -import { useMode } from '../../theme' - -const SUPPORTED_LANGUAGES_DICT = { en: 'English', zh: 'Chinese' } -// Convert dictionary of supported languages into list -const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT) - -const RegisterEmbeddingModel = () => { - const ERROR_COLOR = useMode() - const endPoint = useContext(ApiContext).endPoint - const { setErrorMsg } = useContext(ApiContext) - const [successMsg, setSuccessMsg] = useState('') - const [formData, setFormData] = useState({ - model_name: 'custom-embedding', - dimensions: 768, - max_tokens: 512, - language: ['en'], - model_uri: '/path/to/embedding-model', - }) - - const errorModelName = formData.model_name.trim().length <= 0 - const errorDimensions = formData.dimensions < 0 - const errorMaxTokens = formData.max_tokens < 0 - const errorLanguage = - formData.language === undefined || formData.language.length === 0 - - const handleClick = async () => { - const errorAny = - errorModelName || errorDimensions || errorMaxTokens || errorLanguage - - if (errorAny) { - setErrorMsg('Please fill in valid value for all fields') - return - } - - try { - const response = await fetcher( - endPoint + '/v1/model_registrations/embedding', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: JSON.stringify(formData), - persist: true, - }), - } - ) - if (!response.ok) { - const errorData = await response.json() // Assuming the server returns error details in JSON format - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - } else { - setSuccessMsg( - 'Model has been registered successfully! Navigate to launch model page to proceed.' - ) - } - } catch (error) { - console.error('There was a problem with the fetch operation:', error) - setErrorMsg(error.message || 'An unexpected error occurred.') - } - } - - const toggleLanguage = (lang) => { - if (formData.language.includes(lang)) { - setFormData({ - ...formData, - language: formData.language.filter((l) => l !== lang), - }) - } else { - setFormData({ - ...formData, - language: [...formData.language, lang], - }) - } - } - - return ( - <React.Fragment> - <Box padding="20px"></Box> - {/* Base Information */} - <FormControl sx={styles.baseFormControl}> - <TextField - label="Model Name" - error={errorModelName} - defaultValue={formData.model_name} - size="small" - helperText="Alphanumeric characters with properly placed hyphens and underscores. Must not match any built-in model names." - onChange={(event) => - setFormData({ ...formData, model_name: event.target.value }) - } - /> - <Box padding="15px"></Box> - - <TextField - error={errorDimensions} - label="Dimensions" - value={formData.dimensions} - size="small" - onChange={(event) => { - setFormData({ - ...formData, - dimensions: parseInt(event.target.value, 10), - }) - }} - /> - <Box padding="15px"></Box> - - <TextField - error={errorMaxTokens} - label="Max Tokens" - value={formData.max_tokens} - size="small" - onChange={(event) => { - setFormData({ - ...formData, - max_tokens: parseInt(event.target.value, 10), - }) - }} - /> - <Box padding="15px"></Box> - - <TextField - label="Model Path" - size="small" - value={formData.model_uri} - onChange={(e) => { - setFormData({ - ...formData, - model_uri: e.target.value, - }) - }} - helperText="Provide the model directory path." - /> - <Box padding="15px"></Box> - - <label - style={{ - paddingLeft: 5, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - > - Model Languages - </label> - <Box sx={styles.checkboxWrapper}> - {SUPPORTED_LANGUAGES.map((lang) => ( - <Box key={lang} sx={{ marginRight: '10px' }}> - <FormControlLabel - control={ - <Checkbox - checked={formData.language.includes(lang)} - onChange={() => toggleLanguage(lang)} - name={lang} - sx={ - errorLanguage - ? { - 'color': ERROR_COLOR, - '&.Mui-checked': { - color: ERROR_COLOR, - }, - } - : {} - } - /> - } - label={SUPPORTED_LANGUAGES_DICT[lang]} - style={{ - paddingLeft: 10, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - /> - </Box> - ))} - </Box> - <Box padding="15px"></Box> - </FormControl> - - <Box width={'100%'}> - {successMsg !== '' && ( - <Alert severity="success"> - <AlertTitle>Success</AlertTitle> - {successMsg} - </Alert> - )} - <Button - variant="contained" - color="primary" - type="submit" - onClick={handleClick} - > - Register Model - </Button> - </Box> - </React.Fragment> - ) -} - -export default RegisterEmbeddingModel - -const styles = { - baseFormControl: { - width: '100%', - margin: 'normal', - size: 'small', - }, - checkboxWrapper: { - display: 'flex', - flexWrap: 'wrap', - maxWidth: '80%', - }, - labelPaddingLeft: { - paddingLeft: 5, - }, - formControlLabelPaddingLeft: { - paddingLeft: 10, - }, - buttonBox: { - width: '100%', - margin: '20px', - }, - error: { - fontWeight: 'bold', - margin: '5px 0', - padding: '1px', - borderRadius: '5px', - }, -} diff --git a/xinference/web/ui/src/scenes/register_model/register_rerank.js b/xinference/web/ui/src/scenes/register_model/register_rerank.js deleted file mode 100644 index 075b35ff9d..0000000000 --- a/xinference/web/ui/src/scenes/register_model/register_rerank.js +++ /dev/null @@ -1,206 +0,0 @@ -import { Box, Checkbox, FormControl, FormControlLabel } from '@mui/material' -import Alert from '@mui/material/Alert' -import AlertTitle from '@mui/material/AlertTitle' -import Button from '@mui/material/Button' -import TextField from '@mui/material/TextField' -import React, { useContext, useState } from 'react' - -import { ApiContext } from '../../components/apiContext' -import fetcher from '../../components/fetcher' -import { useMode } from '../../theme' - -const SUPPORTED_LANGUAGES_DICT = { en: 'English', zh: 'Chinese' } -// Convert dictionary of supported languages into list -const SUPPORTED_LANGUAGES = Object.keys(SUPPORTED_LANGUAGES_DICT) - -const RegisterRerankModel = () => { - const ERROR_COLOR = useMode() - const endPoint = useContext(ApiContext).endPoint - const { setErrorMsg } = useContext(ApiContext) - const [successMsg, setSuccessMsg] = useState('') - const [formData, setFormData] = useState({ - model_name: 'custom-rerank', - language: ['en'], - model_uri: '/path/to/rerank-model', - }) - - const errorModelName = formData.model_name.trim().length <= 0 - const errorLanguage = - formData.language === undefined || formData.language.length === 0 - - const handleClick = async () => { - const errorAny = errorModelName || errorLanguage - - if (errorAny) { - setErrorMsg('Please fill in valid value for all fields') - return - } - - try { - const response = await fetcher( - endPoint + '/v1/model_registrations/rerank', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: JSON.stringify(formData), - persist: true, - }), - } - ) - if (!response.ok) { - const errorData = await response.json() // Assuming the server returns error details in JSON format - setErrorMsg( - `Server error: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - } else { - setSuccessMsg( - 'Model has been registered successfully! Navigate to launch model page to proceed.' - ) - } - } catch (error) { - console.error('There was a problem with the fetch operation:', error) - setErrorMsg(error.message || 'An unexpected error occurred.') - } - } - - const toggleLanguage = (lang) => { - if (formData.language.includes(lang)) { - setFormData({ - ...formData, - language: formData.language.filter((l) => l !== lang), - }) - } else { - setFormData({ - ...formData, - language: [...formData.language, lang], - }) - } - } - - return ( - <React.Fragment> - <Box padding="20px"></Box> - {/* Base Information */} - <FormControl sx={styles.baseFormControl}> - <TextField - label="Model Name" - error={errorModelName} - defaultValue={formData.model_name} - size="small" - helperText="Alphanumeric characters with properly placed hyphens and underscores. Must not match any built-in model names." - onChange={(event) => - setFormData({ ...formData, model_name: event.target.value }) - } - /> - <Box padding="15px"></Box> - - <TextField - label="Model Path" - size="small" - value={formData.model_uri} - onChange={(e) => { - setFormData({ - ...formData, - model_uri: e.target.value, - }) - }} - helperText="Provide the model directory path." - /> - <Box padding="15px"></Box> - - <label - style={{ - paddingLeft: 5, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - > - Model Languages - </label> - <Box sx={styles.checkboxWrapper}> - {SUPPORTED_LANGUAGES.map((lang) => ( - <Box key={lang} sx={{ marginRight: '10px' }}> - <FormControlLabel - control={ - <Checkbox - checked={formData.language.includes(lang)} - onChange={() => toggleLanguage(lang)} - name={lang} - sx={ - errorLanguage - ? { - 'color': ERROR_COLOR, - '&.Mui-checked': { - color: ERROR_COLOR, - }, - } - : {} - } - /> - } - label={SUPPORTED_LANGUAGES_DICT[lang]} - style={{ - paddingLeft: 10, - color: errorLanguage ? ERROR_COLOR : 'inherit', - }} - /> - </Box> - ))} - </Box> - <Box padding="15px"></Box> - </FormControl> - - <Box width={'100%'}> - {successMsg !== '' && ( - <Alert severity="success"> - <AlertTitle>Success</AlertTitle> - {successMsg} - </Alert> - )} - <Button - variant="contained" - color="primary" - type="submit" - onClick={handleClick} - > - Register Model - </Button> - </Box> - </React.Fragment> - ) -} - -export default RegisterRerankModel - -const styles = { - baseFormControl: { - width: '100%', - margin: 'normal', - size: 'small', - }, - checkboxWrapper: { - display: 'flex', - flexWrap: 'wrap', - maxWidth: '80%', - }, - labelPaddingLeft: { - paddingLeft: 5, - }, - formControlLabelPaddingLeft: { - paddingLeft: 10, - }, - buttonBox: { - width: '100%', - margin: '20px', - }, - error: { - fontWeight: 'bold', - margin: '5px 0', - padding: '1px', - borderRadius: '5px', - }, -} diff --git a/xinference/web/ui/src/scenes/register_model/styles/registerModelStyle.css b/xinference/web/ui/src/scenes/register_model/styles/registerModelStyle.css new file mode 100644 index 0000000000..e7d8b9fd68 --- /dev/null +++ b/xinference/web/ui/src/scenes/register_model/styles/registerModelStyle.css @@ -0,0 +1,121 @@ +.formBox { + position: relative; + max-width: 50vw; + min-width: 50vw; + max-height: 80vh; + overflow: auto; + padding: 40px 20px 0 0; + transition: all 0.4s ease-in-out; +} + +.broaden { + max-width: 100%; + min-width: 100%; + padding-right: 0; +} + +.show-json { + display: flex; + align-items: center; + position: fixed; + top: 90px; + right: 60px; + color: #444; +} + +.icon { + position: absolute; + right: -40px; + cursor: pointer; + margin-left: 20px; +} + +.icon:hover { + color: #1976d2; +} + +.arrow { + font-size: 24px !important; +} + +.jsonBox { + position: relative; + min-height: 80vh; + width: 100%; + transition: all 0.4s ease-in-out; +} + +.hide { + width: 0; + transform: translate(30vw, 0); + overflow: hidden; +} + +.checkboxWrapper { + display: flex; + flex-wrap: wrap; + align-items: center; + width: 100%; +} + +.jsonBox-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.jsonBox-title { + line-height: 40px; + font-weight: 700; +} + +.textarea { + width: 100%; + height: calc(100% - 40px); + padding: 5px 10px; + border: 1px solid #ddd; + border-radius: 5px; + resize: none; + color: #444; +} + +.addBtn { + margin-left: 20px !important; +} + +.item { + position: relative; + background-color: #eee; + margin: 10px 50px 0; + padding: 20px; + border-radius: 10px; + overflow: hidden; +} + +.item:hover .deleteBtn { + transform: translateX(-50px); +} + +.deleteBtn { + position: absolute; + right: 20px; + top: calc(50% - 25px); + width: 50px; + height: 50px; + transform: translateX(80px); + text-align: center; + line-height: 70px; + border-radius: 25px; + background-color: #1976d2; + transition: all 0.3s ease-in-out; +} + +.deleteBtn:hover { + cursor: pointer; + box-shadow: 0 0 10px #aaa; +} + +.deleteIcon { + font-size: 28px !important; + color: #fff; +} diff --git a/xinference/web/ui/src/scenes/running_models/index.js b/xinference/web/ui/src/scenes/running_models/index.js index ccf3fe312e..4024c8f6d2 100644 --- a/xinference/web/ui/src/scenes/running_models/index.js +++ b/xinference/web/ui/src/scenes/running_models/index.js @@ -10,15 +10,21 @@ import { useNavigate } from 'react-router-dom' import { ApiContext } from '../../components/apiContext' import ErrorMessageSnackBar from '../../components/errorMessageSnackBar' import fetcher from '../../components/fetcher' +import fetchWrapper from '../../components/fetchWrapper' import Title from '../../components/Title' +import { isValidBearerToken } from '../../components/utils' const RunningModels = () => { - const [tabValue, setTabValue] = React.useState('1') + const [tabValue, setTabValue] = React.useState( + sessionStorage.getItem('runningModelType') + ) const [llmData, setLlmData] = useState([]) const [embeddingModelData, setEmbeddingModelData] = useState([]) const [imageModelData, setImageModelData] = useState([]) const [audioModelData, setAudioModelData] = useState([]) + const [videoModelData, setVideoModelData] = useState([]) const [rerankModelData, setRerankModelData] = useState([]) + const [flexibleModelData, setFlexibleModelData] = useState([]) const { isCallingApi, setIsCallingApi } = useContext(ApiContext) const { isUpdatingModel, setIsUpdatingModel } = useContext(ApiContext) const { setErrorMsg } = useContext(ApiContext) @@ -28,13 +34,16 @@ const RunningModels = () => { const handleTabChange = (event, newValue) => { setTabValue(newValue) + navigate(newValue) + sessionStorage.setItem('runningModelType', newValue) } const update = (isCallingApi) => { - if (cookie.token === '' || cookie.token === undefined) { - return - } - if (cookie.token === 'need_auth') { + if ( + sessionStorage.getItem('auth') === 'true' && + !isValidBearerToken(sessionStorage.getItem('token')) && + !isValidBearerToken(cookie.token) + ) { navigate('/login', { replace: true }) return } @@ -46,63 +55,68 @@ const RunningModels = () => { setAudioModelData([ { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, ]) + setVideoModelData([ + { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, + ]) setImageModelData([ { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, ]) setRerankModelData([ { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, ]) + setFlexibleModelData([ + { id: 'Loading, do not refresh page...', url: 'IS_LOADING' }, + ]) } else { setIsUpdatingModel(true) - fetcher(`${endPoint}/v1/models`, { - method: 'GET', - }) + + fetchWrapper + .get('/v1/models') .then((response) => { - if (!response.ok) { - response.json().then((errorData) => { - setErrorMsg( - `Login failed: ${response.status} - ${ - errorData.detail || 'Unknown error' - }` - ) - }) - } else { - response.json().then((response) => { - const newLlmData = [] - const newEmbeddingModelData = [] - const newImageModelData = [] - const newAudioModelData = [] - const newRerankModelData = [] - response.data.forEach((model) => { - let newValue = { - ...model, - id: model.id, - url: model.id, - } - if (newValue.model_type === 'LLM') { - newLlmData.push(newValue) - } else if (newValue.model_type === 'embedding') { - newEmbeddingModelData.push(newValue) - } else if (newValue.model_type === 'audio') { - newAudioModelData.push(newValue) - } else if (newValue.model_type === 'image') { - newImageModelData.push(newValue) - } else if (newValue.model_type === 'rerank') { - newRerankModelData.push(newValue) - } - }) - setLlmData(newLlmData) - setEmbeddingModelData(newEmbeddingModelData) - setAudioModelData(newAudioModelData) - setImageModelData(newImageModelData) - setRerankModelData(newRerankModelData) - setIsUpdatingModel(false) - }) - } + const newLlmData = [] + const newEmbeddingModelData = [] + const newImageModelData = [] + const newAudioModelData = [] + const newVideoModelData = [] + const newRerankModelData = [] + const newFlexibleModelData = [] + response.data.forEach((model) => { + let newValue = { + ...model, + id: model.id, + url: model.id, + } + if (newValue.model_type === 'LLM') { + newLlmData.push(newValue) + } else if (newValue.model_type === 'embedding') { + newEmbeddingModelData.push(newValue) + } else if (newValue.model_type === 'audio') { + newAudioModelData.push(newValue) + } else if (newValue.model_type === 'video') { + newVideoModelData.push(newValue) + } else if (newValue.model_type === 'image') { + newImageModelData.push(newValue) + } else if (newValue.model_type === 'rerank') { + newRerankModelData.push(newValue) + } else if (newValue.model_type === 'flexible') { + newFlexibleModelData.push(newValue) + } + }) + setLlmData(newLlmData) + setEmbeddingModelData(newEmbeddingModelData) + setAudioModelData(newAudioModelData) + setVideoModelData(newVideoModelData) + setImageModelData(newImageModelData) + setRerankModelData(newRerankModelData) + setFlexibleModelData(newFlexibleModelData) + setIsUpdatingModel(false) }) .catch((error) => { console.error('Error:', error) setIsUpdatingModel(false) + if (error.response.status !== 403 && error.response.status !== 401) { + setErrorMsg(error.message) + } }) } } @@ -493,6 +507,7 @@ const RunningModels = () => { controlnet: row.controlnet, model_revision: row.model_revision, model_name: row.model_name, + model_ability: row.model_ability, }), }) .then((response) => response.json()) @@ -585,7 +600,9 @@ const RunningModels = () => { }, ] const audioModelColumns = embeddingModelColumns + const videoModelColumns = embeddingModelColumns const rerankModelColumns = embeddingModelColumns + const flexibleModelColumns = embeddingModelColumns const dataGridStyle = { '& .MuiDataGrid-cell': { @@ -628,8 +645,7 @@ const RunningModels = () => { sx={{ height: '100%', width: '100%', - paddingLeft: '20px', - paddingTop: '20px', + padding: '20px 20px 0 20px', }} > <Title title="Running Models" /> @@ -641,14 +657,16 @@ const RunningModels = () => { onChange={handleTabChange} aria-label="tabs" > - <Tab label="Language Models" value="1" /> - <Tab label="Embedding Models" value="2" /> - <Tab label="Rerank models" value="3" /> - <Tab label="Image models" value="4" /> - <Tab label="Audio models" value="5" /> + <Tab label="Language Models" value="/running_models/LLM" /> + <Tab label="Embedding Models" value="/running_models/embedding" /> + <Tab label="Rerank models" value="/running_models/rerank" /> + <Tab label="Image models" value="/running_models/image" /> + <Tab label="Audio models" value="/running_models/audio" /> + <Tab label="Video models" value="/running_models/video" /> + <Tab label="Flexible models" value="/running_models/flexible" /> </TabList> </Box> - <TabPanel value="1" sx={{ padding: 0 }}> + <TabPanel value="/running_models/LLM" sx={{ padding: 0 }}> <Box sx={{ height: '100%', width: '100%' }}> <DataGrid rows={llmData} @@ -662,7 +680,7 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="2" sx={{ padding: 0 }}> + <TabPanel value="/running_models/embedding" sx={{ padding: 0 }}> <Box sx={{ height: '100%', width: '100%' }}> <DataGrid rows={embeddingModelData} @@ -676,7 +694,7 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="3" sx={{ padding: 0 }}> + <TabPanel value="/running_models/rerank" sx={{ padding: 0 }}> <Box sx={{ height: '100%', width: '100%' }}> <DataGrid rows={rerankModelData} @@ -690,7 +708,7 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="4" sx={{ padding: 0 }}> + <TabPanel value="/running_models/image" sx={{ padding: 0 }}> <Box sx={{ height: '100%', width: '100%' }}> <DataGrid rows={imageModelData} @@ -704,7 +722,7 @@ const RunningModels = () => { /> </Box> </TabPanel> - <TabPanel value="5" sx={{ padding: 0 }}> + <TabPanel value="/running_models/audio" sx={{ padding: 0 }}> <Box sx={{ height: '100%', width: '100%' }}> <DataGrid rows={audioModelData} @@ -718,6 +736,34 @@ const RunningModels = () => { /> </Box> </TabPanel> + <TabPanel value="/running_models/video" sx={{ padding: 0 }}> + <Box sx={{ height: '100%', width: '100%' }}> + <DataGrid + rows={videoModelData} + columns={videoModelColumns} + autoHeight={true} + sx={dataGridStyle} + slots={{ + noRowsOverlay: noRowsOverlay, + noResultsOverlay: noResultsOverlay, + }} + /> + </Box> + </TabPanel> + <TabPanel value="/running_models/flexible" sx={{ padding: 0 }}> + <Box sx={{ height: '100%', width: '100%' }}> + <DataGrid + rows={flexibleModelData} + columns={flexibleModelColumns} + autoHeight={true} + sx={dataGridStyle} + slots={{ + noRowsOverlay: noRowsOverlay, + noResultsOverlay: noResultsOverlay, + }} + /> + </Box> + </TabPanel> </TabContext> </Box> )