5.5 瀑布下降法
我們在沒有講述瀑布下降法(即完全梯度下降法)之前就比較了這個方法和隨機梯度下降法的優(yōu)劣涡贱。很多人會覺得丈二金剛摸不著頭腦攀隔。但是這其實是很必要的氧急。因為其實本質上算法是很嚴謹細致的東西,其中精妙之處往往隱藏很深巩螃,所以就需要細細體會才能理解其中的思想次企。我們先講其優(yōu)劣和應用,再來看算法本身,就會站在上帝視角來看待算法的全貌婚肆。否則一旦落入算法代碼的汪洋大海,就變成盲人摸象坐慰,只能看到算法的某一個角较性。弱水三千,只取一瓢结胀。至少你要知道三千弱水的不同赞咙,然后才能選最喜歡的那一瓢。
下面我們進入瀑布下降法的代碼環(huán)節(jié)把跨。
數據處理部分就不再詳述了人弓,這一步和之前的隨機梯度下降法是一樣的。我們需要用到矩陣按列求平均值的函數着逐,下面就是這個函數的代碼:
def matrix_column_avg(mat):
row,column = mat.shape
result = np.zeros(column)
for col in range(column):
for item in range(row):
result[col] += mat[item,col]
result /= row
return result
它輸入一個矩陣崔赌,輸出一行的向量意蛀,向量中的每一個元素都是輸入矩陣的列平均值。另外健芭,我們將每一次的全部數據的梯度下降都打包成一個函數县钥,讓它對所有的數據點做一次梯度下降。輸出是梯度下降的引擎慈迈,梯度下降乘子(它是一個對角矩陣)以及對應于每條數據的誤差列表若贮。代碼如下:
def excute_grad_desc(data,real_value,weights):
weight_matrix = np.empty((len(raw_data),len(weights)))
error_list = []
for item_index in range(len(data)):
# 每個數據條都做一次梯度下降
# 從第一條數據條開始循環(huán)
inputs = data[item_index]
outputs = real_value[item_index]
engine = rand_grad(inputs,outputs,weights)
gdm = list(engine.grad_descent_multiplier())
if min(np.abs(gdm)) > max(np.abs(weights)):
gdm /= 10*min(np.abs(gdm))/max(np.abs(weights))
# 下降因子相對于權重過大,此時應將它縮小痒留,否則極易引起誤差發(fā)散谴麦。
factor = np.diag(gdm)
error_list.append(engine.error_function())
return engine, factor, error_list
最后是執(zhí)行整體梯度下降,用單步梯度下降操作之后得到的值計算出平均權重伸头,然后用平均權重當作新的起點進行下一步的梯度下降匾效。這樣就可以用一個循環(huán)來執(zhí)行,即:
for t in range(100): # 梯度下降的下降次數
engine, factor, error_list = excute_grad_desc(raw_data,sell_price,weights)
weights -= np.matmul(learning_rate,factor)
weight_matrix[item_index] = weights
# 求平均值恤磷,并把它看作是新的權重
weights = matrix_column_avg(weight_matrix)
print("最終的權重:", weights)
# 驗證權重的有效性, 再執(zhí)行一次
engine, factor, error_list = excute_grad_desc(raw_data,sell_price,weights)
print("誤差列表:", error_list)
最終我們會看到如下的結果:
最終的權重: [1.46239029 0.51211936 1.39663107 1.10692271]
誤差列表: [8.17836538021409e-05, 0.0044868083148646085, 0.0037373692234452895, 0.007409998180022533, 0.0014975302720826947, 0.0076731972041592005]