Понятие, которое вы нарисовали в своем вопросе, уже довольно хорошее начало.Я добавлю несколько вещей, чтобы заставить его работать, а также пример кода ниже:
- Вы можете указать
LSTM(n_hidden, input_shape=(None, 2))
напрямую, вместо вставки дополнительного слоя Input
;размерность пакета должна быть опущена для определения. - Поскольку ваша модель будет выполнять какую-то классификацию (на основе данных временного ряда), последний уровень - это то, что мы ожидаем от "нормальной" классификации какну, а
Dense(num_classes, action='softmax')
.Объединение в цепочку слоя LSTM
и слоя Dense
сначала передаст входные временные ряды через слой LSTM
, а затем передаст его выходные данные (определяемые количеством скрытых единиц) в слой Dense
.activation='softmax'
позволяет вычислить оценку класса для каждого класса (мы собираемся использовать горячее кодирование на этапе предварительной обработки данных, см. Пример кода ниже).Это означает, что оценки классов не упорядочены, но вы всегда можете сделать это с помощью np.argsort
или np.argmax
. - Категориальная потеря кроссентропии подходит для сравнения классификационной оценки, поэтому мы будем использовать ее:
model.compile(loss='categorical_crossentropy', optimizer='adam')
. - Так как количество взаимодействий.т. е. длина входных данных модели варьируется от образца к образцу. Мы будем использовать размер партии 1 и подачу по одному образцу за раз.
Ниже приведен пример реализации по вышеупомянутым соображениям.,Обратите внимание, что я немного изменил ваши образцы данных, чтобы обеспечить более «обоснование» выбора групп.Также каждый человек должен выполнить хотя бы одно взаимодействие перед выбором группы (т.е. последовательность ввода не может быть пустой);если это не относится к вашим данным, то может помочь введение дополнительного неактивного взаимодействия (например, 0
).
import pandas as pd
import tensorflow as tf
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.LSTM(10, input_shape=(None, 2))) # LSTM for arbitrary length series.
model.add(tf.keras.layers.Dense(3, activation='softmax')) # Softmax for class probabilities.
model.compile(loss='categorical_crossentropy', optimizer='adam')
# Example interactions:
# * 1: Likes the group,
# * 2: Dislikes the group,
# * 3: Chooses the group.
df = pd.DataFrame([
[1, 1, 3],
[1, 1, 3],
[1, 2, 2],
[1, 3, 3],
[2, 2, 1],
[2, 2, 3],
[2, 1, 2],
[2, 3, 2],
[3, 1, 1],
[3, 1, 1],
[3, 1, 1],
[3, 2, 3],
[3, 2, 2],
[3, 3, 1]],
columns=['person', 'interaction', 'group']
)
data = [person[1][['interaction', 'group']].values for person in df.groupby('person')]
x_train = [x[:-1] for x in data]
y_train = tf.keras.utils.to_categorical([x[-1, 1]-1 for x in data]) # Expects class labels from 0 to n (-> subtract 1).
print(x_train)
print(y_train)
class TrainGenerator(tf.keras.utils.Sequence):
def __init__(self, x, y):
self.x = x
self.y = y
def __len__(self):
return len(self.x)
def __getitem__(self, index):
# Need to expand arrays to have batch size 1.
return self.x[index][None, :, :], self.y[index][None, :]
model.fit_generator(TrainGenerator(x_train, y_train), epochs=1000)
pred = [model.predict(x[None, :, :]).ravel() for x in x_train]
for p, y in zip(pred, y_train):
print(p, y)
И соответствующий пример вывода:
[...]
Epoch 1000/1000
3/3 [==============================] - 0s 40ms/step - loss: 0.0037
[0.00213619 0.00241093 0.9954529 ] [0. 0. 1.]
[0.00123938 0.99718493 0.00157572] [0. 1. 0.]
[9.9632275e-01 7.5039308e-04 2.9268670e-03] [1. 0. 0.]
Использование пользовательских выражений генератора: Согласно документации мы можем использовать любой генератор для получения данных.Ожидается, что генератор будет выдавать пакеты данных и обходить весь набор данных бесконечно.При использовании tf.keras.utils.Sequence
нам не нужно указывать параметр steps_per_epoch
, так как по умолчанию он будет len(train_generator)
.Следовательно, при использовании пользовательского генератора мы также предоставляем этот параметр:
import itertools as it
model.fit_generator(((x_train[i % len(x_train)][None, :, :],
y_train[i % len(y_train)][None, :]) for i in it.count()),
epochs=1000,
steps_per_epoch=len(x_train))