Merge branch 'release/1.37' into build_swift_image

This commit is contained in:
Jintao Huang
2026-06-16 19:52:34 +08:00
32 changed files with 978 additions and 109 deletions

View File

@@ -1,14 +1,13 @@
FROM {base_image}
# Use bash so that `source` and other bash builtins work in all following RUN steps.
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_DEFAULT_TIMEOUT=300 \
PIP_RETRIES=10 \
SOC_VERSION={soc_version}
SHELL ["/bin/bash", "-c"]
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV PIP_DEFAULT_TIMEOUT=300
ENV PIP_RETRIES=10
ENV TRANSFORMERS_VERBOSITY=error
ENV TRANSFORMERS_NO_ADVISORY_WARNINGS=1
# ---------- System dependencies ----------
RUN rm -f /etc/apt/apt.conf.d/docker-clean && \
find /etc/apt/apt.conf.d -maxdepth 1 -type f | xargs -r grep -l "APT::Update::Post-Invoke\|docker-clean" | xargs -r rm -f && \
apt-get update -y && \
@@ -19,23 +18,62 @@ RUN rm -f /etc/apt/apt.conf.d/docker-clean && \
rm -rf /var/lib/apt/lists/*
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple && \
pip config set install.trusted-host mirrors.aliyun.com
pip config set install.trusted-host mirrors.aliyun.com && \
ARCH=$(uname -m) && \
if [ "$ARCH" = "x86_64" ]; then \
pip config set global.extra-index-url "https://download.pytorch.org/whl/cpu/"; \
fi
{extra_content}
# ---------- Install vllm + vllm-ascend ----------
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
if [ -f /usr/local/Ascend/nnal/atb/set_env.sh ]; then source /usr/local/Ascend/nnal/atb/set_env.sh; fi && \
git clone --depth 1 --branch v0.18.0 https://github.com/vllm-project/vllm && \
git clone --depth 1 --branch v0.18.0 https://github.com/vllm-project/vllm-ascend.git
# Reuse the vllm-ascend base image and only add the extra repos we need.
# --depth 1 keeps the image smaller; branch/tag names work with shallow clone.
RUN ARCH=$(uname -m) && \
source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
source /usr/local/Ascend/nnal/atb/set_env.sh && \
# Install torch & torch_npu & torchvision
pip install torch==2.9.0 torch_npu==2.9.0 torchvision==0.24.0 && \
# Install vllm
cd vllm && VLLM_TARGET_DEVICE=empty pip install -v -e . && cd .. && \
# Install vllm-ascend
cd vllm-ascend && pip install -v -e . && cd ..
# ---------- Clone training-side repositories ----------
RUN git clone --depth 1 --branch v0.15.3 https://github.com/NVIDIA/Megatron-LM.git /Megatron-LM && \
git clone --depth 1 --branch core_r0.15.3 https://gitcode.com/Ascend/MindSpeed.git /MindSpeed && \
GIT_LFS_SKIP_SMUDGE=1 git clone --depth 1 -b {swift_branch} --single-branch https://github.com/modelscope/ms-swift.git /ms-swift && \
git clone --depth 1 https://github.com/modelscope/mcore-bridge.git /mcore-bridge
# ---------- Install training-side repositories ----------
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
if [ -f /usr/local/Ascend/nnal/atb/set_env.sh ]; then source /usr/local/Ascend/nnal/atb/set_env.sh; fi && \
cd /MindSpeed && pip install --no-cache-dir -e . && \
cd /mcore-bridge && pip install --no-cache-dir -e . && \
pip cache purge
cd /ms-swift && pip install --no-cache-dir -e .
# ---------- Pin torch to the correct version + torch_npu ----------
# x86: must force-install the CPU build from pytorch.org/whl/cpu
# aarch64: PyPI only provides the CPU build, so install it directly from the Aliyun mirror
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
if [ -f /usr/local/Ascend/nnal/atb/set_env.sh ]; then source /usr/local/Ascend/nnal/atb/set_env.sh; fi && \
ARCH=$(uname -m) && \
if [ "$ARCH" = "x86_64" ]; then \
pip install --no-cache-dir --force-reinstall --no-deps \
--index-url https://download.pytorch.org/whl/cpu \
torch==2.9.0 torchvision==0.24.0 torchaudio==2.9.0; \
else \
pip install --no-cache-dir --force-reinstall --no-deps \
torch==2.9.0 torchvision==0.24.0 torchaudio==2.9.0; \
fi && \
pip install --no-cache-dir --force-reinstall --no-deps \
torch_npu==2.9.0 && \
rm -rf /root/.cache/pip
# ---------- Remove CUDA-only dependencies pulled in by vllm (they cause missing libtorch_cuda.so errors on NPU) ----------
RUN pip uninstall -y flashinfer tvm-ffi torch-c-dlpack-ext 2>/dev/null || true
ARG INSTALL_MS_DEPS={install_ms_deps}
ENV MEGATRON_LM_PATH=/Megatron-LM
@@ -68,6 +106,8 @@ fi
ARG CUR_TIME={cur_time}
RUN echo $CUR_TIME
RUN pip install --no-cache-dir --no-build-isolation OpenCC
RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
if [ -f /usr/local/Ascend/nnal/atb/set_env.sh ]; then source /usr/local/Ascend/nnal/atb/set_env.sh; fi && \
pip install --no-cache-dir -U funasr scikit-learn && \

View File

@@ -79,7 +79,7 @@ RUN if [ "$IMAGE_TYPE" = "gpu" ]; then \
cd / && rm -fr /tmp/apex && pip cache purge; \
pip install --no-cache-dir "megatron-core==0.17.*" -U; \
elif [ "$IMAGE_TYPE" = "cpu" ]; then \
pip install --no-cache-dir huggingface-hub transformers peft diffusers -U; \
pip install --no-cache-dir huggingface-hub "transformers<5.9" peft diffusers -U; \
else \
pip install "transformers<5.0" "tokenizers<0.22" "trl<0.23" "diffusers<0.35" --no-dependencies; \
fi

View File

@@ -1,5 +1,8 @@
FROM {base_image}
ARG CUR_TIME={cur_time}
RUN echo $CUR_TIME
RUN cd /tmp && GIT_LFS_SKIP_SMUDGE=1 git clone -b {modelscope_branch} --single-branch https://github.com/modelscope/modelscope.git && \
cd modelscope && pip install . -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html && \
cd / && rm -fr /tmp/modelscope && pip cache purge;

View File

@@ -0,0 +1,164 @@
ARG BUILD_BASE_IMAGE=registry.access.redhat.com/ubi9/ubi:9.6
ARG PYTHON_VERSION=3.12
ARG UV_EXTRA_INDEX_URL=https://repos.metax-tech.com/r/maca-pypi/simple
ARG UV_TRUSTED_HOST=repos.metax-tech.com
# may need passing a particular vllm version during build
ARG VLLM_VERSION
ARG MACA_VERSION
ARG CU_BRIDGE_VERSION=${MACA_VERSION}
#################### BASE BUILD IMAGE ####################
FROM ${BUILD_BASE_IMAGE} AS base
ARG UV_TRUSTED_HOST
# maca environment variables
ENV MACA_PATH=/opt/maca
ENV MACA_CLANG_PATH=/opt/maca/mxgpu_llvm/bin
ENV CUCC_PATH="${MACA_PATH}/tools/cu-bridge"
ENV CUDA_PATH=/root/cu-bridge/CUDA_DIR
ENV CUCC_CMAKE_ENTRY=2
ENV PATH="/opt/venv/bin:/root/.local/bin:$PATH"
ENV PATH=/opt/mxdriver/bin:${MACA_PATH}/bin:${MACA_PATH}/mxgpu_llvm/bin:${MACA_PATH}/tools/cu-bridge/tools:${MACA_PATH}/tools/cu-bridge/bin:${PATH}
ENV LD_LIBRARY_PATH=/opt/mxdriver/lib:${MACA_PATH}/lib:${MACA_PATH}/mxgpu_llvm/lib:${MACA_PATH}/ompi/lib:${MACA_PATH}/ucx/lib:${LD_LIBRARY_PATH}
# uv environment variables
ENV VIRTUAL_ENV=/opt/venv
ENV UV_INDEX_STRATEGY="unsafe-best-match"
ENV UV_HTTP_TIMEOUT=6000
ENV UV_LINK_MODE=copy
ARG UV_EXTRA_INDEX_URL
ENV UV_EXTRA_INDEX_URL=${UV_EXTRA_INDEX_URL}
ARG UV_INDEX_URL
ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple
ENV UV_TRUSTED_INDEX_HOST=mirrors.aliyun.com
ENV UV_OVERRIDE=/workspace/override.txt
# vllm compile option
ENV VLLM_INSTALL_PUNICA_KERNELS=1
# AI version arguments
ARG PYTHON_VERSION
ARG VLLM_VERSION
ARG VLLM_METAX_VERSION
ARG MACA_VERSION
ARG MEGATRON_VERSION
ARG SWIFT_VERSION
ARG CU_BRIDGE_VERSION
ARG TE_VERSION
WORKDIR /workspace
COPY override.txt /workspace/override.txt
COPY requirements_extra.txt /workspace/requirements_extra.txt
RUN printf "[metax-centos]\n\
name=Maca Driver Yum Repository\n\
baseurl=https://repos.metax-tech.com/r/metax-driver-centos-$(uname -m)/\n\
enabled=1\n\
gpgcheck=0" > /etc/yum.repos.d/metax-driver-centos.repo
RUN dnf -y install python3-pip hostname && \
dnf clean all
RUN python3 -m pip install uv -i $UV_INDEX_URL --trusted-host ${UV_TRUSTED_INDEX_HOST} && \
uv venv /opt/venv --python=${PYTHON_VERSION}
RUN python3 --version && \
uv self version
RUN yum makecache && yum install -y \
unzip vim git openblas-devel make cmake \
ninja-build gcc g++ procps-ng \
libibverbs librdmacm libibumad \
&& yum clean all
RUN git clone --depth 1 --branch ${SWIFT_VERSION} https://github.com/modelscope/ms-swift.git
RUN git clone --depth 1 --branch ${VLLM_METAX_VERSION} https://github.com/MetaX-MACA/vLLM-metax.git
RUN git clone --depth 1 --branch ${VLLM_VERSION} https://github.com/vllm-project/vllm.git
RUN git clone --depth 1 --branch ${MEGATRON_VERSION} https://github.com/NVIDIA/Megatron-LM.git
# Step 1: install MACA SDK, Metax-Driver and cu-bridge
# Metax-Driver mainly contains vbios and kmd files, which are not needed in a container.
# Here we keep the mx-smi management tool. Kernel version mismatch errors are ignored.
RUN yum makecache && \
yum install -y metax-driver-${MACA_VERSION}* mxgvm && \
yum clean all && rm -rf /var/cache/yum /tmp/*
RUN printf "[maca-sdk]\n\
name=Maca Sdk Yum Repository\n\
baseurl=https://repos.metax-tech.com/r/maca-sdk-rpm-$(uname -m)/\n\
enabled=1\n\
gpgcheck=0" > /etc/yum.repos.d/maca-sdk-rpm.repo
RUN yum makecache && \
yum install -y maca_sdk-${MACA_VERSION}* && \
yum clean all && rm -rf /var/cache/yum /tmp/*
RUN cd /tmp/ && \
export MACA_PATH=/opt/maca && \
curl -o ${CU_BRIDGE_VERSION}.zip -LsSf https://gitee.com/metax-maca/cu-bridge/repository/archive/${CU_BRIDGE_VERSION}.zip && \
unzip ${CU_BRIDGE_VERSION}.zip && \
mv cu-bridge-${CU_BRIDGE_VERSION} cu-bridge && \
chmod 755 cu-bridge -Rf && \
cd cu-bridge && \
mkdir build && cd build && \
cmake -DCMAKE_INSTALL_PREFIX=/opt/maca/tools/cu-bridge ../ && \
make && make install
# Step 2: trim unused MACA packages and install build prerequisites
RUN cd vLLM-metax && \
uv pip install -r requirements/build.txt && \
uv pip install build
RUN yum makecache && yum install -y \
gcc \
binutils \
procps-ng \
libibverbs \
librdmacm \
libibumad \
openblas \
numactl-libs \
&& yum clean all && rm -rf /var/cache/yum /tmp/*
# Step 3: install Metax python requirements
RUN cd vLLM-metax && \
UV_HTTP_TIMEOUT=960 uv pip install -r requirements/maca.txt --trusted-host ${UV_TRUSTED_HOST}
# Step 4: build vLLM with empty device to avoid CUDA dependency
RUN cd vllm && \
python3 use_existing_torch.py && \
uv pip install -r requirements/build.txt
RUN cd vllm && \
VLLM_TARGET_DEVICE=empty uv pip install -v . --no-build-isolation
# Step 5: build vLLM-metax
RUN cd vLLM-metax && \
uv pip install -r requirements/build.txt && \
python3 -m build -w -n && \
uv pip install dist/*.whl
# Step 6: install Megatron-LM
RUN sed -i 's/nvcc/cucc/g' /workspace/Megatron-LM/megatron/legacy/fused_kernels/__init__.py && \
cd Megatron-LM && \
uv pip install .
# Step 7: install transformer-engine
RUN uv pip install transformer_engine==${TE_VERSION} -i https://repos.metax-tech.com/r/maca-pypi/simple --trusted-host ${UV_TRUSTED_HOST}
# Step 8: patch and install ms-swift v4.1.0 with Megatron extra dependencies
RUN sed -i '0,/^\(from \|import \)/{s//import vllm_metax.patch\n&/}' ms-swift/swift/__init__.py && \
cd ms-swift && \
uv pip install '.[megatron]'
# Step 9: install optional runtime dependencies used by swift 4.1.0
RUN uv pip install deepspeed -i https://repos.metax-tech.com/r/maca-pypi/simple --trusted-host ${UV_TRUSTED_HOST}
RUN uv pip install pip
RUN uv pip install -r requirements_extra.txt
RUN ln -sf ${CUDA_PATH}/bin/nvcc ${CUDA_PATH}/bin/cucc
# vllm installation may bring in incompatible CUDA-only wheels. Remove them here.
RUN uv pip uninstall flashinfer-python cupy-cuda12x flash-linear-attention fla-core
#################### FINAL IMAGE ####################

View File

@@ -0,0 +1,73 @@
ARG BUILD_BASE_IMAGE=mx-devops-acr-cn-shanghai.cr.volces.com/opensource/public-ai-release/maca/ms-swift:4.0.4-maca.ai3.5.3.5-torch2.8-py312-ubuntu22.04-amd64
ARG PYTHON_VERSION=3.12
FROM ${BUILD_BASE_IMAGE} AS base
# NOTE:
# This fast-build path inherits Python/Torch/TE from a prebuilt Metax release image.
# We keep the verified base image tag here instead of guessing a newer one.
# As a result, this path may lag behind the Megatron-SWIFT Quick Start recommendations.
# may need passing a particular vllm version during build
ARG VLLM_VERSION
ARG VLLM_METAX_VERSION
ARG MEGATRON_VERSION
ARG SWIFT_VERSION
ENV MACA_PATH=/opt/maca
ENV CUCC_CMAKE_ENTRY=2
ENV CUDA_PATH=/root/cu-bridge/CUDA_DIR
ENV CUCC_PATH=${MACA_PATH}/tools/cu-bridge
ENV PATH=/opt/conda/bin:/opt/conda/condabin:${CUDA_PATH}/bin:${CUCC_PATH}/tools:${CUCC_PATH}/bin:${MACA_PATH}/bin:${PATH}
ENV LD_LIBRARY_PATH=${CUDA_PATH}/lib64:${MACA_PATH}/lib:${MACA_PATH}/mxgpu_llvm/lib:${LD_LIBRARY_PATH}
WORKDIR /workspace
COPY requirements_extra.txt /workspace/requirements_extra.txt
RUN echo $PATH
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
# Initialize cu-bridge if it is not already prepared in the base image.
RUN if [ ! -d /root/cu-bridge ]; then \
${MACA_PATH}/tools/cu-bridge/tools/pre_make; \
fi
# Clone all GitHub sources while the external proxy is enabled.
RUN rm -rf /workspace/ms-swift /workspace/vLLM-metax /workspace/vllm /workspace/Megatron-LM
RUN git clone --depth 1 --branch ${SWIFT_VERSION} https://github.com/modelscope/ms-swift.git
RUN git clone --depth 1 --branch ${VLLM_METAX_VERSION} https://github.com/MetaX-MACA/vLLM-metax.git
RUN git clone --depth 1 --branch ${VLLM_VERSION} https://github.com/vllm-project/vllm.git
RUN git clone --depth 1 --branch ${MEGATRON_VERSION} https://github.com/NVIDIA/Megatron-LM.git
# install cmake
RUN pip install cmake ninja
# Step 1: build original vLLM for torch setup
RUN cd vllm && \
python3 use_existing_torch.py && \
pip install -r requirements/build.txt
# Step 2: build vLLM with empty device to avoid CUDA dependency
RUN cd vllm && \
VLLM_TARGET_DEVICE=empty pip install -v . --no-build-isolation
# Step 3: build vLLM-metax
RUN cd vLLM-metax && \
python3 use_existing_metax.py && \
pip install -r requirements/build.txt && \
python3 -m build -w -n && \
pip install dist/*.whl
# Step 4: patch and install Megatron-LM
RUN sed -i 's/nvcc/cucc/g' /workspace/Megatron-LM/megatron/legacy/fused_kernels/__init__.py && \
cd /workspace/Megatron-LM && \
pip install .
# Step 5: patch and install ms-swift v4.1.0 with its Megatron extra
RUN sed -i '0,/^\(from \|import \)/{s//import vllm_metax.patch\n&/}' ms-swift/swift/__init__.py && \
cd ms-swift && \
pip install "transformers<5.4.0" && \
pip install '.[megatron]' && \
pip install -r /workspace/requirements_extra.txt
CMD ["bash"]

13
docker/Metax/4.1/build.sh Normal file
View File

@@ -0,0 +1,13 @@
docker build \
--network host \
-f Dockerfile.metax \
-t swift:v4.1.0 \
--build-arg VLLM_VERSION=v0.17.1 \
--build-arg VLLM_METAX_VERSION=v0.17.0 \
--build-arg MACA_VERSION=3.5.3 \
--build-arg MEGATRON_VERSION=core_v0.16.0 \
--build-arg SWIFT_VERSION=v4.1.0 \
--build-arg TE_VERSION=2.8.0 \
--build-arg CU_BRIDGE_VERSION=3.5.3 \
--no-cache \
.

View File

@@ -0,0 +1,10 @@
docker build \
--network host \
-f Dockerfile.with_metax_image \
-t swift:v4.1.0 \
--build-arg VLLM_VERSION=v0.17.1 \
--build-arg VLLM_METAX_VERSION=v0.17.0 \
--build-arg MEGATRON_VERSION=core_v0.16.0 \
--build-arg SWIFT_VERSION=v4.1.0 \
--no-cache \
.

View File

@@ -0,0 +1,5 @@
setuptools>=77.0.3,<80
datasets>=3.0,<4.0
flash-linear-attention
mcoplib
transformers<5.4.0

View File

@@ -0,0 +1,14 @@
decord
diffusers==0.35.2
evalscope>=1.0.0
evalscope[opencompass]
evalscope[vlmeval]
keye_vl_utils>=1.5.2
librosa
mpi4py
optimum==1.27.0
pytorchvideo
qwen_omni_utils>=0.0.9
qwen_vl_utils==0.0.14
soundfile
timm

View File

@@ -0,0 +1,52 @@
# 1. Build swift 4.1 image from a UBI9 base image
Full build from a minimal base image, using a venv virtual environment.
## 1.1. Build
``` bash
bash build.sh
```
## 1.2. Run a container
``` bash
docker run -d -it --net=host --uts=host --ipc=host --privileged=true --group-add video \
--shm-size 100gb --ulimit memlock=-1 \
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \
--device=/dev/dri --device=/dev/mxcd \
--name base_image \
${IMAGE_ID} bash
```
## 1.3. Activate the venv environment
``` bash
source /opt/venv/bin/activate
```
## 1.4. Run swift examples
``` bash
cd /workspace/ms-swift
bash examples/train/full/train.sh
```
# 2. Build swift 4.1 image from a Metax release image
Faster build based on the pre-built Metax release image.
## 2.1. Build
``` bash
bash build_from_metax_image.sh
```
## 2.2. Run a container
``` bash
docker run -d -it --net=host --uts=host --ipc=host --privileged=true --group-add video \
--shm-size 100gb --ulimit memlock=-1 \
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \
--device=/dev/dri --device=/dev/mxcd \
--name base_image \
${IMAGE_ID} bash
```
## 2.3. Run swift examples
``` bash
cd /workspace/ms-swift
bash examples/train/full/train.sh
```

View File

@@ -1,6 +1,8 @@
import argparse
import os
import platform
import subprocess
from copy import copy
from datetime import datetime
from typing import Any
@@ -24,9 +26,9 @@ class Builder:
# A mirrored image of nvidia/cuda:12.4.0-devel-ubuntu22.04
args.base_image = 'nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04'
if not args.torch_version:
args.torch_version = '2.9.1'
args.torchaudio_version = '2.9.1'
args.torchvision_version = '0.24.1'
args.torch_version = '2.10.0'
args.torchaudio_version = '2.10.0'
args.torchvision_version = '0.25.0'
if not args.optimum_version:
args.optimum_version = '2.0.0'
if not args.tf_version:
@@ -34,7 +36,7 @@ class Builder:
if not args.cuda_version:
args.cuda_version = '12.8.1'
if not args.vllm_version:
args.vllm_version = '0.15.1'
args.vllm_version = '0.19.1'
if not args.lmdeploy_version:
args.lmdeploy_version = '0.11.0'
if not args.autogptq_version:
@@ -139,6 +141,7 @@ class OldCPUImageBuilder(Builder):
content = content.replace('{base_image}', old_cpu_image)
content = content.replace('{modelscope_branch}',
self.args.modelscope_branch)
content = content.replace('{cur_time}', formatted_time)
return content
def image(self) -> str:
@@ -196,6 +199,7 @@ class OldGPUImageBuilder(Builder):
content = content.replace('{base_image}', old_gpu_image)
content = content.replace('{modelscope_branch}',
self.args.modelscope_branch)
content = content.replace('{cur_time}', formatted_time)
return content
def image(self) -> str:
@@ -338,6 +342,15 @@ class StableCPUImageBuilder(Builder):
class StableGPUImageBuilder(Builder):
"""Dependencies will be stable versions"""
def init_args(self, args: Any) -> Any:
if not args.torch_version:
args.torch_version = '2.10.0'
args.torchaudio_version = '2.10.0'
args.torchvision_version = '0.25.0'
if not args.vllm_version:
args.vllm_version = '0.19.1'
return super().init_args(args)
def generate_dockerfile(self) -> str:
meta_file = './docker/install.sh'
with open('docker/Dockerfile.extra_install', 'r') as f:
@@ -469,10 +482,46 @@ RUN pip install --no-cache-dir -U icecream soundfile pybind11 py-spy
class AscendImageBuilder(StableGPUImageBuilder):
@staticmethod
def _normalize_arch(arch: str = None) -> str:
arch = arch or platform.machine()
arch = arch.lower()
arch_mapping = {
'x86': 'x86',
'x86_64': 'x86',
'amd64': 'x86',
'arm': 'arm',
'aarch64': 'arm',
'arm64': 'arm',
}
if arch not in arch_mapping:
raise ValueError(f'Unsupported architecture: {arch}. '
'Please pass --arch x86 or --arch arm.')
return arch_mapping[arch]
@staticmethod
def _get_atlas_hardware(soc_version: str) -> str:
soc_version = soc_version.lower()
atlas_mapping = {
'ascend910b1': 'A2',
'ascend910_9391': 'A3',
'ascend310p1': '300I',
}
if soc_version.startswith('ascend950'):
return 'A5'
if soc_version not in atlas_mapping:
raise ValueError(
f'Unsupported soc_version: {soc_version}. '
'Supported values are ascend910b1, ascend910_9391, '
'ascend310p1, and values starting with ascend950.')
return atlas_mapping[soc_version]
def init_args(self, args) -> Any:
if not args.base_image:
# Reuse the prebuilt vllm-ascend image to avoid rebuilding its stack.
args.base_image = 'quay.io/ascend/vllm-ascend:v0.14.0rc1-a3'
args.base_image = 'quay.io/ascend/cann:8.5.1-a3-ubuntu22.04-py3.11'
args.arch = self._normalize_arch(args.arch)
args.atlas_hardware = self._get_atlas_hardware(args.soc_version)
return super().init_args(args)
def generate_dockerfile(self) -> str:
@@ -482,6 +531,7 @@ RUN pip install --no-cache-dir -U icecream soundfile pybind11 py-spy
with open('docker/Dockerfile.ascend', 'r') as f:
content = f.read()
content = content.replace('{base_image}', self.args.base_image)
content = content.replace('{soc_version}', self.args.soc_version)
content = content.replace('{extra_content}', extra_content)
content = content.replace('{cur_time}', formatted_time)
content = content.replace('{install_ms_deps}', 'False')
@@ -492,8 +542,9 @@ RUN pip install --no-cache-dir -U icecream soundfile pybind11 py-spy
def image(self) -> str:
return (
f'{docker_registry}:{self.args.base_image.split(":")[-1]}-torch2.7.1'
f'-{self.args.modelscope_version}-ascend-test')
f'{docker_registry}:{self.args.swift_branch}-'
f'{self.args.atlas_hardware}-{self.args.python_tag}-{self.args.arch}'
)
def push(self):
return 0
@@ -518,6 +569,8 @@ parser.add_argument('--autogptq_version', type=str, default=None)
parser.add_argument('--modelscope_branch', type=str, default='master')
parser.add_argument('--modelscope_version', type=str, default='9.99.0')
parser.add_argument('--swift_branch', type=str, default='main')
parser.add_argument('--soc_version', type=str, default='ascend910_9391')
parser.add_argument('--arch', type=str, choices=['x86', 'arm'], default=None)
parser.add_argument('--dry_run', type=int, default=0)
args = parser.parse_args()
@@ -535,4 +588,5 @@ else:
raise ValueError(f'Unsupported image_type: {args.image_type}')
for builder in builder_cls:
args = copy(args)
builder(args, args.dry_run)()

View File

@@ -2316,6 +2316,18 @@ class HubApi:
commit_message=commit_message,
)
# Guard: skip sending empty commits (no effective file changes)
if not payload['actions']:
logger.info(
'Commit skipped: no effective actions in payload '
'(all files already exist).')
return CommitInfo(
commit_url='',
commit_message=commit_message,
commit_description=commit_description or '',
oid='no-op',
)
response = self.session.post(
url,
headers=self.builder_headers(self.headers),
@@ -2753,8 +2765,9 @@ class HubApi:
)
commit_description = commit_description or 'Uploading files'
# Exclude internal cache/checkpoint files from upload
_internal_ignore = [UPLOAD_HASH_CACHE_FILE, _LEGACY_PROGRESS_FILE]
# Exclude internal cache/checkpoint files from upload at any directory depth
_internal_files = [UPLOAD_HASH_CACHE_FILE, _LEGACY_PROGRESS_FILE]
_internal_ignore = [p for f in _internal_files for p in (f, f'*/{f}')]
if ignore_patterns is None:
ignore_patterns = _internal_ignore
elif isinstance(ignore_patterns, str):
@@ -2957,18 +2970,27 @@ class HubApi:
except Exception as e:
logger.error(
f'Batch {batch_idx + 1}/{num_batches} commit failed: {e}')
for r in results:
tracker.mark_failed(
r['file_path_in_repo'], r['file_mtime'],
r['file_size_on_disk'],
error_type='commit_failed')
# Recover uploaded files to retry queue
for r in results:
total_failed_files.append(
((r['file_path_in_repo'], r['file_path']), e))
logger.warning(
f'Batch {batch_idx + 1}/{num_batches}: '
f'{len(results)} uploaded file(s) recovered to retry queue.')
category = classify_error(e)
if not category.is_retryable:
# Permanent error: mark files as failed, do not retry
for r in results:
tracker.mark_failed(
r['file_path_in_repo'], r['file_mtime'],
r['file_size_on_disk'],
error_type='commit_' + category.value)
logger.error(
f'Batch {batch_idx + 1}/{num_batches}: '
f'permanent failure ({category.value}), '
f'{len(results)} file(s) will not be retried.')
else:
# Transient error: recover to retry queue
for r in results:
total_failed_files.append(
((r['file_path_in_repo'], r['file_path']), e))
logger.warning(
f'Batch {batch_idx + 1}/{num_batches}: '
f'{len(results)} file(s) recovered to retry queue '
f'(error_category={category.value}).')
finally:
tracker.save()
@@ -3030,10 +3052,19 @@ class HubApi:
except Exception as e:
logger.error(
f' Retry round {retry_round + 1} commit failed: {e}')
for result in retry_successes:
retry_failures.append(
((result['file_path_in_repo'],
result.get('file_path', '')), e))
category = classify_error(e)
if not category.is_retryable:
for result in retry_successes:
tracker.mark_failed(
result['file_path_in_repo'],
result['file_mtime'],
result['file_size_on_disk'],
error_type='commit_' + category.value)
else:
for result in retry_successes:
retry_failures.append(
((result['file_path_in_repo'],
result.get('file_path', '')), e))
total_failed_files = retry_failures
# Final tracker save
@@ -3253,7 +3284,7 @@ class HubApi:
repo_type=repo_type,
revision=revision)
commit_infos.append(commit_info)
# Mark committed
# Mark committed only after successful commit
self._track_committed_batch(tracker, batch)
logger.info(
f'[ReAct] {round_name}: '
@@ -3261,11 +3292,18 @@ class HubApi:
except Exception as e:
logger.error(
f'[ReAct] {round_name} commit failed: {e}')
# Recover uploaded files back to failures
for r in batch:
round_failures.append(
((r['file_path_in_repo'],
r['file_path']), e))
category = classify_error(e)
if not category.is_retryable:
for r in batch:
tracker.mark_failed(
r['file_path_in_repo'], r['file_mtime'],
r['file_size_on_disk'],
error_type='commit_' + category.value)
else:
for r in batch:
round_failures.append(
((r['file_path_in_repo'],
r['file_path']), e))
# OBSERVE: classify new failures, enforce per-file retry limit
new_retryable = []

View File

@@ -14,7 +14,8 @@ from modelscope.utils.config import Config, ConfigDict
from modelscope.utils.constant import DEFAULT_MODEL_REVISION, Invoke, ModelFile
from modelscope.utils.device import verify_device
from modelscope.utils.logger import get_logger
from modelscope.utils.plugins import (register_modelhub_repo,
from modelscope.utils.plugins import (filter_plugin_in_whitelist,
register_modelhub_repo,
register_plugins_repo)
logger = get_logger()
@@ -31,7 +32,9 @@ class Model(ABC):
device_name = kwargs.get('device', 'gpu')
verify_device(device_name)
self._device_name = device_name
self.trust_remote_code = kwargs.get('trust_remote_code', False)
self.trust_remote_code = kwargs.get(
'trust_remote_code',
False) or check_model_from_owner_group(model_dir)
def __call__(self, *args, **kwargs) -> Dict[str, Any]:
return self.postprocess(self.forward(*args, **kwargs))
@@ -136,7 +139,8 @@ class Model(ABC):
kwargs.pop(Invoke.KEY)
else:
invoked_by = Invoke.PRETRAINED
_model_trusted = check_model_from_owner_group(model_name_or_path)
trust_remote_code = trust_remote_code or _model_trusted
ignore_file_pattern = kwargs.pop('ignore_file_pattern', None)
if osp.exists(model_name_or_path):
local_model_dir = model_name_or_path
@@ -190,7 +194,7 @@ class Model(ABC):
# Security check: Only allow execution of remote code or plugins if trust_remote_code is True
plugins = cfg.safe_get('plugins')
if plugins and not trust_remote_code:
if filter_plugin_in_whitelist(plugins) and not trust_remote_code:
raise RuntimeError(
'Detected plugins field in the model configuration file, but '
'trust_remote_code=True was not explicitly set.\n'
@@ -203,7 +207,7 @@ class Model(ABC):
'Please make sure that you can trust the external codes.')
register_modelhub_repo(local_model_dir, allow_remote=trust_remote_code)
default_args = {}
if trust_remote_code:
if trust_remote_code and not _model_trusted:
default_args = {'trust_remote_code': trust_remote_code}
register_plugins_repo(plugins)
for k, v in kwargs.items():

View File

@@ -343,7 +343,7 @@ class ControlLDM(LatentDiffusion, Model):
self.only_mid_control = only_mid_control
self.control_scales = [1.0] * 13
self.trust_remote_code = kwargs.get('trust_remote_code', False)
self.check_trust_remote_code()
self.check_trust_remote_code(self.model_dir)
@torch.no_grad()
def get_input(self, batch, k, bs=None, *args, **kwargs):

View File

@@ -68,7 +68,7 @@ class ImageViewTransform(TorchModel):
self.model = None
self.model = load_model_from_config(
self.model, config, ckpt, device=self.device)
self.check_trust_remote_code()
self.check_trust_remote_code(model_dir=model_dir)
def forward(self, model_path, x, y):
pred_results = _infer(self.model, model_path, x, y, self.device)

View File

@@ -29,7 +29,7 @@ class SingleStageDetector(TorchModel):
init model by cfg
"""
super().__init__(model_dir, *args, **kwargs)
self.check_trust_remote_code()
self.check_trust_remote_code(model_dir=model_dir)
config_path = osp.join(model_dir, self.config_name)
config = parse_config(config_path)
self.cfg = config

View File

@@ -33,7 +33,7 @@ class DROEstimation(TorchModel):
def __init__(self, model_dir: str, **kwargs):
"""str -- model file root."""
super().__init__(model_dir, **kwargs)
self.check_trust_remote_code()
self.check_trust_remote_code(model_dir=model_dir)
model_path = osp.join(model_dir, ModelFile.TORCH_MODEL_FILE)

View File

@@ -246,7 +246,7 @@ class MsDataset:
'you can trust the external codes.')
# Raise csv field size limit to avoid errors with large cells
if config_kwargs.get('engine') == 'python':
if config_kwargs.pop('engine', None) == 'python':
import csv as csv_module
import sys
try:

View File

@@ -9,12 +9,12 @@ by :func:`~hf_datasets_util.load_dataset_with_ctx`.
import importlib
import inspect
import os
import re
from functools import partial
from pathlib import Path
from typing import Dict, List, Optional, Sequence, Tuple, Union
from typing import Dict, List, Optional, Tuple
from datasets import (BuilderConfig, DownloadConfig, DownloadMode, Features,
Version, config, data_files)
from datasets import (BuilderConfig, DownloadConfig, config)
from datasets.data_files import (
FILES_TO_IGNORE, DataFilesDict, EmptyDatasetError,
_get_data_files_patterns, _is_inside_unrequested_special_dir,
@@ -24,17 +24,16 @@ from datasets.download.streaming_download_manager import (
_prepare_path_and_storage_options, xbasename, xjoin)
from datasets.exceptions import DataFilesNotFoundError
from datasets.info import DatasetInfosDict
from datasets.load import (BuilderConfigsParameters, DatasetModule,
from datasets.load import (BuilderConfigsParameters,
DatasetModule,
create_builder_configs_from_metadata_configs,
get_dataset_builder_class, import_main_class,
import_main_class,
infer_module_for_data_files)
from datasets.naming import camelcase_to_snakecase
from datasets.packaged_modules import (_MODULE_TO_EXTENSIONS,
_PACKAGED_DATASETS_MODULES)
from datasets.utils.file_utils import (cached_path, is_local_path,
relative_to_absolute_path)
from datasets.utils.file_utils import (cached_path, is_local_path)
from datasets.utils.metadata import MetadataConfigs
from datasets.utils.track import tracked_str
from fsspec import filesystem
from fsspec.core import _un_chain
from fsspec.utils import stringify_path
@@ -42,14 +41,16 @@ from huggingface_hub import DatasetCard, DatasetCardData
from packaging import version
from modelscope import HubApi
from modelscope.msdatasets.utils._compat import (
_HAS_SCRIPT_LOADING, _create_importable_file, _get_importable_file_path,
_load_importable_file, files_to_hash, get_imports, init_dynamic_modules,
resolve_trust_remote_code)
from modelscope.msdatasets.utils._compat import (_create_importable_file,
_get_importable_file_path,
_load_importable_file,
files_to_hash,
get_imports,
init_dynamic_modules,
resolve_trust_remote_code)
from modelscope.utils.constant import (DEFAULT_DATASET_REVISION,
REPO_TYPE_DATASET)
from modelscope.utils.file_utils import is_relative_path
from modelscope.utils.import_utils import has_attr_in_class
from modelscope.utils.logger import get_logger
# ALL_ALLOWED_EXTENSIONS moved to datasets.packaged_modules in datasets 4.0
@@ -60,6 +61,73 @@ except ImportError:
logger = get_logger()
def _extract_split_names(split):
"""Extract base split names from a split specification string.
Handles simple names ("tool"), sliced splits ("train[:100]"),
and combined splits ("train+test").
Args:
split: A split specification string, or None.
Returns:
A set of split name strings, or None if *split* is None or
cannot be parsed.
"""
if split is None:
return None
split_str = str(split)
parts = split_str.split('+')
names = set()
for part in parts:
# Remove slice notation like "[:100]" or "[50%:]"
name = re.split(r'\[', part.strip())[0]
if name:
names.add(name)
return names if names else None
def _filter_data_files_by_split(data_files, download_config):
"""Filter data_files entries to only include the requested split(s).
Args:
data_files: The raw data_files value from metadata_configs.
Expected format: list of dicts with 'split' and 'path' keys.
download_config: The DownloadConfig instance (may be None).
Returns:
Filtered data_files if a split filter is active; otherwise
the original *data_files* unchanged.
"""
# 1. Safely retrieve the split value
split_str = None
if download_config is not None:
storage_opts = getattr(download_config, 'storage_options', None)
if isinstance(storage_opts, dict):
split_str = storage_opts.get('split')
if split_str is None:
return data_files
# 2. Parse split names
split_names = _extract_split_names(split_str)
if not split_names:
return data_files
# 3. Only filter list[dict] format
if not isinstance(data_files, list):
return data_files
if not all(isinstance(item, dict) and 'split' in item for item in data_files):
return data_files
# 4. Filter
filtered = [df for df in data_files if df.get('split') in split_names]
# 5. Fallback: if filtered is empty, return original data
return filtered if filtered else data_files
# ---------------------------------------------------------------------------
# Shared HubApi instance (avoids creating a new requests.Session per call)
# ---------------------------------------------------------------------------
@@ -575,6 +643,8 @@ def get_module_without_script(self) -> DatasetModule:
else:
subset_data_files = next(iter(
metadata_configs.values()))['data_files']
subset_data_files = _filter_data_files_by_split(
subset_data_files, self.download_config)
patterns = sanitize_patterns(subset_data_files)
else:
patterns = _get_data_patterns(

View File

@@ -12,6 +12,7 @@ Sub-modules:
_module_factories dataset module factory functions & data-file resolution
"""
import contextlib
import inspect
import os
import warnings
from dataclasses import fields
@@ -25,7 +26,7 @@ from datasets import (Dataset, DatasetBuilder, DatasetDict,
DownloadConfig, DownloadManager, DownloadMode, Features,
IterableDataset, IterableDatasetDict, Split,
VerificationMode, Version, config, data_files, LargeList,
Sequence as SequenceHf)
Sequence as SequenceHf, SplitDict)
try:
from datasets import List as DatasetList
@@ -407,10 +408,26 @@ def _get_paths_info(
# ===================================================================
# HfFileSystem patch (_hf_fs_open)
# HfFileSystem patches (_hf_fs_open, _hf_fs_init)
# ===================================================================
_hf_fs_open_original = None
_hf_fs_init_original = None
def _hf_fs_init_with_cookie(self, *args, endpoint=None, token=None, **kwargs):
"""HfFileSystem.__init__ wrapper that injects ModelScope cookie auth.
ModelScope's /resolve/ endpoint authenticates via `m_session_id` cookie
rather than the `Authorization: Bearer` header used by HuggingFace Hub.
This wrapper ensures the cookie is included in all subsequent HTTP
requests made by the HfFileSystem instance.
"""
_hf_fs_init_original(self, *args, endpoint=endpoint, token=token, **kwargs)
if token and isinstance(token, str):
if not hasattr(self._api, 'headers') or self._api.headers is None:
self._api.headers = {}
self._api.headers['Cookie'] = f'm_session_id={token}'
def _hf_fs_open(self, path, mode='rb', **kwargs):
@@ -456,6 +473,154 @@ def _hf_fs_open(self, path, mode='rb', **kwargs):
return _hf_fs_open_original(self, path, mode=mode, **kwargs)
class _DryRunDownloadManager:
"""Minimal download-manager stub for split discovery without I/O.
Returns placeholder paths for all download/extract calls, allowing
_split_generators() to execute and return SplitGenerator objects
(which carry split names) without triggering actual network or disk I/O.
"""
_PLACEHOLDER = os.devnull
def download(self, url_or_urls):
return self._map(url_or_urls)
def download_and_extract(self, url_or_urls):
return self._map(url_or_urls)
def extract(self, path_or_paths):
return self._map(path_or_paths)
def download_custom(self, url_or_urls, custom_download):
return self._map(url_or_urls)
def iter_archive(self, path):
return iter([])
def iter_files(self, paths):
return iter([])
@property
def manual_dir(self):
return None
@property
def is_streaming(self):
return False
def _map(self, input_):
if isinstance(input_, dict):
return {k: self._PLACEHOLDER for k in input_}
if isinstance(input_, (list, tuple, set)):
return type(input_)(self._PLACEHOLDER for _ in input_)
return self._PLACEHOLDER
def _discover_splits_from_builder(builder_instance):
"""Discover available split names by dry-running _split_generators().
For script-based datasets that lack README split metadata, this calls
the builder's _split_generators() with a stub download manager to
extract split names without performing any actual downloads.
Returns:
A set of split name strings, or an empty set if discovery fails.
"""
if not hasattr(builder_instance, '_split_generators'):
return set()
try:
generators = builder_instance._split_generators(_DryRunDownloadManager())
return {str(sg.name) for sg in generators}
except Exception as e:
logger.debug(f'Failed to discover splits from builder: {e}')
return set()
def _validate_split_exists(builder_instance, split):
"""Fail-fast check: raise ValueError before downloading if the
requested split does not exist in the dataset metadata.
Args:
builder_instance: The DatasetBuilder instance with info/config.
split: The user-requested split specification (may be None).
Raises:
ValueError: If any requested split name is not found among
the available splits declared in the dataset metadata.
"""
if split is None:
return
from modelscope.msdatasets.utils._module_factories import _extract_split_names
split_names = _extract_split_names(split)
if not split_names:
return
# Source 1: info.splits (original metadata from README)
available = set()
info = getattr(builder_instance, 'info', None)
if info is not None and info.splits:
available = set(info.splits.keys())
# Source 2: config.data_files keys
if not available:
config = getattr(builder_instance, 'config', None)
data_files = getattr(config, 'data_files', None)
if isinstance(data_files, dict):
available = set(data_files.keys())
# Source 3: dry-run _split_generators() for script-based datasets
if not available:
available = _discover_splits_from_builder(builder_instance)
if not available:
logger.debug(
'Cannot determine available splits from dataset metadata; '
'split validation skipped. Invalid splits will be caught downstream.'
)
return
missing = split_names - available
if missing:
raise ValueError(
f'Split {sorted(missing)} not found in dataset. '
f'Available splits: {sorted(available)}'
)
def _align_builder_splits_with_data_files(builder_instance, split):
"""Align builder.info.splits with the actually requested split(s).
When data_files have been filtered to a subset of splits (see
_filter_data_files_by_split in _module_factories.py), the builder's
info.splits metadata may still list all original splits from the
README. download_and_prepare() calls verify_splits() which would
then raise ExpectedMoreSplitsError. This helper prunes info.splits
to only contain the splits that will actually be generated.
"""
if split is None:
return
info = getattr(builder_instance, 'info', None)
if info is None or info.splits is None:
return
from modelscope.msdatasets.utils._module_factories import _extract_split_names
split_names = _extract_split_names(split)
if not split_names:
return
existing_keys = set(info.splits.keys())
if split_names >= existing_keys:
return # All splits requested, no filtering needed
filtered = {k: v for k, v in info.splits.items() if k in split_names}
if not filtered:
return # Safety: don't empty out splits
info.splits = SplitDict(filtered, dataset_name=info.splits.dataset_name)
# ===================================================================
# DatasetsWrapperHF
# ===================================================================
@@ -544,34 +709,66 @@ class DatasetsWrapperHF:
storage_options=storage_options,
trust_remote_code=trust_remote_code,
_require_default_config_name=name is None,
split=split,
**config_kwargs,
)
if dataset_info_only:
ret_dict = {}
# Case 1: Local .py script file
if isinstance(path, str) and path.endswith('.py') and os.path.exists(path):
from datasets import get_dataset_config_names
subset_list = get_dataset_config_names(path)
ret_dict = {_subset: [] for _subset in subset_list}
return ret_dict
if builder_instance is None or not hasattr(builder_instance,
'builder_configs'):
logger.error(f'No builder_configs found for {path} dataset.')
if builder_instance is None:
logger.error(f'No builder instance created for {path} dataset.')
return ret_dict
_tmp_builder_configs = builder_instance.builder_configs
for tmp_config_name, tmp_builder_config in _tmp_builder_configs.items():
tmp_config_name = str(tmp_config_name)
if hasattr(tmp_builder_config, 'data_files') and tmp_builder_config.data_files is not None:
ret_dict[tmp_config_name] = [str(item) for item in list(tmp_builder_config.data_files.keys())]
# Case 2: Try builder_configs with data_files (packaged datasets)
_tmp_builder_configs = getattr(builder_instance, 'builder_configs', None)
if _tmp_builder_configs:
if hasattr(_tmp_builder_configs, 'items'):
configs_iter = _tmp_builder_configs.items()
else:
ret_dict[tmp_config_name] = []
configs_iter = [(getattr(c, 'name', 'default'), c) for c in _tmp_builder_configs]
for tmp_config_name, tmp_builder_config in configs_iter:
tmp_config_name = str(tmp_config_name)
if hasattr(tmp_builder_config, 'data_files') and tmp_builder_config.data_files is not None:
ret_dict[tmp_config_name] = [str(item) for item in list(tmp_builder_config.data_files.keys())]
# Case 3: Fallback for script datasets — use info.splits or dry-run discovery
if not ret_dict or all(not v for v in ret_dict.values()):
config_name = getattr(builder_instance, 'config_name', 'default') or 'default'
splits = []
# Try info.splits (from README metadata)
info = getattr(builder_instance, 'info', None)
if info is not None and info.splits:
splits = sorted(info.splits.keys())
# Fallback: dry-run _split_generators()
if not splits:
discovered = _discover_splits_from_builder(builder_instance)
if discovered:
splits = sorted(discovered)
if splits:
ret_dict = {config_name: splits}
elif not ret_dict:
ret_dict = {config_name: []}
return ret_dict
_validate_split_exists(builder_instance, split)
if streaming:
return builder_instance.as_streaming_dataset(split=split)
_align_builder_splits_with_data_files(builder_instance, split)
builder_instance.download_and_prepare(
download_config=download_config,
download_mode=download_mode,
@@ -624,6 +821,7 @@ class DatasetsWrapperHF:
storage_options: Optional[Dict] = None,
trust_remote_code: Optional[bool] = None,
_require_default_config_name=True,
split: Optional[Union[str, Split]] = None,
**config_kwargs,
) -> DatasetBuilder:
@@ -644,6 +842,12 @@ class DatasetsWrapperHF:
download_config = download_config.copy(
) if download_config else DownloadConfig()
download_config.storage_options.update(storage_options)
if split is not None:
download_config = download_config.copy(
) if download_config else DownloadConfig()
if download_config.storage_options is None:
download_config.storage_options = {}
download_config.storage_options['split'] = split
dataset_module = DatasetsWrapperHF.dataset_module_factory(
path,
@@ -683,6 +887,24 @@ class DatasetsWrapperHF:
builder_cls = get_dataset_builder_class(
dataset_module, dataset_name=dataset_name)
_config_cls = builder_cls.BUILDER_CONFIG_CLASS
if hasattr(_config_cls, '__dataclass_fields__'):
_valid_fields = set(_config_cls.__dataclass_fields__.keys())
# Also preserve parameters accepted by the builder's
# __init__ (e.g. writer_batch_size, base_path, repo_id)
# so they are not inadvertently stripped.
try:
_init_params = set(
inspect.signature(builder_cls.__init__).parameters.keys()
)
except (ValueError, TypeError):
_init_params = set()
_valid_fields = _valid_fields | _init_params
config_kwargs = {
k: v for k, v in config_kwargs.items()
if k in _valid_fields
}
builder_instance: DatasetBuilder = builder_cls(
cache_dir=cache_dir,
dataset_name=dataset_name,
@@ -946,7 +1168,7 @@ def load_dataset_with_ctx(*args, **kwargs):
non-streaming mode) or kept alive (for streaming mode, where lazy
iteration needs the patches to remain active).
"""
global _hf_fs_open_original
global _hf_fs_open_original, _hf_fs_init_original
# Save originals
hf_endpoint_origin = config.HF_ENDPOINT
@@ -962,6 +1184,7 @@ def load_dataset_with_ctx(*args, **kwargs):
HubDatasetModuleFactoryWithScript.get_module if _HAS_SCRIPT_LOADING else None)
generate_from_dict_origin = features.generate_from_dict
hf_fs_open_origin = HfFileSystem._open
hf_fs_init_origin = HfFileSystem.__init__
# Apply patches
config.HF_ENDPOINT = get_endpoint()
@@ -980,6 +1203,8 @@ def load_dataset_with_ctx(*args, **kwargs):
features.generate_from_dict = generate_from_dict_ms
_hf_fs_open_original = hf_fs_open_origin
HfFileSystem._open = _hf_fs_open
_hf_fs_init_original = hf_fs_init_origin
HfFileSystem.__init__ = _hf_fs_init_with_cookie
streaming = kwargs.get('streaming', False)
@@ -990,10 +1215,12 @@ def load_dataset_with_ctx(*args, **kwargs):
_repo_tree_cache.clear()
HubApi._dataset_id_type_cache.clear()
HfFileSystem._open = hf_fs_open_origin
_hf_fs_open_original = None
if not streaming:
HfFileSystem._open = hf_fs_open_origin
_hf_fs_open_original = None
HfFileSystem.__init__ = hf_fs_init_origin
_hf_fs_init_original = None
config.HF_ENDPOINT = hf_endpoint_origin
file_utils.get_from_cache = get_from_cache_origin
features.generate_from_dict = generate_from_dict_origin

View File

@@ -53,11 +53,12 @@ def _request_with_retry_ms(
url: str,
max_retries: int = 2,
base_wait_time: float = 0.5,
max_wait_time: float = 2,
max_wait_time: float = 3,
timeout: float = 10.0,
**params,
) -> requests.Response:
"""Wrapper around requests to retry in case it fails with a ConnectTimeout, with exponential backoff.
"""Wrapper around requests to retry in case it fails with a ConnectTimeout,
ReadTimeout or ConnectionError, with exponential backoff.
Note that if the environment variable HF_DATASETS_OFFLINE is set to 1, then a OfflineModeIsEnabled error is raised.
@@ -72,12 +73,35 @@ def _request_with_retry_ms(
"""
tries, success = 0, False
response = None
range_header = (params.get('headers') or {}).get('Range', '')
while not success:
tries += 1
try:
logger.debug(
'[MS_DOWNLOAD] _request_with_retry_ms sending request: '
'method=%s, url=%s, timeout=%s, Range=%s',
method, url, timeout, range_header or 'N/A',
)
t0 = time.perf_counter()
response = requests.request(method=method.upper(), url=url, timeout=timeout, **params)
elapsed = time.perf_counter() - t0
logger.debug(
'[MS_DOWNLOAD] _request_with_retry_ms response: '
'status=%s, content_length=%s, elapsed=%.3fs, url=%s',
response.status_code,
response.headers.get('Content-Length', 'N/A'),
elapsed,
url,
)
success = True
except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError) as err:
except (requests.exceptions.ReadTimeout,
requests.exceptions.ConnectTimeout,
requests.exceptions.ConnectionError) as err:
logger.error(
'[MS_DOWNLOAD] _request_with_retry_ms %s: '
'method=%s, url=%s, timeout=%s, error=%s',
type(err).__name__, method, url, timeout, err,
)
if tries > max_retries:
raise err
else:
@@ -88,7 +112,7 @@ def _request_with_retry_ms(
def http_head_ms(
url, proxies=None, headers=None, cookies=None, allow_redirects=True, timeout=10.0, max_retries=0
url, proxies=None, headers=None, cookies=None, allow_redirects=True, timeout=10.0, max_retries=3
) -> requests.Response:
headers = copy.deepcopy(headers) or {}
headers['user-agent'] = get_datasets_user_agent_ms(user_agent=headers.get('user-agent'))
@@ -106,8 +130,12 @@ def http_head_ms(
def http_get_ms(
url, temp_file, proxies=None, resume_size=0, headers=None, cookies=None, timeout=100.0, max_retries=0, desc=None
url, temp_file, proxies=None, resume_size=0, headers=None, cookies=None, timeout=300.0, max_retries=3, desc=None
) -> Optional[requests.Response]:
logger.debug(
'[MS_DOWNLOAD] http_get_ms entry: url=%s, timeout=%s, resume_size=%s',
url, timeout, resume_size,
)
headers = dict(headers) if headers is not None else {}
headers['user-agent'] = get_datasets_user_agent_ms(user_agent=headers.get('user-agent'))
if resume_size > 0:
@@ -147,7 +175,7 @@ def get_from_cache_ms(
user_agent=None,
local_files_only=False,
use_etag=True,
max_retries=0,
max_retries=3,
token=None,
use_auth_token='deprecated',
ignore_url_params=False,
@@ -320,6 +348,7 @@ def get_from_cache_ms(
if scheme not in ('http', 'https'):
fsspec_get(url, temp_file, storage_options=storage_options, desc=download_desc)
else:
logger.info('[MS_DOWNLOAD] get_from_cache_ms downloading: url=%s', url)
http_get_ms(
url,
temp_file=temp_file,

View File

@@ -70,7 +70,8 @@ class LinearAECPipeline(Pipeline):
self.check_trust_remote_code(
'This pipeline requires `trust_remote_code=True` to load the module defined'
' in the `dey_mini.yaml`, setting this to True means you trust the code and files'
' listed in this model repo.')
' listed in this model repo.',
model_dir=model)
self.use_cuda = torch.cuda.is_available()
with open(

View File

@@ -6,13 +6,15 @@ from typing import Any, Dict, List, Optional, Union
from modelscope.hub.snapshot_download import snapshot_download
from modelscope.metainfo import DEFAULT_MODEL_FOR_PIPELINE
from modelscope.models.base import Model
from modelscope.utils.automodel_utils import check_model_from_owner_group
from modelscope.utils.config import ConfigDict, check_config
from modelscope.utils.constant import (DEFAULT_MODEL_REVISION, Invoke, Tasks,
ThirdParty)
from modelscope.utils.hub import read_config
from modelscope.utils.import_utils import is_transformers_available
from modelscope.utils.logger import get_logger
from modelscope.utils.plugins import (register_modelhub_repo,
from modelscope.utils.plugins import (filter_plugin_in_whitelist,
register_modelhub_repo,
register_plugins_repo)
from modelscope.utils.registry import Registry, build_from_cfg
from modelscope.utils.task_utils import is_embedding_task
@@ -79,6 +81,7 @@ def pipeline(task: str = None,
device: str = None,
model_revision: Optional[str] = DEFAULT_MODEL_REVISION,
ignore_file_pattern: List[str] = None,
trust_remote_code: bool = False,
**kwargs) -> Pipeline:
""" Factory method to build an obj:`Pipeline`.
@@ -95,6 +98,8 @@ def pipeline(task: str = None,
device (str, optional): whether to use gpu or cpu is used to do inference.
ignore_file_pattern(`str` or `List`, *optional*, default to `None`):
Any file pattern to be ignored in downloading, like exact file names or file extensions.
trust_remote_code (bool, optional): Whether to allow execution of remote code or
plugins declared in the model configuration. Defaults to False.
Return:
pipeline (obj:`Pipeline`): pipeline object for certain task.
@@ -113,6 +118,10 @@ def pipeline(task: str = None,
if task is None and pipeline_name is None:
raise ValueError('task or pipeline_name is required')
model_id = model[0] if isinstance(model,
list) and len(model) > 0 else model
_model_trusted = check_model_from_owner_group(model_id)
trust_remote_code = trust_remote_code or _model_trusted
pipeline_props = None
if pipeline_name is None:
# get default pipeline for this task
@@ -155,9 +164,24 @@ def pipeline(task: str = None,
third_party=third_party,
ignore_file_pattern=ignore_file_pattern)
register_plugins_repo(cfg.safe_get('plugins'))
register_modelhub_repo(model,
cfg.get('allow_remote', False))
if cfg:
plugins = cfg.safe_get('plugins')
allow_remote = cfg.get('allow_remote', False)
if (filter_plugin_in_whitelist(plugins)
or allow_remote) and not trust_remote_code:
raise RuntimeError(
'Detected plugins or allow_remote field in the model '
'configuration file, but trust_remote_code=True was not '
'explicitly set.\n'
'To prevent potential execution of malicious code, loading '
'has been refused.\n'
'If you trust this model repository, please pass '
'trust_remote_code=True to pipeline().')
register_plugins_repo(plugins)
model_dir = model if isinstance(model,
str) else model[0]
register_modelhub_repo(
model_dir, trust_remote_code and allow_remote)
if pipeline_name:
pipeline_props = {'type': pipeline_name}
@@ -226,7 +250,13 @@ def pipeline(task: str = None,
if preprocessor is not None:
cfg.preprocessor = preprocessor
return build_pipeline(cfg, task_name=task)
if _model_trusted:
return build_pipeline(cfg, task_name=task)
else:
return build_pipeline(
cfg,
task_name=task,
default_args={'trust_remote_code': trust_remote_code})
def add_default_pipeline_info(task: str,

View File

@@ -193,7 +193,8 @@ class DiscoDiffusionPipeline(DiffusersPipeline):
self.check_trust_remote_code(
'This pipeline requires `trust_remote_code=True` to load the module defined'
' in `model_index.json`, setting this to True means you trust the code and files'
' listed in this model repo.')
' listed in this model repo.',
model_dir=model)
model_path = model
@@ -209,12 +210,6 @@ class DiscoDiffusionPipeline(DiffusersPipeline):
if model_config['use_fp16']:
self.unet.convert_to_fp16()
self.trust_remote_code = kwargs.get('trust_remote_code', False)
self.check_trust_remote_code(
'This pipeline requires import modules listed in `model_index.json`, '
'please add `trust_remote_code=True` if you trust this model repo.'
)
with open(
os.path.join(model_path, 'model_index.json'),
'r',

View File

@@ -208,6 +208,7 @@ class Preprocessor(ABC):
revision: Optional[str] = DEFAULT_MODEL_REVISION,
cfg_dict: Config = None,
preprocessor_mode=ModeKeys.INFERENCE,
trust_remote_code=False,
**kwargs):
"""Instantiate a preprocessor from local directory or remote model repo. Note
that when loading from remote, the model revision can be specified.

View File

@@ -2,10 +2,11 @@
from modelscope.metainfo import Trainers
from modelscope.pipelines.builder import normalize_model_input
from modelscope.pipelines.util import is_official_hub_path
from modelscope.utils.config import check_config
from modelscope.utils.automodel_utils import check_model_from_owner_group
from modelscope.utils.constant import DEFAULT_MODEL_REVISION
from modelscope.utils.hub import read_config
from modelscope.utils.plugins import (register_modelhub_repo,
from modelscope.utils.plugins import (filter_plugin_in_whitelist,
register_modelhub_repo,
register_plugins_repo)
from modelscope.utils.registry import Registry, build_from_cfg
@@ -19,10 +20,18 @@ def build_trainer(name: str = Trainers.default, default_args: dict = None):
name (str, optional): Trainer name, if None, default trainer
will be used.
default_args (dict, optional): Default initialization arguments.
If ``trust_remote_code`` key is set to True in default_args,
remote code and plugins declared in the model configuration
will be allowed to execute.
"""
cfg = dict(type=name)
default_args = default_args or {}
model = default_args.get('model', None)
model_revision = default_args.get('model_revision', DEFAULT_MODEL_REVISION)
model_id = model[0] if isinstance(model,
list) and len(model) > 0 else model
trust_remote_code = default_args.get(
'trust_remote_code', False) or check_model_from_owner_group(model_id)
if isinstance(model, str) \
or (isinstance(model, list) and isinstance(model[0], str)):
@@ -33,7 +42,23 @@ def build_trainer(name: str = Trainers.default, default_args: dict = None):
model, str) else read_config(
model[0], revision=model_revision)
model_dir = normalize_model_input(model, model_revision)
register_plugins_repo(configuration.safe_get('plugins'))
register_modelhub_repo(model_dir,
configuration.get('allow_remote', False))
if configuration:
plugins = configuration.safe_get('plugins')
allow_remote = configuration.get('allow_remote', False)
if (filter_plugin_in_whitelist(plugins)
or allow_remote) and not trust_remote_code:
raise RuntimeError(
'Detected plugins or allow_remote field in the model '
'configuration file, but trust_remote_code=True was '
'not explicitly set.\n'
'To prevent potential execution of malicious code, '
'loading has been refused.\n'
'If you trust this model repository, please pass '
'trust_remote_code=True in default_args to '
'build_trainer().')
register_plugins_repo(plugins)
model_dir_str = model_dir if isinstance(model_dir,
str) else model_dir[0]
register_modelhub_repo(model_dir_str, trust_remote_code
and allow_remote)
return build_from_cfg(cfg, TRAINERS, default_args=default_args)

View File

@@ -135,6 +135,7 @@ class EpochBasedTrainer(BaseTrainer):
self._inner_iter = 0
self._stop_training = False
self._compile = kwargs.get('compile', False)
self.trust_remote_code = kwargs.get('trust_remote_code', False)
self.train_dataloader = None
self.eval_dataloader = None
@@ -814,7 +815,10 @@ class EpochBasedTrainer(BaseTrainer):
override this method in a subclass.
"""
model = Model.from_pretrained(self.model_dir, cfg_dict=self.cfg)
model = Model.from_pretrained(
self.model_dir,
cfg_dict=self.cfg,
trust_remote_code=self.trust_remote_code)
if not isinstance(model, nn.Module) and hasattr(model, 'model'):
return model.model
elif isinstance(model, nn.Module):

View File

@@ -137,7 +137,7 @@ def check_model_from_owner_group(model_dir: str,
Returns:
bool: Whether the group can be trusted
"""
if not model_dir:
if not model_dir or not isinstance(model_dir, str):
return False
if owner_group is None:
owner_group = ['iic', 'damo']

View File

@@ -524,6 +524,7 @@ def _patch_kernels():
"""
try:
from kernels import utils as kernels_utils
from kernels.utils import _get_hf_api
except ImportError:
return
if hasattr(kernels_utils, '_get_hf_api_origin'):
@@ -535,6 +536,7 @@ def _patch_kernels():
def _unpatch_kernels():
try:
from kernels import utils as kernels_utils
from kernels.utils import _get_hf_api
except ImportError:
return
origin = getattr(kernels_utils, '_get_hf_api_origin', None)

View File

@@ -8,6 +8,7 @@ import importlib
import importlib.metadata
import os
import pkgutil
import re
import shutil
import subprocess
import sys
@@ -46,6 +47,18 @@ OFFICIAL_PLUGINS = [
LOCAL_PLUGINS_FILENAME = '.modelscope_plugins'
GLOBAL_PLUGINS_FILENAME = os.path.join(Path.home(), '.modelscope', 'plugins')
DEFAULT_PLUGINS = []
PLUGIN_WHITE_LIST = ['pai-easycv']
def filter_plugin_in_whitelist(plugins):
if not plugins:
return plugins
if isinstance(plugins, str):
plugins = [plugins]
return [
plugin for plugin in plugins if re.split(r'[><=!~]', plugin.strip())
[0].strip() not in PLUGIN_WHITE_LIST
]
@contextmanager

View File

@@ -205,6 +205,8 @@ def build_from_cfg(cfg,
raise TypeError(
f'type must be a str or valid type, but got {type(obj_type)}')
try:
if not obj_cls.__module__.startswith('modelscope'):
args.pop('trust_remote_code', None)
if hasattr(obj_cls, '_instantiate'):
return obj_cls._instantiate(**args)
else:

View File

@@ -1,5 +1,5 @@
# Make sure to modify __release_datetime__ to release time when making official release.
__version__ = '1.36.3'
__version__ = '1.37.1'
# default release datetime for branches under active development is set
# to be a time far-far-away-into-the-future
__release_datetime__ = '2026-04-29 02:00:00'
__release_datetime__ = '2026-05-20 23:59:59'