1. 程式人生 > 其它 >【樹葉分類】基於matlab GUI BP神經網路植物葉片識別分類【含Matlab原始碼 916期】

【樹葉分類】基於matlab GUI BP神經網路植物葉片識別分類【含Matlab原始碼 916期】

一、簡介

1 概述
BP(Back Propagation)神經網路是1986年由Rumelhart和McCelland為首的科研小組提出,參見他們發表在Nature上的論文 Learning representations by back-propagating errors 。

BP神經網路是一種按誤差逆傳播演算法訓練的多層前饋網路,是目前應用最廣泛的神經網路模型之一。BP網路能學習和存貯大量的 輸入-輸出模式對映關係,而無需事前揭示描述這種對映關係的數學方程。它的學習規則是使用最速下降法,通過反向傳播來不斷 調整網路的權值和閾值,使網路的誤差平方和最小。

2 BP演算法的基本思想
上一次我們說到,多層感知器在如何獲取隱層的權值的問題上遇到了瓶頸。既然我們無法直接得到隱層的權值,能否先通過輸出層得到輸出結果和期望輸出的誤差來間接調整隱層的權值呢?BP演算法就是採用這樣的思想設計出來的演算法,它的基本思想是,學習過程由訊號的正向傳播與誤差的反向傳播兩個過程組成。
正向傳播時,輸入樣本從輸入層傳入,經各隱層逐層處理後,傳向輸出層。若輸出層的實際輸出與期望的輸出(教師訊號)不符,則轉入誤差的反向傳播階段。
反向傳播時,將輸出以某種形式通過隱層向輸入層逐層反傳,並將誤差分攤給各層的所有單元,從而獲得各層單元的誤差訊號,此誤差訊號即作為修正各單元權值的依據。
這兩個過程的具體流程會在後文介紹。

BP演算法的訊號流向圖如下圖所示

3 BP網路特性分析——BP三要素
我們分析一個ANN時,通常都是從它的三要素入手,即
1)網路拓撲結構;
2)傳遞函式;
3)學習演算法。

每一個要素的特性加起來就決定了這個ANN的功能特性。所以,我們也從這三要素入手對BP網路的研究。
3.1 BP網路的拓撲結構
上一次已經說了,BP網路實際上就是多層感知器,因此它的拓撲結構和多層感知器的拓撲結構相同。由於單隱層(三層)感知器已經能夠解決簡單的非線性問題,因此應用最為普遍。三層感知器的拓撲結構如下圖所示。
一個最簡單的三層BP:

3.2 BP網路的傳遞函式
BP網路採用的傳遞函式是非線性變換函式——Sigmoid函式(又稱S函式)。其特點是函式本身及其導數都是連續的,因而在處理上十分方便。為什麼要選擇這個函式,等下在介紹BP網路的學習演算法的時候會進行進一步的介紹。
單極性S型函式曲線如下圖所示。

雙極性S型函式曲線如下圖所示。

3.3 BP網路的學習演算法
BP網路的學習演算法就是BP演算法,又叫 δ 演算法(在ANN的學習過程中我們會發現不少具有多個名稱的術語), 以三層感知器為例,當網路輸出與期望輸出不等時,存在輸出誤差 E ,定義如下




下面我們會介紹BP網路的學習訓練的具體過程。

4 BP網路的訓練分解
訓練一個BP神經網路,實際上就是調整網路的權重和偏置這兩個引數,BP神經網路的訓練過程分兩部分:

前向傳輸,逐層波浪式的傳遞輸出值;
逆向反饋,反向逐層調整權重和偏置;
我們先來看前向傳輸。
前向傳輸(Feed-Forward前向反饋)
在訓練網路之前,我們需要隨機初始化權重和偏置,對每一個權重取[ − 1 , 1 ] [-1,1][−1,1]的一個隨機實數,每一個偏置取[ 0 , 1 ] [0,1][0,1]的一個隨機實數,之後就開始進行前向傳輸。

神經網路的訓練是由多趟迭代完成的,每一趟迭代都使用訓練集的所有記錄,而每一次訓練網路只使用一條記錄,抽象的描述如下:

while 終止條件未滿足:
    for record:dataset:
        trainModel(record)



4.1 逆向反饋(Backpropagation)


4.2 訓練終止條件
每一輪訓練都使用資料集的所有記錄,但什麼時候停止,停止條件有下面兩種:
設定最大迭代次數,比如使用資料集迭代100次後停止訓練
計算訓練集在網路上的預測準確率,達到一定門限值後停止訓練

5 BP網路執行的具體流程
5.1 網路結構
輸入層有n nn個神經元,隱含層有p pp個神經元,輸出層有q qq個神經元。
5.2 變數定義








第九步:判斷模型合理性
判斷網路誤差是否滿足要求。
當誤差達到預設精度或者學習次數大於設計的最大次數,則結束演算法。
否則,選取下一個學習樣本以及對應的輸出期望,返回第三部,進入下一輪學習。

6 BP網路的設計
在進行BP網路的設計是,一般應從網路的層數、每層中的神經元個數和啟用函式、初始值以及學習速率等幾個方面來進行考慮,下面是一些選取的原則。
6.1 網路的層數
理論已經證明,具有偏差和至少一個S型隱層加上一個線性輸出層的網路,能夠逼近任何有理函式,增加層數可以進一步降低誤差,提高精度,但同時也是網路 複雜化。另外不能用僅具有非線性啟用函式的單層網路來解決問題,因為能用單層網路解決的問題,用自適應線性網路也一定能解決,而且自適應線性網路的 運算速度更快,而對於只能用非線性函式解決的問題,單層精度又不夠高,也只有增加層數才能達到期望的結果。
6.2 隱層神經元的個數
網路訓練精度的提高,可以通過採用一個隱含層,而增加其神經元個數的方法來獲得,這在結構實現上要比增加網路層數簡單得多。一般而言,我們用精度和 訓練網路的時間來恆量一個神經網路設計的好壞:
(1)神經元數太少時,網路不能很好的學習,訓練迭代的次數也比較多,訓練精度也不高。
(2)神經元數太多時,網路的功能越強大,精確度也更高,訓練迭代的次數也大,可能會出現過擬合(over fitting)現象。
由此,我們得到神經網路隱層神經元個數的選取原則是:在能夠解決問題的前提下,再加上一兩個神經元,以加快誤差下降速度即可。

6.3 初始權值的選取
一般初始權值是取值在(−1,1)之間的隨機數。另外威得羅等人在分析了兩層網路是如何對一個函式進行訓練後,提出選擇初始權值量級為s√r的策略, 其中r為輸入個數,s為第一層神經元個數。

6.4 學習速率
學習速率一般選取為0.01−0.8,大的學習速率可能導致系統的不穩定,但小的學習速率導致收斂太慢,需要較長的訓練時間。對於較複雜的網路, 在誤差曲面的不同位置可能需要不同的學習速率,為了減少尋找學習速率的訓練次數及時間,比較合適的方法是採用變化的自適應學習速率,使網路在 不同的階段設定不同大小的學習速率。

6.5 期望誤差的選取
在設計網路的過程中,期望誤差值也應當通過對比訓練後確定一個合適的值,這個合適的值是相對於所需要的隱層節點數來確定的。一般情況下,可以同時對兩個不同 的期望誤差值的網路進行訓練,最後通過綜合因素來確定其中一個網路。

7 BP網路的侷限性
BP網路具有以下的幾個問題:

(1)需要較長的訓練時間:這主要是由於學習速率太小所造成的,可採用變化的或自適應的學習速率來加以改進。
(2)完全不能訓練:這主要表現在網路的麻痺上,通常為了避免這種情況的產生,一是選取較小的初始權值,而是採用較小的學習速率。
(3)區域性最小值:這裡採用的梯度下降法可能收斂到區域性最小值,採用多層網路或較多的神經元,有可能得到更好的結果。

8 BP網路的改進
P演算法改進的主要目標是加快訓練速度,避免陷入區域性極小值等,常見的改進方法有帶動量因子演算法、自適應學習速率、變化的學習速率以及作用函式後縮法等。 動量因子法的基本思想是在反向傳播的基礎上,在每一個權值的變化上加上一項正比於前次權值變化的值,並根據反向傳播法來產生新的權值變化。而自適應學習 速率的方法則是針對一些特定的問題的。改變學習速率的方法的原則是,若連續幾次迭代中,若目標函式對某個權倒數的符號相同,則這個權的學習速率增加, 反之若符號相反則減小它的學習速率。而作用函式後縮法則是將作用函式進行平移,即加上一個常數。

二、原始碼

function varargout = Processing(varargin)
% PROCESSING MATLAB code for Processing.fig
%      PROCESSING, by itself, creates a new PROCESSING or raises the existing
%      singleton*.
%
%      H = PROCESSING returns the handle to a new PROCESSING or the handle to
%      the existing singleton*.
%
%      PROCESSING('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in PROCESSING.M with the given input arguments.
%
%      PROCESSING('Property','Value',...) creates a new PROCESSING or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before Processing_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to Processing_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help Processing

% Last Modified by GUIDE v2.5 22-May-2021 22:54:29

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Processing_OpeningFcn, ...
                   'gui_OutputFcn',  @Processing_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before Processing is made visible.
function Processing_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to Processing (see VARARGIN)

% Choose default command line output for Processing
handles.output = hObject;
setappdata(handles.Processing,'X',0);
setappdata(handles.Processing,'bw',0);
% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Processing wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = Processing_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in pushbutton12.
function pushbutton12_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton12 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton13.
function pushbutton13_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton13 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton8.
function pushbutton8_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton8 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton14.
function pushbutton14_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton14 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton15.
function pushbutton15_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton15 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton16.
function pushbutton16_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton16 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)



   
   
% --- Executes on button press in InputImage.
function InputImage_Callback(hObject, eventdata, handles)
% hObject    handle to InputImage (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

[filename,pathname]=uigetfile({'*.jpg';'*.bmp';'*.tif';'*.*'},'載入影象');  
 file=[pathname,filename];     
%  global S  %設定一個全域性變數S,儲存初始影象路徑,以便之後的還原操作
%  S=file;  
 X=imread(file);  
  set(handles.imageshow1,'HandleVisibility','ON'); 
   axes(handles.imageshow1); 
   imshow(X);  
   handles.img=X;  
   guidata(hObject,handles); 
setappdata(handles.Processing,'X',X);


% --- Executes on button press in pushbutton9.
function pushbutton9_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton9 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes during object creation, after setting all properties.
function imageshow1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to imageshow1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called
% global fname fpath see
% [fname,fpath]=uigetfile('*.*','開啟');
% see=[fpath fname];
% I=imread(see);
% axes(handles.axes1);
% imshow(I,'notruesize');
% title('原始圖片');
function B=boundaries(BW,conn,dir)
% 函式輸入
% BW:二值影象矩陣%
% conn:4或8
% 返回二值影象中連通區域的邊緣畫素的座標


if nargin<3   %nargin定義在使用者自定義函式體內,nargin返回
              %用來呼叫函式的變數的個數。
    dir='cw';
end
if nargin<2
    conn=8;
end

L=bwlabel(BW,conn); %返回值是矩陣L,大小同BW,包含了BW中的連通部分的標記

% 初始化結果矩陣B 
numObjects=max(L(:));%尋找L中所作標記中的最大值,這個最大值實際上就對應著L中
% 包含的最多的連通部分的數目。
if numObjects>0
    B={zeros(0,2)};%元包陣列中僅包含一個元素。
    B=repmat(B,numObjects,1);%將B進行numObjects*1個複製構成新的B。
else
    B={};
end

%在影象邊界補充0值畫素 
Lp=padarray(L,[1 1],0,'both');

%在方向和引索座標間建立關係 
M=size(Lp,1);%SIZE(X,1) returns the number of rows. 
             
if conn==8
    %Order is N NE E SE S SW W NW.
    offsets=[-1,M-1,M,M+1,1,-M+1,-M,-M-1];
else
    %Order is N E S W.
    offsets=[-1,M,1,-M];
end

% 搜尋方向的起始方向
if conn==8
    next_search_direction_lut=[8 8 2 2 4 4 6 6];
else
    next_search_direction_lut=[4 1 2 3];
end

%下一個訪問節點
if conn==8
  next_direction_lut=[2 3 4 5 6 7 8 1];
else
  next_direction_lut=[2 3 4 1];
end

START=-1;
BOUNDARY=-2;

scratch=zeros(100,1);
%Find candidate starting locations for boundaries.
[rr,cc]=find((Lp(2:end-1,:)>0)&(Lp(1:end-2,:)==0));
rr=rr+1;
for k=1:length(rr)
    r=rr(k);
    c=cc(k);
    if (Lp(r,c)>0)&(Lp(r-1,c)==0)&isempty(B{Lp(r,c)})
        %We've found the start of the next boundary.Compute its linear
        %offset,record which boundary it is,mark it,and initialize the
        %counter for the number of boundary pixels.
        idx=(c-1)*size(Lp,1)+r;
        which=Lp(idx);
        scratch(1)=idx;
        Lp(idx)=START;
        numpixels=1;
        currentpixel=idx;
        initial_departure_direction=[];
        done=0;
        next_search_direction=2;
        while ~done
            %Find the next boundary pixel.
            direction=next_search_direction;
            found_next_pixel=0;
            for k=1:length(offsets)
                neighbor=currentpixel+offsets(direction);
                if Lp(neighbor)~=0
                    %Found the next boundary pixel.
                    if (Lp(currentpixel)==START)&...
                        isempty(initial_departure_direction)
                    %We are making the initial departure from the starting
                    %pixel.
                    initial_departure_direction=direction;
                    elseif (Lp(currentpixel)==START)&...
                            (initial_departure_direction==direction)
                       % We are about to retrace our path.
                       %That means we're done.
                       done=1;
                       found_next_pixel=1;
                       break;
                    end
                    %Take the next step along the boundary.
                    next_search_direction=...
                        next_search_direction_lut(direction);
                    found_next_pixel=1;
                    numpixels=numpixels+1;
                    if numpixels>size(scratch,1)
                        %Double the scratch space.
                        scratch(2*size(scratch,1))=0;
                    end
                    scratch(numpixels)=neighbor;
                    if Lp(neighbor)~=START
                       Lp(neighbor)=BOUNDARY;
                    end
                    currentpixel=neighbor;
                    break;
                end
                direction=next_direction_lut(direction);
            end
            if ~found_next_pixel
                %If there is no next neighbor,the object must just have a
                %single pixel.
                numpixels=2;
                scratch(2)=scratch(1);
                done=1;
            end
        end
        %Convert linear indices to row_column coordinates and save in the
        %output cell array.
        [row,col]=ind2sub(size(Lp),scratch(1:numpixels));
        B{which}=[row-1,col-1];
    end
end

if strcmp(dir,'ccw')
    for k=1:length(B)
        B{k}=B{k}(end:-1:1,:);
    end
end

三、執行結果

四、備註

版本:2014a

完整程式碼或代寫加1564658423