逻辑回归实现数字手写识别
我是用自己写的算法实现数字手写识别,采用的是Mnist的数据集,因为数据过多,所以我训练集取了600张,测试集取了100张
提取图片
因为mnist的数据集下载的是ubyte格式,我先把他转成jpg格式。
代码如下:
def readfile(): # 读取源图片文件
with open('E:\\pycharm\\python-代码\\train-images.idx3-ubyte', 'rb') as f1:
buf1 = f1.read()
return buf1
def get_image(buf1): # 解析并保存图片
image_index = 0
image_index += struct.calcsize('>IIII')
magic, numImages, imgRows, imgCols = struct.unpack_from(">IIII", buf1, 0)
im = []
for i in range(numImages):
temp = struct.unpack_from('>784B', buf1, image_index)
im = np.array(temp)
im2 = im.reshape(28, 28)
cv2.imwrite("E:\\train\\testIM" + str(i) + ".jpg", im2) # 保存路径自己设置
image_index += struct.calcsize('>784B') # 28*28=784(B)
if i % 20 == 0: # 知道图片保存的进度
print(i)
else:
print(i, )
把图片转化成像素以及提取图片的标签
mnist数据集的图片都是28 x 28的,像素提取出来以后的矩阵也是28 x 28的。我把像素的矩阵转化为1 x 784的向量。600张图片即为600 x 784的矩阵,再进行转置,变为784 x 600的矩阵。
def gettrainImages(): # 得到训练集像素
train_set = np.zeros([train_num, 784], int) # 建立一个600行,784列的空矩阵
for i in range(0, train_num):
print("训练集第"+str(i)+"张图片")
img = np.array(Image.open('E:/train/testIM' + str(i) + '.jpg')) # 读取前600张图片的像素
for rows in range(28):
for cols in range(28):
if img[rows, cols] >= 127: # 若灰度值大于等于127,则为1,否则为0
img[rows, cols] = 1
else:
img[rows, cols] = 0
train_set[i, rows * 28 + cols] = img[rows, cols]
train_flatten = np.transpose(train_set) # 转置像素
return train_flatten
def gettrainLabels(): # 解析训练标签(解析出来的标签和图片顺序是一一对应的)
f1 = open("C:\\Users\\84782\\Desktop\\Mnist\\train-labels.idx1-ubyte", 'rb')
buf1 = f1.read()
f1.close()
index = 0
magic, num = struct.unpack_from(">II", buf1, 0)
index += struct.calcsize('>II')
labs = []
labs = struct.unpack_from('>' + str(num) + 'B', buf1, index)
labs_change = np.zeros((10, train_num))
for i in range(0, 10): # 改变训练集标签,第一行非零数标签为0,0的标签为1;第二行不是1的数标签为0,1的标签为1,以此类推
for j in range(0, train_num):
if labs[j] == i:
labs_change[i, j] = 1
else:
labs_change[i, j] = 0
return labs_change, labs # 返回训练集标签
训练集最后的维度为:(784, 600)
训练集标签的维度为:(10, 600)
测试集最后的维度为:(784, 100)
测试集标签的维度为:(1, 100)
提取测试集像素也是一样的。
sigmoid函数
def sigmoid(z):
s = 1 / (1 + np.exp(-z))
return s
计算代价函数和求出w和b的偏导数
def propagate(w, b, X, Y):
A = sigmoid(np.dot(w.T, X) + b)
cost = (-1 / train_num) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A))) # 计算代价
dw = (1 / train_num) * np.dot(X, (A - Y).T)
db = (1 / train_num) * np.sum(A - Y)
# 创造一个字典,保存dw和db
grads = {
"dw": dw,
"db": db
}
return grads, cost
梯度下降,优化参数w和b
def optimize(w, b, X, Y, num_iterations, learning_rate):
costs = []
for i in range(num_iterations):
grads, cost = propagate(w, b, X, Y)
dw = grads["dw"]
db = grads["db"]
w = w - learning_rate * dw
b = b - learning_rate * db
if i % 100 == 0:
costs.append(cost)
if i % 100 == 0:
print("迭代的次数:%i,误差值: %f" % (i, cost))
return w, b
调用函数,生成十个分类器,然后开始训练和测试
# 0的分类器
print("\n开始训练0的分类器")
w0 = np.zeros((784, 1))
b0 = 0
w0, b0 = optimize(w0, b0, train_set, train_labc[0], num_iterations=500, learning_rate=1)
A0 = sigmoid(np.dot(w0.T, train_set) + b0)
fin_A[0] = A0
test_A0 = sigmoid(np.dot(w0.T, test_set) + b0)
test_A[0] = test_A0
# 1的分类器
print("\n开始训练1的分类器")
w1 = np.zeros((784, 1))
b1 = 0
w1, b1 = optimize(w1, b1, train_set, train_labc[1], num_iterations=500, learning_rate=1)
A1 = sigmoid(np.dot(w1.T, train_set) + b1)
fin_A[1] = A1
test_A1 = sigmoid(np.dot(w1.T, test_set) + b1)
test_A[1] = test_A1
# 2的分类器
print("\n开始训练2的分类器")
w2 = np.zeros((784, 1))
b2 = 0
w2, b2 = optimize(w2, b2, train_set, train_labc[2], num_iterations=500, learning_rate=1)
A2 = sigmoid(np.dot(w2.T, train_set) + b2)
fin_A[2] = A2
test_A2 = sigmoid(np.dot(w2.T, test_set) + b2)
test_A[2] = test_A2
# 3的分类器
print("\n开始训练3的分类器")
w3 = np.zeros((784, 1))
b3 = 0
w3, b3 = optimize(w3, b3, train_set, train_labc[3], num_iterations=500, learning_rate=1)
A3 = sigmoid(np.dot(w3.T, train_set) + b3)
fin_A[3] = A3
test_A3 = sigmoid(np.dot(w3.T, test_set) + b3)
test_A[3] = test_A3
# 4的分类器
print("\n开始训练4的分类器")
w4 = np.zeros((784, 1))
b4 = 0
w4, b4 = optimize(w4, b4, train_set, train_labc[4], num_iterations=500, learning_rate=1)
A4 = sigmoid(np.dot(w4.T, train_set) + b4)
fin_A[4] = A4
test_A4 = sigmoid(np.dot(w4.T, test_set) + b4)
test_A[4] = test_A4
# 5的分类器
print("\n开始训练5的分类器")
w5 = np.zeros((784, 1))
b5 = 0
w5, b5 = optimize(w5, b5, train_set, train_labc[5], num_iterations=500, learning_rate=1)
A5 = sigmoid(np.dot(w5.T, train_set) + b5)
fin_A[5] = A5
test_A5 = sigmoid(np.dot(w5.T, test_set) + b5)
test_A[5] = test_A5
# 6的分类器
print("\n开始训练6的分类器")
w6 = np.zeros((784, 1))
b6 = 0
w6, b6 = optimize(w6, b6, train_set, train_labc[6], num_iterations=500, learning_rate=1)
A6 = sigmoid(np.dot(w6.T, train_set) + b6)
fin_A[6] = A6
test_A6 = sigmoid(np.dot(w6.T, test_set) + b6)
test_A[6] = test_A6
# 7的分类器
print("\n开始训练7的分类器")
w7 = np.zeros((784, 1))
b7 = 0
w7, b7 = optimize(w7, b7, train_set, train_labc[7], num_iterations=500, learning_rate=1)
A7 = sigmoid(np.dot(w7.T, train_set) + b7)
fin_A[7] = A7
test_A7 = sigmoid(np.dot(w7.T, test_set) + b7)
test_A[7] = test_A7
# 8的分类器
print("\n开始训练8的分类器")
w8 = np.zeros((784, 1))
b8 = 0
w8, b8 = optimize(w8, b8, train_set, train_labc[8], num_iterations=500, learning_rate=1)
A8 = sigmoid(np.dot(w8.T, train_set) + b8)
fin_A[8] = A8
test_A8 = sigmoid(np.dot(w8.T, test_set) + b8)
test_A[8] = test_A8
# 9的分类器
print("\n开始训练9的分类器")
w9 = np.zeros((784, 1))
b9 = 0
w9, b9 = optimize(w9, b9, train_set, train_labc[4], num_iterations=2000, learning_rate=5)
A9 = sigmoid(np.dot(w9.T, train_set) + b9)
fin_A[9] = A9
test_A9 = sigmoid(np.dot(w9.T, test_set) + b9)
test_A[9] = test_A9
训练结果保存到一个10行600列的数组
测试结果保存到一个10行100列的数组
最后开始测试准确率
for i in range(train_num): # 训练集的准确率
trainnum_max = 0 # 更新num_max
train_max = 0
for j in range(10):
if fin_AT[i, j] >= train_max:
trainnum_max = j
train_max = fin_AT[i, j]
answer_train[0, i] = trainnum_max
if answer_train[0, i] == train_lab[i]:
right += 1
for i in range(test_num): # 测试集的准确率
testnum_max = 0
test_max = 0
for j in range(10):
if test_AT[i, j] >= test_max:
testnum_max = j
test_max = test_AT[i,j]
answer_test[0, i] =testnum_max
if answer_test[0, i] == test_lab[0, i]:
right_test += 1
最后的结果
600张训练集,100张测试集的结果
训练集准确率为:87.33333333333333%
测试集准确率为:79.0%