#python #tensorflow #keras
#питон #тензорный поток #keras
Вопрос:
Я хочу обучить модель предсказывать эмоции человека по физическим сигналам. У меня есть три физических сигнала, и я использую их в качестве входных функций;
экг (электрокардиография), gsr (кожно-гальваническая реакция), temp (температура)
В моем наборе данных всего 312 записей, принадлежащих участникам, и в каждой записи содержится 18000 строк данных. Поэтому, когда я объединяю их в один фрейм данных, всего получается 5616000 строк.
Вот мой фрейм данных x_train
;
ecg gsr temp
0 0.1912 0.0000 40.10
1 0.3597 0.0000 40.26
2 0.3597 0.0000 40.20
3 0.3597 0.0000 40.20
4 0.3597 0.0000 40.33
5 0.3597 0.0000 40.03
6 0.2739 0.0039 40.13
7 0.1641 0.0031 40.20
8 0.0776 0.0025 40.20
9 0.0005 0.0020 40.26
10 -0.0375 0.0016 40.03
11 -0.0676 0.0013 40.16
12 -0.1071 0.0010 40.20
13 -0.1197 0.0047 40.20
.. ....... ...... .....
.. ....... ...... .....
.. ....... ...... .....
5616000 0.0226 0.1803 38.43
И у меня есть 6 классов, которые соответствуют эмоциям. Я закодировал эти метки цифрами;
гнев = 0, спокойствие = 1, отвращение = 2, страх = 3, счастье = 4, печаль = 5
Вот мой y_train;
emotion
0 0
1 0
2 0
3 0
4 0
. .
. .
. .
18001 1
18002 1
18003 1
. .
. .
. .
360001 2
360002 2
360003 2
. .
. .
. .
. .
5616000 5
Чтобы передать мой CNN, я изменяю форму train_x и одним горячим способом кодирую данные train_y.
train_x = train_x.values.reshape(312,18000,3) #because I have 18000 rows in each record and 3 input features
train_y = train_y.values.reshape(312,18000)
trunc_train_y = train_y[:,:1] # to get 1 label for every 18000 column vector of signal
train_y_enc = pd.DataFrame(trunc_train_y)
train_y_enc = pd.get_dummies(train_y_enc[0]) # one hot encoded labels
После изменения формы я создал свою модель CNN;
model = Sequential()
model.add(Conv1D(2,700,activation='relu',input_shape=(18000,3)))
model.add(Conv1D(2,700,activation='relu'))
model.add(MaxPooling1D(4))
model.add(Conv1D(2,700,activation='relu'))
model.add(Conv1D(2,700,activation='relu'))
model.add(GlobalAveragePooling1D())
model.add(Dropout(0.5))
model.add(Dense(6,activation='softmax'))
model.compile(optimizer = sgd, loss = 'categorical_crossentropy', metrics = ['acc'])
model.fit(train_x,train_y_enc,epochs = 300, batch_size = 32, validation_split=0.33, shuffle=False)
Проблема в том, что точность не превышает 0,2, и когда я проверяю прогнозы, они всегда предсказывают один и тот же класс. Я пытался увеличить уровни, поиграть со скоростью обучения, изменить функцию потерь, изменить оптимизатор, но ничто не помогло мне решить эту проблему.
Вот матрица путаницы;
Как я могу решить эту проблему? Заранее спасибо.
Комментарии:
1. Ваша обработка данных выглядит очень странно. Я думаю, так и должно быть
(train_sample_length, num_features)
. Кроме того, почему вашаtrain_y
форма(312,18000)
? Должно быть(train_sample_length, num_classes).
, я вижу в вашем случаеnum_features=3
иnum_classes=5
.2. @Anakin, потому что у меня всего 312 разных записей. Я переношу сигналы так, чтобы каждая последовательность сигналов соответствовала одной строке. Таким образом, в каждой строке имеется 18006 столбцов (длина сигнала одна метка с горячим кодированием). Я выполняю операцию транспонирования, потому что я не хочу помечать каждую миллисекунду сигнала, лучше транспонировать его и помечать только один раз.
3. Получил часть 312. Возможно, вам следует рассмотреть все 5616000 строк, перетасовать данные и разделить их на обучение и проверку
4. @Anakin, если я собираюсь перетасовать его в форме с 5616000 строк, тогда вся структура сигналов будет нарушена.
5. Возможно, я неправильно понял вашу проблему. Хорошо, скажите мне: для прогнозирования вы хотите ввести 3D-вектор
[ecg gsr temp]
и предсказатьemotion
?
Ответ №1:
В определении уровня Conv1D допущена ошибка. Из кода очевидно, что вы определили 2 фильтра и ядро размером 700, однако обычно используется около 3 фильтров и большое количество фильтров. Попробуйте использовать это и обучаться без разделения проверки.
`model = Sequential()
model.add(Conv1D(64, 3, activation='relu', input_shape=(18000, 3)))
model.add(Conv1D(64, 3, activation='relu'))
model.add(MaxPooling1D(3))
model.add(Conv1D(128, 3, activation='relu'))
model.add(Conv1D(128, 3, activation='relu'))
model.add(GlobalAveragePooling1D())
model.add(Dropout(0.5))
model.add(Dense(6, activation='softmax')) `
Комментарии:
1. Это скорее комментарий, чем ответ.
2. Если я удалю GlobalAvaragePoolling1D(), это приведет к ошибке.
Error when checking target: expected dense_9 to have 3 dimensions, but got array with shape (312, 6)