├── BP.py ├── README.md ├── biases.txt ├── biases0.1.txt ├── biases2.txt ├── test_loadimage.py ├── testtk.py ├── weights.txt ├── weights0.1.txt ├── weights2.txt ├── 参数.txt ├── 实验报告.docx └── 思路图.docx /BP.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | from math import * 4 | import numpy as np 5 | from numpy import * 6 | import numpy as np 7 | from os import listdir 8 | 9 | import test_loadimage 10 | learningrate = 0.01 11 | 12 | def loadImages(dirName): 13 | hwLabels = [] 14 | trainingFileList = listdir(dirName) 15 | m = len(trainingFileList) 16 | trainingMat = zeros((m,1024)) 17 | for i in range(m): 18 | fileNameStr = trainingFileList[i] 19 | fileStr = fileNameStr.split('.')[0] 20 | classNumstr = int(fileStr.split('_')[0]) 21 | if classNumstr == 1:hwLabels.append([0,1,0,0,0,0,0,0,0,0]) 22 | else:hwLabels.append([0,0,0,0,0,0,0,0,0,1]) 23 | trainingMat[i,:] = img2vector('%s/%s'%(dirName , fileNameStr)) 24 | return trainingMat , hwLabels 25 | 26 | def img2vector(filename): 27 | #将32*32的矩阵转换为1*1024的向量 28 | returnVect = zeros((1,1024)) 29 | fr = open(filename) 30 | for i in range(32): 31 | lineStr = fr.readline() #一次读一行 32 | for j in range(32): 33 | returnVect[0,32*i+j] = int(lineStr[j]) 34 | return returnVect 35 | 36 | def WeightInit(i,j): 37 | """ 38 | 权值初始化 39 | :param i:前一层的神经元数量 40 | :param j: 后一层的神经元数量 41 | :return: 初始化后的权值矩阵 42 | """ 43 | W = mat(random.uniform(-2.4 / i, 2.4 / i, size=(j, i))) 44 | return W 45 | 46 | def init(M): 47 | W = [] ; b = [] 48 | for i in range(1,len(M)): 49 | W.append(WeightInit(M[i-1] , M[i])) 50 | b.append(mat(random.uniform(-2.4/M[i],2.4/M[i],size=(1,M[i]))).transpose()) 51 | return W,b 52 | 53 | #激励函数 54 | def sigmoid(x): 55 | if type(x) != int : 56 | y = np.zeros(shape(x)) 57 | for i in range(len(x)): 58 | y[i] = 1/(1+exp(-x[i])) 59 | else: 60 | y = 1/(1+exp(-x)) 61 | return y 62 | 63 | #激励函数的导数 64 | def ft(x): 65 | y = sigmoid(x)*(1-sigmoid(x)) 66 | return y 67 | 68 | def forward(M , W , b , data , label): 69 | """ 70 | 前向推导函数 71 | :param M: 层数向量 72 | :param W: 权值矩阵 73 | :param data: 传入的单个数据 74 | :param label:传入的单个标签 75 | :return:net, O, y, E矩阵 76 | """ 77 | Layer = len(M) 78 | net = [];O = [] 79 | for i in range(Layer): 80 | net.append(mat(np.zeros(M[i])).T) 81 | O.append(mat(np.zeros(M[i])).T) 82 | O[0] = data.transpose() 83 | y = mat(np.zeros(10)).T 84 | E = mat(np.zeros(10)).T 85 | for m in range(1,Layer): 86 | net[m] = W[m-1] * O[m-1] + b[m-1]; #第m层神经元净输入 87 | O[m] = sigmoid(net[m]); #第m层神经元净输出 88 | y = O[Layer-1]; 89 | E = 0.5*multiply(y-label,y-label) 90 | return net, O, y, E 91 | 92 | def backward(M, W, b, net, O, y, E, label,rate): 93 | """ 94 | 后向推导函数 95 | :param M:层数向量 96 | :param W:权值矩阵 97 | :param net:forward return的每一层的输入,list内嵌列矩阵 98 | :param O:forward return的每一层的输出,list内嵌列矩阵 99 | :param y:forword return的该数据的预测输出,列矩阵 100 | :param E:forward return的预测值和真实值的平方的二分之一 101 | :return:更新后的权值矩阵 102 | """ 103 | grad = [] 104 | for i in range(len(M)): 105 | grad.append(mat(np.zeros(M[i])).transpose()) 106 | layer = list(range(1,len(M))) 107 | layer.reverse() 108 | for m in layer: #从输出层回退 109 | if m == len(M) - 1: # 如果是输出层 110 | grad[m] = -multiply((label - y), ft(net[m])) 111 | W[m-1] -= rate * grad[m] *O[m-1].transpose() 112 | b[m-1] -= rate * grad[m] 113 | else: 114 | t = W[m].transpose()*grad[m+1] 115 | grad[m] = multiply(ft(net[m]),t) 116 | W[m-1] -= rate * grad[m]*O[m-1].transpose() 117 | b[m-1] -= rate * grad[m] 118 | return W , b 119 | 120 | def training(M , W , b, dataMat , labelMat , testMat , labelMat2 , iteration = 5 ): 121 | """ 122 | 训练模型,输出结果 123 | :param M:神经元数量向量 124 | :param W: 初始化的权值矩阵 125 | :param dataSet: 数据集 126 | :param labelSet: 标签集 127 | :return: 训练后的结果 128 | """ 129 | for iter in range(iteration): 130 | print("epoc %d:"%iter) 131 | for i in range(len(dataMat)): 132 | net, O, y, E = forward(M , W , b , dataMat[i] , labelMat[i].transpose()) 133 | rate = learningrate + 1/(iter + 1) 134 | W , b = backward(M , W , b, net , O , y ,E , labelMat[i].transpose(),rate) 135 | #print("第%d个样本训练!"%i) 136 | error = test(dataMat , labelMat , M , W , b) 137 | error2 = test(testMat , labelMat2 , M , W , b) 138 | return W , b 139 | 140 | def test(testSet ,testLabel , M , W , b): 141 | count = 0 142 | for i in range(len(testSet)): 143 | net, O, y, E = forward(M , W , b , testSet[i] , testLabel[i].transpose()) 144 | t = argmax(y) 145 | if t == argmax(testLabel[i].transpose()): 146 | count += 1 147 | #print("data%d 测试正确\n" % i) 148 | print("正确率为:%f" % (count/len(testSet))) 149 | return count/len(testSet) 150 | 151 | def store(input , filename): 152 | import pickle 153 | fw = open(filename , 'wb') 154 | pickle.dump(input , fw) 155 | fw.close() 156 | 157 | def grab(filename): 158 | import pickle 159 | fr = open(filename,'rb') 160 | return pickle.load(fr) 161 | 162 | def show(M , W , b , data ): 163 | Layer = len(M) 164 | net = [] 165 | O = [] 166 | for i in range(Layer): 167 | net.append(mat(np.zeros(M[i])).T) 168 | O.append(mat(np.zeros(M[i])).T) 169 | O[0] = data.transpose() 170 | y = mat(np.zeros(10)).T 171 | E = mat(np.zeros(10)).T 172 | for m in range(1, Layer): 173 | net[m] = W[m - 1] * O[m - 1] + b[m - 1] # 第m层神经元净输入 174 | O[m] = sigmoid(net[m]) # 第m层神经元净输出 175 | y = O[Layer - 1] 176 | return y 177 | 178 | if __name__ == "__main__": 179 | M = [256, 25 , 10] 180 | W, b = init(M) 181 | dataArr, labelArr, testArr, labelArr2 = test_loadimage.getdata() 182 | dataMat = mat(dataArr) 183 | labelMat = mat(labelArr) 184 | testMat = mat(testArr) 185 | labelMat2 = mat(labelArr2) 186 | W, b = training(M, W, b, dataMat, labelMat, testMat , labelMat2 , 100) 187 | store(W, 'weights.txt') 188 | store(b , 'biases.txt') 189 | #b = grab('biases.txt') 190 | test(testMat , labelMat2 , M , W , b) 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BP- 2 | 利用BP神经网络实现手写数字识别 3 | -------------------------------------------------------------------------------- /biases.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/biases.txt -------------------------------------------------------------------------------- /biases0.1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/biases0.1.txt -------------------------------------------------------------------------------- /biases2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/biases2.txt -------------------------------------------------------------------------------- /test_loadimage.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import numpy as np 3 | import sys, os 4 | from PIL import Image, ImageDraw 5 | 6 | #将512*512矩阵pre转化成n*n的post矩阵 7 | def MatrixProcess(n,pre,post): 8 | m=512/n 9 | m=int(m) 10 | #将矩阵中的值变成0或1(0则为1,255则为0) 11 | for i in range(512): 12 | for j in range(512): 13 | if pre[i, j] == 0: 14 | pre[i, j] = 1 15 | else: 16 | pre[i, j] = 0 17 | for i in range(0,n): 18 | for j in range(0,n): 19 | # print (pre[j * m:(j + 1) * m, i * m:(i + 1) * m]) 20 | # print (sum(pre[j * m:(j + 1) * m, i * m:(i + 1) * m])) 21 | if np.sum(pre[i*m:(i+1)*m,j*m:(j+1)*m])>=10: 22 | post[i,j]=1 23 | else: 24 | post[i,j]=0 25 | return post 26 | 27 | 28 | # 二值判断,如果确认是噪声,用改点的上面一个点的灰度进行替换 29 | # 该函数也可以改成RGB判断的,具体看需求如何 30 | 31 | def getPixel(image, x, y, G, N):#降噪 32 | L = image.getpixel((x, y)) 33 | if L > G: 34 | L = True 35 | else: 36 | L = False 37 | 38 | nearDots = 0 39 | if L == (image.getpixel((x - 1, y - 1)) > G): 40 | nearDots += 1 41 | if L == (image.getpixel((x - 1, y)) > G): 42 | nearDots += 1 43 | if L == (image.getpixel((x - 1, y + 1)) > G): 44 | nearDots += 1 45 | if L == (image.getpixel((x, y - 1)) > G): 46 | nearDots += 1 47 | if L == (image.getpixel((x, y + 1)) > G): 48 | nearDots += 1 49 | if L == (image.getpixel((x + 1, y - 1)) > G): 50 | nearDots += 1 51 | if L == (image.getpixel((x + 1, y)) > G): 52 | nearDots += 1 53 | if L == (image.getpixel((x + 1, y + 1)) > G): 54 | nearDots += 1 55 | 56 | if nearDots < N: 57 | return image.getpixel((x, y - 1)) 58 | else: 59 | return None 60 | 61 | # 降噪 62 | 63 | 64 | # 根据一个点A的RGB值,与周围的8个点的RBG值比较,设定一个值N(0 maxx: 129 | maxx=tempmaxx 130 | if tempmaxy>maxy: 131 | maxy=tempmaxy 132 | if maxy-miny<40: 133 | maxy=maxy+25 134 | miny=miny-25 135 | if maxx-minx<40: 136 | maxx=maxx+25 137 | minx=minx-25 138 | scalim=Image.fromarray(data[minx:maxx,miny:maxy]) 139 | scalim = scalim.resize((512, 512), Image.ANTIALIAS) 140 | scalim.show() 141 | scalim = scalim.convert("L") 142 | scalim = scalim.convert("1") 143 | 144 | # clearNoise(im, 50, 2, 1)#除噪 145 | data_s = scalim.getdata() 146 | data_s = np.matrix(data_s) 147 | # 变换成512*512 148 | data_s = np.reshape(data_s, (512, 512)) 149 | 150 | 151 | 152 | 153 | #print(data[0]) 154 | #new_im = Image.fromarray(data) 155 | #new_im.show() 156 | return data_s 157 | 158 | 159 | #将txt中数据输出为1xn*n的矩阵,值矩阵,值,txt命名格式'classsNumstr_order',如'5_2'为第二张5的手写图片转化成的txt 160 | def loadtxt(n,dirName): 161 | trainingFileList = os.listdir(dirName) 162 | m = len(trainingFileList) 163 | trainingMat = np.zeros((m,n*n)) 164 | hwLabels = np.mat(np.zeros((m, 10))) 165 | for i in range(m): 166 | fileNameStr = trainingFileList[i] 167 | fileStr = fileNameStr.split('.')[0] 168 | classNumstr = int(fileStr.split('_')[0]) 169 | hwLabels[i,int(classNumstr)]=1 170 | trainingMat[i,:] =img2vector(n,'%s/%s'%(dirName , fileNameStr)) 171 | return trainingMat , hwLabels 172 | 173 | #读取txt中的数据 174 | def img2vector(n,filename): 175 | returnVect = np.zeros((1,n*n)) 176 | fr = open(filename) 177 | lineStr=fr.readline() 178 | for i in range(n*n): 179 | returnVect[0,i] = int(lineStr[i]) 180 | return returnVect 181 | 182 | 183 | def getimages(n=16): 184 | trainingimageList = os.listdir("image") 185 | m = len(trainingimageList) 186 | for i in range(m): 187 | data = np.mat(np.zeros((1,512*512))) 188 | data = loadImage('image/%s'%trainingimageList[i],data)#将图片转换成512*512的矩阵 189 | data_norm = np.mat(np.zeros((n,n)))#data_norm是将data处理后矩阵 190 | data_norm = MatrixProcess(n, data, data_norm) 191 | print (data_norm) 192 | fileNameStr = trainingimageList[i] 193 | fileStr = fileNameStr.split('.')[0] 194 | np.savetxt('data/%s.txt'%fileStr,data_norm,'%d',newline='',delimiter='') 195 | print('转换完毕') 196 | 197 | def getdata(n=16): 198 | DataSet, Labels = loadtxt(n, "data") 199 | testSet , testLabels = loadtxt(n,'testdata') 200 | return DataSet,Labels , testSet , testLabels 201 | 202 | def show_loadtxt(n,dirName): 203 | trainingFileList = os.listdir(dirName) 204 | m = len(trainingFileList) 205 | trainingMat = np.zeros((m, n * n)) 206 | hwLabels = np.mat(np.zeros((m, 10))) 207 | for i in range(m): 208 | fileNameStr = trainingFileList[i] 209 | trainingMat[i, :] = img2vector(n, '%s/%s' % (dirName, fileNameStr)) 210 | return trainingMat 211 | 212 | def show(n=16): 213 | data = np.mat(np.zeros((1, 512 * 512))) 214 | data = loadImage('showimage/show.jpg', data) # 将图片转换成512*512的矩阵 215 | data_norm = np.mat(np.zeros((n, n))) # data_norm是将data处理后矩阵 216 | data_norm = MatrixProcess(n, data, data_norm) 217 | print (data_norm) 218 | np.savetxt('showdata/show.txt' , data_norm, '%d', newline='', delimiter='') 219 | 220 | -------------------------------------------------------------------------------- /testtk.py: -------------------------------------------------------------------------------- 1 | # encoding=utf-8 2 | from tkinter import * 3 | from tkinter import ttk 4 | from PIL import * 5 | from PIL import ImageGrab 6 | import BP 7 | import test_loadimage as tl 8 | from tkinter import scrolledtext 9 | from tkinter import Menu 10 | from tkinter import Spinbox 11 | from tkinter import messagebox as mBox 12 | 13 | k=10 14 | 15 | canvas_width = 500 16 | canvas_height = 500 17 | 18 | 19 | def callback(): 20 | #屏幕size=1536*864 21 | im0 = ImageGrab.grab((90,80,590,330)) 22 | #im0.show() 23 | im0.save('showimage/show.jpg') 24 | tl.show() 25 | W=BP.grab('weights2.txt') 26 | b = BP.grab('biases2.txt') 27 | M = [256, 25, 10] 28 | data=tl.show_loadtxt(16,'showdata') 29 | y=BP.show(M , W , b , data ) 30 | #print(y) 31 | max=0 32 | for i in range(len(y)): 33 | if y[i]>max: 34 | max=y[i] 35 | k=i 36 | print(k) 37 | a.set(k) 38 | master.update() 39 | 40 | def paint( event ): 41 | python_green = "#476042" 42 | x1, y1 = ( event.x - 1 ), ( event.y - 1 ) 43 | x2, y2 = ( event.x + 1 ), ( event.y + 1 ) 44 | w.create_oval( x1, y1, x2, y2, fill = python_green ) 45 | 46 | master = Tk() 47 | master.title( "Painting using Ovals" ) 48 | a=StringVar() 49 | #fm1 = Frame(master, bg='red', width=500, height=500) 50 | w = Canvas(master,bg='white',width=canvas_width,height=canvas_height) 51 | label=ttk.Label(master,text='The Number Is:').place(x=5,y=3) 52 | label=ttk.Label(master,textvariable=a).place(x=100,y=3) 53 | la=ttk.Button(master, text="start",width=10,command=callback).pack() 54 | ttk.Button(master, text="clear",width=10,command=(lambda x=ALL:w.delete(x))).pack(side='bottom') 55 | #one = Label(master,tex,compound='left',width = 30,height = 2).pack() 56 | #expand = YES, fill = BOTH 57 | w.pack() 58 | w.bind( "", paint ) 59 | 60 | message = Label( master, text = "Press and Drag the mouse to draw" ) 61 | message.pack( side = BOTTOM ) 62 | 63 | mainloop() -------------------------------------------------------------------------------- /weights.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/weights.txt -------------------------------------------------------------------------------- /weights0.1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/weights0.1.txt -------------------------------------------------------------------------------- /weights2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/weights2.txt -------------------------------------------------------------------------------- /参数.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/参数.txt -------------------------------------------------------------------------------- /实验报告.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/实验报告.docx -------------------------------------------------------------------------------- /思路图.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nan1104/BP-/09aacc0bd8b3e433084f0645e0b223b2d1e1fc54/思路图.docx --------------------------------------------------------------------------------