來自:腩啵兔子 - 博客園
作者:腩啵兔子
鏈接:http://www.cnblogs.com/lrysjtu/p/5399704.html
已獲轉(zhuǎn)載授權(quán)
最近在github上看到一個很有趣的項目仔粥,通過文本訓(xùn)練可以讓計算機(jī)寫出特定風(fēng)格的文章,有人就專門寫了一個小項目生成汪峰風(fēng)格的歌詞柑潦。看完后有一些自己的小想法峻凫,也想做一個玩兒一玩兒渗鬼。用到的原理是深度學(xué)習(xí)里的循環(huán)神經(jīng)網(wǎng)絡(luò),無奈理論太艱深荧琼,只能從頭開始開始慢慢看譬胎,因此產(chǎn)生寫一個項目的想法,把機(jī)器學(xué)習(xí)和深度學(xué)習(xí)里關(guān)于分類的算法整理一下命锄,按照原理寫一些demo堰乔,方便自己也方便其他人。項目地址:https://github.com/LiuRoy/classfication_demo脐恩,目前實現(xiàn)了邏輯回歸和神經(jīng)網(wǎng)絡(luò)兩種分類算法镐侯。
Logistic回歸
這是相對比較簡單的一種分類方法,準(zhǔn)確率較低驶冒,也只適用于線性可分?jǐn)?shù)據(jù)苟翻,網(wǎng)上有很多關(guān)于logistic回歸的博客和文章,講的也都非常通俗易懂骗污,就不贅述崇猫。此處采用隨機(jī)梯度下降的方式實現(xiàn),講解可以參考《機(jī)器學(xué)習(xí)實戰(zhàn)》第五章logistic回歸需忿。代碼如下:
def train(self, num_iteration=150):
? ? """隨機(jī)梯度上升算法
? ? Args:
? ? ? ? data (numpy.ndarray): 訓(xùn)練數(shù)據(jù)集
? ? ? ? labels (numpy.ndarray): 訓(xùn)練標(biāo)簽
? ? ? ? num_iteration (int): 迭代次數(shù)
? ? """
? ? for j in xrange(num_iteration):
? ? ? ? data_index = range(self.data_num)
? ? ? ? for i in xrange(self.data_num):
? ? ? ? ? ? # 學(xué)習(xí)速率
? ? ? ? ? ? alpha = 0.01
? ? ? ? ? ? rand_index = int(random.uniform(0, len(data_index)))
? ? ? ? ? ? error = self.label[rand_index] - sigmoid(sum(self.data[rand_index] * self.weights + self.b))
? ? ? ? ? ? self.weights += alpha * error * self.data[rand_index]
? ? ? ? ? ? self.b += alpha * error
? ? ? ? ? ? del(data_index[rand_index])
效果圖:
神經(jīng)網(wǎng)絡(luò)
參考的是這篇文章诅炉,如果自己英語比較好,還可以查看英文文章屋厘,里面有簡單的實現(xiàn)涕烧,唯一的缺點就是沒有把原理講明白。關(guān)于神經(jīng)網(wǎng)絡(luò)汗洒,個人認(rèn)為確實不是一兩句就能解釋清楚的议纯,尤其是網(wǎng)上的博客,要么只給公式仲翎,要么只給圖痹扇,看起來都非常的晦澀铛漓,建議大家看一下加州理工的一個公開課,有中文字幕鲫构,一個小時的課程絕對比自己花一天查文字資料理解的深刻浓恶,知道原理之后再來看前面的那篇博客就很輕松啦!
BGD實現(xiàn)
博客里面實現(xiàn)用的是批量梯度下降(batch gradient descent)结笨,代碼:
def batch_gradient_descent(self, num_passes=20000):
? ? """批量梯度下降訓(xùn)練模型"""
? ? for i in xrange(0, num_passes):
? ? ? ? # Forward propagation
? ? ? ? z1 = self.data.dot(self.W1) + self.b1
? ? ? ? a1 = np.tanh(z1)
? ? ? ? z2 = a1.dot(self.W2) + self.b2
? ? ? ? exp_scores = np.exp(z2)
? ? ? ? probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
? ? ? ? # Backpropagation
? ? ? ? delta3 = probs
? ? ? ? delta3[range(self.num_examples), self.label] -= 1
? ? ? ? dW2 = (a1.T).dot(delta3)
? ? ? ? db2 = np.sum(delta3, axis=0, keepdims=True)
? ? ? ? delta2 = delta3.dot(self.W2.T) * (1 - np.power(a1, 2))
? ? ? ? dW1 = np.dot(self.data.T, delta2)
? ? ? ? db1 = np.sum(delta2, axis=0)
? ? ? ? # Add regularization terms (b1 and b2 don't have regularization terms)
? ? ? ? dW2 += self.reg_lambda * self.W2
? ? ? ? dW1 += self.reg_lambda * self.W1
? ? ? ? # Gradient descent parameter update
? ? ? ? self.W1 += -self.epsilon * dW1
? ? ? ? self.b1 += -self.epsilon * db1
? ? ? ? self.W2 += -self.epsilon * dW2
? ? ? ? self.b2 += -self.epsilon * db2
效果圖:
注意:強(qiáng)烈懷疑文中的后向傳播公式給錯了包晰,因為和代碼里的delta2 = delta3.dot(self.W2.T) * (1 - np.power(a1, 2))對不上。
SGD實現(xiàn)
考慮到logistic回歸可以用隨機(jī)梯度下降炕吸,而且公開課里面也說隨機(jī)梯度下降效果更好一些伐憾,所以在上面的代碼上自己改動了一下,代碼:
def stochastic_gradient_descent(self, num_passes=200):
? ? """隨機(jī)梯度下降訓(xùn)練模型"""
? ? for i in xrange(0, num_passes):
? ? ? ? data_index = range(self.num_examples)
? ? ? ? for j in xrange(self.num_examples):
? ? ? ? ? ? rand_index = int(np.random.uniform(0, len(data_index)))
? ? ? ? ? ? x = np.mat(self.data[rand_index])
? ? ? ? ? ? y = self.label[rand_index]
? ? ? ? ? ? # Forward propagation
? ? ? ? ? ? z1 = x.dot(self.W1) + self.b1
? ? ? ? ? ? a1 = np.tanh(z1)
? ? ? ? ? ? z2 = a1.dot(self.W2) + self.b2
? ? ? ? ? ? exp_scores = np.exp(z2)
? ? ? ? ? ? probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
? ? ? ? ? ? # Backpropagation
? ? ? ? ? ? delta3 = probs
? ? ? ? ? ? if y:
? ? ? ? ? ? ? ? delta3[0, 0] -= 1
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? delta3[0, 1] -= 1
? ? ? ? ? ? dW2 = (a1.T).dot(delta3)
? ? ? ? ? ? db2 = np.sum(delta3, axis=0, keepdims=True)
? ? ? ? ? ? va = delta3.dot(self.W2.T)
? ? ? ? ? ? vb = 1 - np.power(a1, 2)
? ? ? ? ? ? delta2 = np.mat(np.array(va) * np.array(vb))
? ? ? ? ? ? dW1 = x.T.dot(delta2)
? ? ? ? ? ? db1 = np.sum(delta2, axis=0)
? ? ? ? ? ? # Add regularization terms (b1 and b2 don't have regularization terms)
? ? ? ? ? ? dW2 += self.reg_lambda * self.W2
? ? ? ? ? ? dW1 += self.reg_lambda * self.W1
? ? ? ? ? ? # Gradient descent parameter update
? ? ? ? ? ? self.W1 += -self.epsilon * dW1
? ? ? ? ? ? self.b1 += -self.epsilon * db1
? ? ? ? ? ? self.W2 += -self.epsilon * dW2
? ? ? ? ? ? self.b2 += -self.epsilon * db2
? ? ? ? ? ? del(data_index[rand_index])
可能是我寫的方式不好赫模,雖然可以得到正確的結(jié)果树肃,但是性能上卻比不上BGD,希望大家能指出問題所在瀑罗,運行效果圖:
其他
SVM我還在看胸嘴,里面的公式推導(dǎo)能把人繞死,稍晚一點寫好合入斩祭,數(shù)學(xué)不好就是坑啊劣像。至于決策樹分類,貝葉斯分類等比較簡單的摧玫,沒有數(shù)學(xué)功底的人實現(xiàn)起來也很容易耳奕,就不放進(jìn)去了。