TDN-IntensityGMM-TW
Machine-learning ground-motion models (GMM) for Taiwan. Given an earthquake's
magnitude, depth and epicentre, they predict PGA and PGV at any target
location, from which the CWA seismic intensity is obtained. Shipped as
self-contained ONNX files that run anywhere onnxruntime runs.
Flagship: TDN-IntensityGMM-TW-524k-v1.onnx - trained on 523,569 station
records from 1,181 Taiwan earthquakes (2020-2025), merging the P-Alert MEMS
network and the CWA strong-motion reports.
Model family
Naming: TDN-<task>-TW-[source-]<records>k-v<n>
| file | task | training data | records |
|---|---|---|---|
TDN-IntensityGMM-TW-524k-v1.onnx |
PGA/PGV regression | P-Alert + CWA (merged) | 523,569 |
TDN-IntensityGMM-TW-PAlert-479k-v1.onnx |
PGA/PGV regression | P-Alert only | 478,846 |
TDN-IntensityGMM-TW-CWA-45k-v1.onnx |
PGA/PGV regression | CWA reports only | 44,723 |
TDN-IntensityCLF-TW-524k-v1.onnx |
10-class intensity | P-Alert + CWA (merged) | 523,569 |
TDN-IntensityCLF-TW-PAlert-479k-v1.onnx |
10-class intensity | P-Alert only | 478,846 |
- IntensityGMM predicts
log10(PGA)andlog10(PGV); the ONNX graph raises them back to linear units, so it outputs PGA (gal) and PGV (cm/s). Intensity follows from the CWA threshold table below. - IntensityCLF is a direct 10-way softmax over the CWA intensity scale and returns class probabilities. Useful when you want a calibrated distribution rather than a point estimate, and it recovers rare high intensities better than binning the regression output.
Quick start
import numpy as np
import onnxruntime as ort
sess = ort.InferenceSession("TDN-IntensityGMM-TW-524k-v1.onnx")
def features(M, depth, ev_lat, ev_lon, t_lat, t_lon):
import math
p1, p2, dl = math.radians(ev_lat), math.radians(t_lat), math.radians(t_lon - ev_lon)
a = math.sin((p2 - p1) / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
dist = 2 * 6371.0 * math.asin(math.sqrt(a))
lnR = math.log(max(math.hypot(dist, depth), 3.0))
az = math.atan2(math.sin(dl) * math.cos(p2),
math.cos(p1) * math.sin(p2) - math.sin(p1) * math.cos(p2) * math.cos(dl))
return [M, depth, dist, lnR, ev_lat, ev_lon, t_lat, t_lon, math.sin(az), math.cos(az)]
x = np.array([features(6.5, 10.0, 23.9, 121.6, 24.0, 121.7)], dtype=np.float32)
pga, pgv = sess.run(None, {"features": x})
print(float(pga[0][0]), "gal", float(pgv[0][0]), "cm/s")
A ready-made wrapper and CLI live in the repository
(predict_point.py, palert/predict.py); a township-resolution ShakeMap
renderer is in shakemap.py.
Inputs and outputs
Input features: float32[N, 10]. The feature order is fixed:
| # | name | how to compute |
|---|---|---|
| 0 | M |
magnitude (ML) |
| 1 | depth |
focal depth (km) |
| 2 | dist |
epicentral distance (km), haversine |
| 3 | lnR |
ln(max(sqrt(dist^2 + depth^2), 3)) |
| 4, 5 | ev_lat, ev_lon |
epicentre |
| 6, 7 | t_lat, t_lon |
target site |
| 8, 9 | sinAz, cosAz |
azimuth, epicentre -> site |
Only dist, lnR and the azimuth depend on the target, so a whole ShakeMap is
one batched call.
Output - IntensityGMM: PGA[N,1] (gal), PGV[N,1] (cm/s).
IntensityCLF: intensity_probs[N,10].
Intensity (CWA 10-level scale) is the max of the PGA and PGV bins:
| level | 0 | 1 | 2 | 3 | 4 | 5弱 | 5強 | 6弱 | 6強 | 7 |
|---|---|---|---|---|---|---|---|---|---|---|
| PGA (gal) | 0.8 | 2.5 | 8 | 25 | 80 | 140 | 250 | 440 | 800 | - |
| PGV (cm/s) | 0.2 | 0.7 | 1.9 | 5.7 | 15 | 30 | 50 | 80 | 140 | - |
Class index i runs 0..9 in that order.
Training data
| source | network | events | station records | period |
|---|---|---|---|---|
| P-Alert | P波警報器強震網 (IES Academia Sinica / NTU), ~780 MEMS stations | 696 | 478,846 | 2024-01-19 .. 2026-10-06 |
| CWA reports | 中央氣象署 顯著有感地震報告 (free-field strong motion) | 1,088 | 44,723 | 2020-01-01 .. 2025-12-27 |
| merged | both | 1,181 groups | 523,569 | 2020-2025 |
Magnitudes 3.5-7.2, epicentral distances 0.4-570 km.
Labels. P-Alert: PGA/PGV from the public station records. CWA: per-station PGA/PGV from the published earthquake-report parameter files. Both give three components plus a combined value per station. The CWA threshold table above reproduces the intensity that the CWA itself printed in those reports for 98.5% of records, which is a useful sanity check on both the table and the parsing.
Cross-source event matching. The two catalogs describe overlapping earthquakes with different clock conventions (P-Alert is UTC, CWA reports are local time) and different id schemes. Events were matched one-to-one with tight tolerances (origin times within 60 s, epicentre within 0.2 deg, magnitude within 0.8), and the train/test split is grouped by matched event, so the two sources of a single earthquake never straddle the split. 603 cross-source pairs were matched. Looser tolerances chain aftershock sequences together and were rejected.
Training procedure
- MLP
10 -> 256 -> 256 -> 256 -> 2(SiLU), input standardisation baked into the ONNX graph, AdamW + OneCycle, 120 epochs, batch 8192. - Targets are
log10(PGA)andlog10(PGV)(roughly log-normal, so regression in log space). - Sample weights
1/sqrt(stations_per_event)so large events do not dominate. - Event-grouped split, 85% / 15%.
- Classifier: same trunk, 10-way softmax, class weights
1/sqrt(count).
Evaluation
Event-grouped held-out splits. The splits are not identical across rows (different datasets, different held-out event counts), so compare within a dataset, not across the first two rows:
| dataset | model | held-out | PGA R^2 | PGV R^2 | intensity exact | within +-1 |
|---|---|---|---|---|---|---|
| P-Alert | IntensityGMM | 104 ev / 71,410 rec | 0.777 | 0.741 | 0.756 | 0.985 |
| P-Alert | IntensityCLF | 104 ev / 71,410 rec | - | - | 0.743 | 0.984 |
| CWA | IntensityGMM | 163 ev / 6,419 rec | 0.698 | 0.723 | 0.705 | 0.988 |
| merged | IntensityGMM | 177 ev / 82,282 rec | 0.782 | 0.739 | 0.766 | 0.984 |
| merged | IntensityCLF | 177 ev / 82,282 rec | - | - | 0.761 | 0.984 |
R^2 is on log10; intensity exact is the share of records whose binned
intensity matches the reference exactly.
Per-class recall (P-Alert split), showing why the classifier exists:
| level | n | IntensityGMM | IntensityCLF | reference GMM |
|---|---|---|---|---|
| 0 | 43,451 | 0.879 | 0.862 | 0.797 |
| 1 | 16,123 | 0.631 | 0.589 | 0.758 |
| 2 | 8,129 | 0.501 | 0.561 | 0.369 |
| 3 | 2,850 | 0.436 | 0.413 | 0.329 |
| 4 | 721 | 0.388 | 0.477 | 0.359 |
| 5弱 | 95 | 0.189 | 0.168 | 0.189 |
| 5強 | 26 | 0.231 | 0.000 | 0.038 |
| 6弱 | 13 | 0.077 | 0.769 | 0.000 |
Comparison with YuYu1015/YuYu1015-IntensityGMM-TW-45k-v1
Evaluated on the same P-Alert held-out split, with the identical feature definition:
| model | PGA R^2 | PGV R^2 | intensity exact | within +-1 |
|---|---|---|---|---|
TDN-IntensityGMM-TW-PAlert-479k-v1 |
0.777 | 0.741 | 0.756 | 0.985 |
YuYu1015-IntensityGMM-TW-45k-v1 |
0.703 | 0.576 | 0.715 | 0.985 |
The reference's own train/test split is unknown, so treat this as a sanity check
rather than a rigorous benchmark. Notably its "45k" matches the size of the CWA report
corpus (44,723 records), so it was likely trained on the same CWA reports; our
-CWA-45k- variant is the direct counterpart at that data scale, and the merged
variant is what you get by scaling up ~12x.
Limitations
- Intensity is binned, not modelled. The GMM predicts continuous PGA/PGV; the intensity label follows from fixed thresholds, so accuracy near a threshold flips on tiny changes. The classifier avoids this but is less accurate overall.
- High intensities are rare. Levels 5弱 and above are 0.02% of the data, so tail accuracy is limited by data volume, not model capacity.
- CWA reports only list felt stations (intensity >= 1), so the CWA-only variant never sees weak motion and its PGA/PGV range is compressed.
- Site effects are not modelled. There is no Vs30, topography, basin or station-response term. Two stations at the same distance can differ by a factor of several; the model predicts the conditional mean.
- Instrument differences. CWA free-field strong-motion sensors record higher acceleration than P-Alert MEMS sensors at the same site, so the merged model runs a little hot compared with the P-Alert-only model.
- Taiwan only. Extrapolation to other regions, or to magnitudes above ~7.2, is untested.
- Not for life-safety or alerting decisions.
Repository
TDN-IntensityGMM-TW-524k-v1.onnx flagship regression model
TDN-IntensityGMM-TW-PAlert-479k-v1.onnx P-Alert-only variant
TDN-IntensityGMM-TW-CWA-45k-v1.onnx CWA-only variant
TDN-IntensityCLF-TW-524k-v1.onnx flagship classifier
TDN-IntensityCLF-TW-PAlert-479k-v1.onnx P-Alert-only classifier
README.md this model card
LICENSE Apache-2.0
.gitattributes .gitignore LFS rules, excludes regenerated data
shakemap.png example ShakeMap, merged flagship model
shakemap_palert.png same event, P-Alert-only model
checkpoints/ PyTorch checkpoints + metrics JSON
data/ township centres + township boundaries for shakemap.py
(county outlines for use_model.py's grid demo are not
shipped; shakemap.py and use_model.py both degrade
gracefully without them, or fetch them per the pipeline)
palert/ inference + feature + training helpers
predict_point.py self-contained single-point CLI
shakemap.py township ShakeMap renderer
use_model.py demo: single site, station ranking, ShakeMap
fetch_all.py fetch_cwa.py fetch_cwa_scweb.py data download
merge_datasets.py merge P-Alert + CWA, event-matched
train.py train_intensity.py training
export_onnx.py export_intensity_onnx.py ONNX export
evaluate_onnx.py compare.py evaluation
The training datasets are not shipped - they are several hundred MB and
subject to the source terms above. Rebuild them with the fetch scripts, or use
the ONNX files directly; only shakemap.py --from-event needs the dataset, and
--M/--depth/--ev-lat/--ev-lon covers the same ground without it.
pip install -r requirements.txt
python predict_point.py --M 6.5 --depth 10 --ev-lat 23.9 --ev-lon 121.6 \
--t-lat 24.0 --t-lon 121.7
python shakemap.py --M 7.1 --depth 19.7 --ev-lat 23.88 --ev-lon 121.57
Citation
Please cite the source datasets, which are what make these models possible.
Central Weather Administration (CWA)
以中央氣象署(CWA)強震觀測資料(2020–2025)訓練;震度門檻依 CWA 2020 十級制。
Central Weather Administration (CWA, Taiwan). (2012). Central Weather Administration Seismographic Network [Data set]. International Federation of Digital Seismograph Networks. https://doi.org/10.7914/SN/T5
P-Alert Strong Motion Network
梁文宗、邱昊德、李文蕙、古進上、楊民、吳逸民(2023)。2023年版P波警報器強震網的網路資料服務平台。台灣地震科學中心簡訊,第40期,0004。 doi: 10.30067/TECNL.202306_(40).0004
Liang, W.-T., Qiu, H.-D., Li, W.-H., Ku, C.-S., Yang, M., & Wu, Y.-M. (2023). The 2023 version of the P-Alert (P-wave alarm) Strong Motion Network online data service platform. TEC Newsletter, No. 40, 0004. https://doi.org/10.30067/TECNL.202306_(40).0004
The network itself is described in:
Wu, Y.-M., Chen, D.-Y., Lin, T.-L., Hsieh, C.-Y., Chin, T.-L., Chang, W.-Y., Li, W.-S., & Ker, S.-H. (2013). A High-Density Seismic Network for Earthquake Early Warning in Taiwan Based on Low Cost Sensors. Seismological Research Letters, 84(6), 1048-1054. https://doi.org/10.1785/0220130085
Note the DOI contains an underscore: TECNL.202306_(40).0004. It is sometimes
reproduced without it, in which case it does not resolve.
Station coordinates included at data/raw/stations.json (787 stations) come from
the same network's public station list, accessed through the platform described in
the reference above.
Map data
shakemap.py needs township geometry; it is included so the renderer works out of
the box. These files are map data, not training data - the models were not
trained on them.
Township boundaries - data/twtown.geojson, the twtown2010.4 file (0.0001
degree simplification) from ronnywang/twgeojson.
That project built it from the Taiwan Ministry of the Interior's Socio-Economic
Geographic Information System (內政部國土資訊系統社會經濟資料庫共通平台, SEGIS),
2012 vintage / post-五都升格, and republished it as GeoJSON for the g0v community.
The upstream repository states its source but declares no explicit licence, so the terms of the original MOI/SEGIS data govern. Verify those terms before redistributing the geometry; for the model artifacts themselves nothing depends on it beyond drawing the figure.
Note the 2010 vintage: that file still says 桃園縣 and uses 市/鎮/鄉 where the
2020s say 桃園市/區. shakemap.py reconciles the naming at draw time (see its
module docstring for the full list of differences).
Township centres - data/tw_town_centers.json: 371 township / city-district
centres with postal codes, from the public gist
memochou1993/aa9b6b1185221f88a03109f10d32e5e2.
Data-use statement
中文:
本研究之模型訓練與驗證資料,係採用由中央研究院與國立臺灣大學合作建置之 P-Alert 強震觀測網(梁文宗等,2023)開放資料庫。研究中自其提供之測站紀錄 提取各測站之最大地動加速度(PGA)與最大地動速度(PGV)作為迴歸標的,並以 地震規模、震源深度、震央座標與測站座標推得之震央距與方位角作為輸入特徵, 投入機器學習地震動模型(Ground Motion Model)進行 PGA 與 PGV 之預測,再依 中央氣象署震度分級表轉換為震度;另將中央氣象署顯著有感地震報告之各測站 PGA、PGV 與震度(2020–2025)併入同一訓練集。
English:
Training and validation data come from the open database of the P-Alert Strong Motion Network (Liang et al., 2023), jointly built by Academia Sinica and National Taiwan University. Per-station peak ground acceleration (PGA) and peak ground velocity (PGV) were taken as the regression targets, and event magnitude, focal depth, epicentral coordinates and site coordinates were reduced to epicentral distance and azimuth as input features, feeding a machine-learning Ground Motion Model; the CWA intensity scale is then applied. Per-station PGA, PGV and intensity from CWA significant-earthquake reports (2020-2025) were merged into the same training set.
Terminology note
"GMM" in this repository means Ground Motion Model, the engineering seismology term for a model predicting ground-motion intensity measures from source, path and site parameters. It is a neural network (MLP) here, not a Gaussian Mixture Model, which shares the same abbreviation in machine learning. Please keep the two apart when citing this work.
This model also does not process waveforms. P-Alert data were read through the network's public per-station PGA/PGV records, not extracted from SAC-format acceleration files, and no P-wave features (such as Pd or tau_c) are used.
This model
TDN Studio · walbcglgh1113 (2026). TDN-IntensityGMM-TW [Model]. https://huggingface.co/walbcglgh/TDN-IntensityGMM-TW
The repository TDN-Intensity-v1 hosts the model family whose artifacts are named
TDN-IntensityGMM-TW-* (PGA/PGV regression) and TDN-IntensityCLF-TW-* (direct
intensity classification). When you cite it, please also cite the data references
above, and name the variant and version you used, for example
TDN-IntensityGMM-TW-524k-v1.
License
Code and model weights are released under Apache-2.0. The training data is not redistributed here and remains subject to its source terms; cite the data providers as above.