Kaggle competition: YKC-2nd
CUT = cfg['parse_params']['cut_time']
SR = 48000
TIME = cfg['data_params']['sample_time']
FMAX = cfg['data_params']['spec_fmax']
FMIN = cfg['data_params']['spec_fmin']
N_MEL = cfg['data_params']['spec_mel']
HEIGHT, WIDTH = cfg['data_params']['img_shape']
CLASS_N = 24<create_dataframe>
train = pd.read_csv(".. /input/ykc-cup-2nd/train.csv")
 test = pd.read_csv(".. /input/ykc-cup-2nd/test.csv")
 sub = pd.read_csv(".. /input/ykc-cup-2nd/sample_submission.csv")
 train.shape, test.shape, sub.shape
raw_dataset = tf.data.TFRecordDataset([TRAIN_TFREC + '/00-148.tfrec'])
 raw_dataset<categorify>
df = pd.concat([train, test])
 df = df.reset_index(drop=True)
 df.shape
feature_description = {
'recording_id': tf.io.FixedLenFeature([], tf.string, default_value=''),
'audio_wav': tf.io.FixedLenFeature([], tf.string, default_value=''),
'label_info': tf.io.FixedLenFeature([], tf.string, default_value=''),
}
parse_dtype = {
'audio_wav': tf.float32,
'recording_id': tf.string,
'species_id': tf.int32,
'songtype_id': tf.int32,
't_min': tf.float32,
'f_min': tf.float32,
't_max': tf.float32,
'f_max':tf.float32,
'is_tp': tf.int32
}
@tf.function
def _parse_function(example_proto):
sample = tf.io.parse_single_example(example_proto, feature_description)
 wav, _ = tf.audio.decode_wav(sample['audio_wav'], desired_channels=1)
 label_info = tf.strings.split(sample['label_info'], sep='"')[1]
labels = tf.strings.split(label_info, sep=';')
 @tf.function
def _cut_audio(label):
items = tf.strings.split(label, sep=',')
 spid = tf.squeeze(tf.strings.to_number(items[0], tf.int32))
soid = tf.squeeze(tf.strings.to_number(items[1], tf.int32))
tmin = tf.squeeze(tf.strings.to_number(items[2]))
fmin = tf.squeeze(tf.strings.to_number(items[3]))
tmax = tf.squeeze(tf.strings.to_number(items[4]))
fmax = tf.squeeze(tf.strings.to_number(items[5]))
tp = tf.squeeze(tf.strings.to_number(items[6], tf.int32))
tmax_s = tmax * tf.cast(SR, tf.float32)
 tmin_s = tmin * tf.cast(SR, tf.float32)
 cut_s = tf.cast(CUT * SR, tf.float32)
 all_s = tf.cast(60 * SR, tf.float32)
 tsize_s = tmax_s - tmin_s
cut_min = tf.cast(
 tf.maximum(0.0,
tf.minimum(tmin_s -(cut_s - tsize_s)/ 2,
tf.minimum(tmax_s +(cut_s - tsize_s)/ 2, all_s)- cut_s)
), tf.int32 
)
 cut_max = cut_min + CUT * SR
_sample = {
'audio_wav': tf.reshape(wav[cut_min:cut_max], [CUT*SR]),
'recording_id': sample['recording_id'],
'species_id': spid,
'songtype_id': soid,
't_min': tmin - tf.cast(cut_min, tf.float32)/tf.cast(SR, tf.float32),
'f_min': fmin,
't_max': tmax - tf.cast(cut_min, tf.float32)/tf.cast(SR, tf.float32),
'f_max': fmax,
'is_tp': tp
}
return _sample
samples = tf.map_fn(_cut_audio, labels, dtype=parse_dtype)
 return samples
parsed_dataset = raw_dataset.map(_parse_function ).unbatch()<feature_engineering>
target = "department_id"
n_split = 5
kfold = StratifiedKFold(n_splits=n_split, shuffle = True, random_state=42 )
@tf.function
def _cut_wav(x):
cut_min = tf.random.uniform([], maxval=(CUT-TIME)*SR, dtype=tf.int32)
 cut_max = cut_min + TIME * SR
cutwave = tf.reshape(x['audio_wav'][cut_min:cut_max], [TIME*SR])
 y = {}
y.update(x)
 y['audio_wav'] = cutwave
y['t_min'] = tf.maximum(0.0, x['t_min'] - tf.cast(cut_min, tf.float32)/ SR)
 y['t_max'] = tf.maximum(0.0, x['t_max'] - tf.cast(cut_min, tf.float32)/ SR)
 return y
@tf.function
def _cut_wav_val(x):
cut_min =(CUT-TIME)*SR // 2
cut_max = cut_min + TIME * SR
cutwave = tf.reshape(x['audio_wav'][cut_min:cut_max], [TIME*SR])
 y = {}
y.update(x)
 y['audio_wav'] = cutwave
y['t_min'] = tf.maximum(0.0, x['t_min'] - tf.cast(cut_min, tf.float32)/ SR)
 y['t_max'] = tf.maximum(0.0, x['t_max'] - tf.cast(cut_min, tf.float32)/ SR)
 return y<feature_engineering>
df["product_name"] = df["product_name"].apply(lambda words : words.lower().replace(",", "" ).replace("&", "" ).split(" "))
df.head()
@tf.function
def _filtTP(x):
return x['is_tp'] == 1<data_type_conversions>
model_names = ["crawl-300d-2M", "crawl-300d-2M-subword", "wiki-news-300d-1M", "wiki-news-300d-1M-subword"]
def show_wav(sample, ax):
wav = sample["audio_wav"].numpy()
rate = SR
ax.plot(np.arange(len(wav)) / rate, wav)
 ax.set_title(
 sample["recording_id"].numpy().decode()
+("/%d" % sample["species_id"])
 +("TP" if sample["is_tp"] else "FP"))
return Audio(( wav * 2**15 ).astype(np.int16), rate=rate)
 fig, ax = plt.subplots(figsize=(15, 3))
show_wav(next(iter(parsed_dataset)) , ax )<normalization>
fasttext_pretrain_cols = []
unused_words = defaultdict(int)
 for model_name in model_names:
model = pd.read_pickle(f".. /input/fasttext/{model_name}.pkl")
 def to_mean_vec(x, model):
v = np.zeros(model.vector_size)
 for w in x:
try:
v += model[w]
except:
unused_words[w] += 1
v = v /(np.sqrt(np.sum(v ** 2)) + 1e-16)
 return v
def to_max_vec(x, model):
v = np.zeros(model.vector_size)
 for w in x:
try:
v = np.maximum(v, model[w])
 except:
pass
return v
mean_vecs = df["product_name"].apply(lambda x : to_mean_vec(x, model))
mean_vecs = np.vstack(mean_vecs)
 cols = [f"fasttext_pretrain_{model_name}_mean_vec{k}" for k in range(mean_vecs.shape[1])]
fasttext_pretrain_cols += cols
mean_vec_df = pd.DataFrame(mean_vecs, columns=cols)
 df = pd.concat([df, mean_vec_df], axis = 1)
 max_vecs = df["product_name"].apply(lambda x : to_max_vec(x, model))
max_vecs = np.vstack(max_vecs)
 cols = [f"fasttext_pretrain_{model_name}_max_vec{k}" for k in range(max_vecs.shape[1])]
fasttext_pretrain_cols += cols
max_vec_df = pd.DataFrame(max_vecs, columns=cols)
 df = pd.concat([df, max_vec_df], axis = 1)
 df.head()
@tf.function
def _wav_to_spec(x):
mel_power = cfg['data_params']['mel_power']
stfts = tf.signal.stft(x["audio_wav"], frame_length=2048, frame_step=512, fft_length=2048)
 spectrograms = tf.abs(stfts)** mel_power
num_spectrogram_bins = stfts.shape[-1]
lower_edge_hertz, upper_edge_hertz, num_mel_bins = FMIN, FMAX, N_MEL
linear_to_mel_weight_matrix = tf.signal.linear_to_mel_weight_matrix(
 num_mel_bins, num_spectrogram_bins, SR, lower_edge_hertz,
upper_edge_hertz)
 mel_spectrograms = tf.tensordot(
 spectrograms, linear_to_mel_weight_matrix, 1)
 mel_spectrograms.set_shape(spectrograms.shape[:-1].concatenate(
 linear_to_mel_weight_matrix.shape[-1:]))
log_mel_spectrograms = tf.math.log(mel_spectrograms + 1e-6)
 y = {
'audio_spec': tf.transpose(log_mel_spectrograms),
}
y.update(x)
 return y
spec_dataset = parsed_dataset.filter(_filtTP ).map(_cut_wav ).map(_wav_to_spec )<categorify>
train = df[~df[target].isna() ]
test = df[df[target].isna() ]
@tf.function
def _create_annot(x):
targ = tf.one_hot(x["species_id"], CLASS_N, on_value=x["is_tp"], off_value=0)
 return {
'input': x["audio_spec"],
'target': tf.cast(targ, tf.float32)
 }
annot_dataset = spec_dataset.map(_create_annot )<normalization>
def to_weighted_count_vec(x, word_sets):
v = np.zeros(21)
 for w in x:
hits = []
for i in range(21):
if w in word_sets[i]:
hits.append(i)
 for i in hits:
v[i] += 1.0 / len(hits)
 return v
weighted_count_cols = [f"weighted_count_vec{k}" for k in range(21)]
@tf.function
def _preprocess_img(x, training=False):
image = tf.expand_dims(x, axis=-1)
 image = tf.image.resize(image, [HEIGHT, WIDTH])
 image = tf.image.per_image_standardization(image)
 @tf.function
def _specaugment(image):
ERASE_TIME = 50
ERASE_MEL = 16
image = tf.expand_dims(image, axis=0)
 xoff = tf.random.uniform([2], minval=ERASE_TIME//2, maxval=WIDTH-ERASE_TIME//2, dtype=tf.int32)
 xsize = tf.random.uniform([2], minval=ERASE_TIME//2, maxval=ERASE_TIME, dtype=tf.int32)
 yoff = tf.random.uniform([2], minval=ERASE_MEL//2, maxval=HEIGHT-ERASE_MEL//2, dtype=tf.int32)
 ysize = tf.random.uniform([2], minval=ERASE_MEL//2, maxval=ERASE_MEL, dtype=tf.int32)
 image = tfa.image.cutout(image, [HEIGHT, xsize[0]], offset=[HEIGHT//2, xoff[0]])
 image = tfa.image.cutout(image, [HEIGHT, xsize[1]], offset=[HEIGHT//2, xoff[1]])
 image = tfa.image.cutout(image, [ysize[0], WIDTH], offset=[yoff[0], WIDTH//2])
 image = tfa.image.cutout(image, [ysize[1], WIDTH], offset=[yoff[1], WIDTH//2])
 image = tf.squeeze(image, axis=0)
 return image
if training:
gau = tf.keras.layers.GaussianNoise(0.3)
 image = tf.cond(tf.random.uniform([])< 0.5, lambda: gau(image, training=True), lambda: image)
 image = tf.image.random_brightness(image, 0.2)
 image = tf.cond(tf.random.uniform([])< 0.5, lambda: _specaugment(image), lambda: image)
 image =(image - tf.reduce_min(image)) /(tf.reduce_max(image)- tf.reduce_min(image)) * 255.0
image = tf.image.grayscale_to_rgb(image)
 image = cfg['model_params']['arch_preprocess'](image)
 return image
@tf.function
def _preprocess(x):
image = _preprocess_img(x['input'], True)
 return(image, x["target"])
 @tf.function
def _preprocess_val(x):
image = _preprocess_img(x['input'], False)
 return(image, x["target"])
 @tf.function
def _preprocess_test(x):
image = _preprocess_img(x['audio_spec'], False)
 return(image, x["recording_id"] )<choose_model_class>
train_weighted_count = pd.DataFrame(index=train.index, columns=weighted_count_cols, dtype=np.float32)
 for i_fold,(train_idx, valid_idx)in enumerate(kfold.split(train, train[target])) :
tr = train.loc[train_idx]
va = train.loc[valid_idx]
word_sets = [set(sum(tr[tr["department_id"] == i]["product_name"], [])) for i in range(21)]
vecs = va["product_name"].apply(lambda x : to_weighted_count_vec(x, word_sets))
vecs = np.vstack(vecs)
 vec_df = pd.DataFrame(vecs, index=va.index, columns=weighted_count_cols)
 train_weighted_count.loc[valid_idx, :] = vec_df
train = pd.concat([train, train_weighted_count], axis=1 )
def create_model() :
with strategy.scope() :
backbone = cfg['model_params']['arch'](include_top=False, weights='imagenet')
 if cfg['model_params']['freeze_to'] is None:
for layer in backbone.layers:
layer.trainable = False
else:
for layer in backbone.layers[:cfg['model_params']['freeze_to']]:
layer.trainable = False
model = tf.keras.Sequential([
backbone,
tf.keras.layers.GlobalAveragePooling2D() ,
tf.keras.layers.BatchNormalization() ,
tf.keras.layers.Dropout(0.4),
tf.keras.layers.Dense(1024, activation='relu', kernel_initializer=tf.keras.initializers.he_normal()),
tf.keras.layers.BatchNormalization() ,
tf.keras.layers.Dropout(0.4),
tf.keras.layers.Dense(CLASS_N, bias_initializer=tf.keras.initializers.Constant(-2.))])
 return model
model = create_model()
model.summary()<prepare_x_and_y>
test_weighted_count = pd.DataFrame(index=test.index, columns=weighted_count_cols, dtype=np.float32)
 word_sets = [set(sum(train[train["department_id"] == i]["product_name"], [])) for i in range(21)]
vecs = test["product_name"].apply(lambda x : to_weighted_count_vec(x, word_sets))
vecs = np.vstack(vecs)
 test_weighted_count.loc[:, :] = pd.DataFrame(vecs, index=test.index, columns=weighted_count_cols)
 test = pd.concat([test, test_weighted_count], axis=1 )
@tf.function
def _mixup(inp, targ):
indice = tf.range(len(inp))
indice = tf.random.shuffle(indice)
 sinp = tf.gather(inp, indice, axis=0)
 starg = tf.gather(targ, indice, axis=0)
 alpha = 0.2
t = tf.compat.v1.distributions.Beta(alpha, alpha ).sample([len(inp)])
 tx = tf.reshape(t, [-1, 1, 1, 1])
 ty = tf.reshape(t, [-1, 1])
 x = inp * tx + sinp *(1-tx)
 y = targ * ty + starg *(1-ty)
 return x, y<create_dataframe>
features = fasttext_pretrain_cols + weighted_count_cols + ["order_rate", "order_dow_mode", "order_hour_of_day_mode"]
tfrecs = sorted(tf.io.gfile.glob(TRAIN_TFREC + '/*.tfrec'))
parsed_trainval =(tf.data.TFRecordDataset(tfrecs, num_parallel_reads=AUTOTUNE)
.map(_parse_function, num_parallel_calls=AUTOTUNE ).unbatch() 
.filter(_filtTP ).enumerate() )<data_type_conversions>
train = reduce_mem_usage(train)
 test = reduce_mem_usage(test )
indices = []
spid = []
recid = []
for i, sample in tqdm(parsed_trainval.prefetch(AUTOTUNE)) :
indices.append(i.numpy())
 spid.append(sample['species_id'].numpy())
 recid.append(sample['recording_id'].numpy().decode() )<create_dataframe>
preds_test = []
scores = []
oof = np.zeros(( len(train), 21))
for i_fold,(train_idx, valid_idx)in enumerate(kfold.split(train, train[target])) :
print(f"--------fold {i_fold}-------")
 x_tr = train.loc[train_idx, features]
y_tr = train.loc[train_idx, target]
x_va = train.loc[valid_idx, features]
y_va = train.loc[valid_idx, target]
lgb = LGBMClassifier(objective='multiclass', colsample_bytree=0.2, n_estimators=500)
 lgb.fit(x_tr, y_tr, eval_set=[(x_va, y_va)], early_stopping_rounds=10, verbose=10)
 def predict_proba(x):
return lgb.predict_proba(x)
 pred_val = predict_proba(x_va)
 oof[valid_idx] += pred_val
score = {
"logloss" : log_loss(y_va, pred_val),
"f1_micro" : f1_score(y_va, np.argmax(pred_val, axis = 1), average = "micro")}
print(score)
 scores.append(score)
 pred_test = predict_proba(test[features])
 preds_test.append(pred_test )
table = pd.DataFrame({'indices': indices, 'species_id': spid, 'recording_id': recid})
 table<categorify>
score_df = pd.DataFrame(scores)
 score_df
def create_idx_filter(indice):
@tf.function
def _filt(i, x):
return tf.reduce_any(indice == i)
 return _filt
@tf.function
def _remove_idx(i, x):
return x<categorify>
oof_df = pd.DataFrame(oof)
 oof_df.to_csv("oof_lgb.csv", index = False )
def create_train_dataset(batchsize, train_idx):
global parsed_trainval
parsed_train =(parsed_trainval 
.filter(create_idx_filter(train_idx)) 
.map(_remove_idx))
dataset =(parsed_train.cache() 
.shuffle(len(train_idx)) 
.repeat() 
.map(_cut_wav, num_parallel_calls=AUTOTUNE)
.map(_wav_to_spec, num_parallel_calls=AUTOTUNE)
.map(_create_annot, num_parallel_calls=AUTOTUNE)
.map(_preprocess, num_parallel_calls=AUTOTUNE)
.batch(batchsize))
if cfg['model_params']['mixup']:
dataset =(dataset.map(_mixup, num_parallel_calls=AUTOTUNE)
.prefetch(AUTOTUNE))
else:
dataset = dataset.prefetch(AUTOTUNE)
 return dataset
def create_val_dataset(batchsize, val_idx):
global parsed_trainval
parsed_val =(parsed_trainval 
.filter(create_idx_filter(val_idx)) 
.map(_remove_idx))
vdataset =(parsed_val 
.map(_cut_wav_val, num_parallel_calls=AUTOTUNE)
.map(_wav_to_spec, num_parallel_calls=AUTOTUNE)
.map(_create_annot, num_parallel_calls=AUTOTUNE)
.map(_preprocess_val, num_parallel_calls=AUTOTUNE)
.batch(8*strategy.num_replicas_in_sync)
.cache())
 return vdataset<categorify>
for i in range(len(preds_test)) :
pred_df = pd.DataFrame(preds_test[i])
 pred_df.to_csv(f"pred_{i}_lgb.csv", index = False )
@tf.function
def _one_sample_positive_class_precisions(example):
y_true, y_pred = example
retrieved_classes = tf.argsort(y_pred, direction='DESCENDING')
 class_rankings = tf.argsort(retrieved_classes)
 retrieved_class_true = tf.gather(y_true, retrieved_classes)
 retrieved_cumulative_hits = tf.math.cumsum(tf.cast(retrieved_class_true, tf.float32))
idx = tf.where(y_true)[:, 0]
i = tf.boolean_mask(class_rankings, y_true)
 r = tf.gather(retrieved_cumulative_hits, i)
 c = 1 + tf.cast(i, tf.float32)
 precisions = r / c
dense = tf.scatter_nd(idx[:, None], precisions, [y_pred.shape[0]])
 return dense
class LWLRAP(tf.keras.metrics.Metric):
def __init__(self, num_classes, name='lwlrap'):
super().__init__(name=name)
 self._precisions = self.add_weight(
 name='per_class_cumulative_precision',
shape=[num_classes],
initializer='zeros', 
)
 self._counts = self.add_weight(
 name='per_class_cumulative_count',
shape=[num_classes],
initializer='zeros', 
)
 def update_state(self, y_true, y_pred, sample_weight=None):
precisions = tf.map_fn(
 fn=_one_sample_positive_class_precisions,
elems=(y_true, y_pred),
dtype=(tf.float32), 
)
 increments = tf.cast(precisions > 0, tf.float32)
 total_increments = tf.reduce_sum(increments, axis=0)
 total_precisions = tf.reduce_sum(precisions, axis=0)
 self._precisions.assign_add(total_precisions)
 self._counts.assign_add(total_increments)
 def result(self):
per_class_lwlrap = self._precisions / tf.maximum(self._counts, 1.0)
 per_class_weight = self._counts / tf.reduce_sum(self._counts)
 overall_lwlrap = tf.reduce_sum(per_class_lwlrap * per_class_weight)
 return overall_lwlrap
def reset_states(self):
self._precisions.assign(self._precisions * 0)
 self._counts.assign(self._counts * 0 )<categorify>
pred_test_final = np.array(preds_test ).mean(axis = 0)
 pred_test_final = np.argmax(pred_test_final, axis = 1 )
<train_model><EOS> 
sub["department_id"] = pred_test_final
sub.to_csv("submission_lgb.csv", index = False)
 sub.head()