【问题标题】:Trouble training a Tensorflow MLP to classify inputs -1, 0, or 1训练 Tensorflow MLP 以对输入 -1、0 或 1 进行分类时遇到问题
【发布时间】:2019-01-30 07:35:52
【问题描述】:

我正在尝试创建一个多层感知器来根据一些指标对情绪进行分类。情绪可以是 -1(差)、0(中性)或 1(好)。我能找到的所有分类器示例都是 one-hot,所以我认为我在调整它以处理连续特征的方式上做错了。

# Data Prep
np.random.shuffle(raw_data)
X_vals = raw_data[:-200,0:4]
Y_vals = [(x,) for x in raw_data[:-200,4]]
X_test = raw_data[-200:,0:4]
Y_test = [(x,) for x in raw_data[-200:,4]]

# Parameters
learning_rate = 0.001
training_epochs = 10
batch_size = 200
display_step = 1

# Network Parameters
n_hidden_1 = 16 # 1st layer number of neurons
n_hidden_2 = 16 # 2nd layer number of neurons
n_input = 4
n_classes = 1

# tf Graph input
X = tf.placeholder("float", [None, n_input])
Y = tf.placeholder("float", [None, n_classes])

# Store layers weight & bias
weights = {
    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_hidden_2, n_classes]))
}
biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}


# Create model
def multilayer_perceptron(x):
    # Hidden fully connected layer with 256 neurons
    layer_1 = tf.nn.tanh(tf.add(tf.matmul(x, weights['h1']), biases['b1']))
    # Hidden fully connected layer with 256 neurons
    layer_2 = tf.nn.tanh(tf.add(tf.matmul(layer_1, weights['h2']), biases['b2']))
    # Output fully connected layer with a neuron for each class
    out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
    return out_layer

# Construct model
logits = multilayer_perceptron(X)

# Define loss and optimizer
loss_op = tf.losses.mean_squared_error(labels=Y,
                                        predictions=tf.nn.softmax(logits))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)

# Initializing the variables
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    # Training cycle
    for epoch in range(training_epochs):
        avg_cost = 0.
        total_batch = int(raw_data.shape[0]/batch_size)
        # Loop over all batches
        for i in range(total_batch):
            batch_x = X_vals[epoch*batch_size:(epoch+1)*batch_size]
            batch_y = Y_vals[epoch*batch_size:(epoch+1)*batch_size]
            # Run optimization op (backprop) and cost op (to get loss value)
            _, c = sess.run([train_op, loss_op], feed_dict={X: batch_x,
                                                            Y: batch_y})
            print("Optimization Finished!")

# Test model
pred = tf.nn.softmax(logits)  # Apply softmax to logits
correct_prediction = tf.equal(tf.round(pred), Y)
# Calculate accuracy
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print("Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))

所以我希望所有这些都应该做的是创建一个 tanh 感知器,它有 2 个隐藏层,每个层有 16 个神经元和一个 softmax 输出层,在除 200 个数据点之外的所有数据点上对其进行训练,然后在最后 200 个数据点上对其进行测试. 它应该吐出 -1 和 1 之间的值,然后我将其四舍五入以根据 -1、0 或 1 的正确标签进行评估。

我想我一定是做错了什么,因为它的结果并不比随机机会好,即使输入和输出之间有 30% 的 Pearson 相关性。这应该很简单。

【问题讨论】:

  • Minimal, complete, verifiable example 适用于此。请提供有代表性的输入数据:只需在程序顶部硬编码raw_data 的值。还要记住包括使您的程序按发布的方式运行所需的其他支持。
  • 您应该能够生成输入特征和输出之间具有约 30% 相关性的随机数据并重现它。我会看看我能做些什么来提供我被允许分享的示例数据。
  • 为什么是n_classes=1??另外,既然你有分类问题,你不应该使用均方误差,这是回归的......
  • 我只需要一个输出神经元;我希望那里的值介于 -1 到 1 之间,因为我的三个类别是 -1、0 和 1。我相信均方误差在这里是合适的,因为它的行为更像是一个拟合问题。
  • 生成“在输入特征和输出之间具有约 30% 相关性的随机数据并重现该数据”应该是您的工作,而不是潜在受访者的工作......!

标签: python python-3.x tensorflow machine-learning neural-network


【解决方案1】:

我注意到您的模型有两个问题。首先,softmax 层将所有数据限制在 [0,1] 范围内,因此您永远不会得到您想要的 -1 值。数据绝对应该像您所说的那样进行一次热编码,因为即使您的模型可以吐出-1,它仍然会非常有偏差并且在测试时不是很准确。所以我会将n_classes 更改为 3,并使索引 0 坏,索引 1 中性,索引 2 好。您的标签应该是 3 向量,其中正确类索引处的向量为 1,其他地方为 0。这表示您希望模型学习的每个类别标签的概率分布。

最后,您使用的是均方误差 (MSE)。这是欧几里得嵌入的一个很好的误差度量(例如,如果你想像 YOLO 那样学习边界框的位置),但它不适用于你想要的概率分布嵌入,因为它测量了欧几里得之间的距离标签和网络输出。你想要的是tf.losses.softmax_cross_entropy。这首先通过 softmax 发送数据,然后计算交叉熵(两个概率分布之间的 KL 散度)。

所以你应该改变

loss_op = tf.losses.mean_squared_error(labels=Y,predictions=tf.nn.softmax(logits))

loss_op = tf.losses.softmax_cross_entropy(onehot_labels=Y,logits=logits)

确保在测试期间仍然使用 softmax。

最后,您使用的是 1 对 1 的训练/测试拆分。通常人们会使用 3 比 1 或 3 比 2 之类的值,这样您的训练数据就会多于测试数据,这通常会带来更好的结果。

【讨论】:

  • 感谢对softmax的指正!!我已将其更改为 tanh,但恐怕它的性能并没有更好。我不愿意切换到 one-hot,因为我所做的感觉更像是预测一个连续的数量而不是对某物进行分类。 (另外,我使用的是 10:1 的训练/测试分割!)
  • 我强烈建议按照建议对标签进行单热编码并使用交叉熵损失。你这里有一个类预测问题,而不是回归问题。至少在敲门之前尝试一下。特别是因为你到目前为止没有任何运气。
  • 也许我应该将其视为回归问题,而不是分类问题?长期目标是获得一个介于 -1 和 1 之间的连续情绪指标。如果是这种情况,我该如何改变我的方法?
  • 啊,我明白了。好吧,如果您愿意,您可以对其进行一次热编码,然后取网络的 logits 输出的质心以获得 [-1,1] 中的值,这可能会更准确。
  • 切换到one-hot和三个类别后,我仍然与随机机会大致相当。有什么想法吗?
猜你喜欢
  • 2016-03-04
  • 2017-07-12
  • 2019-09-28
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
相关资源
最近更新 更多