过拟合
过拟合现象
机器学习中,过拟合现象就是训练模型高度适用于训练集,而对测试集或未知数据集效果不好的情况。表现为训练集过度拟合具有高准确率,而测试集的准确率明显低于测试集。
防止过拟合
防止过拟合的方法有:增加数据集,正则化方法以及Dropout方法。
1. 增加数据集
- 数据挖掘中,数据量越多,对模型参数调整就越准确。多的数据往往比好的训练模型要重要,因此,增加数据集,能明显的提高准确率、模型的可靠性以及防止过拟合。
2. 正则化方法
- 在代价函数中加入一个正则项,例如:
C=C0+λ2n∑ww2C=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