Я строю модель на основе этого кода для подавления шума . Моя проблема с ванильной реализацией состоит в том, что она загружает все данные одновременно, что не самая лучшая идея, когда обучающие данные становятся действительно большими; мой входной файл, обозначенный в связанном коде как training.h5
, занимает более 30 ГБ.
Я решил вместо этого go с tf.data
интерфейсом, который должен позволять мне работать с большими наборами данных; Моя проблема здесь заключается в том, что я не знаю, как правильно сформировать TFRecordDataset
, чтобы он соответствовал требованиям API модели.
Если вы установите model.fit(x_train, [y_train, vad_train]
, для этого по существу потребуется следующее:
- x_train, форма
[nb_sequences, window, 42]
- y_train, форма
[nb_sequences, window, 22]
- vad_train, форма
[nb_sequences, window, 1]
window
один типично исправления (в коде: 2000
), поэтому единственная переменная nb_sequences
зависит от размера вашего набора данных. Однако с tf.data
мы не предоставляем x
и y
, а только x
(см. Документы API модели ).
Сохранение tfrecord в файл
Чтобы сделать код воспроизводимым, я создал входной файл со следующим кодом:
writer = tf.io.TFRecordWriter(path='example.tfrecord')
for record in data:
feature = {}
feature['X'] = tf.train.Feature(float_list=tf.train.FloatList(value=record[:42]))
feature['y'] = tf.train.Feature(float_list=tf.train.FloatList(value=record[42:64]))
feature['vad'] = tf.train.Feature(float_list=tf.train.FloatList(value=[record[64]]))
example = tf.train.Example(features=tf.train.Features(feature=feature))
serialized = example.SerializeToString()
writer.write(serialized)
writer.close()
data
- это наши тренировочные данные с формой [10000, 65]
. Мой example.tfrecord
доступен здесь . Это 3 МБ, в действительности это будет 30 ГБ +.
Вы можете заметить, что в связанном коде массив numpy имеет форму [x, 87]
, а мой - [x, 65]
. Это нормально - остаток нигде не используется.
Загрузка набора данных с помощью tf.data.TFRecordDataset
Я хотел бы использовать tf.data
для загрузки «по запросу» данных с некоторой предварительной выборкой Нет необходимости хранить все это в памяти. Моя попытка:
import datetime
import numpy as np
import h5py
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import GRU
from tensorflow.keras import regularizers
from tensorflow.keras.constraints import Constraint
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras import backend as K
from tensorflow.keras.layers import concatenate
def load_dataset(path):
def _parse_function(example_proto):
keys_to_features = {
'X': tf.io.FixedLenFeature([42], tf.float32),
'y': tf.io.FixedLenFeature([22], tf.float32),
'vad': tf.io.FixedLenFeature([1], tf.float32)
}
features = tf.io.parse_single_example(example_proto, keys_to_features)
return (features['X'], (features['y'], features['vad']))
dataset = tf.data.TFRecordDataset(path).map(_parse_function)
return dataset
def my_crossentropy(y_true, y_pred):
return K.mean(2 * K.abs(y_true - 0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1)
def mymask(y_true):
return K.minimum(y_true + 1., 1.)
def msse(y_true, y_pred):
return K.mean(mymask(y_true) * K.square(K.sqrt(y_pred) - K.sqrt(y_true)), axis=-1)
def mycost(y_true, y_pred):
return K.mean(mymask(y_true) * (10 * K.square(K.square(K.sqrt(y_pred) - K.sqrt(y_true))) + K.square(
K.sqrt(y_pred) - K.sqrt(y_true)) + 0.01 * K.binary_crossentropy(y_pred, y_true)), axis=-1)
def my_accuracy(y_true, y_pred):
return K.mean(2 * K.abs(y_true - 0.5) * K.equal(y_true, K.round(y_pred)), axis=-1)
class WeightClip(Constraint):
'''Clips the weights incident to each hidden unit to be inside a range
'''
def __init__(self, c=2.0):
self.c = c
def __call__(self, p):
return K.clip(p, -self.c, self.c)
def get_config(self):
return {'name': self.__class__.__name__,
'c': self.c}
def build_model():
reg = 0.000001
constraint = WeightClip(0.499)
main_input = Input(shape=(None, 42), name='main_input')
tmp = Dense(24, activation='tanh', name='input_dense', kernel_constraint=constraint, bias_constraint=constraint)(
main_input)
vad_gru = GRU(24, activation='tanh', recurrent_activation='sigmoid', return_sequences=True, name='vad_gru',
kernel_regularizer=regularizers.l2(reg), recurrent_regularizer=regularizers.l2(reg),
kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(tmp)
vad_output = Dense(1, activation='sigmoid', name='vad_output', kernel_constraint=constraint,
bias_constraint=constraint)(vad_gru)
noise_input = concatenate([tmp, vad_gru, main_input])
noise_gru = GRU(48, activation='relu', recurrent_activation='sigmoid', return_sequences=True, name='noise_gru',
kernel_regularizer=regularizers.l2(reg), recurrent_regularizer=regularizers.l2(reg),
kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(noise_input)
denoise_input = concatenate([vad_gru, noise_gru, main_input])
denoise_gru = GRU(96, activation='tanh', recurrent_activation='sigmoid', return_sequences=True, name='denoise_gru',
kernel_regularizer=regularizers.l2(reg), recurrent_regularizer=regularizers.l2(reg),
kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(
denoise_input)
denoise_output = Dense(22, activation='sigmoid', name='denoise_output', kernel_constraint=constraint,
bias_constraint=constraint)(denoise_gru)
model = Model(inputs=main_input, outputs=[denoise_output, vad_output])
model.compile(loss=[mycost, my_crossentropy],
metrics=[msse],
optimizer='adam', loss_weights=[10, 0.5])
return model
model = build_model()
dataset = load_dataset('example.tfrecord')
Мой набор данных теперь имеет следующую форму:
<MapDataset shapes: ((42,), ((22,), (1,))), types: (tf.float32, (tf.float32, tf.float32))>
, что, как я думал, - это то, что ожидает Model API (спойлер: это не так).
model.fit(dataset.batch(10))
выдает следующую ошибку:
ValueError: Error when checking input: expected main_input to have 3 dimensions, but got array with shape (None, 42)
Имеет смысл, у меня нет window
здесь. В то же время кажется, что Model(inputs=main_input, outputs=[denoise_output, vad_output])
.
не получает правильную форму, как изменить load_dataset
так, чтобы он соответствовал ожидаемому API модели для tf.data
?