利用Theano实现简单手写识别

学了一个星期的Theano,写篇博客mark一下了。+-_-+
首先说下Theano是什么,Theano 是Python一个深度学习框架,主要功能有编译函数,对函数求导,这里面最nb的地方莫过于对函数求导,直接导致不用再手写各种梯度下降算法了,像什么BP,RNN,LSTM神经网络都能很easy的搞定呐。
回到实验,以前用HOG特征训练精度能到94%的酱紫,这次直接将整张图片直接输入到网络中,精度大概能到97%的样子,如果fine tune的话 到99%应该是没有问题的。
说一下网络的构成吧,一个输入层X就是图片像素构成的向量784维(图片是28*28),中间加一个隐藏层H1维度是784*1000,最后放一层输出层是1000*10,综合起来一共要训练的参数为W1(784*1000),W2(1000*10),每层之间分别加一个偏执向量b1(1000*1),b2(10*1),最终一共需要训练的参数为784*1000+1000*10+1000+10 = 786010个,训练数据一共有60000个,妥妥的没问题。数据采用的是标准的mnit的数据集。代码可能就200行的样子,刚开始写Python写得有点烂啊!!

#读取数据图片和标签
#readData.py
import numpy as np
import struct
import matplotlib.pyplot as plt


def readIm():
    filename='data/train-images.idx3-ubyte'
    binfile = open(filename , 'rb')
    buf = binfile.read()
    index = 0
    magic, numImages , numRows , numColumns = struct.unpack_from('>IIII' , buf , index)

    x =[]
    index += struct.calcsize('>IIII')

    for i in xrange(numImages):
        im = struct.unpack_from('>784B' , buf, index)
        index += struct.calcsize('>784B')
        im=list(im)
        x.append(im)
        '''
        #预览图片
        io = im.reshape(28,28)
        fig = plt.figure()
        plt.imshow(io , cmap='gray')
        plt.show()
        '''
    x=np.array(x)
    return x


def read_labels():
    filename = 'data/train-labels.idx1-ubyte'
    binfi = open(filename , 'rb')
    buf = binfi.read()
    index = 0
    [magic , numlabels] = struct.unpack_from('>II', buf, index)
    index += struct.calcsize('>II')
    y = np.array([])
    while y.shape[0] < numlabels:
        l = struct.unpack_from('>B', buf, index)
        index += struct.calcsize('>B')
        im = np.array(l)
        if y.size==0:
            y = im
        else :
            y=np.vstack((y,im))
    ret = []
    for i in y:
        tmp = [0]*10
        tmp[i]=1
        ret.append(tmp)
    ret = np.array(ret)
    return ret
#网络构造,代码TM太简单,想想以前写的MATLAB,说多了都是泪啊!!!
#bp_net.py
import numpy as np
import theano
import theano.tensor as T

class BPnet:

    def __init__(self,x_size=784,y_size=10,hide=1000):
        self.INIT = 0.5
        W1 = np.random.uniform(-self.INIT, self.INIT , (x_size, hide))
        W2 = np.random.uniform(-self.INIT, self.INIT , (hide, y_size))
        b1 = np.random.uniform(-self.INIT, self.INIT , hide)
        b2 = np.random.uniform(-self.INIT, self.INIT , y_size)
        self.W1 = theano.shared(name='W1', value=W1.astype(theano.config.floatX))
        self.W2 = theano.shared(name='W2', value=W2.astype(theano.config.floatX))
        self.b1 = theano.shared(name='b1',value=b1.astype(theano.config.floatX))
        self.b2 = theano.shared(name='b2',value=b2.astype(theano.config.floatX))
        self.__build_bp()

    def __build_bp(self):

        x = T.vector('x')
        y = T.vector('y')
        h1 = T.nnet.sigmoid(T.dot(x,self.W1)+self.b1)
        o = T.nnet.sigmoid(T.dot(h1,self.W2)+self.b2)
        error=T.sum(-y * T.log(o) - (1.-y) * T.log(1-o))
        dw1,db1,dw2,db2 =      T.grad(error,self.W1),T.grad(error,self.b1),T.grad(error,self.W2),T.grad(error,self.b2)
        prediction = T.argmax(o, axis=0)
        self.predict = theano.function([x],prediction)
        self.get_grad = theano.function(inputs=[x,y],outputs=[o,error,dw1,db1,dw2,db2,prediction])
#保存数据和加载数据
#utils.py
import numpy as np

def save(outfile,value):

    np.savez(outfile, name=value)

def load(path,name):

    try:
        npzfile=np.load(path)
        value = npzfile[name]
        return value
    except:
        return None
#训练我网络代码,这段代码写得很烂,Theano里面有scan循环的函数,然后还没有看明白,所以就写了个loop,看着有点恶心,训练也是用的经典的最速梯度下降法+SGD(最优化没有白学!哈哈哈)
#train_net.py
import numpy as np
from  datetime import datetime
import bp_net as bp
import utils
import readData as  rd

x_train= utils.load('data/x.npz','name')
x_train=x_train/255.0
y_train= utils.load('data/y.npz','name')
if x_train == None :
    x_train = rd.readIm()
    utils.save("data/x.npz",x_train)
if  y_train == None:
    y_train = rd.read_labels()
    utils.save("data/y.npz",y_train)
EPOCH = 100
NUM = 60000
def train_sgd(model,rate,EPOCH,NUM):
    i = 0
    ep = 0
    while True:
        while i < NUM:
           dw1 = np.zeros([784,1000])
           dw2 = np.zeros([1000,10])
           db1 = np.zeros(1000)
           db2 = np.zeros(10)
           cnt = 0
           error = 0
           j = i
           ep+=1
           while j < EPOCH+i:
               ans = model.get_grad(x_train[j,:],y_train[j,:])
               dw1 += ans[2]
               db1 += ans[3]
               dw2 += ans[4]
               db2 += ans[5]
               if y_train[j, :][ans[6]] == 1:
                   cnt += 1
               j += 1
               error += ans[1]
           dw1 /= (1.00*EPOCH)
           dw2 /= (1.00*EPOCH)
           db1 /= (1.00*EPOCH)
           db2 /= (1.00*EPOCH)
           error /= (1.0*EPOCH)
           model.W1.set_value( model.W1.get_value()-dw1*rate)
           model.W2.set_value( model.W2.get_value()-dw2*rate)
           model.b1.set_value( model.b1.get_value()-db1*rate)
           model.b2.set_value( model.b2.get_value()-db2*rate)
           i += EPOCH
           now = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
           print("Epoch : %d .Cross error is %f .Accuracy is %f . at %s ." % (ep,error, cnt*1.00/(1.00*EPOCH),now))
        i = 0
model = bp.BPnet()
time_start = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
print("start training %s ." %(time_start))
train_sgd(model,0.2,EPOCH,NUM)

最后贴一下最终的实验结果吧:
这里写图片描述
一个batch 大概20s的样子,速度还是很快的。
想想快回家了,想想还是有点小激动的!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值