数据在官网,kaggle手写数字识别不需要爬墙,注册什么的看看知乎吧
1.利用神经网络,神经网络这个类是编写的,代码如下
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 31 16:46:44 2020
@author:
"""
import numpy
import pandas as pd
import scipy.special
import matplotlib.pyplot
from itertools import islice
#定义类神经网络
class neuralNetwork:
# 初始化,输入输入层、隐藏层、输出层、学习率
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
#让输入层隐藏层以及隐藏层到输出层的权重随机分别期望为0、方差为下一层节点数相关的正态分布中,抽样得到初始值
self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
#(self.hnodes, self.inodes))权重矩阵
self.lr = learningrate
#定义sigmoid函数
self.activation_function = lambda x: scipy.special.expit(x)
pass
# 训练神经网络
def train(self, inputs_list, targets_list):
# 把输入转换为二位数组,后面空着,为了计算所以转置
inputs = numpy.array(inputs_list, ndmin=2).T
targets = numpy.array(targets_list, ndmin=2).T
#隐藏层输入
hidden_inputs = numpy.dot(self.wih, inputs)
#隐藏层的输出
hidden_outputs = self.activation_function(hidden_inputs)
# 输出层的输入
final_inputs = numpy.dot(self.who, hidden_outputs)
# 输出层的输出
final_outputs = self.activation_function(final_inputs)
# 输出层的误差
output_errors = targets - final_outputs
# 隐藏层的误差,对应公式
hidden_errors = numpy.dot(self.who.T, output_errors)
# 更新隐藏层和输出层的权重
self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
# 更新隐藏层和输入层的权重
self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))
pass
#得到最终的结果
def query(self, inputs_list):
#输入转化为二维数组
inputs = numpy.array(inputs_list, ndmin=2).T
#隐藏层输入
hidden_inputs = numpy.dot(self.wih, inputs)
#隐藏层输出
hidden_outputs = self.activation_function(hidden_inputs)
# 输出层输入
final_inputs = numpy.dot(self.who, hidden_outputs)
# 输出层输出
final_outputs = self.activation_function(final_inputs)
return final_outputs
input_nodes = 784#28*28的图像
hidden_nodes = 200
output_nodes = 10#输出的是0-9的一个概率结果
learning_rate = 0.1
n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)
# 读入csv文件
training_data_file = open("train.csv", 'r')
for line in islice(training_data_file, 0, None):
training_data_list =training_data_file.readlines()
training_data_file.close()
# 训练次数
epochs = 5
for e in range(epochs):
# 遍历训练样本
for record in training_data_list:
# 用,把读入的分开
all_values = record.split(',')
# 把图像的0-255归一化
inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# create the target output values (all 0.01, except the desired label which is 0.99)
targets = numpy.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99#all_values[0]也就是第一个标签数字,目标为概率0.99
n.train(inputs, targets)#进行训练
pass
pass
# 读入测试文件
test_data_file = open("test.csv", 'r')
for line in islice(test_data_file, 0, None):
test_data_list=test_data_file.readlines()
test_data_file.close()
print(len(test_data_list))
#测试神经网络
# scorecard看模型表现
result = []
#遍历测试集
for record in test_data_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values) / 255.0 * 0.99) + 0.01
# 得到输出的结果
outputs = n.query(inputs)
# 将输出最大的作为输出的结果,argmax输出索引
label= numpy.argmax(outputs)
result.append(label)
image_id = pd.Series(range(1,len(result)+1))
result_2 = pd.DataFrame({'ImageID': image_id,'Label':result})
# 保存为CSV文件
result_2.to_csv('result_submit.csv',index = False)
print('Done')
我拿到官网提交的结果,准确率大概97.5%还可以
2.利用keras创建一个卷积神经网络
没有进行多次试验取最优里,只是为了得到结果直接设置的参数,因此后期还需要再调一调
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
import pandas as pd
import numpy as np
from keras import backend
backend.set_image_data_format('channels_first')
batch_size = 128
num_classes = 10
epochs = 12
# input image dimensions
img_rows, img_cols = 28, 28
# the data, shuffled and split between train and test sets
(x_train1, y_train1), (x_test, y_test) = mnist.load_data()
data_train = pd.read_csv("train.csv")
data1 = pd.DataFrame(data_train)
data1 = np.array(data1)
x_train=data1[:,1:]
y_train=data1[:,0]
data_test = pd.read_csv("test.csv")
data2 = pd.DataFrame(data_test)
data2 = np.array(data2)
x_test=data2
#y_test=y_test[0:10]
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
#y_test = keras.utils.np_utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(1, 28, 28), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=keras.metrics.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
verbose=1)
#这里可以设置一个交叉验证集,我打算再改改
result1 = model.predict(x_test)
result=result1.argmax(axis=1)
image_id = pd.Series(range(1,len(result)+1))
result_2 = pd.DataFrame({'ImageID': image_id,'Label':result})
# 保存为CSV文件
result_2.to_csv('result_submit3.csv',index = False)
print('Done')
再官网提交结果后,跑出来的结果为98%多一点,因此还有很多需要改进的地方
这里参考了:kagge手写数字识别手把手入门
它的代码是旧版的,自己进行了一些更改,加了一些卷积层,大概思路差不多吧,也可以利用keras里面的minist的手写数字数字识别那个库,跑一跑代码,都是学习嘛
3.SimpleConvNet
写的卷积神经网络的代码,也可以用,但自己用的不好,不知道哪里出了问题,还打算改一改
import pandas as pd
import math
import pickle
import numpy as np
from collections import OrderedDict
#三维矩阵转换为二维提高效率
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_data.shape
out_h = (H + 2 * pad - filter_h) // stride + 1
out_w = (W + 2 * pad - filter_w) // stride + 1
img = np.pad(input_data, [(0, 0), (0, 0), (pad, pad), (pad, pad)], 'constant')
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))
for y in range(filter_h):
y_max = y + stride * out_h
for x in range(filter_w):
x_max = x + stride * out_w
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N * out_h * out_w, -1)
return col
#im2col的逆处理
def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):
N, C, H, W = input_shape
out_h = (H + 2 * pad - filter_h) // stride + 1
out_w = (W + 2 * pad - filter_w) // stride + 1
col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)
img = np.zeros((N, C, H + 2 * pad + stride - 1, W + 2 * pad + stride - 1))
for y in range(filter_h):
y_max = y + stride * out_h
for x in range(filter_w):
x_max = x + stride * out_w
img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]
return img[:, :, pad:H + pad, pad:W + pad]
#定义卷积层的正向传播运算(forward)和反向传播运算backward
class Convolution:
def __init__(self, W, b, stride=1, pad=0):
self.W = W
self.b = b
self.stride = stride
self.pad = pad
self.x = None
self.col = None
self.col_W = None
self.dW = None
self.db = None
def forward(self, x):
FN, C, FH, FW = self.W.shape
N, C, H, W = x.shape
out_h = 1 + int((H + 2 * self.pad - FH) / self.stride)
out_w = 1 + int((W + 2 * self.pad - FW) / self.stride)
col = im2col(x, FH, FW, self.stride, self.pad)
col_W = self.W.reshape(FN, -1).T
out = np.dot(col, col_W) + self.b
out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)
self.x = x
self.col = col
self.col_W = col_W
return out
def backward(self, dout):
FN, C, FH, FW = self.W.shape
dout = dout.transpose(0, 2, 3, 1).reshape(-1, FN)
self.db = np.sum(dout, axis=0)
self.dW = np.dot(self.col.T, dout)
self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)
dcol = np.dot(dout, self.col_W.T)
dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)
return dx
#定义池化层
class Pooling:
def __init__(self, pool_h, pool_w, stride=1, pad=0):
self.pool_h = pool_h
self.pool_w = pool_w
self.stride = stride
self.pad = pad
self.x = None
self.arg_max = None
def forward(self, x):
N, C, H, W = x.shape
out_h = int(1 + (H - self.pool_h) / self.stride)
out_w = int(1 + (W - self.pool_w) / self.stride)
col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
col = col.reshape(-1, self.pool_h * self.pool_w)
arg_max = np.argmax(col, axis=1)
out = np.max(col, axis=1)
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
self.x = x
self.arg_max = arg_max
return out
def backward(self, dout):
dout = dout.transpose(0, 2, 3, 1)
pool_size = self.pool_h * self.pool_w
dmax = np.zeros((dout.size, pool_size))
dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
dmax = dmax.reshape(dout.shape + (pool_size,))
dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)
return dx
#全连接层构建
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.original_x_shape = None
self.dW = None
self.db = None
def forward(self, x):
self.original_x_shape = x.shape
x = x.reshape(x.shape[0], -1)
self.x = x
out = np.dot(self.x, self.W) + self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
dx = dx.reshape(*self.original_x_shape)
return dx
#激活函数relu和softmax
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
def softmax(x):
if x.ndim == 2:
x = x.T
x = x - np.max(x, axis=0)
y = np.exp(x) / np.sum(np.exp(x), axis=0)
return y.T
x = x - np.max(x)
return np.exp(x) / np.sum(np.exp(x))
#优化器
class Adam:
def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
self.lr = lr
self.beta1 = beta1
self.beta2 = beta2
self.iter = 0
self.m = None
self.v = None
def update(self, params, grads):
if self.m is None:
self.m, self.v = {}, {}
for key, val in params.items():
self.m[key] = np.zeros_like(val)
self.v[key] = np.zeros_like(val)
self.iter += 1
lr_t = self.lr * np.sqrt(1.0 - self.beta2 ** self.iter) / (1.0 - self.beta1 ** self.iter)
for key in params.keys():
self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
self.v[key] += (1 - self.beta2) * (grads[key] ** 2 - self.v[key])
params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
#交叉熵损失函数
def cross_entropy_error(y, t):
if y.ndim == 1:
t = t.reshape(1, t.size)
y = y.reshape(1, y.size)
if t.size == y.size:
t = t.argmax(axis=1)
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size
#损失函数的反向传播函数
class SoftmaxWithLoss:
def __init__(self):
self.loss = None
self.y = None
self.t = None
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
def backward(self, dout=1):
batch_size = self.t.shape[0]
if self.t.size == self.y.size:
dx = (self.y - self.t) / batch_size
else:
dx = self.y.copy()
dx[np.arange(batch_size), self.t] -= 1
dx = dx / batch_size
return dx
#搭建卷积神经网络的模型,包括预测层、损失据算、准确计算、梯度计算、保存权重、读取权重等功能
class SimpleConvNet:
def __init__(self, input_dim=(1, 28, 28),
conv_param={'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
hidden_size=100, output_size=10, weight_init_std=0.01):
filter_num = conv_param['filter_num']
filter_size = conv_param['filter_size']
filter_pad = conv_param['pad']
filter_stride = conv_param['stride']
input_size = input_dim[1]
conv_output_size = (input_size - filter_size + 2 * filter_pad) / filter_stride + 1
pool_output_size = int(filter_num * (conv_output_size / 2) * (conv_output_size / 2))
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(filter_num,
input_dim[0], filter_size, filter_size)
self.params['b1'] = np.zeros(filter_num)
self.params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
self.params['b2'] = np.zeros(hidden_size)
self.params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b3'] = np.zeros(output_size)
self.layers = OrderedDict()
self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'],
conv_param['stride'], conv_param['pad'])
self.layers['Relu1'] = Relu()
self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2'])
self.layers['Relu2'] = Relu()
self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3'])
self.last_layer = SoftmaxWithLoss()
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
def loss(self, x, t):
y = self.predict(x)
return self.last_layer.forward(y, t)
def accuracy(self, x, t, batch_size=100):
if t.ndim != 1: t = np.argmax(t, axis=1)
acc = 0.0
for i in range(int(x.shape[0] / batch_size)):
tx = x[i * batch_size:(i + 1) * batch_size]
tt = t[i * batch_size:(i + 1) * batch_size]
y = self.predict(tx)
y = np.argmax(y, axis=1)
acc += np.sum(y == tt)
return acc / x.shape[0]
def gradient(self, x, t):
self.loss(x, t)
dout = 1
dout = self.last_layer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
grads = {}
grads['W1'], grads['b1'] = self.layers['Conv1'].dW, self.layers['Conv1'].db
grads['W2'], grads['b2'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
grads['W3'], grads['b3'] = self.layers['Affine2'].dW, self.layers['Affine2'].db
return grads
def save_params(self, file_name='params.pkl'):
params = {}
for key, val in self.params.items():
params[key] = val
with open(file_name, 'wb') as f:
pickle.dump(params, f)
def load_params(self, file_name='params.pkl'):
with open(file_name, 'rb') as f:
params = pickle.load(f)
for key, val in params.items():
self.params[key] = val
for i, key in enumerate(['Conv1', 'Affine1', 'Affine2']):
self.layers[key].W = self.params['W' + str(i + 1)]
self.layers[key].b = self.params['b' + str(i + 1)]
参考https://github.com/Bingjie-Du/SimpleConvNet/blob/master/SimpleConvNet.ipynb