Alvo de treinamento da função de custo versus objetivo desejado da precisão

Quando treinamos redes neurais, normalmente usamos descida em gradiente, que depende de uma função de custo real e diferenciada contínua e diferenciada. A função de custo final pode, por exemplo, levar o erro médio quadrático. Ou, dito de outra maneira, a descida do gradiente assume implicitamente que o objetivo final éregressão - minimizar uma medida de erro com valor real.

Às vezes, o que queremos que uma rede neural faça é executarclassificação - dada uma entrada, classifique-a em duas ou mais categorias distintas. Nesse caso, a meta final com a qual o usuário se importa é a precisão da classificação - a porcentagem de casos classificados corretamente.

Mas quando estamos usando uma rede neural para classificação, emboranosso o objetivo é a precisão da classificação,não é isso que a rede neural está tentando otimizar. A rede neural ainda está tentando otimizar a função de custo com valor real. Às vezes, eles apontam na mesma direção, mas às vezes não. Em particular, eu tenho encontrado casos em que uma rede neural treinada para minimizar corretamente a função de custo tem uma precisão de classificação pior que uma simples comparação de limites codificados manualmente.

Eu reduzi isso para um caso de teste mínimo usando o TensorFlow. Ele configura um perceptron (rede neural sem camadas ocultas), o treina em um conjunto de dados absolutamente mínimo (uma variável de entrada, uma variável de saída binária) avalia a precisão da classificação do resultado e a compara com a precisão da classificação de uma mão simples comparação de limiares codificados; os resultados são 60% e 80%, respectivamente. Intuitivamente, isso ocorre porque um único outlier com um grande valor de entrada gera um valor de saída correspondentemente grande; portanto, a maneira de minimizar a função de custo é se esforçar muito para acomodar esse caso, classificando incorretamente outros dois casos comuns. O perceptron está fazendo corretamente o que foi instruído a fazer; é que isso não corresponde ao que realmente queremos de um classificador. Mas a precisão da classificação não é uma função diferenciável contínua, portanto, não podemos usá-la como alvo para a descida do gradiente.

Como podemos treinar uma rede neural para que ela acabe maximizando a precisão da classificação?

import numpy as np
import tensorflow as tf
sess = tf.InteractiveSession()
tf.set_random_seed(1)

# Parameters
epochs = 10000
learning_rate = 0.01

# Data
train_X = [
    [0],
    [0],
    [2],
    [2],
    [9],
]
train_Y = [
    0,
    0,
    1,
    1,
    0,
]

rows = np.shape(train_X)[0]
cols = np.shape(train_X)[1]

# Inputs and outputs
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)

# Weights
W = tf.Variable(tf.random_normal([cols]))
b = tf.Variable(tf.random_normal([]))

# Model
pred = tf.tensordot(X, W, 1) + b
cost = tf.reduce_sum((pred-Y)**2/rows)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
tf.global_variables_initializer().run()

# Train
for epoch in range(epochs):
    # Print update at successive doublings of time
    if epoch&(epoch-1) == 0 or epoch == epochs-1:
        print('{} {} {} {}'.format(
            epoch,
            cost.eval({X: train_X, Y: train_Y}),
            W.eval(),
            b.eval(),
            ))
    optimizer.run({X: train_X, Y: train_Y})

# Classification accuracy of perceptron
classifications = [pred.eval({X: x}) > 0.5 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('{}/{} = perceptron accuracy'.format(correct, rows))

# Classification accuracy of hand-coded threshold comparison
classifications = [x[0] > 1.0 for x in train_X]
correct = sum([p == y for (p, y) in zip(classifications, train_Y)])
print('{}/{} = threshold accuracy'.format(correct, rows))

questionAnswers(2)

yourAnswerToTheQuestion