# Step3

## 论文
`
Step-3 is Large yet Affordable: Model-system Co-design for Cost-effective Decoding
`
- https://arxiv.org/abs/2507.19427

## 模型结构
Step3 是一个先进的多模态推理模型，基于混合专家架构构建，拥有 321B 总参数，单token激活38B参数。
它采用端到端设计，旨在最大限度地降低解码成本，同时在视觉语言推理领域提供顶级性能。
通过 Multi-Matrix Factorization Attention(MFA)和Attention-FFN Disaggregation (AFD)的协同设计，Step3 高端和低端加速器上均保持卓越的效率。
AFD的架构实现如图所示。
<div align=center>
    <img src="./figures/AFD_architecture.png"/>
</div>

## 算法原理

Step-3引入了两大优化设计:

- 在模型算法方面，引入了MFA(Multi-matrix Factorization Attention)算法，其计算密度设计更加均衡，相较于MHA, GQA, MLA实现更低的decode成本。
- 在系统设计方面，引入了Attention FFN分离架构(Attention-FFN Disaggregation, AFD), 并根据具体硬件配置相应并行策略。


## 环境配置
### 硬件需求
DCU型号：BW1000，节点数量：2 台，卡数：2*8 张。

### 通信配置
一、节点间基础通信

`在本地机器上配置以下内容：`

1、关闭防火墙：
```
systemctl stop  firewalld # 若为centos 
ufw disable # 若为Ubuntu
```
2、设置amd_iommu=on:
```
vim /etc/default/grub
```
<div align=center>
    <img src="./figures/amd_iommu.png"/>
</div>

更新下配置:
```
grub2-mkconfig -o /boot/efi/EFI/rocky/grub.cfg
```
重启机器后校验是否生效(检查是否存在imxxx=pt)：
```
BOOT_IMAGE=(hd0,gpt3)/vmlinuz-4.18.0-372.9.1.el8.x86_64 root=UUID=80974f58-7d23-49bb-bd8b-8e299eb0d188 ro crashkernel=auto rhgb quiet systemd.unified_cgroup_hierachy=1 systemd.unified_cgroup_hierarchy=1 amd_iommu=on iommu=pt
```

`在后面步骤启动的容器里面配置以下内容：`

```
apt update
apt install openssh-server -y
```
vim /etc/ssh/sshd_config # 修改下面PermitRootLogin为yes
```
# 取消以下4句命令的注释
RSAAuthentication yes #启用 RSA 认证
PubkeyAuthentication yes #启用公钥私钥配对认证方式
AuthorizedKeysFile ~/.ssh/authorized_keys #公钥文件路径（和下面生成的文件同）
PermitRootLogin yes #root能使用ssh登录
```

重启ssh服务，并设置开机启动：
```
service sshd restart
chkconfig sshd on

查看sshd状态：service ssh status
开启sshd服务：/etc/init.d/ssh restart
```

下面开始设置节点间免密通信的秘钥：

1、ssh-keygen生成秘钥
```
ssh-keygen -t ed25519 # 此处以ed25519为例，读者可自己设置为其它名字，遇到提问全部回车键确认
```
2、将需要使用的各个节点`~/.ssh/authorized_keys`里的秘钥收集复制到`~/.ssh/id_rsa.pub`，每个节点`~/.ssh/id_rsa.pub`里的所有秘钥最终一致。格式类似如下：
<div align=center>
    <img src="./figures/id_rsa.png"/>
</div>

3、设置节点间的通信端口号
```
/usr/sbin/sshd -p 10085 # 不同节点可以设置不同的端口号，打通秘钥和端口号之后可以用ssh -p之类的命令验证节点间是否通信已经通畅，否则需检查前面步骤是否设置成功。
```

以上设置非标准步骤，不同服务器或集群存在明显差异，无法完全复制此过程，请读者根据自己机器的实际情况灵活采用，总体目标是开启amd_iommu、打通节点间的容器内可以直接免密登录。

二、ray相关通信

`在后面步骤启动的容器里面配置以下内容：`
```
vim ~/.bashrc
```
在脚本`.bashrc`最后面添加以下命令（以BW200卡的集群为例）：

```
export ALLREDUCE_STREAM_WITH_COMPUTE=1
export VLLM_HOST_IP=x.x.x.x
export NCCL_SOCKET_IFNAME=ib0
export GLOO_SOCKET_IFNAME=ib0
unset NCCL_ALGO
export NCCL_MIN_NCHANNELS=16
export NCCL_MAX_NCHANNELS=16 
export NCCL_NET_GDR_READ=1
export HIP_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
export LMSLIM_USE_LIGHTOP=0
#针对hycpu环境建议设置绑核操作：
export VLLM_NUMA_BIND=1
export VLLM_RANK0_NUMA=0
export VLLM_RANK1_NUMA=1
export VLLM_RANK2_NUMA=2
export VLLM_RANK3_NUMA=3
export VLLM_RANK4_NUMA=4
export VLLM_RANK5_NUMA=5
export VLLM_RANK6_NUMA=6
export VLLM_RANK7_NUMA=7
#BW集群需要额外设置的环境变量：
export NCCL_NET_GDR_LEVEL=7
export NCCL_SDMA_COPY_ENABLE=0
export NCCL_IB_HCA=mlx5_2:1,mlx5_3:1,mlx5_4:1,mlx5_5:1,mlx5_6:1,mlx5_7:1,mlx5_8:1,mlx5_9:1
export NCCL_TOPO_FILE="topo-input.xml"
# 若为K100_AI卡，则添加以下信息(本步骤以BW卡为示例，故注释了以下信息。)：
# export VLLM_ENFORCE_EAGER_BS_THRESHOLD=44 
```
其中`VLLM_HOST_IP`和`NCCL_SOCKET_IFNAME`需要替换成每个自己机器上查到的信息，每个节点的ip不同，查询方式如下：
```
通信口和ip查询方法：ifconfig
VLLM_HOST_IP： 节点本地通信口ip
NCCL_SOCKET_IFNAME和GLOO_SOCKET_IFNAME： 节点本地通信网口名
```
`示例：`
<div align=center>
    <img src="./figures/ip.png"/>
</div>

带BW卡的集群VLLM_HOST_IP需要设置为ib网卡对应的IP，避免出现rccl超时问题：

<div align=center>
    <img src="./figures/ip_bw.png"/>
</div>


注意：添加完以上信息后需要激活环境变量
```
source ~/.bashrc
```

`Tips：由于通信配置方面属于运维人员的专业内容，以上关于通信的配置建议读者联系运维人员进行配置。`

### Docker（方法一）
```
docker pull image.sourcefind.cn:5000/dcu/admin/base/custom:vllm-ubuntu22.04-dtk25.04.1-rc5-das1.6-py3.10-20250802-step3
docker run -it --name step_vllm --shm-size=1024G  --device=/dev/kfd --device=/dev/dri/ --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 --ipc=host --network host --group-add video -v /opt/hyhal:/opt/hyhal:ro -v $PWD/Step3_pytorch:/home/Step3_pytorch f0e4191089de /bin/bash
wget --content-disposition 'https://download.sourcefind.cn:65024/file/4/triton/DAS1.6/triton-3.0.0+das.opt1.dtk25041-cp310-cp310-manylinux_2_28_x86_64.whl'
pip install triton-3.0.0+das.opt1.dtk25041-cp310-cp310-manylinux_2_28_x86_64.whl
```
### Dockerfile（方法二）
```
cd $PWD/Step3_pytorch/docker
docker build --no-cache -t step3:latest .
docker run -it --name step_vllm --shm-size=1024G  --device=/dev/kfd --device=/dev/dri/ --privileged --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --ulimit memlock=-1:-1 --ipc=host --network host --group-add video -v /opt/hyhal:/opt/hyhal:ro -v $PWD/Step3_pytorch:/home/Step3_pytorch f0e4191089de /bin/bash
wget --content-disposition 'https://download.sourcefind.cn:65024/file/4/triton/DAS1.6/triton-3.0.0+das.opt1.dtk25041-cp310-cp310-manylinux_2_28_x86_64.whl'
pip install triton-3.0.0+das.opt1.dtk25041-cp310-cp310-manylinux_2_28_x86_64.whl
```

## 数据集
`无`

## 训练
`无`

## 推理
预训练权重目录结构，将后续模型地址切换成实际模型权重地址：
```
/home/Step3_pytorch/
    └── stepfun-ai/step3
```
### 多机多卡
启动ray集群
```
# 启动ray
# 启动主节点的ray, x.x.x.x 为前面步骤中ifconfig查到的主节点ip（VLLM_HOST_IP），--port为端口号，可以随意设置，保持主节点和其余节点端口号一致。
ray start --head --node-ip-address=x.x.x.x --port=6379 --num-gpus=8 --num-cpus=32 
# 启动其它节点的ray,注意 x.x.x.x 为前面步骤中ifconfig查到的主节点ip（VLLM_HOST_IP）。
ray start --address='x.x.x.x:6379' --num-gpus=8 --num-cpus=32
# 可用ray status 查看ray的集群启动状态。
```


vLLM Deployment(vllm官方暂不支持AFD，只支持非分离模式部署):

```
#head节点执行

VLLM_USE_NN=0 VLLM_USE_FLASH_ATTN_PA=0 vllm serve /path/to/step3 \
    --reasoning-parser step3 \
    --enable-auto-tool-choice \
    --tool-call-parser step3 \
    --trust-remote-code \
    --max-num-batched-tokens 4096 \
    --distributed-executor-backend ray  \
    --dtype float16  \
    -tp 16 \
    --port $PORT_SERVING 

```

- Client Request Examples
```
from openai import OpenAI

# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"

client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="/path/to/step3",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://xxxxx.png"
                    },
                },
                {"type": "text", "text": "Please describe the image."},
            ],
        },
    ],
)
print("Chat response:", chat_response)
```
- You can also upload base64-encoded local images:
```
import base64
from openai import OpenAI
# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"
client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)
image_path = "/path/to/local/image.png"
with open(image_path, "rb") as f:
    encoded_image = base64.b64encode(f.read())
encoded_image_text = encoded_image.decode("utf-8")
base64_step = f"data:image;base64,{encoded_image_text}"
chat_response = client.chat.completions.create(
    model="step3",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": base64_step
                    },
                },
                {"type": "text", "text": "Please describe the image."},
            ],
        },
    ],
)
print("Chat response:", chat_response)
```
- text only:
```
from openai import OpenAI

# Set OpenAI's API key and API base to use vLLM's API server.
openai_api_key = "EMPTY"
openai_api_base = "http://localhost:8000/v1"
client = OpenAI(
    api_key=openai_api_key,
    base_url=openai_api_base,
)

chat_response = client.chat.completions.create(
    model="/path/to/step3",  # 模型路径
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "The capital of France is"},
    ],
)
print("Chat response:", chat_response.choices[0].message.content)
```
更多资料可参考源项目中的[`README_ori`](./README_ori.md)。
## result
example1:
- text:Please describe the image.
- image:

<div align=center>
    <img src="./figures/bee.jpg"/>
</div>


- 输出结果:


<div align=center>
    <img src="./figures/result.png"/>
</div>

### 精度
DCU与GPU精度一致，推理框架：vllm。
## 应用场景
### 算法类别
`对话问答`
### 热点应用行业
`电商,教育,广媒`
## 预训练权重
huggingface权重下载地址为：

- [stepfun-ai/step3](https://huggingface.co/stepfun-ai/step3)

`注：建议加镜像源下载：export HF_ENDPOINT=https://hf-mirror.com`
## 源码仓库及问题反馈
- https://developer.sourcefind.cn/codes/modelzoo/step3_pytorch
## 参考资料
- https://github.com/stepfun-ai/Step3/tree/main

