Tensorflow的逻辑回归例子,详解

上一篇博文中的例子,其中有几处小小的错误,比如没有使用激活函数,导致正向传播的过程中没有消除线性化,对离散型的非线性标签数据(Y值),输出结果时没有将其概率化。另外,损失函数也有一点问题,我在测试过程中发现和预期并不一致。

这里做了一些修改,并加入了b值,使逻辑回归的元素完整,取得了更好的拟合效果。逻辑回归损失函数推导过程如下:


本例构造了一个三层网络,输入(2cell),隐藏(10cell),输出(1cell)。我对本例的理解视图和传统神经网络的图形表达,均手工画在下面,个人认为,理解了结构之后的视图,更利于今后的深入研究和使用。


代码:

# coding:utf-8

import tensorflow as tf
from numpy.random import RandomState

# 使用命名空间定义元素,便于使用tensorboard查看神经网络图形化
with tf.name_scope('graph_1') as scope:
    batch_size = 500  # 神经网络训练集batch大小为500
    # 定义神经网络的结构,输入为2个参数,隐藏层为10个参数,输出为1个参数
    # w1为输入到隐藏层的权重,2*10的矩阵(2表示输入层有2个因子,也就是两列输入,10表示隐藏层有10个cell)
    w1 = tf.Variable(tf.random_normal([2, 10], stddev=1, seed=1), name='w1')
    # w2为隐藏层到输出的权重,10*1的矩阵(接受隐藏的10个cell输入,输出1列数据)
    w2 = tf.Variable(tf.random_normal([10, 1], stddev=1, seed=1), name='w2')
    # b1和b2均为一行,列数对应由w1和w2的列数决定
    b1 = tf.Variable(tf.random_normal([1, 10], stddev=1, seed=1), name='b1')
    b2 = tf.Variable(tf.random_normal([1, 1], stddev=1, seed=1), name='b2')

    # 维度中使用None,则可以不规定矩阵的行数,方便存储不同batch的大小。(占位符)
    x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
    y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')

    # 定义神经网络前向传播的过程,定义了1层隐藏层。
    # 输入到隐藏、隐藏到输出的算法均为逻辑回归,即y=wx+b的模式
    a = tf.add(tf.matmul(x, w1, name='a'), b1)
    y = tf.add(tf.matmul(tf.tanh(a), w2, name='y'), b2)  # 使用tanh激活函数使模型非线性化
    y_hat = tf.sigmoid(y)  # 将逻辑回归的输出概率化

    # 定义损失函数和反向传播的算法,见吴恩达视频课程第二周第三节课,逻辑回归的损失函数
    cross_entropy = - \
        tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y_hat, 1e-10, 1.0)) +
                       (1-y_)*tf.log(tf.clip_by_value((1-y_hat), 1e-10, 1.0)))
    # 方差损失函数,逻辑回归不能用
    # cost = -tf.reduce_mean(tf.square(y_ - y_hat))
    # clip_by_value函数将y限制在1e-10和1.0的范围内,防止出现log0的错误,即防止梯度消失或爆发
    
    train_step = tf.train.AdamOptimizer(0.0001).minimize((cross_entropy))  # 反向传播算法

    # 通过随机数生成一个模拟数据集
    rdm = RandomState(1)  # rdm为伪随机数发生器,种子为1
    dataset_size = 128000
    X = rdm.rand(dataset_size, 2)  # 生成随机数,大小为128000*2的矩阵
    # x_hat = rdm.rand(1, 2)
    x_hat = []
    x_hat.append(list(X[300]))
    print(x_hat)

    # 打标签,所有x1+x2<1的都被认为是正样本,其余为负样本。
    Y = [[int(x1+x2 < 1)] for (x1, x2) in X]  # 列表解析格式
    # 若x1+x2 <1为真,则int(x1+x2 <1)为1,若假,则输出为0


# 创建会话
with tf.Session() as sess:
    writer = tf.summary.FileWriter("logs/", sess.graph)
    init_op = tf.global_variables_initializer()  # 所有需要初始化的值
    sess.run(init_op)  # 初始化变量
    print(sess.run(w1))
    print(sess.run(w2))
    print('x_hat =', x_hat, 'y_hat =', sess.run(y_hat, feed_dict={x: x_hat}))

    '''
    # 在训练之前神经网络权重的值,w1,w2,b1,b2的值
    '''

    # 设定训练的轮数
    STEPS = 100000
    for i in range(STEPS):
        # 每次从数据集中选batch_size个数据进行训练
        start = (i * batch_size) % dataset_size  # 训练集在数据集中的开始位置
        # 结束位置,若超过dataset_size,则设为dataset_size
        end = min(start + batch_size, dataset_size)

        # 通过选取的样本训练神经网络并更新参数
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            # 每隔一段时间计算在所有数据上的损失函数并输出
            total_cross_entropy = sess.run(
                cross_entropy, feed_dict={x: X, y_: Y})
            total_w1 = sess.run(w1)
            total_b1 = sess.run(b1)
            total_w2 = sess.run(w2)
            total_b2 = sess.run(b2)
            print("After %d training steps(s), cross entropy on all data is %g" % (
                i, total_cross_entropy))
            print('w1=', total_w1, ',b1=', total_b1)
            print('w2=', total_w2, ',b2=', total_b2)

    # 在训练之后神经网络权重的值
    print(sess.run(w1))
    print(sess.run(w2))
    print('x_hat =', x_hat, 'y_hat =', sess.run(y_hat, feed_dict={x: x_hat}))

 输出结果如下:


经过10万次迭代后,损失收敛到0.0154059,基本可以用了。最后预测结果也打印出来了,对于这种随机产生的数据,也不在意训练集和测试集了,如果想测试新的数据,可以自行生成,然后把w1,w2,b1,b2代入三个正向传播函数,看看效果如何即可。

在tensorboard中显示了一下这个graph,比我手画的复杂多了,没理解的话,绝对会被这种高大上的东西吓到不敢继续,理解了的话,也就没那么难了。以后只需要把函数换成实际应用中的算法即可,解决基本应用问题不大。


在tensorboard的graph中,可以很明显的看出正向传播和反向传播的路径,从下到上是正向传播,到了sigmoid节点为止(输出y_hat值)。然后从sigmoid节点处再向上,就是一个反向求导过程。



  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值