Liueic

Back

MMSeqs2 本地搜索

MMSeqs2 本地搜索

安装 MMseqs 2 (带 AVX 2 支持)#

需要安装最新版的 MMseqs 2,建议使用静态编译版本以获得最佳性能

# 下载静态编译版本 (Linux AVX2)
wget https://mmseqs.com/latest/mmseqs-linux-avx2.tar.gz
tar xvf mmseqs-linux-avx2.tar.gz
export PATH=$(pwd)/mmseqs/bin/:$PATH

# 验证安装
mmseqs -h
bash

下载并构建数据库#

可以前往这个网站进行下载:Steinegger Lab Dataset

需要下载的数据库有:uniref30_2302.db.tar.gzcolabfold_envdb_2023.tar.gz

数据库非常大

解压,创建索引#

创建对应的目录:

mkdir MMSeqs # 创建目录
cd MMSeqs
tar -I pigz -xvf /48T/software/colabfold_envdb_2023.tar.gz -C .
tar -I pigz -xvf /48T/software/uniref30_2302.db.tar.gz -C .
bash

然后等待,这一步等待时间非常长,建议使用 tmux 或者其他的东西挂起终端,怕意外中断

padding,(对 colabfold_envdb_2023 同理):

# 语法: mmseqs makepaddedseqdb <输入数据库> <输出数据库名称>
mmseqs makepaddedseqdb uniref30_2302_db uniref30_2302_db_padded
bash

这一步发生了什么? 它会生成一个新的数据库(uniref 30_2302_db_padded),里面的序列长度会被补齐(Pad)到特定的倍数,这会占用额外的磁盘空间,但对于 A 100 这种大卡来说,能极大地减少显存访问的碎片化,速度至关重要

这一步无法使用 GPU 进行加速,只能使用 CPU

开始推理#

可以直接参考我写的这个脚本,你可能需要根据自己的需求来更改,MMseqs 本身应该是支持多序列单文件的输入的:

#!/bin/bash
# =====================================================================
# MMseqs2 多物种批量 MSA 生成脚本
# =====================================================================

set -u
set -e

# --- 1. 核心路径配置 (请核对) ---
# 输入数据的文件夹 (当前目录)
INPUT_ROOT="./Gene_Family"
# 输出结果的总目录
OUTPUT_ROOT="./MSA_Results"

# MMseqs 程序和数据库路径 (根据你之前的记录填写)
MMSEQS_BIN="/mnt/liueic/MMSeqs/mmseqs/bin/mmseqs"
DB_UNIREF="/mnt/liueic/MMSeqs/uniref30_2302_db"
DB_ENV="/mnt/liueic/MMSeqs/colabfold_envdb_2023"

# --- 2. 参数设置 ---
THREADS=16
GPU_ID=1
export CUDA_VISIBLE_DEVICES="$GPU_ID"

# 创建总输出目录
mkdir -p "$OUTPUT_ROOT"

echo "=========================================================="
echo "开始批量处理 MSA"
echo "扫描目录: $INPUT_ROOT"
echo "结果输出: $OUTPUT_ROOT"
echo "=========================================================="

# 遍历所有 .faa 文件
for fasta_file in "${INPUT_ROOT}"/*.faa; do
    # 检查文件是否存在 (防止目录为空)
    [ -e "$fasta_file" ] || continue

    # --- A. 提取物种名,创建独立文件夹 ---
    filename=$(basename "$fasta_file")
    # 提取物种名 (去掉后缀 blast.pep.faa,让文件夹名更短更干净)
    species_name="${filename%.pep.faa}"
    # 或者如果你想要完整文件名做文件夹,用这个: species_name="${filename%.*}"
    
    # 定义该物种的专属输出目录
    JOB_DIR="${OUTPUT_ROOT}/${species_name}"
    TMP_DIR="${JOB_DIR}/tmp"
    FINAL_DIR="${JOB_DIR}/final_a3m"
    
    mkdir -p "$JOB_DIR" "$TMP_DIR" "$FINAL_DIR"

    echo ""
    echo "----------------------------------------------------------"
    echo "正在处理物种: $species_name"
    echo "输入文件: $filename"
    echo "专属目录: $JOB_DIR"
    echo "----------------------------------------------------------"

    # --- B. 运行 MMseqs2 流程 ---
    
    # 1. CreateDB
    "$MMSEQS_BIN" createdb "$fasta_file" "$JOB_DIR/query_db" --shuffle 0 > /dev/null

    # 2. Search UniRef30 (A100 加速)
    echo "   Running Search UniRef30..."
    "$MMSEQS_BIN" search "$JOB_DIR/query_db" "$DB_UNIREF" \
        "$JOB_DIR/res_uniref" "$TMP_DIR" \
        --threads "$THREADS" -s 8 --gpu 1 --max-seqs 2000 --num-iterations 3 > /dev/null

    # 3. Search EnvDB
    echo "   Running Search EnvDB..."
    "$MMSEQS_BIN" search "$JOB_DIR/query_db" "$DB_ENV" \
        "$JOB_DIR/res_env" "$TMP_DIR" \
        --threads "$THREADS" -s 8 --gpu 1 --max-seqs 2000 --num-iterations 3 > /dev/null

    # 4. Result2MSA
    echo "   Converting to MSA..."
    "$MMSEQS_BIN" result2msa "$JOB_DIR/query_db" "$DB_UNIREF" \
        "$JOB_DIR/res_uniref" "$JOB_DIR/msa_uniref" \
        --msa-format-mode 2 --threads "$THREADS" > /dev/null

    "$MMSEQS_BIN" result2msa "$JOB_DIR/query_db" "$DB_ENV" \
        "$JOB_DIR/res_env" "$JOB_DIR/msa_env" \
        --msa-format-mode 2 --threads "$THREADS" > /dev/null

    # 5. Unpack (解包)
    # 先解包到一个临时 merged 目录方便合并
    RAW_A3M_DIR="$JOB_DIR/raw_a3m"
    mkdir -p "$RAW_A3M_DIR"
    
    "$MMSEQS_BIN" unpackdb "$JOB_DIR/msa_uniref" "$RAW_A3M_DIR" --unpack-name-mode 0 --unpack-suffix ".uniref" > /dev/null
    "$MMSEQS_BIN" unpackdb "$JOB_DIR/msa_env" "$RAW_A3M_DIR" --unpack-name-mode 0 --unpack-suffix ".env" > /dev/null

    # --- C. 合并 & 重命名 (自动化修正文件名) ---
    echo "   Merging and Renaming..."
    
    # 读取 ID 映射表 (MMseqs 自动生成的 query_db.lookup)
    LOOKUP_FILE="$JOB_DIR/query_db.lookup"
    
    while read -r id original_header; do
        # 1. 解析文件名
        # original_header 可能是 ">SeqID description...",我们要取第一个词作为文件名
        clean_name=$(echo "$original_header" | awk '{print $1}' | tr -d '>' | tr '|/ ' '___')
        
        # 定义输入输出
        uni_file="${RAW_A3M_DIR}/${id}.uniref"
        env_file="${RAW_A3M_DIR}/${id}.env"
        final_file="${FINAL_DIR}/${clean_name}.a3m"
        
        # 2. 合并操作
        if [ -f "$uni_file" ]; then
            cat "$uni_file" > "$final_file"
            
            # 如果有环境序列,去掉第一行后追加
            if [ -f "$env_file" ]; then
                tail -n +2 "$env_file" >> "$final_file"
            fi
        fi
    done < "$LOOKUP_FILE"

    # --- D. 清理 ---
    echo "   Cleaning up tmp files for $species_name..."
    rm -rf "$TMP_DIR" "$RAW_A3M_DIR" "$JOB_DIR/res_uniref*" "$JOB_DIR/res_env*" "$JOB_DIR/msa_*"

    echo "$species_name 完成!"
done

echo "=========================================================="
echo "所有物种处理完毕!"
echo "请查看结果目录: $OUTPUT_ROOT"
echo "=========================================================="
bash

查看是否运行成功,查看显卡调用 nvidia-smi

运行结束后的目录结构:

MSA_Results_P450/
├── Manduca_sexta/                <-- 自动根据文件名创建的文件夹
│   ├── query_db                  <-- 保留了 DB 以备不时之需
│   └── final_a3m/                <-- 这里是可以直接喂给 ColabFold 的!
│       ├── SeqA.a3m              
│       ├── SeqB.a3m
│       └── SeqC.a3m
├── Papilio_xuthus/
│   └── final_a3m/
│       ├── ...
└── ...
plaintext

MMseqs 2 的工作流是: FASTA -> Createdb -> Search (生成 ResultDB) -> Result 2 MSA (转换) -> UnpackDB (解压出文件)

后话#

ColabFold 里面允许我们自定义 host-url,于是我就病急乱投医,我真的去找了 MSA Search 的容器镜像,在英伟达的官网这里可以找到:Overview — NVIDIA NIM for MSA Search

然后非常令人哭笑不得的是,如果你直接使用中国大陆的 IP 去拉这个容器,他会告诉你说让你去找大陆的代理商

但是据我测试这个代理商国内如果你要使用的话,需要以机构/企业的身份去申请,就很离谱,因为英伟达上面下载只需要个人开发者申请一个 key 就可以了

所以我整了个花活,我用了 Azure 东京地区的服务器,去拉这个容器,然后再把容器中转到阿里云的容器仓库,再用集群从阿里云容器仓库拉这个容器

虽然我最后没有跑起来,因为我用的是 singularity,这个东西有各种奇奇怪怪的文件系统写入的问题,很无语

gpuserver#

因为这个 MMseqs 每次都需要重新读取数据,导致速度非常慢!需要启动一个守护进程,把数据写入到显存/内存中,以一个服务端的形式提供服务

#!/bin/bash
# ===============================================================
# MMseqs2 GPU 驻留服务启动脚本 (修正版)
# ===============================================================

set -u

# === 1. 配置路径 ===
MMSEQS_BIN="mmseqs/bin/mmseqs"
WORKDIR=$(pwd)

# 数据库路径 (确保这些路径是正确的)
DB_UNIREF="uniref30_2302_db"
DB_ENV="colabfold_envdb_2023"

# 日志文件
LOG_UNIREF="server_uniref.log"
LOG_ENV="server_env.log"

# === 2. GPU 环境设置 ===
# 指定卡,这里简化处理,默认使用 GPU 0 或 1
# 如果你有特定 GPU 编号,请修改这里
export CUDA_VISIBLE_DEVICES=0  

echo "------------------------------------------------"
echo "正在启动 MMSeqs2 GPU Resource Managers..."
echo "注意:gpuserver 不是网络服务器,它不监听端口。"
echo "它将数据库锁定在 GPU/内存中以加速本地搜索。"
echo "------------------------------------------------"

# 检查可执行文件
if [ ! -f "$MMSEQS_BIN" ]; then
    echo "错误: 找不到 mmseqs 可执行文件: $MMSEQS_BIN"
    exit 1
fi

# --- 启动 UniRef30 Server ---
echo "启动 UniRef30 GPU Resident Process..."
# 去掉了 --port, --gpu-mode, --gpu-mem, --db-load-mode, --threads
# gpuserver 只需要数据库路径。其他参数通常是在 'search' 时指定的,
# 或者它会默认加载。
nohup "$MMSEQS_BIN" gpuserver "$DB_UNIREF" \
    > "$LOG_UNIREF" 2>&1 &

PID_UNIREF=$!
echo "   PID: $PID_UNIREF | Log: $LOG_UNIREF"

# --- 启动 ColabFold EnvDB Server ---
echo "启动 EnvDB GPU Resident Process..."
nohup "$MMSEQS_BIN" gpuserver "$DB_ENV" \
    > "$LOG_ENV" 2>&1 &

PID_ENV=$!
echo "   PID: $PID_ENV | Log: $LOG_ENV"

echo "------------------------------------------------"
echo "   GPU 服务已启动。"
echo "------------------------------------------------"
bash

然后这个坑点在于,新版本的 MMseqs 的参数已经改了,不能使用启动 http 服务器这种方式处理任务了,我也没想好要怎么处理这个问题