一 感知器
感知器學習筆記:https://blog.csdn.net/liyuanbhu/article/details/51622695
感知器(Perceptron)是二分類的線性分類模型,其輸入為實例的特征向量,輸出為實例的類別,取+1和-1。這種算法的局限性很大:
- 只能將數據分為 2 類;
- 數據必須是線性可分的;
雖然有這些局限,但是感知器是 ANN 和 SVM 的基礎,理解了感知器的原理,對學習ANN 和 SVM 會有幫助,所以還是值得花些時間的。
感知器可以表示為 f:Rn -> {-1,+1}的映射函數,其中f的形式如下:
f(x) = sign(w.x+b)
其中w,b都是n維列向量,w表示權重,b表示偏置,w.x表示w和x的內積。感知器的訓練過程其實就是求解w和b的過程,正確的w和b所構成的超平面w.x + b=0恰好將兩類數據點分割在這個平面的兩側。
二 神經網絡
今天,使用的神經網絡就是由一個個類似感知器的神經元模型疊加拼接成的。目前常用的神經元包括S型神經元,ReLU神經元,tanh神經元,Softmax神經元等等。
手寫數字識別是目前在學習神經網絡中普遍使用的案例。在這個案例中將的是簡單的全連接網絡實現手寫數字識別,這個例子主要包括三個部分。
- .模型搭建;
- 確定目標函數,設置損失和梯度值;
- 選擇算法,設置優化器選擇合適的學習率更新權重和偏置;
MNIST數據集可以從這里下載:https://github.com/mnielsen/neural-networks-and-deep-learning,也可以使用TensorFlow提供的一個庫,可以直接用來自動下載和安裝MNIST:
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('MNIST-data',one_hot=True)
運行上面代碼,會自動下載數據集並將文件解壓到當前代碼所在統計目錄下的MNIST_data文件夾下。其中one_hot = True,表示將樣本轉換為one_hot編碼。也就是二值化。
手寫數字識別代碼如下:
# -*- coding: utf-8 -*- """ Created on Sun Apr 1 19:16:15 2018 @author: Administrator """ ''' 使用TnsorFlow實現手寫數字識別 ''' import numpy as np import matplotlib.pyplot as plt #繪制訓練集准確率,以及測試卷准確率曲線 def plot_overlay_accuracy(training_accuracy,test_accuaracy): ''' test_accuracy,training_accuracy:訓練集測試集准確率 ''' #迭代次數 num_epochs = len(test_accuaracy) #獲取一個figure實例 fig = plt.figure()
#使用面向對象的方式添加Axes實例,參數1:子圖總行數 參數2:子圖總列數 參數3:子圖位置 ax = fig.add_subplot(111) ax.plot(np.arange(0, num_epochs), [accuracy*100.0 for accuracy in test_accuaracy], color='#2A6EA6', label="Accuracy on the test data") ax.plot(np.arange(0, num_epochs), [accuracy*100.0 for accuracy in training_accuracy], color='#FFA933', label="Accuracy on the training data") ax.grid(True) ax.set_xlim([0, num_epochs]) ax.set_xlabel('Epoch') ax.set_ylim([90, 100]) ax.legend(loc="lower right") #右小角 plt.show() #繪制訓練集代價和測試卷代價函數曲線 def plot_overlay_cost(training_cost,test_cost): ''' test,reaining:訓練集測試集代價 list類型 ''' #迭代次數 num_epochs = len(test_cost) fig = plt.figure() ax = fig.add_subplot(111) ax.plot(np.arange(0, num_epochs), [cost for cost in test_cost], color='#2A6EA6', label="Cost on the test data") ax.plot(np.arange(0, num_epochs), [cost for cost in training_cost], color='#FFA933', label="Cost on the training data") ax.grid(True) ax.set_xlim([0, num_epochs]) ax.set_xlabel('Epoch') #ax.set_ylim([0, 0.75]) ax.legend(loc="upper right") plt.show() from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix ''' 打印圖片 images:list或者tuple,每一個元素對應一張圖片 title:list或者tuple,每一個元素對應一張圖片的標題 h:高度的像素數 w:寬度像素數 n_row:輸出行數 n_col:輸出列數 ''' def plot_gallery(images,title,h,w,n_row=3,n_col=4): #pyplt的方式繪圖 指定整個繪圖對象的寬度和高度 plt.figure(figsize=(1.8*n_col,2.4*n_row)) plt.subplots_adjust(bottom=0,left=.01,right=.99,top=.90,hspace=.35) #繪制每個子圖 for i in range(n_row*n_col): #第i+1個子窗口 默認從1開始編號 plt.subplot(n_row,n_col,i+1) #顯示圖片 傳入height*width矩陣 https://blog.csdn.net/Eastmount/article/details/73392106?locationNum=5&fps=1 plt.imshow(images[i].reshape((h,w)),cmap=plt.cm.gray) #cmap Colormap 灰度 #設置標題 plt.title(title[i],size=12) plt.xticks(()) plt.yticks(()) plt.show() ''' 打印第i個測試樣本對應的標題 Y_pred:測試集預測結果集合 (分類標簽集合) Y_test: 測試集真實結果集合 (分類標簽集合) target_names:分類每個標簽對應的名稱 i:第i個樣本 ''' def title(Y_pred,Y_test,target_names,i): pred_name = target_names[Y_pred[i]].rsplit(' ',1)[-1] true_name = target_names[Y_test[i]].rsplit(' ',1)[-1] return 'predicted:%s\ntrue: %s' %(pred_name,true_name) import tensorflow as tf #設置tensorflow對GPU使用按需分配 config = tf.ConfigProto() config.gpu_options.allow_growth = True sess = tf.InteractiveSession(config=config) ''' 一 導入數據 ''' from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('MNIST-data',one_hot=True) print(type(mnist)) #<class 'tensorflow.contrib.learn.python.learn.datasets.base.Datasets'> print('Training data shape:',mnist.train.images.shape) #Training data shape: (55000, 784) print('Test data shape:',mnist.test.images.shape) #Test data shape: (10000, 784) print('Validation data shape:',mnist.validation.images.shape) #Validation data shape: (5000, 784) print('Training label shape:',mnist.train.labels.shape) #Training label shape: (55000, 10) ''' 二 搭建前饋神經網絡模型 搭建一個包含輸入層分別為 784,1024,10個神經元的神經網絡 ''' #初始化權值和偏重 def weight_variable(shape): #使用正太分布初始化權值 initial = tf.truncated_normal(shape,stddev=0.1) #標准差為0.1 return tf.Variable(initial) def bias_variable(shape): initial = tf.constant(0.1,shape=shape) return tf.Variable(initial) #input layer None表示張量第一維度可以是任意長度的 x_ = tf.placeholder(tf.float32,shape=[None,784]) y_ = tf.placeholder(tf.float32,shape=[None,10]) #隱藏層 w_h = weight_variable([784,1024]) b_h = bias_variable([1024]) hidden = tf.nn.relu(tf.matmul(x_,w_h) + b_h) #輸出層 w_o = weight_variable([1024,10]) b_o = bias_variable([10]) output = tf.nn.softmax(tf.matmul(hidden,w_o) + b_o) ''' 三 設置對數似然損失函數 ''' #代價函數 J =-(Σy.logaL)/n .表示逐元素乘 cost = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(output),axis=1)) ''' 四 求解 ''' train = tf.train.AdamOptimizer(0.001).minimize(cost) #預測結果評估 #tf.argmax(output,1) 按行統計最大值得索引 correct = tf.equal(tf.argmax(output,1),tf.argmax(y_,1)) #返回一個數組 表示統計預測正確或者錯誤 accuracy = tf.reduce_mean(tf.cast(correct,tf.float32)) #求准確率 #創建list 保存每一迭代的結果 training_accuracy_list = [] test_accuracy_list = [] training_cost_list=[] test_cost_list=[] #使用會話執行圖 sess.run(tf.global_variables_initializer()) #初始化變量 #開始迭代 使用Adam優化的隨機梯度下降法 for i in range(5000): #一個epoch需要迭代次數計算公式:測試集長度 / batch_size x_batch,y_batch = mnist.train.next_batch(batch_size = 64) #開始訓練 train.run(feed_dict={x_:x_batch,y_:y_batch}) if (i+1)%200 == 0: #輸出訓練集准確率 #training_accuracy = accuracy.eval(feed_dict={x_:mnist.train.images,y_:mnist.train.labels}) training_accuracy,training_cost = sess.run([accuracy,cost],feed_dict={x_:mnist.train.images,y_:mnist.train.labels}) training_accuracy_list.append(training_accuracy) training_cost_list.append(training_cost) print('{0}:Training set accuracy {1},cost {2}.'.format(i+1,training_accuracy,training_cost)) #輸出測試機准確率 #test_accuracy = accuracy.eval(feed_dict={x_:mnist.test.images,y_:mnist.test.labels}) test_accuracy,test_cost = sess.run([accuracy,cost],feed_dict={x_:mnist.test.images,y_:mnist.test.labels}) test_accuracy_list.append(test_accuracy) test_cost_list.append(test_cost) print('{0}:Test set accuracy {1},cost {2}.'.format(i+1,test_accuracy,test_cost)) #繪制曲線圖 plot_overlay_cost(training_cost_list,test_cost_list) plot_overlay_accuracy(training_accuracy_list,test_accuracy_list) #取24個樣本,可視化顯示預測效果 x_batch,y_batch = mnist.test.next_batch(batch_size = 24) #獲取x_batch圖像對象的數字標簽 y_test = np.argmax(y_batch,1) #獲取預測結果 y_pred = np.argmax(output.eval(feed_dict={x_:x_batch,y_:y_batch}),1) #顯示與分類標簽0-9對應的名詞 target_names = ['number 0','number 1','number 2','number 3','number 4','number 5','number 6','number 7','number 8','number 9'] #需要測試的真實的標簽和預測作為比較 顯示主要的分類指標,返回每個類標簽的精確、召回率及F1值 print(classification_report(y_test,y_pred,target_names = target_names)) #建立一個n*n 分別對應每一組真實的和預測的值 用於呈現一種可視化效果 print(confusion_matrix(y_test,y_pred,labels = range(len(target_names)))) #標題 prediction_titles = [title(y_pred,y_test,target_names,i) for i in range(y_pred.shape[0])] #打印圖片 plot_gallery(x_batch,prediction_titles,28,28,6,4)
運行結果如下:
在上一個程序中有一個很明顯的缺陷,我們的神經網絡的層數是固定的,如果有多層的話,我們需要一一定義每一層,這樣就會很麻煩,下面通過定義一個類來實現上面程序的功能。
# -*- coding: utf-8 -*- """ Created on Mon Apr 2 10:32:10 2018 @author: Administrator """ ''' 定義一個network類,實現全連接網絡 ''' import matplotlib.pyplot as plt ''' 打印圖片 images:list或者tuple,每一個元素對應一張圖片 title:list或者tuple,每一個元素對應一張圖片的標題 h:高度的像素數 w:寬度像素數 n_row:輸出行數 n_col:輸出列數 ''' def plot_gallery(images,title,h,w,n_row=3,n_col=4): #pyplt的方式繪圖 指定整個繪圖對象的寬度和高度 plt.figure(figsize=(1.8*n_col,2.4*n_row)) plt.subplots_adjust(bottom=0,left=.01,right=.99,top=.90,hspace=.35) #繪制每個子圖 for i in range(n_row*n_col): #第i+1個子窗口 默認從1開始編號 plt.subplot(n_row,n_col,i+1) #顯示圖片 傳入height*width矩陣 https://blog.csdn.net/Eastmount/article/details/73392106?locationNum=5&fps=1 plt.imshow(images[i].reshape((h,w)),cmap=plt.cm.gray) #cmap Colormap 灰度 #設置標題 plt.title(title[i],size=12) plt.xticks(()) plt.yticks(()) plt.show() ''' 打印第i個測試樣本對應的標題 Y_pred:測試集預測結果集合 (分類標簽集合) Y_test: 測試集真是結果集合 (分類標簽集合) target_names:分類每個標簽對應的名稱 i:第i個樣本 ''' def title(Y_pred,Y_test,target_names,i): pred_name = target_names[Y_pred[i]].rsplit(' ',1)[-1] true_name = target_names[Y_test[i]].rsplit(' ',1)[-1] return 'predicted:%s\ntrue: %s' %(pred_name,true_name) import tensorflow as tf import numpy as np import random ''' 導入數據 ''' from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('MNIST-data',one_hot=True) print(type(mnist)) #<class 'tensorflow.contrib.learn.python.learn.datasets.base.Datasets'> print('Training data shape:',mnist.train.images.shape) #Training data shape: (55000, 784) print('Test data shape:',mnist.test.images.shape) #Test data shape: (10000, 784) print('Validation data shape:',mnist.validation.images.shape) #Validation data shape: (5000, 784) print('Training label shape:',mnist.train.labels.shape) #Training label shape: (55000, 10) class network(object): ''' 全連接神經網絡 ''' def __init__(self,sizes): ''' 注意程序中op變量只需要初始化一遍就可以,在fit()中初始化 sizes:list傳入每層神經元個數 ''' #保存參數 self.__sizes = sizes #神經網絡每一層的神經元個數數組類型 self.sizes = tf.placeholder(tf.int64,shape=[1,len(sizes)]) #計算神經網絡層數 包括輸入層 self.num_layer = tf.size(self.sizes) #隨機初始化權重 第i層和i+1層之間的權重向量 self.weights = [self.weight_variable(shape=(x,y)) for x,y in zip(sizes[:-1],sizes[1:])] #隨機初始化偏置 第i層的偏置向量 i=1...num_layers 注意不可以設置shape=(x,1) self.biases = [self.bias_variable(shape=[x,]) for x in sizes[1:]] #輸入樣本和輸出類別變量 self.x_ = tf.placeholder(tf.float32,shape=[None,sizes[0]]) self.y_ = tf.placeholder(tf.float32,shape=[None,sizes[-1]]) #設置tensorflow對GPU使用按需分配 config = tf.ConfigProto() config.gpu_options.allow_growth = True self.sess = tf.InteractiveSession(config=config) def weight_variable(self,shape): ''' 初始化權值 ''' #使用截斷式正太分布初始化權值 截斷式即在正態分布基礎上加以限制,以使生產的數據在一定范圍上 initial = tf.truncated_normal(shape,mean=0.0,stddev= 1.0/shape[0]) #方差為1/nin return tf.Variable(initial) def bias_variable(self,shape): ''' #初始化偏重 ''' initial = tf.truncated_normal(shape,mean=0.0,stddev= 1.0/shape[0]) #方差為1/nin return tf.Variable(initial) def feedforward(self,x): ''' 構建階段:前向反饋 x:變量op,tf.placeholder()類型變量 返回一個op ''' #計算隱藏層 output = x for i in range(len(self.__sizes)-1): b = self.biases[i] w = self.weights[i] if i != len(self.__sizes)-2 : output = tf.nn.relu(tf.matmul(output,w) + b) else: output = tf.nn.softmax(tf.matmul(output,w) + b) return output def fit(self,training_x,training_y,learning_rate=0.001,batch_size=64,epochs=10): ''' 訓練神經網絡 x:訓練集樣本 y:訓練集樣本對應的標簽 learning_rate:學習率 batch_size:批量大小 epochs:迭代輪數 ''' #計算輸出層 output = self.feedforward(self.x_) #代價函數 J =-(Σy.logaL)/n .表示逐元素乘 cost = tf.reduce_mean( -tf.reduce_sum(self.y_*tf.log(output),axis = 1)) #求解 train = tf.train.AdamOptimizer(learning_rate).minimize(cost) #使用會話執行圖 #初始化變量 必須在train之后 self.sess.run(tf.global_variables_initializer()) #訓練集長度 n = training_x.shape[0] #開始迭代 使用Adam優化的隨機梯度下降法 for i in range(epochs): # 預取圖像和label並隨機打亂 random.shuffle([training_x,training_y]) x_batches = [training_x[k:k+batch_size] for k in range(0,n,batch_size)] y_batches = [training_y[k:k+batch_size] for k in range(0,n,batch_size)] #開始訓練 for x_batch,y_batch in zip(x_batches,y_batches): train.run(feed_dict={self.x_:x_batch,self.y_:y_batch}) #計算每一輪迭代后的誤差 並打印 train_cost = cost.eval(feed_dict={self.x_:training_x,self.y_:training_y}) print('Epoch {0} Training set cost {1}:'.format(i,train_cost)) def predict(self,test_x): ''' 對輸入test_x樣本進行預測 ''' output = self.feedforward(self.x_) #使用會話執行圖 return output.eval(feed_dict={self.x_:test_x}) def accuracy(self,x,y): ''' 返回值准確率 x:測試樣本集合 y:測試類別集合 ''' output = self.feedforward(self.x_) correct = tf.equal(tf.argmax(output,1),tf.argmax(self.y_,1)) #返回一個數組 表示統計預測正確或者錯誤 accuracy = tf.reduce_mean(tf.cast(correct,tf.float32)) #求准確率 #使用會話執行圖 return accuracy.eval(feed_dict={self.x_:x,self.y_:y}) def cost(self,x,y): ''' 計算代價值 ''' #計算輸出層 output = self.feedforward(self.x_) #代價函數 J =-(Σy.logaL)/n .表示逐元素乘 cost = tf.reduce_mean(-tf.reduce_sum(self.y_*tf.log(output),axis=1)) #使用會話執行圖 return cost.eval(feed_dict={self.x_:x,self.y_:y}) #開始測試 nn = network([784,1024,10]) nn.fit(mnist.train.images,mnist.train.labels,0.0001,64,10) weights = nn.sess.run(nn.weights) print('輸出權重維數:') for weight in weights: print(weight.shape) print('輸出偏置維數:') biases = nn.sess.run(nn.biases) for biase in biases: print(biase.shape) print('准確率:',nn.accuracy(mnist.test.images,mnist.test.labels)) #取24個樣本,可視化顯示預測效果 x_batch,y_batch = mnist.test.next_batch(batch_size = 24) #獲取x_batch圖像對象的數字標簽 y_test = np.argmax(y_batch,1) #獲取預測結果 y_pred = np.argmax(nn.predict(x_batch),1) #顯示與分類標簽0-9對應的名詞 target_names = ['number 0','number 1','number 2','number 3','number 4','number 5','number 6','number 7','number 8','number 9'] #標題 prediction_titles = [title(y_pred,y_test,target_names,i) for i in range(y_pred.shape[0])] #打印圖片 plot_gallery(x_batch,prediction_titles,28,28,6,4)
運行結果如下: