使用TensorFlow进行二元分类的多层感知机设置

我在尝试使用TensorFlow进行二元分类的多层感知机设置时遇到了一些问题。

我有一个非常大的数据集(约1.5*10^6个样本),每个样本都有一个二元标签(0/1)和100个特征。我需要做的是设置一个简单的多层感知机,然后尝试改变学习率和初始化模式来记录结果(这是一个作业)。然而,我得到了一些奇怪的结果,我的多层感知机似乎在早期就卡在一个低但不理想的成本上,并且一直没有摆脱它。当学习率设置得相当低时,成本几乎立即变为NAN。我不知道问题出在我如何构建多层感知机(我尝试了几次,将最后一次的代码发布出来)还是我的TensorFlow实现中有什么遗漏的地方。

代码

import tensorflow as tfimport numpy as npimport scipy.io# 导入并转换数据集print("正在导入数据集。")dataset = scipy.io.mmread('tfidf_tsvd.mtx')with open('labels.txt') as f:    all_labels = f.readlines()all_labels = np.asarray(all_labels)all_labels = all_labels.reshape((1498271,1))# 将数据集分为训练集(66%)和测试集(33%)training_set    = dataset[0:1000000]training_labels = all_labels[0:1000000]test_set        = dataset[1000000:1498272]test_labels     = all_labels[1000000:1498272]print("数据集准备就绪。") # 参数learning_rate   = 0.01 #argvmini_batch_size = 100training_epochs = 10000display_step    = 500# 网络参数n_hidden_1  = 64    # 第一隐藏层神经元数n_hidden_2  = 32    # 第二隐藏层神经元数n_hidden_3  = 16    # 第三隐藏层神经元数n_input     = 100   # LSA后的特征数量# TensorFlow图形输入x = tf.placeholder(tf.float64, shape=[None, n_input], name="x-data")y = tf.placeholder(tf.float64, shape=[None, 1], name="y-labels")print("正在创建模型。")# 创建模型def multilayer_perceptron(x, weights):    # 第一隐藏层使用SIGMOID激活    layer_1 = tf.matmul(x, weights['h1'])    layer_1 = tf.nn.sigmoid(layer_1)    # 第二隐藏层使用SIGMOID激活    layer_2 = tf.matmul(layer_1, weights['h2'])    layer_2 = tf.nn.sigmoid(layer_2)    # 第三隐藏层使用SIGMOID激活    layer_3 = tf.matmul(layer_2, weights['h3'])    layer_3 = tf.nn.sigmoid(layer_3)    # 输出层使用SIGMOID激活    out_layer = tf.matmul(layer_2, weights['out'])    return out_layer# 层权重,应该更改它们以查看结果weights = {    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1], dtype=np.float64)),           'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2], dtype=np.float64)),    'h3': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_3],dtype=np.float64)),    'out': tf.Variable(tf.random_normal([n_hidden_2, 1], dtype=np.float64))}# 构建模型pred = multilayer_perceptron(x, weights)# 定义损失和优化器cost = tf.nn.l2_loss(pred-y,name="squared_error_cost")optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)# 初始化变量init = tf.initialize_all_variables()print("模型准备就绪。")# 启动图形with tf.Session() as sess:    sess.run(init)    print("开始训练。")    # 训练周期    for epoch in range(training_epochs):        #avg_cost = 0.        # 加载小批量数据        minibatch_x = training_set[mini_batch_size*epoch:mini_batch_size*(epoch+1)]        minibatch_y = training_labels[mini_batch_size*epoch:mini_batch_size*(epoch+1)]        # 运行优化操作(反向传播)和成本操作        _, c = sess.run([optimizer, cost], feed_dict={x: minibatch_x, y: minibatch_y})        # 计算平均损失        avg_cost = c / (minibatch_x.shape[0])        # 每轮显示日志        if (epoch) % display_step == 0:        print("轮次:", '%05d' % (epoch), "训练误差=", "{:.9f}".format(avg_cost))    print("优化完成!")    # 测试模型    # 计算准确率    test_error = tf.nn.l2_loss(pred-y,name="squared_error_test_cost")/test_set.shape[0]    print("测试误差:", test_error.eval({x: test_set, y: test_labels}))

输出

python nn.py正在导入数据集。数据集准备就绪。正在创建模型。模型准备就绪。开始训练。轮次: 00000 训练误差= 0.331874878轮次: 00500 训练误差= 0.121587482轮次: 01000 训练误差= 0.112870921轮次: 01500 训练误差= 0.110293652轮次: 02000 训练误差= 0.122655269轮次: 02500 训练误差= 0.124971940轮次: 03000 训练误差= 0.125407845轮次: 03500 训练误差= 0.131942481轮次: 04000 训练误差= 0.121696954轮次: 04500 训练误差= 0.116669835轮次: 05000 训练误差= 0.129558477轮次: 05500 训练误差= 0.122952110轮次: 06000 训练误差= 0.124655344轮次: 06500 训练误差= 0.119827300轮次: 07000 训练误差= 0.125183779轮次: 07500 训练误差= 0.156429254轮次: 08000 训练误差= 0.085632880轮次: 08500 训练误差= 0.133913128轮次: 09000 训练误差= 0.114762624轮次: 09500 训练误差= 0.115107805优化完成!测试误差: 0.116647016708

这是MMN建议的

weights = {    'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1], stddev=0, dtype=np.float64)),         'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2], stddev=0.01, dtype=np.float64)),    'h3': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_3],  stddev=0.01, dtype=np.float64)),    'out': tf.Variable(tf.random_normal([n_hidden_2, 1], dtype=np.float64))}

这是输出

轮次: 00000 训练误差= 0.107566668轮次: 00500 训练误差= 0.289380907轮次: 01000 训练误差= 0.339091784轮次: 01500 训练误差= 0.358559815轮次: 02000 训练误差= 0.122639698轮次: 02500 训练误差= 0.125160135轮次: 03000 训练误差= 0.126219718轮次: 03500 训练误差= 0.132500418轮次: 04000 训练误差= 0.121795254轮次: 04500 训练误差= 0.116499476轮次: 05000 训练误差= 0.124532673轮次: 05500 训练误差= 0.124484790轮次: 06000 训练误差= 0.118491177轮次: 06500 训练误差= 0.119977633轮次: 07000 训练误差= 0.127532511轮次: 07500 训练误差= 0.159053519轮次: 08000 训练误差= 0.083876224轮次: 08500 训练误差= 0.131488483轮次: 09000 训练误差= 0.123161189轮次: 09500 训练误差= 0.125011362优化完成!测试误差: 0.129284643093

连接第三隐藏层,感谢MMN

我的代码中有一个错误,我只有两个隐藏层而不是三个。我通过以下方式进行了修正:

'out': tf.Variable(tf.random_normal([n_hidden_3, 1], dtype=np.float64))

out_layer = tf.matmul(layer_3, weights['out'])

不过,我恢复了stddev的旧值,因为它似乎导致成本函数波动较少。

输出仍然令人担忧

轮次: 00000 训练误差= 0.477673073轮次: 00500 训练误差= 0.121848744轮次: 01000 训练误差= 0.112854530轮次: 01500 训练误差= 0.110597624轮次: 02000 训练误差= 0.122603499轮次: 02500 训练误差= 0.125051472轮次: 03000 训练误差= 0.125400717轮次: 03500 训练误差= 0.131999354轮次: 04000 训练误差= 0.121850889轮次: 04500 训练误差= 0.116551533轮次: 05000 训练误差= 0.129749704轮次: 05500 训练误差= 0.124600464轮次: 06000 训练误差= 0.121600218轮次: 06500 训练误差= 0.121249676轮次: 07000 训练误差= 0.132656938轮次: 07500 训练误差= 0.161801757轮次: 08000 训练误差= 0.084197352轮次: 08500 训练误差= 0.132197409轮次: 09000 训练误差= 0.123249055轮次: 09500 训练误差= 0.126602369优化完成!测试误差: 0.129230736355

Steven提出的两个更多更改Steven建议将Sigmoid激活函数改为ReLu,所以我尝试了。同时,我注意到我没有为输出节点设置激活函数,所以我也做了这个更改(应该很容易看出我做了什么更改)。

开始训练。轮次: 00000 训练误差= 293.245977809轮次: 00500 训练误差= 0.290000000轮次: 01000 训练误差= 0.340000000轮次: 01500 训练误差= 0.360000000轮次: 02000 训练误差= 0.285000000轮次: 02500 训练误差= 0.250000000轮次: 03000 训练误差= 0.245000000轮次: 03500 训练误差= 0.260000000轮次: 04000 训练误差= 0.290000000轮次: 04500 训练误差= 0.315000000轮次: 05000 训练误差= 0.285000000轮次: 05500 训练误差= 0.265000000轮次: 06000 训练误差= 0.340000000轮次: 06500 训练误差= 0.180000000轮次: 07000 训练误差= 0.370000000轮次: 07500 训练误差= 0.175000000轮次: 08000 训练误差= 0.105000000轮次: 08500 训练误差= 0.295000000轮次: 09000 训练误差= 0.280000000轮次: 09500 训练误差= 0.285000000优化完成!测试误差: 0.220196439287

这是对每个节点(包括输出)使用Sigmoid激活函数的结果

轮次: 00000 训练误差= 0.110878121轮次: 00500 训练误差= 0.119393080轮次: 01000 训练误差= 0.109229532轮次: 01500 训练误差= 0.100436962轮次: 02000 训练误差= 0.113160662轮次: 02500 训练误差= 0.114200962轮次: 03000 训练误差= 0.109777990轮次: 03500 训练误差= 0.108218725轮次: 04000 训练误差= 0.103001394轮次: 04500 训练误差= 0.084145737轮次: 05000 训练误差= 0.119173495轮次: 05500 训练误差= 0.095796251轮次: 06000 训练误差= 0.093336573轮次: 06500 训练误差= 0.085062860轮次: 07000 训练误差= 0.104251661轮次: 07500 训练误差= 0.105910949轮次: 08000 训练误差= 0.090347288轮次: 08500 训练误差= 0.124480612轮次: 09000 训练误差= 0.109250224轮次: 09500 训练误差= 0.100245836优化完成!测试误差: 0.110234139674

我发现这些数字非常奇怪,在第一种情况下,它卡在一个比Sigmoid更高的成本上,尽管Sigmoid应该很早就饱和了。在第二种情况下,它以几乎是最后一个的训练误差开始…所以它基本上用一个小批量就收敛了。我开始认为我没有正确计算成本,在这一行:avg_cost = c / (minibatch_x.shape[0])


回答:

所以可能是几个原因:

  1. 你可能饱和了Sigmoid单元(如MMN提到的),我建议尝试使用ReLU单元来代替。

替换:

tf.nn.sigmoid(layer_n)

为:

tf.nn.relu(layer_n)
  1. 你的模型可能没有足够的表达能力来实际学习你的数据。即它可能需要更深的层。
  2. 你也可以尝试不同的优化器,如Adam(),如下所示

替换:

optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

为:

optimizer = tf.train.AdamOptimizer().minimize(cost)

其他几点:

  1. 你应该为你的权重添加一个偏置项

如下所示:

biases = { 'b1': tf.Variable(tf.random_normal([n_hidden_1],   dtype=np.float64)),        'b2': tf.Variable(tf.random_normal([n_hidden_2], dtype=np.float64)), 'b3': tf.Variable(tf.random_normal([n_hidden_3],dtype=np.float64)), 'bout': tf.Variable(tf.random_normal([1], dtype=np.float64)) }def multilayer_perceptron(x, weights):    # 第一隐藏层使用SIGMOID激活    layer_1 = tf.matmul(x, weights['h1']) + biases['b1']    layer_1 = tf.nn.sigmoid(layer_1)    # 第二隐藏层使用SIGMOID激活    layer_2 = tf.matmul(layer_1, weights['h2']) + biases['b2']    layer_2 = tf.nn.sigmoid(layer_2)    # 第三隐藏层使用SIGMOID激活    layer_3 = tf.matmul(layer_2, weights['h3']) + biases['b3']    layer_3 = tf.nn.sigmoid(layer_3)    # 输出层使用SIGMOID激活    out_layer = tf.matmul(layer_2, weights['out']) + biases['bout']    return out_layer
  1. 你可以随时间更新学习率

如下所示:

    learning_rate = tf.train.exponential_decay(INITIAL_LEARNING_RATE,                                           global_step,                                           decay_steps,                                           LEARNING_RATE_DECAY_FACTOR,                                           staircase=True)

你只需要定义衰减步骤,即何时衰减,以及LEARNING_RATE_DECAY_FACTOR,即衰减多少。

Related Posts

Keras Dense层输入未被展平

这是我的测试代码: from keras import…

无法将分类变量输入随机森林

我有10个分类变量和3个数值变量。我在分割后直接将它们…

如何在Keras中对每个输出应用Sigmoid函数?

这是我代码的一部分。 model = Sequenti…

如何选择类概率的最佳阈值?

我的神经网络输出是一个用于多标签分类的预测类概率表: …

在Keras中使用深度学习得到不同的结果

我按照一个教程使用Keras中的深度神经网络进行文本分…

‘MatMul’操作的输入’b’类型为float32,与参数’a’的类型float64不匹配

我写了一个简单的TensorFlow代码,但不断遇到T…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注