天天看點

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

過于自負

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

在細說之前, 我們先用實際生活中的一個例子來比喻一下過拟合現象. 說白了, 就是機器學習模型于自信. 已經到了自負的階段了. 那自負的壞處, 大家也知道, 就是在自己的小圈子裡表現非凡, 不過在現實的大圈子裡卻往往處處碰壁. 是以在這個簡介裡, 我們把自負和過拟合畫上等号

回歸分類的過拟合

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

機器學習模型的自負又表現在哪些方面呢. 這裡是一些資料. 如果要你畫一條線來描述這些資料, 大多數人都會這麼畫. 對, 這條線也是我們希望機器也能學出來的一條用來總結這些資料的線. 這時藍線與資料的總誤差可能是10. 可是有時候, 機器過于糾結這誤內插補點, 他想把誤差減到更小, 來完成他對這一批資料的學習使命. 是以, 他學到的可能會變成這樣 . 它幾乎經過了每一個資料點, 這樣, 誤內插補點會更小 . 可是誤差越小就真的好嗎? 看來我們的模型還是太天真了. 當我拿下面圖中的這個模型運用在現實中的時候, 他的自負就展現出來. 小二, 來一打現實資料 . 這時, 之前誤差大的藍線誤差基本保持不變 .誤差小的 紅線誤內插補點突然飙高 , 自負的紅線再也驕傲不起來, 因為他不能成功的表達除了訓練資料以外的其他資料. 這就叫做過拟合. Overfitting.

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

那麼在分類問題當中. 過拟合的分割線可能是這樣, 小二, 再上一打資料 . 我們明顯看出, 有兩個黃色的資料并沒有被很好的分隔開來. 這也是過拟合在作怪.好了, 既然我們時不時會遇到過拟合問題, 那解決的方法有那些呢.

解決方法一

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

方法一: 增加資料量, 大部分過拟合産生的原因是因為資料量太少了. 如果我們有成千上萬的資料, 紅線也會慢慢被拉直, 變得沒那麼扭曲 .

解決方法二:

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

建立 dropout 層

import tensorflow as tf
from sklearn.datasets import load_digits
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import LabelBinarizer
           
#define placeholeder for inputs to network
keep_prob = tf.placeholder(tf.float32)
xs = tf.placeholder(tf.float32,[None,64])  #8*8
ys = tf.placeholder(tf.float32,[None,10])
           

這裡的keep_prob是保留機率,即我們要保留的結果所占比例,它作為一個placeholder,在run時傳入, 當keep_prob=1的時候,相當于100%保留,也就是dropout沒有起作用。 下面我們分析一下程式結構,首先準備資料,

#load data 
digits = load_digits()
X = digits.data
y = digits.target
y = LabelBinarizer().fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3)
           

其中X_train是訓練資料, X_test是測試資料。 然後添加隐含層和輸出層

# add output layer
l1 = add_layer(xs, 64, 50, 'l1', activation_function=tf.nn.tanh)
prediction = add_layer(l1, 50, 10, 'l2', activation_function=tf.nn.softmax)
           

loss函數(即最優化目标函數)選用交叉熵函數。交叉熵用來衡量預測值和真實值的相似程度,如****果完全相同,交叉熵就等于零。

cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction),
                                              reduction_indices=[1]))  # loss
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
           

train方法(最優化算法)采用梯度下降法。

訓練

最後開始train,總共訓練500次。

sess.run(train_step, feed_dict={xs: X_train, ys: y_train, keep_prob: 0.5})
#sess.run(train_step, feed_dict={xs: X_train, ys: y_train, keep_prob: 1})
           

可視化結果

訓練中keep_prob=1時,就可以暴露出overfitting問題。keep_prob=0.5時,dropout就發揮了作用。 我們可以兩種參數分别運作程式,對比一下結果。

當keep_prob=1時,模型對訓練資料的适應性優于測試資料,存在overfitting,輸出如下: 紅線是 train 的誤差, 藍線是 test 的誤差.

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

當keep_prob=0.5時效果好了很多,輸出如下:

什麼是過拟合 (Overfitting) 、解決方法、代碼示例(tensorflow實作)

總體代碼

from __future__ import print_function
import tensorflow as tf
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelBinarizer

#load data 
digits = load_digits()
X = digits.data
y = digits.target
y = LabelBinarizer().fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3)

def add_layer(inputs, in_size, out_size, layer_name, activation_function=None, ):
    # add one more layer and return the output of this layer
    Weights = tf.Variable(tf.random_normal([in_size, out_size]))
    biases = tf.Variable(tf.zeros([1, out_size]) + 0.1, )
    Wx_plus_b = tf.matmul(inputs, Weights) + biases
    # here to dropout 加入正則化
    Wx_plus_b = tf.nn.dropout(Wx_plus_b, keep_prob)
    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b, )
    tf.summary.histogram(layer_name + '/outputs', outputs)
    return outputs

#define placeholeder for inputs to network
keep_prob = tf.placeholder(tf.float32)
xs = tf.placeholder(tf.float32,[None,64])  #8*8
ys = tf.placeholder(tf.float32,[None,10])

# add output layer
l1 = add_layer(xs, 64, 50, 'l1', activation_function=tf.nn.tanh)
prediction = add_layer(l1, 50, 10, 'l2', activation_function=tf.nn.softmax)
#the loss between predicton and real data
cross_entropy = tf.reduce_mean(-tf.reduce_sum(ys * tf.log(prediction),
                                              reduction_indices=[1]))  # loss
tf.summary.scalar('loss', cross_entropy)
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

sess = tf.Session()
merged = tf.summary.merge_all()#可視化工具
# summary writer goes in here 
train_writer = tf.summary.FileWriter("logs/train", sess.graph)
test_writer = tf.summary.FileWriter("logs/test", sess.graph)

# tf.initialize_all_variables() no long valid from
# 2017-03-02 if using tensorflow >= 0.12
if int((tf.__version__).split('.')[1]) < 12 and int((tf.__version__).split('.')[0]) < 1:
    init = tf.initialize_all_variables()
else:
    init = tf.global_variables_initializer()
sess.run(init)

for i in range(500):
    sess.run(train_step, feed_dict={xs: X_train, ys: y_train, keep_prob: 0.5})
    if i%50 ==0:
        #record loss
        train_result = sess.run(merged, feed_dict={xs: X_train, ys: y_train, keep_prob: 1})
        test_result = sess.run(merged, feed_dict={xs: X_test, ys: y_test, keep_prob: 1})
        train_writer.add_summary(train_result, i)#可視化工具
        test_writer.add_summary(test_result, i)
           

繼續閱讀