問題描述:根據水庫中蓄水標線(water level) 使用正則化的線性回歸模型預 水流量(water flowing out of dam),然后 debug 學習算法 以及 討論偏差和方差對 該線性回歸模型的影響
①可視化數據集
本作業的數據集分成三部分:
ⓐ訓練集(training set),樣本矩陣(訓練集):X,結果標簽(label of result)向量 y
ⓑ交叉驗證集(cross validation set),確定正則化參數 Xval 和 yval
ⓒ測試集(test set) for evaluating performance,測試集中的數據 是從未出現在 訓練集中的
將數據加載到Octave中如下:訓練集中一共有12個訓練實例,每個訓練實例只有一個特征。故假設函數hθ(x) = θ0·x0 + θ1·x1 ,用向量表示成:hθ(x) = θT·x
一般地,x0 為 bais unit,默認 x0==1
數據可視化:
②正則化線性回歸模型的代價函數
代價函數公式如下:
Octave代碼實現如下:這里的代價函數是用向量(矩陣)乘法來實現的。
reg = (lambda / (2*m)) * ( ( theta( 2:length(theta) ) )' * theta(2:length(theta)) ); J = sum((X*theta-y).^2)/(2*m) + reg;
注意:由於θ0不參與正則化項的,故上面Octave數組下標是從2開始的(Matlab數組下標是從1開始的,θ0是Matlab數組中的第一個元素)。
③正則化的線性回歸梯度
梯度的計算公式如下:
其中,下面公式的向量表示就是:[XT · (X·θ - y)]/m,用Matlab表示就是:X'*(X*theta-y) / m
梯度的Octave代碼實現如下:
grad_tmp = X'*(X*theta-y) / m;
grad = [ grad_tmp(1:1); grad_tmp(2:end) + (lambda/m)*theta(2:end) ];
function [J, grad] = linearRegCostFunction(X, y, theta, lambda) %LINEARREGCOSTFUNCTION Compute cost and gradient for regularized linear %regression with multiple variables % [J, grad] = LINEARREGCOSTFUNCTION(X, y, theta, lambda) computes the % cost of using theta as the parameter for linear regression to fit the % data points in X and y. Returns the cost in J and the gradient in grad % Initialize some useful values m = length(y); % number of training examples % You need to return the following variables correctly J = 0; grad = zeros(size(theta)); % ====================== YOUR CODE HERE ====================== % Instructions: Compute the cost and gradient of regularized linear % regression for a particular choice of theta. % % You should set J to the cost and grad to the gradient. % reg = (lambda / (2*m)) * ( ( theta( 2:length(theta) ) )' * theta(2:length(theta)) ); J = sum((X*theta-y).^2)/(2*m) + reg; grad_tmp = X'*(X*theta-y) / m; grad = [ grad_tmp(1:1); grad_tmp(2:end) + (lambda/m)*theta(2:end) ]; % ========================================================================= grad = grad(:); end
④使用Octave的函數 fmincg 函數訓練線性回歸模型,得到模型的參數。
function [theta] = trainLinearReg(X, y, lambda) %TRAINLINEARREG Trains linear regression given a dataset (X, y) and a %regularization parameter lambda % [theta] = TRAINLINEARREG (X, y, lambda) trains linear regression using % the dataset (X, y) and regularization parameter lambda. Returns the % trained parameters theta. % % Initialize Theta initial_theta = zeros(size(X, 2), 1); % Create "short hand" for the cost function to be minimized costFunction = @(t) linearRegCostFunction(X, y, t, lambda); % Now, costFunction is a function that takes in only one argument options = optimset('MaxIter', 200, 'GradObj', 'on'); % Minimize using fmincg theta = fmincg(costFunction, initial_theta, options); end
⑤線性回歸模型的圖形化表示
上面已經通過 fmincg 求得了模型參數了,那么我們求得的模型 與 數據的擬合程度 怎樣呢?看下圖:
從上圖中可以看出,由於我們的數據是二維的,但是卻用一個線性模型去擬合,故很明顯出現了 underfiting problem
在這里,我們很容易將模型以圖形化方式表現出來,因為,我們的訓練數據的特征很少(一維)。當訓練數據的特征很多(feature variables)時,就很難畫圖了(三維以上很難直接用圖形表示了...)。這時,就需要用 “學習曲線”來檢查 訓練出來的模型與數據是否很好地擬合了。
⑥偏差與方差之間的權衡
高偏差---欠擬合,underfit
高方差---過擬合,overfit
可以用學習曲線(learning curve)來診斷偏差--方差 問題。學習曲線的 x 軸是訓練集大小(training set size),y 軸則是交叉驗證誤差和訓練誤差。
訓練誤差的定義如下:
注意:訓練誤差Jtrain(θ)是沒有正則化項的,因此在調用linearRegCostFunction時,lambda==0。Octave實現如下(learningCurve.m)
function [error_train, error_val] = ... learningCurve(X, y, Xval, yval, lambda) %LEARNINGCURVE Generates the train and cross validation set errors needed %to plot a learning curve % [error_train, error_val] = ... % LEARNINGCURVE(X, y, Xval, yval, lambda) returns the train and % cross validation set errors for a learning curve. In particular, % it returns two vectors of the same length - error_train and % error_val. Then, error_train(i) contains the training error for % i examples (and similarly for error_val(i)). % % In this function, you will compute the train and test errors for % dataset sizes from 1 up to m. In practice, when working with larger % datasets, you might want to do this in larger intervals. % % Number of training examples m = size(X, 1); % You need to return these values correctly error_train = zeros(m, 1); error_val = zeros(m, 1); % ====================== YOUR CODE HERE ====================== % Instructions: Fill in this function to return training errors in % error_train and the cross validation errors in error_val. % i.e., error_train(i) and % error_val(i) should give you the errors % obtained after training on i examples. % % Note: You should evaluate the training error on the first i training % examples (i.e., X(1:i, :) and y(1:i)). % % For the cross-validation error, you should instead evaluate on % the _entire_ cross validation set (Xval and yval). % % Note: If you are using your cost function (linearRegCostFunction) % to compute the training and cross validation error, you should % call the function with the lambda argument set to 0. % Do note that you will still need to use lambda when running % the training to obtain the theta parameters. % % Hint: You can loop over the examples with the following: % % for i = 1:m % % Compute train/cross validation errors using training examples % % X(1:i, :) and y(1:i), storing the result in % % error_train(i) and error_val(i) % .... % % end % % ---------------------- Sample Solution ---------------------- for i = 1:m theta = trainLinearReg(X(1:i, :), y(1:i), lambda); error_train(i) = linearRegCostFunction(X(1:i, :), y(1:i), theta, 0); error_val(i) = linearRegCostFunction(Xval, yval, theta, 0); % ------------------------------------------------------------- % ========================================================================= end
學習曲線的圖形如下:可以看出欠擬合時,在 training examples 數目很少時,訓練出來的模型還能擬合"一點點數據",故訓練誤差相對較小;但對於交叉驗證誤差而言,它是使用未知的數據得算出來到的,而現在模型欠擬合,故幾乎不能 擬合未知的數據,因此交叉驗證誤差非常大。
隨着 training examples 數目的增多,由於欠擬合,訓練出來的模型越來越來能擬合一些數據了,故訓練誤差增大了。而對於交叉驗證誤差而言,最終慢慢地與訓練誤差一致並變得越來越平坦,此時,再增加訓練樣本(training examples)已經對模型的訓練效果沒有太大影響了---在欠擬合情況下,再增加訓練集的個數也不能再降低訓練誤差了。
⑦多項式回歸
從上面的學習曲線圖形可以看出:出現了underfit problem,通過添加更多的特征(features),使用更高冪次的多項式來作為假設函數擬合數據,以解決欠擬合問題。
多項式回歸模型的假設函數如下:
通過對特征“擴充”,以添加更多的features,代碼實現如下:polyFeatures.m
for i = 1:p X_poly(:,i) = X.^i; end
“擴充”了特征之后,就變成了多項式回歸了,但由於多項式回歸的特征取值范圍差距太大(比如有些特征的取值很小,而有些特征的取值非常大),故需要用到Normalization(歸一化),歸一化的代碼如下:
function [X_norm, mu, sigma] = featureNormalize(X) %FEATURENORMALIZE Normalizes the features in X % FEATURENORMALIZE(X) returns a normalized version of X where % the mean value of each feature is 0 and the standard deviation % is 1. This is often a good preprocessing step to do when % working with learning algorithms. mu = mean(X); X_norm = bsxfun(@minus, X, mu); sigma = std(X_norm); X_norm = bsxfun(@rdivide, X_norm, sigma); % ============================================================ end
繼續再用原來的linearRegCostFunction.m計算多項式回歸的代價函數和梯度,得到的多項式回歸模型的假設函數的圖形如下:(注意:lambda==0,沒有使用正則化):
從多項式回歸模型的 圖形看出:它幾乎很好地擬合了所有的訓練樣本數據。因此,可認為出現了:過擬合問題(overfit problem)---高方差
多項式回歸模型的學習曲線 圖形如下:
從多項式回歸的學習曲線圖形看出:訓練誤差幾乎為0(非常貼近 x 軸了),這正是因為過擬合---模型幾乎完美地穿過了訓練數據集中的每個數據點,從而訓練誤差非常小。
交叉驗證誤差先是很大(訓練樣本數目為2時),然后隨着訓練樣本數目的增多,cross validation error 變得越來越小了(訓練樣本數目2 增加到 5 過程中);然后,當訓練樣本數目再增多時(11個以上的訓練樣本時...),交叉驗證誤差又變得大了(過擬合導致泛化能力下降)。
⑧使用正則化來解決多項化回歸模型的過擬合問題
設置正則化項 lambda == 1(λ==1)時,得到的模型假設函數圖形如下:
可以看出:這里的擬合曲線不再是 lambda == 0 時 那樣彎彎曲曲的了,也不是非常精准地穿過每一個點,而是變得相對比較平滑。這正是 正則化 的效果。
lambda==1 (λ==1) 時的學習曲線如下:
lambda==1時的學習曲線表明:該模型有較好的泛化能力,能夠對未知的數據進行較好的預測。因為,它的交叉驗證誤差和訓練誤差非常接近,且非常小。(訓練誤差小,表明模型能很好地擬合數據,但有可能出現過擬合的問題,過擬合時,是不能很好地對未知數據進行預測的;而此處交叉驗證誤差也小,表明模型也能夠很好地對未知數據進行預測)
最后來看下,多項式回歸模型的正則化參數 lambda == 100(λ==100)時的情況:(出現了underfit problem--欠擬合--高偏差)
模型“假設函數”曲線如下:
學習曲線圖形如下:
⑨如何自動選擇合適的 正則化參數 lambda(λ) ?
從第⑧點中看出:正則化參數 lambda(λ) 等於0時,出現了過擬合, lambda(λ) 等於100時,又出現了欠擬合, lambda(λ) 等於1時,模型剛剛好。
那在訓練過程中如何自動選擇合適的lambda參數呢?
可以使用交叉驗證集(根據交叉驗證誤差來選擇合適的 lambda 參數)
Concretely, you will use a cross validation set to evaluate how good each lambda value is.
After selecting the best lambda value using the cross validation set,
we can then evaluate the model on the test set to estimate how well the model will perform on actual unseen data.
具體的選擇方法如下:
首先有一系列的待選擇的 lambda(λ) 值,在本λ作業中用一個lambda_vec向量保存這些 lambda 值(一共有10個):
lambda_vec = [0 0.001 0.003 0.01 0.03 0.1 0.3 1 3 10]'
然后,使用訓練數據集 針對這10個 lambda 分別訓練 10個正則化的模型。然后對每個訓練出來的模型,計算它的交叉驗證誤差,選擇交叉驗證誤差最小的那個模型所對應的lambda(λ)值,作為最適合的 λ 。(注意:在計算訓練誤差和交叉驗證誤差時,是沒有正則化項的,相當於 lambda==0)
for i = 1:length(lambda_vec) theta = trainLinearReg(X,y,lambda_vec(i));%對於每個lambda,訓練出模型參數theta %compute jcv and jval without regularization,causse last arguments(lambda) is zero error_train(i) = linearRegCostFunction(X, y, theta, 0);%計算訓練誤差 error_val(i) = linearRegCostFunction(Xval, yval, theta, 0);%計算交叉驗證誤差 end
對於這10個不同的 lambda,計算出來的訓練誤差和交叉驗證誤差如下:
lambda Train Error Validation Error 0.000000 0.173616 22.066602 0.001000 0.156653 18.597638 0.003000 0.190298 19.981503 0.010000 0.221975 16.969087 0.030000 0.281852 12.829003 0.100000 0.459318 7.587013 0.300000 0.921760 4.636833 1.000000 2.076188 4.260625 3.000000 4.901351 3.822907 10.000000 16.092213 9.945508
訓練誤差、交叉驗證誤差以及 lambda 之間的關系 圖形表示如下:
當 lambda >= 3 的時候,交叉驗證誤差開始上升,如果再增大 lambda 就可能出現欠擬合了...
從上面看出:lambda == 3 時,交叉驗證誤差最小。lambda==3時的擬合曲線如下:(可與 lambda==1時的擬合曲線及學習曲線對比一下,看有啥不同)
學習曲線如下: