機器學習基礎知識:
包括線性迴歸,邏輯迴歸,交叉熵,softmax,KNN,神經網絡中梯度的傳遞思想。關於線性迴歸和邏輯迴歸部分的知識,可以參考這個博客的內容,就不再累述:http://blog.csdn.net/viewcode/article/details/8794401。
關於softmax的理解:
softmax是另一種誤差函數的表現形式,可以叫做softmax-loss function.
loss的計算公式:
softmax梯度的求導(使用鏈式求導法,在two-layer-network中會使用到):
神經網絡中的梯度的傳遞思想與上面softmax的鏈式求導法類似,逐級計算梯度然後一級一級傳導。可以大大降低求梯度的難度。
part 2
cs231n/assignment1:
KNN:
原理:使用 k_nearest_neighbor分類器,實現對小型圖像的識別,流程是:
1,載入數據:從cifar10數據庫中隨機抽取5000個樣本作爲訓練集,500個樣本作爲測試集。
2,數據前處理:每個樣本是一個32*32的彩色圖片,一個像素由3個顏色組成,所以一張圖片包含32×32×3=3072個數據,使用reshape函數,把每個樣本的數據變成一個行向量(3072維),然後訓練集就變成一個5000*3072的矩陣,測試集變成一個500*3072的矩陣。
3,計算距離矩陣:分別用三種方法(兩層嵌套循環,一層循環,不使用循環)計算測試集中的樣本與訓練集中的樣本在像素上的L2距離,存儲在距離矩陣中(500*5000)。
兩層嵌套循環:
vector1=np.mat(X[i])
vector2=np.mat(self.X_train[j])
dists[i,j]=math.sqrt((vector1-vector2)*((vector1-vector2).T))
每次計算兩個行向量的L2距離,存放在dists[i,j]中。
一層循環:
p=np.mat(X[i])
cT=self.X_train.T
dists[i]=np.sqrt(np.square(p)*np.ones(cT.shape)+np.mat(np.ones(p.shape))*np.square(cT)-2*p*cT)
每次計算測試集一個樣本(行向量)與訓練集所有樣本(矩陣)的L2距離,存放在dists[i]的行中。
不使用循環:
a=np.mat(X)
aT=np.mat(self.X_train.T)
dists=np.sqrt(np.square(a)*np.ones(aT.shape)+np.ones(a.shape)*np.square(aT)-2*a*aT)
直接對測試集和訓練集兩個矩陣進行運算,不使用循環,dists[i,j]中存放的是第i個測試樣本與第j個訓練樣本的L2距離。
4,類別預測:在這一步中,針對每個測試集中的樣本,對其所對應的dists距離矩陣中的對應行向量中的距離排序(從小到大),然後選取前K(K是一個超參數)個最小的距離,然後返回對應的標籤存放在closest_y中,然後對closest_y中元素進行統計分析,從中挑選出出現次數最多的標籤,使用“多數贊成投票”法決定測試樣本的標籤的預測,最後返回到數組中:y_pred,其中存放所有測試樣本的預測標籤。
代碼段1:
order=np.argsort(dists[i]) #order is an array contains the index of array distance rank from mintomax
for j in range(1,k+1):
min=order[0,j-1] #order_k is the index of K-th value label
closest_y.append(self.y_train[min]) #min is the min index of distance
實現功能:把dists[i]按從小到大排序,然後取前k個對應的標籤存放到closest_y中。
代碼段2:
from collections import Counter
c=Counter(closest_y).most_common(1)
d=list(c[0])
y_pred[i]=d[0]
實現功能:統計closest_y中出現最多次數的標籤給到y_pred[i]。
5,測試了K=1和等於K=5下識別的準確度:分別是
k=1:Got 137 / 500 correct => accuracy: 0.274000
k=5:Got 142 / 500 correct => accuracy: 0.284000
可看出k=5的情況下準確度稍微高一點。
6,測試了計算dists矩陣的三種不同方式下耗費的計算時間:
Two loop version took 57.856100 seconds
One loop version took 25.614912 seconds
No loop version took 0.358330 seconds
可明顯看出,向量和矩陣運算的使用明顯加快了計算速度,特別是無循環下,直接用矩陣進行運算的速度超乎想象,可見矩陣的並行計算有很大的優勢,的確是趨勢。
7,交叉驗證,最後一步,knn算法使用了交叉驗證的方法來實現對超參數K的調諧,分別針對k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]這幾個
超參數選項,分別使用交叉驗證的方法反覆計算多次,驗證其所得到的預測準則度,然後找出效果最好的那個超參數k.
代碼段1:
X_train_folds=np.array_split(X_train,num_folds)
y_train_folds=np.array_split(y_train,num_folds)
實現功能:把訓練集均分爲num_folds份。
代碼段2:
for k in k_choices:
for i in range(num_folds):
X_train_cross = np.array(X_train_folds[:i] + X_train_folds[i + 1:])
y_train_cross = np.array(y_train_folds[:i] + y_train_folds[i + 1:])
X_train_cross = X_train_cross.reshape(-1, X_train_cross.shape[2])
y_train_cross = y_train_cross.reshape(-1)
X_test_cross = np.array(X_train_folds[i])
y_test_cross = np.array(y_train_folds[i])
classifier = KNearestNeighbor()
classifier.train(X_train_cross, y_train_cross)
dists= classifier.compute_distances_no_loops(X_test_cross)
y_test_pred = classifier.predict_labels(dists,k)
num_correct = np.sum(y_test_pred == y_test_cross)
accuracy = float(num_correct) / y_test_cross.shape[0]
if (k in k_to_accuracies.keys()):
k_to_accuracies[k].append(accuracy)
else:
k_to_accuracies[k] = []
k_to_accuracies[k].append(accuracy)
實現功能:循環數次,每次使用不同的K值,然後每個k值驗證num_folds次,每次驗證時,訓練集的第i部分作爲測試集,其餘部分作爲訓練集,最後把結果存起來
然後對結果(準確度)進行統計分析,可以繪製出一下的曲線:
SVM:
這個算法的難點,主要是loss函數的計算和偏導數的計算,首先公式爲:
L= (1/N)∑iLi + λR(W)
Li= ∑j≠yi max(0, (xiW)j−(xyiW)j+Δ)
其中:
λR(W):正則化懲罰,爲什麼要正則化,因爲w不唯一,如果w正好能使得loss=0(最優權重),那麼kw也能做到,爲了得到唯一的W進行分類工作,我們可以添加一個正則化懲罰項。其最主要作用是防止過擬合,提高模型的泛化能力,因爲如果產生了大數值的權重容易導致產生過大的loss,進而過擬合,所以正則化懲罰能有效地抑制大數組權重的產生。
(xiW)j:錯誤分類的得分,(xyiW)j:正確分類的得分,意味着對於每一張圖像樣本,正確分類的得分應該比錯誤分類的得分至少高Δ(Δ的取值在實際中一般爲1)。
梯度的公式:
∇WyiLi = - xiT(∑j≠yi1(xiWj- xiWyi +1>0)) + 2λWyi
∇WjLi = xiT 1(xiWj- xiWyi +1>0) + 2λWj , (j≠yi)
其中1()爲邏輯函數,表達式爲真爲1,假爲0.
代碼段1:
for i in xrange(num_train):
scores = X[i].dot(W)
correct_class_score = scores[y[i]]
for j in xrange(num_classes):
if j == y[i]:
continue
margin = scores[j] - correct_class_score + 1 # note delta = 1
if margin > 0:
loss += margin
dW[:, y[i]] += -X[i, :]
dW[:, j] += X[i, :]
loss /= num_train
dW /= num_train
loss += 0.5 * reg * np.sum(W * W)
dW += reg * W
實現功能:用循環的方式,求出loss和dW
代碼段2:
scores = X.dot(W)
num_train = X.shape[0]
num_classes = W.shape[1]
scores_correct = scores[np.arange(num_train), y] # 1 by N
scores_correct = np.reshape(scores_correct, (num_train, 1)) # N by 1
margins = scores - scores_correct + 1.0 # N by C
margins[np.arange(num_train), y] = 0.0
margins[margins <= 0] = 0.0
loss += np.sum(margins) / num_train
loss += 0.5 * reg * np.sum(W * W)
實現功能:用對向量的操作,不適用循環語句,直接求出loss
代碼段3:
margins[margins > 0] = 1.0
row_sum = np.sum(margins, axis=1)
margins[np.arange(num_train), y] = -row_sum
dW += np.dot(X.T, margins)/num_train + reg * W
實現功能:用對向量的操作,不適用循環語句,直接求出dW
代碼段4:
params = [(x,y) for x in learning_rates for y in regularization_strengths]
for lrate, regular in params:
svm = LinearSVM()
loss_hist = svm.train(X_train, y_train, learning_rate=lrate, reg=regular,num_iters=700, verbose=False)
y_train_pred = svm.predict(X_train)
accuracy_train = np.mean(y_train == y_train_pred)
y_val_pred = svm.predict(X_val)
accuracy_val = np.mean(y_val == y_val_pred)
results[(lrate, regular)]=(accuracy_train, accuracy_val)
if (best_val < accuracy_val):
best_val = accuracy_val
best_svm = svm
實現功能:svm算法中超參數的調諧,兩個超參數:學習率和正則化懲罰係數:
learning_rates= [1.4e-7, 1.45e-7, 1.5e-7, 1.55e-7, 1.6e-7, 1.65e-7, 1.7e-7]
regularization_strengths= [3e4, 3.1e4, 3.2e4, 3.3e4, 3.4e4]
經過雙重循環嘗試遍所有可能的超參數組合,求出其對應的準確率,進行比較,可以找出準確率最高的一組超參數組合:
lr 1.400000e-07 reg 3.100000e+04 train accuracy: 0.375755 val accuracy: 0.401000
可見最好的超參數是學習率爲 1.400000e-07,正則化懲罰係數爲3.100000e+04,對應的準確率爲40.1%.
Softmax:
softmax和svm方法極其類似,唯一區別就是loss函數和梯度的計算方法不一樣,svm中是Hingeloss,在softmax中替換成了交叉熵cross-entropyloss:
Loss:
L= -(1/N)∑i∑j1(k=yi)log(exp(fk-fmax)/∑jexp(fj-fmax))+ λR(W)
其中:-fmax是爲了保證數值穩定性的問題,因爲在計算過程中,exp(fyi)和 ∑jexp(fj)的值可能會變得非常大,大值數相除容易導致數值不穩定,所以要把這個大數值給剔除掉。λR(W)則是正則化懲罰,保證w的唯一性,抑制產生大數值的權重導致過擬合。
偏導:
∇WkL = -(1/N)∑i xiT(pi,m-Pm)+ 2λWk
其中:Pk= exp(fk-fmax)/∑jexp(fj-fmax)
因爲和svm類似,所以softmax和svm的代碼段也很類似:
代碼段1:
dW_each = np.zeros_like(W)
num_train, dim = X.shape
num_class = W.shape[1]
f = X.dot(W)
f_max = np.reshape(np.max(f, axis=1), (num_train, 1)) # N by 1
prob = np.exp(f - f_max) / np.sum(np.exp(f - f_max), axis=1, keepdims=True) # N by C
y_trueClass = np.zeros_like(prob)
y_trueClass[np.arange(num_train), y] = 1.0
for i in xrange(num_train):
for j in xrange(num_class):
loss += -(y_trueClass[i, j] * np.log(prob[i, j]))
dW_each[:, j] = -(y_trueClass[i, j] - prob[i, j]) * X[i, :]
dW += dW_each
loss /= num_train
loss += 0.5 * reg * np.sum(W * W)
dW /= num_train
dW += reg * W
實現功能:使用兩層顯示循環,計算loss和dW。
代碼段2:
num_train, dim = X.shape
f = X.dot(W)
f_max = np.reshape(np.max(f, axis=1), (num_train, 1))
prob = np.exp(f - f_max) / np.sum(np.exp(f - f_max), axis=1, keepdims=True)
y_trueClass = np.zeros_like(prob)
y_trueClass[range(num_train), y] = 1.0
loss += -np.sum(y_trueClass * np.log(prob)) / num_train + 0.5 * reg * np.sum(W * W)
dW += -np.dot(X.T, y_trueClass - prob) / num_train + reg * W
實現功能:直接對向量進行計算,直接算出loss和dW。
代碼段3:
params = [(x,y) for x in learning_rates for y in regularization_strengths ]
for lrate, regular in params:
softmax = Softmax()
loss_hist = softmax.train(X_train, y_train, learning_rate=lrate, reg=regular,num_iters=700, verbose=True)
y_train_pred = softmax.predict(X_train)
accuracy_train = np.mean( y_train == y_train_pred)
y_val_pred = softmax.predict(X_val)
accuracy_val = np.mean(y_val == y_val_pred)
results[(lrate, regular)] = (accuracy_train, accuracy_val)
if(best_val < accuracy_val):
best_val = accuracy_val
best_softmax = softmax
實現功能:softmax算法中超參數的調諧,兩個超參數:學習率和正則化懲罰係數:
learning_rates= [1.4e-7, 1.45e-7, 1.5e-7, 1.55e-7, 1.6e-7, 1.65e-7, 1.7e-7]
regularization_strengths= [3e4, 3.1e4, 3.2e4, 3.3e4, 3.4e4]
經過雙重循環嘗試遍所有可能的超參數組合,求出其對應的準確率,進行比較,可以找出準確率最高的一組超參數組合:
lr 1.400000e-07 reg 3.400000e+04 train accuracy: 0.340592 val accuracy: 0.367000
可見最好的超參數是學習率爲 1.400000e-07,正則化懲罰係數爲3.400000e+04,對應的準確率爲36.7%.
二層神經網絡:
神經網絡基本結構示意:
這個應用旨在學會搭建一個最小系統的神經網絡:只包含一個輸入層通過一個隱含層(一層神經元細胞)的神經網絡,然後是輸出層。
神經網絡的具體訓練過程如下:
1,參數設置:迭代次數N-iteration,Cifar-10中取出的樣本庫50000個,每次迭代抽樣容量:batch-size。
2,樣本庫預處理:把樣本圖片(32*32*3
)正則化,即所有圖片減去平均圖像,可以控制圖片矩陣的大小在一個範圍內,矩陣reshape爲行向量3072維。
3,初始化訓練參數設置。
4,開始迭代過程:從樣本中隨機抽取batch-size個圖片,輸入神經網絡,前向傳導(hiddenlayer中神經元使用Relu作爲激活函數),得到loss,然後反向傳導,
反向逐級計算梯度,然後得到loss(softmaxloss)對W1和W2的偏導數,並用其更新W1和W2(隨機梯度下降法)。
5,進行下一次迭代:從樣本中隨機抽取另外batch-size個圖片,重複上面步驟,更新W1和W2以使得loss趨於極小值點。
6,在迭代過程中,每間隔一個紀元epoch(epoch=50000/batch-size)次迭代,會進行一次訓練準確度的檢查,會計算並記錄此時神經網絡訓練出的訓練誤差和驗證誤差,並且爲了防止迭代到後期,學習率過大的問題,還會對學習率進行衰減。
對於迭代過程中的前向傳導和反向傳導:
上圖中給出了迭代過程中數據在神經網絡中前向傳導和反向傳導的公式。
neural-net.py中代碼實現:
代碼段1:
z1=X.dot(W1)+b1#(H)
a1=np.zeros_like(z1)
a1=np.maximum(z1,0)
scores=a1.dot(W2)+b2
實現功能:計算出前向傳導過程的中間值和最終輸出。
代碼段2:
scores = scores - np.reshape(np.max(scores,axis=1),(N,-1))
p = np.exp(scores)/np.reshape(np.sum(np.exp(scores),axis=1),(N,-1))
loss = -sum(np.log(p[np.arange(N),y]))/N
loss += 0.5*reg*np.sum(W1*W1)+0.5*reg*np.sum(W2*W2)
實現功能:前向傳導過程中的softmax-loss計算,並且對loss進行w1和w2正則化。代碼段3:
dldf=p
dldf[range(N),y]-=1.0
dldf/=N
dfdw2=a1
dW2=np.dot(dfdw2.T,dldf)
dh2 = np.sum(dldf,axis=0,keepdims=False)
dfda1=W2
dlda1=np.dot(dldf,dfda1.T)
dldz1=dlda1
dldz1[a1<=0]=0
dh1 = np.sum(dldz1,axis=0,keepdims=False)
dz1dw1=X
dW1=np.dot(dz1dw1.T,dldz1)
dW2 += reg*W2
dW1 += reg*W1
grads['W1']=dW1
grads['b1']=dh1
grads['W2']=dW2
grads['b2']=dh2
實現功能:反向傳導,逐級計算梯度,計算出loss對w1,w2梯度(正則化)。
代碼段4;
sample_index = np.random.choice(num_train, batch_size)
X_batch = X[sample_index, :] # select the batch sample
y_batch = y[sample_index] # select the batch label
實現功能:從50000個樣本庫中隨機抽取batch-size個樣本,作爲訓練集。
代碼段5:
W1 = grads['W1']
b1 = grads['b1']
W2 = grads['W2']
b2 = grads['b2']
self.params['W1'] -= learning_rate*W1
self.params['b1'] -= learning_rate*b1
self.params['W2'] -= learning_rate*W2
self.params['b2'] -= learning_rate*b2
實現功能:用梯度更新W1和W2,隨機梯度下降法.
代碼段6:
z1=X.dot(self.params['W1'])+self.params['b1']#(H)
a1=np.zeros_like(z1)
a1=np.maximum(z1,0)
scores=a1.dot(self.params['W2'])+self.params['b2']
y_pred = np.argmax(scores, axis=1)
實現功能:預測樣本的類型。two-layer-net.ipyn文件:
代碼段1:
best_valacc=-1.0
input_size = 32 * 32 * 3
num_classes = 10
#hidden_size = 50
hidden_size = 32 * 32 * 3
learn_rate =[7.2e-4]
#learning_rate_decay=[0.94,0.95,0.93]
reg=[1e-3]
results = {}
params = [x1 for x1 in learn_rate ]
# for x3 in learning_rate_decay for x4 in reg]
for learn_rate in params:
net = TwoLayerNet(input_size, hidden_size, num_classes)
# Train the network
stats = net.train(X_train, y_train, X_val, y_val,
num_iters=6400, batch_size=128,
learning_rate =7.2e-4, learning_rate_decay=0.95,
reg=1e-3, verbose=True)
# Predict on the validation set
val_acc = np.mean(net.predict(X_val) == y_val)
results[learn_rate] =val_acc
if val_acc>best_valacc:
best_valacc = val_acc
best_net = net
for learn_rate in sorted(results):
val_accuracy = results[(learn_rate)]
print 'learn_rate %e val accuracy: %f' % (
learn_rate, val_accuracy)
print 'best validation accuracy achieved during cross-validation: %f' % best_valacc
實現功能:反覆修改神經網絡的初始化參數和超參數,調試出具有最高分類精度的超參數。結果:
按照上面代碼中的參數設置最終實現的精度爲54.7%.