zoukankan      html  css  js  c++  java
  • tensorflow实现线性模型和sklearn的线性模型比较

    自己用tensorflow实现了linear模型,但是和sklearn提供的模型效果相比,实验结果差了很多,所以尝试了修改优化算法,正则化,损失函数和归一化,记录尝试的所有过程和自己的实验心得。

    
    import numpy as np
    import tensorflow as tf
    import sklearn
    import pandas as pd
    class Model:
        def __init__(self, sess, feature_size, step, learning_rate, regulation):
            self.sess = sess
            self.feature_size = feature_size
            self.step = step
            self.learning_rate = learning_rate
            self.regulation = regulation
    
            self.build_model()
            self.add_loss()
            self.add_optimizer()
    
            self.sess.run(tf.global_variables_initializer())
            self.sess.run(tf.local_variables_initializer())
    
        def build_model(self):
            self.x = tf.placeholder(shape=[None, self.feature_size], dtype=tf.float32)
            self.y_true = tf.placeholder(shape=[None, 1], dtype=tf.float32)
    
            with tf.name_scope('linear_model'):
                l2_reg = tf.contrib.layers.l2_regularizer(0.1)
                self.w = tf.get_variable(name='w', shape=[self.feature_size, 1],
                                         initializer=tf.truncated_normal_initializer(), regularizer=l2_reg)
                self.b = tf.get_variable(name='b', shape=[1],
                                         initializer=tf.truncated_normal_initializer(stddev=1, seed=1))
                self.y_pred = tf.matmul(self.x, self.w) + self.b
    
        def add_loss(self, loss='l2'):
            reg_variables = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
            if loss == 'l2':
                self.loss = tf.reduce_mean(tf.square(self.y_true - self.y_pred))
            if loss == 'l1':
                self.loss = tf.reduce_mean(tf.abs(self.y_true - self.y_pred))
            if loss == 'huber':
                delta = tf.constant(0.25)  # delta越大两边线性部分越陡峭,损失越大
                self.loss = tf.multiply(tf.square(delta), tf.sqrt(1. + tf.square((self.y_true - self.y_pred) / delta)) - 1.)
            self.loss += tf.add_n(reg_variables)
    
        def add_optimizer(self):
            self.optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
            self.train_step = self.optimizer.minimize(self.loss)
    
        def predict(self, x_test):
            self.pred_test = tf.matmul(tf.cast(x_test, tf.float32), self.w) + self.b
    
            pred_test = self.sess.run([self.pred_test])
    
            return pred_test
    
        def train(self, train_data, train_label):
            loss, y_pred = self.sess.run([self.loss, self.y_pred], feed_dict={self.x: train_data, self.y_true: train_label})
            return loss, y_pred
    if __name__ == '__main__':
        feature_size, step, learning_rate, regulation = 100, 1000, 0.0001, 'L2'
        sample_size = 30
        x = [list(np.random.rand(feature_size)) for _ in range(sample_size)]
        y = [np.random.rand(1) for _ in range(sample_size)]
    
        x = pd.DataFrame(x).apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x))).values
    
        with tf.Session() as sess:
            model = Model(sess, feature_size, step, learning_rate, regulation)
            _, _ = model.train(x, y)
            # print('loss is ', loss)
    
            pred_test = model.predict(x)
            # print('pred label	ture label')
            # for each in zip(pred, y):
            #     print(round(each[0][0], 6), '	', round(each[1][0], 6))
            loss = sum([(each[0][0] - each[1][0]) ** 2 for each in zip(pred_test, y)])
            print('LR net loss ', loss)
    
        from sklearn import linear_model
    
        reg = linear_model.LinearRegression()
        reg.fit(x, y)
        pred_test1 = reg.predict(x)
        loss = sum([(each[0][0] - each[1][0]) ** 2 for each in zip(pred_test1, y)])
        print('sklearn loss ', loss)
    
        import matplotlib.pyplot as plt
    
        fig = plt.figure()
        x = [i for i in range(len(x))]
    
        plt.plot(x, y, 'k*-', markersize=12)
        plt.plot(x, [each[0] for each in pred_test[0]], 'r.-', markersize=12)
        plt.plot(x, [each[0] for each in pred_test1], 'b.-', markersize=12)
        plt.legend(('true', 'my', 'Linear Fit'), loc='lower right')
        plt.title('regression compare')
        plt.show()
    

    以下是实验记录:
    权重的初始化很重要,初始化成为为0,结果全为0,初始化阶段的正太分布,结果全为负数

    GradientDescentOptimizer
    LR net loss [74.816734]
    sklearn loss 4.22780141391886e-30

    MomentumOptimizer
    LR net loss [1.5802944]
    sklearn loss 2.1308488904700377e-30

    如果数据是稀疏的,用以下四种算法,同时保证可以更快的退出鞍点,用Adam算法,加入动量。
    https://segmentfault.com/a/1190000012668819

    AdagradOptimizer 对稀疏数据很友好
    LR net loss [19.184008]
    sklearn loss 1.1571757477856268e-29

    RMSPropOptimizer
    LR net loss [1.3790985]
    sklearn loss 5.1738182026018704e-30

    AdadeltaOptimizer 结果会非常不稳定
    LR net loss [16.51035]
    sklearn loss 7.90786835165399e-30

    AdamOptimizer
    LR net loss [0.98462635]
    sklearn loss 5.571330143123396e-30

    总结: 使用RMS,Ada系列的优化器会使结果好一些,但是这几种不同的优化器之间的效果差距不大。 一般选用Adam优化器

    AdamOptimizer + 加入L2正则化项
    LR net loss [0.0768552]
    sklearn loss 4.7639803104362666e-30
    使模型权重变小,结果更平滑。

    AdamOptimizer + 加入L1正则化项
    LR net loss [5.0768552]
    sklearn loss 4.7639803104362666e-30
    L1正则化效果很差,我猜测是因为正则化使权重稀疏,结果主要收到个别权重影响,但是个别的权重学习不好,所以整体效果不好。
    同时L1正则化的梯度恒定,有可能在梯度下降中不收敛。
    L1对异常点的容忍度很高,模型不容易过拟合。所以整体应该是欠拟合。

    AdamOptimizer + 加入L2正则化项 + huber 损失(之前默认L2损失)
    LR net loss [0.58679754]
    sklearn loss 3.3163743270370446e-29

    使用huberloss,加大对异常点的容忍,使损失较小的时候梯度平滑。

    AdamOptimizer + 加入L2正则化项 + L2 损失 + 归一化
    LR net loss [0.989549]
    sklearn loss 1.8846380063795735e-29
    归一化的作用:1. 模型需要 2.较少数值影响 3. 归纳分布 4.促进模型收敛 5. 减速模型的梯度收敛
    https://www.cnblogs.com/silence-tommy/p/7113498.html

    1. 神经网络训练开始前,都要对数据做一个归一化处理,归一化有很多好处,原因是网络学习的过程的本质就是学习数据分布,一旦训练数据和测试数据的分布不同,那么网络的泛化能力就会大大降低.

    2. 每一批次的数据分布如果不相同的话,那么网络就要在每次迭代的时候都去适应不同的分布,这样会大大降低网络的训练速度,这也就是为什么要对数据做一个归一化预处理的原因。另外对图片进行归一化处理还可以处理光照,对比度等影响。
      由此又可以引出来神经网络的BN层结构。
      事实上BN用于解决多层神经网络的传递的数据分布不均衡问题。 在线性回归中无法使用。

    AdamOptimizer + 加入L2正则化项 + L2 损失 + 归一化 + 修改infer的方式
    LR net loss [1.4737219]
    sklearn loss 8.079969451484434e-29

    seq0

    到此,整个实验就结束了。 最后我自己用tensorflow实现的linear还是比不过sklean提供的线性模型。即使是loss很小,但是画图可以观察到我的模型结果很不稳定。
    所以我专门去看了sklearn的源码。linear源码:数据预处理和稀疏矩阵处理,如果是稀疏的,直接用稀疏矩阵的最小二乘法,如果是普通的直接用scipy的最小二乘法。但是又被scipy封装了, 这样就没有办法继续看了。

  • 相关阅读:
    VC++中使用内存映射文件处理大文件
    802.1x协议解析
    Jscript中window.setInterval和window.setTimeout区别
    在C#中使用代理的方式触发事件
    JavaScript实用的一些技巧
    控制C#编的程序内存的占用
    纯C#钩子实现及应用(转)
    DES的建立过程
    C# 显示占用内存
    解决“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”
  • 原文地址:https://www.cnblogs.com/x739400043/p/11302676.html
Copyright © 2011-2022 走看看