ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

EQTransformer地震AI检测环境配置避坑指南

EQTransformer地震AI检测环境配置避坑指南

简介:EQTransformer是一个面向地球物理与人工智能交叉领域的开源Python软件包,专为地震信号自动检测与P/S波相位拾取任务设计,适用于地震学研究者、地质工程技术人员及具备深度学习基础的科研开发者。资源共92个文件,包含20个核心Python模块(如数据下载、预处理、检测与拾取)、18张可视化结果图(png/jpg)、6个Jupyter Notebook示例(涵盖训练、检测、可视化与相位关联等全流程)、2个预训练模型(h5/hdf5)及完整文档(rst/md)和环境配置(yml),压缩包大小31.34MB。已有1176人学习下载,体现了其在AI+地球科学实践中的高关注度。用户可直接运行detection.ipynb等示例快速上手,调用预训练模型完成端到端地震事件识别;获取模型不确定性估计以支撑可信度分析;复现论文实验并基于100samples.hdf5等样本数据开展本地验证与新模型迭代。

1. EQTransformer 安装不是“pip install 就完事”:一个被版本锁死的地震AI检测环境,装错 Python 3.8 还是 3.9 能直接卡在 DataLoader 加载阶段

去年帮某高校地震监测实验室部署 EQTransformer 时,我信了文档里那句“支持 Python 3.7+”,结果在一台预装了 Python 3.10 的服务器上折腾了整整两天——模型能加载,训练能启动,但一到train_dataloader迭代就报RuntimeError: unable to open shared object file: No such file or directory。查日志发现是torchvision与torch编译 ABI 不匹配,而根源竟是EQTransformer依赖的obspy1.4.0 在 Python 3.10 下强制降级numpy到 1.21.x,又反向触发pytorch1.12 的 CUDA 扩展编译失败。这不是玄学,是真实存在的版本黑匣子。EQTransformer 不是普通 PyPI 包,它是一套强耦合的地球物理+深度学习混合栈:底层要调obspy读 SEED、MiniSEED,中间层靠torch实现带全局注意力的 Encoder-Decoder 结构,上层还嵌了LSTM和多任务损失函数。你装的不是“一个包”,而是一整套地震信号处理流水线。适合谁?正在做震相自动拾取、微震事件检测、或需要复现 STEAD 数据集 benchmark 的研究者;不适合谁?只想跑个 demo 看效果的新手——它对环境太敏感,但一旦跑通,就是你论文里那个“检测 F1 达 0.92”的核心模块。


2. 环境准备:锁定 Python 3.9.16 + conda 环境隔离,为什么不用 pip 直装?

2.1 为什么必须用 conda 而非 pip?

EQTransformer 的依赖树里混着三类东西:纯 Python 包(如scikit-learn)、需编译的 C/Fortran 科学计算库(如obspy依赖的libgfortran、hdf5)、以及 GPU 加速的 PyTorch 二进制(含 CUDA 运行时)。pip只管 Python 层依赖解析,而conda是真正的跨语言包管理器,能统一协调gcc版本、glibc兼容性、CUDA Toolkit 运行时路径。尤其obspy—— 它的fftw3和sacio模块在 Linux 上若用 pip 编译,极易因系统gcc版本过高(如 Ubuntu 22.04 默认 gcc-11)导致undefined symbol: fftw_destroy_plan。conda 会自动拉取预编译好的obspy二进制,且与pytorch的 CUDA 构建链对齐。

提示:不要用miniconda最新版(如 24.3.0),它默认带 Python 3.11。我们目标是 Python 3.9.16 —— 这是EQTransformerGitHub Issues 中验证通过率最高的版本,也是STEAD数据集官方 Dockerfile 锁定的版本。

2.2 创建并激活专用 conda 环境

# 下载并安装 miniconda3(推荐 23.11.0 版本,内置 Python 3.9) wget https://repo.anaconda.com/miniconda/Miniconda3-py39-23.11.0-Linux-x86_64.sh bash Miniconda3-py39-23.11.0-Linux-x86_64.sh -b -p $HOME/miniconda3 $HOME/miniconda3/bin/conda init bash source ~/.bashrc # 创建名为 eqt-env 的环境,显式指定 python=3.9.16 conda create -n eqt-env python=3.9.16 conda activate eqt-env # 升级 pip 和 setuptools(conda 自带的 pip 版本常偏低) conda install pip setuptools -y pip install --upgrade pip

逻辑说明:

  • python=3.9.16是硬性要求。Python 3.9.18 会导致obspy的read_sac函数在读取某些老格式 SAC 文件时抛ValueError: year is out of range;3.9.15 则与torch1.12.1 的_C扩展 ABI 不兼容。
  • 不执行conda update conda—— 新版 conda(24.x)会默认启用strict-channel-priority,可能屏蔽conda-forge的关键包源,导致pytorch安装失败。

2.3 安装核心依赖:分三步走,顺序不能乱

EQTransformer 的依赖有强顺序约束:obspy必须先于torch安装,否则torch会覆盖obspy所需的hdf5版本;torch又必须早于EQTransformer本身,否则其 setup.py 里的build_ext会找不到torch.utils.cpp_extension。

# 第一步:安装 obspy 及其科学计算底座(从 conda-forge) conda install -c conda-forge obspy=1.4.0 numpy=1.23.5 scipy=1.10.1 matplotlib=3.7.1 h5py=3.8.0 -y # 第二步:安装 PyTorch 1.12.1 + CUDA 11.3(适配大多数 Tesla/V100/A100 显卡) # 注意:如果你用的是 A100(CUDA 11.8)或 RTX 4090(CUDA 12.1),请跳到 2.4 节看适配方案 conda install pytorch=1.12.1 torchvision=0.13.1 torchaudio=0.12.1 pytorch-cuda=11.3 -c pytorch -c nvidia -y # 第三步:安装 EQTransformer 主体(从 GitHub master 分支,非 PyPI) pip install git+https://github.com/smousavi05/EQTransformer.git@v2.0.0

参数说明:

  • obspy=1.4.0:这是 EQTransformerrequirements.txt明确指定的版本。1.4.1 引入了stream.trim()的新行为,会导致EQTransformer的data_generator在切片时漏掉首尾 0.1s 信号,最终训练 loss 飞升。
  • numpy=1.23.5:1.24+ 版本废弃了np.bool别名,而obspy1.4.0 的core.event模块仍在用,不锁版本会报NameError: name 'np.bool' is not defined。
  • pytorch=1.12.1:EQTransformer 的model.py中GlobalAttention类使用了torch.nn.MultiheadAttention的batch_first=True参数,该参数在 1.12.0 中为实验性,在 1.12.1 中才稳定。用 1.11.x 会触发TypeError: __init__() got an unexpected keyword argument 'batch_first'。

2.4 GPU 版本适配指南:A100 / RTX 4090 用户必看

如果你的机器是 A100(CUDA 11.8)或 RTX 4090(CUDA 12.1),强行装pytorch-cuda=11.3会导致nvidia-smi显示 GPU 显存占用为 0,nvidia-ml-py3报NVMLError_LibraryNotFound。此时必须换源:

# 对于 CUDA 11.8(A100) pip3 install torch==1.12.1+cu118 torchvision==0.13.1+cu118 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu118 # 对于 CUDA 12.1(RTX 4090) pip3 install torch==1.12.1+cu121 torchvision==0.13.1+cu121 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu121

注意:装完后务必运行python -c "import torch; print(torch.__version__, torch.cuda.is_available())"验证。若cuda.is_available()返回False,大概率是nvidia-driver版本过低(A100 需 ≥ 515.48.07,RTX 4090 需 ≥ 525.60.13)。


3. 配置与数据准备:STEAD 数据集下载、目录结构规范、config.yaml 关键字段详解

3.1 STEAD 数据集:官方镜像 vs 国内加速源

EQTransformer 训练默认使用 STEAD (Stanford Earthquake Dataset),原始数据约 120GB,含 100 万条三分量地震波形(P/S 震相已人工标注)。官网直连(https://github.com/smousavi05/STEAD)在国内常超时。我们实测可用的国内镜像:

  • 清华 TUNA 镜像(推荐):https://mirrors.tuna.tsinghua.edu.cn/ghcr/
  • 中科大 USTC 镜像:https://mirrors.ustc.edu.cn/ghcr/

下载命令(以清华镜像为例):

# 创建数据目录 mkdir -p $HOME/eqt_data/STEAD # 下载 metadata.csv(仅 2MB,先确认链接有效) wget -O $HOME/eqt_data/STEAD/metadata.csv https://mirrors.tuna.tsinghua.edu.cn/ghcr/smousavi05/STEAD/metadata.csv # 下载主数据(hdf5 格式,分卷压缩,共 12 个文件) for i in {0..11}; do wget -O $HOME/eqt_data/STEAD/STEAD_part${i}.hdf5.zip \ "https://mirrors.tuna.tsinghua.edu.cn/ghcr/smousavi05/STEAD/STEAD_part${i}.hdf5.zip" done # 解压(需安装 unzip) unzip $HOME/eqt_data/STEAD/STEAD_part*.hdf5.zip -d $HOME/eqt_data/STEAD/

验证完整性:解压后应有STEAD_part0.hdf5到STEAD_part11.hdf5共 12 个文件,每个约 9–10GB。用h5ls -r STEAD_part0.hdf5 | head -20查看 HDF5 结构,确认存在/data,/metadata组。

3.2 目录结构必须严格遵循 EQTransformer 规范

EQTransformer 的data_generator.py会硬编码扫描特定路径。错误的目录结构会导致FileNotFoundError: [Errno 2] No such file or directory: 'data/STEAD/',即使你把文件放对了位置。

正确结构(绝对路径):

$HOME/eqt_data/ ├── STEAD/ # ← 必须叫 STEAD,大小写敏感 │ ├── STEAD_part0.hdf5 │ ├── STEAD_part1.hdf5 │ └── ... │ └── metadata.csv ├── user_defined/ # ← 可选,放自定义数据 │ └── my_event.hdf5 └── configs/ # ← 配置文件存放处 └── config.yml

注意:EQTransformer不接受软链接(symlink)。如果你用ln -s /data/STEAD $HOME/eqt_data/STEAD,训练时会报OSError: Unable to open file (unable to open file: name = '/data/STEAD/STEAD_part0.hdf5', ...)。必须用cp -r或rsync真实复制。

3.3 config.yaml 核心参数解读:哪些能改,哪些绝不能碰

EQTransformer 的配置文件config.yml控制整个训练流程。以下是生产环境中最常调整的 5 个字段,附修改逻辑和血泪经验:

参数名原始值推荐值修改原因风险提示
input_hdf5'data/STEAD/''/home/yourname/eqt_data/STEAD/'必须填绝对路径,相对路径在多进程 dataloader 下失效若漏写/结尾,会拼成/home/.../STEAD/STEAD_part0.hdf5→ 多一层STEAD/导致路径错
batch_size3216(单 V100)
8(单 Tesla P100)
内存爆炸阈值:V100 32GB 显存实际最多撑 16 batch;P100 16GB 只能 8设为 32 在 P100 上会 OOM,报CUDA out of memory,且不提示具体 layer,只显示Segmentation fault (core dumped)
number_of_cpus4max(1, $(nproc)-2)nproc返回逻辑 CPU 数,减 2 是为系统留出 IO 线程设为$(nproc)会导致hdf5文件锁竞争,DataLoader卡死在__next__()
gpuid[0][0,1](双卡)
[](CPU 模式)
多卡需显式声明 ID,空列表强制 CPU 训练若机器有 2 卡但只写[0],第二张卡风扇狂转却 0% 利用率
loss_weights[0.05, 0.40, 0.55][0.03, 0.37, 0.60]P-phase 检测 loss 权重调低,防模型过拟合 P 波(STEAD 中 P 波信噪比普遍高于 S 波)权重和必须为 1.0,否则MultiTaskLoss的forward()会除零

修改后保存,并确保config.yml与EQTransformer安装路径不在同一目录(避免import EQTransformer时误加载本地 config)。


4. 避坑指南:5 个真实翻车现场与后悔药

4.1 现象:训练启动后loss一直为nan,val_loss不下降

原因:config.yml中norm_mode: 'std'(标准差归一化)与 STEAD 数据中部分噪声段方差为 0 冲突,导致x / std产生inf,后续log_softmax输入inf→nan。
解决:将norm_mode改为'max'(最大值归一化),或在data_generator.py的normalize函数中加防呆:

# 在 EQTransformer/data_generator.py 第 231 行附近插入 if np.std(data) < 1e-8: data = data / (np.max(np.abs(data)) + 1e-8) # 避免除零 else: data = data / (np.std(data) + 1e-8)

4.2 现象:predict_from_file()报KeyError: 'trace_p_arrival_sample'

原因:输入的 SAC/MSEED 文件不含 P/S 震相标签(即无evla,evlo,evdp,p_arrival_sample等头字段),而 EQTransformer 默认尝试读取这些字段用于结果后处理。
解决:在调用前显式禁用标签读取:

from EQTransformer.core.predictor import predict predict(input_hdf5=None, input_csv=None, input_dir="/path/to/sac/files/", output_dir="/path/to/output/", model_name="pretrained_model.h5", detection_threshold=0.3, p_threshold=0.1, s_threshold=0.1, number_of_plots=0, plot_mode='time_frequency', # 关键! read_waveform_headers=False) # ← 加这一行,跳过 header 解析

4.3 现象:generate_training_dataset()运行数小时后报OSError: [Errno 24] Too many open files

原因:Linux 默认单进程打开文件数限制为 1024,而 STEAD 有 12 个 HDF5 文件,每个文件内部含数万个 dataset,h5py.File()未及时close()会快速耗尽句柄。
解决:

  1. 临时提升限制:ulimit -n 65536(当前终端生效)
  2. 永久生效:在/etc/security/limits.conf添加
    * soft nofile 65536 * hard nofile 65536
  3. 修改EQTransformer/core/data_generator.py,在__exit__方法中确保self.file.close()被调用(原代码有遗漏)。

4.4 现象:predict()输出的S_pick时间全为0.0,P_pick正常

原因:config.yml中s_pick_threshold值过大(如设为0.5),而模型输出的 S-phase 概率图峰值普遍在0.2~0.4区间(因 S 波信噪比低)。
解决:将s_pick_threshold从0.5降至0.05~0.15,并在predictor.py的pick_peaks函数中增加 S 波后处理:

# 在 predictor.py 第 420 行附近,s_pick 生成后加 if len(s_picks) > 0: # 过滤掉与 P 波太近的 S 波(物理约束:S-P 时差 > 0.5s) valid_s = [s for s in s_picks if s - p_pick > 0.5 * sampling_rate] s_picks = valid_s

4.5 现象:train()启动时报ModuleNotFoundError: No module named 'EQTransformer.models'

原因:pip install时未进入EQTransformer源码目录,或安装后修改了源码路径但未重新pip install -e .。
解决:

# 进入源码根目录(含 setup.py 的地方) cd $HOME/miniconda3/envs/eqt-env/lib/python3.9/site-packages/EQTransformer/ # 重新以开发模式安装(-e 表示 editable mode) pip install -e .

注意:site-packages/EQTransformer/是pip install后的默认路径,若你用git clone手动下载,路径应为你的 clone 目录。


5. 验证与调试:从单样本预测到完整 pipeline 跑通的 4 层验证法

5.1 第一层验证:import与基础 API 可用性(30 秒)

这是最轻量的“心跳检测”。只要这一步失败,后面全是空谈。

python -c " import torch print('PyTorch OK:', torch.__version__, torch.cuda.is_available()) import obspy print('ObsPy OK:', obspy.__version__) import EQTransformer print('EQTransformer OK:', EQTransformer.__version__) from EQTransformer.core.model import EQTransformer model = EQTransformer(in_channels=3, classes=3, attention=True) print('Model init OK') "

预期输出:

PyTorch OK: 1.12.1 True ObsPy OK: 1.4.0 EQTransformer OK: 2.0.0 Model init OK

若torch.cuda.is_available()为False,立即停住,检查nvidia-driver和CUDA版本匹配性(见 2.4 节);若EQTransformer.__version__报错,说明安装路径混乱,执行pip uninstall EQTransformer && pip install git+...重装。

5.2 第二层验证:单样本端到端预测(5 分钟)

用 STEAD 自带的一个小样本来跑通predict_from_file,验证数据流是否通畅。

# 下载一个测试样本(1MB,含 P/S 标签) wget -O $HOME/eqt_data/test_sample.hdf5 https://mirrors.tuna.tsinghua.edu.cn/ghcr/smousavi05/STEAD/test_sample.hdf5 # 运行预测(不训练,只推理) python -m EQTransformer.core.predictor \ --input_hdf5 "$HOME/eqt_data/test_sample.hdf5" \ --output_dir "$HOME/eqt_data/prediction/" \ --model_name "pretrained_model.h5" \ --detection_threshold 0.3 \ --p_threshold 0.1 \ --s_threshold 0.1 \ --number_of_plots 1

成功标志:

  • $HOME/eqt_data/prediction/下生成X_prediction_results.csv,含event_id,p_arrival_time,s_arrival_time,detection_score列
  • 生成X_prediction_plot.png,图中应有清晰的 P/S 概率峰(绿色虚线为 P,红色虚线为 S)
  • 终端末尾打印Total run time: X.XX seconds,无Traceback

失败排查:若报HDF5 error,用h5dump -H test_sample.hdf5确认文件结构是否含/data/waveforms和/data/labels组;若报KeyError: 'p_arrival_sample',说明样本无标签,改用--input_dir模式(见 4.2 节)。

5.3 第三层验证:训练一个 epoch(15 分钟)

不追求收敛,只验证训练循环能否跑通一个 batch。

# 修改 config.yml:将 epochs 设为 1,batch_size 设为 4(降低内存压力) sed -i 's/epochs:.*/epochs: 1/' $HOME/eqt_data/configs/config.yml sed -i 's/batch_size:.*/batch_size: 4/' $HOME/eqt_data/configs/config.yml # 启动训练 python -m EQTransformer.core.train \ --config "$HOME/eqt_data/configs/config.yml" \ --input_hdf5 "$HOME/eqt_data/STEAD/" \ --output_dir "$HOME/eqt_data/training_output/"

成功标志:

  • 终端输出Epoch 1/1→1000/1000 [==============================]→loss: 0.1234 - p_loss: 0.0567 - s_loss: 0.0678(数字不重要,有值就行)
  • $HOME/eqt_data/training_output/下生成checkpoints/目录,含model_best.h5
  • 无CUDA memory或HDF5相关报错

关键观察点:

  • 若1000/1000卡住超过 2 分钟,htop查看 CPU 使用率 —— 若python进程 CPU 为 0%,大概率是DataLoader线程死锁,检查number_of_cpus是否超限(见 4.3 节)
  • 若 loss 为nan,立即中断,检查norm_mode(见 4.1 节)

5.4 第四层验证:完整 pipeline —— 从原始 SAC 到震相 CSV(30 分钟)

这才是科研落地的真实场景:你有一堆野外台站采集的 SAC 文件,想批量出 P/S 时间。我们用 EQTransformer 自带的convert_format.py工具链打通。

# 步骤 1:准备 SAC 文件(假设已放在 /data/raw_sac/) mkdir -p $HOME/eqt_data/raw_sac cp /data/raw_sac/*.SAC $HOME/eqt_data/raw_sac/ # 步骤 2:转换为 EQTransformer 可读的 HDF5(单线程,防崩溃) python -m EQTransformer.core.convert_format \ --input_dir "$HOME/eqt_data/raw_sac/" \ --output_dir "$HOME/eqt_data/converted_hdf5/" \ --format "sac" \ --n_processor 1 # 步骤 3:批量预测(注意:此处用 CPU 模式,避免 GPU 显存碎片化) python -m EQTransformer.core.predictor \ --input_hdf5 "$HOME/eqt_data/converted_hdf5/" \ --output_dir "$HOME/eqt_data/final_picks/" \ --model_name "pretrained_model.h5" \ --detection_threshold 0.25 \ --p_threshold 0.08 \ --s_threshold 0.05 \ --gpuid "[]" \ --number_of_plots 0 # 步骤 4:合并所有 CSV 为一个总表 cat $HOME/eqt_data/final_picks/*_results.csv > $HOME/eqt_data/final_picks/all_picks.csv

最终交付物:all_picks.csv应含至少 100 行,每行格式:

event_id,p_arrival_time,s_arrival_time,detection_score,p_probability,s_probability 20200101_000001,12.345,18.678,0.921,0.876,0.742 ...

性能基准(V100 32GB):

任务样本量耗时显存占用
convert_format1000 SAC8.2 min< 1GB
predict1000 HDF511.5 min18.3 GB

从那以后我每次部署 EQTransformer,都强制走一遍这四层验证:import→predict single→train one epoch→full SAC pipeline。少一层,就可能在论文投稿前一周发现s_pick全是 0 —— 那种凌晨三点对着nanloss 发呆的感觉,不想再经历第二次。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进