機器學習:過擬合、神經網路Dropout
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

過擬合


過擬合現象

機器學習中,過擬合現象就是訓練模型高度適用於訓練集,而對測試集或未知資料集效果不好的情況。表現為訓練集過度擬合具有高準確率,而測試集的準確率明顯低於測試集。


防止過擬合

防止過擬合的方法有:增加資料集,正則化方法以及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

相關文章

程式語言 最新文章