6

私はテンソルフローでニューラルネットワークを書き始めましたが、サンプルプロジェクトのそれぞれに直面しているように見える問題が1つあります。

私の損失は常に 50 かそれ以上から始まり、減少しないか、減少したとしてもゆっくりと減少するため、すべてのエポックの後、許容可能な損失率に近づくことさえできません。

すでに試したこと(結果に大きな影響はありませんでした)

  • 過適合でテストされていますが、次の例では、15000 のトレーニングと 15000 のテスト データセット、および 900 のニューロンのようなものがあることがわかります
  • さまざまなオプティマイザーとオプティマイザー値をテストしました
  • テストデータをトレーニングデータとしても使用して、トレーニングデータを増やしてみました
  • バッチサイズを増減してみました

https://youtu.be/vq2nnJ4g6N0の知識でネットワークを作成しました

しかし、私のテストプロジェクトの1つを見てみましょう:

名前のリストがあり、性別を仮定したかったので、生データは次のようになります。

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

genders=["f","m","f",...]

それをネットワークに供給するために、名前をcharCodeの配列に変換し(最大長は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.]]

出力層として [30,20]、[20,10]、[10,10]、[10,2] の 3 つの隠れ層を持つネットワークを構築しました。すべての隠れ層には活性化関数として ReLU があります。出力層にはソフトマックスがあります。

# 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)

次に、損失、精度、およびトレーニング操作の計算を行います。

# 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)

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))

そして、次の結果が得られます。

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


私は何を間違っていますか?

私のプロジェクトで ~69 から始まり、それ以下にならないのはなぜですか?


どうもありがとうございました!

4

1 に答える 1

3

バイナリ分類の開始点として、サンプルあたり0.69ナットのエントロピーに問題はありません。

基数 2 に変換すると0.69/log(2)、サンプルあたりほぼ正確に 1 ビットであることがわかります。これは、バイナリ分類について確信が持てない場合に期待するものとまったく同じです。

私は通常、合計の代わりに平均損失を使用するので、バッチサイズの影響を受けにくくなっています。

また、エントロピーを自分で直接計算しないでください。その方法は簡単に壊れてしまうからです。あなたはおそらくしたいですtf.nn.sigmoid_cross_entropy_with_logits

また、純粋な勾配降下ではなく、Adam Optimizer から始めるのも好きです。

この問題で問題が発生する可能性がある 2 つの理由を次に示します。

1) 文字コードは順序付けされていますが、その順序は何の意味もありません。入力がワンホット ベクトルとして入力された場合、ネットワークが入力として取りやすくなります。したがって、入力は 26x30 = 780 要素ベクトルになります。それがなければ、ネットワークは文字間の境界を学習する大量の容量を無駄にしなければなりません。

2) 完全に接続されたレイヤーしかありません。これにより、名前の絶対位置とは無関係に事実を学習することができなくなります。2015 年の女の子の名前のトップ 10 のうち 6 つは「a」で終わりましたが、男の子の名前のトップ 10 のうち 0 人は「a」で終わりました。現在書かれているように、ネットワークは名前の長さごとに「通常、'a' で終わる場合は女の子の名前です」を個別に再学習する必要があります。いくつかの畳み込み層を使用すると、すべての名前の長さにわたって事実を 1 回学習できるようになります。

于 2016-12-22T00:28:39.353 に答える