Керас: модель CNN не учится - PullRequest
3 голосов
/ 20 апреля 2019

Я хочу тренировать модель, чтобы предсказывать свои эмоции по физическим сигналам.У меня есть физический сигнал, и я использую его в качестве входной функции;

ЭКГ (электрокардиография)

В моем наборе данных имеется 312 всего записей, принадлежащихучастникам и в каждой записи есть 18000 строк данных.Поэтому, когда я объединяю их в один фрейм данных, получается всего 5616000 строк.

Вот мой train_x массив данных;

            ecg  
0        0.1912 
1        0.3597 
2        0.3597 
3        0.3597 
4        0.3597 
5        0.3597 
6        0.2739 
7        0.1641 
8        0.0776 
9        0.0005 
10      -0.0375 
11      -0.0676 
12      -0.1071 
13      -0.1197 
..      ....... 
..      ....... 
..      ....... 
5616000 0.0226  

И у меня есть 6 классов, которые соответствуют эмоциям.Я закодировал эти метки числами:

гнев = 0, спокойствие = 1, отвращение = 2, страх = 3, счастье = 4, грусть = 5

Здесьэто мой train_y;

         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,1) 
train_y = train_y.values.reshape(312,18000)
train_y = train_y[:,:1]  # truncated train_y to have single corresponding value to a complete signal.
train_y = pd.DataFrame(train_y)
train_y = pd.get_dummies(train_y[0]) #one hot encoded labels

После этих процессов вот как они выглядят; train_x после изменения формы;

[[[0.60399908]
  [0.79763273]
  [0.79763273]
  ...
  [0.09779361]
  [0.09779361]
  [0.14732245]]

 [[0.70386905]
  [0.95101687]
  [0.95101687]
  ...
  [0.41530258]
  [0.41728671]
  [0.42261905]]

 [[0.75008021]
  [1.        ]
  [1.        ]
  ...
  [0.46412148]
  [0.46412148]
  [0.46412148]]

 ...

 [[0.60977509]
  [0.7756791 ]
  [0.7756791 ]
  ...
  [0.12725148]
  [0.02755331]
  [0.02755331]]

 [[0.59939494]
  [0.75514785]
  [0.75514785]
  ...
  [0.0391334 ]
  [0.0391334 ]
  [0.0578706 ]]

 [[0.5786066 ]
  [0.71539303]
  [0.71539303]
  ...
  [0.41355098]
  [0.41355098]
  [0.4112712 ]]]

train_y после одного горячего кодирования;

    0  1  2  3  4  5
0    1  0  0  0  0  0
1    1  0  0  0  0  0
2    0  1  0  0  0  0
3    0  1  0  0  0  0
4    0  0  0  0  0  1
5    0  0  0  0  0  1
6    0  0  1  0  0  0
7    0  0  1  0  0  0
8    0  0  0  1  0  0
9    0  0  0  1  0  0
10   0  0  0  0  1  0
11   0  0  0  0  1  0
12   0  0  0  1  0  0
13   0  0  0  1  0  0
14   0  1  0  0  0  0
15   0  1  0  0  0  0
16   1  0  0  0  0  0
17   1  0  0  0  0  0
18   0  0  1  0  0  0
19   0  0  1  0  0  0
20   0  0  0  0  1  0
21   0  0  0  0  1  0
22   0  0  0  0  0  1
23   0  0  0  0  0  1
24   0  0  0  0  0  1
25   0  0  0  0  0  1
26   0  0  1  0  0  0
27   0  0  1  0  0  0
28   0  1  0  0  0  0
29   0  1  0  0  0  0
..  .. .. .. .. .. ..
282  0  0  0  1  0  0
283  0  0  0  1  0  0
284  1  0  0  0  0  0
285  1  0  0  0  0  0
286  0  0  0  0  1  0
287  0  0  0  0  1  0
288  1  0  0  0  0  0
289  1  0  0  0  0  0
290  0  1  0  0  0  0
291  0  1  0  0  0  0
292  0  0  0  1  0  0
293  0  0  0  1  0  0
294  0  0  1  0  0  0
295  0  0  1  0  0  0
296  0  0  0  0  0  1
297  0  0  0  0  0  1
298  0  0  0  0  1  0
299  0  0  0  0  1  0
300  0  0  0  1  0  0
301  0  0  0  1  0  0
302  0  0  1  0  0  0
303  0  0  1  0  0  0
304  0  0  0  0  0  1
305  0  0  0  0  0  1
306  0  1  0  0  0  0
307  0  1  0  0  0  0
308  0  0  0  0  1  0
309  0  0  0  0  1  0
310  1  0  0  0  0  0
311  1  0  0  0  0  0

[312 rows x 6 columns]

После изменения формы я создал свою модель CNN;

model = Sequential()
model.add(Conv1D(100,700,activation='relu',input_shape=(18000,1))) #kernel_size is 700 because 18000 rows = 60 seconds so 700 rows = ~2.33 seconds and there is two heart beat peak in every 2 second for ecg signal.
model.add(Conv1D(50,700))
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling1D(4))
model.add(Flatten())
model.add(Dense(6,activation='softmax'))

adam = keras.optimizers.Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)

model.compile(optimizer = adam, loss = 'categorical_crossentropy', metrics = ['acc'])
model.fit(train_x,train_y,epochs = 50, batch_size = 32, validation_split=0.33, shuffle=False)

Проблема в том, что точность не превышает 0,2 и колеблется вверх и вниз.Похоже, модель ничего не изучает.Я попытался увеличить слои , играть со скоростью обучения , изменить функцию потерь , изменить оптимизатор , масштабированиеданные , нормализуют данные , но ничего не помогло мне решить эту проблему.Я также попробовал более простые модели Dense или модели LSTM, но не могу найти способ, который работает.

Как я могу решить эту проблему?Заранее спасибо.

Дополнение:

Я хотел добавить результаты тренировок после 50 эпох;

Epoch 1/80
249/249 [==============================] - 24s 96ms/step - loss: 2.3118 - acc: 0.1406 - val_loss: 1.7989 - val_acc: 0.1587
Epoch 2/80
249/249 [==============================] - 19s 76ms/step - loss: 2.0468 - acc: 0.1647 - val_loss: 1.8605 - val_acc: 0.2222
Epoch 3/80
249/249 [==============================] - 19s 76ms/step - loss: 1.9562 - acc: 0.1767 - val_loss: 1.8203 - val_acc: 0.2063
Epoch 4/80
249/249 [==============================] - 19s 75ms/step - loss: 1.9361 - acc: 0.2169 - val_loss: 1.8033 - val_acc: 0.1905
Epoch 5/80
249/249 [==============================] - 19s 74ms/step - loss: 1.8834 - acc: 0.1847 - val_loss: 1.8198 - val_acc: 0.2222
Epoch 6/80
249/249 [==============================] - 19s 75ms/step - loss: 1.8278 - acc: 0.2410 - val_loss: 1.7961 - val_acc: 0.1905
Epoch 7/80
249/249 [==============================] - 19s 75ms/step - loss: 1.8022 - acc: 0.2450 - val_loss: 1.8092 - val_acc: 0.2063
Epoch 8/80
249/249 [==============================] - 19s 75ms/step - loss: 1.7959 - acc: 0.2369 - val_loss: 1.8005 - val_acc: 0.2222
Epoch 9/80
249/249 [==============================] - 19s 75ms/step - loss: 1.7234 - acc: 0.2610 - val_loss: 1.7871 - val_acc: 0.2381
Epoch 10/80
249/249 [==============================] - 19s 75ms/step - loss: 1.6861 - acc: 0.2972 - val_loss: 1.8017 - val_acc: 0.1905
Epoch 11/80
249/249 [==============================] - 19s 75ms/step - loss: 1.6696 - acc: 0.3173 - val_loss: 1.7878 - val_acc: 0.1905
Epoch 12/80
249/249 [==============================] - 19s 75ms/step - loss: 1.5868 - acc: 0.3655 - val_loss: 1.7771 - val_acc: 0.1270
Epoch 13/80
249/249 [==============================] - 19s 75ms/step - loss: 1.5751 - acc: 0.3936 - val_loss: 1.7818 - val_acc: 0.1270
Epoch 14/80
249/249 [==============================] - 19s 75ms/step - loss: 1.5647 - acc: 0.3735 - val_loss: 1.7733 - val_acc: 0.1429
Epoch 15/80
249/249 [==============================] - 19s 75ms/step - loss: 1.4621 - acc: 0.4177 - val_loss: 1.7759 - val_acc: 0.1270
Epoch 16/80
249/249 [==============================] - 19s 75ms/step - loss: 1.4519 - acc: 0.4498 - val_loss: 1.8005 - val_acc: 0.1746
Epoch 17/80
249/249 [==============================] - 19s 75ms/step - loss: 1.4489 - acc: 0.4378 - val_loss: 1.8020 - val_acc: 0.1270
Epoch 18/80
249/249 [==============================] - 19s 75ms/step - loss: 1.4449 - acc: 0.4297 - val_loss: 1.7852 - val_acc: 0.1587
Epoch 19/80
249/249 [==============================] - 19s 75ms/step - loss: 1.3600 - acc: 0.5301 - val_loss: 1.7922 - val_acc: 0.1429
Epoch 20/80
249/249 [==============================] - 19s 75ms/step - loss: 1.3349 - acc: 0.5422 - val_loss: 1.8061 - val_acc: 0.2222
Epoch 21/80
249/249 [==============================] - 19s 75ms/step - loss: 1.2885 - acc: 0.5622 - val_loss: 1.8235 - val_acc: 0.1746
Epoch 22/80
249/249 [==============================] - 19s 75ms/step - loss: 1.2291 - acc: 0.5823 - val_loss: 1.8173 - val_acc: 0.1905
Epoch 23/80
249/249 [==============================] - 19s 75ms/step - loss: 1.1890 - acc: 0.6506 - val_loss: 1.8293 - val_acc: 0.1905
Epoch 24/80
249/249 [==============================] - 19s 75ms/step - loss: 1.1473 - acc: 0.6627 - val_loss: 1.8274 - val_acc: 0.1746
Epoch 25/80
249/249 [==============================] - 19s 75ms/step - loss: 1.1060 - acc: 0.6747 - val_loss: 1.8142 - val_acc: 0.1587
Epoch 26/80
249/249 [==============================] - 19s 75ms/step - loss: 1.0210 - acc: 0.7510 - val_loss: 1.8126 - val_acc: 0.1905
Epoch 27/80
249/249 [==============================] - 19s 75ms/step - loss: 0.9699 - acc: 0.7631 - val_loss: 1.8094 - val_acc: 0.1746
Epoch 28/80
249/249 [==============================] - 19s 75ms/step - loss: 0.9127 - acc: 0.8193 - val_loss: 1.8012 - val_acc: 0.1746
Epoch 29/80
249/249 [==============================] - 19s 75ms/step - loss: 0.9176 - acc: 0.7871 - val_loss: 1.8371 - val_acc: 0.1746
Epoch 30/80
249/249 [==============================] - 19s 75ms/step - loss: 0.8725 - acc: 0.8233 - val_loss: 1.8215 - val_acc: 0.1587
Epoch 31/80
249/249 [==============================] - 19s 75ms/step - loss: 0.8316 - acc: 0.8514 - val_loss: 1.8010 - val_acc: 0.1429
Epoch 32/80
249/249 [==============================] - 19s 75ms/step - loss: 0.7958 - acc: 0.8474 - val_loss: 1.8594 - val_acc: 0.1270
Epoch 33/80
249/249 [==============================] - 19s 75ms/step - loss: 0.7452 - acc: 0.8795 - val_loss: 1.8260 - val_acc: 0.1587
Epoch 34/80
249/249 [==============================] - 19s 75ms/step - loss: 0.7395 - acc: 0.8916 - val_loss: 1.8191 - val_acc: 0.1587
Epoch 35/80
249/249 [==============================] - 19s 75ms/step - loss: 0.6794 - acc: 0.9357 - val_loss: 1.8344 - val_acc: 0.1429
Epoch 36/80
249/249 [==============================] - 19s 75ms/step - loss: 0.6106 - acc: 0.9357 - val_loss: 1.7903 - val_acc: 0.1111
Epoch 37/80
249/249 [==============================] - 19s 75ms/step - loss: 0.5609 - acc: 0.9598 - val_loss: 1.7882 - val_acc: 0.1429
Epoch 38/80
249/249 [==============================] - 19s 75ms/step - loss: 0.5788 - acc: 0.9478 - val_loss: 1.8036 - val_acc: 0.1905
Epoch 39/80
249/249 [==============================] - 19s 75ms/step - loss: 0.5693 - acc: 0.9398 - val_loss: 1.7712 - val_acc: 0.1746
Epoch 40/80
249/249 [==============================] - 19s 75ms/step - loss: 0.4911 - acc: 0.9598 - val_loss: 1.8497 - val_acc: 0.1429
Epoch 41/80
249/249 [==============================] - 19s 75ms/step - loss: 0.4824 - acc: 0.9518 - val_loss: 1.8105 - val_acc: 0.1429
Epoch 42/80
249/249 [==============================] - 19s 75ms/step - loss: 0.4198 - acc: 0.9759 - val_loss: 1.8332 - val_acc: 0.1111
Epoch 43/80
249/249 [==============================] - 19s 75ms/step - loss: 0.3890 - acc: 0.9880 - val_loss: 1.9316 - val_acc: 0.1111
Epoch 44/80
249/249 [==============================] - 19s 75ms/step - loss: 0.3762 - acc: 0.9920 - val_loss: 1.8333 - val_acc: 0.1746
Epoch 45/80
249/249 [==============================] - 19s 75ms/step - loss: 0.3510 - acc: 0.9880 - val_loss: 1.8090 - val_acc: 0.1587
Epoch 46/80
249/249 [==============================] - 19s 75ms/step - loss: 0.3306 - acc: 0.9880 - val_loss: 1.8230 - val_acc: 0.1587
Epoch 47/80
249/249 [==============================] - 19s 75ms/step - loss: 0.2814 - acc: 1.0000 - val_loss: 1.7843 - val_acc: 0.2222
Epoch 48/80
249/249 [==============================] - 19s 75ms/step - loss: 0.2794 - acc: 1.0000 - val_loss: 1.8147 - val_acc: 0.2063
Epoch 49/80
249/249 [==============================] - 19s 75ms/step - loss: 0.2430 - acc: 1.0000 - val_loss: 1.8488 - val_acc: 0.1587
Epoch 50/80
249/249 [==============================] - 19s 75ms/step - loss: 0.2216 - acc: 1.0000 - val_loss: 1.8215 - val_acc: 0.1587

Ответы [ 8 ]

4 голосов
/ 24 апреля 2019

Я бы рекомендовал сделать несколько шагов назад и рассмотреть более простой подход.
На основании следующего ...

Я пытался увеличить слои, поиграть со скоростью обучения, изменить функцию потерь, изменить оптимизатор, масштабировать данные, нормализовать данные, но ничего не помогло мне решить эту проблему. Я также пробовал более простые модели Dense или модели LSTM, но не могу найти способ, который работает.

Не похоже, что у вас есть такое сильное понимание ваших данных и инструментов ... что хорошо, потому что это возможность учиться.

Несколько вопросов

  1. У вас есть модель базовой линии? Вы пробовали просто запустить полиномиальную логистическую регрессию? Если нет, я бы настоятельно рекомендовал начать там. Прохождение разработки функций, необходимых для создания такой модели, будет иметь неоценимое значение, поскольку вы увеличиваете сложность своей модели.

  2. Вы проверяли дисбаланс классов?

  3. Почему вы используете CNN? Что вы хотите достичь с помощью сверточных слоев? Для меня, когда я строю модель зрения, скажем, для классификации обуви в моем шкафу, я использую несколько сверточных слоев для выделения пространственных объектов, таких как ребра и изгибы.

  4. В связи с третьим вопросом ... Откуда вы взяли эту архитектуру? Это из публикации? Это современная модель следов ЭКГ? Или это самая доступная модель? Иногда эти два не совпадают. Я бы покопался в литературе и немного поискал в сети, чтобы найти больше информации о нейронных сетях и анализе следов ЭКГ.

Я думаю, что если вы сможете ответить на эти вопросы, вы сможете решить свою проблему самостоятельно.

1 голос
/ 25 апреля 2019

Текущая проблема в вашей реализации заключается в том, что вы использовали данные для формы (312,18000,1) для своей модели, у вас есть только 312 выборок, и вы использовали разделение проверки на 0,33, то есть вы используете только 209 выборок для целей обучения.

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv1d_1 (Conv1D)            (None, 17301, 100)        70100     
_________________________________________________________________
conv1d_2 (Conv1D)            (None, 16602, 50)         3500050   
_________________________________________________________________
dropout_1 (Dropout)          (None, 16602, 50)         0         
_________________________________________________________________
batch_normalization_1 (Batch (None, 16602, 50)         200       
_________________________________________________________________
activation_1 (Activation)    (None, 16602, 50)         0         
_________________________________________________________________
max_pooling1d_1 (MaxPooling1 (None, 4150, 50)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 207500)            0         
_________________________________________________________________
dense_1 (Dense)              (None, 6)                 1245006   
=================================================================
Total params: 4,815,356
Trainable params: 4,815,256
Non-trainable params: 100
_________________________________________________________________

Как я видел model.summary(), ваша модель имеет 4815256 обучаемых параметров. Таким образом, ваша модель легко переписывает тренировочные данные. Проблема в том, что у вас так много параметров для изучения без достаточного количества образцов. Вы можете попробовать уменьшить размер вашей модели, как показано ниже:

model = Sequential()
model.add(Conv1D(100,2,activation='relu',input_shape=(18000,1))) 
model.add(Conv1D(10,2))
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling1D(4))
model.add(Flatten())
model.add(Dense(6,activation='softmax'))
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv1d_1 (Conv1D)            (None, 17999, 100)        300       
_________________________________________________________________
conv1d_2 (Conv1D)            (None, 17998, 10)         2010      
_________________________________________________________________
dropout_1 (Dropout)          (None, 17998, 10)         0         
_________________________________________________________________
batch_normalization_1 (Batch (None, 17998, 10)         40        
_________________________________________________________________
activation_1 (Activation)    (None, 17998, 10)         0         
_________________________________________________________________
max_pooling1d_1 (MaxPooling1 (None, 4499, 10)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 44990)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 6)                 269946    
=================================================================
Total params: 272,296
Trainable params: 272,276
Non-trainable params: 20
_________________________________________________________________

Как я знаю, у вас есть 3 типа данных ecg, gsr, temp. Таким образом, вы можете использовать train_x как (312,18000,3). и ваш train_y будет (312,6).

Если вышеуказанное решение не работает,

  1. Составьте график распределения классов из вашего набора данных и проверьте, есть ли Классовый дисбаланс в данных.
  2. Поскольку ваша модель соответствует данным, попробуйте создать больше данных (если этот набор данных создан вами) или найдите для этого какой-либо метод увеличения данных.
0 голосов
/ 01 мая 2019

Ваша модель явно соответствует набору данных. Одно из предположений, которое никто не учел среди комментаторов, - увеличить шаг. Здесь у вас есть kernel size = 700, без отступов и stride = 1. Таким образом, вы получите вывод с формой (None, 17301, 100) из первого слоя Conv.

Я бы попытался либо увеличить шаг до числа от 50 до 100 (смещая ваше ядро ​​на доли 2.33/(700/stride) секунд), либо вставить слой Pooling после каждого из слоев Conv.

0 голосов
/ 30 апреля 2019

Я столкнулся с проблемой ЭКГ, когда год назад выполнил свое последнее задание в колледже, но с другим подходом и данными (MIT-BIH).

Кажется, вы используете один провод, не так ли? Вы пытались подготовить данные перед тем, как их почистить (учтите шум сердцебиения)? Мое предложение состоит в том, чтобы не объединять все данные в один список для обучения, которое может происходить более подходящим образом из-за характера сердцебиения человека, стараться проводить обучение с учетом пола или возраста. В некоторой литературе это довольно помогает.

Модель не работает должным образом не из-за неправильной реализации, а иногда из-за того, как мы хорошо подготавливаем данные.

0 голосов
/ 26 апреля 2019

Я бы предложил следующее:

  1. Я вижу, что количество точек данных меньше.Чем сложнее проблема, тем больше данных требуется для углубленного изучения модели.Ищите подобный набор данных с большим количеством данных.Обучите свою сеть на этом наборе данных и перенесите ее в свою проблему.

  2. Есть ли способ дополнить данные ??Я вижу, что длина вашего сигнала равна 18000. Вы можете уменьшить выборку данных наполовину, используя различные методы, и увеличить набор данных.Вы будете работать с сигналом длиной 9000.

  3. Попробуйте уменьшить длину ядра свертки до 3 или 5 и увеличьте глубину модели, добавив еще один слой сверток.

  4. Я бы настоятельно рекомендовал попробовать случайные лесные деревья с градиентом и посмотреть, как они работают.

0 голосов
/ 22 апреля 2019

Я сомневаюсь, что способ train_y был предварительно обработан, он не мог правильно синхронизироваться с вашим train_x.Мой вопрос был бы: ты сжал свой y_train, следуя какой-то частотной технике?
Я думаю, что если вы сжимали свои метки (для каждой строки) с помощью какой-то частотной техники, вы уже внесли большой уклон в свои данные.Дайте мне знать, как было сделано сжатие!Спасибо

0 голосов
/ 21 апреля 2019

Вы можете попытаться добавить регуляризатор (ы) (L1 или L2), поставить отметку kernel_initializer и / или настроить скорость обучения во время обучения с помощью обратных вызовов. Пример ниже взят из регрессионной модели.

model = Sequential()
model.add(Dense(128, input_dim=dims, activation='relu'))
model.add(Dropout(0.2))
model.add(layers.BatchNormalization())
model.add(Dense(16, activation='relu', kernel_initializer='normal', kernel_regularizer=regularizers.l1(x)))
model.add(Dropout(0.2))
model.add(layers.BatchNormalization())
model.add(Dense(1, kernel_initializer='normal'))

model.compile(optimizer=optimizers.adam(lr=l), loss='mean_squared_error')

reduce_lr = ReduceLROnPlateau(monitor='val_loss', mode='min', factor=0.5, patience=3, min_lr=0.000001, verbose=1, cooldown=0)

history = model.fit(xtrain, ytrain, epochs=epochs, batch_size=batch_size, validation_split=0.3, callbacks=[reduce_lr])
0 голосов
/ 20 апреля 2019

Я считаю, что ваш код верен, но, как сказал комментатор, вы, вероятно, перегрузили свои данные.

Возможно, вы захотите отобразить точность проверки и точность обучения по эпохам, чтобы визуализировать это.

Вы должны сначала рассмотреть вопрос об улучшении вашей проблемы с более простой моделью. Обратите внимание, что это вряд ли улучшит вашу общую производительность, но ваша точность проверки будет более точно соответствовать вашей точности обучения. Другой вариант - добавить пул сразу после слоев свертки.

...