pirelli1453 commited on
Commit
16a677c
·
verified ·
1 Parent(s): a9f844b

Upload 4 files

Browse files
Files changed (4) hide show
  1. README.md +19 -8
  2. app.py +262 -0
  3. model_output4/rf_model.pkl +3 -0
  4. requirements.txt +7 -0
README.md CHANGED
@@ -1,14 +1,25 @@
1
  ---
2
- title: RaspShakeRandomForest
3
- emoji: 🦀
4
- colorFrom: gray
5
- colorTo: pink
6
  sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
11
- short_description: raspberyshake sistemi deprem sınıflandırıcı
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Sismik Siniflandirma
3
+ emoji: 🌍
4
+ colorFrom: red
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 4.44.0
 
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
+ # Sismik Sinyal Sınıflandırma
13
+
14
+ Marmara bölgesi RaspberryShake istasyonlarından (RF9F7, R772A, R6080) toplanan
15
+ verilerle eğitilmiş bir RandomForest modeli. MSEED dosyası yükleyin,
16
+ DEPREM veya NOISE olarak sınıflandırsın.
17
+
18
+ ## Özellikler
19
+ - 16 sismik özellik (STA/LTA, spektral oranlar, kurtosis, envelope şekli vb.)
20
+ - Amplitüd-bağımsız özellikler kullanır (farklı istasyon sensör kazançlarından etkilenmez)
21
+ - Ayarlanabilir karar eşiği
22
+
23
+ ## Kısıtlar
24
+ - Şu an sınırlı veriyle eğitildi (~126 segment), gelişim aşamasında
25
+ - Sadece Marmara bölgesi RaspberryShake verisiyle test edildi
app.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Sismik Sınıflandırma - HuggingFace Space (Gradio)
4
+ ===================================================
5
+ RandomForest modeliyle MSEED dosyalarını DEPREM / NOISE olarak sınıflandırır.
6
+
7
+ HF Spaces kurulumu:
8
+ 1. huggingface.co/new-space -> SDK: Gradio, Hardware: CPU basic (ücretsiz)
9
+ 2. Bu dosyayı app.py olarak yükle
10
+ 3. requirements.txt'i yükle
11
+ 4. rf_model.pkl dosyasını da Space'e yükle (aynı dizine)
12
+ """
13
+
14
+ import os
15
+ import json
16
+ import tempfile
17
+ import warnings
18
+ warnings.filterwarnings("ignore")
19
+
20
+ import numpy as np
21
+ import joblib
22
+ import gradio as gr
23
+ from obspy import read
24
+ from obspy.signal.trigger import classic_sta_lta, trigger_onset
25
+ from obspy.signal.filter import envelope as obspy_envelope
26
+ from scipy import signal as scipy_signal
27
+ from scipy.stats import kurtosis, skew
28
+
29
+ import matplotlib
30
+ matplotlib.use("Agg")
31
+ import matplotlib.pyplot as plt
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Özellik çıkarımı — train_rf2.py ile BİREBİR AYNI
35
+ # ---------------------------------------------------------------------------
36
+ BANDPASS = (0.5, 15.0)
37
+ STA_S = 2.0
38
+ LTA_S = 20.0
39
+ MIN_NPTS = 200
40
+ MODEL_PATH = "rf_model.pkl"
41
+
42
+
43
+ def extract_features(tr) -> dict:
44
+ data = tr.data.astype(np.float64)
45
+ n = len(data)
46
+ df = tr.stats.sampling_rate
47
+ if n < MIN_NPTS:
48
+ return None
49
+
50
+ data -= np.mean(data)
51
+ sos = scipy_signal.butter(4, BANDPASS, btype="bandpass", fs=df, output="sos")
52
+ fdata = scipy_signal.sosfiltfilt(sos, data)
53
+
54
+ rms = np.sqrt(np.mean(fdata**2))
55
+ if rms < 1e-10:
56
+ return None
57
+
58
+ max_amp = np.max(np.abs(fdata))
59
+ peak_rms = max_amp / rms
60
+ zcr = ((fdata[:-1] * fdata[1:]) < 0).sum() / n
61
+
62
+ env = obspy_envelope(fdata)
63
+ env_smooth = scipy_signal.savgol_filter(env, min(51, n // 4 * 2 + 1), 3)
64
+ env_smoothness = np.std(np.diff(env_smooth)) / (np.mean(env_smooth) + 1e-10)
65
+
66
+ cum_e = np.cumsum(env ** 2)
67
+ idx90 = np.searchsorted(cum_e, 0.9 * cum_e[-1])
68
+ dur90 = idx90 / df
69
+
70
+ kurt_val = kurtosis(fdata)
71
+ skew_val = skew(fdata)
72
+
73
+ try:
74
+ cft = classic_sta_lta(fdata, int(STA_S * df), int(LTA_S * df))
75
+ sta_lta_max = np.max(cft)
76
+ sta_lta_mean = np.mean(cft)
77
+ triggers = trigger_onset(cft, 4.0, 1.5)
78
+ num_triggers = len(triggers)
79
+ except Exception:
80
+ cft = np.zeros_like(fdata)
81
+ sta_lta_max, sta_lta_mean, num_triggers = 0.0, 0.0, 0
82
+
83
+ nperseg = min(256, n // 2)
84
+ freqs, psd = scipy_signal.welch(fdata, df, nperseg=nperseg)
85
+ total_power = np.sum(psd) + 1e-30
86
+
87
+ def band_ratio(f_low, f_high):
88
+ mask = (freqs >= f_low) & (freqs < f_high)
89
+ return np.sum(psd[mask]) / total_power
90
+
91
+ low_ratio = band_ratio(0.5, 2.0)
92
+ mid1_ratio = band_ratio(2.0, 5.0)
93
+ mid2_ratio = band_ratio(5.0, 10.0)
94
+ high_ratio = band_ratio(10.0, 25.0)
95
+
96
+ dom_freq_idx = np.argmax(psd[freqs <= 25])
97
+ dom_freq = freqs[dom_freq_idx]
98
+
99
+ psd_norm = psd / total_power
100
+ spec_entropy = -np.sum(psd_norm * np.log(psd_norm + 1e-30))
101
+ spec_mean_freq = np.sum(freqs * psd_norm)
102
+ spec_bandwidth = np.sqrt(np.sum(((freqs - spec_mean_freq) ** 2) * psd_norm))
103
+
104
+ is_rf9f7 = 1 if "RF9F7" in (tr.stats.station or "").upper() else 0
105
+
106
+ feats = {
107
+ "peak_rms": peak_rms,
108
+ "zcr": zcr,
109
+ "kurt": kurt_val,
110
+ "skewness": skew_val,
111
+ "env_smoothness": env_smoothness,
112
+ "dur90_s": dur90,
113
+ "sta_lta_max": sta_lta_max,
114
+ "sta_lta_mean": sta_lta_mean,
115
+ "num_triggers": num_triggers,
116
+ "dom_freq": dom_freq,
117
+ "low_ratio": low_ratio,
118
+ "mid1_ratio": mid1_ratio,
119
+ "mid2_ratio": mid2_ratio,
120
+ "high_ratio": high_ratio,
121
+ "spec_entropy": spec_entropy,
122
+ "spec_bandwidth": spec_bandwidth,
123
+ "is_rf9f7": is_rf9f7,
124
+ }
125
+ # Grafik için ek veriler (feature dict'ine karışmaması için ayrı döndürülür)
126
+ return feats, fdata, cft, df
127
+
128
+
129
+ # ---------------------------------------------------------------------------
130
+ # Model yükleme (bir kere, global)
131
+ # ---------------------------------------------------------------------------
132
+ _bundle = None
133
+
134
+ def get_model():
135
+ global _bundle
136
+ if _bundle is None:
137
+ _bundle = joblib.load(MODEL_PATH)
138
+ return _bundle
139
+
140
+
141
+ def make_plot(fdata, cft, df, label, deprem_proba):
142
+ t = np.arange(len(fdata)) / df
143
+ fig, axes = plt.subplots(2, 1, figsize=(9, 5), sharex=True)
144
+
145
+ color = "#d64545" if label == "DEPREM" else "#3b6fd6"
146
+ axes[0].plot(t, fdata, color=color, linewidth=0.6)
147
+ axes[0].set_ylabel("Genlik (filtrelenmiş)")
148
+ axes[0].set_title(f"Tahmin: {label} (DEPREM olasılığı: %{deprem_proba*100:.1f})")
149
+
150
+ axes[1].plot(t, cft, color="purple", linewidth=0.8)
151
+ axes[1].axhline(4.0, color="black", linestyle=":", linewidth=1, label="Tetik eşiği")
152
+ axes[1].set_ylabel("STA/LTA")
153
+ axes[1].set_xlabel("Zaman (s)")
154
+ axes[1].legend(loc="upper right", fontsize=8)
155
+
156
+ plt.tight_layout()
157
+ return fig
158
+
159
+
160
+ def predict_mseed(file_obj, threshold):
161
+ if file_obj is None:
162
+ return "Lütfen bir MSEED dosyası yükleyin.", None, None
163
+
164
+ try:
165
+ st = read(file_obj.name)
166
+ except Exception as e:
167
+ return f"Dosya okunamadı: {e}", None, None
168
+
169
+ tr = None
170
+ for cha in ["EHZ", "HHZ", "BHZ", "EHN"]:
171
+ sel = st.select(channel=cha)
172
+ if len(sel) > 0:
173
+ tr = sel[0]
174
+ break
175
+ if tr is None:
176
+ tr = st[0]
177
+
178
+ result = extract_features(tr)
179
+ if result is None:
180
+ return f"Özellik çıkarılamadı (dosya çok kısa, min {MIN_NPTS} örnek gerekli).", None, None
181
+
182
+ feats, fdata, cft, df = result
183
+
184
+ bundle = get_model()
185
+ model, le, feature_cols = bundle["model"], bundle["le"], bundle["meta"]["feature_cols"]
186
+
187
+ X = np.array([[feats.get(c, 0.0) for c in feature_cols]])
188
+ X = np.where(~np.isfinite(X), 0.0, X)
189
+ proba = model.predict_proba(X)[0]
190
+
191
+ deprem_idx = list(le.classes_).index("DEPREM")
192
+ deprem_p = float(proba[deprem_idx])
193
+ label = "DEPREM" if deprem_p >= threshold else "NOISE"
194
+
195
+ emoji = "🔴 DEPREM" if label == "DEPREM" else "🔵 NOISE"
196
+ summary = (
197
+ f"## {emoji}\n\n"
198
+ f"**DEPREM olasılığı:** %{deprem_p*100:.1f}\n\n"
199
+ f"**NOISE olasılığı:** %{(1-deprem_p)*100:.1f}\n\n"
200
+ f"**Kanal:** {tr.stats.network}.{tr.stats.station}.{tr.stats.location}.{tr.stats.channel}\n\n"
201
+ f"**Başlangıç:** {tr.stats.starttime}\n\n"
202
+ f"**Süre:** {tr.stats.npts/tr.stats.sampling_rate:.1f} sn"
203
+ )
204
+
205
+ feat_table = "| Özellik | Değer |\n|---|---|\n"
206
+ for k, v in feats.items():
207
+ feat_table += f"| {k} | {v:.4f} |\n"
208
+
209
+ fig = make_plot(fdata, cft, df, label, deprem_p)
210
+
211
+ return summary, feat_table, fig
212
+
213
+
214
+ # ---------------------------------------------------------------------------
215
+ # Gradio arayüzü
216
+ # ---------------------------------------------------------------------------
217
+
218
+ with gr.Blocks(title="Sismik Sınıflandırma") as demo:
219
+ gr.Markdown(
220
+ "# 🌍 Sismik Sinyal Sınıflandırma (Marmara / RaspberryShake)\n"
221
+ "MSEED dosyası yükleyin, RandomForest modeli DEPREM veya NOISE olarak sınıflandırsın.\n\n"
222
+ "*Not: Model şu an sınırlı (Marmara bölgesi, RaspberryShake istasyonları) veriyle eğitildi, "
223
+ "gelişim aşamasındadır.*"
224
+ )
225
+
226
+ with gr.Row():
227
+ with gr.Column(scale=1):
228
+ file_input = gr.File(label="MSEED Dosyası (.mseed)", file_types=[".mseed", ".miniseed", ".seed"])
229
+ threshold_slider = gr.Slider(
230
+ minimum=0.1, maximum=0.9, value=0.5, step=0.05,
231
+ label="DEPREM karar eşiği",
232
+ info="Düşürürsen daha hassas (recall↑), yükseltirsen daha seçici (precision↑)"
233
+ )
234
+ submit_btn = gr.Button("Analiz Et", variant="primary")
235
+
236
+ with gr.Column(scale=1):
237
+ result_md = gr.Markdown(label="Sonuç")
238
+
239
+ with gr.Row():
240
+ plot_output = gr.Plot(label="Dalga Formu + STA/LTA")
241
+
242
+ with gr.Accordion("Detaylı özellik değerleri", open=False):
243
+ feat_output = gr.Markdown()
244
+
245
+ submit_btn.click(
246
+ fn=predict_mseed,
247
+ inputs=[file_input, threshold_slider],
248
+ outputs=[result_md, feat_output, plot_output],
249
+ )
250
+
251
+ gr.Markdown(
252
+ "---\n"
253
+ "**API kullanımı:** Bu Space'e programatik erişim için `gradio_client` kütüphanesini kullanabilirsiniz:\n"
254
+ "```python\n"
255
+ "from gradio_client import Client, file\n"
256
+ "client = Client(\"KULLANICI_ADI/SPACE_ADI\")\n"
257
+ "result = client.predict(file(\"ornek.mseed\"), 0.5, api_name=\"/predict\")\n"
258
+ "```"
259
+ )
260
+
261
+ if __name__ == "__main__":
262
+ demo.launch()
model_output4/rf_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6bfd4d1ffa2488e81175dff19c68e094ce1bf71407008f486114b9f91459cda5
3
+ size 521865
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ obspy>=1.4.0
3
+ scikit-learn>=1.3.0
4
+ numpy>=1.24.0
5
+ scipy>=1.10.0
6
+ matplotlib>=3.7.0
7
+ joblib>=1.3.0