机器学习:过拟合、神经网络Dropout

过拟合


过拟合现象

机器学习中,过拟合现象就是训练模型高度适用于训练集,而对测试集或未知数据集效果不好的情况。表现为训练集过度拟合具有高准确率,而测试集的准确率明显低于测试集。


防止过拟合

防止过拟合的方法有:增加数据集,正则化方法以及Dropout方法。

1. 增加数据集

  • 数据挖掘中,数据量越多,对模型参数调整就越准确。多的数据往往比好的训练模型要重要,因此,增加数据集,能明显的提高准确率、模型的可靠性以及防止过拟合。

2. 正则化方法

  • 在代价函数中加入一个正则项,例如:
    C=C0+λ2nww2C=C0+λ2n∑ww2

    其中,CC表示新的代价函数,C0C0表示原来的代价函数,比如二次代价函数;λλ表示可调参数用来调节正则项的重要性,nn表示数据集大小;ww表示权值。
  • 在进行权值更新时,多考虑一个正则项。即要使得代价函数变小,则要求正则项变小。从而使得接近于0的权值变得几乎等于0,继而削弱某些神经元的影响,减小了网络的复杂程度。

3. Dropout

训练的过程中,使得部分神经元工作,部分神经元不工作。而在测试的时候,激活所有的神经元。可以尝试用下图来理解:

这里写图片描述


Dropout实例(在Tensorflow框架下实现神经网络)

以UCI的鸢尾花数据集Iris Data Set为例,在tensorflow中创建一个神经网络对iris.data进行分类。并使用dropout防止过拟合。

1.没使用Dropout之前

  • python代码
import tensorflow as tf

def min_max(data, new_min=0.0, new_max=1.0):
    """定义最小-最大规范化函数"""
    min_max_data = []
    for value in data:
        value = (value-min(data)) / (max(data)-min(data)) * (new_max - new_min) + new_min  # 最小最大规范化公式
        value = round(value, 2)   # 保留两位小数
        min_max_data.append(value)
    return min_max_data


def data_pre(filename):
    """数据预处理"""
    with open(filename,'r') as f:
        content = f.read()
    iris_list = content.strip().split('\n')
    label_data = []

    labels = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']   # 三种鸢尾花标签

    # 鸢尾花4个属性值列表
    sepal_length = []
    sepal_width = []
    petal_length = []
    petal_width = []

    for iris in iris_list:
        iris_data = iris.split(',')
        sepal_length.append(float(iris_data[0]))
        sepal_width.append(float(iris_data[1]))
        petal_length.append(float(iris_data[2]))
        petal_width.append(float(iris_data[2]))

        tmp_list = [0,0,0]   # 表示类别的小列表
        if iris_data[-1] in labels:
            index = labels.index(iris_data[-1])
            tmp_list[index] = 1
        label_data.append([tmp_list])

    # 对4个属性进行规范化
    norm_sepal_length = min_max(sepal_length)
    norm_sepal_width = min_max(sepal_width)
    norm_petal_length = min_max(petal_length)
    norm_petal_width = min_max(petal_width)

    attribute_data = []
    for i in range(len(norm_petal_length)):
        a_list = [[norm_sepal_length[i], norm_sepal_width[i], norm_petal_length[i], norm_petal_width[i]]]
        attribute_data.append(a_list)

    return attribute_data, label_data

def run_tensorflow_nn(attribute_data, label_data):
    """使用tensorflow训练神经网络"""
    # 定义两个placeholder分别储存输入值向量x和输出值向量y
    x = tf.placeholder(tf.float32,[1,4])
    y = tf.placeholder(tf.float32,[1,3])

    # 创建神经网络,包含两个隐含层,输入层有4个神经元对应4个属性值,输出层为3个神经元对应3个类别值

    # 初始化第一层权值和偏置值
    W1 = tf.Variable(tf.truncated_normal([4, 200], stddev=0.1))  # 用截断的正态分布,标准差为0.1
    b1 = tf.Variable(tf.zeros([200])+0.1)
    # 第一层输出
    L1 = tf.nn.tanh(tf.matmul(x,W1) + b1)

    # 初始化第二层权值和偏置值
    W2 = tf.Variable(tf.truncated_normal([200, 80], stddev=0.1))
    b2 = tf.Variable(tf.zeros([80])+0.1)
    # 第二层输出
    L2 = tf.nn.tanh(tf.matmul(L1,W2) + b2)

    # 初始化输出层权值和偏置值
    W3 = tf.Variable(tf.truncated_normal([80,3], stddev=0.1))
    b3 = tf.Variable(tf.zeros([3])+0.1)
    # 输出层输出
    output = tf.nn.softmax(tf.matmul(L2, W3) + b3)  # 多分类问题输出层神经元激活函数用softmax()函数

    # 定义交叉熵代价函数
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=output))

    # 使用梯度下降法
    train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)

    # 定义判断结果变量,储存在布尔型列表中, tf.argmax() 返回列表的最大值所在的索引值
    correct_output = tf.equal(tf.argmax(y,1), tf.argmax(output,1))  # tf.equal()比较里面两个参数是否相等,返回True和False

    # 求准确计数
    accuracy = tf.cast(correct_output, tf.float32)   # tf.cast()把布尔型转换为32位浮点型

    # 进行训练
    with tf.Session() as sess:
        # 初始化变量
        init = tf.global_variables_initializer()
        sess.run(init)

        for epoch in  range(5): # 循环5个周期
            for i in range(len(attribute_data[:100])):
                train_x = attribute_data[i]
                train_y = label_data[i]
                sess.run(train_step, feed_dict={x:train_x, y:train_y})

            # 计算训练集准确率
            train_count = []
            for i in range(len(attribute_data[:100])):
                train_x = attribute_data[i]
                train_y = label_data[i]
                train_count.append(sess.run(accuracy, feed_dict={x:train_x, y:train_y})[0])

            train_acc = sum(train_count) / len(train_count)
            # print(train_acc)

            # 计算测试集准确率
            test_count = []
            for i in range(len(attribute_data[100:])):
                test_x = attribute_data[i]
                test_y = label_data[i]
                # sess.run(train_step, feed_dict={x: test_x, y: test_y})
                test_count.append(sess.run(accuracy, feed_dict={x: test_x, y: test_y})[0])
            test_acc = sum(test_count) / len(test_count)
            print("第" + str(epoch+1) + "个训练周期训练集的准确率为:{}%".format(train_acc*100)+", ","测试集的准确率为:{}%".format(test_acc*100),'\n')


if __name__ == "__main__":

    filename = 'iris.data'
    attribute_data, label_data = data_pre(filename)
    run_tensorflow_nn(attribute_data, label_data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 运行结果
1个训练周期训练集的准确率为:33.3%,  测试集的准确率为:32.2%2个训练周期训练集的准确率为:33.3%,  测试集的准确率为:32.2%3个训练周期训练集的准确率为:36.7%,  测试集的准确率为:35.6%4个训练周期训练集的准确率为:62.2%,  测试集的准确率为:62.7%5个训练周期训练集的准确率为:66.7%,  测试集的准确率为:64.4%6个训练周期训练集的准确率为:66.7%,  测试集的准确率为:67.8%7个训练周期训练集的准确率为:66.7%,  测试集的准确率为:67.8%8个训练周期训练集的准确率为:66.7%,  测试集的准确率为:67.8%9个训练周期训练集的准确率为:67.8%,  测试集的准确率为:67.8%10个训练周期训练集的准确率为:68.9%,  测试集的准确率为:67.8% 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. 使用Dropout之后

  • 代码
import tensorflow as tf

def min_max(data, new_min=0.0, new_max=1.0):
    """定义最小-最大规范化函数"""
    min_max_data = []
    for value in data:
        value = (value-min(data)) / (max(data)-min(data)) * (new_max - new_min) + new_min  # 最小最大规范化公式
        value = round(value, 2)   # 保留两位小数
        min_max_data.append(value)
    return min_max_data


def data_pre(filename):
    """数据预处理"""
    with open(filename,'r') as f:
        content = f.read()
    iris_list = content.strip().split('\n')
    label_data = []

    labels = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']   # 三种鸢尾花标签

    # 鸢尾花4个属性值列表
    sepal_length = []
    sepal_width = []
    petal_length = []
    petal_width = []

    for iris in iris_list:
        iris_data = iris.split(',')
        sepal_length.append(float(iris_data[0]))
        sepal_width.append(float(iris_data[1]))
        petal_length.append(float(iris_data[2]))
        petal_width.append(float(iris_data[2]))

        tmp_list = [0,0,0]   # 表示类别的小列表
        if iris_data[-1] in labels:
            index = labels.index(iris_data[-1])
            tmp_list[index] = 1
        label_data.append([tmp_list])

    # 对4个属性进行规范化
    norm_sepal_length = min_max(sepal_length)
    norm_sepal_width = min_max(sepal_width)
    norm_petal_length = min_max(petal_length)
    norm_petal_width = min_max(petal_width)

    attribute_data = []
    for i in range(len(norm_petal_length)):
        a_list = [[norm_sepal_length[i], norm_sepal_width[i], norm_petal_length[i], norm_petal_width[i]]]
        attribute_data.append(a_list)

    return attribute_data, label_data

def run_tensorflow_nn(attribute_data, label_data):
    """使用tensorflow训练神经网络"""
    # 定义两个placeholder分别储存输入值向量x和输出值向量y
    x = tf.placeholder(tf.float32,[1,4])
    y = tf.placeholder(tf.float32,[1,3])
    keep_prob = tf.placeholder(tf.float32)

    # 创建神经网络,包含两个隐含层,输入层有4个神经元对应4个属性值,输出层为3个神经元对应3个类别值

    # 初始化第一层权值和偏置值
    W1 = tf.Variable(tf.truncated_normal([4, 200], stddev=0.1))  # 用截断的正态分布,标准差为0.1
    b1 = tf.Variable(tf.zeros([200])+0.1)
    # 第一层输出
    L1 = tf.nn.tanh(tf.matmul(x,W1) + b1)
    L1_drop = tf.nn.dropout(L1, keep_prob)  # keep_prob表示有多少比例的神经元工作
    # 初始化第二层权值和偏置值
    W2 = tf.Variable(tf.truncated_normal([200, 80], stddev=0.1))
    b2 = tf.Variable(tf.zeros([80])+0.1)
    # 第二层输出
    L2 = tf.nn.tanh(tf.matmul(L1_drop,W2) + b2)
    L2_drop = tf.nn.dropout(L2, keep_prob)

    # 初始化输出层权值和偏置值
    W3 = tf.Variable(tf.truncated_normal([80,3], stddev=0.1))
    b3 = tf.Variable(tf.zeros([3])+0.1)
    # 输出层输出
    output = tf.nn.softmax(tf.matmul(L2_drop, W3) + b3)  # 多分类问题输出层神经元激活函数用softmax()函数

    # 定义交叉熵代价函数
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=output))

    # 使用梯度下降法
    train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)

    # 定义判断结果变量,储存在布尔型列表中, tf.argmax() 返回列表的最大值所在的索引值
    correct_output = tf.equal(tf.argmax(y,1), tf.argmax(output,1))  # tf.equal()比较里面两个参数是否相等,返回True和False

    # 求准确计数
    accuracy = tf.cast(correct_output, tf.float32)   # tf.cast()把布尔型转换为32位浮点型

    # 进行训练
    with tf.Session() as sess:
        # 初始化变量
        init = tf.global_variables_initializer()
        sess.run(init)

        # 划分训练集和测试集
        train_attribute_data = attribute_data[:30] + attribute_data[50:80] + attribute_data[100:130]  # 训练集
        train_label_data = label_data[:30] + label_data[50:80] + label_data[100:130]  # 均匀的取三个类别的数据
        test_attribute_data = attribute_data[30:50] + attribute_data[80:100] + attribute_data[130:-1] # 测试集
        test_label_data = label_data[30:50] + label_data[80:100] + label_data[130:-1]

        for epoch in  range(10): # 循环5个周期
            for i in range(len(train_attribute_data)):
                train_x = train_attribute_data[i]
                train_y = train_label_data[i]
                sess.run(train_step, feed_dict={x:train_x, y:train_y,keep_prob: 0.7})

            # 计算训练集准确率
            train_count = []
            for i in range(len(train_attribute_data)):
                train_x = train_attribute_data[i]
                train_y = train_label_data[i]
                train_count.append(sess.run(accuracy, feed_dict={x:train_x, y:train_y, keep_prob: 1})[0])

            train_acc = sum(train_count) / len(train_count)
            # print(train_acc)
            # 计算测试集准确率
            test_count = []
            for i in range(len(test_attribute_data)):
                test_x = test_attribute_data[i]
                test_y = test_label_data[i]
                test_count.append(sess.run(accuracy, feed_dict={x: test_x, y: test_y, keep_prob: 1})[0])
            test_acc = sum(test_count) / len(test_count)
            print("第" + str(epoch+1) + "个训练周期训练集的准确率为:{:.1f}%".format(train_acc*100)+", ","测试集的准确率为:{:.1f}%".format(test_acc*100),'\n')


if __name__ == "__main__":

    filename = 'iris.data'
    attribute_data, label_data = data_pre(filename)
    run_tensorflow_nn(attribute_data, label_data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 运行结果
1个训练周期训练集的准确率为:33.3%,  测试集的准确率为:32.2%2个训练周期训练集的准确率为:33.3%,  测试集的准确率为:32.2%3个训练周期训练集的准确率为:44.4%,  测试集的准确率为:42.4%4个训练周期训练集的准确率为:66.7%,  测试集的准确率为:64.4%5个训练周期训练集的准确率为:66.7%,  测试集的准确率为:66.1%6个训练周期训练集的准确率为:66.7%,  测试集的准确率为:66.1%7个训练周期训练集的准确率为:66.7%,  测试集的准确率为:66.1%8个训练周期训练集的准确率为:66.7%,  测试集的准确率为:66.1%9个训练周期训练集的准确率为:66.7%,  测试集的准确率为:67.8%10个训练周期训练集的准确率为:66.7%,  测试集的准确率为:66.1% 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 总结:

使用Dropout相比于没使用之前,效果不是太明显-.-,就当为了实现Dropout一个例子吧。可能是iris.data数据集比较好(噪声和离群点少)的缘故。 
另外,本例代码还能够优化,Tensorflow水很深,继续学习吧。。


参考资料

讲师Ben: 炼数成金课程——深度学习框架Tensorflow学习与应用 
UCI Machine Learning Repository : Iris Data Set

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值