
简介面向地震学研究者、地球物理专业学生及具备一定 Python 基础的深度学习实践者这份资源提供基于注意力机制深度神经网络的 EQTransformer 软件包可在全球地震数据上同时完成地震信号检测与 P/S 相位拾取并输出概率及模型不确定性。压缩包共 92 个文件、约 31.34MB包含 20 个 Python 源码模块、16 份 rst 文档、6 个 ipynb 示例教程以及用于示意结果和模型/样本数据的 png、h5、hdf5 等文件结构上覆盖连续波形下载、预处理、检测拾取、模型构建测试与简单相位关联。已有 1176 人学习下载适合据此复现预训练模型流程、理解分层网络与多任务学习设计并借助示例笔记本和测试代码快速开展实验或二次开发。1. 一条24小时波形扔进去EQTransformer解决的是检测与相位拾取的联合作业凌晨两点台网值班室里最枯燥的活不是修设备而是把当天几十条三分量连续波形挨个翻一遍手动标出哪个时刻像事件、P波在哪、S波在哪。EQTransformer 这个 Python 包干的就是这件事喂给它连续波形它同时输出事件检测概率和 P/S 相位到时检测与拾取在一个模型里完成不用先跑检测再跑拾取两套流程。它背后是 deep-learning 路线卷积网络提取局部波形特征双向 LSTM 和 Transformer 的自注意力机制兼顾前后文与全局依赖多任务学习让 detection 和 phase-picking 共享同一套表示。适合手里有台网连续数据、要批量构建地震目录的开发者也适合想把相位拾取接进自有处理流水线的人。前提是你能把数据整理成它认识的格式并且接受它输出的是一堆概率曲线而不是现成目录。2. 数据准备链路从mseed原始波形到可喂给模型的HDF52.1 安装与依赖Python 3.9 是相对稳的选择EQTransformer 依赖 TensorFlow 2.x、ObsPy、h5py、pandas、numpy跑推理时 CPU 也能凑合但批量处理连续波形基本离不开 GPU。我一般用 conda 单独开环境避免和系统里的 TensorFlow 版本打架conda create -n eqt python3.9 -y conda activate eqt pip install EQTransformer装完先验证两件事包能不能导入TensorFlow 能不能看到 GPU。import EQTransformer import tensorflow as tf print(EQTransformer:, getattr(EQTransformer, __version__, unknown)) print(TensorFlow:, tf.__version__) print(GPU:, tf.config.list_physical_devices(GPU))这段代码只做环境自检。__version__有些发行版本不暴露取不到就打印 unknown不影响使用。GPU 列表为空说明当前是 CPU 模式预测能跑但会慢一个量级。TensorFlow 和 CUDA/cuDNN 的版本匹配是玄学重灾区装完先跑一个小的tf.matmul确认没有动态库报错再往下走。2.2 输入数据长什么样一个文件一个台站三分量按天切EQTransformer 的prep命令期望输入目录下是一批 mseed 文件每个文件包含一个台站的三分量连续波形通常按天切分。文件命名没有强制模板但最好带上台网、台站、位置码、通道和日期后面排查问题时能一眼定位。通道名要统一常见的组合是 HHZ/HHN/HHE 或 BHZ/BHN/BHE同一个目录里不要混着来。采样率是最容易埋雷的地方。模型训练时用的是 100 Hz 采样prep会把非 100 Hz 的数据重采样过去但重采样之前如果元数据里的采样率本身就是错的后面全盘皆输。我习惯在转换前先抽查一条from obspy import read st read(20240101.MS01..HHZ.mseed) tr st[0] print(台站:, tr.stats.station) print(采样率:, tr.stats.sampling_rate) print(起始时间:, tr.stats.starttime) print(采样点数:, tr.stats.npts) print(理论时长(s):, tr.stats.npts / tr.stats.sampling_rate)npts / sampling_rate和endtime - starttime应该对得上差得明显说明头段里的采样率或时间戳有问题。这个检查花不了几秒但能省掉后面几小时的困惑。2.3 prep 到底做了什么重采样、滑窗、归一化、写 HDF5prep的核心工作是把连续波形切成固定长度的窗口。默认窗口 60 秒、100 Hz也就是 6000 个采样点窗口之间有重叠避免事件正好落在边界上被切掉。eqtransformer prep \ -i ./mseed \ -o ./h5data \ --sampling_rate 100 \ --chunk_size 6000 \ --overlap 0.3 \ --number_of_workers 4参数含义如下参数作用常见取值-i输入 mseed 目录按台站/日期组织-o输出 HDF5 目录单独磁盘别和原始数据混放--sampling_rate重采样目标100--chunk_size单窗口采样点数600060 s × 100 Hz--overlap窗口重叠比例0.3 左右--number_of_workers并行进程数按 CPU 核数别把内存打满overlap0.3意味着步长是 42 秒一个 24 小时连续文件大约切出两千多个窗口。多台站、多天累积下来HDF5 体积会很快上去输出盘要留足空间。转换完成后不要直接开跑预测先打开一个 HDF5 看看结构import h5py with h5py.File(./h5data/MS01_20240101.h5, r) as f: print(顶层键:, list(f.keys())) for key in f.keys(): if isinstance(f[key], h5py.Dataset): print(key, f[key].shape, f[key].dtype)常见结构是一个data数据集形状为(窗口数, 6000, 3)外加记录台站、起始时间、窗口索引的元数据。不同版本键名可能不同先keys()再取别照着旧教程硬编码。抽一个窗口画出来看波形是否正常、三个分量有没有明显反序这一步比看日志有用。2.4 目录组织与批处理脚本台站多了以后手工一条条转不现实。我通常按“台网/台站/年份”三级目录放原始 mseed再用一个 shell 循环按台站调用prep失败的命令记到日志里重跑#!/usr/bin/env bash set -u RAW_ROOT./mseed H5_ROOT./h5data LOG./prep_failed.log : $LOG for sta_dir in $RAW_ROOT/*; do sta$(basename $sta_dir) mkdir -p $H5_ROOT/$sta if ! eqtransformer prep -i $sta_dir -o $H5_ROOT/$sta \ --sampling_rate 100 --chunk_size 6000 --overlap 0.3 \ --number_of_workers 4; then echo $sta $LOG fi doneset -u防止变量拼错时静默跑偏失败重定向到日志而不是直接中断是为了让一个坏台站不至于卡住整批。跑完先看日志行数再随机抽两个台站的 HDF5 检查窗口数和时间范围确认没有出现“文件生成了但内容是空的”这种情况。3. 模型结构与推理卷积、LSTM、自注意力如何拼成三输出头3.1 输入张量与卷积编码先把 6000 点压成特征序列模型输入是(6000, 3)三个通道对应三分量。前面几层是一维卷积加批归一化和激活函数沿着时间轴滑动把原始波形里的短周期特征、包络变化压成更低分辨率、更多通道的特征图。卷积核在三个分量上共享权重但第一层会分别看每个分量所以分量顺序错了模型不会报错只会悄悄给出奇怪的概率。加载权重后可以直接看模型摘要确认输入输出形状import tensorflow as tf model tf.keras.models.load_model(./model.h5, compileFalse) model.summary(line_length120) print(输入:, model.inputs) print(输出:, model.outputs)compileFalse是为了跳过自定义损失函数和优化器配置只做结构查看。摘要里重点看三件事输入是不是(None, 6000, 3)输出是不是三个分支最后几层的激活是不是 sigmoid。如果输出只有一个分支说明权重文件和当前代码版本不匹配别硬跑。3.2 BiLSTM 与 Transformer一个管前后文一个管全局依赖卷积之后接双向 LSTM把正反两个方向的时间上下文都吃进来适合捕捉 P 波初动这种前后差异明显的模式。再往后是 Transformer 的自注意力层让窗口内任意两个时间点直接建立联系处理长周期背景噪声和远距离相位关系时比纯 RNN 更稳。两条路径叠在一起模型既知道局部波形长什么样也能看到整段 60 秒的全局结构。这部分对使用者来说是黑盒但有一个实际影响自注意力的计算量和窗口长度是平方关系chunk_size从 6000 加到 12000显存占用不是线性涨。想在更长的窗口上跑先降batch_size试别一上来就把卡打爆。3.3 三个输出头与多任务损失detection、P、S 各管一段模型末端分三个头分别输出检测概率曲线、P 波概率曲线、S 波概率曲线长度都对齐回 6000 点每个时间点一个 0 到 1 之间的值。训练时三条损失加权求和检测任务学“这段有没有事件”相位任务学“P/S 具体在第几个采样点”。多任务学习的好处是相位标注能反过来帮助检测检测的上下文也能约束相位位置。推理时的阈值就是卡在这三条曲线上的detection_threshold检测概率超过多少算一个事件候选P_thresholdP 波概率超过多少算一次拾取S_thresholdS 波概率超过多少算一次拾取默认常见值是 0.3但这不是万能钥匙。噪声水平高的台网0.3 会带来一堆误检小震多的区域调高又会漏。先按默认跑一批和人工目录对一遍再决定往哪个方向调。3.4 predict 命令与输出解析CSV 里到底有什么准备好 HDF5 和权重文件后预测命令大致如下eqtransformer predict \ -m ./model.h5 \ -i ./h5data \ -o ./predictions \ --detection_threshold 0.3 \ --P_threshold 0.3 \ --S_threshold 0.3 \ --batch_size 100 \ --number_of_workers 2-m是权重路径-i是prep输出的 HDF5 目录-o下会生成逐窗口的概率结果和一个汇总 CSV。batch_size控制一次送进 GPU 的窗口数显存小就降到 20 或 50number_of_workers是数据加载进程数GPU 推理时不要开太大否则 CPU 和 GPU 抢资源吞吐反而下降。汇总结果读进来先看列名和行数import pandas as pd df pd.read_csv(./predictions/predictions.csv) print(df.columns.tolist()) print(df.shape) print(df.head(3))不同版本列名有差异常见会包含台站、检测时间、检测概率、P 到时、S 到时、P/S 概率。拿到之后先按台站分组、按时间排序检查有没有同一秒内重复出现好几条记录。滑窗有重叠同一个事件在相邻窗口里被重复检出是正常现象后处理必须合并不能直接拿原始 CSV 当目录用。4. 训练与微调把通用权重迁移到本地台网4.1 训练数据要求标注 CSV 和正负样本比例微调之前要有一批带标注的波形。常见做法是把事件波形和纯噪声窗口一起放进 HDF5再配一个 CSV每行对应一个窗口字段包括窗口名、P 到时采样点、S 到时采样点、事件结束位置等。P/S 标注允许为空但空标注的样本会被当作负样本或只参与检测任务具体看训练脚本怎么处理。正负样本比例是血泪经验全是事件样本训出来的模型看什么都像地震纯噪声要占到三成以上而且噪声要来自同一批台站、同一时间段别拿完全无关的背景垫进去。标注质量比数量重要P 波标偏 0.2 秒模型学到的就是模糊初动。4.2 train 命令与关键参数训练入口和预测类似换一个子命令eqtransformer train \ -m ./model.h5 \ -i ./train_h5 \ -o ./train_out \ --epochs 30 \ --batch_size 20 \ --learning_rate 0.0001-m这里既可以是从头初始化的模型也可以是预训练权重。epochs不是越大越好验证损失连续几轮不降就该停。batch_size受显存限制20 到 50 是常见区间。learning_rate做微调时用 1e-4 量级从头训可以到 1e-3。参数名以eqtransformer train --help为准不同版本会有增减。训练过程中重点盯验证集上的检测召回和相位残差不要只看总损失。总损失被大量负样本拉低看起来一路下降实际 P/S 拾取可能已经崩了。4.3 迁移学习与小数据量策略本地台网标注通常只有几百到几千条直接从头训基本过拟合。我一般冻结前面几层卷积只训 LSTM 之后的部分和三个输出头等验证集稳定后再解冻最后一组卷积用小学习率继续。数据量少于五百条时甚至只训输出头也有明显收益。阈值调优单独做不要和训练混在一起。拿一个独立验证集扫detection_threshold从 0.1 到 0.7画召回和误检的权衡曲线选一个业务上能接受的折中点。测试集留到最后只跑一次反复在测试集上调阈值等于变相过拟合。5. 避坑与排查采样率、分量顺序和阈值这些细节最容易翻车5.1 采样率与分量顺序模型不报错但结果会偏现象整批数据跑完检测概率普遍低于 0.1人工看波形明明有事件。原因多半是原始数据采样率不是 100 Hzprep虽然重采样了但头段里的sampling_rate写错重采样按错误比例做波形被拉长或压缩。另一种情况是通道顺序不统一有的台站是 ZNE有的是 ENZ模型看到的三个通道对不上训练时的语义。解决转换前逐文件检查stats.sampling_rate和stats.channel在prep里显式指定--sampling_rate 100通道名统一成同一套命名再入库。抽一个窗口把三个分量画出来P 波在垂直分量上初动最清楚如果垂直分量看起来像水平分量顺序就是反了。5.2 时间戳、gap 与滑窗边界假事件和整体偏移现象输出里出现一批集中在某个时刻的检测回看原始波形发现那段是数据断档或者 P/S 到时整体比人工标注晚几十秒。原因是连续波形中间有 gapObsPy 合并后时间轴不连续滑窗跨过断档时把两段不相干的波形拼进同一个 60 秒窗口。时间偏移则多半是窗口起始时间的基准没对齐。解决prep之前先按 gap 切段每段单独处理不要指望模型自己识别断档。检查starttime npts/sampling_rate是否等于endtime不等就先修头段。输出 CSV 里的时间是绝对 UTC 时间别自己再叠加窗口偏移否则会越改越偏。5.3 阈值与重复检测0.3 不是万能钥匙现象同一个事件在结果里出现五六条记录或者小震全被漏掉。原因是滑窗重叠导致同一事件在相邻窗口重复检出而固定阈值没有考虑台网噪声差异。解决后处理按台站和时间排序把检测时间相差几秒以内的记录合并保留概率最高的一条P/S 取对应窗口内的峰值。阈值按台网分批调高噪声台站单独一套参数。多台站结果做关联之后再定性单台检测概率 0.35 的事件如果三个台站同时检到可信度远高于单台 0.6。5.4 显存、并行与输出目录跑崩了先看这三处现象跑到一半 OOM或者 GPU 利用率只有百分之十几。原因是batch_size设得太大或者number_of_workers开了一堆进程同时往 GPU 塞数据。输出目录权限不对也会导致跑完没有结果文件日志里只留一行看不见的警告。解决batch_size从 20 起步往上试显存占用稳定后再加。CPU 预处理可以多进程GPU 推理阶段把 worker 降到 1 到 2。每次换参数先跑一个小台站验证全链路确认输出目录有 CSV、有日志、有时间戳再放开全量。6. 二次开发把预测结果接进自己的关联与定位流水线6.1 用 predictor 函数替代命令行命令行适合批处理真正嵌到调度系统里还是用 Python API 稳。核心入口是predictor参数和命令行基本一一对应from EQTransformer.core.predictor import predictor predictor( input_dir./h5data/MS01, input_model./model.h5, output_dir./predictions/MS01, detection_threshold0.3, P_threshold0.3, S_threshold0.3, batch_size50, number_of_workers2, gpulist[0], )gpulist指定用哪张卡多卡机器上可以按台站分批并行。output_dir建议按台站分开后面合并结果时路径清晰。这个函数会自己写 CSV 和日志调用前确保目录存在异常捕获包在外层单台站失败不影响整批。6.2 结果合并、关联与定位的衔接预测输出是“台站-时间-相位”的列表离地震目录还差关联和定位两步。先在单台站内合并重复检测import pandas as pd df pd.read_csv(./predictions/MS01/predictions.csv) df[detection_time] pd.to_datetime(df[detection_time]) df df.sort_values(detection_time).reset_index(dropTrue) # 同一台站 5 秒内的重复检测合并保留概率最高的一条 merged [] for _, group in df.groupby((df[detection_time].diff() pd.Timedelta(seconds5)).cumsum()): merged.append(group.loc[group[detection_prob].idxmax()]) df_dedup pd.DataFrame(merged).sort_values(detection_time)这段逻辑按时间差切组每组保留检测概率最大的记录。5 秒是经验值台网密集、事件频繁时可以缩短到 2 秒。合并后的结果按台站输出下一步交给多台站关联同一事件在不同台站的 P 到时差应该符合走时曲线聚类之后再接定位程序。关联阶段不要只用 P 波S 波到时的约束能明显压掉误关联。6.3 验证方法和人工目录对一遍再上线验证不要只看几条波形。拿一个月的人工目录做基准按时间容差 0.5 秒匹配检测算召回率和误检率P/S 到时算残差分布看均值有没有系统偏移。如果 P 波残差整体偏正说明拾取偏晚回头查窗口边界和阈值如果残差分布是双峰多半是某个台站的分量顺序或采样率有问题。我一般还会抽误检最多的十个时间段回看波形区分是模型看错了还是原始数据有断档。误检集中在数据质量差的台站时优先修数据而不是继续调模型。从那以后我每次换一批台网数据都先抽三个窗口画图核对采样率、分量顺序和时间戳再跑全量预测这个习惯帮我省掉了至少两次整批重跑。希望帮到你。本文还有配套的精品资源点击获取