机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(五)
上幾節(jié)講述了真實數(shù)據(jù)集在回歸問題以及分類問題上的總流程,但是對于模型的選擇及參數(shù)的選擇仍然一知半解,因此本節(jié)開始講述關(guān)于模型的一些知識,本節(jié)會略過一些比較基礎(chǔ)的知識,將一些較為深入的知識。如果在哪個方面沒有看懂,可以在網(wǎng)上查詢,網(wǎng)上基礎(chǔ)資料也比較多,也可以在下方評論。
五、訓練模型
1、線性模型
線性模型形如:
y=θ0+θ1x1+θ2x2+?θnxny=θ0+θ1x1+θ2x2+?θnxn 為了得到使均方誤差最小的θθ,一般采用兩種方法:Normal Equation
使用數(shù)學方法推導能直接求得參數(shù)θθ的方法為Normal Equation。而對于線性模型,數(shù)學方法為:最小二乘法。
通過最小二乘法能直接得到線性模型:
θ^=(XTX)?1XTyθ^=(XTX)?1XTy 對應的Scikit-learn中的函數(shù)為LinearRegression,下面是一個例子y=4*x+3 import numpy as np X = 2 * np.random.rand(100, 1) y = 4 + 3 * X + np.random.randn(100, 1)from sklearn.linear_model import LinearRegression lin_reg = LinearRegression() lin_reg.fit(X, y) lin_reg.intercept_, lin_reg.coef_- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
可以看到得到的結(jié)果接近4和3,沒有達到準確值是由于加入了隨機噪聲的原因。
??雖然能夠精確的得到結(jié)果,但是這個算法的復雜度很高,計算XTXXTX?的逆的算法復雜度就為O(n2.4)?O(n3)O(n2.4)?O(n3),如果訓練樣本非常大,則運行時間會很長。而且這只是只有一種特征的情況,則運行時間會更長。?
??因此這種方法適合數(shù)據(jù)量較小的情況,能夠找到精確解。
梯度下降法(Gradient Descent)
??為了處理訓練樣本數(shù)比較大數(shù)據(jù),通常采用梯度下降法,得到一個近似解,但是速度較快。梯度下降法就是通過設(shè)置學習率eta與迭代次數(shù),每一代計算目標函數(shù)的梯度來更新權(quán)值的方法。(具體不做介紹)?
??學習率太小會導致收斂太慢,學習率太大會導致偏離最優(yōu)解,因此可以通過之前講的grid search來調(diào)整參數(shù)。對于迭代次數(shù)可以一開始設(shè)置一個比較大的數(shù),當梯度開始變得很小時,則可以停下來,記錄迭代次數(shù)。
Batch Gradient Descent
Batch Gradient Descent即每次迭代使用所有樣本計算梯度,取平均,來更新參數(shù)。可以看到這個方法能直接朝著最優(yōu)解方向前進。
??????????????
eta = 0.1 # learning rate n_iterations = 1000 m = 100 theta = np.random.randn(2,1) # random initialization X_b = np.c_[np.ones((100, 1)), X] for iteration in range(n_iterations):gradients = 2/float(m) * X_b.T.dot(X_b.dot(theta) - y)theta = theta - eta * gradients- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Stochastic Gradient Descent
??由于Batch Gradient Descent每次迭代使用全部訓練集,當訓練集數(shù)據(jù)量較大時,訓練速度則會很慢。因此與這個相反,隨機梯度下降(Stochastic Gradient Descent)就是每一代隨機選擇一個樣本,計算梯度,更新參數(shù)。由于每次只抽取一個樣本,因此在大量數(shù)據(jù)也能很好的計算。
?????????????
??但是當接近最優(yōu)解時(如圖)始終無法收斂到最優(yōu)解,這是由于每次根據(jù)一個樣本更新參數(shù),每個樣本都有自己的梯度方向,所以會不斷的在最優(yōu)解附近振蕩。為了解決這個問題,引入了learning_schedule參數(shù),這個一個學習率衰減參數(shù),在迭代的過程中,不斷減少學習率,在迭代結(jié)束時學習率非常小,可以看作不再振蕩,接近最優(yōu)解。
隨機梯度下降skicit-learn也有對應的函數(shù):其中n_iter為迭代次數(shù),eta0為學習率,penalty下面會說到。
from sklearn.linear_model import SGDRegressor sgd_reg = SGDRegressor(n_iter=50, penalty=None, eta0=0.1) sgd_reg.fit(X, y.ravel()) sgd_reg.intercept_, sgd_reg.coef_- 1
- 2
- 3
- 4
Mini-batch Gradient Descent
??結(jié)合Batch Gradient Descent和Stochastic Gradient Descent,每一代計算Mini-batch(遠小于Batch)個樣本的梯度,計算平均值,更新參數(shù)。這種方式的好處是能在數(shù)據(jù)量比較大的訓練樣本中進行矩陣運算,特別是可以在GPU上計算。(在深度學習中運用的比較多)?
2、多項式模型
??如果數(shù)據(jù)不是簡單的一條直線,也可以通過線性模型來訓練,其中一種比較簡單的方法是通過給訓練數(shù)據(jù)特征開n次方。下面是一個例子:
m = 100 X = 6 * np.random.rand(m, 1) - 3 y = 0.5 * X**2 + X + 2 + np.random.randn(m, 1)from sklearn.preprocessing import PolynomialFeatures poly_features = PolynomialFeatures(degree=2, include_bias=False) X_poly = poly_features.fit_transform(X) X[0],X_poly[0]- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
可以看到,通過PolynomialFeatures以后,得到新的特征(x,x2)(x,x2),再用這個新特征訓練一個線性模型。
lin_reg = LinearRegression() lin_reg.fit(X_poly, y)- 1
- 2
注:若存在兩個特征a和b,若degree=2時,不僅增加了a2a2和b2b2,還有abab
Learning Curves
??如果使用高degree創(chuàng)造非常多特征來作多項式模型,你能夠很好的擬合訓練數(shù)據(jù)。然而這種只對訓練數(shù)據(jù)擬合的情況稱為過擬合(如圖),而對于線性模型則為欠擬合。
????
??為了檢測模型是否有效,在第3節(jié)已經(jīng)講述了其中一種方法,交叉驗證法。下面再介紹一種方法Learning Curves。通過分開訓練和驗證集,不斷調(diào)整訓練集的數(shù)量,計算均方誤差來畫出曲線,觀察訓練集和驗證集在訓練中的情況。
import matplotlib.pyplot as plt from sklearn.metrics import mean_squared_error from sklearn.model_selection import train_test_split def plot_learning_curves(model, X, y):X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)train_errors, val_errors = [], []for m in range(1, len(X_train)):model.fit(X_train[:m], y_train[:m])y_train_predict = model.predict(X_train[:m])y_val_predict = model.predict(X_val)train_errors.append(mean_squared_error(y_train_predict, y_train[:m]))val_errors.append(mean_squared_error(y_val_predict, y_val))plt.plot(np.sqrt(train_errors), "r-+", linewidth=2, label="train")plt.plot(np.sqrt(val_errors), "b-", linewidth=3, label="val")plt.xlabel("Training set size") plt.ylabel("RMSE") lin_reg = LinearRegression() plot_learning_curves(lin_reg, X, y)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
????????
??可以看到當訓練集中只有一個或兩個實例時,模型可以完美地擬合它們,這就是曲線從零開始的原因。但是,當新樣本被添加到訓練集時,模型不可能很好地擬合訓練數(shù)據(jù),這是由于樣本是復雜的。再看看驗證數(shù)據(jù)上模型的性能。當模型在很少的訓練樣本時,就不能很好的泛化推廣,這就是為什么驗證錯誤最初是相當大的。當新樣本被添加到訓練集時,通過學習,從而驗證錯誤緩慢下降。誤差最終會停留在一個類似高原的地方。?
??上面為degree=1的模型,再看看degree=10的模型
- 1
- 2
- 3
- 4
- 5
- 6
- 7
??????????
??可以看到degree=10的訓練誤差和驗證誤差都比degree=1的要小。所以該模型較好。我們還可以看到兩條曲線中間的間隙,間隙越大,說明過擬合程度越大。?
3、正則化線性模型(Regularized Linear Models)
為了防止過擬合,可以給模型損失函數(shù)(如均方誤差)增加正則項。
Ridge Regression(L2正則化)
Ridge Regression的損失函數(shù)為:
J(θ)=MSE(θ)+α12∑i=1nθi2J(θ)=MSE(θ)+α12∑i=1nθi2??可以看到加入后面的正則項后會使θθ靠近0,直觀上可以理解為對MSE(θ)MSE(θ)(即模型)貢獻越小的θθ,懲罰越大,這樣的θθ越小,所以通過正則化能夠減小這些無關(guān)特征帶來的影響。
需要注意的是:在Ridge Regression之前要先對特征進行縮放(標準化或最大最小縮放),這是因為Ridge Regression對特征的尺度大小很敏感。
??同樣有兩種方法計算最優(yōu)解Normal Equation和梯度下降法。
??對于Normal Equation結(jié)果為:
θ^?= (XTX +?αA)?1XTyθ^?= (XTX +?αA)?1XTy對應的代碼為
from sklearn.linear_model import Ridge ridge_reg = Ridge(alpha=1, solver="cholesky") ridge_reg.fit(X, y)- 1
- 2
- 3
隨機梯度下降L2正則化對應的代碼為
from sklearn.linear_model import SGDRegressor sgd_reg = SGDRegressor(penalty="l2") sgd_reg.fit(X, y.ravel())- 1
- 2
- 3
??????????
?? 通過設(shè)置不同的αα值,可以看到通過正則化后曲線變得平緩,看起來比沒有正則化的曲線有著更好的泛化推廣能力。
Lasso Regression(L1正則化)
Lasso Regression的損失函數(shù)為:?
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
???????????
可以看到經(jīng)過L1正則化后曲線變得更加平緩,更像一條直線。
需要注意的是:L1正則化后會導致在最優(yōu)點附近震蕩,因此要像隨機梯度下降一樣減小學習率。
Elastic Net
Elastic Net的損失函數(shù)為:
J(θ)=MSE(θ)+rα∑i=1n|θi|+1?r2α∑i=1nθi2J(θ)=MSE(θ)+rα∑i=1n|θi|+1?r2α∑i=1nθi2??可以看到Elastic Net是L1正則化和L2正則化的結(jié)合,通過一個參數(shù)調(diào)整比例。
#最小二乘ElasticNet方法 from sklearn.linear_model import ElasticNet elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5) elastic_net.fit(X, y)#隨機梯度下降ElasticNet(線性) from sklearn.linear_model import SGDRegressor sgd_reg = SGDRegressor(penalty="elasticnet",l1_ratio=0.5) sgd_reg.fit(X, y.ravel())- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
如何選擇正則化
??加入少量的正則化一般都會給模型帶來一定的提升。一般情況下都會選擇Ridge(L2正則化);但是如果得知數(shù)據(jù)中只有少量的特征是有用的,那么推薦使用Lasso(L1正則化)或Elastic Net;一般來說Elastic Net會比Lasso效果要好,因為當遇到強相關(guān)性特征說特征數(shù)量大于訓練樣本時Lasso會表現(xiàn)的很奇怪。?
提前中斷訓練(Early Stopping)
??通過調(diào)整迭代次數(shù),在驗證誤差達到最小時立即停止訓練。圖中是用Batch Gradient Descent訓練的,隨著迭代次數(shù)的上升,驗證集上的預測誤差會下降。 但是,過了一段時間驗證錯誤停止下降,反而往上開始回升。 這表明該模型已經(jīng)開始過度擬合訓練數(shù)據(jù)。 一旦驗證錯誤達到最小,立即停止訓練。 這是一種簡單而有效的正則化技術(shù)。
??????
需要注意的是:對于Stochastic 和 Mini-batch Gradient Descent的曲線不會這么平滑。其中一種方案是當?shù)竭_最低點時,再過一段時間(當你覺得不會再下降),停止,將參數(shù)調(diào)回到當時的最低點。
下面是一個例子,當warm_start=True時,調(diào)用fit()后繼續(xù)訓練模型而不是重新訓練模型。
from sklearn.base import clone sgd_reg = SGDRegressor(n_iter=1, warm_start=True, penalty=None, learning_rate="constant", eta0=0.0005) minimum_val_error = float("inf") #正無窮 best_epoch = None best_model = None for epoch in range(1000):sgd_reg.fit(X_train_poly_scaled, y_train) # 繼續(xù)訓練y_val_predict = sgd_reg.predict(X_val_poly_scaled)val_error = mean_squared_error(y_val_predict, y_val)if val_error < minimum_val_error:minimum_val_error = val_errorbest_epoch = epochbest_model = clone(sgd_reg) #保存模型- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
4、Logistic回歸(Logistic Regression)
Logistic回歸與線性回歸模型比較相似,Logistic回歸在線性回歸模型的基礎(chǔ)上增加了sigmoid函數(shù)σ()σ(),即
hθ(x)=σ(θTx)hθ(x)=σ(θTx) 其中 σ(t)=11+e?tσ(t)=11+e?t 損失函數(shù)采用對數(shù)似然損失函數(shù): J(θ)=?1m∑i=1m[yilog(hθ(xi))+(1?yi)log(1?hθ(xi)]J(θ)=?1m∑i=1m[yilog?(hθ(xi))+(1?yi)log?(1?hθ(xi)] 訓練與線性回歸模型相似,可以計算梯度,用梯度下降法更新參數(shù)。??下面利用Logistic回歸對真實數(shù)據(jù)Iris進行分類。Iris數(shù)據(jù)為150個訓練樣本,包含4個特征,分為3類。
??首先先用Logistic模型作一個二分類器。取出其中一種特征,判斷是否為某一類。
#Iris import numpy as np from sklearn import datasets iris = datasets.load_iris() X = iris["data"][:, 3:] # 只讀取最后一個特征 y = (iris["target"] == 2).astype(np.int) # 取出判斷是否為第3類的label#訓練Logistic回歸模型 from sklearn.linear_model import LogisticRegression log_reg = LogisticRegression() log_reg.fit(X, y)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
對于一個二分類問題,還可以畫出判別線
????????????
注:對于Logistic回歸同樣需要L1,L2正則化,而這個scikit-learn也默認設(shè)置了。?
4、Softmax回歸(Softmax Regression)
??對于Logistic回歸是一個二分類器,然而不需要像第4節(jié)所講到了訓練多個二分類器來實現(xiàn)多分類。Logistic回歸可以直接擴展成一個多分類器Softmax回歸。
??與Logistic回歸相似,Softmax回歸計算每一類的一個概率,歸為概率最大的一類。
Softmax函數(shù)為:
p^k=σ(s(x))k=exp(sk(x))∑j=1Kexp(sj(x))p^k=σ(s(x))k=exp?(sk(x))∑j=1Kexp?(sj(x)) 其中: sk(x)=θkTxsk(x)=θkTx 其中K為類別數(shù),需要注意的是 θkθk說明每個類別對應有自己的 θθ,所有 θkθk組合起來是全部的參數(shù)。對于Softmax回歸使用交叉熵(cross entropy)函數(shù)作為損失函數(shù):
J(θ)=?1m∑i=1m∑k=1Kyk(i)log(p^k(i))J(θ)=?1m∑i=1m∑k=1Kyk(i)log?(p^k(i)) 訓練與線性回歸模型相似,可以計算每一類的偏導數(shù),用梯度下降法更新每一類的參數(shù)。下面是一個實例,LogisticRegression默認使用(OVA),如果使用Softmax就把multi_class=”multinomial”
X = iris["data"][:, (2, 3)] # petal length, petal width y = iris["target"] softmax_reg = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10) softmax_reg.fit(X, y)- 1
- 2
- 3
- 4
總結(jié)
以上是生活随笔為你收集整理的机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(五)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习实战(用Scikit-learn
- 下一篇: 机器学习实战(用Scikit-learn