EQTransformer实战:连续波形事件检测与P/S震相拾取调优

发布时间:2026/10/24 7:41:38
EQTransformer实战:连续波形事件检测与P/S震相拾取调优 简介面向地震学与深度学习交叉研究者的 EQTransformer 工具包基于带注意力机制的分层深度神经网络完成地震信号检测与 P、S 相位拾取可同时输出概率和模型不确定性适用于连续波形处理、震相拾取及模型复现实验。资源包共 92 个文件、约 31.34MB以 Python 源码和编译缓存为主配有 RST 文档、IPython Notebook 示例、预训练 H5/HDF5 模型与样例数据以及 PNG/JPG 可视化图片另有环境配置、测试和许可证文件便于直接运行、阅读文档并二次开发。已有 1176 人学习或下载。包内模块覆盖连续地震数据下载、预处理、检测、相位拾取、模型构建与测试并提供简单的相位关联示例配合多个 Notebook 演示训练、检测、可视化、下载和关联流程读者可据此搭建从数据到拾取结果的完整实验链路理解网络结构与不确定性估计并在自有数据上迁移预训练模型。1. 震后十分钟先要一张能进定位程序的到时表台网值班的人最怕的不是没数据是三通道连续波形堆了几十 GB而定位程序在等一张 P/S 到时表。人工挑震相一条 24 小时记录顺利时也要十几分钟赶上噪声大的台站翻车概率极高。EQTransformer 这个 Python 包解决的就是这一段喂进连续三通道波形直接吐事件检测结果和 P、S 相位拾取时刻。它把 Transformer 的全局注意力机制和 LSTM 的时序建模拼进同一个神经网络用多任务学习让「有没有事件」「P 在哪」「S 在哪」三件事共享一套编码属于典型的深度学习地震信号检测方案。适合两类人手上有一批 miniseed 想快速出一版目录的台网/观测业务人员以及想拿它做迁移学习、换区域重新训练的开发。下面按「模型怎么搭 → 数据怎么喂 → 怎么跑 → 哪里会踩坑 → 怎么改」拆。2. 模型结构拆解一个 6000×3 的波形窗口如何走完全程2.1 输入窗口与三路输出为什么不拆成三个模型EQTransformer 的输入张量形状固定为(6000, 3)也就是 100 Hz 采样率下 60 秒、三个分量通常 Z/N/E。这个窗口长度不是随手定的太短盖不住 S 波后续的尾波太长则池化后的时间分辨率不够拾取误差会被放大。项目里从预处理、生成器到预测器6000这个数字贯穿始终改它等于改整个模型的形状契约后面会细说。模型的输出不是一路而是三路等长的 6000 点概率序列detector给每个采样点一个「这里属于某个事件」的概率picker_P和picker_S分别给 P、S 到时的概率。三路共享前面同一套编码器这是多任务学习的核心收益——检测任务见得多、标签相对可靠它学到的「这段波形像不像事件」的表征会反哺拾取分支反过来精确到采样点的相位标签又逼着编码器保留高频细节。我见过有人把它拆成「一个检测模型 两个拾取模型」分别训练然后抱怨小震漏检变多本质就是把共享表征这条路堵死了。代价也很直接三路 loss 权重必须调。检测分支的标签在整段 60 秒里只有一小段是 1正负样本极端不均衡拾取分支的正样本更是只有几个采样点。权重给歪了模型会退化成「全输出 0」这个局部最优训练曲线看着在降实际一个事件都检不出来。2.2 编码器逐层拆卷积、双向 LSTM、自注意力各管一段编码器是「四层卷积 → 双向 LSTM → 若干 Transformer 块」的堆叠。卷积负责局部波形特征提取并降采样四层池化把 6000 点压到 375 点相当于每 16 个采样点合成一个时间步双向 LSTM 在这个 375 步的序列上做前后向时序建模抓 P 波到 S 波这种「有先后顺序」的包络关系Transformer 块再叠上去做全局注意力让模型能同时看到窗口首尾——这一点对区分「前 10 秒的微小事件」和「第 50 秒的噪声尖峰」很关键纯 LSTM 在长序列上容易把远距离依赖稀释掉。简化后的骨架长这样层序和超参按项目里的默认值写# EQTransformer/core/models.py 的核心结构精简示意保留真实层序 import tensorflow as tf from tensorflow.keras import layers, Model, Input def conv_block(x, filters, kernel_size, pool2): 卷积 BN ReLU 池化负责提局部特征并降采样 x layers.Conv1D(filters, kernel_size, paddingsame)(x) x layers.BatchNormalization()(x) x layers.Activation(relu)(x) return layers.MaxPooling1D(pool_sizepool)(x) # 6000 - 3000 - ... - 375 def transformer_block(x, num_heads4, ff_dim64, drop0.1): 多头自注意力 前馈两次残差 LayerNorm标准 Transformer 编码块 attn layers.MultiHeadAttention(num_headsnum_heads, key_dimx.shape[-1])(x, x) x layers.Add()([x, attn]) x layers.LayerNormalization()(x) ff layers.Dense(ff_dim, activationrelu)(x) ff layers.Dense(x.shape[-1])(ff) x layers.Add()([x, ff]) return layers.LayerNormalization()(x) def define_EQTransformer(input_dim(6000, 3), cnn_blocks4, lstm_units64): inp Input(shapeinput_dim) x inp # 四层卷积滤波器数 8/16/32/64核长 11/9/7/7先宽后窄前期看大尺度形态 for f, k in zip([8, 16, 32, 64], [11, 9, 7, 7]): x conv_block(x, f, k) # 双向 LSTM375 个时间步上做前后向建模return_sequences 必须为 True x layers.Bidirectional(layers.LSTM(lstm_units, return_sequencesTrue))(x) x transformer_block(x) x transformer_block(x) # 三路解码头stride2 反卷积堆 4 次375 * 16 6000回到采样点级别 outs [] for name in [detector, picker_P, picker_S]: y x for f in [32, 16, 8]: y layers.Conv1DTranspose(f, 7, strides2, paddingsame, activationrelu, namef{name}_up{f})(y) y layers.Conv1DTranspose(1, 7, strides2, paddingsame, activationsigmoid, namename)(y) outs.append(layers.Reshape((input_dim[0],), namef{name}_out)(y)) return Model(inputsinp, outputsouts, nameEQTransformer)几个参数值得单独说清。核长 11/9/7/7 的递减设计是血泪经验第一层大核覆盖约 0.1 秒的波形够看清 P 波起跳的陡度后面层核变小是为了在降采样后不糊掉细节。conv_block里的paddingsame保证每层长度严格折半四层下来正好 6000/16不会出现张量长度对不齐的低级报错。解码头用Conv1DTranspose而不是简单UpSampling1D是因为反卷积带可学习参数能把编码器压掉的相位信息「补」回来代价是参数量增加。最后一层sigmoid输出 0~1 概率这个选择直接决定了 loss 只能是二分类交叉熵换成 softmax 或回归 MSE 都会让收敛变难。还有一处容易被忽略layers.Reshape之前必须确保长度恰好 6000。如果你为了省显存把输入改成 3000 点四层池化只能到 187.5非整数会直接报错这时候要么改池化层数要么把输入补齐到 16 的整数倍——我一般倾向前者网络结构跟窗口长度绑死是这类模型最常见的改造门槛。2.3 多头输出与损失权重多任务学习里的取舍三路输出决定了整个训练配置的形态loss 是一个字典键必须和模型输出层的名字对应权重分别控制检测和两类拾取的话语权。项目默认给的是检测 0.2、P 0.4、S 0.4——检测偏轻不是笔误因为检测的标签在整个窗口上是稠密的每个采样点都有 0/1梯度贡献本来就大拾取标签稀疏需要更高权重才能把梯度拉起来。# 编译时的三路 loss 配置键名与输出层 name 必须一一对应 model.compile( optimizertf.keras.optimizers.Adam(learning_rate1e-3), loss{detector: binary_crossentropy, picker_P: binary_crossentropy, picker_S: binary_crossentropy}, loss_weights{detector: 0.2, picker_P: 0.4, picker_S: 0.4}, metrics[accuracy], )标签侧有个细节决定了模型能不能拾到「人眼级」的精度训练标签不是把到时位置写成一个孤立的 1、其余全 0而是用高斯核在到时附近做平滑项目里对应input_gaussian_sigma这类参数默认 3 个采样点量级。原因很实际——人工标注的到时本身有 ±2~3 个采样点的抖动硬标签等于逼模型去拟合标注误差训出来的概率峰又尖又抖做阈值判断时非常玄学。高斯平滑相当于告诉模型「这附近都算对」概率峰变成一段圆滑的凸起取 argmax 或取峰中心都稳。调整权重时我一般按这个顺序试先把 P、S 权重各降到 0.1 看检测分支能不能单独收敛验证编码器没问题再逐步加回去如果 S 的 loss 死活下不去而 P 正常八成是窗口里 S 已经跑出 6000 点边界标签被截断成半个峰这时候该动的是预处理阶段的窗口对齐策略而不是继续调权重。这个顺序能省掉大量「改了权重但问题在数据」的无用功。3. 目录结构与数据流从 miniseed 到 X_prediction_results.csv3.1 core / model / utils 三个目录各管什么包的结构不复杂但第一次打开还是容易找不到入口。核心逻辑全在EQTransformer/core/预训练权重和结构描述放在EQTransformer/model/辅助脚本在EQTransformer/utils/。按职责拆一下更直观EQTransformer/ ├── core/ │ ├── models.py # define_EQTransformer网络结构定义 │ ├── trainer.py # Trainer 类训练/验证/回调/保存权重 │ ├── generator.py # DataGenerator从 hdf5 按批取数 在线增广 │ ├── mseed_predictor.py # mseed_predictor连续波形滑窗检测的主入口 │ ├── preprocessing.py # preprocess原始 miniseed - 训练用 hdf5 │ ├── postprocessing.py # 滑窗结果去重、合并、按阈值出拾取 │ ├── losses.py # 自定义损失含类别加权 │ ├── metrics.py # 训练期监控的指标 │ └── plotting.py # 波形 概率曲线叠加图 ├── model/ │ ├── EqT_original_model.h5 # 预训练权重 │ └── ... # 配套的结构描述文件json/yaml └── utils/ └── ... # 元数据准备等一次性脚本分工背后的设计思路是「训练态」和「推理态」复用同一份模型定义。models.py只负责搭图不碰数据trainer.py负责喂 hdf5mseed_predictor.py负责喂 miniseed 并按窗口切分。想加自定义 loss 就改losses.py想换滑窗合并策略就动postprocessing.py不用去碰预测器主流程。我一般改项目先看mseed_predictor.py因为它是唯一一个把「读波形 → 归一化 → 滑窗 → 批量预测 → 后处理 → 写 CSV」全串起来的地方读懂它等于读懂了推理链路。3.2 训练集 HDF5 的字段约定最容易被忽略的一环自己训练时第一道坎不是模型是数据格式。项目约定训练集是一个 HDF5 文件里面至少有两组数据data是波形张量形状(N, 6000, 3)metadata是复合数据类型的表一条波形一行字段里带台站信息、到时采样点索引、拾取状态和权重。字段名错一个字母生成器就会在取批时报 KeyError而不是在加载时给你友好提示。import h5py with h5py.File(sample_train.hdf5, r) as f: print(f[data].shape) # (N, 6000, 3)N 条 60 秒三通道波形 meta f[metadata] print(meta.dtype.names) # 复合 dtype字段名就是列名 # 关键字段p_arrival_sample / s_arrival_sample 是窗口内的采样点索引 print(meta[p_arrival_sample][:5]) # p_status / s_status 标记这条样本的到时是否可用于训练 print(meta[p_status][:5])字段的含义要掰开看。p_arrival_sample是 P 到时在 6000 点窗口里的相对索引不是绝对时间戳如果你的预处理把波形截取起点搞错了这个索引会整体偏移训出来的模型拾取结果系统性偏早或偏晚而且 loss 曲线看不出异常——这种系统性偏差最耗时间。p_status/s_status这类标记位用来区分「人工标注」「自动标注」「无标注」生成器会据此决定这条样本要不要参与对应分支的 loss 计算如果把无标注样本的 status 全填成 1等于往训练集里灌噪声。snr字段在做数据筛选时很有用想只保留高信噪比样本训练一个「干净版」模型时直接按这一列卡阈值就行。data里的数值范围也要留意。项目在预处理阶段对每条波形做去均值、去趋势并按标准差归一化预测时对应normalization_mode参数所以 hdf5 里存的是已经归一化过的浮点序列。如果你拿原始 counts 值直接塞进 hdf5训练初期梯度会爆到 nan这时候别急着怀疑学习率——九成是归一化这一步漏了。3.3 滑窗、重叠与归一化预处理阶段埋的雷连续波形预测走的是滑窗从一条几小时的记录上按 6000 点窗口、overlap默认 0.3的步进切出大量窗口批量送进模型再把每个窗口的概率序列映射回绝对时间轴。重叠 0.3 的含义是每次前进 4200 点相邻窗口有 1800 点重合这样落在窗口边界上的事件不会被切掉——一个事件的 P 波如果正好在窗口最后 100 点不重叠的话 S 波就丢了模型只能拾到一个 P。from EQTransformer.core.preprocessing import preprocess # 原始 miniseed - 训练用 hdf5参数以本机 help(preprocess) 为准 preprocess( input_dirmseed_raw, # 原始连续波形目录 output_dirhdf5_out, # 输出 hdf5 元数据表 chunk_size6000, # 与模型输入长度严格一致不要随手改 )chunk_size是这个调用里最不能乱动的参数因为它同时被三处引用模型输入层形状、生成器的批切分、预测器的滑窗步长。改一处不改其余两处轻则报形状不匹配重则静默出错——比如预测时窗口是 3000 点但模型期望 6000某些版本会自动补齐零检出的概率曲线在尾部被拉平你会以为是「模型对小震不敏感」其实是补零补出来的假象。归一化模式也值得单独确认。std是按整条波形标准差归一化对增益变化大的台站比较稳但遇到那种一段平静一段强震的记录整段标准差会被强震段拉高平静段的小事件归一化后被压得几乎看不见。我的做法是对长记录先按固定长度分段再归一化虽然多一步但能明显改善小事件检出。这类调整不需要改模型属于纯数据侧的收益。4. 跑起来环境、权重、三条命令4.1 环境安装TensorFlow / Keras 版本是生死线这个包依赖 TensorFlow 的 Keras 接口附带 obspy读 miniseed、h5py、pandas、matplotlib、scikit-learn。安装本身一条命令但真正的坑在版本项目成型于 Keras 2.x 时代权重文件是旧格式.h5里面还带自定义层。如果你装了最新版 TensorFlowKeras 3 那一支load_model十有八九直接抛错或者更糟——加载成功但层序被重排预测结果全是乱的。# 建议先建独立环境别往系统 Python 里装 python -m venv eqt-env source eqt-env/bin/activate # 先装 TensorFlow 2.xKeras 2 分支再装包本体 pip install tensorflow2.15.* pip install EQTransformer # 装完立刻验证别等跑预测时才发现 python -c import tensorflow as tf; print(tf.__version__); import EQTransformer; print(ok)版本这一行不是保守是踩过太多次。Keras 3 改了序列化格式和部分层的默认行为MultiHeadAttention的key_dim推断逻辑也变过旧权重加载后即使不报错输出分布也会偏。稳妥做法是让 TensorFlow 停在 2.x、Keras 停在 2.x并在环境里显式装tf-keras兼容包遇到ModuleNotFoundError: keras之类的提示时它是第一顺位怀疑对象。Windows 上还多一条路径里带中文或空格可能导致 h5py 读写失败把工程目录放在纯英文路径下能省掉半天排查。4.2 用预训练权重跑检测mseed_predictor 参数逐个过推理入口是mseed_predictor一行调用就能从 miniseed 目录跑到 CSV。第一次跑建议只放一两个台站、一小时的波形先确认链路通再上全量——直接用几天的连续数据跑中途因为某个台站缺分量报错前面几十分钟的计算全白费。from EQTransformer.core.mseed_predictor import mseed_predictor mseed_predictor( input_dirmseed_data, # 待检测的 miniseed 目录可递归 input_modelEqT_original_model.h5, # 预训练权重路径指向包内 model 目录 stations_jsonstations_list.json, # 台站与通道元数据缺了会读不到三分量 output_diroutput, detection_threshold0.3, # 事件检测概率阈值 P_threshold0.3, # P 拾取概率阈值 S_threshold0.3, # S 拾取概率阈值 overlap0.3, # 滑窗重叠比例边界事件的后悔药 number_of_plots10, # 只画前 N 条画太多 IO 拖慢整体 plot_modetime, # 按时间轴出图 batch_size500, # 显存不够就往下压 normalization_modestd, )参数里三个阈值是业务效果的主开关别当成一次性配置。detection_threshold调低会捡回小震但误检上升调高则目录变干净但漏震P_threshold/S_threshold影响的是拾取点是否被保留跟检测阈值是「与」的关系——三路都得过线这条拾取才会进结果表。我一般先用默认 0.3 跑一遍当基线再看误检集中在哪些台站按台站单独配阈值比全局调更有效。batch_size是显存和速度的平衡点6000×3 的窗口不算大但几百条一批的中间激活值很占显存OOM 时先降它而不是降窗口长度。stations_json是最容易漏的参数。它提供台站坐标、通道方位等元数据波形文件里虽然有台站名但分量顺序和朝向不一定可靠缺了这份元数据模型可能把 E 分量当 Z 分量喂进去检测概率会莫名整体偏低。这份文件的格式是「台站字典的列表」常见写法[ { network: XX, station: ABC, channels: [HHZ, HHN, HHE], coords: [100.0, 30.0, 500.0] } ]列表里每项对应一个台站channels的顺序要和波形里的分量顺序一致coords是经纬度和高程。批量准备这份文件时用脚本从台站目录生成别手写——台站一多漏一个通道就是一次静默的错误结果。4.3 输出目录里有什么CSV、报告、图跑完先看output/下有没有预测结果表。这张表是整个流程的交付物一条记录对应一次拾取典型列包括台站/台网标识、事件时间、事件在窗口内的索引、检测概率、P 到时与 P 概率、S 到时与 S 概率。import pandas as pd df pd.read_csv(output/X_prediction_results.csv) # 二次过滤三路概率都过线才留下相当于把「与」逻辑再收紧一档 df df[(df.detection_probability 0.3) (df.p_probability 0.3) (df.s_probability 0.3)].copy() # 时间列统一转成 datetime方便和台网目录、定位程序对齐 df[p_arrival_time] pd.to_datetime(df[p_arrival_time]) df[s_arrival_time] pd.to_datetime(df[s_arrival_time]) print(len(df), df[station].nunique())过滤这一步看着多余其实是必须的预测器内部虽然有阈值但后处理合并重叠窗口时保留的是「先到的那条」某些情况下会出现检测概率高、拾取概率略低于阈值但仍被写进表的记录。再筛一遍能保证送进关联器把多个台站的拾取拼成同一个事件的数据是干净的。时间列务必转 datetime 再参与后续计算字符串直接相减得到的是类型错误或者天知道什么东西。除 CSV 之外输出目录里通常还有一份文本报告记录处理了多少文件、跳过多少、耗时和若干张波形叠加概率曲线的图。图不要只当装饰它是排查利器概率曲线在事件位置有明显双峰P 一个、S 一个说明拾取正常如果只有一个宽峰多半是 P 和 S 挨得太近或者窗口里 S 被截断如果整段曲线都在 0.3 附近抖动那是归一化或数据质量的问题不是模型的问题。number_of_plots设成 10~20 够用设成几百会让整个流程卡在 matplotlib 上。4.4 自己训练Trainer 的参数与关键超参想换区域、换台网特性预训练权重往往不够用得自己训。入口是Trainer类调用形式是「实例化 一次 train」参数分成四类数据、结构、优化、增广。下面这份配置是能跑通的起点from EQTransformer.core.trainer import Trainer trainer Trainer() trainer.train( input_hdf5sample_train.hdf5, input_dimention(6000, 3), # 注意拼写就是 dimention别手改成 dimension cnn_blocks4, # 卷积块数改这个要同步改解码头 lstm_blocks1, batch_size64, epochs200, patience3, # 验证 loss 连续 3 轮不降就早停 learning_rate_schedulerTrue, # 余弦/阶梯衰减后期收敛更稳 augmentationTrue, # 在线增广小数据集必开 loss_weights{detector: 0.2, picker_P: 0.4, picker_S: 0.4}, train_valid_test_split[0.85, 0.05, 0.10], output_namemy_eqt, model_dirmy_model, log_dirmy_log, )input_dimention这个拼写是项目里的原样写对才能被接受这种小地方翻车过不止一次。train_valid_test_split里验证集只占 5%看着少但地震波形样本相关性很强同一事件的多个台站记录如果分散到训练和验证两侧验证 loss 会虚低——所以切分最好按事件划分而不是按样本随机划分否则你看到的「验证集准确率 0.95」是假的。增广开关在小数据集上不能省项目内置了加噪声、丢通道、随机平移、幅度缩放等策略其中随机平移把事件在窗口里左右挪对拾取任务收益最大等于零成本扩充了到时位置分布。训练过程的产物是权重文件加日志。日志里重点看三条曲线总 loss、三个分支各自的 loss、验证集指标。总 loss 平稳下降但 P 分支不降说明权重或标签有问题训练 loss 降验证 loss 升那是过拟合先减 cnn_blocks 或加 dropout别急着加数据。200 轮不是硬指标有早停的情况下大多数数据集在几十轮内就收敛了。5. 避坑与排查五个让结果整体出错的细节5.1 数据与元数据类的坑现象预测跑完 CSV 是空的或者事件数少得离谱但日志显示文件都处理成功了。原因stations_json里的台站名、通道名和 miniseed 里的实际命名对不上大小写、台网代码前缀差异预测器按元数据找不到对应通道直接跳过该文件。解决先用 obspy 读一个文件打印stats.network、stats.station、stats.channel再逐字段比对 json别靠肉眼猜。批量场景写个脚本做集合差集一次把所有不匹配的台站列出来。现象训练 loss 前几轮就变成 nan。原因hdf5 里存的是未归一化的原始 counts数值量级在 1e4 以上梯度直接爆。解决检查data数据集的数值范围正常应该在 -5~5 之间超了就回到预处理阶段补上去均值、去趋势和标准差归一化别在训练脚本里临时除一个常数糊弄过去。5.2 模型加载与运行类的坑现象load_model报未知层、或者加载成功但预测概率全在 0.5 附近。原因Keras 3 与旧.h5权重不兼容或者自定义层多头注意力、自定义损失没通过custom_objects注册。解决把 TensorFlow 固定在 2.x Keras 2.x 分支加载时显式传入项目里的自定义对象确认不了就先只加载结构文件、再load_weights两步走能定位到底是结构问题还是权重问题。现象跑长记录时内存一路涨到被系统杀掉。原因一次性把所有滑窗结果留在内存里再后处理几小时的三分量数据切出上千个窗口激活值加起来很可观。解决降batch_size把输入目录拆成按天或按台站分批跑输出 CSV 追加合并。这类批处理脚本我一般写成可断点续跑的跑一半挂了不至于从头再来。现象同一条波形跑两次拾取结果差了几十个采样点。原因增广在推理阶段没关掉或者随机种子没固定。解决推理走mseed_predictor而不是自己搭生成器确需自建流程时把增广标志位显式置 False 并固定随机种子结果不可复现的模型在生产环境里基本没法用。5.3 结果解读类的坑现象目录里事件数量是人工目录的三倍全是误检。原因检测阈值用了默认值但目标区域的背景噪声水平微震、海洋波浪、人文噪声和预训练数据差异很大模型把持续性噪声当成了事件。解决先抽十几个误检样本画图看形态如果都是同一类噪声说明是数据域差异不是阈值问题此时要么提高检测阈值并加最短事件间隔约束要么拿本地数据做微调。单纯调阈值压误检通常会把小震一起压掉。6. 二次开发换区域数据比换模型划算得多拿到这个包之后最想做的事通常是「换到我这片区域」。我的建议很明确优先微调不要从头训练。预训练权重在大规模波形上学到的低层特征P 波起跳的陡度、S 波的能量包络是通用的从头训需要的数据量和算力大概率超出个人能承受的范围。具体做法是冻结编码器、只放开三路解码头和最后一个 Transformer 块用较小的学习率1e-4 量级在本地数据上跑十几轮import tensorflow as tf # compileFalse 先拿结构随后手工编译避免旧优化器状态干扰 base tf.keras.models.load_model(EqT_original_model.h5, compileFalse) # 冻结前段编码器只放开解码头末尾十几层 for layer in base.layers[:-12]: layer.trainable False base.compile( optimizertf.keras.optimizers.Adam(1e-4), # 微调学习率比预训练小一个量级 loss{detector: binary_crossentropy, picker_P: binary_crossentropy, picker_S: binary_crossentropy}, loss_weights{detector: 0.2, picker_P: 0.4, picker_S: 0.4}, )判断微调是否有效的验证方法要说清留出至少 20 个人工标注事件做测试集且这些事件的台站不能出现在训练集里。只看训练 loss 下降没有意义多任务模型很容易在本地小数据上过拟合到「记住这几个台站」。真正该看的是拾取误差的分布——P 波残差中位数能不能压到 0.05 秒以内S 波在 0.1 秒以内以及不同震级段的检出率是否均衡。如果小震检出率明显偏低而大震正常说明微调把模型往「高信噪比偏好」上带偏了增广里的加噪声比例要往上提。另一个高性价比的改造方向是后处理和阈值策略而不是动网络。把拾取结果送进关联器之前加一层按台站自适应的阈值用该台站一段时间的历史预测概率分布取 95 分位作为动态阈值比全局固定 0.3 稳定得多。再就是合并重叠窗口时的去重规则项目默认留先到的那条我一般改成「同一事件窗内 P 概率最高的那条」实测能减少重复事件。这些都是纯 Python 逻辑改起来风险低、验证快比重新训练划算。还有一个我常被问到的点能不能加一个分量或者改成两分量输入。技术上可以但输入形状是贯穿模型定义、生成器、预测器、权重的硬约束改完预训练权重就废了只能从头训。除非你的台网真的没有三通道数据否则不值得。踩过的坑里印象最深的一次是改完预处理脚本忘了同步chunk_size训练集窗口是 6000 点、预测时按 3000 点切模型自动补齐零之后 S 波概率峰整个被拉平我盯着图看了半天怀疑是权重加载错了最后才发现是两行配置没对齐。从那以后我每次改窗口长度都强制走一遍「打印模型输入形状 → 打印 hdf5 的 data.shape → 跑一条波形看输出长度」这三步核对多花两分钟能省掉一整天。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询