自寫邏輯回歸(利用隨機梯度下降法)

2021-09-29 08:33:32 字數 3640 閱讀 5941

'''

梯度下降法需要對每個楊訥都需要遍歷。時間複雜度太大

為了解決這個時間複雜度問題,我們最常用的演算法其實是隨機梯度下降法,可以理解成是梯度下降法的乙個變種。

''''''

隨機梯度下降法的核心思想是:每一次的迭代更新不再依賴於所有樣本的梯度之和,

而是僅僅依賴於其中乙個樣本的梯度。所以這種方法的優勢很明顯,

通過很「便宜」的方式獲得梯度,並頻繁地對引數迭代更新。

這裡最大的問題是梯度的雜訊。當我們使用梯度下降法時,梯度的計算是依賴於所有樣本的,

但隨機梯度下降法的梯度計算僅僅依賴於其中的乙個樣本。

這必然會導致計算出來的結果包含大量的雜訊,

因為我們試圖使用乙個樣本的梯度來替換所有樣本的梯度之和。

所以呢,在隨機梯度下降法的模式下,我們通常會把學習率設定為比較小的值,

這樣可以有效削弱梯度計算中帶來的不穩定性。

相比梯度下降法,當我們使用隨機梯度下降法的時候可以看到每一次迭代之後的目標函式或者損失函式會有一些波動性。

有一些更新會帶來目標值的提公升,

但有些更新反而讓目標值變得更差。但只要實現細節合理,大的趨勢是沿著好的方向而發展的。

目前來看,梯度下降法和隨機梯度下降法分別可以看作是兩個極端。前者考慮所有的樣本,後者僅僅考慮其中的乙個樣本。

有些犀利的朋友可能自然會問到:既然這兩個極端各有優缺點,那是否可以使用乙個折中的方案呢?

恭喜你,確實有乙個折中的方案,叫做mini-batch gradient descent。

它不依賴於所有的樣本,但也不依賴於僅僅乙個樣本,

而是它從所有樣本中隨機挑選一部分樣本來計算梯度並更新引數。

'''# 匯入相應的庫

import numpy as np

import matplotlib.pyplot as plt

import random

# 隨機生成樣本資料。 二分類問題,每乙個類別生成5000個樣本資料

np.random.seed(12)

num_observations = 5000

x1 = np.random.multivariate_normal([0, 0], [[1, .75], [.75, 1]], num_observations)

x2 = np.random.multivariate_normal([1, 4], [[1, .75], [.75, 1]], num_observations)

x = np.vstack((x1, x2)).astype(np.float32)

y = np.hstack((np.zeros(num_observations),

np.ones(num_observations)))

print(x.shape, y.shape)

# 資料的視覺化

plt.figure(figsize=(12, 8))

plt.scatter(x[:, 0], x[:, 1],

c=y, alpha=.4)

# 實現sigmoid函式

def sigmoid(x):

return 1 / (1 + np.exp(-x))

# 計算log likelihood

def log_likelihood(x, y, w, b):

"""針對於所有的樣本資料,計算(負的)log likelihood,也叫做cross-entropy loss

這個值越小越好

x: 訓練資料(特徵向量), 大小為n * d

y: 訓練資料(標籤),一維的向量,長度為d

w: 模型的引數, 一維的向量,長度為d

b: 模型的偏移量,標量

"""# 首先按照標籤來提取正樣本和負樣本的下標

pos, neg = np.where(y == 1), np.where(y == 0)

# 對於正樣本計算 loss, 這裡我們使用了matrix operation。 如果把每乙個樣本都迴圈一遍效率會很低。

pos_sum = np.sum(np.log(sigmoid(np.dot(x[pos], w) + b)))

# 對於負樣本計算 loss

neg_sum = np.sum(np.log(1 - sigmoid(np.dot(x[neg], w) + b)))

# 返回cross entropy loss

return -(pos_sum + neg_sum)

# 實現邏輯回歸模型

def logistic_regression_minibatch(x, y, num_steps, learning_rate):

"""基於梯度下降法實現邏輯回歸模型

x: 訓練資料(特徵向量), 大小為n * d

y: 訓練資料(標籤),一維的向量,長度為d

num_steps: 梯度下降法的迭代次數

learning_rate: 步長

"""w, b = np.zeros(x.shape[1]), 0

for step in range(num_steps):

# todo 隨機取樣乙個batch, batch大小為100

size=x.shape[0]

idx=np.random.choice(x.shape[0],100)

batch_x=x[idx]

batch_y=y[idx]

#print(batch.shape)

# print(batch.shape) #(100, 2)

# todo 計算**值與實際值之間的誤差

error=sigmoid(np.dot(batch_x,w)+b)-batch_y

# todo 對於w, b的梯度計算

grad_w =np.matmul(batch_x.t,error)

grad_b =np.sum(error)

# 對於w, b的梯度更新

w = w - learning_rate * grad_w

b = b - learning_rate * grad_b

# 每隔一段時間,計算一下log likelihood,看看有沒有變化

# 正常情況下, 它會慢慢變小,最後收斂

if step % 10000 == 0:

print(step,log_likelihood(x, y, w, b))

return w, b

w, b = logistic_regression_minibatch(x, y, num_steps=1000000, learning_rate=5e-4)

print("(自己寫的)邏輯回歸的引數w, b分別為: ", w, b)

# 這裡我們直接呼叫sklearn的模組來訓練,看看跟自己手寫的有沒有區別。如果結果一樣就說明是正確的!

from sklearn.linear_model import logisticregression

# c設定乙個很大的值,意味著不想加入正則項 (在第七章會看到正則作用,這裡就理解成為了公平的比較)

clf = logisticregression(fit_intercept=true, c=1e15)

clf.fit(x, y)

print("(sklearn)邏輯回歸的引數w, b分別為: ", clf.coef_, clf.intercept_, )

梯度下降法和隨機梯度下降法

批量梯度下降法 batch gradient descent 在更新引數時使用所有的樣本來進行更新 隨機梯度下降法 stochastic gradient descent 求梯度時沒有用所有的m個樣本的資料,而是僅僅選取乙個樣本j來求梯度。小批量梯度下降法 mini batch gradient d...

回歸 梯度下降法

給定 m條訓練資料,假定方法 先說明向量問題,乙個向量就代表一條特徵值 梯度下降公式 重複公式直到 收斂。公式中意思是 1 第i個 2 重複計算1。直到 repeat util convergence python def gradient x,y,bu,number m,n x.shape wei...

隨機梯度下降法

剛剛看完史丹福大學機器學習第四講 牛頓法 也對學習過程做一次總結吧。一 誤差準則函式與隨機梯度下降 數學一點將就是,對於給定的乙個點集 x,y 找到一條曲線或者曲面,對其進行擬合之。同時稱x中的變數為特徵 feature y值為 值。如圖 乙個典型的機器學習的過程,首先給出一組輸入資料x,我們的演算...