首页 > 代码库 > 简单的神经网络算法-手写数字识别

简单的神经网络算法-手写数字识别

本文通过BP神经网络实现一个简单的手写识别系统。

一、基础知识

1环境

python2.7

需要numpy等库

可利用sudo apt-get install python-安装

2神经网络原理

http://www.hankcs.com/ml/back-propagation-neural-network.html

讲的特别清楚,本实验过程中涉及矩阵运算都用numpy库的函数

3.js的基础知识

http://www.w3school.com.cn/tags/html_ref_canvas.asp

canvas的基础知识

http://blog.csdn.net/iamduoluo/article/details/7215639

xmlhttp的介绍

4.BaseHTTPServer库和numpy的使用

二、重要过程

1、如何将手写的图像转化为数据?

将画布分成网格,计算鼠标按下移动的路线经过的方格,例如将画布分为20*20格,则可以构建data[400]的数组,鼠标经过的data[i]=1,可以得到数据输入

drawGrid: function(ctx) {
        for (var x = this.PIXEL_WIDTH, y = this.PIXEL_WIDTH; x < this.CANVAS_WIDTH; x += this.PIXEL_WIDTH, y += this.PIXEL_WIDTH) {
            ctx.strokeStyle = this.BLUE;  //设置颜色
            ctx.beginPath();    
            ctx.moveTo(x, 0);   //把焦点移到(x,0)
            ctx.lineTo(x, this.CANVAS_WIDTH);   //画线(x,0)到(x,canvas_width)
            ctx.stroke();    //提交画线

            ctx.beginPath();
            ctx.moveTo(0, y);
            ctx.lineTo(this.CANVAS_WIDTH, y);
            ctx.stroke();
        }
    },

    onm ouseMove: function(e, ctx, canvas) {
        if (!canvas.isDrawing) {
            return;
        }
        this.fillSquare(ctx, e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);   //e.clientX是浏览器边缘与鼠标点的x距离,offsetleft是画布边与左侧浏览器边缘的距离
    },

    onm ouseDown: function(e, ctx, canvas) {
        canvas.isDrawing = true;
        this.fillSquare(ctx, e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop);
    },

    onm ouseUp: function(e) {
        canvas.isDrawing = false;
    },

    fillSquare: function(ctx, x, y) {
        var xPixel = Math.floor(x / this.PIXEL_WIDTH);   //就算坐标
        var yPixel = Math.floor(y / this.PIXEL_WIDTH);
        //存储手写输入数据
        this.data[((xPixel-1)  * this.TRANSLATED_WIDTH + yPixel)-1] = 1;

        ctx.fillStyle = ‘#ffffff‘;
        ctx.fillRect(xPixel * this.PIXEL_WIDTH, yPixel * this.PIXEL_WIDTH, this.PIXEL_WIDTH, this.PIXEL_WIDTH); //正方形填充颜色
    },

2、浏览器与客户端的交互

主要通过json 数据交互

sendData: function(json) {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open(‘POST‘, this.HOST + ":" + this.PORT, false);
        xmlHttp.onload = function() { this.receiveResponse(xmlHttp); }.bind(this);
        xmlHttp.onerror = function() { this.onError(xmlHttp) }.bind(this);
        var msg = JSON.stringify(json);   //序列化为json
        xmlHttp.setRequestHeader(‘Content-length‘, msg.length);   //参考给的链接最上
        xmlHttp.setRequestHeader("Connection", "close");
        xmlHttp.send(msg);
    }

服务器

class JSONHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """处理接收到的POST请求"""
    def do_POST(self):
        response_code = 200
        response = ""
        var_len = int(self.headers.get(‘Content-Length‘))
        content = self.rfile.read(var_len);
        payload = json.loads(content);

        # 如果是训练请求,训练然后保存训练完的神经网络
        if payload.get(‘train‘):
            #print payload[‘trainArray‘]
            nn.train(payload[‘trainArray‘],2)
            nn.save()
        # 如果是预测请求,返回预测值
        elif payload.get(‘predict‘):
            try:
                print nn.predict(data_matrix[0])
                response = {"type":"test", "result":str(nn.predict(payload[‘image‘]))}
            except:
                response_code = 500
        else:
            response_code = 400

        self.send_response(response_code)
        self.send_header("Content-type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        if response:
            self.wfile.write(json.dumps(response))
        return
3、神经网络的实现

参考500 lines or less

后向传播算法步骤

  • 随机初始化参数,对输入利用前向传播计算输出。

  • 对每个输出节点按照下式计算delta:技术分享

  • 对每个隐藏节点按照下式计算delta:技术分享

  • 计算梯度技术分享并更新权值参数和偏置参数:技术分享。这里的技术分享是学习率,影响训练速度。


                # 前向传播得到结果向量
                y1 = np.dot(np.mat(self.theta1), np.mat(data.y0).T)
                sum1 =  y1 + np.mat(self.input_layer_bias)
                y1 = self.sigmoid(sum1)

                y2 = np.dot(np.array(self.theta2), y1)
                y2 = np.add(y2, self.hidden_layer_bias)
                y2 = self.sigmoid(y2)

                # 后向传播得到误差向量
                actual_vals = [0] * 10
                actual_vals[data.label] = 1
                output_errors = np.mat(actual_vals).T - np.mat(y2)
                hidden_errors = np.multiply(np.dot(np.mat(self.theta2).T, output_errors), self.sigmoid_prime(sum1))  //multiply函数用法,可以简单看为对应相乘

                # 更新权重矩阵与偏置向量
                self.theta1 += self.LEARNING_RATE * np.dot(np.mat(hidden_errors), np.mat(data.y0))
                self.theta2 += self.LEARNING_RATE * np.dot(np.mat(output_errors), np.mat(y1).T)
                self.hidden_layer_bias += self.LEARNING_RATE * output_errors
                self.input_layer_bias += self.LEARNING_RATE * hidden_errors

先写这么多

神经网络中的实现采取了简化的方法,实验效果一般,不过也是一次有趣的实验,下次有待更新神经网络的另一种完全实现。

 

简单的神经网络算法-手写数字识别