悟会 while (i++);
主页   |  列表   |  留言   |  关于   |  收藏
当前时间:2018-01-20 05:05:11

上次,我用tnsorflow展示了一两层神经网络,实现8->256的译码功能.

今天,我们继续前行,捣鼓一个可实用化的东东:手写文本识别.

手写识别作为MNIST界的Hello, world,不搞真是说不过去啊.


本示例中共写了两个不同的神经网络,一个是包含两个隐藏层的传统bp网络,一个是包含两层卷积和池化层的cnn网络,用于展示不同网络模型的训练速度和拟合效果.两个网络均能实现图片到字母的转换,bp网络最终准确率在90%,而cnn则轻松到了99%.


手里没有训练图集,本想从网上搞搞,然于我天朝网络受限,从MNIST下东西,可真是难于上青天.于是只好自写了一个文本图片数据生成库,虽不能实用,使用于验证模型的有效性还是足够的.


网络相关的代码(net.py):

#! usr/bin/python #coding=utf-8

import tensorflow as tf
import numpy as np
import random as rnd

#引入自写模块
import fontimg

# 获取数据集(直接调用自写的fontimg模块生成)
# 随机生成26个大写字母的24x24图片,图片除写有字母外,还有随机的噪点以及-60~60度的旋转
# [24,24]的图片点阵数据被转化成归一化后的一维[24x24]灰度数据
def next_batch(bs, tflg = True):
    return fontimg.make_datas(bs, tflg)

# 将标签/结果转化成数值
def result2dec(rs):
    return np.argmax(rs) #argmax就是返回向量中值最大的维数值
    
# 验证网络准确率
def do_test(sess, yo_opt, bs):
    #获取验证集
    bx, by = next_batch(bs, True)
    #进行网络运算 
    yo = sess.run(yo_opt, feed_dict={x: bx, keep_prob : 1.0})
    
    scnt = 0.0
    #对比运算结果和标签,计算准确率
    for i in range(bs):
        if result2dec(yo[i]) == result2dec(by[i]):
            scnt = scnt + 1.0
            
    return scnt * 100.0 / bs  

#添加一个网络层
def add_layer(x, input_size, output_size, afun = None):
    # 随机化隐藏层权重
    w = tf.Variable(tf.random_normal([input_size, output_size]))
    # 偏置设置为0
    b = tf.Variable(tf.zeros([output_size]), "float")
    # 设置激活函数
    if (afun != None):
        y = afun(tf.matmul(x, w) + b)
    else :
        y = tf.matul(x, w) + b
        
    return y

#普通bp网络,包含2个隐藏层(只要你开心,1个隐藏层不算多,3个隐藏层也不算少,多多少少其实没什么l用)
def make_bp_net(x):
    #首个隐藏层,16x16个节点 
    h0 = add_layer(x, 24 * 24, 16 * 16, tf.nn.sigmoid)
    #第二个隐藏层,8x8个节点
    h1 = add_layer(h0, 16 * 16, 8 * 8, tf.nn.sigmoid)
    
    #dropout层, 实测没什么l用,所以注掉了
    keep_prob = tf.placeholder("float")
    #dh1 = tf.nn.dropout(h1, keep_prob)    
    dh1 = h1
    
    #输出层,26维向量
    y = add_layer(dh1, 8 * 8, 26, tf.nn.softmax)

    return y, keep_prob


#设置权重
def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

#设置偏置
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

#卷积运算,输出图片大小在输入相同
def conv2d(x, w):
    return tf.nn.conv2d(x, w, strides=[1, 1, 1, 1], padding='SAME')

#池化运算,输出图片大小高宽各减半
def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')    
    
#卷积网络(照虎画猫而来,不要问我为什么,其实我什么也不知道)
def make_cnn_net(x):
    #将一维图片数据转化为2维
    x2d = tf.reshape(x, [-1, 24, 24, 1])
    
    #第一个卷积层(5x5过滤器,输出16个特征,只要你开心,160个也可以)
    w_c1 = weight_variable([5, 5, 1, 16])
    b_c1 = bias_variable([16])
    #这里使用relu
    h_c1 = tf.nn.relu(conv2d(x2d, w_c1) + b_c1)
    #池化
    h_p1 = max_pool_2x2(h_c1)
    
    #第二个卷积层(6x6过滤器,只要你开心,4x4,5x5都可以,这次我们输出32个特征)
    w_c2 = weight_variable([6, 6, 16, 32])
    b_c2 = bias_variable([32])
    h_c2 = tf.nn.relu(conv2d(h_p1, w_c2) + b_c2)
    h_p2 = max_pool_2x2(h_c2)

    #全连接层(两度池化后,图片从24x24 => 12x12 => 6x6, 每个图片32个特征)
    #该层我们设计512个节点(只要你开心,513也没问题,真的) 
    w_fc1 = weight_variable([6 * 6 * 32, 512])
    b_fc1 = bias_variable([512])

    #将池化后的数据转成1维,好做全连接
    h_p2_flat = tf.reshape(h_p2, [-1, 6 * 6 * 32])
    #激活函数,也可以使用sigmoid,实测效果差不多
    h_fc1 = tf.nn.relu(tf.matmul(h_p2_flat, w_fc1) + b_fc1)  
    
    #在输出层之前,我们先做个dropout,传说中能够防止过拟合(实测没有多少l用)
    keep_prob = tf.placeholder("float")
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
    #h_fc1_drop = h_fc1         
    
    #输出层,512到26的全连接
    w_fc2 = weight_variable([512, 26])
    b_fc2 = bias_variable([26])
    y = tf.nn.softmax(tf.matmul(h_fc1_drop, w_fc2) + b_fc2)
    
    return y, keep_prob    

#我们开始创建网络,输入为图片数据,输出为图片分类,用传统bp还是cnn,可自选
#设置网络模式
#net = 'bp'      #这个网络农村长大的,发育不良,准确率大概大80-90%,训练速度慢
net = 'cnn'     #这个网络高大上,训练神速,准确率高,直达99%以上
    
#先来搞输入层,24x24图片(已转化成灰度一维数组)    
x = tf.placeholder("float", [None, 24 * 24])

#再依你所选,我们创建对应网络
if 'bp' == net:
    #bp网络
    y, keep_prob = make_bp_net(x)
else :
    #或者cnn网络
    y, keep_prob = make_cnn_net(x)

#最后弄loss层
# 标签占位符
y_ = tf.placeholder("float", [None, 26])
# 最小化交叉熵
loss = -tf.reduce_sum(y_* tf.log(y))
# 不同网络不同训练方法
if 'bp' == net:
    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
else :  #也可以使用GradientDescentOptimizer,注意步进要调小
    train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
    

# 在运算之前,先要初始化所有tf变量
init = tf.initialize_all_variables()
# 创建tf会话,并执行init操作
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
sess.run(init)

print "%s net training..." % net
# 启动网络训练(运算量稍大,整个过程可能需要数分钟,耐心等待)
eflg = False
for i in range(1000):
    #获取训练数据,一次获取100条
    bx, by = next_batch(100)
    #将数据feed到网络中,执行训练操作
    sess.run(train_step, feed_dict={x: bx, y_: by, keep_prob : 0.5})
    #每100轮训练,测试一下准确率
    if i > 0 and i % 100 == 0:
        sr = do_test(sess, y, 100)
        print i, ' \t: ', sr
        if (sr > 99.0): eflg = True
    
    #准确度达标,提前退出训练    
    if eflg : break

    
# 我们再测试一下准确率
print '###last rate \t:', do_test(sess, y, 1000)

# 最后,我们用网络来识别一下字符串,别捣鼓了半天,什么用都木体现
chs = [chr(i) for i in range(65, 91)] #大写字母表
# 按指定字串生成数据(注意这能只能是大写字母)
text = 'TENSORFLOW'
ims, lables = fontimg.make_string_datas(text)
# 让网络执行y运算,将图片转化为文字
letters = sess.run(y, feed_dict={x: ims, keep_prob : 1.0})
# 显示识别结果(编号 : 识别值 - 真实值 - 标签值)
for i in range(len(text)):
    print "[%.2d] : " % (i + 1), chs[result2dec(letters[i])], '-', text[i], '-', chs[result2dec(lables[i])]

#关闭会话,回收资源,要养成好习惯噢!
sess.close()


图片生存器代码(fontimg.py):

#! usr/bin/python #coding=utf-8

import PIL.Image as Image
import PIL.ImageDraw as ImageDraw
import PIL.ImageFont as ImageFont
import PIL.ImageFilter as ImageFilter
import random as rnd

# 图片数据生成程序

class FontImg(object):
    def __init__(self, img_size, fnt_size, fnt_file = ''):
        self.img_size = img_size
        self.fnt_size = fnt_size
        if '' == fnt_file : fnt_file = './font.otf'
        self.font = ImageFont.truetype(fnt_file, fnt_size)
        
    #创建一个字符图片
    def create_img(self, ch, bg_color, fnt_color):
        img = Image.new("RGB",[self.img_size, self.img_size], bg_color)
        dopt = ImageDraw.Draw(img)
        
        dopt.rectangle([0, 0, self.img_size - 1, self.img_size - 1], fill = bg_color)
        loc = dopt.textsize(ch, font = self.font)
        xp = (self.img_size - loc[0]) / 2
        yp = (self.img_size - loc[1]) / 2 - 2
        dopt.text([xp, yp], ch, fill = fnt_color, font = self.font)
        
        return img
    
    #为图片添加随机噪点    
    def noise_img(self, img, dots, dot_color, dopt):
        for i in range(dots):
            x = rnd.randint(0, self.img_size - 1)
            y = rnd.randint(0, self.img_size - 1)
            dopt.point([(x, y)], dot_color)
    
    #创建一个图片,并对其进行随机旋转及添加噪点
    def make_img(self, ch, dflg = False):
        img = self.create_img(ch, 'black', 'white')
        
        if dflg:
            #随机旋转-60~60度
            if (rnd.randint(0, 100) > 30):
                img = img.rotate(rnd.randint(-60, 60))
            
            #随机噪点    
            dopt = ImageDraw.Draw(img)
            self.noise_img(img, rnd.randint(0, self.img_size * self.img_size / 6), 'white', dopt)  
        
        return img
    
    #将图片数据转化成归一化后的灰度一维数据    
    def make_img_data(self, data, ch, sflg):
        img = self.make_img(ch, sflg)
        ps = img.convert('L').load()
        
        for y in range(self.img_size):
            for x in range(self.img_size):
                   data[y * self.img_size + x] = float(ps[x, y]) / 255.0

    #随机生成图片数据,bs指定图片个数
    def make_data(self, bs, sflg = False, string = ''):
        chs = [chr(i) for i in range(65, 91)]        
        isize = self.img_size * self.img_size
        
        if (string != ''):  #指定字符串的转换
            bs = len(string)
            rflg = False
        else :
            rflg = True  
        
        x = [[0.0 for i in range(isize)] for i in range(bs)]
        y = [[0.0 for i in range(len(chs))] for i in range(bs)]
        
        for b in range(bs):
            if rflg :
                cindx = rnd.randint(0, len(chs) - 1)
                ch = chs[cindx]
            else :
                ch = string[b]
                cindx = ord(ch) - ord('A')
                if (cindx < 0 or cindx > 25) :
                    cindx = 0
                    ch = 'A'
                    #print 'error!'
            y[b][cindx] = 1.0
            self.make_img_data(x[b], ch, sflg)
            
        return x, y    

#随机生成图片数据
def make_datas(bs, tflg = False):
    fm = FontImg(24, 20)
    
    return fm.make_data(bs, tflg)

#指定生成图片数据
def make_string_datas(chs):
    fm = FontImg(24, 20) 
    
    return fm.make_data(0, False, chs)      

if __name__ == '__main__':
    fm = FontImg(24, 20)
    im = fm.make_img('B', True)
    im.save('a.bmp')
    
    #x, y = make_datas(1)
    x, y = make_string_datas('ABC')
    print x
    print y


2017-10-23   |  人工智能   |  赞(0)   |  评论(0)   |  阅读全文(117)

弃caffe和c++,顺利转向tensorflow和python的怀抱,先把神经网络的Hello, word搞起!


#! usr/bin/python #coding=utf-8

import tensorflow as tf
import numpy as np
import random as rnd

# 本示例使用一个两层神经网络,训练后可实现8位二进制数到10进制的转换
# 输入: 8维向量,用于表示二进数对应的8个bit位
# 输出: 256维向量,二进数的十进制值为n,向量的第n维值为1.0,其于所有维的值为0.0
# 显然,这是一个标准的softmax回归模型
# 实际上,使用单层网络实际目标不是难事,本示例使用两层网络,仅仅只是为了演示.

# @@首先,我们先写几个函数,用于自动生成训练和测试数据
# 数据产生函数,用于生成训练数据(参数bs指定生成数据条数)
def next_batch(bs):
    #输入为一个8维向量,每个维度表示二进制数对应位的值
    xs = [[0.0 for i in range(8)] for j in range(bs)]
    #标签为一个256维向量,若二进制输入对应的十进制数为n时,其对应维的值为1.0,其余维值均为0
    ys = [[0.0 for i in range(256)] for j in range(bs)]
    
    #随机生成数据
    for j in range(bs):
        b = 0
        for i in range(8):  #随机生成二进制数据
            xs[j][i] = rnd.choice([0.0, 1.0])
            if (xs[j][i] > 0.5):
                b = b * 2 + 1
        #设置对应的标签值        
        ys[j][b % 256] = 1.0        

    #同时返回数据及对应标签
    return xs, ys

# 将标签/结果转化成数值
def result2dec(rs):
    return np.argmax(rs) #argmax就是返回向量中值最大的维数值
    
# 验证网络准确率
def do_test(sess, yo_opt, bs):
    #获取验证集
    bx, by = next_batch(bs)
    #进行网络运算 
    yo = sess.run(yo_opt, feed_dict={x: bx})
    
    scnt = 0.0
    #对比运算结果和标签,计算准确率
    for i in range(bs):
        if result2dec(yo[i]) == result2dec(by[i]):
            scnt = scnt + 1.0
            
    return scnt * 100.0 / bs        
    
# @@其次,我们开始构架网络

#step1: 构造输入层,这里使用占位符,用于训练过程动态输入数据
x = tf.placeholder("float", [None, 8])

#step2: 构造隐藏层,8个结点,与输入层全连接
# 随机化隐藏层权重
wh = tf.Variable(tf.random_normal([8, 8]))
# 偏置设置为0
bh = tf.Variable(tf.zeros([8]), "float")
# 隐藏层输出,激活函数选择了sigmoid
oh = tf.nn.sigmoid(tf.matmul(x, wh) + bh)

#step3: 构造输出层,256个节点,与隐藏层全连接
# 随机化输出层权重
wo = tf.Variable(tf.random_normal([8, 256]))
# 偏置设置为0
bo = tf.Variable(tf.zeros([256]), "float")
# 输出,激活函数当然是softmax
y = tf.nn.softmax(tf.matmul(oh, wo) + bo)

#step4: 构架loss层
# 标签占位符,用于动态输入标签数据到网络
y_ = tf.placeholder("float", [None, 256])
# 计算交叉熵(别问为什么,我只是搬运工,y_, y不要对调噢)
loss = -tf.reduce_sum(y_* tf.log(y))
# 也可以用方差做为损失函数玩玩,效果(收敛速度)可能要差点
#loss = tf.reduce_sum(tf.square(y - y_))
# 训练方向为使交叉熵(loss)最小
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)

# 至此,神经网络已经搭建完毕,是时候启动运算了

# 在运算之前,先要初始化所有tf变量
init = tf.initialize_all_variables()
# 创建tf会话,并执行init操作
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
sess.run(init)

# @@来吧,我们可对网络进行训练了
eflg = False
for i in range(50000):
    #获取训练数据,一次获取100条
    bx, by = next_batch(100)
    #将数据feed到网络中,运算吧,tf君!
    sess.run(train_step, feed_dict={x: bx, y_: by})
    #每100轮训练,测试一下准确率
    if i > 0 and i % 100 == 0:
        sr = do_test(sess, y, 100)
        print i, ' \t: ', sr
        if (sr > 99.0): eflg = True
    
    #准确度达标,退出训练    
    if eflg : break

    
# @@最后,我们再测试一下准确率
print '###last rate \t:', do_test(sess, y, 10000)

# 关闭会话,回收资源
sess.close()


# @@好吧,程序写完了,运行之,你可能得到这样的结果:
100      :  51.0
200      :  55.0
300      :  84.0
400      :  83.0
500      :  80.0
600      :  95.0
700      :  98.0
800      :  91.0
900      :  93.0
1000      :  90.0
1100      :  95.0
1200      :  96.0
1300      :  96.0
1400      :  96.0
1500      :  95.0
1600      :  97.0
1700      :  95.0
1800      :  98.0
1900      :  97.0
2000      :  99.0
2100      :  100.0
###last rate     : 99.29

# @@恩恩,随着训练次数的增加,准确率稳步提升,最后训练出的模型大概有99%的准确率.
2017-10-20   |  人工智能   |  赞(0)   |  评论(0)   |  阅读全文(202)

什么是watchpoint

watchpoint,顾名思义,其一般用来观察某个变量/内存地址的状态(也可以是表达式),如可以监控该变量/内存值是否被程序读/写情况。在我们跟踪一些变量被意外改写的问题(如越界)时,可能有奇效....

2016-05-20   |  C语言编程   |  赞(11)   |  评论(0)   |  阅读全文(305)

google被墙,一些专业资料度娘查起来又经常无力,肿么办,肿么办?两步搞定:

step 1 修改/etc/hosts,加入如下内容:

#gle.com.hk
220.255.2.153   www.google.com.hk
220.255.2.153   accounts.google.com.hk
220.255.2.153   clients1.google.com.hk
220.255.2.153   desktop.google.com.hk
220.255.2.153   encrypted.google.com.hk
220.255.2.153   gxc.google.com.hk
220.255.2.153   video.google.com.hk
220.255.2.153   id.google.com.hk
220.255.2.153   mobile.google.com.hk
220.255.2.153   picasaweb.google.com.hk


step 2 打开浏览器,访问https://www.google.com.hk/

是不是很神奇,又可以愉快地查资料了。


以上方法在ubuntu+firefox上已亲测可用,注意url开头一定是https噢。

windows下方法类似,修改hosts内容就可。

2016-04-26   |  Linux系统   |  赞(0)   |  评论(0)   |  阅读全文(352)

上周对十一月份的代码评审情况进行了一次审查,发现一个有趣的问题:某两个部门有不少人不会用或者是不喜欢用我们的代码评审系统,原因也很简单:不好用!结果也很清晰,这两个部门的代码评审数据非常惨淡,在六个部门中垫底.既然有其他部门做得更好,而且数据差距比较大,首先想到的是态度问题,当场对落后部门的负责人进行了批评并做了绩效处罚的决定....

2015-12-07   |  工作总结   |  赞(0)   |  评论(0)   |  阅读全文(359)

函数中随处return,是造成我们资源泄露和程序死锁的主要根源。很多同志写过类似的代码,函数中创建了和引用了多个资源,中间使用的过程中出错了,程序return,经典的代码是这样的:

void fun()
 {
     Lock(mutex)
    mem = malloc(size);
    if (null == mem)
     {
         return; //死锁
    }
    fh = fopen(“test.txt”);
    if (fh)
     {
         return; //死锁+内存泄露
    }
    if (fwrite(“abc”, fh) < 0)
     {
         return; //死锁+内存泄露+句柄泄露
    }
    fclose(fh);
     free(mem);
     Unlock(mtex)
 }

...

2015-12-03   |  C语言编程   |  赞(0)   |  评论(0)   |  阅读全文(901)

这几天原本可得的一点清静,被几个无聊的软件问题无端打扰了.我们几个计划这个月底要了掉的项目,出了一些岔子,设备测试或者老化运行期间,出了无故重启或者功能异常.项目组的人自己捣鼓了几天,没什么有进展,来我这求方案,而我能够得到的信息,却只是最后设备不如预期地工作了,其他与之相关的线索,要嘛嘛没有.

这样的情景,在我并不漫长的工作生涯中,已不知多少次重演.感谢我们那些懒惰而又恐慌程序员,这些年把我训练成了处理这些无头公案的专家....

2015-11-23   |  工作总结   |  赞(0)   |  评论(0)   |  阅读全文(257)

最近有个嵌入式研发项目又被Linux out of memory(OOM)给盯上了,安排人力突了两周多时间,进展不是很大,为之不多的收获如下:

1 oom并非内存泄漏和系统内存配置不足导致,真凶是内存碎片:512M的os内存,经常在还有200-300M的free余量下产生oom,buddy系统中有成千上万的4K,8K碎片.

2 oom经常发生在vfs do_write或者net模块中的new skb接口中,实际上当时的内存碎片中也有匹配的内存块存在,但还是oom了.

3 我们的同志分析,可能与linux cma内存管理有关....

2015-11-23   |  工作总结   |  赞(0)   |  评论(0)   |  阅读全文(327)
1 2 3 4 5 6 10 11 12 >>
管理登录:

欢迎光临悟会的博客

**您是本博第51586位访客**
**今日访问量:17次**
**总点击数:70687次**
第三方登录

页面执行0.1796秒,网站运行1212天
邮箱: duxlong@live.cn QQ: 276444133
悟会的博客 ©2013-2018 by bpns(i++)