Tensorflow - 损失从高开始并且不会减少

J P*_*ack 6 loss neural-network deep-learning tensorflow cross-entropy

我开始用张量流编写神经元网络,我的每个示例项目中都有一个问题.

我的损失总是从50或更高的东西开始并且没有减少,或者如果它减少,它的确如此缓慢,以至于在我所有的时代之后我甚至没有接近可接受的损失率.

它已经尝试过的事情(并没有太大影响结果)

  • 测试过度拟合,但在下面的例子中,您可以看到我有15000个训练和15000个测试数据集以及900个神经元之类的东西
  • 测试了不同的优化器和优化器值
  • 尝试使用testdata作为trainingdata来增加traingdata
  • 尝试增加和减少批量大小

我根据https://youtu.be/vq2nnJ4g6N0的知识创建了网络

但是,让我们看看我的一个测试项目:

我有一个名单列表,并希望假设性别,所以我的原始数据如下所示:

names=["Maria","Paul","Emilia",...]

genders=["f","m","f",...]
Run Code Online (Sandbox Code Playgroud)

为了将它提供给网络,我将名称转换为charCodes数组(期望最大长度为30)并将性别转换为位数组

names=[[77.,97. ,114.,105.,97. ,0. ,0.,...]
       [80.,97. ,117.,108.,0.  ,0. ,0.,...]
       [69.,109.,105.,108.,105.,97.,0.,...]]

genders=[[1.,0.]
         [0.,1.]
         [1.,0.]]
Run Code Online (Sandbox Code Playgroud)

我为输出层建立了3个隐藏层[30,20],[20,10],[10,10]和[10,2]的网络.所有隐藏层都具有ReLU作为激活功能.输出层具有softmax.

# Input Layer
x = tf.placeholder(tf.float32, shape=[None, 30])
y_ = tf.placeholder(tf.float32, shape=[None, 2])

# Hidden Layers
# H1
W1 = tf.Variable(tf.truncated_normal([30, 20], stddev=0.1))
b1 = tf.Variable(tf.zeros([20]))
y1 = tf.nn.relu(tf.matmul(x, W1) + b1)

# H2
W2 = tf.Variable(tf.truncated_normal([20, 10], stddev=0.1))
b2 = tf.Variable(tf.zeros([10]))
y2 = tf.nn.relu(tf.matmul(y1, W2) + b2)

# H3
W3 = tf.Variable(tf.truncated_normal([10, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))
y3 = tf.nn.relu(tf.matmul(y2, W3) + b3)

# Output Layer
W = tf.Variable(tf.truncated_normal([10, 2], stddev=0.1))
b = tf.Variable(tf.zeros([2]))
y = tf.nn.softmax(tf.matmul(y3, W) + b)
Run Code Online (Sandbox Code Playgroud)

现在计算损失,准确性和训练操作:

# Loss
cross_entropy = -tf.reduce_sum(y_*tf.log(y))

# Accuracy
is_correct = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))

# Training
train_operation = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
Run Code Online (Sandbox Code Playgroud)

我分批训练100个网络

sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(150):
    bs = 100
    index = i*bs
    inputBatch = inputData[index:index+bs]
    outputBatch = outputData[index:index+bs]

    sess.run(train_operation, feed_dict={x: inputBatch, y_: outputBatch})
    accuracyTrain, lossTrain = sess.run([accuracy, cross_entropy], feed_dict={x: inputBatch, y_: outputBatch})

    if i%(bs/10) == 0:
        print("step %d loss %.2f accuracy %.2f" % (i, lossTrain, accuracyTrain))
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

step 0 loss 68.96 accuracy 0.55
step 10 loss 69.32 accuracy 0.50
step 20 loss 69.31 accuracy 0.50
step 30 loss 69.31 accuracy 0.50
step 40 loss 69.29 accuracy 0.51
step 50 loss 69.90 accuracy 0.53
step 60 loss 68.92 accuracy 0.55
step 70 loss 68.99 accuracy 0.55
step 80 loss 69.49 accuracy 0.49
step 90 loss 69.25 accuracy 0.52
step 100 loss 69.39 accuracy 0.49
step 110 loss 69.32 accuracy 0.47
step 120 loss 67.17 accuracy 0.61
step 130 loss 69.34 accuracy 0.50
step 140 loss 69.33 accuracy 0.47
Run Code Online (Sandbox Code Playgroud)


我究竟做错了什么?

为什么它在我的项目中以〜69开始而不是更低?


非常感谢你们!

mda*_*ust 3

作为二元分类的起点,每个样本的熵为 0.69 nat并没有什么问题。

如果转换为基数 2,0.69/log(2)您会发现每个样本几乎恰好是 1 位,如果您不确定二进制分类,这正是您所期望的。

我通常使用平均损失而不是总和,因此对批量大小不太敏感。

您也不应该自己直接计算熵,因为该方法很容易崩溃。你可能想要tf.nn.sigmoid_cross_entropy_with_logits

我也喜欢从 Adam 优化器开始,而不是纯粹的梯度下降。

以下是您可能遇到此问题的两个原因:

1)字符代码是有顺序的,但顺序并不代表什么。如果您的输入作为 one-hot 向量输入,那么网络会更容易将它们作为输入。所以你的输入将是一个 26x30 = 780 元素向量。如果没有这个,网络就必须浪费大量的能力来学习字母之间的边界。

2)你只有完全连接的层。这使得它不可能了解与其在名称中的绝对位置无关的事实。2015 年排名前 10 的女孩名字中,有 6 个以“a”结尾,而排名前 10 的男孩名字中,有 0 个以“a”结尾。正如目前所写,您的网络需要针对每个名称长度独立地重新学习“如果以“a”结尾,通常是一个女孩的名字”。使用一些卷积层将允许它在所有名称长度上一次学习事实。