大綱
- 神經網絡學習
- 常用模型分析
- iOS中的CoreML等閉源庫
- 通過bench_ios中的CC_ANN使用激活函數ReLU和Sigmoid實現DNN網絡。
- caffe、tensorflow等對比
目錄:
- 介紹一個CC_ANN使用例子
- 回顧神經網絡的構成
- 進行一次完整計算
CC_ANN是用oc封裝的一層和多層神經網絡例子,支持激活函數Sigmoid和ReLU
調用例子
//一次乘法的學習
//創建一個ANN網絡
CC_ANN *ann=[[CC_ANN alloc]init];
//學習100次
int count=100
[ann autoTrainTwoToOne:@[@[@[@(0.2),@(0.6)],@(0.12)],@[@[@(0.4),@(0.6)],@(0.24)],@[@[@(0.3),@(0.4)],@(0.12)]] activeFunction:ActiveFunctionTypeSigmoid trainTimes:count];
double predict1=[ann calWithInput:@[@(0.2),@(0.6)]];
double predict2=[ann calWithInput:@[@(0.4),@(0.6)]];
double predict3=[ann calWithInput:@[@(0.3),@(0.4)]];
double predict4=[ann calWithInput:@[@(0.4),@(0.5)]];
NSLog(@"p1=%f p2=%f p3=%f p4=%f",predict1,predict2,predict3,predict4);
//打印結果
p1=0.121306 p2=0.237448 p3=0.122096 p4=0.208426
耗時0.002秒
//學習1000次
int count=1000
//打印結果
p1=0.120000 p2=0.239999 p3=0.120001 p4=0.209638
耗時0.026秒
//學習10000次
int count=10000
//打印結果
p1=0.120000 p2=0.240000 p3=0.120000 p4=0.209638
耗時0.28秒
例子結論:
- 學習次數越多,對例子的還原越正確。如2*6越來越接近12
- 學習次數到達一定次數後,對預測的精確度不會再提高。如我們沒有教過4*5,但是預測答案接近20,在學習1000次後,達到20.9638,但是學習10000次也沒有將精度再次提高
這個例子符合神經網絡的特徵
下面看下如何構建一層神經網絡,具體的計算方法。
線性函數和sigmoid函數
LinearRegression模型:
sigmoid函數:
隱層決定了最終的分類效果
可以看到,隱層越多,分類效果越好,因爲可以轉折的點更多。實際上,Kolmogorov理論指出:雙隱層感知器就足以解決任何複雜的分類問題。
但是,過多的隱層和神經元結點會帶來過擬合問題,不要試圖降低神經網絡參數量來減緩過擬合,用正則化或者dropout。
神經網絡結構
傳遞函數/激活函數
每一層傳遞使用wx+b,對每一個輸出使用sigmoid、tanh、relu等激活函數使線性的結果非線性化。
爲什麼需要傳遞函數?
簡單理解上,如果不加激活函數,無論多少層隱層,最終的結果還是原始輸入的線性變化,這樣一層隱層就可以達到結果,就沒有多層感知器的意義了。所以每個隱層都會配一個激活函數,提供非線性變化。
BP算法
一個反饋網絡,類似生物的反饋網絡,和人走路不會摔倒一樣,每一次輸出都會有反饋去修正誤差,使下一次結果更接近理想結果。
以三層感知器爲例做計算:
網絡結構
可以用到的公式爲:
代入參數:
兩個輸入;
隱層: b1, w1, w2, w3, w4 (都有初始值) 計算一個合理的初始值可以使用前面提到的HE初始化、隨機初始化和pre-train初始化
輸出層:b2, w5, w6, w7, w8(賦了初始值)
這裏使用sigmoid激活函數
用E來衡量誤差大小,爲反饋提供支持:
獲得E後反向計算誤差:
對E求導就可計算出誤差梯度
計算出w5、w6、w7、w8的誤差梯度:
誤差梯度乘以學習率即是需要調整的誤差值
同理,再向上一級推導出w1-w4的誤差值:
完成一次反向傳播:
求誤差對w5的偏導過程 參數更新: 求誤差對w1的偏導 注意,w1對兩個輸出的誤差都有影響
通過以上過程可以更新所有權重,就可以再次迭代更新了,直到滿足條件。
可以提供的數學函數:
@interface CC_Math : NSObject
+ (double)sign:(double)input;
/**
* 激活函數
*/
+ (double)sigmoid:(double)input;
+ (double)reLU:(double)input;
/**
* 雙s曲線
*/
+ (double)doubleS:(int)input;
/**
* 標準正態分佈
*/
+ (double)randn:(double)input;
/**
* 獲得初始化權重
* length w個數
*/
+ (NSMutableArray *)getW_positive_unitball:(int)length;
/**
* weight = np.random.randn(in_node, out_node)/np.sqrt(in_node)
*/
+ (NSMutableArray *)getW_XavierFiller:(int)length;
/**
* Xavier論文中使用的激活函數是tanh函數,而神經網絡中使用較廣泛的是relu激活函數,所以提出此方法。
weight = np.random.randn(in_node, out_node)/np.sqrt(in_node/2)
*/
+ (NSMutableArray *)getW_MSRAFiller:(int)length;
@end
可以提供的ANN函數
typedef enum : NSUInteger {
ActiveFunctionTypeReLU,
ActiveFunctionTypeSigmoid,//如使用sigmoid 輸入輸出範圍在[-1,1]
} ActiveFunctionType;
@interface CC_ANN : NSObject
/**
* 訓練結束後可計算結果
*/
- (double)calWithInput:(NSArray *)input;
//- (double)calWithInput_twolevel:(NSArray *)input;
/**
* 一層深度學習
* samples 學習樣本 多個樣本以數組形式
例:@[@[@[@(0.2),@(0.6)],@(0.12)],@[@[@(0.4),@(0.6)],@(0.24)]]
* weights 初始化權重 一層深度 2個輸入1個輸出需要權重 2^2+2=6個初始值
* learningRate 學習率 選一個較小值 如0.4
* activeFunction 激活函數
* times 訓練次數
*/
- (void)trainTwoToOne:(NSArray *)samples weights:(NSArray *)weights learningRate:(double)learningRate activeFunction:(ActiveFunctionType)activeFunction trainTimes:(int)times;
/**
* 一層深度學習 自動尋找最佳學習率 自動獲取初始化權值w
* activeFunction 激活函數
* times 訓練次數
*/
- (void)autoTrainTwoToOne:(NSArray *)samples activeFunction:(ActiveFunctionType)activeFunction trainTimes:(int)times;
/**
* 一層深度學習 自動尋找最佳學習率 自動獲取初始化權值w
* errorRate 到最小錯誤率前不會停止學習
*/
- (void)autoTrainTwoToOne:(NSArray *)samples activeFunction:(ActiveFunctionType)activeFunction untilErrorRate:(double)errorRate;
- (void)trainTwoToOne:(NSArray *)samples trainTimes:(int)times deep:(int)deep;
- (void)trainTwoToOne:(NSArray *)samples trainTimes:(int)times;
@end