Почему прогнозы моей модели keras CNN всегда одинаковы? - PullRequest
1 голос
/ 30 мая 2020

Я обучил модель CNN классифицировать сигналы ЭКГ на 4 разных класса и впоследствии сохранил ее. Теперь я загрузил его и попытался предсказать некоторые вещи с его помощью, и я даю ему 32 сигнала ЭКГ. Итак, первый прогноз всегда дает мне 4 разных процента, но следующие 31 идентичны друг другу. Кто-нибудь знает почему? Полный код можно найти здесь: https://github.com/awerdich/physionet

# Convolutional blocks
def conv2d_block(model, depth, layer_filters, filters_growth, 
                 strides_start, strides_end, input_shape, first_layer = False):

    ''' Convolutional block. 
    depth: number of convolutional layers in the block (4)
    filters: 2D kernel size (32)
    filters_growth: kernel size increase at the end of block (32)
    first_layer: provide input_shape for first layer'''

    # Fixed parameters for convolution
    conv_parms = {'kernel_size': (3, 3),
                  'padding': 'same',
                  'dilation_rate': (1, 1),
                  'activation': None,
                  'data_format': 'channels_last',
                  'kernel_initializer': 'glorot_normal'}

    for l in range(depth):

        if first_layer:

            # First layer needs an input_shape 
            model.add(layers.Conv2D(filters = layer_filters,
                                    strides = strides_start,
                                    input_shape = input_shape, **conv_parms))
            first_layer = False

        else:
            # All other layers will not need an input_shape parameter
            if l == depth - 1:
                # Last layer in each block is different: adding filters and using stride 2
                layer_filters += filters_growth
                model.add(layers.Conv2D(filters = layer_filters,
                                        strides = strides_end, **conv_parms))
            else:
                model.add(layers.Conv2D(filters = layer_filters,
                                        strides = strides_start, **conv_parms))

        # Continue with batch normalization and activation for all layers in the block
        model.add(layers.BatchNormalization(center = True, scale = True))
        model.add(layers.Activation('relu'))

    return model

def MeanOverTime():
    lam_layer = layers.Lambda(lambda x: K.mean(x, axis=1), output_shape=lambda s: (1, s[2]))
    return lam_layer

# Define the model
# Model parameters
filters_start = 32 # Number of convolutional filters
layer_filters = filters_start # Start with these filters
filters_growth = 32 # Filter increase after each convBlock
strides_start = (1, 1) # Strides at the beginning of each convBlock
strides_end = (2, 2) # Strides at the end of each convBlock
depth = 4 # Number of convolutional layers in each convBlock
n_blocks = 6 # Number of ConBlocks
n_channels = 1 # Number of color channgels
input_shape = (*dim, n_channels) # input shape for first layer


model = Sequential()

for block in range(n_blocks):

    # Provide input only for the first layer
    if block == 0:
        provide_input = True
    else:
        provide_input = False

    model = conv2d_block(model, depth,
                         layer_filters,
                         filters_growth,
                         strides_start, strides_end,
                         input_shape,
                         first_layer = provide_input)

    # Increase the number of filters after each block
    layer_filters += filters_growth



# Remove the frequency dimension, so that the output can feed into LSTM
# Reshape to (batch, time steps, filters)
model.add(layers.Reshape((-1, 224)))
model.add(layers.core.Masking(mask_value = 0.0))
model.add(MeanOverTime())

# Alternative: Replace averaging by LSTM

# Insert masking layer to ignore zeros
#model.add(layers.core.Masking(mask_value = 0.0))

# Add LSTM layer with 3 neurons
#model.add(layers.LSTM(200))
#model.add(layers.Flatten())

# And a fully connected layer for the output
model.add(layers.Dense(4, activation='sigmoid', kernel_regularizer = regularizers.l2(0.1)))


model.summary()

# Compile the model and run a batch through the network
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.Adam(lr=0.001),
              metrics=['acc'])

history = model.fit_generator(generator = train_generator,
                              steps_per_epoch = 50,
                              epochs = 10,
                              validation_data = val_generator,
                              validation_steps = 50)

model.save('PredictionTest.model')

для прогноза я немного изменил пакетный генератор:

def __data_generation(h5file, list_IDs, batch_size, dim, nperseg, noverlap, n_channels, sequence_length, n_classes, shuffle):
    'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
    # Initialization
    X = np.empty((batch_size, *dim, n_channels), dtype = float)
    y = np.empty((batch_size), dtype = int)
    # Generate data
    for i, ID in enumerate(list_IDs):
        data = extend_ts(h5file[ID]['ecgdata'][:, 0], sequence_length)
        data = np.reshape(data, (1, len(data)))

        # Generate spectrogram
        data_spectrogram = spectrogram(data, nperseg = nperseg, noverlap = noverlap)[2]   

        # Normalize
        data_norm = (data_spectrogram - np.mean(data_spectrogram))/np.std(data_spectrogram)

        X[i,] = np.expand_dims(data_norm, axis = 3)

        return X

я даю ему немного параметры и поместите 32 сигнала в val_generator (я знаю, что это не генератор прямо сейчас)

params = {'batch_size': batch_size,
          'dim': dim,
          'nperseg': spectrogram_nperseg,
          'noverlap': spectrogram_noverlap,
          'n_channels': 1,
          'sequence_length': sequence_length,
          'n_classes': n_classes,
          'shuffle': True}

val_generator = __data_generation(h5file, dataset_list, **params)

тогда, когда я пытаюсь его предсказать

from keras.models import load_model
model = load_model("Physionet17_ECG_CNN.model")
prediction = model.predict(val_generator)
print(prediction)

, я получаю эти прогнозы

[[1.9367344e-03 9.4601721e-01 6.0286120e-02 1.1672693e-03]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]
 [3.3482336e-04 6.3787904e-03 5.1438063e-02 9.9722642e-01]]

Кто-нибудь знает, почему это происходит? Спасибо

На случай, если кто-то захочет увидеть весь код прогноза

import tensorflow as tf
import numpy as np
import pandas as pd
import os
import h5py
import matplotlib
import scipy.io
import cv2
import numpy as np
from matplotlib import pyplot as plt

# Magic
%matplotlib inline
matplotlib.style.use('ggplot')

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder

# Keras5
import keras
from keras.models import Sequential
from keras import layers
from keras import optimizers
from keras import backend as K
from keras import regularizers

# Tensorflow -- the info from the devices used
import tensorflow as tf
from tensorflow.python.client import device_lib

# Custom imports
from physionet_processing import (fetch_h5data, spectrogram, 
                                  special_parameters, transformed_stats, extend_ts)

from physionet_generator_Copy1 import DataGeneratorAdib

### Open hdf5 file, load the labels and define training/validation splits ###

# Data folder and hdf5 dataset file
data_root = os.path.normpath('.')
hd_file = os.path.join(data_root, 'physioANDptb.h5')

# Open hdf5 file
h5file =  h5py.File(hd_file, 'r')
print(h5file)
# Get a list of dataset names -- keys()-gives the list of all attributes
dataset_list = list(h5file.keys())
#print(dataset_list)
# Encode labels to integer numbers
label_set = ['A', 'N', 'O', '~']
encoder = LabelEncoder().fit(label_set)
label_set_codings = [0, 1, 2, 3]

### Set up batch generators ###

# Parameters needed for the batch generator
# Maximum sequence length
max_length = 18286

# Output dimensions
sequence_length = max_length
spectrogram_nperseg = 64 # Spectrogram window
spectrogram_noverlap = 32 # Spectrogram overlap
n_classes = len(label_set)

batch_size = 32

# import ipdb; ipdb.set_trace() # debugging starts here

# calculate image dimensions
data = fetch_h5data(h5file, [0], sequence_length)# fetch some raw sequences from the hdf5 file
_, _, Sxx = spectrogram(data, nperseg = spectrogram_nperseg, noverlap = spectrogram_noverlap)
dim = Sxx[0].shape
print(data.shape)

# print(dataset_list)

def __data_generation(h5file, list_IDs, batch_size, dim, nperseg, noverlap, n_channels, sequence_length, n_classes, shuffle):
    'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
    # Initialization
    X = np.empty((batch_size, *dim, n_channels), dtype = float)
    y = np.empty((batch_size), dtype = int)
    # Generate data
    for i, ID in enumerate(list_IDs):
        data = extend_ts(h5file[ID]['ecgdata'][:, 0], sequence_length)
        data = np.reshape(data, (1, len(data)))

        # Generate spectrogram
        data_spectrogram = spectrogram(data, nperseg = nperseg, noverlap = noverlap)[2]   

        # Normalize
        data_norm = (data_spectrogram - np.mean(data_spectrogram))/np.std(data_spectrogram)

        X[i,] = np.expand_dims(data_norm, axis = 3)

        return X

params = {'batch_size': batch_size,
          'dim': dim,
          'nperseg': spectrogram_nperseg,
          'noverlap': spectrogram_noverlap,
          'n_channels': 1,
          'sequence_length': sequence_length,
          'n_classes': n_classes,
          'shuffle': True}


val_generator = __data_generation(h5file, dataset_list, **params)

for i, batch in enumerate(val_generator):
    if i == 1:
        break


from keras.models import load_model
model = load_model("Physionet17_ECG_CNN_E50_SPE200.model")

val_generator = np.arange(18810*3)
val_generator = val_generator.reshape(3, 570, 33, 1)
# bla1 = np.arange(18810)
# bla1 = bla1.reshape(1, 570, 33, 1)
# val_generator(2,)= bla1
val_generator.shape

val_generator = np.random.random((32, 570, 33, 1))


prediction = model.predict(val_generator)
print(prediction)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...