Почему у классификатора персептрона Spark ML высокий показатель F1, а та же модель на TensorFlow работает очень плохо? - PullRequest
0 голосов
/ 30 ноября 2018

Наша команда работает над проблемой НЛП.У нас есть набор данных с некоторыми помеченными предложениями, и мы должны классифицировать их на два класса , 0 или 1.

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

Поскольку данные очень искажены , мы измеряем балл модели с помощью балла F1, вычисляя егокак в наборе поездов (80%), так и в тестовом наборе (20%).

Spark

Мы использовали многослойный классификатор персептрона , представленный в MLlib PySpark:

layers = [300, 600, 2]

trainer = MultilayerPerceptronClassifier(featuresCol='features', labelCol='target',
                                         predictionCol='prediction', maxIter=10, layers=layers,
                                         blockSize=128)
model = trainer.fit(train_df)
result = model.transform(test_df)

predictionAndLabels = result.select("prediction", "target").withColumnRenamed("target", "label")
evaluator = MulticlassClassificationEvaluator(metricName="f1")
f1_score = evaluator.evaluate(predictionAndLabels)

Таким образом, мы получаем оценки F1 в диапазоне от 0,91 до 0,93.

TensorFlow

Затем мы решили переключиться (в основном для целей обучения) на TensorFlow, поэтому мы реализовалинейронная сеть, использующая ту же архитектуру и формулы, что и MLlib:

# Network Parameters
n_input = 300
n_hidden_1 = 600
n_classes = 2

# TensorFlow graph input
features = tf.placeholder(tf.float32, shape=(None, n_input), name='inputs')
labels = tf.placeholder(tf.float32, shape=(None, n_classes), name='labels')

# Initializes weights and biases
init_biases_and_weights()

# Layers definition
layer_1 = tf.add(tf.matmul(features, weights['h1']), biases['b1'])
layer_1 = tf.nn.sigmoid(layer_1)

out_layer = tf.matmul(layer_1, weights['out']) + biases['out']
out_layer = tf.nn.softmax(out_layer)

# Optimizer definition
learning_rate_ph = tf.placeholder(tf.float32, shape=(), name='learning_rate')
loss_function = tf.losses.log_loss(labels=labels, predictions=out_layer)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate_ph).minimize(loss_function)

# Start TensorFlow session
init = tf.global_variables_initializer()
tf_session = tf.InteractiveSession()
tf_session.run(init)

# Train Neural Network
learning_rate = 0.01
iterations = 100
batch_size = 256

total_batch = int(len(y_train) / batch_size)
for epoch in range(iterations):
    avg_cost = 0.0
    for block in range(total_batch):
        batch_x = x_train[block * batch_size:min(block * batch_size + batch_size, len(x_train)), :]
        batch_y = y_train[block * batch_size:min(block * batch_size + batch_size, len(y_train)), :]
        _, c = tf_session.run([optimizer, loss_function], feed_dict={learning_rate_ph: learning_rate,
                                                                     features: batch_x,
                                                                     labels: batch_y})
        avg_cost += c
    avg_cost /= total_batch
    print("Iteration " + str(epoch + 1) + " Logistic-loss=" + str(avg_cost))

# Make predictions
predictions_train = tf_session.run(out_layer, feed_dict={features: x_train, labels: y_train})
predictions_test = tf_session.run(out_layer, feed_dict={features: x_test, labels: y_test})

# Compute F1-score
f1_score = f1_score_tf(y_test, predictions_test)

Функции поддержки:

def initialize_weights_and_biases():
    global weights, biases
    epsilon_1 = sqrt(6) / sqrt(n_input + n_hidden_1)
    epsilon_2 = sqrt(6) / sqrt(n_classes + n_hidden_1)
    weights = {
        'h1': tf.Variable(tf.random_uniform([n_input, n_hidden_1],
                                        minval=0 - epsilon_1, maxval=epsilon_1, dtype=tf.float32)),
        'out': tf.Variable(tf.random_uniform([n_hidden_1, n_classes],
                                         minval=0 - epsilon_2, maxval=epsilon_2, dtype=tf.float32))
    }
    biases = {
        'b1': tf.Variable(tf.constant(1, shape=[n_hidden_1], dtype=tf.float32)),
        'out': tf.Variable(tf.constant(1, shape=[n_classes], dtype=tf.float32))
    }

def f1_score_tf(actual, predicted):
    actual = np.argmax(actual, 1)
    predicted = np.argmax(predicted, 1)

    tp = tf.count_nonzero(predicted * actual)
    fp = tf.count_nonzero(predicted * (actual - 1))
    fn = tf.count_nonzero((predicted - 1) * actual)
    precision = tp / (tp + fp)
    recall = tp / (tp + fn)

    f1 = 2 * precision * recall / (precision + recall)
    return tf.Tensor.eval(f1)

Таким образом, мы получаем оценки F1 в диапазоне от 0,24 до 0,25.

Вопрос

Единственный дЗначения, которые я вижу между двумя нейронными сетями:

  • Оптимизатор: L-BFGS в Spark, градиентный спуск в TensorFlow
  • Веса иСмещение инициализации: Spark выполняет свою собственную инициализацию, в то время как мы инициализируем их вручную в TensorFlow

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

Я не могу понять, работает ли TensorFlow очень плохо или, возможно, результаты Spark не соответствуют действительности.И в обоих случаях я думаю, что мы не видим чего-то важного.

1 Ответ

0 голосов
/ 30 ноября 2018

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

Вместо этого используйте normal или truncated_normal со значением по умолчанию, равным нулю.среднее значение и небольшая дисперсия для весов:

weights = {
        'h1': tf.Variable(tf.truncated_normal([n_input, n_hidden_1],
                                        stddev=0.01, dtype=tf.float32)),
        'out': tf.Variable(tf.truncated_normal([n_hidden_1, n_classes],
                                         stddev=0.01, dtype=tf.float32))
    }

и ноль для смещений:

biases = {
        'b1': tf.Variable(tf.constant(0, shape=[n_hidden_1], dtype=tf.float32)),
        'out': tf.Variable(tf.constant(0, shape=[n_classes], dtype=tf.float32))
    }

Тем не менее, яЯ не уверен в правильности использования MulticlassClassificationEvaluator для задачи двоичной классификации, и я бы предложил провести дополнительные проверки вручную, чтобы убедиться, что функция действительно возвращает то, что, как вы думаете, она возвращает ...

...