Мультиклассовый классификатор персептрона Keras классифицирует все как один класс - PullRequest
0 голосов
/ 02 мая 2019

Мой набор данных имеет следующую форму

[[  1.   337.   118.   ...   9.65   1.     0.92]
 [  2.   324.   107.   ...   8.87   1.     0.76]
 [  3.   316.   104.   ...   8.     1.     0.72]
 ...
 [498.   330.   120.   ...   9.56   1.     0.93]
 [499.   312.   103.   ...   8.43   0.     0.73]
 [500.   327.   113.   ...   9.04   0.     0.84]]

Этот последний столбец является зависимой переменной, все остальные являются независимыми переменными.Первый столбец - это переменная ID, от которой я избавляюсь, потому что я предполагаю, что она не предоставляет никакой информации.

Я сгруппировал зависимую переменную в 5 ячеек, символизирующих 5 классов следующим образом:

X = raw[:,1:8]
Y = raw[:,8]

def mapping(x):
  if (x <= 0.5):
    return 0;
  if (x <= 0.65):
    return 1;
  if (x <= 0.8):
    return 2;
  if (x <= 0.9):
    return 3;
  if (x <= 1):
    return 4;

Y = np.array(list(map(mapping, Y)))

Результирующая частота классов выглядит следующим образом:

(array([0, 1, 2, 3, 4]), array([ 39, 119, 200,  81,  61]))

Так что не похоже, что один класс превалирует над другими.

Однако при запуске моегоМногослойная модель персептрона, она продолжает классифицировать все в одном классе.Какой класс зависит от цикла, но он одинаков для каждой записи.

Моя модель выглядит следующим образом:

Y = to_categorical(Y)

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.33, random_state=10)

learning_rate = 0.001
n_layer_1 = 64
n_layer_2 = 64
num_classes = 5

def build_classification_model(train_set):
  model = keras.Sequential([
    layers.Dense(n_layer_1, activation=tf.nn.relu, input_shape=tuple([train_set.shape[1]])),
    layers.Dense(n_layer_2, activation=tf.nn.relu, ),
    layers.Dense(5, activation=tf.nn.softmax)
  ])

  optimizer = tf.keras.optimizers.SGD()

  model.compile(loss='categorical_crossentropy',
                optimizer=optimizer,
                metrics=['categorical_accuracy', 'mean_squared_error'])
  return model

model = build_classification_model(train_X)
num_epochs = 200

print('Training...')
history = model.fit(train_X, train_Y, batch_size=500, epochs=num_epochs, verbose=0)
print('Done.')
prediction = model.predict(train_X)

С prediction при каждом запуске выглядит так:

array([[2.17507738e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        2.74140113e-14],
       [1.16876501e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        1.38829174e-14],
       [2.22264258e-18, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        4.08135584e-15],
       ...,
       [2.78243342e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        2.62153224e-14],
       [1.69924047e-16, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        1.70491795e-13],
       [5.26733592e-17, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00,
        4.98645043e-14]], dtype=float32)

Обратите внимание, что он выбрал все как класс 3.

Неважно, добавлю ли я новый слой, изменит количество узлов в скрытых слоях или изменит скорость обучения: вероятности для каждой записивыглядят очень похоже.

Что я делаю не так?

Спасибо

1 Ответ

1 голос
/ 02 мая 2019

Сначала я хотел бы предложить две вещи:

  1. Разделение ваших данных стратифицированным образом в течение train_test_split, чтобы убедиться, что в ваших поездах и тестовых наборах содержится репрезентативное количество выборок всех классов.Это легко реализовать:

train_X, test_X, train_Y, test_Y = train_test_split(X, Y, test_size=0.33, random_state=10, stratify=Y)

Это обеспечит обучение модели на достаточном количестве образцов из всех классов.

Размер вашей партии слишком велик, я полагаю, здесь есть недоразумение.При использовании SGD размер пакета - это количество выборок, обработанных сетью до обновления градиента, а не количество имеющихся у вас обучающих примеров.Судя по всему, у вас нет даже 500 учебных примеров.Небольшой размер пакета, часто используются значения по умолчанию 32, обеспечивает многократное обновление градиента за эпоху.Большое количество обновлений градиента гораздо более эффективно для градиентного спуска, который требует небольших шагов при каждом обновлении градиента.200 обновлений, поскольку ваша сеть в данный момент настроена, не так много, учитывая количество параметров, поэтому уменьшите размер пакета!
...