Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit 57a9994

Browse files
Merge pull request #722 from emthompson-usgs/clipnn
Add ANN clipping code and test
2 parents d3c99f3 + bc33cde commit 57a9994

16 files changed

Lines changed: 453 additions & 145 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
4.761942028999328613e-01
2+
0.000000000000000000e+00
3+
-1.225080061703920364e-02
4+
-1.355059593915939331e-01
5+
-1.208401098847389221e-01
6+
-7.738453336060047150e-03
7+
4.859382510185241699e-01
8+
4.901650547981262207e-01
9+
-2.172667719423770905e-02
10+
4.954338967800140381e-01
11+
-1.108687669038772583e-01
12+
2.171477675437927246e-01
13+
0.000000000000000000e+00
14+
-2.487021684646606445e-02
15+
-1.521449834108352661e-01
16+
-1.403292119503021240e-01
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-2.244666516780853271e-01
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
5, 16,'relu',1, 'sigmoid'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
3.450458645820617676e-01,-7.405894994735717773e-02,-1.254874318838119507e-01,6.901898235082626343e-02,6.200880929827690125e-02,-5.206618085503578186e-02,3.653981387615203857e-01,3.055597841739654541e-01,-1.107454746961593628e-01,3.208941221237182617e-01,2.763029001653194427e-02,1.331859640777111053e-02,-6.405838578939437866e-02,-6.867430359125137329e-02,3.231020644307136536e-02,2.827584557235240936e-02
2+
3.734845221042633057e-01,2.110916376113891602e-02,-8.760424703359603882e-02,2.904709428548812866e-02,2.542885206639766693e-02,1.748742721974849701e-02,3.287482857704162598e-01,3.899096846580505371e-01,1.059170365333557129e-01,3.266265094280242920e-01,-2.623116225004196167e-02,-7.134835422039031982e-02,-3.654503822326660156e-02,5.247752740979194641e-02,-1.276246458292007446e-01,-8.618847280740737915e-02
3+
-2.637018561363220215e-01,9.931030683219432831e-03,7.612888514995574951e-02,4.233799874782562256e-01,3.749962747097015381e-01,-3.536137193441390991e-02,-2.761034965515136719e-01,-2.436323314905166626e-01,-4.983592405915260315e-02,-2.751033008098602295e-01,3.659239709377288818e-01,-4.732813537120819092e-01,-3.619530797004699707e-02,2.397446148097515106e-02,4.228172004222869873e-01,3.860528171062469482e-01
4+
-6.323192119598388672e-01,4.159574955701828003e-02,-5.320734810084104538e-03,6.299901008605957031e-01,6.613637804985046387e-01,-6.171951442956924438e-02,-6.351884603500366211e-01,-6.061330437660217285e-01,1.258744485676288605e-02,-5.780773162841796875e-01,6.167728900909423828e-01,-4.708586633205413818e-01,2.903726417571306229e-03,3.173625096678733826e-02,6.945689320564270020e-01,6.336471438407897949e-01
5+
-7.286261767148971558e-02,-1.223115250468254089e-02,5.675805732607841492e-02,3.030084669589996338e-01,2.992148697376251221e-01,3.216066956520080566e-02,-1.026946008205413818e-01,-3.335395455360412598e-02,2.125462144613265991e-02,-9.568803012371063232e-02,2.686659991741180420e-01,3.815599381923675537e-01,3.298680111765861511e-02,1.124517992138862610e-02,2.315190583467483521e-01,2.518956959247589111e-01
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-5.802513360977172852e-01
2+
-4.969757422804832458e-02
3+
-1.531651243567466736e-02
4+
5.004003047943115234e-01
5+
5.555523037910461426e-01
6+
1.285628415644168854e-02
7+
-4.915536046028137207e-01
8+
-5.825893878936767578e-01
9+
5.253348499536514282e-02
10+
-5.880233645439147949e-01
11+
5.758425593376159668e-01
12+
-6.398365497589111328e-01
13+
8.936516940593719482e-03
14+
-5.767295602709054947e-03
15+
5.209476947784423828e-01
16+
5.556588172912597656e-01

gmprocess/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.1.9.dev7+g4d21e34.d20210915"
1+
__version__ = "1.1.9.dev20+gd3c99f3.d20210920"

gmprocess/waveform_processing/clipping/clip_detection.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
14
class ClipDetection():
25
'''
36
Parent class for clipping detection algorithms.
@@ -18,6 +21,7 @@ class ClipDetection():
1821
_get_results():
1922
Iterates through and runs _detect() on each trace in the stream.
2023
'''
24+
2125
def __init__(self, st, test_all=False):
2226
'''
2327
Constructs all neccessary attributes for the ClipDetection method
@@ -32,7 +36,7 @@ def __init__(self, st, test_all=False):
3236
self.st = st.copy()
3337
self.is_clipped = False
3438
self.test_all = test_all
35-
39+
3640
def _clean_trace(self, tr):
3741
'''
3842
Helper function to clean the trace
@@ -86,4 +90,4 @@ def _get_results(self):
8690
if self.test_all:
8791
continue
8892
else:
89-
break
93+
break
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""Module for implementing the Artificial Neural Net model for clipping, as
5+
developed by Kleckner et al. This code is based on Xavier Bellagamba's python
6+
NN implementation of "A neural network for automated quality screening of
7+
ground motion records from small magnitude earthquakes"
8+
DOI: 10.1193/122118EQS292M
9+
"""
10+
11+
import csv
12+
import numpy as np
13+
import pkg_resources
14+
import os
15+
16+
# Path to model data
17+
NN_PATH = os.path.join('data', 'nn_clipping')
18+
NN_PATH = pkg_resources.resource_filename('gmprocess', NN_PATH)
19+
20+
21+
class clipNet():
22+
'''
23+
Class allowing the instantiation and use of simple (1 or 2 layers)
24+
neural networks
25+
'''
26+
27+
def __init__(self):
28+
'''
29+
Instantiate an empty neural network (no weights, functions, or
30+
biases loaded
31+
'''
32+
self.n_input = 0
33+
self.n_neuron_H1 = 0
34+
self.n_neuron_H2 = -1
35+
self.n_output = 0
36+
self.activation_H1 = 'NA'
37+
self.activation_H2 = 'NA'
38+
self.activation_output = 'NA'
39+
self.w_H1 = []
40+
self.w_H2 = []
41+
self.b_H1 = []
42+
self.b_H2 = []
43+
self.w_output = []
44+
self.b_output = []
45+
46+
data_path = os.path.join(NN_PATH, 'masterF.txt')
47+
with open(data_path) as masterF:
48+
readCSV = csv.reader(masterF)
49+
for row in readCSV:
50+
if len(row) == 7:
51+
self.n_input = int(row[0])
52+
self.n_neuron_H1 = int(row[1])
53+
# self.n_neuron_H2 = int(row[3])
54+
self.n_output = int(row[5])
55+
self.activation_H1 = row[2]
56+
# self.activation_H2 = row[4]
57+
self.activation_output = row[6]
58+
elif len(row) == 5:
59+
self.n_input = int(row[0])
60+
self.n_neuron_H1 = int(row[1])
61+
self.n_output = int(row[3])
62+
self.activation_H1 = row[2]
63+
self.activation_output = row[4]
64+
65+
masterF.close()
66+
67+
# Load weights and biases
68+
# Weights first hidden layer
69+
data_path = os.path.join(NN_PATH, 'weight_1.csv')
70+
self.w_H1 = np.asarray(loadCSV(data_path))
71+
72+
# Biases first hidden layer
73+
data_path = os.path.join(NN_PATH, 'bias_1.csv')
74+
self.b_H1 = np.asarray(loadCSV(data_path))
75+
76+
# Weights output layer
77+
data_path = os.path.join(NN_PATH, 'weight_output.csv')
78+
self.w_output = np.asarray(loadCSV(data_path))
79+
80+
# Biases output layer
81+
data_path = os.path.join(NN_PATH, 'bias_output.csv')
82+
self.b_output = np.asarray(loadCSV(data_path))
83+
84+
# Second hidden layer
85+
if self.n_neuron_H2 != -1:
86+
# Weights second hidden layer
87+
data_path = os.path.join(NN_PATH, 'weight_2.csv')
88+
self.w_H2 = np.asarray(loadCSV(data_path))
89+
90+
# Biases second hidden layer
91+
data_path = os.path.join(NN_PATH, 'bias_2.csv')
92+
self.b_H2 = np.asarray(loadCSV(data_path))
93+
94+
def evaluate(self, v_input):
95+
'''
96+
Use a populated neural network (i.e. from the input, returns the
97+
classification score or the regression result).
98+
99+
Args:
100+
v_input (list or np.array):
101+
Values to correspond to the following paramters: mag, dist, 6M
102+
amplitude check, histogram check, ping check.
103+
104+
Returns:
105+
np.array: numpy array containing the results.
106+
'''
107+
# Transform input if required
108+
if isinstance(v_input, list):
109+
v_input = np.asarray(v_input)
110+
111+
t1 = np.array([8.8, 445.8965938, 1., 1., 1.])
112+
t2 = np.array([4, 0.68681514, 0., 0., 0.])
113+
t3 = np.array([0., 0., 0., 0., 0.])
114+
v_input = 2.0 / (t1 - t2) * (v_input - t3)
115+
116+
v_inter = np.array([])
117+
118+
# First layer
119+
if self.activation_H1 == 'sigmoid':
120+
v_inter = sigmoid(np.dot(v_input.T, self.w_H1) + self.b_H1)
121+
elif self.activation_H1 == 'tanh':
122+
v_inter = tanh(np.dot(v_input.T, self.w_H1) + self.b_H1)
123+
elif self.activation_H1 == 'relu':
124+
v_inter = relu(np.dot(v_input.T, self.w_H1) + self.b_H1)
125+
else:
126+
v_inter = relu(np.dot(v_input.T, self.w_H1) + self.b_H1.T)
127+
128+
# If second layer exist
129+
if self.n_neuron_H2 != -1:
130+
if self.activation_H2 == 'sigmoid':
131+
v_inter = sigmoid(np.dot(v_inter, self.w_H2) + self.b_H2)
132+
elif self.activation_H2 == 'tanh':
133+
v_inter = tanh(np.dot(v_inter, self.w_H2) + self.b_H2)
134+
else:
135+
v_inter = np.dot(v_inter, self.w_H2) + self.b_H2
136+
137+
# Final layer
138+
if self.activation_output == 'sigmoid':
139+
v_inter = sigmoid(np.dot(v_inter, self.w_output) + self.b_output)
140+
elif self.activation_output == 'tanh':
141+
v_inter = tanh(np.dot(v_inter, self.w_output) + self.b_output)
142+
else:
143+
v_inter = sigmoid(np.dot(v_inter, self.w_output) + self.b_output)
144+
145+
return v_inter
146+
147+
148+
def loadCSV(data_path, row_ignore=0, col_ignore=0):
149+
'''
150+
Load csv files from a given path and returns a list of list.
151+
For all imported data, check if is a number. If so, returns a
152+
float. If not, returns a string.
153+
154+
Args:
155+
data_path (string):
156+
path to the csv to load.
157+
row_ignore (int):
158+
number of rows to ignore.
159+
col_ignore (int):
160+
number of columns to ignore.
161+
162+
Returns:
163+
list of list: containing the data from the csv
164+
'''
165+
166+
M = []
167+
with open(data_path) as csvfile:
168+
readCSV = csv.reader(csvfile)
169+
170+
# Skip header
171+
for i in range(row_ignore):
172+
next(csvfile)
173+
174+
for row in readCSV:
175+
# Input vector
176+
single_line = []
177+
for i in range(col_ignore, len(row)):
178+
if isNumber(row[i]):
179+
single_line.append(float(row[i]))
180+
else:
181+
single_line.append(row[i])
182+
M.append(single_line)
183+
184+
return M
185+
186+
187+
def sigmoid(v_input):
188+
'''
189+
Performs a sigmoid operation on the input (1/(e(-x)+1))
190+
191+
Args:
192+
v_input (float):
193+
a number defined on R (real).
194+
195+
Returns:
196+
float: sigmoid result (a number between 0 and 1).
197+
'''
198+
v_act = []
199+
for x in v_input:
200+
v_act.append(1. / (1 + np.exp(-x)))
201+
return v_act
202+
203+
204+
def tanh(v_input):
205+
'''
206+
Performs a hyperbolic tangent operation on the input (2/(e(2x)+1))
207+
208+
Args:
209+
v_input (float):
210+
a number defined on R (real).
211+
212+
Returns:
213+
float: tanh result (a number between -1 and 1).
214+
'''
215+
v_act = []
216+
for x in v_input:
217+
v_act.append(np.tanh(x))
218+
return v_act
219+
220+
221+
def relu(v_input):
222+
'''
223+
Performs a hyperbolic tangent operation on the input (2/(e(2x)+1))
224+
225+
Args:
226+
v_input (float):
227+
a number defined on R (real).
228+
229+
Returns:
230+
float: tanh result (a number between -1 and 1).
231+
'''
232+
v_act = []
233+
for x in v_input:
234+
v_act.append(np.maximum(0.0, x))
235+
return v_act
236+
237+
238+
def isNumber(s):
239+
'''
240+
Check if given input is a number.
241+
242+
Args:
243+
s (any type):
244+
Data to test.
245+
246+
Returns:
247+
bool: True if is a number, False if isn't
248+
'''
249+
try:
250+
float(s)
251+
return True
252+
253+
except ValueError:
254+
return False

gmprocess/waveform_processing/clipping/histogram.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
14
import numpy as np
25
from statsmodels.tsa.holtwinters import ExponentialSmoothing
36
from gmprocess.waveform_processing.clipping.clip_detection import ClipDetection
@@ -57,14 +60,6 @@ def __init__(self, st, num_bins=6200, min_width=7,
5760
self.num_clip_intervals = None
5861
self._get_results()
5962

60-
def _clean_trace(self, tr):
61-
'''
62-
Helper function to clean a trace.
63-
64-
See parent class.
65-
'''
66-
return ClipDetection._clean_trace(self, tr)
67-
6863
def _signal_scale(self, signal, alpha):
6964
'''
7065
Helper function to scale signal data

gmprocess/waveform_processing/clipping/jerk.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
14
import numpy as np
25
from gmprocess.waveform_processing.clipping.clip_detection import ClipDetection
36

@@ -45,14 +48,6 @@ def __init__(self, st, point_thresh=25, test_all=False):
4548
self.num_outliers = None
4649
self._get_results()
4750

48-
def _clean_trace(self, tr):
49-
'''
50-
Helper function to clean a trace.
51-
52-
See parent class.
53-
'''
54-
return ClipDetection._clean_trace(self, tr)
55-
5651
def _detect(self, tr):
5752
'''
5853
Check for jerk outliers. Based on method described by:

0 commit comments

Comments
 (0)