我正在使用Tensorflow构建一个简单的单隐藏层神经网络。
对于输入,每行数据对应10个答案。每行的前两个元素是正确的,即与真实标签相同。相反,最后8个元素与真实标签相反。
例如,
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 正确答案是1[0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 正确答案是0[0, 0, 1, 1, 1, 1, 1, 1, 1, 1], 正确答案是0[1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 正确答案是1
我希望我的神经网络能够学习到前两个元素/特征总是给出正确的结果。因此,我希望网络对前两个特征赋予更大的权重。然而,网络总是在某个损失值上卡住。
更有趣的是,准确率被定义为正确预测的标签占总标签数的比例。损失函数是使用sigmoid函数计算的,即$y * log(logit) + (1-y) * log(1-logit)$。有时候,随着损失的减少,准确率会增加。例如,
epoch是: 0 损失是: 7.661093 准确率是: 1.0 epoch是: 100 损失是: 7.579134 准确率是: 0.54545456 epoch是: 200 损失是: 7.5791006 准确率是: 0.54545456
我认为网络应该能够不断增加前两个元素的权重,直到它能完全预测出正确的标签。
请问有人能告诉我应该怎么做才能让网络正确预测标签,而不是卡住吗?
我的代码如下:
import tensorflow as tfimport numpy as npclass SigmoidNeuralNetwork(): def __init__(self, learning_rate, training_data, correct_labels, epoch_number): self.learning_rate = learning_rate self.training_data = training_data self.correct_labels = correct_labels self.X = tf.placeholder(tf.float32) self.y = tf.placeholder(tf.float32) self.feature_num = len(self.training_data[0]) self.sample_num = len(self.training_data) self.W = tf.Variable(tf.random_uniform([self.feature_num, 1], -1.0, 1.0), dtype=tf.float32) self.b = tf.Variable([0.0]) self.epoch_number = epoch_number def launch_network(self): db = tf.matmul(self.X, tf.reshape(self.W, [-1, 1])) + self.b hyp = tf.sigmoid(db) cost0 = self.y * tf.log(tf.clip_by_value(hyp, 1e-10, 1.0)) cost1 = (1 - self.y) * tf.log(tf.clip_by_value((1 - hyp), 1e-10, 1.0)) cost = (cost0 + cost1) / float(self.sample_num) loss = -tf.reduce_sum(cost) optimizer = tf.train.GradientDescentOptimizer(learning_rate=self.learning_rate) train = optimizer.minimize(loss) # new_train_X = self.training_data.astype(np.float32) output = tf.add(tf.matmul(new_train_X, self.W), self.b) prediction = tf.sigmoid(output) predicted_class = tf.greater(prediction, 0.5) ground_labels = tf.reshape(tf.equal(self.y, 1.0), predicted_class.shape) correct = tf.equal(predicted_class, ground_labels) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) # init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) for epoch in range(self.epoch_number): _, loss_val, accuracy_val = sess.run([train, loss, accuracy], {self.X: self.training_data, self.y: self.correct_labels}) if epoch % 100 == 0: print "epoch是: ", epoch, "损失是: ", loss_val, " 准确率是: ", accuracy_val # print "权重是: ", sess.run(self.W).flatten()train_data = np.array([ [1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0]])correct_answers = np.array([1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1])sigmoid_network = SigmoidNeuralNetwork(learning_rate=0.01, training_data=train_data, correct_labels=correct_answers, epoch_number=10000)sigmoid_network.launch_network()
回答:
问题是什么?
原帖作者写道:
我认为网络应该能够不断增加前两个元素的权重,直到它能完全预测出正确的标签。
你完全正确。
请问有人能告诉我应该怎么做才能让网络正确预测标签,而不是卡住吗?
问题出在launch_network()
函数中:
def launch_network(self): db = tf.matmul(self.X, tf.reshape(self.W, [-1, 1])) + self.b hyp = tf.sigmoid(db) cost0 = self.y * tf.log(tf.clip_by_value(hyp, 1e-10, 1.0)) ... (略) ...
请注意,db
和hyp
的形状都是(self.sample_num, 1)
(二维),但self.y
(即correct_answers
)的形状是(self.sample_num,)
(一维)。
在第五行计算cost0
时,你进行了self.y * tf.log(...hyp...)
的乘法操作。因此,结果的形状变成了(self.sample_num, self.sample_num)
,而不是(self.sample_num, 1)
。
解决方案建议
最简单的解决方案是将correct_answers
的形状改为(self.sample_num, 1)
(二维),而不是(self.sample_num,)
(一维),如下所示:
correct_answers = np.array([1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1])[:,np.newaxis]