JAVA實(shí)現(xiàn)感知器算法
簡(jiǎn)述
隨著互聯(lián)網(wǎng)的高速發(fā)展,A(AI)B(BigData)C(Cloud)已經(jīng)成為當(dāng)下的核心發(fā)展方向,假如三者深度結(jié)合的話,AI是其中最核心的部分。所以如果說在未來社會(huì),每個(gè)人都必須要學(xué)會(huì)編程的話,那么對(duì)于程序員來說,人工智能則是他們所必須掌握的技術(shù)(科技發(fā)展真tm快)。
這篇文章介紹并用JAVA實(shí)現(xiàn)了一種最簡(jiǎn)單的感知器網(wǎng)絡(luò),不糾結(jié)于公式的推導(dǎo),旨在給大家提供一下學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)的思路,對(duì)神經(jīng)網(wǎng)絡(luò)有一個(gè)大概的認(rèn)識(shí)。
感知器網(wǎng)絡(luò)模型分析
首先看一張圖
如果稍微對(duì)神經(jīng)網(wǎng)絡(luò)感興趣的一定對(duì)這張圖不陌生,這張圖是神經(jīng)元的結(jié)構(gòu)圖
X1~Xm表示輸入,W1~Wm表示突觸權(quán)值,Σ表示求和結(jié)點(diǎn),Activation function表示激活函數(shù),之后輸出一個(gè)結(jié)果,具體的流程是
神經(jīng)元接收到輸入,每個(gè)輸入都會(huì)與其相對(duì)路徑上的權(quán)值相乘,到了求和結(jié)點(diǎn)進(jìn)行求和,這里把求和結(jié)點(diǎn)的結(jié)果設(shè)為z :
z = X1 * W1 + X2 * W2 + X3 * W3 + ...... + Xm * Wm
之后將 z 傳入到激活函數(shù)(這里我們稱激活函數(shù)為 f)進(jìn)行二分類模式識(shí)別 :
if f(x) > e,y = 1 else y = -1 e 為閾值 y 為分類結(jié)果
這里可以看出,如果 f(x) 的值大于閾值,得到分類 y = 1,反之 y = -1
注:相對(duì)于生物神經(jīng)元受到刺激表示的反應(yīng),如果刺激在可接受范圍之內(nèi),則神經(jīng)元會(huì)抑制刺激(y = -1),如果超過范圍則會(huì)興奮(y = 1),而這個(gè)范圍的分水嶺就是閾值(e)
學(xué)習(xí)
我們發(fā)現(xiàn),如果權(quán)值和閾值都固定的話,那么這個(gè)神經(jīng)網(wǎng)絡(luò)就沒有存在的意義了,所以我們引入學(xué)習(xí)的概念,通過學(xué)習(xí),讓神經(jīng)網(wǎng)絡(luò)去修改權(quán)值和閾值,從而可以動(dòng)態(tài)的修正模式識(shí)別的正確率,這才是機(jī)器學(xué)習(xí)的本質(zhì)。
那么如何學(xué)習(xí)呢?當(dāng)我們?cè)谑褂弥拔覀冃枰峁┙o此網(wǎng)絡(luò)一組樣本數(shù)據(jù)(這里采取的是有教師模式學(xué)習(xí)),樣本數(shù)據(jù)包括輸入數(shù)據(jù)x和正確的識(shí)別結(jié)果y'。
當(dāng)我們輸入訓(xùn)練數(shù)據(jù)x得到模式識(shí)別y之后進(jìn)行判斷,如果 y != y' ,則會(huì)去調(diào)整此網(wǎng)絡(luò)的權(quán)值和閾值,調(diào)整請(qǐng)看公式,μ 表示學(xué)習(xí)率(修正率),update 表示需要修正值:
update = μ * (yi - y') update = (f(x) - y') m Σ Wi += update * Xi i=1 e += update
當(dāng)感知器分類結(jié)果等于正確分類,update = 0,不調(diào)整網(wǎng)絡(luò);如果不等于正確分類,則會(huì)調(diào)整全部的權(quán)值(w)與閾值(e)
以上就是我所介紹的感知器最簡(jiǎn)單的學(xué)習(xí)流程:
輸入數(shù)據(jù)->求和得到z->通過激活函數(shù)等到分類結(jié)果->分類結(jié)果與正確結(jié)果不符則調(diào)整網(wǎng)絡(luò)
下面就讓我們來實(shí)現(xiàn)這個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)吧
Java代碼實(shí)現(xiàn)
這里我所實(shí)現(xiàn)的是通過神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)識(shí)別整數(shù)的正負(fù)
首先定義一個(gè)感知器的類
/** * Created by CimZzz on 12/2/17. * */ public class Perceptron { /** * 學(xué)習(xí)率 */ private final float learnRate; /** * 學(xué)習(xí)次數(shù) */ private final int studyCount; /** * 閾值 */ private float e; /** * 權(quán)值 * 因?yàn)榕袛嗾麛?shù)正負(fù)只需要一條輸入,所以這里只有一個(gè)權(quán)值,多條輸入可以設(shè)置為數(shù)組 */ private float w; /** * 每次學(xué)習(xí)的正確率 */ private float[] correctRate; // /** * 構(gòu)造函數(shù)初始化學(xué)習(xí)率,學(xué)習(xí)次數(shù),權(quán)值、閾值初始化為0 * @param learnRate 學(xué)習(xí)率(取值范圍 0 < learnRate < 1) * @param studyCount 學(xué)習(xí)次數(shù) */ public Perceptron(float learnRate, int studyCount) { this.learnRate = learnRate; this.studyCount = studyCount; this.e = 0; this.w = 0; this.correctRate = new float[studyCount]; } /** * 學(xué)習(xí)函數(shù),samples 是一個(gè)包含輸入數(shù)據(jù)和分類結(jié)果的二維數(shù)組, * samples[][0] 表示輸入數(shù)據(jù) * samples[][1] 表示正確的分類結(jié)果 * @param samples 訓(xùn)練數(shù)據(jù) */ public void fit(int[][] samples) { int sampleLength = samples.length; for(int i = 0 ; i < studyCount ; i ++) { int errorCount = 0; for (int[] sample : samples) { float update = learnRate * (sample[1]-predict(sample[0])); //更新權(quán)值、閾值 w += update * sample[0]; e += update; //計(jì)算錯(cuò)誤次數(shù) if (update != 0) errorCount++; } //計(jì)算此次學(xué)習(xí)的正確率 correctRate[i] = 1 - errorCount * 1.0f / sampleLength; } } /** * 求和函數(shù),模擬求和結(jié)點(diǎn)操作 輸入數(shù)據(jù) * 權(quán)值 * @param num 輸入數(shù)據(jù) * @return 求和結(jié)果 z */ private float sum(int num) { return num * w + e; } /** * 激活函數(shù),通過求和結(jié)果 z 和閾值 e 進(jìn)行判斷 * @param num 輸入數(shù)據(jù) * @return 分類結(jié)果 */ public int predict(int num) { return sum(num) >= 0 ? 1 : -1; } /** * 打印正確率 */ public void printCorrectRate() { for (int i = 0 ; i < studyCount ; i ++) System.out.printf("第%d次學(xué)習(xí)的正確率 -> %.2f%%\n",i + 1,correctRate[i] * 100); } }
然后寫生成訓(xùn)練數(shù)據(jù)的函數(shù)
/** * 生成訓(xùn)練數(shù)據(jù) * @return 訓(xùn)練數(shù)據(jù) */ private static int[][] genStudyData() { //這里我們?nèi)?-100 ~ 100 之間的整數(shù),大于0的設(shè)為模式 y = 1,反之為 y = -1 int[][] data = new int[201][2]; for(int i = -100 , j = 0; i <= 100 ; i ++ , j ++) { data[j][0] = i; data[j][1] = i >= 0 ? 1 : -1; } return data; } /** * 生成訓(xùn)練數(shù)據(jù) * @return 訓(xùn)練數(shù)據(jù) */ private static int[][] genStudyData2() { //這里我們?nèi)?1~250 之間的整數(shù),大于125的設(shè)為模式 y = 1,反之為 y = -1 int[][] data = new int[250][2]; for(int i = 1 , j = 0; i <= 250 ; i ++ , j ++) { data[j][0] = i; data[j][1] = i >= 125 ? 1 : -1; } return data; }
最后是主函數(shù)
public static void main(String[] args) { //這里的學(xué)習(xí)率和訓(xùn)練次數(shù)可以根據(jù)情況人為調(diào)整 Perceptron perceptron = new Perceptron(0.4f,500); perceptron.fit(genStudyData()); perceptron.printCorrectRate(); System.out.println(perceptron.predict(-1)); System.out.println(perceptron.predict(126)); }
大家可以測(cè)試一下
局限性
這個(gè)感知器神經(jīng)網(wǎng)絡(luò)比較簡(jiǎn)單,是適用于可線性劃分的數(shù)據(jù),比如一維的話正數(shù)和負(fù)數(shù),二維的坐標(biāo)象限分類;對(duì)于不可線性劃分的數(shù)據(jù)無法進(jìn)行正確的分類,如尋找質(zhì)數(shù)等
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python實(shí)現(xiàn)的knn算法示例
- python使用KNN算法手寫體識(shí)別
- 以Python代碼實(shí)例展示kNN算法的實(shí)際運(yùn)用
- kNN算法python實(shí)現(xiàn)和簡(jiǎn)單數(shù)字識(shí)別的方法
- Java實(shí)現(xiàn)的樸素貝葉斯算法示例
- Java實(shí)現(xiàn)的傅里葉變化算法示例
- Java實(shí)現(xiàn)五子棋AI算法
- 使用棧的迷宮算法java版代碼
- Java實(shí)現(xiàn)走迷宮回溯算法
- Java實(shí)現(xiàn)Floyd算法求最短路徑
- Java實(shí)現(xiàn)的KNN算法示例
相關(guān)文章
淺談xml配置spring profiles的幾個(gè)注意點(diǎn)
這篇文章主要介紹了淺談xml配置spring profiles的幾個(gè)注意點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Java中的==和equals()區(qū)別小結(jié)
在Java編程中,理解==操作符和equals()方法的區(qū)別是至關(guān)重要的,本文主要介紹了Java中的==和equals()區(qū)別,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08