神经网络学习帖,不断更新(2017.6.26日更新)

未解决  未打赏  
messias messias  悬赏: 5 金币
发布:2017-06-26 14:11:22 分类:问答
先占个位置。。。
  • messias messias    
    Time:2017-06-27 02:33:50

    本想边写边修改,不想简码站不可以修改已发布的内容,所以浪费了沙发。。。



     



    因为是学习记录帖,那么可能会忽略各位看官的感受,这个过程可能不会太连贯,我也是脚踩西瓜皮,滑到哪儿算哪儿,这里抱歉了。如果有愿意看的人,给点意见,给点指导,本人表示万分感谢。帖子里可能会转述他人的成果,包括代码、图片等,这里一并对这些有分享精神的坛友表示感谢。



     



    之前,花过不少精力琢磨过验证码的识别,对于比较规则的验证码,都能搞定。只是这种方法,只能针对某站的某型的验证码有效,那么有没有比较通用的方法呢?曾经在某群看到过一个验证码识别的模块,对于干扰线、变形、重叠的验证码,识别率也很高,是bp神经网络一个应用。开口1万买源代码,对方不同意作罢。为什么我愿意花这个钱,主要是考虑本人接单的类型,大部分都有识别验证码的要求。对接打码平台,也能解决问题,但是打码平台都是向服务器请求,这个效率比较低,识别率也并不高。买这个源代码,是想把自己的这个老大难问题解决掉。虽然网络神经也不能解决所有类型的验证码识别,能解决掉大多数类型也是非常值得一试的。把这套方法搞清楚之后,可以应用到其他问题的解决。



     



    这两天搜了一些资料,大多数都是晦涩难懂的理论、数学公式、专业名词,看起来头疼。那么需要把相关的内容系统的恶补一下吗?我担心自己很难坚持下来,很容易半途而废。那么,就按照自己的方法来吧,从最简单的开始,碰到不懂的就去查资料,有些孤立的概念或者公式直接强记,先把骨架搭起来,先把这个理论的脉络搞清楚,皮肉慢慢充实。具体到如何搭建一个神经网络,网络上相关内容比较少,主要是些英文资料,本人英文稀烂。这里不转述别人的文章,主要结合自己的理解用aar代码来实现。



     



    这里借用一下别人的图片:
    图片名称

    在这个问题里,之前有4组数据输入,得到4个数据的输出,问第5次会输出啥?

    常规来说,我们肉眼来分析这个规律,马上就可以得到输出的都是输入的第一个字符。

     

    那么就像验证妈的识别,对于特定的验证码,识别特征都是人工来确定,但是如何准确的提取识别特征是个问题,提取到了特征又如何用代码表达出来是个更大的问题。神经网络的牛逼之处,就在于通过学习训练来获取识别特征,所谓卷积神经网络的卷积核是通过训练来收敛到某一组值,即特征,这一点最难理解……看了三天资料,这个问题理解了对我之后的学习有点睛之效。那么也解决了之前的疑问,神经网络那么高大上,他比别的方法究竟牛逼在何处。

     

    在上述的问题中,这个特征就是输出的都是输入的第一个字符,那么我们很容易判断第5次会输出1。这个简单的例子,只是为了更好的说明神经网络是如何工作的,那么我们碰到的大多数问题,靠人工是无法找到这个规律的。这其中的逻辑是,每次输入有3个值,那么给每个值分配一个权重(三个权重初始化为-1~1的随机值,权重初始化的问题,里面还有很多内容,这里先放放。),通过多次的学习,根据神经网络的输出和期望的输出结果的误差来调整这三个输入值的权重。学习完成后,会将这三个权重调整到最优值。实际测试时,会根据最优的权重输出正确的结果。

     

    训练过程:

















    1.读取输入,得到输入和权重的点积结果并归一化。

    这里某些字符输入不方便,直接借用别人的图片:

    图片名称

    公式中weight即是三个值的权重,input是输入的三个值。这个公式即为点积公式;三个输入值,则为三个神经元;

    那么,归一化是利用函数Sigmoid实现的:
    图片名称

    归一化后,使得点积映射到0~1之间。

    这个函数的图像:
    图片名称
    最后,得到输出的计算公式为:
    图片名称

    2.计算误差,即期望输出和神经网络的输出之间的差值。如果输出为0.6,那我们期望他输出1,则差值为1-0.6



    3.计算调整值,比较好的方法是,误差大调整的步长就大,误差小调整的步长就小,也就是调整量和误差成正比。那么,我们通过输出(归一化后),来获取输出在上面曲线的斜率(变化率),再乘误差,则是调整值。

    那么,变化率是上面归一化函数的导数:
    图片名称
    则调整值: 
    图片名称

     点积越大,越接近1,斜率越小,调整值越小。误差越大,调整值越大。




    4.调整权重,调整值和输入点积,获取各神经元的调整值,原权重加各神经元的调整值,则得到各神经元新的权重。

    下面,用aar代码来实现:

    今天就到这,先睡了。。。明天继续。。。






  • 包包 包包    
    Time:2017-06-27 08:56:30
    [good]
  • messias messias    
    Time:2017-06-28 17:28:44


    import console;
    io.open();
    var inputNum=3;
    var coreWidth=4;
    var testInput={1;0;0}
    var initWeight=function(num){
    math.randomize();
    var weight={};
    for(i=1;num;1){table.push(weight,2*math.random()-1)}
    return weight;
    }
    var weight=initWeight(inputNum)
    io.print("weight:",console.dump(weight));
    var infer=function(nodeNum,inputTab,weightTab){
    var dot=0;
    for(i=1;nodeNum;1){
    dot+=inputTab[[i]]*weightTab[[i]]
    }
    return 1/(1+math.exp(-dot));
    }
    //-------------------------------------初始化
    var core={};
    for(i=1;1000000;1){
    math.randomize();
    var trainInput,transfer={},{};
    for(i=1;inputNum;1){
    table.push(trainInput,math.random(0,1))
    }

    var outPut=infer(inputNum,trainInput,weight)
    var err=trainInput[[1]]-outPut;

    for(i=1;inputNum;1){
    table.push(transfer,trainInput[[i]]*err*outPut*(1-outPut));
    }
    table.push(core,transfer);
    if(i>coreWidth){table.remove(core)}

    /*
    if(i>0 and i%coreWidth==0){//每4次输出后,4个误差和输入卷积,该卷积是孤立的
    for(i=1;inputNum;1){
    var adjust=0;
    for(j=1;#core;1){
    adjust+=core[[j]][[i]]
    }
    weight[[i]]+=adjust;
    }
    }
    */
    for(i=1;inputNum;1){ //每次输出后的误差和之前的3个误差与4个输入卷积,该卷积包含之前所有输入和误差的信息。
    var adjust=0;
    for(j=1;coreWidth;1){
    adjust+=core[[j]][[i]]
    }
    weight[[i]]+=adjust;
    }
    /*
    io.print("transfer:",console.dump(transfer));
    io.print("transfer:"++#transfer);
    io.print("lencore:"++#core);
    io.print("trainInput:",console.dump(trainInput));
    io.print("dot:"++dot);
    io.print("core:",console.dump(core));
    io.print("weight:",console.dump(weight));
    io.print(string.repeat(30,"="));
    */
    }

    io.print("weight:",console.dump(weight));
    io.print("outPut:",infer(inputNum,{0;0;1},weight));

    execute("pause")

    上面的代码,每次学习,偶尔会无法收敛,只是作为如何搭建神经网络的说明。
  • messias messias    
    Time:2017-06-28 23:29:15
    上次的代码,总感觉有些问题,这次修改了以后,收敛的非常好,而且每次循环1万次就可以达到目标:
    import console;
    io.open();
    var inputNum=3;
    var coreWidth=4;
    var trainInput={{0;0;1}{1;1;1}{1;0;1}{0;1;1}}

    var initWeight=function(num){
    math.randomize();
    var weight={};
    for(i=1;num;1){table.push(weight,2*math.random()-1)}
    return weight;
    }
    var weight=initWeight(inputNum)
    io.print("weight:",console.dump(weight));
    var infer=function(nodeNum,inputTab,weightTab){ //这个函数两个作用,一是给下面的学习调用来获取输出,二是用来测试
    var dot=0;
    for(i=1;nodeNum;1){
    dot+=inputTab[[i]]*weightTab[[i]]
    }
    return 1/(1+math.exp(-dot));
    }
    //-------------------------------------初始化

    for(i=1;10000;1){
    math.randomize();
    var transfer;
    var outPut,err=0,0;
    for(i=1;coreWidth;1){
    transfer=trainInput[[i]]; //取训练数据二维数组中的行,转为一维数组
    outPut=infer(inputNum,transfer,weight); //一行输入代入神经网络正向输出,归一化
    for(j=1;inputNum;1){
    weight[[j]]+=(transfer[[1]]-outPut)*outPut*(1-outPut)*trainInput[[i]][[j]]; //一行输入的误差*斜率,和输入的三个项分别乘积,累加四次到三个权重
    }
    }
    }

    io.print("weight:",console.dump(weight));
    io.print("outPut:",infer(inputNum,{0;0;1},weight));

    execute("pause")
    说说两次代码的差别:
    1.第一次的代码,训练集是随机生成的,训练百万个。而第二次的训练集是上面给定的四组例子循环1万次。
    2.第一次的代码做了两种类型的测试,一是每4个输入获取一个权重调整值,二是每个输入都获取权重调整值,但这两种情况都有些问题。第二次的代码,每个训练集(4组)获取一次权重调整值。
    3.第二次的代码更加简洁,效率高了很多。主要是拆解了点积的运算,尽量合并到一个循环中,循环次数少了很多。
    4.第一次代码,训练百万次效果依然有问题,而第二次代码,训练1万次,已经精确到百分之一。

    为什么会有这样的效果,这其中的逻辑关系还没有理解,再找些资料看看吧。


  • wjxdyx wjxdyx    
    Time:2017-06-30 15:36:04
    mark支持一下
  • Danboy Danboy    
    Time:2017-06-30 22:58:59
    支持。。。。。。
  • messias messias    
    Time:2017-07-07 14:12:46
    这两天没闲着。。。
    用aar来完成矩阵运算比较麻烦,也担心效率,所以找了c++矩阵运算的工具Eigen,不需要额外的库,只需要添加相关的头文件即可。考虑把Eigen相关的矩阵运算写成dll,然后aar来调用,这样在aar中就不用自己来实现矩阵运算。搞了大概10个函数后,考虑到和aar的对接问题,一个是要全部指针来传递数据,在aar中就是结构体数组,行、列数这些细节非常多,更加上数据类型的问题,这样写一个比较通用的东西,就非常麻烦了,还一个就是aar的双精处理有些问题,最后想想放弃了。后来考虑直接把学习部分写成一个dll函数由aar来调用,这样省去了更多麻烦。

    学习部分的dll函数,已经写好,也做了调试,但是制作成dll后,Eigen的exp函数失效(直接返回指数),没找到原因。如果要用c++的exp函数,就需要自己写循环来实现,这样的话,使用Eigen就失去了意义。那么,现在考虑使用relu来做为激活函数,这样就绕开了exp函数的问题。

    使用relu来作为激活函数,是否能达到自己的要求,如何设置各值,都需要测试。。。
[ 发单/接单 ]
换IP投票软件
PC蛋蛋自动挂机投注
新浪微博发微博显示尾巴的方法,比如显示来自iphone 7
百度文库批量自动上传软件
一点资讯app刷阅读量/评论/收藏/订阅功能/手机号注册
定做一个阿迪达斯官网注册器(需要破点击文字式验证码)
定制人人网自动注册/修改资料/采集/私聊软件
酷狗繁星直播网页协yi
YY多功能刷订阅刷粉丝
滑块验证码本地识别
狼人杀POST QQ登录注册 获取金币数量
做个贴吧发发帖的软件懂的来
今日头条账号保存cookie
抖音粉丝软件定做,只要粉丝
百家号自媒体发文软件定制
哔哩哔哩播放量
读取TB某个商品上架时间和相关信息
网易博客软件定制
定制天涯论坛发帖软件
定制今日头条批量自动发私信软件
[ 站内搜索 ]
[ 最近热帖 ]
万能助手 -- 扩展库大全集 13748
用aardio创建web工程图文讲解(1) 12836
电脑编程入门自学:Fiddler https 抓包时提示创建根证书不成功问题彻底解决(https插件dll方式) 11740
aardio绘图演示 11410
通过chrome.dll中间件控制外部chrome浏览器 10120
我常用的aardio技巧 9771
《边学C语言边赚钱——简码编程入门教程》系列集合 9616
aardio使用http或whttp进行get/post请求时经常cookies失效怎么办?__电脑计算机编程入门教程自学 9322
[源码下载]简码视频加密解密播放工具个人版v1.0发布,永久免费开源的知识变现神器 8557
python人工智能爬虫系列:怎么查看python版本_电脑计算机编程入门教程自学 8048
编程入门教程:aardio批量上传文件并显示进度条 7882
aardio调用nodejs的ws模块做一个简单的聊天通信示例 7037
电脑计算机编程入门教程自学:原生JavaScript判断字符是否为A-Za-z英文字母 6908
电脑计算机编程入门教程自学:腾讯tx或极验geetest滑块按住拖动完成拼图验证成功破解思路及源码 6501
乐玩插件AARDIO调用 6084
[ 近期热答 ]
电脑计算机编程入门教程自学:什么是buffer缓冲区? 1
aardio_代码编辑框书签管理器开源 1
aardio_怎么用ide库从代码编辑框中取出指定行的源码? 1
aardio_codepage代码页编码乱码暴力猜解工具 1
aardio内嵌echarts图表添加鼠标事件响应功能 2
aardio列表框listbox_模糊查找和精确查找 1
8亿QQ绑定手机泄露:通过腾讯QQ号查询QQ绑定的手机号码漏洞! 1
carl listviewex调用例子----------源码搬运工 2
Aardio内嵌Electron浏览框怎么正确添加启动参数? 1
Aardio取汉字的字节数或字符数 1
怎么实现mssql图片数据的读写 2
aardio_从49个数字里选六个和值为150的不重复的数字 1
在嵌入wps的时候,多了一个 透明的边框,这个怎么消除它 1
万能助手入门帮助教程:学会科学地管理工作文件 1
Aaardio开发内嵌Electron浏览框放服务器上无法下载组件的解决办法 1