#python #tensorflow #keras #lstm #loss-function
Вопрос:
У меня есть проблема многоклассовой классификации, и я использую LSTM для ее решения. Я тренировал свою модель с помощью categorical_crossentropy
. Но когда дело доходит до проверки качества модели (после обучения) Я должен использовать эту пользовательскую метрику, где A
есть 2D-матрица штрафов:
def score(y_true, y_pred):
S = 0.0
y_true = y_true.astype(int)
y_pred = y_pred.astype(int)
for i in range(0, y_true.shape[0]):
S -= A[y_true[i], y_pred[i]]
return S/y_true.shape[0]
Такая пользовательская метрика может приниматься в качестве входных y_true
данных и y_pred
в качестве Series
объектов Pandas, и она выводит отрицательное число, которое чем ближе к нулю, тем лучше.
Я хотел бы заменить текущую categorical_crossentropy
функцию потерь пользовательской потерей, поведение которой аналогично приведенной выше пользовательской метрике, то есть учитывает матрицу A
штрафов.
Проблемы, с которыми я сталкиваюсь, заключаются в том, что входы функции потерь являются Tensor
объектами, а Series
не объектами Панд, с которыми я совершенно незнаком. Не только это, но, поскольку я имею дело с LSTM, форма моих входных тензоров находится в 3D:
y_true: Tensor("IteratorGetNext:1", shape=(1, 25131, 12), dtype=uint8)
type(y_true): <class 'tensorflow.python.framework.ops.Tensor'>
y_pred: Tensor("sequential_26/time_distributed_26/Reshape_1:0", shape=(1, 25131, 12), dtype=float32)
type(y_pred): <class 'tensorflow.python.framework.ops.Tensor'>
Если это поможет, это моя архитектура:
callbacks = [EarlyStopping(monitor='val_loss', patience=25)]
model = Sequential()
model.add(Masking(mask_value = 0.))
model.add(Bidirectional(LSTM(64, return_sequences=True, activation = "tanh")))
model.add(Dropout(0.3))
model.add(TimeDistributed(Dense(12, activation='softmax')))
adam = adam_v2.Adam(learning_rate=0.002)
model.compile(optimizer=adam, loss=score, metrics=['accuracy'])
history = model.fit(X_train, y_train, epochs=150, batch_size=1, shuffle=False,
validation_data=(X_test, y_test), verbose=2, callbacks=[callbacks])
Это формы моих входных данных для модели, всего у меня 12 классов:
print(f'{X_train.shape} {X_test.shape} {y_train.shape} {y_test.shape}')
(73, 25131, 29) (25, 23879, 29) (73, 25131, 12) (25, 23879, 12)
Это матрица A
штрафов размером 12×12, которые представляют собой количество классов задачи многоклассовой классификации:
И это соревнование, для которого я создаю модель:
Комментарии:
1. можем ли мы предположить, что A имеет форму (X_train.shape[0], X_train.shape[0]) ?
2. Штрафная матрица
A
имеет форму 12×12 (которые являются классами). Я добавлю это к вопросу.
Ответ №1:
Поскольку вы хотите провести оценку модели, вам нужна метрика, а не убытки.
Чтобы преобразовать функцию в пользовательскую метрику в tensorflow:
- Приведение
y_true
иy_pred
чтобыint
не получить то, что вы хотите, вам нужно использоватьtf.argmax
вместо этого, предполагая, чтоy_true
это однократно закодированные метки иy_pred
вероятности. (потому что вы использовалиcategorical_crossentropy
для обучения иsoftmax
в качестве функции активации на выходном уровне) - Определите пользовательский класс метрик
Примеры Кодов:
class Score(tf.keras.metrics.Metric):
def __init__(self, A, name="score", **kwargs):
super().__init__(name=name, **kwargs)
self.A = tf.constant(A,dtype=tf.float32)
self.S = self.add_weight(name="S", initializer="zeros")
self.num_elems = self.add_weight(name="num_elems", initializer="zeros")
def update_state(self, y_true, y_pred, sample_weight=None):
#convert y_true and y_pred to indices and flatten them
y_true = tf.reshape(tf.argmax(y_true,-1),(-1,))
y_pred = tf.reshape(tf.argmax(y_pred,-1),(-1,))
num_elems = y_true.shape[0]
indices = tf.stack([y_true,y_pred],1)
#access A using indices and sum
self.S.assign_add(-tf.reduce_sum(tf.gather_nd(self.A,indices)))
self.num_elems.assign_add(num_elems)
def result(self):
return self.S/self.num_elems
Кроме того, model.fit
используется для обучения модели. Если вы хотите только оценить модель, передайте Score()
ее в качестве показателя и используйте model.evaluate
.
Примеры Кодов:
model.compile(optimizer=adam, loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=['accuracy',Score(A)])
model.evaluate(X_test, y_test, batch_size=1)