matlab手写神经网络实现识别手写数字
實驗說明
一直想自己寫一個神經網絡來實現手寫數字的識別,而不是套用別人的框架。恰巧前幾天,有幸從同學那拿到5000張已經貼好標簽的手寫數字圖片,于是我就嘗試用matlab寫一個網絡。
實驗數據:5000張手寫數字圖片(.jpg),圖片命名為1.jpg,2.jpg…5000.jpg。還有一個放著標簽的excel文件。
數據處理:前4000張作為訓練樣本,后1000張作為測試樣本。
圖片處理:用matlab的imread()函數讀取圖片的灰度值矩陣(28,28),然后把每張圖片的灰度值矩陣reshape為(28*28,1),然后把前4000張圖片的灰度值矩陣合并為x_train,把后1000張圖片的灰度值矩陣合并為x_test。
神經網絡設計
網絡層設計:一層隱藏層,一層輸出層
輸入層:一張圖片的灰度值矩陣reshape后的784個數,也就是x_train中的某一列
輸出層:(10,1)的列向量,其中列向量中最大的數所在的索引就是預測的數字
激勵函數:sigmoid函數(公式)
更新法則:后向傳播算法(參考)
一點說明:這里的訓練我分別用了普通梯度下降法和mini_batch(batch size 為10)梯度下降法來實現
測試:用了兩種方式表示正確率,一是統計預測正確的個數,而是利用matlab的plotconfusion函數
網絡實現
全部實現包括5個函數(gedata.m / layerout.m / mytrain.m / mytrain_mini.m / test.m)和一個main.m文件。
讀取數據(getdata.m)
function[x_train,y_train,x_test,y_test]=getdata() %把圖片變成像素矩陣 %path :圖片路徑 % x_train:訓練樣本像素矩陣(784,4000) %y_train:訓練樣本標簽(10,4000) %x_test:測試樣本像素矩陣(784,1000) %y_test:測試樣本標簽(10,1000)% photopath = './photo/'; % snames=dir([photopath '*' '.jpg'])%get all filenames in photopath % l = length(snames) % % %get x_ data % x_train = []; % x_test = []; % % for i=1:4000 % iname=[photopath snames(i).name] %the path of jpg % x = imread(iname); % the shape of x is (28,28) % x = reshape(x,784,1); %reshape x to (784,1) % x_train = [x_train,x]; % end % % for k=4001:5000 % kname=[photopath snames(k).name]; %the path of jpg % x = imread(kname); %the shape of x is (28,28) % x = reshape(x,784,1); %reshape x to (784,1) % x_test = [x_test,x]; % endx_train=[];for i=1:4000x=im2double(imread(strcat(num2str(i),'.jpg')));x=reshape(x,784,1);x_train=[x_train,x]; end x_test =[];for k=4001:5000x=im2double(imread(strcat(num2str(k),'.jpg')));x=reshape(x,784,1);x_test=[x_test,x]; end data=xlsread('label.xlsx'); y_train=data(:,1:4000); y_test = data(:,4001:5000);x_train; y_train; x_test; y_test;end這里踩了一個坑。我本來讀取圖片,是按目錄來讀取的,然后訓練出來的效果一直不好。一度懷疑自己的更新函數寫錯了,改了很久,才發現按目錄讀取的圖片順序是錯誤的!按目錄讀取的圖片并不是按1,2,3…這樣讀的,而是按下面的順序讀取的,這樣就和label對不上了!!!
layerout函數
function [y] = layerout(w,b,x) %output function y = w*x + b; n = length(y); for i =1:ny(i)=1.0/(1+exp(-y(i))); end y; end訓練一(mytrain.m)
function[w,b,w_h,b_h]=mytrain(x_train,y_train) %train function:設置一個隱藏層,784-->隱藏層神經元個數-->10 %x_train:訓練樣本的像素數據 %y_train:訓練樣本的標簽 %w:輸出層權重 %b:輸出層偏置 %w_h:隱藏層權重 %b_h:隱藏層偏置 %step:循環步數step=input('迭代步數:'); a=input('學習因子:'); in = 784; %輸入神經元個數 hid = input('隱藏層神經元個數:');%隱藏層神經元個數 out = 10; %輸出層神經元個數 o =1;w = randn(out,hid); b = randn(out,1); w_h =randn(hid,in); b_h = randn(hid,1);for i=0:step%打亂訓練樣本r=randperm(4000);x_train = x_train(:,r);y_train = y_train(:,r);for j=1:4000x = x_train(:,j);y = y_train(:,j);hid_put = layerout(w_h,b_h,x);out_put = layerout(w,b,hid_put);%更新公式的實現o_update = (y-out_put).*out_put.*(1-out_put);h_update = ((w')*o_update).*hid_put.*(1-hid_put);outw_update = a*(o_update*(hid_put'));outb_update = a*o_update;hidw_update = a*(h_update*(x'));hidb_update = a*h_update;w = w + outw_update;b = b+ outb_update;w_h = w_h +hidw_update;b_h =b_h +hidb_update;end end end訓練二(mytrain_mini.m)
function[w,b,w_h,b_h]=mytrain_mini(x_train,y_train) %train function:設置一個隱藏層,784-->隱藏層神經元個數-->10 %x_train:訓練樣本的像素數據 %y_train:訓練樣本的標簽 %w:輸出層權重 %b:輸出層偏置 %w_h:隱藏層權重 %b_h:隱藏層偏置 %step:循環步數step=ipout('迭代步數:'); a=input('學習因子:'); in = 784; %輸入神經元個數 hid = input('隱藏層神經元個數:');%隱藏層神經元個數 out = 10; %輸出層神經元個數 o =1;w = randn(out,hid); b = randn(out,1); w_h =randn(hid,in); b_h = randn(hid,1);for i=0:step%打亂訓練樣本r=randperm(4000);x_train = x_train(:,r);y_train = y_train(:,r);%mini_batchfor jj=0:399%取batch為10 更新取10次的平均值for j=jj*10+1:(jj+1)*10x = x_train(:,j);y = y_train(:,j);hid_put = layerout(w_h,b_h,x);out_put = layerout(w,b,hid_put);%更新公式的實現o_update = (y-out_put).*out_put.*(1-out_put);h_update = ((w')*o_update).*hid_put.*(1-hid_put);if j==1outw_update = (double(a)/10)*(o_update*(hid_put'));outb_update = (double(a)/10)*o_update;hidw_update = (double(a)/10)*(h_update*(x'));hidb_update = (double(a)/10)*h_update;endif j~=1outw_update = outw_update + (double(a)/10)*(o_update*(hid_put'));outb_update = outb_update -(double(a)/10)*o_update;hidw_update = hidw_update + (double(a)/10)*(h_update*(x'));hidb_update = hidb_update -(double(a)/10)*h_update;endendw = w + outw_update;b = b+ outb_update;w_h = w_h +hidw_update;b_h =b_h +hidb_update;end end end測試(mytest.m)
function[]= mytest(x_test,y_test,w,b,w_h,b_h) %x_test:測試樣本的像素數據 %y_test:測試樣本的標簽 %w:輸出層權重 %b:輸出層偏置 %w_h:隱藏層權重 %b_h:隱藏層偏置test = zeros(10,1000); for k=1:1000x = x_test(:,k);hid = layerout(w_h,b_h,x);test(:,k)=layerout(w,b,hid);%正確率表示方式一:輸出正確個數[t,t_index]=max(test);[y,y_index]=max(y_test);sum = 0;for p=1:length(t_index)if t_index(p)==y_index(p)sum =sum+1;endend endfprintf('正確率: %d/1000\n',sum);%正確率表示方式二:用plotconfusion函數 plotconfusion(y_test,test); endmain.m
[x_train,y_train,x_test,y_test]=getdata();%歸一化 x_train = mapminmax(x_train,0,1); x_test =mapminmax(x_test,0,1);[w1,b1,w_h1,b_h1]=mytrain(x_train,y_train); fprintf('mytrain正確率:\n'); mytest(x_test,y_test,w1,b1,w_h1,b_h1);[w2,b2,w_h2,b_h2]=mytrain(x_train,y_train); fprintf('mytrain_mini正確率:\n'); mytest(x_test,y_test,w2,b2,w_h2,b_h2);實驗結果
直接運行main.m,且兩個訓練方式都輸入相同參數,得到結果如下:
下面是mini_batch的plotconfusion結果,mytrain的也差不多。其中綠色的為正確率:
直觀感覺min_batch方式的訓練會快一丟丟。由于這里數據不多,所以兩者的差別看不大出來!
總結
以上是生活随笔為你收集整理的matlab手写神经网络实现识别手写数字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020hdu多校6
- 下一篇: 夺命雷公狗---DEDECMS----3