基于Numpy的手写数字识别神经网络(不用tensorflow等框架)

之前用tensorflow写了一遍手写数字识别,但部分函数都是调用的封装函数,总感觉没有摸清楚计算推导的原理,遂重新写了一遍。准确度和计算速度没有Tensorflow的高,但是应该是自身算法问题。就不深究啦,原理正确就行。说明只要数学原理正确,什么语言都是能实现的。纪念一下:

#实现手写数字识别
import numpy as np
import pickle
import gzip


class node:
    def __init__(self,layer,next_layer=None):
        self.layer = layer
        self.next_layer = next_layer
        self.value = np.zeros((self.layer,1)) #当前节点的值,如X1,y1
        if self.next_layer!=None:
            self.w = np.random.randn(self.next_layer,self.layer) #当前节点到下一节点的权值 randn为标准差为1的正态分布
            self.b = np.random.randn( self.next_layer,1)

class data:
    def __init__(self):
        self.inputData = None

    def loadData(self,mnist_url):
        f = gzip.open(str(mnist_url), 'rb')
        training_data, validation_data, test_data = pickle.load(f, encoding="latin1")
        f.close()

        training_inputs = [np.reshape(x, (784, 1)) for x in training_data[0]]  #(50000,784,1)
        training_results = [self.vectorized_result(y) for y in training_data[1]] #(50000,10,1)
        training_data = zip(training_inputs, training_results)

        # validation_inputs = [np.reshape(x, (784, 1)) for x in validation_data[0]]
        # validation_data = zip(validation_inputs, validation_data[1])
        #
        test_inputs = [np.reshape(x, (784, 1)) for x in test_data[0]]
        test_data = zip(test_inputs, test_data[1])
        return (training_inputs,training_results,test_data)


    def vectorized_result(self,j):
        e = np.zeros((10, 1))
        e[j] = 1.0
        return e

    def getInput(self):
        return self.inputData

class net:
    def __init__(self):
        self.inputLayer = node(784,30)
        self.hindLayer = node(30,10)
        self.outputLayer = node(10)
        self.learningRate = 0.01
        self.y_real = None

    def sigmoid(self,z):
        return  1.0/(1.0 + np.exp(-z))

    def softmax(self,y):
        sum = 0
        lenth = len(y)
        for i in range(lenth):
            #print(lenth,sum)
            sum += np.exp(y[i])

        for i in range(lenth):
            y [i] = np.exp(y[i])/sum
        return  y

    def feedforward(self, a):
        #计算隐藏层节点值
        z1 = np.dot(self.inputLayer.w,a)+self.inputLayer.b
        y1 = self.sigmoid(z1)

        # 计算输出层节点值
        z2 = np.dot(self.hindLayer.w, y1) + self.hindLayer.b
        y2 = self.sigmoid(z2)

        return y2

    def evaluate(self, test_data):
        test_results = [(np.argmax(self.feedforward(x)), y)
                                for (x, y) in test_data]

        return sum(int(x == y) for (x, y) in test_results)

    def train(self, training_inputs,training_results, epochs,test_data):
        #for (x,y) in training_data:

        training_inputs = list(training_inputs)
        training_results = list(training_results)
        self.y_real = training_results
        # 将训练数据集强转为list
        n = len(training_inputs)  #n=50000
        print(n)

        for j in range(epochs):
            self.forwardPropagation(training_inputs[j])

            self.backwardPropagation(training_results[j])
                # 调用梯度下降算法
            if j%100 ==0:
                self.printResult(j)
                if test_data:
                # 如果有测试数据集
                    test_data = list(test_data)
                    # 将测试数据集强转为list
                    n_test = len(test_data)
                    print("Epoch {} : {} / {}".format(j, self.evaluate(test_data), n_test));
                # j为迭代期序号
                # evaluate(test_data)为测试通过的数据个数
                # n_test为测试数据集的大小
                else:
                    print("Epoch {} complete".format(j))
    def forwardPropagation(self,inputData):
        self.inputLayer.value = inputData

        #计算隐藏层节点值
        z1 = np.dot(self.inputLayer.w,self.inputLayer.value)+self.inputLayer.b
        y1 = self.sigmoid(z1)
        self.hindLayer.value = y1

        # 计算输出层节点值
        z2 = np.dot(self.hindLayer.w, self.hindLayer.value) + self.hindLayer.b
        y2 = self.sigmoid(z2)
        self.outputLayer.value = y2


    def backwardPropagation(self,y2_real):
        #self.target = y2_real
        x1 = np.mat(self.inputLayer.value)
        y1 = np.mat(self.hindLayer.value)
        y2 = np.mat(self.outputLayer.value)
        w2 = np.mat(self.hindLayer.w)
        w1 = np.mat(self.inputLayer.w)
        b1 = np.mat(self.inputLayer.b)
        b2 = np.mat(self.hindLayer.b)
        self.y_real = np.mat(y2_real)

        #更新隐藏层权重值
        partial_1 = y2_real/y2-(1-y2_real)/(1-y2)
        partial_2 = np.multiply(y2,(1-y2))
        partial_3 = y1.transpose()
        delta_b2 =  - np.multiply(partial_1,partial_2)
        delta_w2 =  np.dot(delta_b2,partial_3)
        w2 -= self.learningRate * delta_w2
        b2 -= self.learningRate * delta_b2

        # 更新输入权重值
        partial_1 =[]
        for i in range(self.inputLayer.next_layer):
            z = y2_real/y2-(1-y2_real)/(1-y2)
            #z = np.multiply(y2_real-y2,y2)
            z = np.multiply(z, y2)
            z = np.multiply(z, 1-y2)
            z = np.multiply(z, w2[:,i])
            partial_1 = np.append(partial_1,np.sum(z))

        partial_1 = partial_1.reshape((30,1))
        partial_2 = np.multiply(partial_1,y1)
        partial_3 = x1.transpose()
        delta_b1 = -np.multiply(partial_2,1-y1)
        delta_w1 = np.dot(delta_b1,partial_3)
        b1 -= self.learningRate * delta_b1
        w1 -= self.learningRate * delta_w1
        # for layer in range(self.inputLayer.layer) :
        #     for next_layer in range(self.inputLayer.next_layer):
        #         for out_node in range(self.hindLayer.next_layer):
        #             w1[next_layer][layer] -=  self.learningRate *(-((y2_real[out_node]*(1-y2[out_node])
        #                                       +y2[out_node]*(1-y2_real[out_node]))*w2[out_node][next_layer]
        #                                         *y1[next_layer]*(1-y1[next_layer])*x1[layer]))


    def getloss(self,steps):
        if self.y_real.all() == None:
            return

        # 交叉熵损失函数

        y2 = self.outputLayer.value
        loss1 = np.multiply(self.y_real,np.log(y2))
        loss2 = np.multiply(1-self.y_real,np.log(1-y2))
        loss = -sum((loss1+loss2))
        loss = np.nan_to_num(loss)/10
        # for i in range(self.outputLayer.layer):
        #     loss += -((int(self.y_real[steps][i])*np.log(float(self.outputLayer.value[i])))
        #               + ((1-int(self.y_real[steps][i]))*np.log(1-float(self.outputLayer.value[i]))))


        return  loss


    def printResult(self,steps):
        print("after %d steps , the loss is %f" % (steps,self.getloss(steps)))



def main():
    m_net = net()
    m_data = data()
    training_inputs, training_results ,test_data= m_data.loadData('mnist.pkl.gz')
    m_net.train(training_inputs,training_results, 50000,test_data)


if __name__ == '__main__':
    main()

 

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较复杂的问题,我会尽力回答。首先,我们需要明确手写数字识别一个图像分类问题,卷积神经网络是目前最常用的解决方案之一。因此,我们需要设计一个卷积神经网络来对手写数字图片进行分类。 在Python中,我们可以使用NumPy和Pillow库来处理图像数据。而对于卷积神经网络的实现,我们可以使用Python中的原生代码来实现,而不是使用深度学习框架TensorFlow和Keras。 以下是一个简单手写数字识别卷积神经网络实现的示例代码: ```python import numpy as np from PIL import Image # 定义卷积层和池化层 class ConvLayer: def __init__(self, num_filters, filter_size): self.num_filters = num_filters self.filter_size = filter_size self.filters = np.random.randn(num_filters, filter_size, filter_size) / (filter_size ** 2) def iterate_regions(self, image): height, width = image.shape for y in range(height - self.filter_size + 1): for x in range(width - self.filter_size + 1): region = image[y:y+self.filter_size, x:x+self.filter_size] yield region, y, x def forward(self, input): self.last_input = input height, width = input.shape output = np.zeros((height - self.filter_size + 1, width - self.filter_size + 1, self.num_filters)) for region, y, x in self.iterate_regions(input): output[y, x] = np.sum(region * self.filters, axis=(1, 2)) return output class PoolLayer: def __init__(self, pool_size): self.pool_size = pool_size def iterate_regions(self, image): height, width, _ = image.shape new_height = height // self.pool_size new_width = width // self.pool_size for y in range(new_height): for x in range(new_width): region = image[(y*self.pool_size):(y*self.pool_size+self.pool_size), (x*self.pool_size):(x*self.pool_size+self.pool_size)] yield region, y, x def forward(self, input): self.last_input = input height, width, num_filters = input.shape output = np.zeros((height // self.pool_size, width // self.pool_size, num_filters)) for region, y, x in self.iterate_regions(input): output[y, x] = np.amax(region, axis=(0, 1)) return output # 定义全连接层和softmax层 class DenseLayer: def __init__(self, input_size, output_size): self.weights = np.random.randn(input_size, output_size) * 0.1 self.biases = np.zeros(output_size) def forward(self, input): self.last_input = input output = np.dot(input, self.weights) + self.biases return output class SoftmaxLayer: def __init__(self, input_size, output_size): self.weights = np.random.randn(input_size, output_size) * 0.1 self.biases = np.zeros(output_size) def forward(self, input): self.last_input = input exp_scores = np.exp(input) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) return probs # 定义神经网络结构 class NeuralNetwork: def __init__(self): self.conv_layer = ConvLayer(8, 3) self.pool_layer = PoolLayer(2) self.dense_layer = DenseLayer(13*13*8, 128) self.softmax_layer = SoftmaxLayer(128, 10) def forward(self, image): output = self.conv_layer.forward(image) output = self.pool_layer.forward(output) output = output.reshape(-1, 13*13*8) output = self.dense_layer.forward(output) output = self.softmax_layer.forward(output) return output # 加载手写数字图片 def load_image(filename): img = Image.open(filename).convert('L') img = img.resize((28, 28)) img_arr = np.array(img) img_arr = img_arr.reshape((28, 28, 1)) img_arr = img_arr / 255.0 return img_arr # 实例化神经网络对象 nn = NeuralNetwork() # 加载图片并进行预测 image = load_image('test.png') output = nn.forward(image) print(output) ``` 这段代码实现了一个简单手写数字识别卷积神经网络,包括卷积层、池化层、全连接层和softmax层。我们可以使用Pillow库来加载手写数字图片,然后将其输入到神经网络中进行预测。 由于这个神经网络比较简单,它的准确率可能不太高。如果你想要得到更好的结果,可以考虑增加网络的深度和复杂度,或者使用更先进的卷积神经网络架构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值