1 引言
機器學習(Machine Learning)有很多經典的算法,其中基於深度神經網絡的深度學習算法目前最受追捧,主要是因為其因為擊敗李世石的阿爾法狗所用到的算法實際上就是基於神經網絡的深度學習算法。本文先介紹基本的神經元,然后簡單的感知機,擴展到多層神經網絡,多層前饋神經網絡,其他常見的神經網絡,接着介紹基於深度神經網絡的深度學習,紙上得來終覺淺,本文最后用python語言自己編寫一個多層前饋神經網絡。
2 神經元模型
這是生物大腦中的基本單元——神經元。
在這個模型中,神經元接受到來自n個其他神經元傳遞過來的輸入信號,在這些輸入信號通過帶權重的連接進行傳遞,神經元接受到的總輸入值將與神經元的閾值進行比較,然后通過“激活函數”處理以產生神經元的輸出。
3 感知機與多層網絡
感知機由兩層神經元組成,輸入層接收外界輸入信號后傳遞給輸出層,輸出層是M-P神經元。
要解決非線性可分問題,需考慮使用多層神經元功能。每層神經元與下一層神經元全互連,神經元之間不存在同層連接,也不存在跨層連接。這樣的神經網絡結構通常稱為“多層前饋神經網絡”。
神經網絡的學習過程,就是根據訓練數據來調整神經元之間的“連接權”以及每個功能神經元的閾值;換言之,神經網絡“學”到的東西,蘊涵在連接權與閾值之中。
4 誤差逆傳播算法
網絡在上的均方誤差為:
正是由於其強大的表達能力,BP神經網絡經常遭遇過擬合,其訓練過程誤差持續降低,但測試誤差卻可能上升。有兩種策略常用來緩解BP網絡過擬合。第一種策略是“早停”:將數據分成訓練集和驗證集,訓練集用來計算梯度、更新連接權和閾值。第二種策略是“正則化”,其基本思想是在誤差目標函數中增加一個用於描述網絡復雜度的部分。
5 全局最小與局部極小
若用Ε表示神經網絡在訓練集上的誤差,則它顯然關於連接權ω和閾值$\theta$的函數。此時,神經網絡的訓練過程可看作一個參數尋優的過程,即在參數空間中,尋找最優參數使得E最小。
6 其他常見的神經網絡
- RBF網絡
- ART網絡
- SOM網絡
- 級聯相關網絡
- Elman網絡
- Boltzmann機
7 深度學習
典型的深度學習就是很深層的神經網絡,顯然,對神經網絡模型,提高容量的簡單方法是增加隱層,隱層多了,相應的神經元連接權、閾值等參數就會更多。模型復雜度也可以通過單純增加隱層神經元的數目來實現。
深度學習的多隱層堆疊,每層對上一層的輸出進行處理的機制,可看作是在對輸入信號進行逐層加工,從而把初始的,與輸出目標之間聯系不太密切的輸入表示,轉換為與輸出目標聯系更密切的表示,使得原來僅基於最后一層輸出映射難以完成的任務成為可能。換言之,通過多層處理,逐漸將初始的“低層”特征表示轉換為“高層”特征表示后,用“簡單模型”即可完成復雜的分類任務,由此可將深度學習理解為進行“特征學習”或“表示學習”。
8 使用python制作神經網絡
讓我們勾勒神經網絡類的大概樣子,我們知道它應該至少有三個函數:
- 初始化函數——設置輸入層節點、隱藏層節點和輸出層節點
- 訓練——學習給定訓練集樣本后,優化權重
- 查詢——給定輸入,從輸出節點給出答案
# 神經網絡類 class neuralNetwork: # 初始化網絡 def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes #鏈接權重矩陣 self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes)) self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes)) # learning rate self.lr = learningrate self.activation_function = lambda x: 1/(1+numpy.exp(-x)) pass # 訓練網絡 def train(self, inputs_list, targets_list): # convert inputs list to 2d array inputs = numpy.array(inputs_list, ndmin=2).T targets = numpy.array(targets_list, ndmin=2).T # calculate signals into hidden layer hidden_inputs = numpy.dot(self.wih, inputs) # calculate the signals emerging from hidden layer hidden_outputs = self.activation_function(hidden_inputs) # calculate signals into final output layer final_inputs = numpy.dot(self.who, hidden_outputs) # calculate the signals emerging from final output layer final_outputs = self.activation_function(final_inputs) # output layer error is the (target - actual) output_errors = targets - final_outputs # hidden layer error is the output_errors, split by weights, recombined at hidden nodes hidden_errors = numpy.dot(self.who.T, output_errors) # update the weights for the links between the hidden and output layers self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs)) # update the weights for the links between the input and hidden layers self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs)) pass # 查詢網絡 def query(self, inputs_list): # convert inputs list to 2d array inputs = numpy.array(inputs_list, ndmin=2).T # calculate signals into hidden layer hidden_inputs = numpy.dot(self.wih, inputs) # calculate the signals emerging from hidden layer hidden_outputs = self.activation_function(hidden_inputs) # calculate signals into final output layer final_inputs = numpy.dot(self.who, hidden_outputs) # calculate the signals emerging from final output layer final_outputs = self.activation_function(final_inputs) return final_outputs
手寫數字的數據集MNIST
training_data_file = open("mnist_dataset/mnist_train.csv", 'r') training_data_list = training_data_file.readlines() training_data_file.close()
訓練數據集
epochs = 5 for e in range(epochs): # go through all records in the training data set for record in training_data_list: # split the record by the ',' commas all_values = record.split(',') # scale and shift the inputs # 輸入值需要避免0,輸出值需要避免1 inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # create the target output values (all 0.01, except the desired label which is 0.99) targets = numpy.zeros(output_nodes) + 0.01 # all_values[0] is the target label for this record targets[int(all_values[0])] = 0.99 n.train(inputs, targets) pass pass
測試數據集
test_data_file = open("mnist_dataset/mnist_test.csv", 'r') test_data_list = test_data_file.readlines() test_data_file.close() scorecard = [] # go through all the records in the test data set for record in test_data_list: # split the record by the ',' commas all_values = record.split(',') # correct answer is first value correct_label = int(all_values[0]) # scale and shift the inputs inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 # query the network outputs = n.query(inputs) # the index of the highest value corresponds to the label label = numpy.argmax(outputs) # append correct or incorrect to list if (label == correct_label): # network's answer matches correct answer, add 1 to scorecard scorecard.append(1) else: # network's answer doesn't match correct answer, add 0 to scorecard scorecard.append(0) pass pass # calculate the performance score, the fraction of correct answers scorecard_array = numpy.asarray(scorecard) print ("performance = ", scorecard_array.su m() / scorecard_array.size)