Skip to content

Commit 7e153d5

Browse files
committed
train: Compute voted accuracy
1 parent a14f9af commit 7e153d5

File tree

4 files changed

+152
-88
lines changed

4 files changed

+152
-88
lines changed

microesc/features.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os.path
66
import urllib.request
77
import zipfile
8+
import collections
89

910
import pandas
1011
import numpy
@@ -166,3 +167,52 @@ def load_sample(sample, settings, feature_dir, window_frames,
166167
# add channel dimension
167168
data = numpy.expand_dims(padded, -1)
168169
return data
170+
171+
172+
Sample = collections.namedtuple('Sample', 'start end fold slice_file_name')
173+
174+
def load_windows(sample, settings, loader, overlap):
175+
sample_rate = settings['samplerate']
176+
frame_samples = settings['hop_length']
177+
window_frames = settings['frames']
178+
179+
windows = []
180+
181+
duration = sample.end - sample.start
182+
length = int(sample_rate * duration)
183+
184+
for win in sample_windows(length, frame_samples, window_frames, overlap=overlap):
185+
chunk = Sample(start=win[0]/sample_rate,
186+
end=win[1]/sample_rate,
187+
fold=sample.fold,
188+
slice_file_name=sample.slice_file_name)
189+
d = loader(chunk)
190+
windows.append(d)
191+
192+
return windows
193+
194+
def predict_voted(settings, model, samples, loader, method='mean', overlap=0.5):
195+
196+
out = []
197+
for _, sample in samples.iterrows():
198+
windows = load_windows(sample, settings, loader, overlap=overlap)
199+
inputs = numpy.stack(windows)
200+
201+
predictions = model.predict(inputs)
202+
if method == 'mean':
203+
p = numpy.mean(predictions, axis=0)
204+
assert len(p) == 10
205+
out.append(p)
206+
elif method == 'majority':
207+
votes = numpy.argmax(predictions, axis=1)
208+
p = numpy.bincount(votes, minlength=10) / len(votes)
209+
out.append(p)
210+
211+
ret = numpy.stack(out)
212+
assert len(ret.shape) == 2, ret.shape
213+
assert ret.shape[0] == len(out), ret.shape
214+
assert ret.shape[1] == 10, ret.shape # classes
215+
216+
return ret
217+
218+

microesc/test.py

Lines changed: 7 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import math
33
import os.path
44
import sys
5-
import collections
65

76
import keras
87
import sklearn
@@ -12,50 +11,6 @@
1211

1312
from . import urbansound8k, features, common
1413

15-
Sample = collections.namedtuple('Sample', 'start end fold slice_file_name')
16-
17-
def load_windows(sample, settings, loader, window_frames, overlap):
18-
sample_rate = settings['samplerate']
19-
frame_samples = settings['hop_length']
20-
21-
windows = []
22-
23-
duration = sample.end - sample.start
24-
length = int(sample_rate * duration)
25-
26-
for win in features.sample_windows(length, frame_samples, window_frames, overlap=overlap):
27-
chunk = Sample(start=win[0]/sample_rate,
28-
end=win[1]/sample_rate,
29-
fold=sample.fold,
30-
slice_file_name=sample.slice_file_name)
31-
d = loader(chunk)
32-
windows.append(d)
33-
34-
return windows
35-
36-
def predict_voted(settings, model, samples, loader, window_frames, method='mean', overlap=0.5):
37-
38-
out = []
39-
for _, sample in samples.iterrows():
40-
windows = load_windows(sample, settings, loader, window_frames, overlap=overlap)
41-
inputs = numpy.stack(windows)
42-
43-
predictions = model.predict(inputs)
44-
if method == 'mean':
45-
p = numpy.mean(predictions, axis=0)
46-
assert len(p) == 10
47-
out.append(p)
48-
elif method == 'majority':
49-
votes = numpy.argmax(predictions, axis=1)
50-
p = numpy.bincount(votes, minlength=10) / len(votes)
51-
out.append(p)
52-
53-
ret = numpy.stack(out)
54-
assert len(ret.shape) == 2, ret.shape
55-
assert ret.shape[0] == len(out), ret.shape
56-
assert ret.shape[1] == 10, ret.shape # classes
57-
58-
return ret
5914

6015
def load_history(jobs_dir, job_id):
6116

@@ -133,28 +88,6 @@ def score(model, data):
13388
return val_scores, test_scores
13489

13590

136-
def test_predict_windowed():
137-
138-
from sklearn.metrics import accuracy_score
139-
t = test[0:10]
140-
141-
sbcnn16k32_settings = dict(
142-
feature='mels',
143-
samplerate=16000,
144-
n_mels=32,
145-
fmin=0,
146-
fmax=8000,
147-
n_fft=512,
148-
hop_length=256,
149-
augmentations=5,
150-
)
151-
152-
def load_sample32(sample):
153-
return features.load_sample(sample, sbcnn16k32_settings, window_frames=72, feature_dir='../../scratch/aug')
154-
155-
mean_m = predict_windowed(sbcnn16k32_settings, model, t, loader=load_sample32, method='mean')
156-
accuracy_score(t.classID, mean_m)
157-
15891
def parse(args):
15992

16093
import argparse
@@ -190,11 +123,11 @@ def main():
190123
urbansound8k.maybe_download_dataset(args.datasets_dir)
191124
data = urbansound8k.load_dataset()
192125
folds, test = urbansound8k.folds(data)
193-
settings = common.load_experiment(args.experiments_dir, args.experiment)
194-
frames = settings['frames']
195-
voting = settings['voting']
196-
overlap = settings['voting_overlap']
197-
settings = features.settings(settings)
126+
exsettings = common.load_experiment(args.experiments_dir, args.experiment)
127+
frames = exsettings['frames']
128+
voting = exsettings['voting']
129+
overlap = exsettings['voting_overlap']
130+
settings = features.settings(exsettings)
198131

199132

200133
all_folds = pandas.concat([f[0] for f in folds])
@@ -210,8 +143,8 @@ def load_sample(sample):
210143
window_frames=frames, feature_dir=args.features_dir)
211144

212145
def predict(model, data):
213-
return predict_voted(settings, model, data, loader=load_sample,
214-
window_frames=frames, method=voting, overlap=overlap)
146+
return features.predict_voted(exsettings, model, data, loader=load_sample,
147+
method=voting, overlap=overlap)
215148

216149
if args.model:
217150
best = pandas.DataFrame({ 'model': [ args.model ] * 9})

microesc/train.py

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
import json
88
import functools
99
import datetime
10+
import csv
1011

1112
import pandas
1213
import numpy
1314
import keras
1415
import librosa
16+
import sklearn.metrics
1517

1618
from . import features, urbansound8k, common
1719
from .models import sbcnn
@@ -38,28 +40,90 @@ def dataframe_generator(X, Y, loader, batchsize=10, n_classes=10):
3840
yield batch
3941

4042

43+
class LogCallback(keras.callbacks.Callback):
44+
def __init__(self, log_path, score_epoch):
45+
super().__init__()
46+
47+
self.log_path = log_path
48+
self.score = score_epoch
49+
50+
self._log_file = None
51+
self._csv_writer = None
52+
53+
def __del__(self):
54+
if self._log_file:
55+
self._log_file.close()
56+
57+
58+
def write_entry(self, epoch, data):
59+
data = data.copy()
60+
61+
if not self._csv_writer:
62+
# create writer when we know what fields
63+
self._log_file = open(self.log_path, 'w')
64+
fields = ['epoch'] + sorted(data.keys())
65+
self._csv_writer = csv.DictWriter(self._log_file, fields)
66+
self._csv_writer.writeheader()
67+
68+
data['epoch'] = epoch
69+
self._csv_writer.writerow(data)
70+
self._log_file.flush() # ensure data hits disk
71+
72+
def on_epoch_end(self, epoch, logs):
73+
logs = logs.copy()
74+
75+
more = self.score() # uses current model
76+
for k, v in more.items():
77+
logs[k] = v
78+
79+
self.write_entry(epoch, logs)
80+
81+
82+
83+
4184
def train_model(out_dir, fold, builder,
42-
loader, val_loader,
43-
frame_samples, window_frames,
44-
train_samples=12000, val_samples=3000,
45-
batch_size=200, epochs=50, seed=1, learning_rate=3e-4):
85+
loader, val_loader, settings, seed=1):
4686
"""Train a single model"""
4787

88+
frame_samples = settings['hop_length']
89+
train_samples = settings['train_samples']
90+
window_frames = settings['frames']
91+
val_samples = settings['val_samples']
92+
epochs = settings['epochs']
93+
batch_size = settings['batch']
94+
#learning_rate = settings['learning_rate']
95+
96+
train, val = fold
97+
98+
def top3(y_true, y_pred):
99+
return keras.metrics.top_k_categorical_accuracy(y_true, y_pred, k=3)
100+
48101
model = builder()
49102
model.compile(loss='categorical_crossentropy',
50103
optimizer=keras.optimizers.SGD(lr=0.001, momentum=0.95, nesterov=True),
51104
metrics=['accuracy'])
52105

53-
54106
model_path = os.path.join(out_dir, 'e{epoch:02d}-v{val_loss:.2f}.t{loss:.2f}.model.hdf5')
55107
checkpoint = keras.callbacks.ModelCheckpoint(model_path, monitor='val_acc', mode='max',
56108
period=1, verbose=1, save_best_only=False)
57-
callbacks_list = [checkpoint]
58109

59-
train, val = fold
110+
def voted_score():
111+
y_pred = features.predict_voted(settings, model, val,
112+
loader=val_loader, method='mean', overlap=0.5)
113+
class_pred = numpy.argmax(y_pred, axis=1)
114+
acc = sklearn.metrics.accuracy_score(val.classID, class_pred)
115+
d = {
116+
'voted_val_acc': acc,
117+
}
118+
return d
119+
log_path = os.path.join(out_dir, 'train.csv')
120+
log = LogCallback(log_path, voted_score)
121+
122+
60123
train_gen = dataframe_generator(train, train.classID, loader=loader, batchsize=batch_size)
61124
val_gen = dataframe_generator(val, val.classID, loader=val_loader, batchsize=batch_size)
62125

126+
callbacks_list = [checkpoint, log]
63127
hist = model.fit_generator(train_gen, validation_data=val_gen,
64128
steps_per_epoch=math.ceil(train_samples/batch_size),
65129
validation_steps=math.ceil(val_samples/batch_size),
@@ -147,7 +211,6 @@ def settings(args):
147211
train_settings = {}
148212
for k in default_training_settings.keys():
149213
v = args.get(k, default_training_settings[k])
150-
print('v', k, v, args.get(k))
151214
train_settings[k] = v
152215
return train_settings
153216

@@ -217,12 +280,7 @@ def build_model():
217280
builder=build_model,
218281
loader=functools.partial(load, validation=False),
219282
val_loader=functools.partial(load, validation=True),
220-
frame_samples=feature_settings['hop_length'],
221-
window_frames=model_settings['frames'],
222-
epochs=train_settings['epochs'],
223-
train_samples=train_settings['train_samples'],
224-
val_samples=train_settings['val_samples'],
225-
batch_size=train_settings['batch'])
283+
settings=exsettings)
226284

227285

228286

test/test_training.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,26 @@ def test_window_typical():
5656
w = list(features.sample_windows(int(length), frame_samples, window_frames))
5757
assert len(w) == 8, len(w)
5858
assert w[-1][1] == length
59+
60+
61+
def _test_predict_windowed():
62+
63+
t = test[0:10]
64+
65+
sbcnn16k32_settings = dict(
66+
feature='mels',
67+
samplerate=16000,
68+
n_mels=32,
69+
fmin=0,
70+
fmax=8000,
71+
n_fft=512,
72+
hop_length=256,
73+
augmentations=5,
74+
)
75+
76+
def load_sample32(sample):
77+
return features.load_sample(sample, sbcnn16k32_settings, window_frames=72, feature_dir='../../scratch/aug')
78+
79+
mean_m = features.predict_voted(sbcnn16k32_settings, model, t, loader=load_sample32, method='mean')
80+
81+

0 commit comments

Comments
 (0)