A-A+

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

2020年04月30日 23:45 汪洋大海 暂无评论 共8593字 (阅读1,671 views次)

过拟合


过拟合现象

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


防止过拟合

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

1. 增加数据集

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

2. 正则化方法

  • 在代价函数中加入一个正则项,例如:

    其中,表示新的代价函数,表示原来的代价函数,比如二次代价函数;表示可调参数用来调节正则项的重要性,表示数据集大小;表示权值。

  • 在进行权值更新时,多考虑一个正则项。即要使得代价函数变小,则要求正则项变小。从而使得接近于0的权值变得几乎等于0,继而削弱某些神经元的影响,减小了网络的复杂程度。

3. Dropout

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

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


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

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

1.没使用Dropout之前

  • python代码
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
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
第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%

2. 使用Dropout之后

  • 代码
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
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
第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%
  • 总结:

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

文字来源:https://blog.csdn.net/weixin_40170902/article/details/80092553

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×
标签:

给我留言