写在前面:
此次作业是使用两种方式来识别手写数字,顺序为逻辑回归、神经网络前向传播(带已经训练好的参数)
1. 逻辑回归解决多分类问题
思路:对于每个数字,创建一个分类器(比如说1,则创建分类器识别该组数据是否是一),然后算出每个分类器的参数,将所有分类器(因为此处是数字,所以有十组参数)参数存在一个总的参数数据集中(此数据集就是训练的结果,也就是说通过此数据集可以判断一个新的手写数字图片是数字几)
tips:原理就是将图片的每个参数当做特征,然后训练模型来识别特征值达到学习的目的,最终得到分类器(可以识别新数字的)
下面上源代码:
''' warning: the range of initial data in matlab file is 1-10 but in this place ,the 10 is indicate 0 the data in ex3data1.mat is so many row which size is 1*400(has been compressed) ''' # 此处不使用自己定义的梯度下降函数,使用scipy模块中自带的minimize函数 import numpy as np import matplotlib.pyplot as plt import scipy.io as sio from scipy.optimize import minimize # the function which can plot one image(anyone) in pic_set ''' minimize参数解释: - fun:要优化的函数(损失函数) - method:优化方法 - jac:梯度向量 - x0:参数初始值(n,)(n,1) (n,)(n,1)的区别 ''' def plot_an_image(X): pick_one = np.random.randint(len(X)) image = X[pick_one,:] fig,ax = plt.subplots(figsize = (1,1)) ax.imshow(image.reshape(20,20).T,cmap = 'gray_r') # 去掉刻度 plt.xticks([]) plt.yticks([]) plt.show() def plot_100_image(X): sample_index = np.random.choice(len(X),100) images = X[sample_index,:] # 后面两个参数控制横纵坐标是否显示 fig,ax = plt.subplots(ncols=10,nrows=10,figsize = (8,8),sharex=True,sharey=True) for r in range(10): for c in range(10): ax[r][c].imshow(images[10*r+c].reshape(20,20).T,cmap = 'gray_r') # ax.imshow(image.reshape(20,20).T,cmap = 'gray_r') # 去掉刻度 plt.xticks([]) plt.yticks([]) plt.show() def sigmoid(z): return 1/(1+np.exp(-z)) # 注意此处的传入参数顺序是固定的,打乱会导致调用np模块内优化算法出错 def costFunction(theta,X,y,lamda): A = sigmoid(X@theta) first = (~y)* np.log(A) second = (1-y) * np.log(1-A) # 惩罚项 # 两种写法都可以 # reg = np.sum(np.power(theta[1:],2))*( lamda / 2 * len(X)) reg = theta[1:]@theta[1:]*(lamda / 2 * len(X)) return np.sum(first - second)/len(X) + reg # 无需循环,使用np的内置方法 def gradient_reg(theta,X,y,lamda): reg = theta[1:]*(lamda/len(X)) reg = np.insert(reg,0,values = 0,axis = 0) first = (X.T@(sigmoid(X@theta) - y))/len(X) return first + reg def one_va_all(X,y,lamda,K): n = X.shape[1] # 使用二维数组来存储所有theta theta_all = np.zeros((K,n)) for i in range(1,K+1): # 定义第i个分类器的参数 theta_i = np.zeros(n,) # 判别式y==i是用来分辨是第几类标签 res = minimize(fun = costFunction, x0 = theta_i, args = (X,y == i,lamda), method = 'TNC', jac = gradient_reg) theta_all[i-1,:] = res.x return theta_all def predict(X,theta_final): h = sigmoid(X@theta_final.T) h_argmax = np.argmax(h,axis = 1)# 返回一行中最大值的索引 return h_argmax + 1 data = sio.loadmat('./data_set/ex3data1.mat') # print(data) # print(type(data)) # print(data.keys()) raw_X = data['X'] raw_y = data['y'] # print(raw_X.shape) # print(raw_X[1].shape) # plot_an_image(raw_X) # plot_100_image(raw_X) X = np.insert(raw_X,0,values=1,axis = 1) # 将y从二维数组变成一维数组 y = raw_y.flatten() lamda = 1 K = 10 theta_final = one_va_all(X,y,lamda,K) # for each in y: # print(each) y_pred = predict(X,theta_final) acc = np.mean(y == y_pred) print(acc)
2.使用神经网路解决问题
思路:此处因为已经有训练好的参数,所以直接前向传播就好,此处有一个隐藏层,一个输入层,一个输出层,激活函数使用sigmoid函数,输入层传入的参数是每个照片的图片参数,然后输出层是每个图片在每一个数字判断器中运算的结果(也就是概率),最大的那个就是预测出来的数值
下面上源代码:
''' natural network use natural network to implement the recognization of hand write number input the number image's attribute and output the predict number of each image ''' import numpy as np import scipy.io as sio def sigmoid(z): return 1/(1+np.exp(-z)) data = sio.loadmat('./data_set/ex3data1.mat') raw_X = data['X'] raw_y = data['y'] X = np.insert(raw_X,0,values = 1,axis = 1) # X.shape y = raw_y.flatten() # the theta is format by dictionary theta = sio.loadmat('./data_set/ex3weights.mat') # print(theta.keys()) # <Theta1> includes the attribute of input layer to hidden layer # <Theta2> includes the attribute of hidden layer to output layer theta1 = theta['Theta1'] theta2 = theta['Theta2'] # use sigmoid function as activate function a1 = X # obtain the number of hidden layer z2 = X @ theta1.T a2 = sigmoid(z2) a2 = np.insert(a2,0,values = 1,axis = 1) # obtain the number of output layer z3 = a2 @ theta2.T a3 = sigmoid(z3) y_pred = np.argmax(a3,axis = 1) y_pred += 1 acc = np.mean(y_pred==y) print(acc)
以上
希望对大家有所帮助