机遇 research之路其修远兮,我将上下而求索

Categories


Content
  • 纪念工作一周年
    机遇 research之路其修远兮,我将上下而求索

    纪念工作一周年


    七律·人民解放军占领南京
    作者:毛泽东
    钟山风雨起苍黄,百万雄师过大江。
    虎踞龙盘今胜昔,天翻地覆慨而慷。
    宜将剩勇追穷寇,不可沽名学霸王。
    天若有情天亦老,人间正道是沧桑。
    

    纪念工作一周年

    七月,是北京炎热的开始。前几天都飙升到38摄氏度。两年前这个时候,校招季的到来,然我提前忙碌起来。现在想想,我已经工作一年了。 我们组在这一年里的故事,可以写成一部小说。故事情节可能不如战争年代的故事激荡人心,不及爱情故事扣人心弦,但是一年的努力与成长让我想写点什么。

    万丈高楼平地起,AI建设在基础。基础架构部在深入贯彻落实“正,信,恒,勇,合”的道路上,本着”数据是AI算法之基础,测试是算法优势之保障,落地是算法研发之目的。”的原则,加强系统建设与算法落实,解决AI算法应用的基本问题,构建稳固的AI大楼基础。基础架构部在过去的一年内,在平台建设,算法落地等基础架构建设方面取得卓越的成果。正所谓:“基础不牢,地动山摇。” 打牢基层基础,既是构建工程院的重要内容,也是有序推进AI发展的重要保障,意义十分重大。

    这是加入半年后的年会,为我们部门编写晚会视频开篇。回想我们组的工作内容,的确就是这么回事儿,基础而重要,没有我们的工作,产品组实现起来得非常困难。

    “绿叶吮吸雨露,沐浴阳光的时候,可曾想过根茎在岩石和土壤中的努力付出;花朵以美丽的姿态绽放,接受虫鸟的光顾和人类的褒奖之时可曾想起过根茎的努力付出与绿叶的衬托;秋天的果实以饱满丰硕的体态迎接丰收的时候,可能想起过根茎的努力,叶子与花朵的牺牲。” 而基础架构部的工作内容就像根茎,我只能说很重要,但如果你想被人直接赞美,那是不可能的。

    一年来,结识了不同年龄段的朋友,他们口中的故事是我们日常午餐的甜点。夏天,在空调室内呆久了,就尤其喜欢直射的烈日,晒在身上一下子把身上的霜层烤干。散步到或春天通风,或夏天阴凉,冬日阳光温和的地方,停下来侃侃天地,拉拉家常,有点像户外度假的日子。但一旦到点儿,都立刻马上回到自己的工作岗位上。 我突然想起一句歌词:“打起鼓来,敲起锣来哎,推着小车来送货…” 这虽说的小货郎的工作,但是我们工作内容也像小货郎卖的货品一样丰富多彩,要啥有啥,工作状态也是欢快轻松的。

    最后,我们组缺人,缺人。我们组hc丰富:

    校招-算法开发工程师

    工作职责:
    
    1、机器视觉系统中图像处理、分析及识别算法的设计、实现及性能调优; 
    2、参与图像视觉处理技术的研究与设计; 
    3、参与图像视觉SDK的设计与实现。
    
    任职资格:
    
    1、较强的C/C++语言设计、开发及调试能力; 
    2、熟悉 X86、ARM 的多线程和SIMD代码优化技术; 
    3、有计算机视觉、模式识别、图像处理方面开发经验优先; 
    4、具有GPU cuda编程/openMP/openMPI等并行加速开发经验者优先; 
    5、良好的沟通能力和团队协作能力。
    

    社招-SDK开发工程师

    工作职责:
    
    1. 底层框架通用性封装及优化;保障底层框架SDK的稳定性及高效,跨平台并针对平台进行优化
    2. 算法应用成果转化;深度学习相关算法成果转化,包括基于深度学习底层SDK实现的检测、分类、跟踪等方向的算法
    3. 负责工程性算法策略创建及优化;基于算法SDK,面向行业业务的工程性算法策略的设计及实现;针对不同应用场景,优化工程性算法策略
    4、上层业务支持;针对确定的产品业务,与算法及产品一起快速迭代,保障业务顺利推进
    
    任职资格:
    
    1. 计算机或电子相关专业硕士或以上,两年以上相关工作经验
    2. 精通C/C++开发,编程功底扎实,掌握常用数据结构和算法,熟悉面向对象编程,熟悉常见的架构及设计模式
    3. 有嵌入式SDK开发以及优化等相关经验的优先
    4、有计算机视觉(检测、跟踪、识别)方向、图像处理应用经验优先
    5、有良好的代码开发风格和软件工程思维,熟悉 Git, CMake 等工具
    

    社招-后端高级开发工程师

    工作职责:
    
    1、负责系统后端服务的需求分析、详细设计以及开发工作。
    2、负责系统模块的开发、测试、集成。
    3、不断优化、提升服务的性能。
    
    
    任职资格:
    
    1、本科及以上学历,计算机或地理信息相关专业,3年及以上后端开发经验。
    2、扎实的计算机基础,熟悉常见的数据结构、设计模式及算法
    3、精通至少一门后端语言(nodejs、java、go、python),并能熟练进行服务开发。
    4、熟悉PostgreSQL、Redis等数据库;熟悉Kafka、RabbitMQ等消息中间件;
    5、了解TCP/HTTP/WebSocket等网络通信协议
    6、良好的代码习惯,强大的编码能力,善于学习,勇于解决难题,具备团队精神。
    

    社招-产品技术经理

    工作职责:
    
    1. 负责视觉人工智能算法SDK和平台产品的需求分析、产品规划设计和目标管理
    2. 管理产品生命周期,协调资源,推动跨部门协同,管理依赖和风险,保证高效率、高质量地完成产品开发交付
    3. 负责产品运营推广,跟踪用户反馈,分析系统数据,持续优化产品
    4. 推动研发团队做出合理的技术决策,梳理和改善研发流程和规范
    
    任职资格:
    
    1. 本科或以上学历,计算机或相关专业毕业,3年以上软件、互联网或AI行业产品相关经验
    2. 具有扎实的技术基础和技术背景,熟悉软件或互联网产品开发的开发技术栈,有计算机视觉、机器学习或分布式系统开发相关背景者优先
    3. 熟悉软件或互联网产品开发技术栈,熟悉软件工程和敏捷开发方法
    4. 优秀的学习和沟通能力,逻辑性强,自驱力强,项目推动力强,有团队管理经验者优先
    

    更多岗位可以查询:http://hr.sensetime.com

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    2017年,那人,那事儿
    机遇 research之路其修远兮,我将上下而求索

    2017年,那人,那事儿


    2017已经接近尾声,回想这一年干的事情,历历在目。这一年中遇到了不一样的人,经历了不同的事儿,唯一不变的是纯与真。

    春天,希望之实习

    春天,是美好的。 从2016年12月开始在PerfXLab实习,到现在已经快三个月了。这段实习,很可贵的是认识到了一群真正做计算机的朋友。 贾老师,是我向往的导师类型,他很nice,带我认识什么是优化,如何gdb比较快等等,比实验室的黑盒测试有意思多了。 当然还有几位师兄弟很给力,请教过很多问题。实习期间,我从看着就发怵到看着常常的替换也很欢快, 那段实习的工作,真的学到了很多东西,更重要的是有了一定的编译优化的认知与代码优化的意识。

    后来,袁同学来了,当时觉得很惊讶,放弃网易开发跑这小公司来。但是后来才想明白,干自己想干的,和干别人喜欢看的的问题。 虽然在大公司,在外人看来炫酷,但是可能在创业公司有更多机会接触自己想做的事情,我很佩服袁同学的魄力。后来我们经常一起吃陕西肉夹馍, 上深度学习课,还挺happy的。

    过年回来,好多人都在投递简历找实习,我想还是好好做实验发论文吧。就没有准备春季实习招聘。但是有一次,在群里看到一个招聘信息,大清早的,还没有睡醒就点了一下,结果就发生了奇迹。上午在实验室刷论文呢,就响起了电话。杰哥,美丽又爽朗的组长,面试的时候验证了电话里的猜想。面试很轻松,谈谈技术,侃侃人生规划啥的。聊得投机,干得爽快,丹哥以技术大哥的身份带我飞,看过推荐系统,找过相关算法,调研+实现的任务让我很享受。

    整个春天,只能说:人,真好。

    夏天,奔波之校招

    夏天,忙碌的汗水。 一边忙着准备校招面试和刷题,一边在烈日下奔波。我知道,现在不奔波,日后要为生技奔波。 校招分为两个阶段,内推阶段和校招阶段。首先内推阶段要有亮眼的简历才好。往年8月份才开始的内推,今年提前一年就开始了, 当然,我投递的第一个并不是内推,但是也接到了面试电话NIVIDA,这家公司有我当前最缺的东西——实验要用的显卡,但是我并不太懂 CUDA开发,只是用过一段时间Caffe,不过硬着头皮准备吧。将我实验室做的很粗糙的东西精心准备了一番,写了很多项目在上面,虽然很多都是简单个东西,但是想想研究生期间好像的确没有做什么,有点懊悔起来。但是,终究还是要走下去。面试分为电话面试和现场面试,NIVIDA招人十分重视,不同的office面试是分开的,北京这边电话面试1场+4场连续的面试,让我很头痛。但是说实话,他们的面试题目很基础, 我面的算法岗位,偏重概率论和一些算法的细节与深度,很考验人的实践。现场面试编程题目也很基础,这场面试下来,我知道该准备哪些方面的东西了。上海那边,主要是电话面试,偏重CV方面的项目。令我意外的是上海过了,机会挺好,但是由于个人原因,只能拒绝。

    小米还没开始内推,就请师兄帮内推了。期间从5点开始,一直到晚上7点半结束。分为两场面试,主要考察基本的编程和对项目中设计算法的理解。基本的编程的题目考察很有针对性,如牛顿法实现平方根,对递归与数据结构的理解等等。主要业务是使用tf进行nlp方面的模型,直接落地到小米手机应用中,很nice,这场面试收获很多。

    京东金融是京东最近组建的团队,请假直奔亦庄,做了两个小时的地铁,终于看到了京东的大楼,很气派。感觉他们的电梯调度有问题,等了明明那么多电梯,竟然等那么久才上去,幸好踩点到了。先做了一份小测验,有了前面的面试和经验,回去准备的东西终于派上了用场,测验很快结束,两位年轻的小哥来面试我,真的很年轻。可能是为了给我压力吧,两个人面试我,但是就一个人在说话,问了一些测验的问题和简历上问题,介绍一下组内的情况。后来,来了一位项目组组长,详细介绍了一下团队和相关业务,主要做京东白条和信用预测等业务,主要跟一些金融业务打交道,挺看好的,虽然我对金融一窍不通。但是后来HR小姐姐打电话的时候,我说正要去面试京东的AI团队,就再也没有联系我,哎。。。看来找到可以直接入职的吧。投递了京东AI之后,就去面试了一把,结果被虐得很惨,我记得有一个查找有序数组的变形问题来着,自己太弱鸡了。

    360为了将大量毕业生放到池子里,举办了一场盛大的招聘会,现场人山人海,面试官昏天黑地。投递计算机视觉算法的人太多,导致晚上8点才结束,最后向一位HR自我介绍的时候犯了大错,”我希望能够有机会加入360,精彩360”,竟然不小心说秃噜了,印象大打折扣。不过一面和二面可能印象还可以吧,最后就进入池子里了,一直都没有被捞上来。。。

    面试360的过程中,接到海康威视的电话,我们聊了一下,挺契合的,唯一的缺点就是太远了,不能去实习。而海康威视需要的就是这种可以立马过去实习,然后转正的同志。后面说明了不能去实习的原因等等,就没有消息了。

    阿里内推我投递了,但是自己太菜鸡,做的一些东西不够深入,被面试官问得呼天抢地,终于又回来重新充电喝墨水;

    网易内推,我投递了深度学习算法工程师,远在杭州,好容易过了笔试,要去面试了,结果那几天北京这边几场面试,就放弃了。

    搜狐视频内推招聘会,持续一下午,吃了好多蛋糕,喝了很多咖啡终于轮到我了。我投递了三个岗位,视频推荐岗位,机器学习岗,深度学习岗。原来,我的简历被弄丢了,所以才等了那么久。。。不过幸好,搜狐视频这边的的manager面试,让我重拾信心。面试不是直接问项目,而是解决问题的角度面试,挺新。结合我看过的东西和做过的东西,天马行空地说了几种可能的解决方案,然后分析了一下方法的利弊,竟然让我过了。机器学习那边就很惨了,机器学习算法已经被抛到脑后,什么罗吉斯特回归,什么SVM都忘得一干二净,加上面试官也累得脾气很暴躁,我等得也很焦虑,啥都不想写了,不想说了,后来深度学习的岗位主要是给搜狐客户端提供NLP技术类支持的,后来想想好像我对NLP不太了解就作罢了。

    百度作业帮去看了一下,感觉很极客的。在一个比较老的楼上占了好几层,正好赶上他们放午后水果,看着挺欢快的。面试分为两场,基本编程每场都有,顺带问一下项目什么的。越是基础的题目,越容易考实现能力。比如打印螺旋矩阵等等。

    第一次去西二旗的百度那边的时候,看着那两栋楼很气魄啊。一次是大搜的策略算法岗位,着重考察对任务的立即与解决方案,偏重大数据算法。一次是深度学习研究院,那天正赶上他们晚上有活动,就止于三面,没有下文。

    滴滴内推笔试太简单,导致大部分人都挂掉得很奇怪。后来又过了校招笔试之后,终于在OpenDay去面试了。这次面试体验超级好的,真的。首先,一面的面试官从杭州来,虽然问的问题也比较有深度,而且如果我问他会向我解释一下,完全不像之前遇到的某些面试官那么不和蔼可亲。一面面试结束学到的东西很多。二面面试官比较奇怪,但是我知道他的问题是在看我有没有吃这碗饭的资质,而不是看我做过了什么。

    秋天,喜悦之offer

    秋天,是丰收的季节。经过一整个夏天的奔波和忙碌——笔试,面试,HR沟通,终于到了接不接offer的时候。其实,offer完全可以先接下来的, 毕竟offer在手,才更加理直气壮。截止到国庆节,我已经经历了3个月的面试,虽然手上有offer,但是总觉得这些并不是我最终的归宿。十一回家之后,带着老家丰收的气息,继续回到北京收割最后的秋粮。虽然已经半个多月没有参加面试了,但之前几个月的面试还是学习了不少面试技巧,同时边面试边复习老的问题、学习新的知识点。 回来之后,陆续面试了商汤,小马智行,微软等等,每天都在不停的接电话,面试中。当然,面试的结果还是挺喜人的,又陆续收到了商汤、微软等公司的offer. 加上之前的一些成果,收货总算是丰满起来。

    冬天,反思之感激

    天渐渐冷了,手里的offer越来越少,有的是因为被拒掉的,有的是因为三方迟迟递交。 后来,贾老师邀请我加入PerfXLab,我不知道该如何回复。贾老师,虽然是我实习的老板,但对我来时不仅仅是老板,也是后续优化工作的引路人。杰哥,也对我的就业选择给了宝贵的意见,以知心大姐的角度分析了利弊,最终尊重我的选择;丹哥,在机器学习方面给了很多宝贵的经验,让我在研究生阶段增添了一些科研意味的工作。想想2017经历的人和事儿,两个字:挺好。

    总结

    今年在优化方面有了一定的认识,但是对于多线程开发有待进一步提升,期间在python多线编程方面,马斌哥的教诲很受用。计算机视觉方面,对OpenCV有了更加深刻的理解,对物体检测有了基本的认识,这也是我后续需要继续保持前沿追踪的方面。推荐方面,也蹭了蹭热度,有空多看http://xw.qq.com吧,这是新闻网手机版,添加了推荐和视频频道,其中有我的参与哦。

    希望2018年,更加努力,不忘初心,一骑绝尘,光而不耀。

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    写在2016年元旦
    机遇 research之路其修远兮,我将上下而求索

    写在2016年元旦


    2016年计划

    2016年必将是我的转折一年。 过去的三年,可以说是浑浑噩噩,没有目标,如一个无头苍蝇,漫无目的地寻找着裂缝的鸡蛋。可是,有缝的鸡蛋早已经被淘汰,接下来就是要淘汰无头苍蝇了。

    空虚的两年

    刚进入大三,计划要进实验室学习的。可是,由于自己做事优柔寡断,没能成行,只能成为无业游民。俱乐部那边的活动,让我变得忙碌起来,知道交接了俱乐部的工作之后,我又变得空虚起来。幸好,量和欧教授让我忙了一阵子,还算是没有白白浪费我的大三时光。寒假的时候,我跟花爷、搞搞搞一起水了一个美国数学建模竞赛,结果可想而知,我们真的是寒假来这边度假了。 大三下学期,课程很少了,当我想要进入实验室的时候,老师跟我说有点晚了,想想也是,现在进实验室,干不了一个月的活,就该出去实习了。对的,七月份,我们就出去实习了。虽然是实习,我自己好像还是浑浑噩噩。本来说好的要学点技术,可是工作一天回来,一点代码都不想去看,要不是看美剧就是看日剧,要不就是出去吃吃吃。结果你也知道,胖了20斤左右,看着镜子里的我,都不敢相信这个家伙曾经那么瘦过。 ….

    ============================================================================== ##毕业暑假练车 大学毕业之后,我有点发慌了。同学们纷纷踏上工作岗位的旅程,而我依旧在宿舍过着平静的大学生活。可以说是贪恋最后在九龙湖的时光,也可以说我不喜欢被别人送走,也可以说是我喜欢看着别人离开,独自在此伤感。 所幸我还有驾照要学,袁桑看着学车遥遥无期,干脆直接放弃了。虽然教练说我有点玄,不过,我就全身心地拍在上面,两个月的暑假时间,希望可以学出车来。 刚进入七月,南京进入最闷热的时候。也许是太阳对南京的特殊情感,每天7点多的时候走在道路上已经热得很是难受。七月,也是我科目二学习的时候。 每天早晨醒来,第一件事就是预约练车时间,背上的汗水贴着往下逃跑,“您好,预约练车…”。科目二的教练很是照顾,教练主业是汽车维修,兼职科目二教练,很仔细的一个中年憨厚男子。作为新学员,被教练这么仔细地反复教授还很不习惯,毕竟被科目三教练骂习惯了。 由于预约及时,加上我全身心投入到科目二练习中,很快我的卡就打完了,而且练得也差不多了。交卡,等待考试。10多天后,终于可以考试了。考试的前几天,忽冷忽热的天气,我幸运地中奖了,高烧38多度。模拟和考试那天,拖着疲惫的身子,努力瞪大双眼看着科目二的一些要点,也许是练得时间长,那么糟糕的精神状态下,还是满分过关,下车的时候,我轻松极了。 科目二过了,当天就预约了科目三考试,科目三考试之前,练习了几次之后,终于盼来了考试日期的确定。每次练习都胆战心惊,考试当天的练习,还被科目三教练骂了个狗血喷头。由于科目二的迅速战斗结果,给科目三留下了很充足的时间,即使一次被挂掉也能等来第二次考试。 科目三当天,我只记得我是直道,下午就拿到了驾照。 那天的公交车等了好久都没有来,虽然这样我还是很高兴,因为我有驾照了…

    东南游

    驾照在手,说走就走。 驾照到手的第二天,我就着手准备离开了。宿舍打扫一遍之后,将该扔的扔了,该送人的都送人了,剩下的就是明天出发南下了。

    第一站上海

    很多同学毕业后,大部分都是去了上海。一部分是来上海求学,一部分是来上海工作。毕业后首次来上海玩,当然得找他们混吃混喝。拖着箱子就跑到尚官哥哥那里,蹭吃蹭住。抵达上海的当晚,花花带我们去了一家老上海的餐厅(好像叫老隆兴),很是不错。第二天晚上,找实习的认识的一个清哥吃了一顿日本料理,甚是好吃,等下次碰到他再请他吃好吃的。 再次游走在上海,还是怀着学生时代的情怀。看到豪车摆在路边,我们还是兴奋,虽然跟我们没有半毛钱关系;看到外国美女路过,高兴地手舞足蹈;毕业后奢侈一把,走进了星巴克,不是谈生意,而是为了多喝点牛奶。一年后,三年后,五年后,十年后我们的感觉应该会不越来越不一样了吧~ 再见,上海。我踏上了去厦门的动车。

    第二站厦门

    到了厦门已经是晚上8点了。天下着小雨,虽然维度比南京低很多,但是没有闷热的感觉。我打电话给峰哥,说已经到了。我们互相说了位置,果真,他胖了。峰哥是我高中同学,三年的同床,对的是同床。他住在我的上铺。不管是高一时候的509还是高二时候的203还是高三时候的209,我住下铺,他住上铺。大学他来了厦门,我去了南京,中间到时见过一次,那也是大二的十一了吧。这么多年没见,一看到他,峰哥的品味还是没有变的,牛仔裤配一个紧身短袖衫,好像高中就是这个风格了。 我在厦门呆了大概一个周左右,中间恰逢七夕,作为灯泡的我,就跑到峰哥隔壁那边睡觉去了。至于什么感想呢,就是这一天太虐狗了。出了七夕这一天,其他日子我就到处逛。看了看厦门的几所大学,厦大恬静优美,华侨气派恢弘,集美学村的独特建筑风格让人拍手叫好。 踏上去往深圳的动车,回头挥别厦门。

    第三站深圳

    深圳,很是闷热。湿热的环境给蟑螂提供了适宜的栖息条件。身上黏糊糊的感觉束缚了我的行动,蟑螂爬出来又爬进去,好像嘲笑我一般。 终于来深圳的第三天我去了南方科技大学,去看看这个2011年重大新闻事件挑战中国所有公立大学的神圣之地。可惜,外人不得入内,让我千里迢迢打了一场水漂。虽然绕着南方科技大学绕了一大半,也没能成行。最后闯进来水源保护区,被负责的工作人员赶了出来…… 从深圳,过了口岸就是香港。

    ==============================================================================

    新年计划

    新年伊始,我找到了奋斗的目标。一个志同道合的女孩可能是一剂良药,救治失去方向的大雁重新找到雁群;也是一顶巨大的警钟,不让我陷入低迷;更是未来奋斗道路上不可缺少的伙伴。想想过去混过的两年时光,也许会因为一个女孩的出现而改变。既然,已经出现了,就该好好想想如何重新开始。

    想的不如落实到纸上

    如果想的有100分,如果没有任何督促,最终能够落实的计划不到1分。好记性不如烂笔头,计划也是如此。如果记录下来时常翻看,空想往往就是空想罢了。 今年有四大任务

    数学理论。 矩阵论、随机过程还是要自学的。周二下午旁听随机过程,那么周二下午的马克思同志就得翘掉了。李老师的矩阵论倒是周一周三上午一二节,旁听倒是无妨,但是一定要早睡才好,要不然课堂上睡觉得不偿失。有上个学期的旁听经验可以知道,既然选择旁听,就要拿出学位课的热情。 英语学习。 经过多年不习英语的安逸,如今英语摧残人生。英语成绩一塌糊涂这个我就不详细说了。拿出明天是最后一天的紧张感,拼上最后的尊严,拿下它。

    • 单词量太低,当前4500左右,目标10000单词量
    • 阅读量不够。看论文常常出现看到一半就放弃了,很大程度上是语言障碍。Quora是个不错的平台
    • 听懂英语量不够。虽然听了好多英语,但是听懂的很少,更别提能够跟着说出来的。
    • 看懂听懂不如写到纸上。老套的书写方式,生搬硬套template,使用着自己仅有的几个单词,浑水摸鱼,最后啥都没捞到。 专业知识。 俗话说,做一天和尚撞一天钟。学生就该好好广泛学习,研究生就该好好深入专业知识。专业只有精通才叫专业,技术只有实践才能掌握。我是学习计算机技术的,如果不研究专业前沿,不去实践专业理论,何谈研究生。
    • 搜索知识
    • 图像知识
    • 机器学习 学会关心。 玩笑可以开,但是要掌握分寸。一个人的时候随便怎么开玩笑都可以,但是两个人的时候有些话玩笑就不能够开了。而且两个人之间特别亲密,表达关心还是必要的。
    • 关心在于细节
    • 关心在于小事儿
    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    胡思乱想:过年
    机遇 research之路其修远兮,我将上下而求索

    胡思乱想:过年


    当“过年”成为历史文化遗产

    过年,是我们小时候最期盼的事情了。现在,已经工作,当在回到老家过年,已经是另外一番景象,我不禁思绪万千,年会一直被过下去吗?

    过年,不仅仅是家人团聚,前奏很是繁琐。

    蒸馒头

    年前要蒸馒头,蒸好多馒头。在蒸馒头的日子里,母亲每天要备好老面(含有酵母菌的经过发酵的和水的面粉),称好十几斤面粉备在那里,等到三点的闹钟一响,就和父亲出发了去压面了。小时候因为觉得好玩,就跟在母亲的后面,有时候抱着老面盆子,有时候打着手电筒,卖力地迈着步子紧紧跟在母亲后面。 和面回来,紧接着就进入到做馒头的工序。母亲撕面团,揉面团,父亲、姐姐和我使用模具制作带有各种花纹的馒头————鱼、桃子、元宝是最常见的。手里的面团越来越欢快,跳到盖笺上变成了鱼、元宝…… 端着盖笺的鱼和元宝,放到暖炕上铺好放置整齐,等着再一次的发酵的完成。 等上几个小时,做好的馒头在炕头上发酵成为一个大胖子,是时候开始蒸馒头了。 蒸是极其考验一位农村妇女基本功夫的,不仅要蒸得多,还要蒸得好看。母亲有自己的独门秘诀。每一锅馒头的中间,母亲都会放置一个茶碗,茶碗比馒头高一些,茶碗的上面再放一个篦子,可以再放好多馒头,从而提高了单锅的数量。秘诀不仅仅在于数量,还在于这个茶碗,茶碗中放置的不是简单的水,而是白酒。要知道,白酒是比水更容易蒸发的。当受热时,酒精会随着水蒸汽在馒头上覆盖,形成常见馒头光滑的表面。而酒精的功效就在于能够比水更快一步形成光滑表面,使得馒头看上去更白。 大冷天的,花一整天做馒头,烧得炕滚烫,坐在上面没有两分钟屁股就疼得厉害。我时常想,这么热的炕用来烤肉也是不错的 :)

    二十年后,还会存在这种做馒头方式吗?

    炒花生、瓜子

    很小的时候,父亲还在家里炒过瓜子和花生。 只记得,当时我趴在窗户上看他们忙碌的身影,父亲手中不停地翻动着手中的木铲,锅中的瓜子随着木铲的搅动,”唰唰唰”地声响在厨房上空飘荡。 刚出锅的花生吃起来软软的,但让人上瘾般的好吃。地上的花生皮渐渐多了起来,踩在上面噼里啪啦地响,好玩极了。 现在花生瓜子直接从集市上买可以了,也许在也吃不到刚出锅的花生了。

    制作摇钱树

    所谓的摇钱树,就是一根榆树枝,挂上些许金元宝和绿叶。 榆树枝条是父亲从河边上采来的,经过简单父亲这位老果林员的修剪,更加具有了生金发财的神气。挂上我和姐姐亲手折叠的金色的元宝,然后摘几片菠菜叶子做修饰,一颗摇钱树就这样被培育成功了。 榆树又叫榆钱数树,”余钱”,象征年年有余钱。菠菜象征着农家人民的朴素与辛勤的性格,而元宝是我们的期许。

    现在,简单多了,花几十块钱买一个金色的塑料材料的摇钱树就好了。二十年后,可能会变得更漂亮,可是,其中的乐趣已经早已不在了…

    年前扫墓

    墓,是人逝去后,亲人为其所建的休憩之所。墓地杂草恒生,野兽鸟虫众多,鲜有人去。 我爷爷和奶奶的墓地,每到清明、过年、以及忌日等重要日子,父亲要去扫墓除杂草的。这些看似平常的事情,对于远在他乡工作的年轻人来说,扫墓成为一件费时、费力又感觉没有意义的事情。那个时候,到处墓地,荒草飞长,虫鸟夜鸣,可是没有一个扫墓人的踪影,过年的时候也是如此…

    到处奔跑的孩子

    爱玩,是孩子的天性;奔跑,是孩子的灵性。然而,现在的孩子在村子里已经没有奔跑的场所,有的只是代步的汽车。听,在轰鸣… 小的时候,过年回家,家人来得很多,往往都是一大家子回来。现在,家人来得少了,可是汽车却紧紧地塞紧家门口,行人出行很不方便。是有钱了,可是道路却没有了;是有钱了,可是回家的次数却少了;是有钱了,可是孩子们再也不敢再路上奔跑了;是有钱了,可是当年一起说笑的朋友却碰不到一起扯淡了… 唉~~ 几年后,村子里的老人会越来越少,车子应该不会这么多了吧;几年后,去城市打工的人 越来越多,应该不会有这么多人家还灯火通明了。

    未完待续…

    多少年后,年还是年吗?

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    菜鸟实习初体验--IN NI
    机遇 research之路其修远兮,我将上下而求索

    菜鸟实习初体验--IN NI


    前言

    National Instructions,一家外企,主要做工业通讯设备与系统解决方案。其中最为知名的产品莫过于LabView. 暑期实习招聘后期,收到NI的的实习offer很是开心。2014年7月我正式入职到2015年4月离职,在NI实习半年多,可以说是收益颇丰。真正在企业中工作过,我才真正理解书中所说的“菜鸟”。

    融入

    我和巴神(一位巴姓同学,现在应该成为大佬了)被分配到同一个组,让我这个菜鸟心安了不少。入门阶段,我们俩从熟悉常用软件LabView开始。LabVIEW作为NI起家的东西,虽然在大学课程中接触过,但是现在真正要靠它吃饭,还是花费了一方功夫。LabView总体给我的感觉是学习过程很是迅速,而且很容易实现一些设计设计模式,多线程等C++实现起来比较费劲的东西,而且丰富的插件软件,让它在不同工业企业中大显身手。实习生导师沈祥和仪俊也是很平易近人,有什么问题及时讨论和反馈,很快就在这个新的环境里适应了。

    日常工作

    日常开发过程中,采用Scrum的方式进行任务管理和跟踪,每年迭代一个大版本,但是每个大版本的 要实现什么功能,在9月份的时候就制定好,然后开始计数调研。然后就是定期一步一步地跟踪进度就可以。最忙的时候后应该是3~5月份,这个时候准备开始发版了,开始大规模测试,每天都要解决很多bug.

    在NI做开发还是蛮轻松的。加班的可能性很少,正式员工每年也就加班几天吧。实习生就没有机会体会加班了:). NI的工作氛围是很惬意的,我赶上了几次员工感谢日,一大早 大老板们 站在那里给你分精致的早餐。此外,下午三点半左右是最为欢快的时刻,员工升职小聚啊,结婚分发喜糖啊,添丁分发礼物啊。我好像吃了好多同事给的礼物啊,在这里表示感谢。

    主要工作内容

    LabVIEW DEMO 到 工业软件

    每个进入公司的成员必须要做的一个东西DEMO;“四个灯泡,随机亮,然后你根据之前亮的顺序进行点击。” 当然,我也这么做了一版。后来觉得这个游戏没有什么意思,干脆自己把游戏规则重新润化了一下,加大了游戏的难度,实现了一把。后来,我和巴瑞华合作了一个工业通讯软件ANVIL和HAMMER。这套软件简单来说相当于大学做的socket通讯软件,但是通讯协议不是使用HTTP或者TCP, UDP,而是使用一种工业通讯协议。这个DEMO制作工程中,我们才意识的,原来图形化编程并不是你想的那么easy的,要想写出漂亮的LabVIEW程序,没有 基本的编程规范是不行的。

    • 常用的可以包成子控件,记性C中的函数一样
    • 线要对齐,就行代码格式要符合公司规范一样
    • 一页内的逻辑要清楚,条例,一眼就看懂是怎么设计的

    看似简单的编程方式,也有优雅而艰难的一面。

    测试用例自动化

    手动测试的测试用例转自动化测试用例。根据测试用例的目的,如果能够进行自动化测试的,我们就转成自动化测试用例。其中还有一些测试用例需要根据SPEC文档自己实现。实现过程中有自己的LabVIEW 程序的设计思维和style已经逐渐养成,并且get到了SPEC文档的重要性。手工测试过程可能执行一遍需要几天的时间,现在只需要睡一觉即可。

    新版本技术调研——性能对比测试

    新产品处于research阶段,对性能和稳定有很高的要求。这就要求企业对技术进行相应的调研和实现,而我在其中就是助理调研实习生了。有的时候一个想法需要确认一下丢包的程度和性能情况,那我的任务就来了。期间还有一段时间还写了一个perl的抓包代码,当时看的很是兴奋,终于见识到了perl网络库的强大了。

    wireshark在这个阶段用的多了,也渐渐熟悉起来了,后来干脆自己写一个抓包程序吧,但是未经验证还是算了。 后来就去写C程序,编译成动态链接库,第一次编译shared library,第一次编写需要链接动态库的程序,第一次手动创建软连接等…

    代码检查工具

    国有国法,家有家规。写代码有写代码的规范,企业也有相应的企业规范。为了规范公司代码,我们决定实现一个代码规范检查toolkit. 这个工具作为公司交叉编译系统的插件,可以支持响应的代码风格检查。

    • clang++编译器实现抽象语法树的生成
    • python 2.7 实现检查规则的注册,和语法树的遍历检查
    • RabbitMQ作任务分发

    菜鸟实习总结

    • 好的情绪很重要,让好的情绪伴随每一天,工作、生活将充满激情。
    • 不是别人不帮你,是自己没有发出求救信号
    • 不要抱怨,抱怨只是无用功,还不如沉下心思好好想想为什么会这样
    • 每天进步一点点
    • 别人的优点值得我们学习,别人的缺点即使存在也不关乎我的事情。多多赞美别人
    • 责任是自己的就是自己的,承担下来
    • 仔细聆听他人,不可滔滔不绝
    • 真诚待人,记住别人的名字

    对了,我实习那两年,NI一直是大中华区最佳职场。

    最后总结一下:

    当每天一声早上好成为习惯,  
    一切变得自然而然。  
    好的心情让我们互相感染,    
    工作中的你我变得如此美丽灿烂。   
    

    特别感谢我的manager, Han mentor Yijun,Xiang Yiqing,Bing, Feng, Qian,Jun … 还有我的小伙伴们。

    In me the tiger sniffs the rose.

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    "> opinion 纪念工作一周年
    机遇 research之路其修远兮,我将上下而求索

    纪念工作一周年


    七律·人民解放军占领南京
    作者:毛泽东
    钟山风雨起苍黄,百万雄师过大江。
    虎踞龙盘今胜昔,天翻地覆慨而慷。
    宜将剩勇追穷寇,不可沽名学霸王。
    天若有情天亦老,人间正道是沧桑。
    

    纪念工作一周年

    七月,是北京炎热的开始。前几天都飙升到38摄氏度。两年前这个时候,校招季的到来,然我提前忙碌起来。现在想想,我已经工作一年了。 我们组在这一年里的故事,可以写成一部小说。故事情节可能不如战争年代的故事激荡人心,不及爱情故事扣人心弦,但是一年的努力与成长让我想写点什么。

    万丈高楼平地起,AI建设在基础。基础架构部在深入贯彻落实“正,信,恒,勇,合”的道路上,本着”数据是AI算法之基础,测试是算法优势之保障,落地是算法研发之目的。”的原则,加强系统建设与算法落实,解决AI算法应用的基本问题,构建稳固的AI大楼基础。基础架构部在过去的一年内,在平台建设,算法落地等基础架构建设方面取得卓越的成果。正所谓:“基础不牢,地动山摇。” 打牢基层基础,既是构建工程院的重要内容,也是有序推进AI发展的重要保障,意义十分重大。

    这是加入半年后的年会,为我们部门编写晚会视频开篇。回想我们组的工作内容,的确就是这么回事儿,基础而重要,没有我们的工作,产品组实现起来得非常困难。

    “绿叶吮吸雨露,沐浴阳光的时候,可曾想过根茎在岩石和土壤中的努力付出;花朵以美丽的姿态绽放,接受虫鸟的光顾和人类的褒奖之时可曾想起过根茎的努力付出与绿叶的衬托;秋天的果实以饱满丰硕的体态迎接丰收的时候,可能想起过根茎的努力,叶子与花朵的牺牲。” 而基础架构部的工作内容就像根茎,我只能说很重要,但如果你想被人直接赞美,那是不可能的。

    一年来,结识了不同年龄段的朋友,他们口中的故事是我们日常午餐的甜点。夏天,在空调室内呆久了,就尤其喜欢直射的烈日,晒在身上一下子把身上的霜层烤干。散步到或春天通风,或夏天阴凉,冬日阳光温和的地方,停下来侃侃天地,拉拉家常,有点像户外度假的日子。但一旦到点儿,都立刻马上回到自己的工作岗位上。 我突然想起一句歌词:“打起鼓来,敲起锣来哎,推着小车来送货…” 这虽说的小货郎的工作,但是我们工作内容也像小货郎卖的货品一样丰富多彩,要啥有啥,工作状态也是欢快轻松的。

    最后,我们组缺人,缺人。我们组hc丰富:

    校招-算法开发工程师

    工作职责:
    
    1、机器视觉系统中图像处理、分析及识别算法的设计、实现及性能调优; 
    2、参与图像视觉处理技术的研究与设计; 
    3、参与图像视觉SDK的设计与实现。
    
    任职资格:
    
    1、较强的C/C++语言设计、开发及调试能力; 
    2、熟悉 X86、ARM 的多线程和SIMD代码优化技术; 
    3、有计算机视觉、模式识别、图像处理方面开发经验优先; 
    4、具有GPU cuda编程/openMP/openMPI等并行加速开发经验者优先; 
    5、良好的沟通能力和团队协作能力。
    

    社招-SDK开发工程师

    工作职责:
    
    1. 底层框架通用性封装及优化;保障底层框架SDK的稳定性及高效,跨平台并针对平台进行优化
    2. 算法应用成果转化;深度学习相关算法成果转化,包括基于深度学习底层SDK实现的检测、分类、跟踪等方向的算法
    3. 负责工程性算法策略创建及优化;基于算法SDK,面向行业业务的工程性算法策略的设计及实现;针对不同应用场景,优化工程性算法策略
    4、上层业务支持;针对确定的产品业务,与算法及产品一起快速迭代,保障业务顺利推进
    
    任职资格:
    
    1. 计算机或电子相关专业硕士或以上,两年以上相关工作经验
    2. 精通C/C++开发,编程功底扎实,掌握常用数据结构和算法,熟悉面向对象编程,熟悉常见的架构及设计模式
    3. 有嵌入式SDK开发以及优化等相关经验的优先
    4、有计算机视觉(检测、跟踪、识别)方向、图像处理应用经验优先
    5、有良好的代码开发风格和软件工程思维,熟悉 Git, CMake 等工具
    

    社招-后端高级开发工程师

    工作职责:
    
    1、负责系统后端服务的需求分析、详细设计以及开发工作。
    2、负责系统模块的开发、测试、集成。
    3、不断优化、提升服务的性能。
    
    
    任职资格:
    
    1、本科及以上学历,计算机或地理信息相关专业,3年及以上后端开发经验。
    2、扎实的计算机基础,熟悉常见的数据结构、设计模式及算法
    3、精通至少一门后端语言(nodejs、java、go、python),并能熟练进行服务开发。
    4、熟悉PostgreSQL、Redis等数据库;熟悉Kafka、RabbitMQ等消息中间件;
    5、了解TCP/HTTP/WebSocket等网络通信协议
    6、良好的代码习惯,强大的编码能力,善于学习,勇于解决难题,具备团队精神。
    

    社招-产品技术经理

    工作职责:
    
    1. 负责视觉人工智能算法SDK和平台产品的需求分析、产品规划设计和目标管理
    2. 管理产品生命周期,协调资源,推动跨部门协同,管理依赖和风险,保证高效率、高质量地完成产品开发交付
    3. 负责产品运营推广,跟踪用户反馈,分析系统数据,持续优化产品
    4. 推动研发团队做出合理的技术决策,梳理和改善研发流程和规范
    
    任职资格:
    
    1. 本科或以上学历,计算机或相关专业毕业,3年以上软件、互联网或AI行业产品相关经验
    2. 具有扎实的技术基础和技术背景,熟悉软件或互联网产品开发的开发技术栈,有计算机视觉、机器学习或分布式系统开发相关背景者优先
    3. 熟悉软件或互联网产品开发技术栈,熟悉软件工程和敏捷开发方法
    4. 优秀的学习和沟通能力,逻辑性强,自驱力强,项目推动力强,有团队管理经验者优先
    

    更多岗位可以查询:http://hr.sensetime.com

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    2017年,那人,那事儿
    机遇 research之路其修远兮,我将上下而求索

    2017年,那人,那事儿


    2017已经接近尾声,回想这一年干的事情,历历在目。这一年中遇到了不一样的人,经历了不同的事儿,唯一不变的是纯与真。

    春天,希望之实习

    春天,是美好的。 从2016年12月开始在PerfXLab实习,到现在已经快三个月了。这段实习,很可贵的是认识到了一群真正做计算机的朋友。 贾老师,是我向往的导师类型,他很nice,带我认识什么是优化,如何gdb比较快等等,比实验室的黑盒测试有意思多了。 当然还有几位师兄弟很给力,请教过很多问题。实习期间,我从看着就发怵到看着常常的替换也很欢快, 那段实习的工作,真的学到了很多东西,更重要的是有了一定的编译优化的认知与代码优化的意识。

    后来,袁同学来了,当时觉得很惊讶,放弃网易开发跑这小公司来。但是后来才想明白,干自己想干的,和干别人喜欢看的的问题。 虽然在大公司,在外人看来炫酷,但是可能在创业公司有更多机会接触自己想做的事情,我很佩服袁同学的魄力。后来我们经常一起吃陕西肉夹馍, 上深度学习课,还挺happy的。

    过年回来,好多人都在投递简历找实习,我想还是好好做实验发论文吧。就没有准备春季实习招聘。但是有一次,在群里看到一个招聘信息,大清早的,还没有睡醒就点了一下,结果就发生了奇迹。上午在实验室刷论文呢,就响起了电话。杰哥,美丽又爽朗的组长,面试的时候验证了电话里的猜想。面试很轻松,谈谈技术,侃侃人生规划啥的。聊得投机,干得爽快,丹哥以技术大哥的身份带我飞,看过推荐系统,找过相关算法,调研+实现的任务让我很享受。

    整个春天,只能说:人,真好。

    夏天,奔波之校招

    夏天,忙碌的汗水。 一边忙着准备校招面试和刷题,一边在烈日下奔波。我知道,现在不奔波,日后要为生技奔波。 校招分为两个阶段,内推阶段和校招阶段。首先内推阶段要有亮眼的简历才好。往年8月份才开始的内推,今年提前一年就开始了, 当然,我投递的第一个并不是内推,但是也接到了面试电话NIVIDA,这家公司有我当前最缺的东西——实验要用的显卡,但是我并不太懂 CUDA开发,只是用过一段时间Caffe,不过硬着头皮准备吧。将我实验室做的很粗糙的东西精心准备了一番,写了很多项目在上面,虽然很多都是简单个东西,但是想想研究生期间好像的确没有做什么,有点懊悔起来。但是,终究还是要走下去。面试分为电话面试和现场面试,NIVIDA招人十分重视,不同的office面试是分开的,北京这边电话面试1场+4场连续的面试,让我很头痛。但是说实话,他们的面试题目很基础, 我面的算法岗位,偏重概率论和一些算法的细节与深度,很考验人的实践。现场面试编程题目也很基础,这场面试下来,我知道该准备哪些方面的东西了。上海那边,主要是电话面试,偏重CV方面的项目。令我意外的是上海过了,机会挺好,但是由于个人原因,只能拒绝。

    小米还没开始内推,就请师兄帮内推了。期间从5点开始,一直到晚上7点半结束。分为两场面试,主要考察基本的编程和对项目中设计算法的理解。基本的编程的题目考察很有针对性,如牛顿法实现平方根,对递归与数据结构的理解等等。主要业务是使用tf进行nlp方面的模型,直接落地到小米手机应用中,很nice,这场面试收获很多。

    京东金融是京东最近组建的团队,请假直奔亦庄,做了两个小时的地铁,终于看到了京东的大楼,很气派。感觉他们的电梯调度有问题,等了明明那么多电梯,竟然等那么久才上去,幸好踩点到了。先做了一份小测验,有了前面的面试和经验,回去准备的东西终于派上了用场,测验很快结束,两位年轻的小哥来面试我,真的很年轻。可能是为了给我压力吧,两个人面试我,但是就一个人在说话,问了一些测验的问题和简历上问题,介绍一下组内的情况。后来,来了一位项目组组长,详细介绍了一下团队和相关业务,主要做京东白条和信用预测等业务,主要跟一些金融业务打交道,挺看好的,虽然我对金融一窍不通。但是后来HR小姐姐打电话的时候,我说正要去面试京东的AI团队,就再也没有联系我,哎。。。看来找到可以直接入职的吧。投递了京东AI之后,就去面试了一把,结果被虐得很惨,我记得有一个查找有序数组的变形问题来着,自己太弱鸡了。

    360为了将大量毕业生放到池子里,举办了一场盛大的招聘会,现场人山人海,面试官昏天黑地。投递计算机视觉算法的人太多,导致晚上8点才结束,最后向一位HR自我介绍的时候犯了大错,”我希望能够有机会加入360,精彩360”,竟然不小心说秃噜了,印象大打折扣。不过一面和二面可能印象还可以吧,最后就进入池子里了,一直都没有被捞上来。。。

    面试360的过程中,接到海康威视的电话,我们聊了一下,挺契合的,唯一的缺点就是太远了,不能去实习。而海康威视需要的就是这种可以立马过去实习,然后转正的同志。后面说明了不能去实习的原因等等,就没有消息了。

    阿里内推我投递了,但是自己太菜鸡,做的一些东西不够深入,被面试官问得呼天抢地,终于又回来重新充电喝墨水;

    网易内推,我投递了深度学习算法工程师,远在杭州,好容易过了笔试,要去面试了,结果那几天北京这边几场面试,就放弃了。

    搜狐视频内推招聘会,持续一下午,吃了好多蛋糕,喝了很多咖啡终于轮到我了。我投递了三个岗位,视频推荐岗位,机器学习岗,深度学习岗。原来,我的简历被弄丢了,所以才等了那么久。。。不过幸好,搜狐视频这边的的manager面试,让我重拾信心。面试不是直接问项目,而是解决问题的角度面试,挺新。结合我看过的东西和做过的东西,天马行空地说了几种可能的解决方案,然后分析了一下方法的利弊,竟然让我过了。机器学习那边就很惨了,机器学习算法已经被抛到脑后,什么罗吉斯特回归,什么SVM都忘得一干二净,加上面试官也累得脾气很暴躁,我等得也很焦虑,啥都不想写了,不想说了,后来深度学习的岗位主要是给搜狐客户端提供NLP技术类支持的,后来想想好像我对NLP不太了解就作罢了。

    百度作业帮去看了一下,感觉很极客的。在一个比较老的楼上占了好几层,正好赶上他们放午后水果,看着挺欢快的。面试分为两场,基本编程每场都有,顺带问一下项目什么的。越是基础的题目,越容易考实现能力。比如打印螺旋矩阵等等。

    第一次去西二旗的百度那边的时候,看着那两栋楼很气魄啊。一次是大搜的策略算法岗位,着重考察对任务的立即与解决方案,偏重大数据算法。一次是深度学习研究院,那天正赶上他们晚上有活动,就止于三面,没有下文。

    滴滴内推笔试太简单,导致大部分人都挂掉得很奇怪。后来又过了校招笔试之后,终于在OpenDay去面试了。这次面试体验超级好的,真的。首先,一面的面试官从杭州来,虽然问的问题也比较有深度,而且如果我问他会向我解释一下,完全不像之前遇到的某些面试官那么不和蔼可亲。一面面试结束学到的东西很多。二面面试官比较奇怪,但是我知道他的问题是在看我有没有吃这碗饭的资质,而不是看我做过了什么。

    秋天,喜悦之offer

    秋天,是丰收的季节。经过一整个夏天的奔波和忙碌——笔试,面试,HR沟通,终于到了接不接offer的时候。其实,offer完全可以先接下来的, 毕竟offer在手,才更加理直气壮。截止到国庆节,我已经经历了3个月的面试,虽然手上有offer,但是总觉得这些并不是我最终的归宿。十一回家之后,带着老家丰收的气息,继续回到北京收割最后的秋粮。虽然已经半个多月没有参加面试了,但之前几个月的面试还是学习了不少面试技巧,同时边面试边复习老的问题、学习新的知识点。 回来之后,陆续面试了商汤,小马智行,微软等等,每天都在不停的接电话,面试中。当然,面试的结果还是挺喜人的,又陆续收到了商汤、微软等公司的offer. 加上之前的一些成果,收货总算是丰满起来。

    冬天,反思之感激

    天渐渐冷了,手里的offer越来越少,有的是因为被拒掉的,有的是因为三方迟迟递交。 后来,贾老师邀请我加入PerfXLab,我不知道该如何回复。贾老师,虽然是我实习的老板,但对我来时不仅仅是老板,也是后续优化工作的引路人。杰哥,也对我的就业选择给了宝贵的意见,以知心大姐的角度分析了利弊,最终尊重我的选择;丹哥,在机器学习方面给了很多宝贵的经验,让我在研究生阶段增添了一些科研意味的工作。想想2017经历的人和事儿,两个字:挺好。

    总结

    今年在优化方面有了一定的认识,但是对于多线程开发有待进一步提升,期间在python多线编程方面,马斌哥的教诲很受用。计算机视觉方面,对OpenCV有了更加深刻的理解,对物体检测有了基本的认识,这也是我后续需要继续保持前沿追踪的方面。推荐方面,也蹭了蹭热度,有空多看http://xw.qq.com吧,这是新闻网手机版,添加了推荐和视频频道,其中有我的参与哦。

    希望2018年,更加努力,不忘初心,一骑绝尘,光而不耀。

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    写在2016年元旦
    机遇 research之路其修远兮,我将上下而求索

    写在2016年元旦


    2016年计划

    2016年必将是我的转折一年。 过去的三年,可以说是浑浑噩噩,没有目标,如一个无头苍蝇,漫无目的地寻找着裂缝的鸡蛋。可是,有缝的鸡蛋早已经被淘汰,接下来就是要淘汰无头苍蝇了。

    空虚的两年

    刚进入大三,计划要进实验室学习的。可是,由于自己做事优柔寡断,没能成行,只能成为无业游民。俱乐部那边的活动,让我变得忙碌起来,知道交接了俱乐部的工作之后,我又变得空虚起来。幸好,量和欧教授让我忙了一阵子,还算是没有白白浪费我的大三时光。寒假的时候,我跟花爷、搞搞搞一起水了一个美国数学建模竞赛,结果可想而知,我们真的是寒假来这边度假了。 大三下学期,课程很少了,当我想要进入实验室的时候,老师跟我说有点晚了,想想也是,现在进实验室,干不了一个月的活,就该出去实习了。对的,七月份,我们就出去实习了。虽然是实习,我自己好像还是浑浑噩噩。本来说好的要学点技术,可是工作一天回来,一点代码都不想去看,要不是看美剧就是看日剧,要不就是出去吃吃吃。结果你也知道,胖了20斤左右,看着镜子里的我,都不敢相信这个家伙曾经那么瘦过。 ….

    ============================================================================== ##毕业暑假练车 大学毕业之后,我有点发慌了。同学们纷纷踏上工作岗位的旅程,而我依旧在宿舍过着平静的大学生活。可以说是贪恋最后在九龙湖的时光,也可以说我不喜欢被别人送走,也可以说是我喜欢看着别人离开,独自在此伤感。 所幸我还有驾照要学,袁桑看着学车遥遥无期,干脆直接放弃了。虽然教练说我有点玄,不过,我就全身心地拍在上面,两个月的暑假时间,希望可以学出车来。 刚进入七月,南京进入最闷热的时候。也许是太阳对南京的特殊情感,每天7点多的时候走在道路上已经热得很是难受。七月,也是我科目二学习的时候。 每天早晨醒来,第一件事就是预约练车时间,背上的汗水贴着往下逃跑,“您好,预约练车…”。科目二的教练很是照顾,教练主业是汽车维修,兼职科目二教练,很仔细的一个中年憨厚男子。作为新学员,被教练这么仔细地反复教授还很不习惯,毕竟被科目三教练骂习惯了。 由于预约及时,加上我全身心投入到科目二练习中,很快我的卡就打完了,而且练得也差不多了。交卡,等待考试。10多天后,终于可以考试了。考试的前几天,忽冷忽热的天气,我幸运地中奖了,高烧38多度。模拟和考试那天,拖着疲惫的身子,努力瞪大双眼看着科目二的一些要点,也许是练得时间长,那么糟糕的精神状态下,还是满分过关,下车的时候,我轻松极了。 科目二过了,当天就预约了科目三考试,科目三考试之前,练习了几次之后,终于盼来了考试日期的确定。每次练习都胆战心惊,考试当天的练习,还被科目三教练骂了个狗血喷头。由于科目二的迅速战斗结果,给科目三留下了很充足的时间,即使一次被挂掉也能等来第二次考试。 科目三当天,我只记得我是直道,下午就拿到了驾照。 那天的公交车等了好久都没有来,虽然这样我还是很高兴,因为我有驾照了…

    东南游

    驾照在手,说走就走。 驾照到手的第二天,我就着手准备离开了。宿舍打扫一遍之后,将该扔的扔了,该送人的都送人了,剩下的就是明天出发南下了。

    第一站上海

    很多同学毕业后,大部分都是去了上海。一部分是来上海求学,一部分是来上海工作。毕业后首次来上海玩,当然得找他们混吃混喝。拖着箱子就跑到尚官哥哥那里,蹭吃蹭住。抵达上海的当晚,花花带我们去了一家老上海的餐厅(好像叫老隆兴),很是不错。第二天晚上,找实习的认识的一个清哥吃了一顿日本料理,甚是好吃,等下次碰到他再请他吃好吃的。 再次游走在上海,还是怀着学生时代的情怀。看到豪车摆在路边,我们还是兴奋,虽然跟我们没有半毛钱关系;看到外国美女路过,高兴地手舞足蹈;毕业后奢侈一把,走进了星巴克,不是谈生意,而是为了多喝点牛奶。一年后,三年后,五年后,十年后我们的感觉应该会不越来越不一样了吧~ 再见,上海。我踏上了去厦门的动车。

    第二站厦门

    到了厦门已经是晚上8点了。天下着小雨,虽然维度比南京低很多,但是没有闷热的感觉。我打电话给峰哥,说已经到了。我们互相说了位置,果真,他胖了。峰哥是我高中同学,三年的同床,对的是同床。他住在我的上铺。不管是高一时候的509还是高二时候的203还是高三时候的209,我住下铺,他住上铺。大学他来了厦门,我去了南京,中间到时见过一次,那也是大二的十一了吧。这么多年没见,一看到他,峰哥的品味还是没有变的,牛仔裤配一个紧身短袖衫,好像高中就是这个风格了。 我在厦门呆了大概一个周左右,中间恰逢七夕,作为灯泡的我,就跑到峰哥隔壁那边睡觉去了。至于什么感想呢,就是这一天太虐狗了。出了七夕这一天,其他日子我就到处逛。看了看厦门的几所大学,厦大恬静优美,华侨气派恢弘,集美学村的独特建筑风格让人拍手叫好。 踏上去往深圳的动车,回头挥别厦门。

    第三站深圳

    深圳,很是闷热。湿热的环境给蟑螂提供了适宜的栖息条件。身上黏糊糊的感觉束缚了我的行动,蟑螂爬出来又爬进去,好像嘲笑我一般。 终于来深圳的第三天我去了南方科技大学,去看看这个2011年重大新闻事件挑战中国所有公立大学的神圣之地。可惜,外人不得入内,让我千里迢迢打了一场水漂。虽然绕着南方科技大学绕了一大半,也没能成行。最后闯进来水源保护区,被负责的工作人员赶了出来…… 从深圳,过了口岸就是香港。

    ==============================================================================

    新年计划

    新年伊始,我找到了奋斗的目标。一个志同道合的女孩可能是一剂良药,救治失去方向的大雁重新找到雁群;也是一顶巨大的警钟,不让我陷入低迷;更是未来奋斗道路上不可缺少的伙伴。想想过去混过的两年时光,也许会因为一个女孩的出现而改变。既然,已经出现了,就该好好想想如何重新开始。

    想的不如落实到纸上

    如果想的有100分,如果没有任何督促,最终能够落实的计划不到1分。好记性不如烂笔头,计划也是如此。如果记录下来时常翻看,空想往往就是空想罢了。 今年有四大任务

    数学理论。 矩阵论、随机过程还是要自学的。周二下午旁听随机过程,那么周二下午的马克思同志就得翘掉了。李老师的矩阵论倒是周一周三上午一二节,旁听倒是无妨,但是一定要早睡才好,要不然课堂上睡觉得不偿失。有上个学期的旁听经验可以知道,既然选择旁听,就要拿出学位课的热情。 英语学习。 经过多年不习英语的安逸,如今英语摧残人生。英语成绩一塌糊涂这个我就不详细说了。拿出明天是最后一天的紧张感,拼上最后的尊严,拿下它。

    • 单词量太低,当前4500左右,目标10000单词量
    • 阅读量不够。看论文常常出现看到一半就放弃了,很大程度上是语言障碍。Quora是个不错的平台
    • 听懂英语量不够。虽然听了好多英语,但是听懂的很少,更别提能够跟着说出来的。
    • 看懂听懂不如写到纸上。老套的书写方式,生搬硬套template,使用着自己仅有的几个单词,浑水摸鱼,最后啥都没捞到。 专业知识。 俗话说,做一天和尚撞一天钟。学生就该好好广泛学习,研究生就该好好深入专业知识。专业只有精通才叫专业,技术只有实践才能掌握。我是学习计算机技术的,如果不研究专业前沿,不去实践专业理论,何谈研究生。
    • 搜索知识
    • 图像知识
    • 机器学习 学会关心。 玩笑可以开,但是要掌握分寸。一个人的时候随便怎么开玩笑都可以,但是两个人的时候有些话玩笑就不能够开了。而且两个人之间特别亲密,表达关心还是必要的。
    • 关心在于细节
    • 关心在于小事儿
    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    胡思乱想:过年
    机遇 research之路其修远兮,我将上下而求索

    胡思乱想:过年


    当“过年”成为历史文化遗产

    过年,是我们小时候最期盼的事情了。现在,已经工作,当在回到老家过年,已经是另外一番景象,我不禁思绪万千,年会一直被过下去吗?

    过年,不仅仅是家人团聚,前奏很是繁琐。

    蒸馒头

    年前要蒸馒头,蒸好多馒头。在蒸馒头的日子里,母亲每天要备好老面(含有酵母菌的经过发酵的和水的面粉),称好十几斤面粉备在那里,等到三点的闹钟一响,就和父亲出发了去压面了。小时候因为觉得好玩,就跟在母亲的后面,有时候抱着老面盆子,有时候打着手电筒,卖力地迈着步子紧紧跟在母亲后面。 和面回来,紧接着就进入到做馒头的工序。母亲撕面团,揉面团,父亲、姐姐和我使用模具制作带有各种花纹的馒头————鱼、桃子、元宝是最常见的。手里的面团越来越欢快,跳到盖笺上变成了鱼、元宝…… 端着盖笺的鱼和元宝,放到暖炕上铺好放置整齐,等着再一次的发酵的完成。 等上几个小时,做好的馒头在炕头上发酵成为一个大胖子,是时候开始蒸馒头了。 蒸是极其考验一位农村妇女基本功夫的,不仅要蒸得多,还要蒸得好看。母亲有自己的独门秘诀。每一锅馒头的中间,母亲都会放置一个茶碗,茶碗比馒头高一些,茶碗的上面再放一个篦子,可以再放好多馒头,从而提高了单锅的数量。秘诀不仅仅在于数量,还在于这个茶碗,茶碗中放置的不是简单的水,而是白酒。要知道,白酒是比水更容易蒸发的。当受热时,酒精会随着水蒸汽在馒头上覆盖,形成常见馒头光滑的表面。而酒精的功效就在于能够比水更快一步形成光滑表面,使得馒头看上去更白。 大冷天的,花一整天做馒头,烧得炕滚烫,坐在上面没有两分钟屁股就疼得厉害。我时常想,这么热的炕用来烤肉也是不错的 :)

    二十年后,还会存在这种做馒头方式吗?

    炒花生、瓜子

    很小的时候,父亲还在家里炒过瓜子和花生。 只记得,当时我趴在窗户上看他们忙碌的身影,父亲手中不停地翻动着手中的木铲,锅中的瓜子随着木铲的搅动,”唰唰唰”地声响在厨房上空飘荡。 刚出锅的花生吃起来软软的,但让人上瘾般的好吃。地上的花生皮渐渐多了起来,踩在上面噼里啪啦地响,好玩极了。 现在花生瓜子直接从集市上买可以了,也许在也吃不到刚出锅的花生了。

    制作摇钱树

    所谓的摇钱树,就是一根榆树枝,挂上些许金元宝和绿叶。 榆树枝条是父亲从河边上采来的,经过简单父亲这位老果林员的修剪,更加具有了生金发财的神气。挂上我和姐姐亲手折叠的金色的元宝,然后摘几片菠菜叶子做修饰,一颗摇钱树就这样被培育成功了。 榆树又叫榆钱数树,”余钱”,象征年年有余钱。菠菜象征着农家人民的朴素与辛勤的性格,而元宝是我们的期许。

    现在,简单多了,花几十块钱买一个金色的塑料材料的摇钱树就好了。二十年后,可能会变得更漂亮,可是,其中的乐趣已经早已不在了…

    年前扫墓

    墓,是人逝去后,亲人为其所建的休憩之所。墓地杂草恒生,野兽鸟虫众多,鲜有人去。 我爷爷和奶奶的墓地,每到清明、过年、以及忌日等重要日子,父亲要去扫墓除杂草的。这些看似平常的事情,对于远在他乡工作的年轻人来说,扫墓成为一件费时、费力又感觉没有意义的事情。那个时候,到处墓地,荒草飞长,虫鸟夜鸣,可是没有一个扫墓人的踪影,过年的时候也是如此…

    到处奔跑的孩子

    爱玩,是孩子的天性;奔跑,是孩子的灵性。然而,现在的孩子在村子里已经没有奔跑的场所,有的只是代步的汽车。听,在轰鸣… 小的时候,过年回家,家人来得很多,往往都是一大家子回来。现在,家人来得少了,可是汽车却紧紧地塞紧家门口,行人出行很不方便。是有钱了,可是道路却没有了;是有钱了,可是回家的次数却少了;是有钱了,可是孩子们再也不敢再路上奔跑了;是有钱了,可是当年一起说笑的朋友却碰不到一起扯淡了… 唉~~ 几年后,村子里的老人会越来越少,车子应该不会这么多了吧;几年后,去城市打工的人 越来越多,应该不会有这么多人家还灯火通明了。

    未完待续…

    多少年后,年还是年吗?

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    菜鸟实习初体验--IN NI
    机遇 research之路其修远兮,我将上下而求索

    菜鸟实习初体验--IN NI


    前言

    National Instructions,一家外企,主要做工业通讯设备与系统解决方案。其中最为知名的产品莫过于LabView. 暑期实习招聘后期,收到NI的的实习offer很是开心。2014年7月我正式入职到2015年4月离职,在NI实习半年多,可以说是收益颇丰。真正在企业中工作过,我才真正理解书中所说的“菜鸟”。

    融入

    我和巴神(一位巴姓同学,现在应该成为大佬了)被分配到同一个组,让我这个菜鸟心安了不少。入门阶段,我们俩从熟悉常用软件LabView开始。LabVIEW作为NI起家的东西,虽然在大学课程中接触过,但是现在真正要靠它吃饭,还是花费了一方功夫。LabView总体给我的感觉是学习过程很是迅速,而且很容易实现一些设计设计模式,多线程等C++实现起来比较费劲的东西,而且丰富的插件软件,让它在不同工业企业中大显身手。实习生导师沈祥和仪俊也是很平易近人,有什么问题及时讨论和反馈,很快就在这个新的环境里适应了。

    日常工作

    日常开发过程中,采用Scrum的方式进行任务管理和跟踪,每年迭代一个大版本,但是每个大版本的 要实现什么功能,在9月份的时候就制定好,然后开始计数调研。然后就是定期一步一步地跟踪进度就可以。最忙的时候后应该是3~5月份,这个时候准备开始发版了,开始大规模测试,每天都要解决很多bug.

    在NI做开发还是蛮轻松的。加班的可能性很少,正式员工每年也就加班几天吧。实习生就没有机会体会加班了:). NI的工作氛围是很惬意的,我赶上了几次员工感谢日,一大早 大老板们 站在那里给你分精致的早餐。此外,下午三点半左右是最为欢快的时刻,员工升职小聚啊,结婚分发喜糖啊,添丁分发礼物啊。我好像吃了好多同事给的礼物啊,在这里表示感谢。

    主要工作内容

    LabVIEW DEMO 到 工业软件

    每个进入公司的成员必须要做的一个东西DEMO;“四个灯泡,随机亮,然后你根据之前亮的顺序进行点击。” 当然,我也这么做了一版。后来觉得这个游戏没有什么意思,干脆自己把游戏规则重新润化了一下,加大了游戏的难度,实现了一把。后来,我和巴瑞华合作了一个工业通讯软件ANVIL和HAMMER。这套软件简单来说相当于大学做的socket通讯软件,但是通讯协议不是使用HTTP或者TCP, UDP,而是使用一种工业通讯协议。这个DEMO制作工程中,我们才意识的,原来图形化编程并不是你想的那么easy的,要想写出漂亮的LabVIEW程序,没有 基本的编程规范是不行的。

    • 常用的可以包成子控件,记性C中的函数一样
    • 线要对齐,就行代码格式要符合公司规范一样
    • 一页内的逻辑要清楚,条例,一眼就看懂是怎么设计的

    看似简单的编程方式,也有优雅而艰难的一面。

    测试用例自动化

    手动测试的测试用例转自动化测试用例。根据测试用例的目的,如果能够进行自动化测试的,我们就转成自动化测试用例。其中还有一些测试用例需要根据SPEC文档自己实现。实现过程中有自己的LabVIEW 程序的设计思维和style已经逐渐养成,并且get到了SPEC文档的重要性。手工测试过程可能执行一遍需要几天的时间,现在只需要睡一觉即可。

    新版本技术调研——性能对比测试

    新产品处于research阶段,对性能和稳定有很高的要求。这就要求企业对技术进行相应的调研和实现,而我在其中就是助理调研实习生了。有的时候一个想法需要确认一下丢包的程度和性能情况,那我的任务就来了。期间还有一段时间还写了一个perl的抓包代码,当时看的很是兴奋,终于见识到了perl网络库的强大了。

    wireshark在这个阶段用的多了,也渐渐熟悉起来了,后来干脆自己写一个抓包程序吧,但是未经验证还是算了。 后来就去写C程序,编译成动态链接库,第一次编译shared library,第一次编写需要链接动态库的程序,第一次手动创建软连接等…

    代码检查工具

    国有国法,家有家规。写代码有写代码的规范,企业也有相应的企业规范。为了规范公司代码,我们决定实现一个代码规范检查toolkit. 这个工具作为公司交叉编译系统的插件,可以支持响应的代码风格检查。

    • clang++编译器实现抽象语法树的生成
    • python 2.7 实现检查规则的注册,和语法树的遍历检查
    • RabbitMQ作任务分发

    菜鸟实习总结

    • 好的情绪很重要,让好的情绪伴随每一天,工作、生活将充满激情。
    • 不是别人不帮你,是自己没有发出求救信号
    • 不要抱怨,抱怨只是无用功,还不如沉下心思好好想想为什么会这样
    • 每天进步一点点
    • 别人的优点值得我们学习,别人的缺点即使存在也不关乎我的事情。多多赞美别人
    • 责任是自己的就是自己的,承担下来
    • 仔细聆听他人,不可滔滔不绝
    • 真诚待人,记住别人的名字

    对了,我实习那两年,NI一直是大中华区最佳职场。

    最后总结一下:

    当每天一声早上好成为习惯,  
    一切变得自然而然。  
    好的心情让我们互相感染,    
    工作中的你我变得如此美丽灿烂。   
    

    特别感谢我的manager, Han mentor Yijun,Xiang Yiqing,Bing, Feng, Qian,Jun … 还有我的小伙伴们。

    In me the tiger sniffs the rose.

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    (5)
  • C++ Object Model
    机遇 research之路其修远兮,我将上下而求索

    C++ Object Model

    2020-04-07
    cwlseu

    前言

    面向对象的三大特征是抽象、继承、多态。《深度探索C++对象模型》一书中从数据的排布,C++对象函数的调用设计等等。 我尝试以一个编译器的设计者的角度去理解C++对象,该书中也提到了多种编译器,有的时候也会涉及一些不同编译器厂商在设计过程中的不同,虽然没有深入探究不同的原因以及优劣对比, 但对于我这个新手来说已经开了很大的窗户。

    整个书籍通过横向切割方式,分别从构造、数据成员、成员函数、运行时C++对象的特点来介绍,从缔造者的视角来理解C++对象的设计,有利于我们写出更加高效、简洁的程序。

    关于对象

    C++对象比C struct对象在空间与时间的有额外负担吗?

    封装的后布局成本与C struct是一样的。member functions虽然旱灾class的声明之内,却不出现在的object中。每一个non-inline memberfunction 只会诞生一个函数实例。 C++在布局以及存取时间上的主要的额外负担是由virtual引起的,包括:

    • virtual function机制,引入vptr以及vtbl,支持一个有效率的”执行期绑定”
    • virtual base class,用以实现”多次出现在继承体系中的base class,有一个单一而被共享的实例”
    • 多重继承下,派生类跟第二个以及后续基类之间的转换

    C++对象模型

    在C++中,有两种数据成员(class data members):static 和nonstatic,以及三种类成员函数(class member functions):static、nonstatic和virtual:

    class Base {
    public:
        Base(int i) :baseI(i){};    
        int getI(){ return baseI; } 
        static void countI(){};   //static
        virtual void print(void){ cout << "Base::print()"; } // virtual
        virtual ~Base(){}         // virtual
    private:
        int baseI;  // no static 
        static int baseS;  // static
    };
    

    在此模型下,nonstatic 数据成员被置于每一个类对象中,而static数据成员被置于类对象之外。static与nonstatic函数也都放在类对象之外,而对于virtual 函数,则通过虚函数表+虚指针来支持,具体如下:

    • 每个类生成一个表格,称为虚表(virtual table,简称vtbl)。虚表中存放着一堆指针,这些指针指向该类每一个虚函数。虚表中的函数地址将按声明时的顺序排列,不过当子类有多个重载函数时例外,后面会讨论。
    • 每个类对象都拥有一个虚表指针(vptr),由编译器为其生成。虚表指针的设定与重置皆由类的复制控制(也即是构造函数、析构函数、赋值操作符)来完成。vptr的位置为编译器决定,传统上它被放在所有显示声明的成员之后,不过现在许多编译器把vptr放在一个类对象的最前端。关于数据成员布局的内容,在后面会详细分析。
    • 另外,虚函数表的前面设置了一个指向type_info的指针,用以支持RTTI(Run Time Type Identification,运行时类型识别)。RTTI是为多态而生成的信息,包括对象继承关系,对象本身的描述等,只有具有虚函数的对象在会生成。

    @vs2015下对象的内存结构

    这个模型的优点在于它的空间和存取时间的效率;缺点如下:如果应用程序本身未改变,但当所使用的类的non static数据成员添加删除或修改时,需要重新编译。

    Note: 针对析构函数,g++中的实现有一些令人疑惑的地方,~Base在虚表中出现了两次,我表示不能理解,网上也没有找到相关说明。

    Vtable for Base
    Base::_ZTV4Base: 6u entries
    0     (int (*)(...))0
    4     (int (*)(...))(& _ZTI4Base)
    8     (int (*)(...))Base::print
    12    (int (*)(...))Base::~Base
    16    (int (*)(...))Base::~Base
    

    我猜测可能是我们使用g++编译中合成根据我添加的~Base()合成了一个用于动态内存分配释放的析构函数和静态释放的析构函数。当然如果有大佬知道这个是为什么,请务必指导一番,不胜感激。

    多重继承

    #include<iostream>
    using namespace std;
    class Base1
    {
    public:
    	virtual ~Base1() {};
    	virtual void speakClearly() {cout<<"Base1::speakClearly()"<<endl;}
    	virtual Base1 *clone() const {cout<<"Base1::clone()"<<endl; return new Base1;}
    protected:
    	float data_Base1;
    };
    class Base2
    {
    public:
    	virtual ~Base2() {};
    	virtual void mumble() {cout<<"Base2::mumble()"<<endl;}
    	virtual Base2 *clone() const {cout<<"Base2::clone()"<<endl; return new Base2;}
    protected:
    	float data_Base2;
    };
    class Derived : public Base1,public Base2
    {
    public:
    	virtual ~Derived()  {cout<<"Derived::~Derived()"<<endl;}
    	virtual Derived *clone() const {cout<<"Derived::clone()"<<endl; return new Derived;}
    protected:
    	float data_Derived;
    }
    

    @逻辑上的图

    类似问题在vs2010中也有,主要是多重继承的时,将派生类赋值给第二个基类时

    1>  Derived::$vftable@Base1@:
    1>   | &Derived_meta
    1>   |  0
    1>   0 | &Derived::{dtor}
    1>   1 | &Base1::speakClearly
    1>   2 | &Derived::clone
    1>  
    1>  Derived::$vftable@Base2@:
    1>   | -8
    1>   0 | &thunk: this-=8; goto Derived::{dtor}
    1>   1 | &Base2::mumble
    1>   2 | &thunk: this-=8; goto Base2* Derived::clone
    1>   3 | &thunk: this-=8; goto Derived* Derived::clone
    
    • 派生类的虚函数表数目是它所有基类的虚函数数目之和,基类的虚函数表被复制到派生类的对应的虚函数表中。

    • 派生类中重写基类的虚拟函数时,该被重写的函数在派生类的虚函数列表中得到更新,派生类的虚析构函数覆盖基类的虚析构函数。

    • 派生类中新增加的虚函数被添加到与第一个基类相对应的虚函数表中。

    • virtual table[1]中的clone分别为:Base2* Derived::clone 和 Derived* Derived::clone 。这里为什么会比table[0]多一个Base2* Derived::clone呢? 因为:如果将一个Derived对象地址指定给一个Base1指针或者Derived指针是,虚拟机制使用的是virtual table[0] ;如果将一个Derived对象地址指定给一个Base2指针时,虚拟机制使用的是virtual table[1]。 («C++对象模型» P164)

    构造函数

    参考链接

    MSVC应对多重继承中的thunk技术 C++对象模型详解 图说C++对象模型:对象内存布局详解 RTTI实现详解

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    上一篇 The history of C++

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    The history of C++
    机遇 research之路其修远兮,我将上下而求索

    The history of C++

    2020-04-01
    cwlseu

    前言

    在阅读C++相关的技术书籍或博客时,常常会提到一些日常开发中不常接触的名词,如cfront 2.0或者TR1等,这些名词在C++的历史发展中属于里程碑式的的名词。从C++不同时期的发展中可以看出对于程序员的开发需求逐渐满足,伴随着C++的标准的变化,编译器对语言的支持也逐渐完善。

    C++ 历史大事件

    @

    关键事件总结

    date feature details sample  
    1979 首次实现引入类的C C with Classes first implemented
    1. 新特性:类、成员函数、继承类、独立编译、公共和私有访问控制、友元、函数参数类型检查、默认参数、内联函数、赋值符号重载、构造函数、析构函数、f()相当于f(void)、调用函数和返回函数(同步机制,不是在C++中)</br> 2. 库:并发任务程序库(不是在C++中)
       
    1985 编译器cfront 1.0 1. 新特性:虚函数、函数和操作符重载引用new和delete操作符const关键词、范围解析运算符::
    2. 新加入的库:复数(complex)、字符串(string)、输入输出流(iostream)
       
    1985 《C++编程语言第一版》 The C++ Programming Language, 1st edition    
    1989 编译器cfront 2.0 1.新特性:多重继承、成员指针、保护访问控制、类型安全联接、抽象类、静态和常量成员函数、特定类的new和delete
    2. 新库:I/O 操作器
       
    1990 ANSI C++委员会成立(ANSI C++ Committee founded)      
    1990 《C++参考手册注解》 The Annotated C++ Reference Manual was released.    
    1991 ISO C++委员会成立(ISO C++ Committee founded)      
    1998 C++98 1. 新特性:运行时类型信息[RTTI(dynamic_cast, typeid)]、协变返回类型(covariant return types)、cast 操作符、可变型、布尔型、声明情况、模板例示、成员模板、导出
    2. 新库:容器、算法、迭代器、函数对象(STL中)、区域设置、位集合、值向量、自动指针(auto_ptr)、模块化字符串、输入输出流和复数
    the C++ standards committee published the first international standard for C++ ISO/IEC 14882:1998, which would be informally known as C++98. The Annotated C++ Reference Manual was said to be a large influence in the development of the standard. The Standard Template Library, which began its conceptual development in 1979, was also included.
    *****  
    1999 Boost由委员会成员成立,旨在开发新的高质量库以作为标准库的候选库 Boost founded by the committee members to produce new high-quality candidate libraries for the standard    
    2003 C++03 (ISO/IEC 14882:2003) The committee responded to multiple problems that were reported with their 1998 standard, and revised it accordingly. The changed language was dubbed C++03. 这是一个次要修订版本,修正了一些错误。    
    2006 Performance TR (ISO/IEC TR 18015:2006) (ISO Store ) (2006 draft ) 性能技术报告    
    2007 2007 Library extension TR1 (ISO/IEC TR 19768:2007) (ISO store ) (2005 draft ) 1. 源自Boost:引用包装器(Reference wrapper)智能指针(Smart pointers)、成员函数(Member function)、Result of 、绑定(Binding)、函数(Function)、类型特征(type traits)、随机(Random)、数学特殊函数(Mathematical Special Functions)、元组(Tuple)、数组(Array)、无序容器[Unordered Containers包括哈希(Hash)]还有正则表达式(Regular Expressions)
    2. 源自C99:math.h中同时也是新加入C99的数学函数、空白字符类、浮点环境(Floating-point environment)、十六进制浮点I/O操作符(hexfloat I/O Manipulator)、固定大小整数类型(fixed-size integral types)、长整型(the long long type)、va_copy、snprintf() 和vscanf()函数族,还有C99 的printf()与scanf()函数族的指定转换。 TR1除了一些特殊函数,大部分都被囊括进C++11。
    *****  
    2010 数学特殊函数技术报告[2010 Mathematical special functions TR (ISO/IEC 29124:2010)(ISO Store)] 此TR是一个C++标准库扩展,加入了TR1中的部分特殊函数,但那些函数之前没有被包括进C++11:椭圆积分、指数积分、拉盖尔多项式(Laguerre polynomials)、勒让徳多项式(Legendre polynomials)、艾尔米特多项式(Hermite polynomials)、贝塞尔(Bessel)函数、纽曼(Newmann)函数、$\beta$函数和黎曼(Riemann)$\zeta$函数    
    2011 C++11 (ISO/IEC 14882:2011) (ISO Store) (ANSI Store ) 1. 新语言特性:自动(auto)和类型获取(decltype)、默认和已删除函数(defaulted and deleted functions)、不可更改(final)和重载(override)拖尾返回类型(trailing return type)右值引用(rvalue references)移动构造函数(move constructors)/移动赋值(move assignment)、作用域枚举(scoped enums)、常量表达式(constexpr)和文字类型(literal types)、列表初始化(list initialization)、授权(delegating)和继承构造器(inherited constructors)、大括号或等号(brace-or-equal)初始化器、空指针(nullptr)、长整型(long long)、char16_t和char32_t、类型别名(type aliases)、可变参数模板(variadic templates)、广义联合体(generalized unions)、广义POD、Unicode字符串文字(Unicode string literals)、自定义文字(user-defined literals)、属性(attributes)、$\lambda$表达式(lambda expressions)、无异常(noexcept)、对齐查询(alignof)和对齐指定(alignas)、多线程内存模型(multithreaded memory model)、线程本地存储(thread-local storage)GC接口(GC interface)、range for(based on a Boost library)、静态断言[static assertions(based on a Boost library)]
    2.新库特性:原子操作库(atomic operations library)、emplace()和贯穿整个现有库的右值引用的使用、std::initializer_list、状态性的和作用域内的分配器(stateful and scoped allocators)、前向列表(forward_list)、计时库(chrono library)、分数库(ratio library)、新算法(new algorithms)、Unicode conversion facets
    3.源自TR1:除了特殊的函数,TR1中全部都被囊括进来
    4.源自Boost:线程库(The thread library)、异常指针(exception_ptr)、错误码(error_code)和错误情况(error_condition)、迭代器改进[iterator improvements(std::begin, std::end, std::next, std::prev)]
    5.源自C:C风格的Unicode转换函数
    6.搜集错误报告修复:363个错误在2008草案中被解决,另外有322个错误接着被修复。其中的错误包括530号,它使得std::basic_string对象相连。
    *****  
    2011 十进制浮点技术报告[Decimal floating-point TR (ISO/IEC TR 24733:2011) (ISO Store ) (2009 draft )] 这个TR根据IEEE 754-2008浮点算数标准(Floating Point Arithmetic):std::decimal::decimal32、std::decimal::decimal64、std::decimal::decimal128    
    2012 标准C++基金会成立 The Standard C++ Foundation founded    
    2013 《C++编程语言第四版》 The C++ Programming Language, 4th edition    
    2014 C++14 (2014 final draft ) 1. 新语言特性:变量模板(variable templates)、多态lambda(polymorphic lambdas)、λ动捕获(move capture for lambdas)、new/delete elision、常量表达式函数放宽限制(relax restrictions on constexpr functions)、二值文本(binary literals)、数字分隔符(digit separators)、函数返回类型推演(return type deduction for functions)、用大括号或等号初始符集合初始化类
    2. 新库特性:std::make_unique、std::shared_mutex和std::shared_lock、std::index_sequence、std::exchange、std::quoted,还有许多针对现有库的小改进,比如一些算法的双距离重载(two-range overloads for some algorithms)、类型特征的类型别名版本(type alias versions of type traits)、用户定义字符串(user-defined string)、持续期(duration)和复杂数字文本(complex number literals)等等
    3.搜集错误报告修复:149号库(149 library issues) 基础库技术规范(Library fundamentals TS), 文件系统技术规范(Filesystem TS)和其他专业技术规范( experimental technical specifications)
       

    不同编译器对c++标准的支持

    cfront x.x就是Bjarne Stroustrup的第一个C++编译器,将C++转换成C语言。在1993年,cfront 4.0因为尝试支持异常机制失败而被取消。我们开发者最长打交道的工具就是编译器了。我们只要通过编写程序语言,编译器会翻译成具体的更底层命令来控制计算机去实现我们的需要的功能。但C++语言标准是一个庞大的特性集合,而不同编译器厂商在根据这个统一标准做编译器的过程中,由于各种原因,不可能支持全部的标准中列举出来的特性。 例如,C++11已经流行多年,很多特性是随着编译器版本release才逐渐支持的,如下图:

    @

    参考资料

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    下一篇 C++ Object Model

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    大规模训练数据的shuffle
    机遇 research之路其修远兮,我将上下而求索

    大规模训练数据的shuffle

    2019-12-23
    cwlseu

    大规模训练数据的shuffle

    重要性12

    以猫狗分类为例, 假如数据集是

    Dog,Dog,Dog,… ,Dog,Dog,Dog,Cat,Cat,Cat,Cat,… ,Cat,Cat

    所有的狗都在猫前面,如果不shuffle,模型训练一段时间内只看到了Dog,必然会过拟合于Dog,一段时间内又只能看到Cat,必然又过拟合于Cat,这样的模型泛化能力必然很差。 那如果Dog和Cat一直交替,会不会就不过拟合了呢?

    Dog,Cat,Dog,Cat,Dog ,Cat,Dog,…

    依然会过拟合,模型是会记住训练数据路线的,为什么呢?

    当用随机梯度下降法训练神经网络时,通常的做法是洗牌数据。在纠结细节的情况下,让我们用一个极端的例子来解释为什么shuffle是有用的。假设你正在训练一个分类器来区分猫和狗,你的训练集是50,000只猫后面跟着50,000只狗。如果你不洗牌,你的训练成绩就会很差。 严格地说,这个问题是由梯度噪声中的序列相关性和参数更新的不可交换性引起的。首先我们需要明白固定的数据集顺序,意味着给定迭代步,对应此迭代步的训练数据是固定的。 假如目标函数是$J=f(w, b)$,使用梯度下降优化$J$。给定权重取值$w、b$和迭代步step的情况下,固定的数据集顺序意味着固定的训练样本,也就意味着权值更新的方向是固定的,而无顺序的数据集,意味着更新方向是随机的。所以固定的数据集顺序,严重限制了梯度优化方向的可选择性,导致收敛点选择空间严重变少,容易导致过拟合。所以模型是会记住数据路线的,所以shuffle很重要,一定shuffle。

    2-pass-shuffle算法

    我们假设一个数据集$X^m$包含样本数目为$m$, 大小为$S_{X^m}$, 计算内存RAM大小为$S_{RAM}$. 当$S_X \lt S_{RAM}$的时,我们完全可以使用训练框架中的Dataset shuffle函数进行处理,如Fisher Yates Shuffle。但我们实际应用场景中,$S_X \ggg S_{RAM}$. 本节将针对这种业务场景进行讨论。

    # https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
    def fisher_yates_shuffle(dataset=list()):
    	size = len(dataset)
    	for i in range(size-1):
    		j = random.randint(i, size-1)
    		dataset[i], dataset[j] = dataset[j], dataset[i]
    

    分块是一种很普遍的想法,但是如何分块,以及分块后如何随机地写回到文件中才是最终目标。而且要注意的是,数据集$X^m$的每一次访问都存在大量的IO,将非常耗时。因此,设计随机算法的过程中,IO也要考虑在内。

    2-pass-shuffle算法过程中包括块id的shuffle和块内部的shuffle. Fisher Yates算法和 twice pass shuffle算法如下。

    需要自己设置一个超参数$M$, 直观上需要满足的条件:

    python代码模拟实现如下:

    import os
    import random
    
    # https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
    def fisher_yates_shuffle(dataset=list()):
    	size = len(dataset)
    	for i in range(size-1):
    		j = random.randint(i, size-1)
    		dataset[i], dataset[j] = dataset[j], dataset[i]
    
    def twice_pass_shuffle(dataset, total_size, M):
    	# first pass
    	p = [[] for _ in range(M)]
    	for i in range(total_size):
    		j = random.randint(0, M-1)
    		p[j].append(dataset[i])
    	# second pass
    	result = []
    	for j in range(M):
    		fisher_yates_shuffle(p[j])
    		result.extend(p[j])
    	return result
    
    if __name__ == '__main__':
    	l = [i for i in range(1,101)]
    	print("befor shuffle:\n", l)
    	result = twice_pass_shuffle(l, total_size=100, M=10)
    	print("\nshuffle result:\n", result)
    

    当我面对这个问题的时候,第一次并没有给出这个答案,第二次才给出接近这个算法的答案。 之前的算法分M块,然后M块之间两两洗牌,进行$\frac{M(M-1)}{2}$次。这个方法看上去好像可以,但是存在以下问题:

    • IO次数太多,性能应该不好
    • 两块之间怎么洗牌的算法决定这shuffle的结果是否随机,而且当时我并没有给出比较好的洗牌策略。

    2-pass-shuffle的其他问题处理

    还有可能遇到的问题就是第一次pass过程中,每个分块的数据并不是相等的,很有可能有那么一两块的大小比$S_{RAM}$大,导致后面不能进行内存内shuffle. 这个问题在how to shuffle a big dataset3这篇文章中有一个解决方案。其实还有简单粗暴的方案就是针对这个特殊的分块进行单独处理,再进行一次类似的2-pass-shuffle就是了。

    如何训练过程中,随机从一个超大数据集合中获取训练数据4

    The Dataset.shuffle() implementation is designed for data that could be shuffled in memory; we’re considering whether to add support for external-memory shuffles, but this is in the early stages. In case it works for you, here’s the usual approach we use when the data are too large to fit in memory:

    1. Randomly shuffle the entire data once using a MapReduce/Spark/Beam/etc. job to create a set of roughly equal-sized files (“shards”).
    2. In each epoch:
      • Randomly shuffle the list of shard filenames, using Dataset.list_files(...).shuffle(num_shards).
      • Use dataset.interleave(lambda filename: tf.data.TextLineDataset(filename), cycle_length=N) to mix together records from N different shards.
      • Use dataset.shuffle(B) to shuffle the resulting dataset. Setting B might require some experimentation, but you will probably want to set it to some value larger than the number of records in a single shard.

    参考地址

    1. https://juejin.im/post/5c6b989bf265da2ddd4a5261 “数据集shuffle的重要性” 

    2. https://blog.janestreet.com/how-to-shuffle-a-big-dataset/#whyshuffle “why shuffle” 

    3. https://blog.janestreet.com/how-to-shuffle-a-big-dataset “how to shuffle a big dataset” 

    4. https://github.com/tensorflow/tensorflow/issues/14857 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    下一篇 The history of C++

    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Inference Framework based TensorRT
    机遇 research之路其修远兮,我将上下而求索

    Inference Framework based TensorRT

    2019-11-20
    cwlseu

    引言

    视觉算法经过几年高速发展,大量的算法被提出。为了能真正将算法在实际应用场景中更好地应用,高性能的 inference框架层出不穷。从手机端上的ncnn到tf-lite,NVIDIA在cudnn之后,推出专用于神经网络推理的TensorRT. 经过几轮迭代,支持的操作逐渐丰富,补充的插件已经基本满足落地的需求。笔者觉得,尤其是tensorrt 5.0之后,无论是接口还是使用samples都变得非常方便集成。

    版本选型与基本概念

    FP16 INT8

    The easiest way to benefit from mixed precision in your application is to take advantage of the support for FP16 and INT8 computation in NVIDIA GPU libraries. Key libraries from the NVIDIA SDK now support a variety of precisions for both computation and storage.

    Table shows the current support for FP16 and INT8 in key CUDA libraries as well as in PTX assembly and CUDA C/C++ intrinsics.

    Feature FP16x2 INT8/16 DP4A/DP2A
    PTX instructions CUDA 7.5 CUDA 8
    CUDA C/C++ intrinsics CUDA 7.5 CUDA 8
    cuBLAS GEMM CUDA 7.5 CUDA 8
    cuFFT CUDA 7.5 I/O via cuFFT callbacks
    cuDNN 5.1 6
    TensorRT v1 v2 Tech Preview

    PTX

    PTX(parallel-thread-execution,并行线程执行) 预编译后GPU代码的一种形式,开发者可以通过编译选项 “-keep”选择输出PTX代码,当然开发人员也可以直接编写PTX级代码。另外,PTX是独立于GPU架构的,因此可以重用相同的代码适用于不同的GPU架构。 具体可参考CUDA-PDF之《PTX ISA reference document》

    建议我们的CUDA 版本为CUDA 8.0以上, 显卡至少为GeForce 1060, 如果想支持Int8/DP4A等feature,还是需要RTX 1080或者P40

    TensorRT特性助力高性能算法

    优化原理

    @优化原理

    网络模型的裁剪与重构

    @原始网络

    @vertical fusion

    The above figures explain the vertical fusion optimization that TRT does. The Convolution (C), Bias(B) and Activation(R, ReLU in this case) are all collapsed into one single node (implementation wise this would mean a single CUDA kernel launch for C, B and R).

    @horizontal fusion

    There is also a horizontal fusion where if multiple nodes with same operation are feeding to multiple nodes then it is converted to one single node feeding multiple nodes. The three 1x1 CBRs are fused to one and their output is directed to appropriate nodes. Other optimizations Apart from the graph optimizations, TRT, through experiments and based on parameters like batch size, convolution kernel(filter) sizes, chooses efficient algorithms and kernels(CUDA kernels) for operations in network.

    低精度计算的支持

    • FP16 & Int8指令的支持
    • DP4A(Dot Product of 4 8-bits Accumulated to a 32-bit)

    TensorRT 进行优化的方式是 DP4A (Dot Product of 4 8-bits Accumulated to a 32-bit),如下图:

    @DP4A原理过程 这是PASCAL 系列GPU的硬件指令,INT8卷积就是使用这种方式进行的卷积计算。更多关于DP4A的信息可以参考Mixed-Precision Programming with CUDA 8

    INT8 vector dot products (DP4A) improve the efficiency of radio astronomy cross-correlation by a large factor compared to FP32 computation.

    @INT8 vector dot products (DP4A) improve the efficiency of radio astronomy cross-correlation by a large factor compared to FP32 computation

    硬件方面Tensor Core的支持,优化卷积运算

    这个需要硬件的支持,如果没有类似Volta架构的GPU就不要强求。

    Framework TODO SCHEDULE

    • model load sample 模型初始化当前包括通过parser初始化和通过模型流初始化的方式。通过parser初始化过程相比较来说比较慢,因为包含parser过程
      • caffe model
      • gie model
    • plugin & extend layers
    • int8 quantity inference
      • 矫正算法的设计
      • 量化数据集合的管理,这个可以和NNIE的量化数据统一起来管理
      • 与研究侧共同确定各个层量化的范围
      • 最后更新inference模式

    Document for Reference

    附录

    Init.CaffeModel

    [I] Output "prob": 1000x1x1
    [I] [TRT] Applying generic optimizations to the graph for inference.
    [I] [TRT] Original: 141 layers
    [I] [TRT] After dead-layer removal: 141 layers
    [I] [TRT] After scale fusion: 141 layers
    [I] [TRT] Fusing conv1/7x7_s2 with conv1/relu_7x7
    [I] [TRT] Fusing conv2/3x3_reduce with conv2/relu_3x3_reduce
    。。。
    [I] [TRT] Fusing inception_5b/pool_proj with inception_5b/relu_pool_proj
    [I] [TRT] After vertical fusions: 84 layers
    [I] [TRT] After swap: 84 layers
    [I] [TRT] After final dead-layer removal: 84 layers
    [I] [TRT] Merging layers: inception_3a/1x1 + inception_3a/relu_1x1 || inception_3a/3x3_reduce + inception_3a/relu_3x3_reduce || inception_3a/5x5_reduce + inception_3a/relu_5x5_reduce
    [I] [TRT] Merging layers: inception_3b/1x1 + inception_3b/relu_1x1 || inception_3b/3x3_reduce + inception_3b/relu_3x3_reduce || inception_3b/5x5_reduce + inception_3b/relu_5x5_reduce
    。。。
    [I] [TRT] Merging layers: inception_5b/1x1 + inception_5b/relu_1x1 || inception_5b/3x3_reduce + inception_5b/relu_3x3_reduce || inception_5b/5x5_reduce + inception_5b/relu_5x5_reduce
    [I] [TRT] After tensor merging: 66 layers
    [I] [TRT] Eliminating contatenation inception_3a/output
    [I] [TRT] Generating copy for inception_3a/1x1 + inception_3a/relu_1x1 || inception_3a/3x3_reduce + inception_3a/relu_3x3_reduce || inception_3a/5x5_reduce + inception_3a/relu_5x5_reduce to inception_3a/output
    [I] [TRT] Retargeting inception_3a/3x3 to inception_3a/output
    [I] [TRT] Retargeting inception_3a/5x5 to inception_3a/output
    [I] [TRT] Retargeting inception_3a/pool_proj to inception_3a/output
    [I] [TRT] Eliminating contatenation inception_3b/output
    [I] [TRT] Generating copy for inception_3b/1x1 + inception_3b/relu_1x1 || inception_3b/3x3_reduce + inception_3b/relu_3x3_reduce || inception_3b/5x5_reduce + inception_3b/relu_5x5_reduce to inception_3b/output
    [I] [TRT] Retargeting inception_3b/3x3 to inception_3b/output
    [I] [TRT] Retargeting inception_3b/5x5 to inception_3b/output
    [I] [TRT] Retargeting inception_3b/pool_proj to inception_3b/output
    [I] [TRT] Eliminating contatenation inception_4a/output
    [I] [TRT] Generating copy for inception_4a/1x1 + inception_4a/relu_1x1 || inception_4a/3x3_reduce + inception_4a/relu_3x3_reduce || inception_4a/5x5_reduce + inception_4a/relu_5x5_reduce to inception_4a/output
    [I] [TRT] Retargeting inception_4a/3x3 to inception_4a/output
    [I] [TRT] Retargeting inception_4a/5x5 to inception_4a/output
    [I] [TRT] Retargeting inception_4a/pool_proj to inception_4a/output
    [I] [TRT] Eliminating contatenation inception_4b/output
    [I] [TRT] Generating copy for inception_4b/1x1 + inception_4b/relu_1x1 || inception_4b/3x3_reduce + inception_4b/relu_3x3_reduce || inception_4b/5x5_reduce + inception_4b/relu_5x5_reduce to inception_4b/output
    [I] [TRT] Retargeting inception_4b/3x3 to inception_4b/output
    [I] [TRT] Retargeting inception_4b/5x5 to inception_4b/output
    [I] [TRT] Retargeting inception_4b/pool_proj to inception_4b/output
    [I] [TRT] Eliminating contatenation inception_4c/output
    [I] [TRT] Generating copy for inception_4c/1x1 + inception_4c/relu_1x1 || inception_4c/3x3_reduce + inception_4c/relu_3x3_reduce || inception_4c/5x5_reduce + inception_4c/relu_5x5_reduce to inception_4c/output
    [I] [TRT] Retargeting inception_4c/3x3 to inception_4c/output
    [I] [TRT] Retargeting inception_4c/5x5 to inception_4c/output
    [I] [TRT] Retargeting inception_4c/pool_proj to inception_4c/output
    [I] [TRT] Eliminating contatenation inception_4d/output
    [I] [TRT] Generating copy for inception_4d/1x1 + inception_4d/relu_1x1 || inception_4d/3x3_reduce + inception_4d/relu_3x3_reduce || inception_4d/5x5_reduce + inception_4d/relu_5x5_reduce to inception_4d/output
    [I] [TRT] Retargeting inception_4d/3x3 to inception_4d/output
    [I] [TRT] Retargeting inception_4d/5x5 to inception_4d/output
    [I] [TRT] Retargeting inception_4d/pool_proj to inception_4d/output
    [I] [TRT] Eliminating contatenation inception_4e/output
    [I] [TRT] Generating copy for inception_4e/1x1 + inception_4e/relu_1x1 || inception_4e/3x3_reduce + inception_4e/relu_3x3_reduce || inception_4e/5x5_reduce + inception_4e/relu_5x5_reduce to inception_4e/output
    [I] [TRT] Retargeting inception_4e/3x3 to inception_4e/output
    [I] [TRT] Retargeting inception_4e/5x5 to inception_4e/output
    [I] [TRT] Retargeting inception_4e/pool_proj to inception_4e/output
    [I] [TRT] Eliminating contatenation inception_5a/output
    [I] [TRT] Generating copy for inception_5a/1x1 + inception_5a/relu_1x1 || inception_5a/3x3_reduce + inception_5a/relu_3x3_reduce || inception_5a/5x5_reduce + inception_5a/relu_5x5_reduce to inception_5a/output
    [I] [TRT] Retargeting inception_5a/3x3 to inception_5a/output
    [I] [TRT] Retargeting inception_5a/5x5 to inception_5a/output
    [I] [TRT] Retargeting inception_5a/pool_proj to inception_5a/output
    [I] [TRT] Eliminating contatenation inception_5b/output
    [I] [TRT] Generating copy for inception_5b/1x1 + inception_5b/relu_1x1 || inception_5b/3x3_reduce + inception_5b/relu_3x3_reduce || inception_5b/5x5_reduce + inception_5b/relu_5x5_reduce to inception_5b/output
    [I] [TRT] Retargeting inception_5b/3x3 to inception_5b/output
    [I] [TRT] Retargeting inception_5b/5x5 to inception_5b/output
    [I] [TRT] Retargeting inception_5b/pool_proj to inception_5b/output
    [I] [TRT] After concat removal: 66 layers
    [I] [TRT] Graph construction and optimization completed in 0.00874238 seconds.
    [I] [TRT] 
    [I] [TRT] --------------- Timing conv1/7x7_s2 + conv1/relu_7x7(3)
    [I] [TRT] Tactic 0 time 0.370688
    [I] [TRT] 
    [I] [TRT] --------------- Timing conv1/7x7_s2 + conv1/relu_7x7(14)
    [I] [TRT] Tactic 3146172331490511787 time 0.694752
    [I] [TRT] Tactic 3528302785056538033 time 0.429056
    [I] [TRT] Tactic -6618588952828687390 time 0.419296
    [I] [TRT] Tactic -6362554771847758902 time 0.371168
    [I] [TRT] Tactic -2701242286872672544 time 0.685056
    [I] [TRT] Tactic -675401754313066228 time 0.365568
    [I] [TRT] 
    。。。
    [I] [TRT] Tactic 5 time 0.032192
    [I] [TRT] 
    [I] [TRT] --------------- Timing loss3/classifier(15)
    [I] [TRT] Tactic 2624962759642542471 time 0.07424
    [I] [TRT] Tactic 6241535668063793554 time 0.094688
    [I] [TRT] Tactic 8292480392881939394 time 0.074752
    [I] [TRT] Tactic 8436800165353340181 time 0.059936
    [I] [TRT] Tactic -7597689592892725774 time 0.09216
    [I] [TRT] --------------- Chose 6 (5)
    [I] [TRT] 
    [I] [TRT] --------------- Timing prob(11)
    [I] [TRT] Tactic 0 is the only option, timing skipped
    [I] [TRT] Formats and tactics selection completed in 10.0197 seconds.
    [I] [TRT] After reformat layers: 66 layers
    [I] [TRT] Block size 1073741824
    [I] [TRT] Block size 12845056
    [I] [TRT] Block size 9633792
    [I] [TRT] Block size 3211264
    [I] [TRT] Block size 3211264
    [I] [TRT] Total Activation Memory: 1102643200
    [I] [TRT] Detected 1 input and 1 output network tensors.
    [I] [TRT] Data initialization and engine generation completed in 0.0458818 seconds.
    loadmodel time: 10322 ms
    infer time: 8.20 ms
    

    Init.GIEModel

    [I] [TRT] Glob Size is 40869280 bytes.
    [I] [TRT] Added linear block of size 3211264
    [I] [TRT] Added linear block of size 2408448
    [I] [TRT] Added linear block of size 802816
    [I] [TRT] Added linear block of size 802816
    [I] [TRT] Deserialize required 13227 microseconds.
    [I] googlenet_gie.bin has been successfully loaded.
    loadmodel time: 36 ms
    infer time: 2.80 ms
    

    IPlugin接口中需要被重载的函数

    1) 确定输出:一个是通过int getNbOutput()得到output输出的数目,即用户所定义的一层有几个输出。另一个是通过Dims getOutputDimensions (int index, const Dims* inputs, int nbInputDims) 得到整个输出的维度信息,大家可能不一定遇到有多个输出,一般来讲只有一个输出,但是大家在做检测网络的时候可能会遇到多个输出,一个输出是实际的检测目标是什么,另一个输出是目标的数目,可能的过个输出需要设定Dimension的大小。

    2) 层配置:通过void configure() 实现构建推断(Inference) engine时模型中相应的参数大小等配置,configure()只是在构建的时候调用,这个阶段确定的东西是在运行时作为插件参数来存储、序列化/反序列化的。

    3) 资源管理:通过void Initialize()来进行资源的初始化,void terminate()来销毁资源,甚至中间可能会有一些临时变量,也可以使用这两个函数进行初始化或销毁。需要注意的是,void Initialize()和void terminate()是在整个运行时都被调用的,并不是做完一次推断(Inference)就去调用terminate。相当于在线的一个服务,服务起的时候会调用void Initialize(),而服务止的时候调用void terminate(),但是服务会进进出出很多sample去做推断(Inference)。

    4) 执行(Execution):void enqueue()来定义用户层的操作

    5) 序列化和反序列化:这个过程是将层的参数写入到二进制文件中,需要定义一些序列化的方法。通过size_t getSerializationSize()获得序列大小,通过void serialize()将层的参数序列化到缓存中,通过PluginSample()从缓存中将层参数反序列化。需要注意的是,TensorRT没有单独的反序列化的API,因为不需要,在实习构造函数的时候就完成了反序列化的过程

    6) 从Caffe Parser添加Plugin:首先通过Parsernvinfer1::IPlugin* createPlugin()实现nvcaffeparser1::IPlugin 接口,然后传递工厂实例到ICaffeParser::parse(),Caffe的Parser才能识别

    7) 运行时创建插件:通过IPlugin* createPlugin()实现nvinfer1::IPlugin接口,传递工厂实例到IInferRuntime::deserializeCudaEngine()

    TensorRT 中已经实现的Plugin

    打开verbose logger之后可以看到如下输出,相关的调用接口如下:

    [V] [TRT] Plugin Creator registration succeeded - GridAnchor_TRT
    [V] [TRT] Plugin Creator registration succeeded - NMS_TRT
    [V] [TRT] Plugin Creator registration succeeded - Reorg_TRT
    [V] [TRT] Plugin Creator registration succeeded - Region_TRT
    [V] [TRT] Plugin Creator registration succeeded - Clip_TRT
    [V] [TRT] Plugin Creator registration succeeded - LReLU_TRT
    [V] [TRT] Plugin Creator registration succeeded - PriorBox_TRT
    [V] [TRT] Plugin Creator registration succeeded - Normalize_TRT
    [V] [TRT] Plugin Creator registration succeeded - RPROI_TRT
    [V] [TRT] Plugin Creator registration succeeded - BatchedNMS_TRT
    
    extern "C" {
    //!
    //! \brief Create a plugin layer that fuses the RPN and ROI pooling using user-defined parameters.
    //! Registered plugin type "RPROI_TRT". Registered plugin version "1".
    //! \param featureStride Feature stride.
    //! \param preNmsTop Number of proposals to keep before applying NMS.
    //! \param nmsMaxOut Number of remaining proposals after applying NMS.
    //! \param iouThreshold IoU threshold.
    //! \param minBoxSize Minimum allowed bounding box size before scaling.
    //! \param spatialScale Spatial scale between the input image and the last feature map.
    //! \param pooling Spatial dimensions of pooled ROIs.
    //! \param anchorRatios Aspect ratios for generating anchor windows.
    //! \param anchorScales Scales for generating anchor windows.
    //!
    //! \return Returns a FasterRCNN fused RPN+ROI pooling plugin. Returns nullptr on invalid inputs.
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createRPNROIPlugin(int featureStride, int preNmsTop,
                                                                    int nmsMaxOut, float iouThreshold, float minBoxSize,
                                                                    float spatialScale, nvinfer1::DimsHW pooling,
                                                                    nvinfer1::Weights anchorRatios, nvinfer1::Weights anchorScales);
    
    //!
    //! \brief The Normalize plugin layer normalizes the input to have L2 norm of 1 with scale learnable.
    //! Registered plugin type "Normalize_TRT". Registered plugin version "1".
    //! \param scales Scale weights that are applied to the output tensor.
    //! \param acrossSpatial Whether to compute the norm over adjacent channels (acrossSpatial is true) or nearby spatial locations (within channel in which case acrossSpatial is false).
    //! \param channelShared Whether the scale weight(s) is shared across channels.
    //! \param eps Epsilon for not diviiding by zero.
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createNormalizePlugin(const nvinfer1::Weights* scales, bool acrossSpatial, bool channelShared, float eps);
    
    //!
    //! \brief The PriorBox plugin layer generates the prior boxes of designated sizes and aspect ratios across all dimensions (H x W).
    //! PriorBoxParameters defines a set of parameters for creating the PriorBox plugin layer.
    //! Registered plugin type "PriorBox_TRT". Registered plugin version "1".
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createPriorBoxPlugin(nvinfer1::plugin::PriorBoxParameters param);
    
    //!
    //! \brief The Grid Anchor Generator plugin layer generates the prior boxes of
    //! designated sizes and aspect ratios across all dimensions (H x W) for all feature maps.
    //! GridAnchorParameters defines a set of parameters for creating the GridAnchorGenerator plugin layer.
    //! Registered plugin type "GridAnchor_TRT". Registered plugin version "1".
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createAnchorGeneratorPlugin(nvinfer1::plugin::GridAnchorParameters* param, int numLayers);
    
    //!
    //! \brief The DetectionOutput plugin layer generates the detection output based on location and confidence predictions by doing non maximum suppression.
    //! DetectionOutputParameters defines a set of parameters for creating the DetectionOutput plugin layer.
    //! Registered plugin type "NMS_TRT". Registered plugin version "1".
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createNMSPlugin(nvinfer1::plugin::DetectionOutputParameters param);
    
    //!
    //! \brief The LReLu plugin layer performs leaky ReLU for 4D tensors. Give an input value x, the PReLU layer computes the output as x if x > 0 and negative_slope //! x if x <= 0.
    //! Registered plugin type "LReLU_TRT". Registered plugin version "1".
    //! \param negSlope Negative_slope value.
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createLReLUPlugin(float negSlope);
    
    //!
    //! \brief The Reorg plugin reshapes input of shape CxHxW into a (C*stride*stride)x(H/stride)x(W/stride) shape, used in YOLOv2.
    //! It does that by taking 1 x stride x stride slices from tensor and flattening them into (stridexstride) x 1 x 1 shape.
    //! Registered plugin type "Reorg_TRT". Registered plugin version "1".
    //! \param stride Strides in H and W, it should divide both H and W. Also stride * stride should be less than or equal to C.
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createReorgPlugin(int stride);
    
    //!
    //! \brief The Region plugin layer performs region proposal calculation: generate 5 bounding boxes per cell (for yolo9000, generate 3 bounding boxes per cell).
    //! For each box, calculating its probablities of objects detections from 80 pre-defined classifications (yolo9000 has 9416 pre-defined classifications,
    //! and these 9416 items are organized as work-tree structure).
    //! RegionParameters defines a set of parameters for creating the Region plugin layer.
    //! Registered plugin type "Region_TRT". Registered plugin version "1".
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createRegionPlugin(nvinfer1::plugin::RegionParameters params);
    
    //!
    //! \brief The Clip Plugin performs a clip operation on the input tensor. It
    //! clips the tensor values to a specified min and max. Any value less than clipMin are set to clipMin.
    //! Any values greater than clipMax are set to clipMax. For example, this plugin can be used
    //! to perform a Relu6 operation by specifying clipMin=0.0 and clipMax=6.0
    //! Registered plugin type "Clip_TRT". Registered plugin version "1".
    //! \param layerName The name of the TensorRT layer.
    //! \param clipMin The minimum value to clip to.
    //! \param clipMax The maximum value to clip to.
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createClipPlugin(const char* layerName, float clipMin, float clipMax);
    
    //!
    //! \brief The BatchedNMS Plugin performs non_max_suppression on the input boxes, per batch, across all classes.
    //! It greedily selects a subset of bounding boxes in descending order of
    //! score. Prunes away boxes that have a high intersection-over-union (IOU)
    //! overlap with previously selected boxes. Bounding boxes are supplied as [y1, x1, y2, x2],
    //! where (y1, x1) and (y2, x2) are the coordinates of any
    //! diagonal pair of box corners and the coordinates can be provided as normalized
    //! (i.e., lying in the interval [0, 1]) or absolute.
    //! The plugin expects two inputs.
    //! Input0 is expected to be 4-D float boxes tensor of shape [batch_size, num_boxes,
    //! q, 4], where q can be either 1 (if shareLocation is true) or num_classes.
    //! Input1 is expected to be a 3-D float scores tensor of shape [batch_size, num_boxes, num_classes]
    //! representing a single score corresponding to each box.
    //! The plugin returns four outputs.
    //! num_detections : A [batch_size] int32 tensor indicating the number of valid
    //! detections per batch item. Can be less than keepTopK. Only the top num_detections[i] entries in
    //! nmsed_boxes[i], nmsed_scores[i] and nmsed_classes[i] are valid.
    //! nmsed_boxes : A [batch_size, max_detections, 4] float32 tensor containing
    //! the co-ordinates of non-max suppressed boxes.
    //! nmsed_scores : A [batch_size, max_detections] float32 tensor containing the
    //! scores for the boxes.
    //! nmsed_classes :  A [batch_size, max_detections] float32 tensor containing the
    //! classes for the boxes.
    //!
    //! Registered plugin type "BatchedNMS_TRT". Registered plugin version "1".
    //!
    TENSORRTAPI nvinfer1::IPluginV2* createBatchedNMSPlugin(nvinfer1::plugin::NMSParameters param);
    
    //!
    //! \brief Initialize and register all the existing TensorRT plugins to the Plugin Registry with an optional namespace.
    //! The plugin library author should ensure that this function name is unique to the library.
    //! This function should be called once before accessing the Plugin Registry.
    //! \param logger Logger object to print plugin registration information
    //! \param libNamespace Namespace used to register all the plugins in this library
    //!
    TENSORRTAPI bool initLibNvInferPlugins(void* logger, const char* libNamespace);
    

    https://medium.com/@r7vme/converting-neural-network-to-tensorrt-part-1-using-existing-plugins-edd9c2b9e42a

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    自然场景文本检测与识别
    机遇 research之路其修远兮,我将上下而求索

    自然场景文本检测与识别

    2019-08-09
    cwlseu

    引言

    基于深度学习算法的的自然场景文本检测,经过几年的研究,针对解决实际问题中的某些问题,涌现出CTC, LSTM等大量的单元。在深度学习之前,已经有大量的优秀工作如SWT,MSER等算法被提出,这里我将先对一些OCR领域的经典作品进行介绍,然后再引入OCR中的深度学习算法。

    经典算法在OCR应用中的问题[^9]

    • 文本定位,尤其是非水平的文本定位问题,例如SWT算子是比较常用的文本定位算法,但针对非水平文本定位存在一定的局限性。
    • 无法处理序列不定长的问题
    • 文字大小不一的问题

    开源数据集合

    @数据集合用途统计

    @数据集合标注属性统计

    SWT算子1

    下面根据原文的结构和上述提供的代码详细的解读一下该算法。总的来说该算法分为四步:

    • 利用canny算子检测图片的边界
    • 笔画宽度变换-Stroke Width Transform(这一步输出的图像我们称为SWT图像)
    • 通过SWT图像得到多个连通域
    • 通过自定义的规则过滤一些连通域,得到候选连通域
    • 将连通域合并得到文本行

    Step 1:利用canny算子检测图片的边界

    这步不用多说,基础的图像处理知识,利用OpenCV 的Canny函数可以得到图片边缘检测的结果。

    Step 2:笔画宽度变换(Stroke Width Transform)

    这一步输出图像和输入图像大小一样,只是输出图像像素为笔画的宽度,具体如下。

    如上图所示,通过边缘检测得到上图a,假设现在从边缘上的点p开始,根据p点梯度的反方向找到边缘另一边的点q,如果p点的梯度与q点梯度的反方向夹角在$\pm\pi/6$之间,那么这两点间的距离为一个笔画宽度,那么p点和q点以及它们之间的像素在SWT输出图像中对应位置的值为p和q点的距离大小。

    按照上述的计算方法会有两种情况需要考虑。如下图所示,

    下图a表示一个笔画中的像素可能得到两个笔画宽度,这种情况下将红点出的笔画宽度设置为最小的那个值,下图b表示当一个笔画出现更为复杂情况,b图中的红点计算出的两个笔画宽度用两个红线表示,这两红线都无法真正表示笔画的宽度,这时候笔画宽度取这里面所有像素计算得到的笔画宽度的中值作为红点出的笔画宽度。

    因为有文字比背景更亮和背景比文字更亮两种情况,这样会导致边缘的梯度方向相反,所以这一个步骤要执行两遍。这个步骤结束后得到一张SWT图像。

    Step 3:通过SWT图像得到多个连通域

    在通过上述步骤得到SWT输出图像后,该图像大小与原图像大小一致,图像中的像素值为对应像素所在笔画的宽度(下面称为SWT值)。现将相邻像素SWT值比不超过3.0的归为一个连通域。这样就能得到多个连通域。

    Step 4:过滤连通域

    上述步骤输出的多个连通域中,并不是所有的连通域都被认为是笔画候选区域,需要过滤一些噪声的影响,过滤的规则有:

    • 如果某连通域的方差过大(方差大于连通域的一半为方差过大为过大),则认为该连通域不是有效的
    • 如果某连通域过大(宽大于300)或者过小(宽小于10),则认为该连通域不是有效的(代码中只过滤了过大的连通域,连通域的长宽为连通域外接矩形的长宽)
    • 如果某连通域的长宽比不在0.1-10的范围内,则认为该连通域不是有效的(连通域的长宽为连通域外接矩形的长宽)
    • 如果某连通域的外接矩形包含其他两个连通域,则认为该连通域不是有效的(代码中判定,如果某个连通域的外接矩形包含两个或两个以上连通域外接矩形的中心时,认为其包含了两个连通域) 上述条件都满足的连通域,认为是笔画候选区域,用于输入给下一步操作。

    Step 5:将连通域合并得到文本行

    文中认为,在自然场景中,一般不会只有单个字母出现,所有将连通域合并为文本有利于进一步将噪声排除。

    当两个连通域满足下面条件时,认为这两个连通域是一对:

    • 两个连通域中值的比小于2.0(连通域中值,指的是连通域中所有像素值的中值)
    • 两个连通域高的比小于2.0(连通域的高,指其外界矩形的高)
    • 两个连通域之间的距离小于较宽的连通域宽度的3倍(连通域之间的距离为连通域外界矩形中心点之间的距离)
    • 两个连通域的颜色相似(代码用两个连通域对应于原图区域的像素均值代表该连通域的颜色)

    得到两两连通域组成的多对连通域后,如果有两对连通域有共享的连通域,共享的连通域都在连通域对的一端(即连通域的首端或者尾端),且方向相同(方向用一个连通域中心到另一个连通域中心的方向),就将这两对连通域合并为一个新的连通域组,依次进行,知道没有连通域对需要合并则合并结束。

    最后将合并完的结果中滤除小于3的连通域的连通域组得到的最终结果,认为是一行文字。

    最大极值稳定区域MSER分析2

    最大稳定极值区域MSER是一种类似分水岭图像的分割与匹配算法,它具有仿射不变性。极值区域反映的就是集合中的像素灰度值总大于或小于其邻域区域像素的灰度值。对于最大稳定区域,通过局部阈值集操作,区域内的像素数量变化是最小的。

    MSER的基本原理是对一幅灰度图像(灰度值为0~255)取阈值进行二值化处理,阈值从0到255依次递增。阈值的递增类似于分水岭算法中的水面的上升,随着水面的上升,有一些较矮的丘陵会被淹没,如果从天空往下看,则大地分为陆地和水域两个部分,这类似于二值图像。在得到的所有二值图像中,图像中的某些连通区域变化很小,甚至没有变化,则该区域就被称为最大稳定极值区域。这类似于当水面持续上升的时候,有些被水淹没的地方的面积没有变化。

    上述做法只能检测出灰度图像的黑色区域,不能检测出白色区域,因此还需要对原图进行反转,然后再进行阈值从0~255的二值化处理过程。这两种操作又分别称为MSER+和MSER-。

    MSER是当前认为性能最好的仿射不变性区域的检测方法,其使用不同灰度阈值对图像进行二值化来得到最稳定区域,表现特征有以下三点:

    • 对图像灰度仿射变化具有不变性,
    • 对区域支持相对灰度变化具有稳定性,
    • 对区域不同精细程度的大小区域都能进行检测。

    MSER最大极值稳定区域的提取步骤:

    • 像素点排序
    • 极值区域生成
    • 稳定区域判定
    • 区域拟合
    • 区域归一化

    HMM & CTC

    问题

    序列学习任务需要从未分割的输入数据中预测序列的结果。HMM模型与CRF模型是序列标签任务中主要使用的框架,这些方法对于许多问题已经获得了较好的效果,但是它们也有缺点:

    • 需要大量任务相关的知识,例如,HMM中的状态模型,CRF中的输入特征选择
    • 需要有独立性假设作为支撑;
    • 对于标准的HMM模型,它是生成式的,但是序列标签时判别式的。

    RNN网络除了输入与输出的表达方式需要选择之外不需要任何数据的先验。 它可以进行判别训练,它的内部状态为构建时间序列提供了强大的通用机制。 此外,其对时间和空间噪声具有很强的鲁棒性。

    但是对于RNN呢,它是不能拿来做序列预测的,这是因为RNN只能去预测一些独立标签的分类,因而就需要进行序列预分割。要解决该问题,那么将RNN与HMM结合起来被称之为hybrid approach。在该方法中使用HMM为长序列结构数据建立模型,神经网络就提供局部分类。加入HMM之后可以使得在训练中自动分割序列,并且将原本的网络分类转换到标签序列。然而,它并没有避免上述内容中HMM使用缺点。

    引入CTC

    CTC( Connectionist Temporal Classification),可以解决前面提到的两点局限,直接使用序列进行训练。CTC引入了一个新的损失函数,可以使得RNN网络可以直接使用未切分的序列记性训练。为了使用这个损失函数, 为RNN引入其可以输出的”BLANK”标签, RNN的输出是所有标签的概率。 这里将Temporal Classification定义为$h$,训练数据集合$S$中数据是成对存在的$(\mathbf{x},z)$,其中$\mathbf{x}$是训练的时序数据,$z$是标签数据。目标就是找到一个时序分类器$h$使得$S$中的$x$被分类到$z$。训练这个分类器,就需要一个错误度量,这里就借鉴了编辑(ED)距离度量,而引入了label error rate(LER)。在这里还对其进行了归一化,从而得到了如下的形式:

    将网络输出转换成为基于标签序列的条件概率,从而可以使用分类器对输入按照概率大小进行分类。

    从网络输出到连续标签

    在CTC网络中拥有一个$softmax$输出层,其输出的个数为$∣L∣+1$,$L$是标签元素的集合,额外的一个那当然就是”BLANK”标签了。这些输出定义了将所有可能的标签序列与输入序列对齐的所有可能路径的概率。任何一个标签序列的总概率可以通过对其不同排列的概率求和得到。 首先对于一条可行的路径$p(\pi|x)$被定义为对应路径上的各个时刻输出预测概率的乘积。其定义如下:

    对于预测结果中的一条路径的标签,论文中假设这些不同时刻网络的输出是相互独立的,而这种独立性是通过输出层与自身或网络之间不存在反馈连接来确保实现的。

    在此基础上还定义了映射函数$B$,它的职责就是去除”BLANK”与重复的标签。因而给定的一个标签其输出概率就可以描述为几个可行路径相加和的形式:

    构建分类器

    从上面的内容中已经得到了一个序列标签的输出条件概率,那么怎么才能找到输入数据最匹配的标签呢?最为直观的便是求解

    在给定输入情况下找到其最可能的标签序列,这样的过程使用HMM中的术语叫做解码。目前,还没有一种通过易理解的解码算法,但下面的两种方法在实践过程中也取得了不错的效果。

    最佳路径解码

    该方法是建立在概率最大的路径与最可能的标签时对应的,因而分类器就被描述为如下形式:

    从上面的形式中就可以看出,最佳路径解码的计算式很容易的,因为最佳路径中的元素是各个时刻输出的级联。但是呢,这是不能保证找到最可能的标签的。

    前缀解码

    前缀解码在足够时间的情况下会找到最可能的标签,但是随着输入序列长度的增强时间也会指数增加。如果输入的概率分布是尖状的,那么可以在合理的时间内找到最可能的路径。

    实践中,前缀搜索在这个启发式下工作得很好,通常超过了最佳路径解码,但是在有些情况下,效果不佳。

    CTC网络训练

    目标函数是由极大似然原理导出的。也就是说,最小化它可以最大化目标标签的对数可能性。有了损失函数之后就可以使用依靠梯度进行优化的算法进行最优化。

    CTC在网络中放置在双向递归网络的后面作为序列预测的损失来源。CTC会在RNN网络中传播梯度,进而使得其学习一条好路径。

    CTC前向传播算法

    需要一种有效的方法来计算单个标签的条件概率$p(l|\mathbf{x})$。对于这样的问题,其实就是对应于给定标签的所有路径的综合。通常有很多这样的路径。这里我们采用动态规划的算法计算所有可能路径的概率和,其思想是,与标签对应的路径和可以分解为与标签前缀对应的路径的迭代和。 然后,可以使用递归向前和向后变量有效地计算迭代。 以下是本文设计到的一些符号定义:

    • $y_{k}^{t}$, 时刻t的输出字符$k$
    • $l$, 标签序列对应的损失。
    • $l^{\prime}$,相同的标签序列,但是在字符之间添加了”BLANK”标签

    其中B是溢出所有”BLANK”与重复字符的变换;${\pi \in N^T:B(\pi_{1:t}) = l_{1:s}}$ 是时刻1到t的预测矩阵中,给出经过变换$B$之后与标签有前s个一致的所有可行路径;$y^{t^{\prime}}$ 是指时刻$t^{\prime}$时RNN的输出。而且$\alpha_{t}(s)$可以通过$\alpha_{t-1}(s)$与$\alpha_{t-1}(s-1)$迭代计算出来。

    图3中描述的状态转移图与上面公式的含义是相同的。为了能够在输出路径中出现”BLANK”标签,将标签修改成了$l^{\prime}$,也就是在标签的前后与字符之前插入空白标签,因而生成的标签长度就变成了$2|l|+1$的长度,使其可以再空白标签与非空白标签之间转换,也可以使非空白标签之间发生转换。 上面的公式1中已经给出了其计算的内容,但其计算并不具有可行性。但是可以根据图3中$\alpha_{t}(s)$的递归定义使用动态规划算法去解决该问题,仔细看这幅图,是不是有点像HMM的前向计算过程。

    对于解决该问题使用动态规划的算法进行解决,首先来分析时刻1时候的情况:

    where $\alpha_t(s) \overset{def}{=} \alpha_{t-1}(s) + \alpha_{t-1}(s-1)$ 最后就可以得到一个序列的输出概率

    反向传播算法

    反向传播的变量$\beta_{t}(s)$被定义为$t$时刻$l_{s:|l|}$的总概率

    最大似然训练

    最大似然训练的目的是同时最大化训练集中所有正确分类的对数概率。因而这里可以将损失函数定义为:

    为了使用梯度进行网络训练,因而就需要对网络的输出进行微分,且训练样本是相互独立的,也就是说可以单独考虑了,因而可以将微分写为:

    这里可以用前向后向算法计算上式。主要思想是:对于一个标记l,在给定s和t的情况下,前向和后向变量的内积是对应l所有可能路径的概率。表达式为:

    且根据上面的公式(2)联合可以得到:

    再与前面的公式(3)联合可以得到

    RLSTM(Reverse LSTM)

    • RNN[^6]
    • LSTM[^7][^8]

    Reverse LSTM

    整体架构如下,其中需要用到Reverse这种Layer

    ChannelShuffle

    一般的分组卷积(如ResNeXt的)仅对$3\times3$的层进行了分组操作,然而$1\times1$的pointwise卷积占据了绝大多数的乘加操作,在小模型中为了减少运算量只能减少通道数,然而减少通道数会大幅损害模型精度。作者提出了对$1\times1$也进行分组操作,但是如图1(a)所示,输出只由部分输入通道决定。为了解决这个问题,作者提出了图(c)中的通道混淆(channel shuffle)操作来分享组间的信息,假设一个卷基层有g groups,每个group有n个channel,因此shuffle后会有$g\times n$个通道,首先将输出的通道维度变形为(g, n),然后转置(transpose)、展平(flatten),shuffle操作也是可导的。

    图2 (a)是一个将卷积替换为depthwise卷积3的residual block,(b)中将两个$1\times1$卷积都换为pointwise group convolution,然后添加了channel shuffle,为了简便,没有在第二个pointwise group convolution后面加channel shuffle。根据Xception的论文,depthwise卷积后面没有使用ReLU。(c)为stride > 1的情况,此时在shotcut path上使用$3\times3$的平均池化,并将加法换做通道concatenation来增加输出通道数(一般的设计中,stride=2的同时输出通道数乘2)。

    对于$c \times h \times w$的输入大小,bottleneck channels为m,则ResNet unit需要$hw(2cm + 9m^2)FLOPs$,ResNeXt需要$hw(2cm + 9m^2/g)FLOPs$,ShuffleNet unit只需要$hw(2cm/g + 9m)FLOPs$,g表示卷积分组数。换句话说,在有限计算资源有限的情况下,ShuffleNet可以使用更宽的特征图,作者发现对于小型网络这很重要。

    即使depthwise卷积理论上只有很少的运算量,但是在移动设备上的实际实现不够高效,和其他密集操作(dense operation)相比,depthwise卷积的computation/memory access ratio很糟糕。因此作者只在bottleneck里实现了depthwise卷积。

    CTPN4

    @The-Arch-of-CTPN

    
    class BasicConv(nn.Module):
        def __init__(self, in_planes, out_planes,
                     kernel_size, stride=1, padding=0,
                     dilation=1, groups=1,
                     relu=True, bn=True, bias=True):
            super(BasicConv, self).__init__()
            self.out_channels = out_planes
            self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)
            self.bn = nn.BatchNorm2d(out_planes, eps=1e-5, momentum=0.01, affine=True) if bn else None
            self.relu = nn.ReLU(inplace=True) if relu else None
    
        def forward(self, x):
            x = self.conv(x)
            if self.bn is not None:
                x = self.bn(x)
            if self.relu is not None:
                x = self.relu(x)
            return x
    
    Commom_C = 512
    anchor_k = 10
    
    class CTPN_Model(nn.Module):
        def __init__(self):
            super().__init__()
            base_model = models.vgg16(pretrained=False)
            layers = list(base_model.features)[:-1]
            self.base_layers = nn.Sequential(*layers)  # block5_conv3 output
            self.prelstm = BasicConv(Commom_C, Commom_C, 3,1,1,bn=False)
            self.bilstm = nn.GRU(Commom_C, Commom_C/2, bidirectional=True, batch_first=True)
            self.lstm_fc = BasicConv(Commom_C, Commom_C, 1, 1, relu=True, bn=False)
            self.rpn_class = BasicConv(Commom_C, anchor_k*2, 1, 1, relu=False,bn=False)
            self.rpn_regress = BasicConv(Commom_C, anchor_k*2, 1, 1, relu=False, bn=False)
    
        def forward(self, x):
            #
            # basebone network run
            #
            x = self.base_layers(x)
            #
            # Convert feature map to lstm input
            #
            x = self.prelstm(x)
            x1 = x.permute(0,2,3,1).contiguous()  # channels last
            b = x1.size()  # batch_size, h, w, c
            x1 = x1.view(b[0]*b[1], b[2], b[3])
            #
            # BiLSTM
            #
            x2, _ = self.bilstm(x1)
    
            xsz = x.size()
            x3 = x2.view(xsz[0], xsz[2], xsz[3], 256)  # torch.Size([4, 20, 20, 256])
    
            x3 = x3.permute(0,3,1,2).contiguous()  # channels first
            x3 = self.lstm_fc(x3)
            x = x3
            #
            # RPN
            #
            rpn_cls = self.rpn_class(x)
            rpn_regr = self.rpn_regress(x)
    
            rpn_cls = rpn_cls.permute(0,2,3,1).contiguous()
            rpn_regr = rpn_regr.permute(0,2,3,1).contiguous()
    
            rpn_cls = rpn_cls.view(rpn_cls.size(0), rpn_cls.size(1)*rpn_cls.size(2)*anchor_k, 2)
            rpn_regr = rpn_regr.view(rpn_regr.size(0), rpn_regr.size(1)*rpn_regr.size(2)*anchor_k, 2)
    
            return rpn_cls, rpn_regr
    

    解释一下conv5 feature map如何从$N\times C \times H \times W$变为$N \times 9C \times H \times W$

    在原版caffe代码中是用im2col提取每个点附近的9点临近点,然后每行都如此处理:

    $H\times W \rightarrow 9 \times H \times W$

    接着每个通道都如此处理: $C\times H\times W \rightarrow 9C\times H \times W$

    而im2col是用于卷积加速的操作,即将卷积变为矩阵乘法,从而使用Blas库快速计算。到了tf,没有这种操作,所以一般是用conv2d代替im2col,即强行卷积$C\rightarrow 9C$ 。

    再将这个feature map进行Reshape

    然后以Batch = NH 且最大时间长度$T_{max} = W$的数据流输入双向LSTM,学习每一行的序列特征。双向LSTM输出为$(NH)\times W\times 256$,再经Reshape恢复形状 $(NH)\times W \times 256 \xrightarrow{reshape} N \times 256 \times H \times W$

    该特征即包含空间特性,也包含LSTM学到的序列特征。

    然后经过”FC”卷积层,变为$N\times512\times H \times W$的特征 最后经过类似Faster R-CNN的RPN网络,获得text proposals.

    文本线构造算法

    为了说明问题,假设某张图有图9所示的2个text proposal,即蓝色和红色2组Anchor,CTPN采用如下算法构造文本线:

    按照水平$x$坐标排序anchor 按照规则依次计算每个anchor $box_i$的$pair(box_j)$,组成$pair(box_i, box_j)$ 通过$pair(box_i, box_j)$建立一个Connect graph,最终获得文本检测框

    下面详细解释。假设每个anchor index如绿色数字,同时每个anchor Softmax score如黑色数字。

    文本线构造算法通过如下方式建立每个anchor $box_i$的$pair(box_i, box_j)$:

    正向寻找:

    • 沿水平正方向,寻找和$box_i$水平距离小于50的候选anchor
    • 从候选anchor中,挑出与$box_i$竖直方向$overlap_v \gt 0.7$的anchor
    • 挑出符合条件2中Softmax score最大的$box_j$

    反向寻找:

    • 沿水平负方向,寻找和$box_j$水平距离小于50的候选Anchor
    • 从候选Anchor中,挑出与$box_j$竖直方向$overlap_v \gt 0.7$的anchor
    • 挑出符合条件2中Softmax score最大的$box_k$

    对比$score_i$和$score_k$:

    如果$score_i \ge score_k$,则这是一个最长连接,那么设置$Graph(i, j) = True$ 如果$score_i \lt score_k$,说明这不是一个最长的连接(即该连接肯定包含在另外一个更长的连接中)。

    Text Recognition

    其他相关算法

    Levenshtein distances[^5]是俄罗斯科学家Vladimir Levenshtein在1965年发明的,也叫做编辑距离(实际上编辑距离代表一大类算法),距离代表着从s到t需要删、插、代替单个字符的最小步骤数。主要应用:

    • Spell checking 检查拼写
    • Speech recognition 语音识别
    • DNA analysis DNA分析
    • Plagiarism detection 检测抄袭

    引用

    1. https://blog.csdn.net/liuxiaoheng1992/article/details/85305871 “SWT博客” 

    2. https://www.cnblogs.com/shangd/p/6164916.html “MSER 博客” 

    3. https://arxiv.org/pdf/1610.02357.pdf “Xception” 

    4. https://zhuanlan.zhihu.com/p/34757009 “场景文字检测—CTPN原理与实现”

      • tf code: https://github.com/eragonruan/text-detection-ctpn [^5]: http://www.levenshtein.net/index.html “编辑距离” [^6]: https://zybuluo.com/hanbingtao/note/541458 “循环神经网络” [^7]: http://colah.github.io/posts/2015-08-Understanding-LSTMs/ “理解LSTM” [^8]: https://www.jianshu.com/p/4b4701beba92 “理解LSTM中文” [^9]: https://www.jianshu.com/p/56f8c714f372 “自然场景文本检测识别技术综述”

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    认识神经网络:卷积,归一化,优化和语料
    机遇 research之路其修远兮,我将上下而求索

    认识神经网络:卷积,归一化,优化和语料

    2019-07-22
    cwlseu

    引言

    一个基于神经网络模型的视觉模型中,卷积归一化层是最为耗时的两种layer。卷积数据计算密集类型,今年来大量的优化主要集中在各种设备上的卷积加速。 归一化层通过计算一个批量中的均值与方差来进行特征归一化。众多实践证明,它利于优化且使得深度网络易于收敛。批统计的随机不确定性也作为一个有利于泛化的正则化项。BN 已经成为了许多顶级计算机视觉算法的基础。添加归一化层作为提高算法性能的很好的一种策略,但由于像BN遭受数据同步延时的问题,现在逐渐被一些新的normalization方式所替代。

    卷积

    认识卷积

    卷积定义

    $f(t)$先不动, $g(-t)$相当于$g(t)$函数的图像沿y轴(t=0)做了一次翻转。$g(x-t)$相当于$g(-t)$的整个图像沿着t轴进行了平移,向右平移了x个单位。他们相乘之后围起来的面积就是$h(x)$。

    离散卷积的定义

    其实,深度学习中的卷积对应于数学中的cross correlation. 从卷积的定义来看,我们当前在深度学习中训练的卷积核是翻转之后的卷积核

    下面是一些介绍卷积的文章和常见卷积类型统计表:

    Convolution Name 参考文献 典型代表 附录
    Convolution   AlexNet, VGG  
    1x1 Network in Network GoogLeNet, Inception (1). Dimensionality reduction for efficient computations;
    (2).Efficient low dimensional embedding, or feature pooling;
    (3). Applying nonlinearity again after convolution
    Dilated convolution Multi-Scale Context Aggregation by Dilated Convolutions 语义分割 support exponentially expanding receptive fields without losing resolution or coverage. Upsampling/poolinglayer(e.g. bilinear interpolation) is deterministic. (a.k.a. not learnable);
    内部数据结构丢失, 空间层级化信息丢失;
    小物体信息无法重建 (假设有四个pooling layer则任何小于$2^4=16$pixel的物体信息将理论上无法重建。)
    如何理解空洞卷积
    Group Convolution Deep Roots:Improving CNN Efficiency with Hierarchical Filter Groups MobileNet, ResNeXt  
    Pointwise grouped convolution   ShuffleNet  
    Depthwise separable convolution Xception: Deep Learning with Depthwise Separable Convolutions Xception MobileNet是典型的代表,通过该卷积,大大降低了计算复杂度和模型大小。也是现在落地产品中移动端常用的操作。
    Deconvolutions Deconvolution and Checkerboard Artifacts DSSD Deconvolution也是一种常用的上采样方式,在物体分割和多尺度检测都可用到
    Flattened convolutions Flattened convolutional neural networks for feedforward acceleration   computation costs due to the significant reduction of learning parameters.

    卷积的实现

    计算卷积的方法有很多种,常见的有以下几种方法:

    • 滑窗:这种方法是最直观最简单的方法。但是,该方法不容易实现大规模加速,因此,通常情况下不采用这种方法 (但是也不是绝对不会用,在一些特定的条件下该方法反而是最高效的.)
    • im2col: 目前几乎所有的主流计算框架包括[Caffe]1, MXNet等都实现了该方法。该方法把整个卷积过程转化成了GEMM过程,而GEMM在各种BLAS库中都是被极致优化的,一般来说,速度较快.
    • FFT: 傅里叶变换和快速傅里叶变化是在经典图像处理里面经常使用的计算方法,但是,在 ConvNet 中通常不采用,主要是因为在 ConvNet 中的卷积模板通常都比较小,例如3×3 等,这种情况下,FFT 的时间开销反而更大.
    • [Winograd]2: Winograd 是存在已久最近被重新发现的方法,在大部分场景中,Winograd 方法都显示和较大的优势,目前cudnn中计算卷积就使用了该方法.

    计算复杂度分析

    • 假设输入$I = R^{C_0H_0W_0}$, 卷积核大小为$k$, 输出$O = R^{C_1H_1W_1}$, 则卷积过程的计算量为:

    使用Depthwise separable convolution卷积的计算量为:

    那么计算量之比为

    一般情况下,$k^2 « C_1$, 所以当$k=3$的时候,计算量之比约为原来的$\frac{1}{9}$.

    • 假设input的$H_0 = W_0$,用$w$表示,$k$是卷积核的大小,$p$表示填充的大小,$s$表示stride步长

    Normalization

    @归一化方法 每个子图表示一个feature map张量,以$N$为批处理轴,$C$为通道轴,$(H,W)$作为空间轴。其中蓝色区域内的像素使用相同的均值和方差进行归一化,并通过聚合计算获得这些像素的值。从示意图中可以看出,GN没有在N维度方向上进行拓展,因此batch size之间是独立的,GPU并行化容易得多。

    • batchNorm是在batch上,对NHW做归一化,对小batchsize效果不好;
    • layerNorm在通道方向上,对CHW归一化,主要对RNN作用明显;
    • instanceNorm在图像像素上,对HW做归一化,用在风格化迁移;
    • GroupNorm将channel分组,然后再做归一化;
    • SwitchableNorm是将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。

    Batch Normalization

    需要比较大的Batch Size,需要更强的计算硬件的支持。

    A small batch leads to inaccurate estimation of the batch statistics, and reducing BN’s batch size increases the model error dramatically

    尤其是在某些需要高精度输入的任务中,BN有很大局限性。同时,BN的实现是在Batch size之间进行的,需要大量的数据交换。

    batch normalization存在以下缺点:

    • 对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布;
    • BN实际使用时需要计算并且保存某一层神经网络batch的均值和方差等统计信息,对于对一个固定深度的前向神经网络(DNN,CNN)使用BN,很方便;但对于RNN来说,sequence的长度是不一致的,换句话说RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一个特殊sequence比其他sequence长很多,这样training时,计算很麻烦。(参考于https://blog.csdn.net/lqfarmer/article/details/71439314)

    Layer Normalizaiton

    LN中同层神经元输入拥有相同的均值和方差,不同的输入样本有不同的均值和方差; BN中则针对不同神经元输入计算均值和方差,同一个batch中的输入拥有相同的均值和方差。

    所以,LN不依赖于batch的大小和输入sequence的深度,因此可以用于batchsize为1和RNN中对边长的输入sequence的normalize操作。

    Instance Normalization

    BN注重对每个batch进行归一化,保证数据分布一致,因为判别模型中结果取决于数据整体分布。

    但是图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。

    Group Normalization

    GN does not exploit the batch dimension, and its computation is independent of batch sizes.

    @BN,LN,IN,GN result comparison 从实验结果中可以看出在训练集合上GN的valid error低于BN,但是测试结果上逊色一些。这个 可能是因为BN的均值和方差计算的时候,通过随机批量抽样(stochastic batch sampling)引入了不确定性因素,这有助于模型参数正则化。 而这种不确定性在GN方法中是缺失的,这个将来可能通过使用不同的正则化算法进行改进。

    LRN(Local Response Normalization)

    动机

    在神经深武学有一个概念叫做侧抑制(lateral inhibitio),指的是被激活的神经元抑制相邻的神经元。 归一化的目的就是“抑制”,局部响应归一化就是借鉴侧抑制的思想来实现局部抑制,尤其是当我们使用ReLU 的时候,这种侧抑制很管用。

    好处

    有利于增加泛化能力,做了平滑处理,识别率提高1~2%

    参考文献

    优化

    梯度下降法(Gradient Descent)

    梯度下降法是最早最简单,也是最为常用的最优化方法。梯度下降法实现简单,当目标函数是凸函数时,梯度下降法的解是全局解。 一般情况下,其解不保证是全局最优解,梯度下降法的速度也未必是最快的。梯度下降法的优化思想是用当前位置负梯度方向作为搜索方向, 因为该方向为当前位置的最快下降方向,所以也被称为是”最速下降法”。最速下降法越接近目标值,步长越小,前进越慢。 梯度下降法的搜索迭代示意图如下图所示:

    @梯度下降法的搜索迭代示意图

    梯度下降法的缺点:

    • 靠近极小值时收敛速度减慢,如下图所示;
    • 直线搜索时可能会产生一些问题;
    • 可能会“之字形”地下降。

    @梯度下降法的之字形示意图

    参考文献

    其他参考文献

    深度学习教程

    CS231n: Convolutional Neural Networks for Visual Recognition.

    计算平台

    1. arm平台
    2. linux上编译arm交叉编译链
    3. How to Build a GCC Cross-Compiler

    常用数据集合

    https://www.analyticsvidhya.com/blog/2018/03/comprehensive-collection-deep-learning-datasets/ 这里我们列出了一组高质量的数据集,研究这些数据集将使你成为一个更好的数据科学家。 我们可以使用这些数据集来学习各种深度学习技术,也可以使用它们来磨练您的技能,理解如何识别和构造每个问题,考虑独特的应用场景!

    图像类

    dataset名称 大小 State-of-Art 描述
    MNIST 50MB Dynamic Routing Between Capsules 手写数字识别,包含60000个训练数据及10000个测试数据,可分为10类
    MSCOCO ~25G Mask RCNN COCO is a large-scale and rich for object detection, segmentation and captioning dataset. 330K images, 1.5 million object instances, 80 object categories, 5 captions per image, 250,000 people with key points
    ImageNet 150GB ResNeXt ImageNet is a dataset of images that are organized according to the WordNet hierarchy. WordNet contains approximately 100,000 phrases and ImageNet has provided around 1000 images on average to illustrate each phrase. Number of Records: Total number of images: ~1,500,000; each with multiple bounding boxes and respective class labels
    Open Image Dataset 500GB ResNet 一个包含近900万个图像URL的数据集。 这些图像拥有数千个类别及边框进行了注释。 该数据集包含9,011219张图像的训练集,41,260张图像的验证集以及125,436张图像的测试集。
    VisualQA 25GB Tips and Tricks for Visual Question Answering: Learnings from the 2017 Challenge 图像的问答系统数据集 265,016 images, at least 3 questions per image, 10 ground truth answers per question
    The Street View House Numbers(SVHN) 2.5GB Distributional Smoothing With Virtual Adversarial Training 门牌号数据集,可用来做物体检测与识别
    CIFAR-10 170MB ShakeDrop regularization 图像识别数据集,包含 50000张训练数据,10000张测试数据,可分为10类
    Fashion-MNIST 30MB Random Erasing Data Augmentation 包含60000训练样本和10000测试样本的用于服饰识别的数据集,可分为10类。

    自然语言处理类

    dataset名称 大小 State-of-Art 描述
    IMDB 影评数据 80MB Learning Structured Text Representations 可以实现对情感的分类,除了训练集和测试集示例之外,还有更多未标记的数据。原始文本和预处理的数据也包括在内。25,000 highly polar movie reviews for training, and 25,000 for testing
    Twenty Newsgroups 20MB Very Deep Convolutional Networks for Text Classification 包含20类新闻的文章信息,内类包含1000条数据
    Sentiment140 80MB Assessing State-of-the-Art Sentiment Models on State-of-the-Art Sentiment Datasets 1,60,000 tweets,用于情感分析的数据集
    WordNet 10MB Wordnets: State of the Art and Perspectives 117,000 synsets is linked to other synsets by means of a small number of “conceptual relations.
    Yelp点评数据集 2.66GB JSON文件,2.9GB SQL文件,7.5GB图片数据 Attentive Convolution 包括470万条用户评价,15多万条商户信息,20万张图片,12个大都市。此外,还涵盖110万用户的100万条tips,超过120万条商家属性(如营业时间、是否有停车场、是否可预订和环境等信息),随着时间推移在每家商户签到的总用户数。
    维基百科语料库(英语) 20MB Breaking The Softmax Bottelneck: A High-Rank RNN language Model 包含4400000篇文章 及19亿单词,可用来做语言建模
    博客作者身份语料库 300MB Character-level and Multi-channel Convolutional Neural Networks for Large-scale Authorship Attribution 从blogger.com收集到的19,320名博主的博客,其中博主的信息包括博主的ID、性别、年龄、行业及星座
    各种语言的机器翻译数据集 15GB Attention Is All You Need 包含英-汉、英-法、英-捷克、英语- 爱沙尼亚、英 - 芬兰、英-德、英 - 哈萨克、英 - 俄、英 - 土耳其之间互译的数据集

    语音类

    dataset名称 大小 State-of-Art 描述
    Free Spoken Digit Dataset 10MB Raw Waveform-based Audio Classification Using Sample-level CNN Architectures 数字语音识别数据集,包含3个人的声音,每个数字说50遍,共1500条数据
    Free Music Archive (FMA) 1000GB Learning to Recognize Musical Genre from Audio 可以用于对音乐进行分析的数据集,数据集中包含歌曲名称、音乐类型、曲目计数等信息。
    Ballroom 14GB A Multi-Model Approach To Beat Tracking Considering Heterogeneous Music Styles 舞厅舞曲数据集,可对舞曲风格进行识别。
    Million Song Dataset 280GB Preliminary Study on a Recommender System for the Million Songs Dataset Challenge Echo Nest提供的一百万首歌曲的特征数据.该数据集不包含任何音频,但是可以使用他们提供的代码下载音频
    LibriSpeech 60GB Letter-Based Speech Recognition with Gated ConvNets 包含1000小时采样频率为16Hz的英语语音数据及所对应的文本,可用作语音识别
    VoxCeleb 150MB VoxCeleb: a large-scale speaker identification dataset]() 大型的说话人识别数据集。 它包含约1,200名来自YouTube视频的约10万个话语。 数据在性别是平衡的(男性占55%)。说话人跨越不同的口音,职业和年龄。 可用来对说话者的身份进行识别。

    Analytics Vidhya实践问题

    • Twitter情绪分析
      • 描述:识别是否包含种族歧视及性别歧视的推文。
      • 大小:3MB
      • 31,962 tweets
    • 印度演员的年龄识别数据集
      • 描述:根据人的面部属性,识别人的年龄的数据集。
      • 大小:48MB
      • 19,906 images in the training set and 6636 in the test set
    • 城市声音分类数据集
      • 描述:该数据集包含来自10个类的城市声音的8732个标记的声音片段,每个片段时间小于4秒。
      • 大小:训练数据集3GB,训练数据集2GB。
      • 8732 labeled sound excerpts (<=4s) of urban sounds from 10 classes

    more dataset

    1. https://github.com/BVLC/caffe/blob/master/src/caffe/util/im2col.cpp 

    2. https://arxiv.org/abs/1509.09308v2 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Detection算法Overview
    机遇 research之路其修远兮,我将上下而求索

    Detection算法Overview

    2019-07-14
    cwlseu

    物体检测算法概述

    深度学习让物体检测从实验室走到生活。基于深度学习的物体检测算法分类两大类。一类是像RCNN类似的两stage方法,将ROI的选择和对ROI的分类score过程。 另外一类是类似YOLO将ROI的选择和最终打分实现端到端一步完成。前者是先由算法生成一系列作为样本的候选框,再通过卷积神经网络进行样本分类;后者则不用产生候选框,直接将目标边框定位的问题转化为回归问题处理。正是由于两种方法的差异,在性能上也有不同,前者在检测准确率和定位精度上占优,后者在算法速度上占优。

    @物体检测算法概览图

    各种检测算法之间的性能对比,准确率,速度,以及一些可能加速的tips

    R-CNN的前世

    基于region proposals的方法(Two-Stage方法)

    • RCNN => Fast RCNN => Faster RCNN => FPN @R-CNN、Fast R-CNN、Faster R-CNN三者关系

    RCNN

    在早期深度学习技术发展进程中,主要都是围绕分类问题展开研究,这是因为神经网络特有的结构输出将概率统计和分类问题结合,提供一种直观易行的思路。国内外研究人员虽然也在致力于将其他如目标检测领域和深度学习结合,但都没有取得成效,这种情况直到R-CNN算法出现才得以解决。

    • 论文链接:https://arxiv.org/pdf/1311.2524.pdf
    • 作者:Ross Girshick Jeff Donahue Trevor Darrell Jitendra Malik 之前的视觉任务大多数考虑使用SIFT和HOG特征,而近年来CNN和ImageNet的出现使得图像分类问题取得重大突破,那么这方面的成功能否迁移到PASCAL VOC的目标检测任务上呢?基于这个问题,论文提出了R-CNN。 R-CNN (Region-based CNN features) 性能:RCNN在VOC2007上的mAP是58%左右。

    主要工作流程

    @R-CNN要完成目标定位,其流程主要分为四步 R-CNN要完成目标定位,其流程主要分为四步:

    • 输入图像
    • 利用选择性搜索(Selective Search)这样的区域生成算法提取Region Proposal 提案区域(2000个左右)
    • 将每个Region Proposal分别resize(因为训练好的CNN输入是固定的)后(也即下图中的warped region,文章中是归一化为227×227)作为CNN网络的输入。
    • CNN网络提取到经过resize的region proposal的特征送入每一类的SVM分类器,判断是否属于该类

    RCNN的缺点

    • 对于提取的每个Region Proposal,多数都是互相重叠,重叠部分会被多次重复提取feature),都要分别进行CNN前向传播一次(相当于进行了2000吃提特征和SVM分类的过程),计算量较大。
    • CNN的模型确定的情况下只能接受固定大小的输入(也即wraped region的大小固定)

    优化思路

    既然所有的Region Proposal都在输入图像中,与其提取后分别作为CNN的输入,为什么不考虑将带有Region Proposal的原图像直接作为CNN的输入呢?原图像在经过CNN的卷积层得到feature map,原图像中的Region Proposal经过特征映射(也即CNN的卷积下采样等操作)也与feature map中的一块儿区域相对应。

    SPP net

    • 论文链接:]https://arxiv.org/abs/1406.4729
    • 作者:Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 简述:SPP net中Region Proposal仍然是在原始输入图像中选取的,不过是通过CNN映射到了feature map中的一片区域。

    SPP-NET的主要思想

    @SPPNet架构图

    • 对卷积层的feature map上的Region Proposal映射区域分别划分成1×1,2×2,4×4的窗口(window),
    • 在每个窗口内做max pooling,这样对于一个卷积核产生的feature map,就可以由SPP得到一个(1×1+2×2+4×4)维的特征向量。
    • 论文中采用的网络结构最后一层卷积层共有256个卷积核,所以最后会得到一个固定维度的特征向量(1×1+2×2+4×4)×256维),并用此特征向量作为全连接层的输入后做分类。

    相对于R-CNN,SPP-net的优势

    • 使用原始图像作为CNN网络的输入来计算feature map(R-CNN中是每个Region Proposal都要经历一次CNN计算),大大减少了计算量。
    • RCNN要resize,易于失真,而SPP-net不需要,原因是,SPP net中Region Proposal仍然是通过选择性搜索等算法在输入图像中生成的,通过映射的方式得到feature map中对应的区域,并对Region Proposal在feature map中对应区域做空间金字塔池化。通过空间金字塔池化操作,对于任意尺寸的候选区域,经过SPP后都会得到固定长度的特征向量。

    Fast RCNN

    • Fast R-CNN
    • 作者:Ross Girshick 性能:在VOC2007上的mAP也提高到了68%

    算法框架图

    优点&贡献

    • Fast R-CNN引入了RoI 池化层(相当于是一层SPP),对于图像中的Region Poposal(也即RoI),通过映射关系(图中的RoI projection)可以得到feature map中Region Proposal对应的区域。
    • RoI Pooling层的操作是将feature map上的RoI区域划分为7×7的窗口,在每个窗口内进行max pooling,然后得到(7×7)×256的输出,最后连接到全连接层得到固定长度的RoI特征向量。
    • 前面得到的RoI特征向量再通过全连接层作为Softmax和Regressor的输入,训练过程可以更新所有的网络层
    • 训练过程是端到端的(Sigle-stage),并使用了一个多任务的损失函数(也即将边框回归直接加入到CNN网络中后,Fast R-CNN网络的损失函数包含了Softmax的损失和Regressor的损失)

    小结

    在前面三种目标检测框架中(R-CNN,SPP net,Fast R-CNN),Region Proposal都是通过区域生成的算法(选择性搜索等)在原始输入图像中产生的,不过在SPP net及Fast R-CNN中都是输入图像中的Region Proposal通过映射关系映射到CNN中feature map上再操作的。Fast R-CNN中RoI池化的对象是输入图像中产生的proposal在feature map上的映射区域

    Faster RCNN

    • 论文链接:https://arxiv.org/pdf/1506.01497.pdf
    • 作者:Shaoqing Ren, Kaiming He, Ross Girshick, and Jian Sun

    Faster RCNN算法框架

    @faster RCNN的算法框架 我们先整体的介绍下上图中各层主要的功能

    • 卷积网络提取特征图

    作为一种CNN网络目标检测方法,Faster RCNN首先使用一组基础的conv+relu+pooling层提取input image的feature maps,该feature maps会用于后续的RPN层和全连接层。

    • RPN(Region Proposal Networks,区域提议网络):

    RPN网络主要用于生成region proposals,

    • 首先生成一堆Anchor box,对其进行裁剪过滤后通过softmax判断anchors属于前景(foreground)或者后景(background),即是物体or不是物体,所以这是一个二分类;
    • 另一分支bounding box regression修正anchor box,形成较精确的proposal(注:这里的较精确是相对于后面全连接层的再一次box regression而言)

    Feature Map进入RPN后,先经过一次$33$的卷积,同样,特征图大小依然是$6040$,数量512,这样做的目的应该是进一步集中特征信息,接着看到两个全卷积,即kernel_size=1*1,p=0,stride=1;

    • cls layer 逐像素对其9个Anchor box进行二分类
    • reg layer 逐像素得到其9个Anchor box四个坐标信息

    特征图大小为6040,所以会一共生成6040*9=21600个Anchor box

    @FasterRCNN-RPN

    • Roi Pooling

    该层利用RPN生成的proposals和VGG16最后一层得到的feature map,得到固定大小的proposal feature map,进入到后面可利用全连接操作来进行目标识别和定位

    • Classifier

    会将ROI Pooling层形成固定大小的feature map进行全连接操作,利用Softmax进行具体类别的分类,同时,利用SmoothL1Loss完成bounding box regression回归操作获得物体的精确位置。

    @FasterRCNN算法详细过程图 @FasterRCNN proposal&RPN Netscope

    参考链接

    • [1]. https://www.cnblogs.com/wangyong/p/8513563.html
    • [2]. https://www.jianshu.com/p/00a6a6efd83d
    • [3]. https://www.cnblogs.com/liaohuiqiang/p/9740382.html
    • [4]. https://blog.csdn.net/u011436429/article/details/80414615
    • [5]. https://blog.csdn.net/xiaoye5606/article/details/71191429

    @RCNN系列对比总结表

    RGB大神,He Kaiming致敬!

    FPN(feature pyramid networks for object detection)

    • 论文链接:https://arxiv.org/abs/1612.03144
    • poster链接: https://vision.cornell.edu/se3/wp-content/uploads/2017/07/fpn-poster.pdf
    • caffe实现: https://github.com/unsky/FPN
    • 作者:Tsung-Yi Lin, Piotr Dollár, Ross Girshick, Kaiming He, Bharath Hariharan, Serge Belongie

    图像金字塔

    图像金字塔,在很多的经典算法里面都有它的身影,比如SIFT、HOG等算法。 我们常用的是高斯金字塔,所谓的高斯金字塔是通过高斯平滑和亚采样获得 一些下采样图像,也就是说第K层高斯金字塔通过平滑、亚采样操作就可以 获得K+1层高斯图像,高斯金字塔包含了一系列低通滤波器,其截止频率从 上一层到下一层是以因子2逐渐增加,所以高斯金字塔可以跨越很大的频率范围。 总之,我们输入一张图片,我们可以获得多张不同尺度的图像,我们将这些 不同尺度的图像的4个顶点连接起来,就可以构造出一个类似真实金字塔的一 个图像金字塔。通过这个操作,我们可以为2维图像增加一个尺度维度(或者说是深度), 这样我们可以从中获得更多的有用信息。整个过程类似于人眼看一个目标由远及近的 过程(近大远小原理)。

    @图像金字塔

    论文概述:

    作者提出的多尺度的object detection算法:FPN(feature pyramid networks)。原来多数的object detection算法都是只采用顶层特征做预测,但我们知道低层的特征语义信息比较少,但是目标位置准确;高层的特征语义信息比较丰富,但是目标位置比较粗略。另外虽然也有些算法采用多尺度特征融合的方式,但是一般是采用融合后的特征做预测,而本文不一样的地方在于预测是在不同特征层独立进行的。

    @FPN架构图

    前面已经提到了高斯金字塔,由于它可以在一定程度上面提高算法的性能, 因此很多经典的算法中都包含它。但是这些都是在传统的算法中使用,当然也可以将 这种方法直应用在深度神经网络上面,但是由于它需要大量的运算和大量的内存。 但是我们的特征金字塔可以在速度和准确率之间进行权衡,可以通过它获得更加鲁棒 的语义信息,这是其中的一个原因。

    @FPN不同层识别的目标不同

    如上图所示,我们可以看到我们的图像中存在不同尺寸的目标,而不同的目标具有不同的特征, 利用浅层的特征就可以将简单的目标的区分开来; 利用深层的特征可以将复杂的目标区分开来;这样我们就需要这样的一个特征金字塔来完成这件事。 图中我们在第1层(请看绿色标注)输出较大目标的实例分割结果, 在第2层输出次大目标的实例检测结果,在第3层输出较小目标的实例分割结果。 检测也是一样,我们会在第1层输出简单的目标,第2层输出较复杂的目标,第3层输出复杂的目标。

    小结

    作者提出的FPN(Feature Pyramid Network)算法同时利用低层特征高分辨率和高层特征的高语义信息,通过融合这些不同层的特征达到预测的效果。并且预测是在每个融合后的特征层上单独进行的,这和常规的特征融合方式不同。

    Mask-RCNN

    • 论文地址:https://arxiv.org/abs/1703.06870
    • 作者:Kaiming He,Georgia Gkioxari,Piotr Dollar,Ross Girshick
    • FAIR Detectron:https://github.com/facebookresearch/Detectron
    • tensorflow: https://github.com/matterport/Mask_RCNN

    Mask Scoring R-CNN

    • 论文地址:https://arxiv.org/abs/1903.00241
    • github: https://github.com/zjhuang22/maskscoring_rcnn

    @Mask Scoring RCNN的架构图

    One-stage方法

    以R-CNN算法为代表的two stage的方法由于RPN结构的存在,虽然检测精度越来越高,但是其速度却遇到瓶颈,比较难于满足部分场景实时性的需求。 因此出现一种基于回归方法的one stage的目标检测算法,不同于two stage的方法的分步训练共享检测结果,one stage的方法能实现完整单次 训练共享特征,且在保证一定准确率的前提下,速度得到极大提升。

    SSD原理与实现

    https://blog.csdn.net/u010712012/article/details/86555814 https://github.com/amdegroot/ssd.pytorch http://www.cs.unc.edu/~wliu/papers/ssd_eccv2016_slide.pdf

    CornerNet 人体姿态检测

    • paper出处:https://arxiv.org/abs/1808.01244
    • https://zhuanlan.zhihu.com/p/46505759

    RPN中的Anchor

    Anchor是RPN网络的核心。需要确定每个滑窗中心对应感受野内存在目标与否。由于目标大小和长宽比例不一,需要多个尺度的窗。Anchor即给出一个基准窗大小,按照倍数和长宽比例得到不同大小的窗。有了Anchor之后,才能通过Select Search的方法\Slide Windows方法进行选取ROI的。

    首先我们需要知道anchor的本质是什么,本质是SPP(spatial pyramid pooling)思想的逆向。而SPP本身是做什么的呢,就是将不同尺寸的输入resize成为相同尺寸的输出。所以SPP的逆向就是,将相同尺寸的输出,倒推得到不同尺寸的输入。

    接下来是anchor的窗口尺寸,这个不难理解,三个面积尺寸(128^2,256^2,512^2),然后在每个面积尺寸下,取三种不同的长宽比例(1:1,1:2,2:1).这样一来,我们得到了一共9种面积尺寸各异的anchor。示意图如下: @9个Anchor示意图 至于这个anchor到底是怎么用的,这个是理解整个问题的关键。

    • Faster RCNN
    • SSD
    • YOLO
    • Guided Anchor: https://arxiv.org/abs/1901.03278

    目标检测算法研究问题小结

    目标检测领域的深度学习算法,需要进行目标定位和物体识别,算法相对来说还是很复杂的。当前各种新算法也是层不出穷,但模型之间有很强的延续性,大部分模型算法都是借鉴了前人的思想,站在巨人的肩膀上。我们需要知道经典模型的特点,这些tricks是为了解决什么问题,以及为什么解决了这些问题。这样才能举一反三,万变不离其宗。综合下来,目标检测领域主要的难点如下:

    • 检测速度:实时性要求高,故网络结构不能太复杂,参数不能太多,卷积层次也不能太多。
    • 位置准确率(x y w h)参数必须准确,也就是检测框大小尺寸要匹配,且重合度IOU要高。SSD和faster RCNN通过多个bounding box来优化这个问题
    • 漏检率:必须尽量检测出所有目标物体,特别是靠的近的物体和尺寸小的物体。SSD和faster RCNN通过多个bounding box来优化这个问题
    • 物体宽高比例不常见:SSD通过不同尺寸feature map,yoloV2通过不同尺寸输入图片,来优化这个问题。
    • 靠的近的物体准确率低
    • 小尺寸物体准确率低:SSD取消全连接层,yoloV2增加pass through layer,采用高分辨率输入图片,来优化这个问题

    目标检测特殊层

    ROIpooling

    ROIs Pooling顾名思义,是Pooling层的一种,而且是针对RoIs的Pooling,他的特点是输入特征图尺寸不固定,但是输出特征图尺寸固定;

    ROI是Region of Interest的简写,指的是在“特征图上的框”;

    • 在Fast RCNN中, RoI是指Selective Search完成后得到的“候选框”在特征图上的映射,如下图中的红色框所示;
    • 在Faster RCNN中,候选框是经过RPN产生的,然后再把各个“候选框”映射到特征图上,得到RoIs。

    @

    参考faster rcnn中的ROI Pool层,功能是将不同size的ROI区域映射到固定大小的feature map上。

    缺点:由于两次量化带来的误差;

    • 将候选框边界量化为整数点坐标值。
    • 将量化后的边界区域平均分割成$k\times k$个单元(bin),对每一个单元的边界进行量化。

    案例说明

    下面我们用直观的例子具体分析一下上述区域不匹配问题。如 图1 所示,这是一个Faster-RCNN检测框架。输入一张$800\times 800$的图片,图片上有一个$665\times 665$的包围框(框着一只狗)。图片经过主干网络提取特征后,特征图缩放步长(stride)为32。因此,图像和包围框的边长都是输入时的1/32。800正好可以被32整除变为25。但665除以32以后得到20.78,带有小数,于是ROI Pooling 直接将它量化成20。接下来需要把框内的特征池化$7\times7$的大小,因此将上述包围框平均分割成$7\times7$个矩形区域。显然,每个矩形区域的边长为2.86,又含有小数。于是ROI Pooling 再次把它量化到2。经过这两次量化,候选区域已经出现了较明显的偏差(如图中绿色部分所示)。更重要的是,该层特征图上0.1个像素的偏差,缩放到原图就是3.2个像素。那么0.8的偏差,在原图上就是接近30个像素点的差别,这一差别不容小觑。

    caffe中实现roi_pooling_layer.cpp

    template <typename Dtype>
    void ROIPoolingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
          const vector<Blob<Dtype>*>& top) {
      //输入有两部分组成,data和rois
      const Dtype* bottom_data = bottom[0]->cpu_data();
      const Dtype* bottom_rois = bottom[1]->cpu_data();
      // ROIs的个数
      int num_rois = bottom[1]->num();
      int batch_size = bottom[0]->num();
      int top_count = top[0]->count();
      Dtype* top_data = top[0]->mutable_cpu_data();
      caffe_set(top_count, Dtype(-FLT_MAX), top_data);
      int* argmax_data = max_idx_.mutable_cpu_data();
      caffe_set(top_count, -1, argmax_data);
    
      // For each ROI R = [batch_index x1 y1 x2 y2]: max pool over R
      for (int n = 0; n < num_rois; ++n) {
        int roi_batch_ind = bottom_rois[0];
        // 把原图的坐标映射到feature map上面
        int roi_start_w = round(bottom_rois[1] * spatial_scale_);
        int roi_start_h = round(bottom_rois[2] * spatial_scale_);
        int roi_end_w = round(bottom_rois[3] * spatial_scale_);
        int roi_end_h = round(bottom_rois[4] * spatial_scale_);
        // 计算每个roi在feature map上面的大小
        int roi_height = max(roi_end_h - roi_start_h + 1, 1);
        int roi_width = max(roi_end_w - roi_start_w + 1, 1);
        //pooling之后的feature map的一个值对应于pooling之前的feature map上的大小
        //注:由于roi的大小不一致,所以每次都需要计算一次
        const Dtype bin_size_h = static_cast<Dtype>(roi_height)
                                 / static_cast<Dtype>(pooled_height_);
        const Dtype bin_size_w = static_cast<Dtype>(roi_width)
                                 / static_cast<Dtype>(pooled_width_);
        //找到对应的roi的feature map,如果input data的batch size为1
        //那么roi_batch_ind=0
        const Dtype* batch_data = bottom_data + bottom[0]->offset(roi_batch_ind);
        //pooling的过程是针对每一个channel的,所以需要循环遍历
        for (int c = 0; c < channels_; ++c) {
          //计算output的每一个值,所以需要遍历一遍output,然后求出所有值
          for (int ph = 0; ph < pooled_height_; ++ph) {
            for (int pw = 0; pw < pooled_width_; ++pw) {
              // Compute pooling region for this output unit:
              //  start (included) = floor(ph * roi_height / pooled_height_)
              //  end (excluded) = ceil((ph + 1) * roi_height / pooled_height_)
              // 计算output上的一点对应于input上面区域的大小[hstart, wstart, hend, wend]
              int hstart = static_cast<int>(floor(static_cast<Dtype>(ph)
                                                  * bin_size_h));
              int hend = static_cast<int>(ceil(static_cast<Dtype>(ph + 1)
                                               * bin_size_h));
              int wstart = static_cast<int>(floor(static_cast<Dtype>(pw)
                                                  * bin_size_w));
              int wend = static_cast<int>(ceil(static_cast<Dtype>(pw + 1)
                                               * bin_size_w));
              //将映射后的区域平动到对应的位置[hstart, wstart, hend, wend]
              hstart = min(max(hstart + roi_start_h, 0), height_);
              hend = min(max(hend + roi_start_h, 0), height_);
              wstart = min(max(wstart + roi_start_w, 0), width_);
              wend = min(max(wend + roi_start_w, 0), width_);
              //如果映射后的矩形框不符合
              bool is_empty = (hend <= hstart) || (wend <= wstart);
              //pool_index指的是此时计算的output的值对应于output的位置
              const int pool_index = ph * pooled_width_ + pw;
              //如果矩形不符合,此处output的值设为0,此处的对应于输入区域的最大值为-1
              if (is_empty) {
                top_data[pool_index] = 0;
                argmax_data[pool_index] = -1;
              }
              //遍历output的值对应于input的区域块
              for (int h = hstart; h < hend; ++h) {
                for (int w = wstart; w < wend; ++w) {
                 // 对应于input上的位置
                  const int index = h * width_ + w;
                  //计算区域块的最大值,保存在output对应的位置上
                  //同时记录最大值的索引
                  if (batch_data[index] > top_data[pool_index]) {
                    top_data[pool_index] = batch_data[index];
                    argmax_data[pool_index] = index;
                  }
                }
              }
            }
          }
          // Increment all data pointers by one channel
          batch_data += bottom[0]->offset(0, 1);
          top_data += top[0]->offset(0, 1);
          argmax_data += max_idx_.offset(0, 1);
        }
        // Increment ROI data pointer
        bottom_rois += bottom[1]->offset(1);
      }
    }
    

    ROI Align

    @ROIAlign模块使用示意图

    为了解决ROI Pooling的上述缺点,作者提出了ROI Align这一改进的方法。ROI Align的思路很简单:取消量化操作,使用双线性内插的方法获得坐标为浮点数的像素点上的图像数值,从而将整个特征聚集过程转化为一个连续的操作。值得注意的是,在具体的算法操作上,ROI Align并不是简单地补充出候选区域边界上的坐标点,然后将这些坐标点进行池化,而是重新设计了一套比较优雅的流程,如下图所示: @浮点坐标计算过程

    • 遍历每一个候选区域,保持浮点数边界不做量化。
    • 将候选区域分割成$k\times k$个单元,每个单元的边界也不做量化。
    • 在每个单元中计算固定四个坐标位置,用双线性内插的方法计算出这四个位置的值,然后进行最大池化操作。

    这里对上述步骤的第三点作一些说明:这个固定位置是指在每一个矩形单元(bin)中按照固定规则确定的位置。比如,如果采样点数是1,那么就是这个单元的中心点。如果采样点数是4,那么就是把这个单元平均分割成四个小方块以后它们分别的中心点。显然这些采样点的坐标通常是浮点数,所以需要使用插值的方法得到它的像素值。在相关实验中,作者发现将采样点设为4会获得最佳性能,甚至直接设为1在性能上也相差无几。 事实上,ROIAlign在遍历取样点的数量上没有ROIPooling那么多,但却可以获得更好的性能,这主要归功于解决了misalignment的问题。值得一提的是,我在实验时发现,ROIAlign在VOC2007数据集上的提升效果并不如在COCO上明显。经过分析,造成这种区别的原因是COCO上小目标的数量更多,而小目标受misalignment问题的影响更大(比如,同样是0.5个像素点的偏差,对于较大的目标而言显得微不足道,但是对于小目标,误差的影响就要高很多)。ROIAlign层要将feature map固定为2*2大小,那些蓝色的点即为采样点,然后每个bin中有4个采样点,则这四个采样点经过MAX得到ROI output;

    通过双线性插值避免了量化操作,保存了原始ROI的空间分布,有效避免了误差的产生;小目标效果比较好

    NMS算法优化的必要性

    NMS算法的功能

    非极大值抑制(NMS)非极大值抑制顾名思义就是抑制不是极大值的元素,搜索局部的极大值。例如在对象检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分类及分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是某类对象的概率最大),并且抑制那些分数低的窗口。印象最为深刻的就是Overfeat算法中的狗熊抓鱼图了。

    从R-CNN到SPPNet

    $RCNN$主要作用就是用于物体检测,就是首先通过$selective search$选择$2000$个候选区域,这些区域中有我们需要的所对应的物体的bounding-box,然后对于每一个region proposal都wrap到固定的大小的scale, $227\times227$(AlexNet Input),对于每一个处理之后的图片,把他都放到CNN上去进行特征提取,得到每个region proposal的feature map,这些特征用固定长度的特征集合feature vector来表示。 最后对于每一个类别,我们都会得到很多的feature vector,然后把这些特征向量直接放到SVM现行分类器去判断,当前region所对应的实物是background还是所对应的物体类别,每个region都会给出所对应的score,因为有些时候并不是说这些region中所包含的实物就一点都不存在,有些包含的多有些包含的少,包含的多少还需要合适的bounding box,所以我们才会对于每一region给出包含实物类别多少的分数,选出前几个对大数值,然后再用非极大值抑制canny来进行边缘检测,最后就会得到所对应的bounding box.

    Alt text 同样,SPPNet作者观察得,对selective search(ss)提供的2000多个候选区域都逐一进行卷积处理,势必会耗费大量的时间, 所以SPPNet中先对一整张图进行卷积得到特征图,然后再将ss算法提供的2000多个候选区域的位置记录下来,通过比例映射到整张图的feature map上提取出候选区域的特征图B,然后将B送入到金字塔池化层中,进行权重计算. 然后经过尝试,这种方法是可行的,于是在RCNN基础上,进行了这两个优化得到了这个新的网络SPPNet.

    Faster RCNN

    NMS算法,非极大值抑制算法,引入NMS算法的目的在于:根据事先提供的score向量,以及regions(由不同的bounding boxes,矩形窗口左上和右下点的坐标构成) 的坐标信息,从中筛选出置信度较高的bounding boxes。

    @FasterRCNN中的NMS的作用

    @FasterRCNN中anchor推荐框的个数 Faster RCNN中输入s=600时,采用了三个尺度的anchor进行推荐,分别时128,256和512,其中推荐的框的个数为$1106786$,需要将这$1100k$的推荐框合并为$2k$个。这个过程其实正是$RPN$神经网络模型。

    SSD

    https://blog.csdn.net/wfei101/article/details/78176322 SSD算法中是分为default box(下图中(b)中为default box示意图)和prior box(实际推荐的框) @SSD算法中的anchor box和default box示意图

    @SSD算法架构图

    SSD算法推荐框的个数

    注意

    在图像处理领域,几点经验:

    1. 输入的图像越大,结果越准确,但是计算量也更多
    2. 推荐的框越多,定位准确的概率更高,但是计算量也是会增多
    3. 推荐的框往往远大于最终的定位的个数

    那么NMS存在什么问题呢,其中最主要的问题有这么几个:

    • 物体重叠:如下面第一张图,会有一个最高分数的框,如果使用nms的话就会把其他置信度稍低,但是表示另一个物体的预测框删掉(由于和最高置信度的框overlap过大)
    • 某些情况下,所有的bbox都预测不准,对于下面第二张图我们看到,不是所有的框都那么精准,有时甚至会出现某个物体周围的所有框都标出来了,但是都不准的情况
    • 传统的NMS方法是基于分类分数的,只有最高分数的预测框能留下来,但是大多数情况下IoU和分类分数不是强相关,很多分类标签置信度高的框都位置都不是很准

    参考文献

    1. NMS的解释
    2. 附录中ROI的解释
    3. SSD算法
    4. One-Stage Detector, With Focal Loss and RetinaNet Using ResNet+FPN, Surpass the Accuracy of Two-Stage Detectors, Faster R-CNN
    5. 非极大值抑制算法的两个改进算法 & 传统NMS的问题
    6. 非极大值抑制算法(NMS)与源码分析

    one-stage和two-stage的anchor-base detection

    它们的主要区别

    • one-stage网络速度要快很多
    • one-stage网络的准确性要比two-stage网络要低

    为什么one-stage网络速度要快很多?

    首先来看第一点这个好理解,one-stage网络生成的anchor框只是一个逻辑结构,或者只是一个数据块,只需要对这个数据块进行分类和回归就可以,不会像two-stage网络那样,生成的 anchor框会映射到feature map的区域(rcnn除外),然后将该区域重新输入到全连接层进行分类和回归,每个anchor映射的区域都要进行这样的分类和回归,所以它非常耗时

    为什么one-stage网络的准确性要比two-stage网络要低?

    我们来看RCNN,它是首先在原图上生成若干个候选区域,这个候选区域表示可能会是目标的候选区域,注意,这样的候选区域肯定不会特别多,假如我一张图像是$100\times100$的,它可能会生成2000个候选框,然后再把这些候选框送到分类和回归网络中进行分类和回归,Fast R-CNN其实差不多,只不过它不是最开始将原图的这些候选区域送到网络中,而是在最后一个feature map将这个候选区域提出来,进行分类和回归,它可能最终进行分类和回归的候选区域也只有2000多个并不多。再来看Faster R-CNN,虽然Faster R-CNN它最终一个feature map它是每个像素点产生9个anchor,那么$100\times100$假如到最终的feature map变成了$26\times26$了,那么生成的anchor就是个,虽然看似很多,但是其实它在RPN网络结束后,它会不断的筛选留下2000多个,然后再从2000多个中筛选留下300多个,然后再将这300多个候选区域送到最终的分类和回归网络中进行训练,所以不管是R-CNN还是Fast-RCNN还是Faster-RCNN,它们最终进行训练的anchor其实并不多,几百到几千,不会存在特别严重的正负样本不均衡问题. 但是我们再来看yolo系列网络,就拿yolo3来说吧,它有三种尺度,$13\times 13$,$26\times 26$,$52\times 52$,每种尺度的每个像素点生成三种anchor,那么它最终生成的anchor数目就是 个anchor,而真正负责预测的可能每种尺度的就那么几个,假如一张图片有3个目标,那么每种尺度有三个anchor负责预测,那么10647个anchor中总共也只有9个anchor负责预测,也就是正样本,其余的10638个anchor都是背景anchor,这存在一个严重的正负样本失衡问题,虽然位置损失,类别损失,这10638个anchor不需要参与,但是目标置信度损失,背景anchor参与了,因为

    所以背景anchor对总的损失有了很大的贡献,但是我们其实不希望这样的,我们更希望的是非背景的anchor对总的损失贡献大一些,这样不利于正常负责预测anchor的学习,而two-stage网络就不存在这样的问题,two-stage网络最终参与训练的或者计算损失的也只有2000个或者300个,它不会有多大的样本不均衡问题,不管是正样本还是负样本对损失的贡献几乎都差不多,所以网络会更有利于负责预测anchor的学习,所以它最终的准确性肯定要高些

    总结

    one-stage网络最终学习的anchor有很多,但是只有少数anchor对最终网络的学习是有利的,而大部分anchor对最终网络的学习都是不利的,这部分的anchor很大程度上影响了整个网络的学习,拉低了整体的准确率;而two-stage网络最终学习的anchor虽然不多,但是背景anchor也就是对网络学习不利的anchor也不会特别多,它虽然也能影响整体的准确率,但是肯定没有one-stage影响得那么严重,所以它的准确率比one-stage肯定要高。

    那么什么情况下背景anchor不会拉低这个准确率呢?

    设置阀值,与真实GrundTruth IOU阀值设得小一点,只要大于这个阀值,就认为你是非背景anchor(注意这部分anchor只负责计算目标置信度损失,而位置、类别损失仍然还是那几个负责预测的anchor来负责)或者假如一个图片上有非常多的位置都是目标,这样很多anchor都不是背景anchor;总之保证背景anchor和非背景anchor比例差不多,那样可能就不会拉低这个准确率,但是只要它们比例相差比较大,那么就会拉低这个准确率,只是不同的比例,拉低的程度不同而已

    解决one-stage网络背景anchor过多导致的不均衡问题方案

    • 采用focal loss,将目标置信度这部分的损失换成focal loss
    • 增大非背景anchor的数量

    某个像素点生成的三个anchor,与真实GrundTruth重合最大那个负责预测,它负责计算位置损失、目标置信度损失、类别损失,这些不管,它还有另外两个anchor,虽然另外两个anchor不是与真实GrundTruth重合最大,但是只要重合大于某个阀值比如大于0.7,我就认为它是非背景anchor,但注意它只计算目标置信度损失,位置和类别损失不参与计算,而小于0.3的我直接不让它参与目标置信度损失的计算,实现也就是将它的权重置0,这个思想就类似two-stage网络那个筛选机制,从2000多个anchor中筛选300个参与训练或者计算目标置信度损失,相当于我把小于0.3的anchor我都筛选掉了,让它不参与损失计算

    • 设置权重 在目标置信度损失计算时,将背景anchor的权重设置得很小,非背景anchor的权重设置得很大。

    四步交替训练Faster RCNN

    训练RPN网络

    Faster RCNN有两种训练方式,一种是四步交替训练法,一种是end-to-end训练法。主文件位于/tools/train_fast_rcnn_alt_opt.py。

    第一步,训练RPN,该网络用ImageNet预训练的模型初始化,并端到端微调,用于生成region proposal;

    第二步,由imageNet model初始化,利用第一步的RPN生成的region proposals作为输入数据,训练Fast R-CNN一个单独的检测网络,这时候两个网络还没有共享卷积层;

    第三步,用第二步的fast-rcnn model初始化RPN再次进行训练,但固定共享的卷积层,并且只微调RPN独有的层,现在两个网络共享卷积层了;

    第四步,由第三步的RPN model初始化fast-RCNN网络,输入数据为第三步生成的proposals。保持共享的卷积层固定,微调Fast R-CNN的fc层。这样,两个网络共享相同的卷积层,构成一个统一的网络。

    Faster-RCNN和YOLO的anchor有什么区别

    @FasterRCNN generator anchor

    可以看到yolov3是直接对你的训练样本进行k-means聚类,由训练样本得来的先验框(anchor),也就是对样本聚类的结果。Kmeans因为初始点敏感,所以每次运行得到的anchor值不一样,但是对应的avg iou稳定。用于训练的话就需要统计多组anchor,针对固定的测试集比较了。

    • https://blog.csdn.net/xiqi4145/article/details/86516511

    • https://blog.csdn.net/cgt19910923/article/details/82154401

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Megvii:计算机视觉之物体检测与深度神经网络模型设计专场
    机遇 research之路其修远兮,我将上下而求索

    Megvii:计算机视觉之物体检测与深度神经网络模型设计专场

    2019-05-11
    cwlseu

    概述

    今天主要围绕计算机视觉领域的一些任务中,如何提高score的方面进行了各种方面的讨论。研究领域包括:基本的场景的物体检测,开放领域的物体检测,不规则文本检测。涉及的相关技术有

    • 在backbone设计中总结的一些tips;
    • 如何在物体检测领域,通过分析对比各种方法,提出自己的解决方案;
    • 物体检测领域中多尺度问题的重要性;
    • anchor是什么东西,anchor free和anchor base之间的 vs
    • attention在计算机视觉中的应用SENet

    Deform ConvNet(DCN)1 v.s. ConvNet

    这个专题主要是为了改善遮挡和分割算法而做的相关研究。在普通的卷积中,加入旋转,scale等特性,使得能够对一个非正方凸区域进行卷积。这就可以使得卷积提取特征不仅仅局限在的一个方正的空间区域,可以根据物体的形状等等学习到相关的角度变化等权重,从而实现对非规则空间区域的特征提取。这无疑将物体分割任务直接统一为物体检测任务,还是比较nice的构想。虽然有好处,但由于多个计算过程中引入了非规则的问题,导致计算速度方面可能受到一定的影响。

    Review Object Detection from anchor base to anchor-free

    这个主要通过介绍anchor-base和anchor-free的发展路线,讨论两种方法的之间的优劣之处。认为现在anchor-base的research空间已经有限,所以开始考虑向anchor-free开始进展。anchor-base需要设置较多的超参数,落地的过程中存在较大的调参困难。而anchor-free相对来说,比较少。

    @detection blueprint

    当前scene text detection中的一些问题和研究进展

    这个话题我还比较感兴趣的。因为我后面要做一些自然场景文本检测的一个项目,所以最近在突击这方面的论文。而这个论坛中关于自然场景文本检测的分享让我受益颇丰。我才发现原来要找的相关文献很多都是白翔老师这个组的工作。

    白翔,华中科技大学电信学院教授,先后于华中大获得学士、硕士、博士学位。他的主要研究领域为计算机视觉与模式识别、深度学习应用技术。尤其在形状的匹配与检索、相似性度量与融合、场景OCR取得了一系列重要研究成果,入选2014、2015、2016年Elsevier中国高被引学者。他的研究工作曾获微软学者,首届国家自然科学基金优秀青年基金的资助。他已在相关领域一流国际期刊或会议如PAMI、IJCV、CVPR、ICCV、ECCV、NIPS、ICML、AAAI、IJCAI上发表论文40余篇。任国际期刊Pattern Recognition, Pattern Recognition Letters, Neurocomputing, Frontier of Computer Science编委,VALSE指导委员,曾任VALSE在线委员会(VOOC)主席, VALSE 2016大会主席, 是VALSE在线活动(VALSE Webinar)主要发起人之一。

    现在还是没有入门,师傅已经带我走马观花了,剩下的就是我自己细细品读各个方法的奥秘了。

    暂时定的路线是:

    1. SWT,MSER两个经典方法和衍生方法
    2. 引入CNN之后如何演变到CNN+LSTM的方法
    3. 分割技术如何提升不规则排布文本检测的234

    需要思考的内容:

    1. 常用数据集,和应用场景的实际数据之间的差别
    2. 各个方法之间的改进策略的出发点是什么,有什么收获?
    3. 水平文本检测性能、速度比较推荐的算法是什么,简单应用场景呢?
    4. 常规检测算法的与文本检测算法之间能不能直接迁移应用,有什么gap,克服这个gap需要做什么工作
    5. 分割算法应用到文本检测中有什么结果,为什么会对非规则文本检测有好处

    相关文献及blog

    1. https://arxiv.org/abs/1703.06211 “Deformable Convolutional Networks” 

    2. https://arxiv.org/abs/1811.00751 “Show, Attend and Read: A Simple and Strong Baseline for Irregular Text Recognition” 

    3. https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/81437413 “Mask TextSpotter: An End-to-End Trainable Neural Network for Spotting Text with Arbitrary Shapes” 

    4. https://blog.csdn.net/francislucien2017/article/details/88583219 “不规则文字识别方法之 SAR: Show, Attend and Read” 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    关于开发中常见的编译器技巧
    机遇 research之路其修远兮,我将上下而求索

    关于开发中常见的编译器技巧

    2019-04-11
    cwlseu

    引言

    编译器是我们开发人员与机器指令之间的翻译,现在编译器越来越优化,而且基于一些开源的编译器项目(gcc,clang)等,相继出现不同platform下的编译器。 此外,各种芯片、开发板层出不穷,各个商业公司都针对自己出产的开发板定制特定的编译链条。例如华为hisi系列的himix100中提供的编译链中,包括编译器,链接器,打包器之外,还提供了nm,gdb,gcov,gprof等等开发工具。 这篇文章将主要将开发工作中与编译器(这篇文章中不作特殊说明,指的是gnu gcc编译器)相关的一些options和配置参数进行总结,方便在后面的项目遇到相似的问题进行查阅与借鉴。

    编译常见问题

    包含静态库中所有符号的option

    编译shared target B库的时候,gcc编译器默认是用什么区什么的原则,也就是说,依赖了库A中哪个.o文件中的东西,就会把相应的.o文件 打包到最终的库中。但是,有的时候在这个库中我们并没有引用全部的符号,但是当其他库C依赖我们这个B库的时候,如果引用了B中未引用的A中的符号,这个时候会出现”undefined reference”的编译错误。-Wl,--whole-archive可以实现将所有库中的符号打包进去。

    编译器编译动态库或者运行程序的时候,会对依赖的静态库中进行基于.o的选择,但是有的时候我们希望我们编译的动态库能够包含所有的函数实现给用户使用。gcc中的链接控制选项-Wl,--whole-archive xxxxx_lib -Wl,--no-whole-archive就可以实现类似功能。

    target_link_libraries(xxxx_export 
                PRIVATE "-Wl,--whole-archive" $<TARGET_FILE:xxxxx_lib>
                        "-Wl,--no-whole-archive -Wl,--exclude-libs,ALL")
    

    其他可能问题

    --exclude-libs does not work for static libraries affected by the --whole-archive option.

    • --exclude-libs creates a list of static library paths and does library lookups in this list.
    • --whole-archive splits the static libraries that follow it into separate objects. As a result, lld no longer sees static libraries among linked files and does no --exclude-libs lookups.

    Solution

    The proposed solution is to make --exclude-libs consider object files too. When lld finds an object file it checks whether this file originates from an archive and, if so, looks the archive up in the --exclude-libs list.

    Reference: https://reviews.llvm.org/D39353

    编译运行查找头文件和库的顺序

    gcc 在编译时如何去寻找所需要的头文件:

    • 所以header file的搜寻会从-I开始
    • 然后找gcc的环境变量 C_INCLUDE_PATHCPLUS_INCLUDE_PATHOBJC_INCLUDE_PATH
    • 再找内定目录
      • /usr/include
      • /usr/local/include

    gcc的一系列自带目录 CPLUS_INCLUDE_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.9.4/include:/usr/include/c++/4.9.4

    库文件

    编译的时候:

    • gcc会去找-L
    • 再找gcc的环境变量LIBRARY_PATH
    • 再找内定目录
      • /lib/lib64
      • /usr/lib/usr/lib64
      • /usr/local/lib/usr/local/lib64

    这是当初compile gcc时写在程序内的

    运行时动态库的搜索路径

    动态库的搜索路径搜索的先后顺序是:

    1. 编译目标代码时指定的动态库搜索路径;
    2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
    3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
    4. 默认的动态库搜索路径/lib
    5. 默认的动态库搜索路径/usr/lib

    动态库中的static变量

    In all cases, static global variables (or functions) are never visible from outside a module (dll/so or executable). The C++ standard requires that these have internal linkage, meaning that they are not visible outside the translation unit (which becomes an object file) in which they are defined.

    windows编译

    在windows常用的编译器是VS里面的cl编译器。我们要实现上述 cmake使用cmake -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=TRUE

    Enable this boolean property to automatically create a module definition (.def) file with all global symbols found in the input .obj files for a SHARED library on Windows. The module definition file will be passed to the linker causing all symbols to be exported from the .dll. For global data symbols, __declspec(dllimport) must still be used when compiling against the code in the .dll. All other function symbols will be automatically exported and imported by callers. This simplifies porting projects to Windows by reducing the need for explicit dllexport markup, even in C++ classes.
    
    This property is initialized by the value of the CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS variable if it is set when a target is created.
    

    Reference: WINDOWS_EXPORT_ALL_SYMBOLS

    windows下路径长度不能太长

    error MSB3491: Could n ot write lines to file https://stackoverflow.com/questions/31765909/node-socket-io-client-windows-path-too-long-to-install

    MSVC中预定义宏1

    • _M_IX86 Defined as the integer literal value 600 for compilations that target x86 processors. This macro isn’t defined for x64 or ARM compilation targets.

    • _M_IX86_FP Defined as an integer literal value that indicates the /arch compiler option that was set, or the default. This macro is always defined when the compilation target is an x86 processor. Otherwise, undefined. When defined, the value is:
      • 0 if the /arch:IA32 compiler option was set.
      • 1 if the /arch:SSE compiler option was set.
      • 2 if the /arch:SSE2, /arch:AVX, /arch:AVX2, or /arch:AVX512 compiler option was set. This value is the default if an /arch compiler option wasn’t specified. When /arch:AVX is specified, the macro __AVX__ is also defined. When /arch:AVX2 is specified, both __AVX__ and __AVX2__ are also defined. When /arch:AVX512 is specified, __AVX__, __AVX2__, __AVX512BW__, __AVX512CD__, __AVX512DQ__, __AVX512F__ and __AVX512VL__ are also defined.

      For more information, see /arch (x86).

    • _M_X64 Defined as the integer literal value 100 for compilations that target x64 processors. Otherwise, undefined.

    • _MSC_VER Defined as an integer literal that encodes the major and minor number elements of the compiler’s version number. The major number is the first element of the period-delimited version number and the minor number is the second element. For example, if the version number of the Microsoft C/C++ compiler is 17.00.51106.1, the _MSC_VER macro evaluates to 1700. Enter cl /? at the command line to view the compiler’s version number. This macro is always defined.

      Visual Studio version _MSC_VER
      Visual Studio 6.0 1200
      Visual Studio .NET 2002 (7.0) 1300
      Visual Studio .NET 2003 (7.1) 1310
      Visual Studio 2005 (8.0) 1400
      Visual Studio 2008 (9.0) 1500
      Visual Studio 2010 (10.0) 1600
      Visual Studio 2012 (11.0) 1700
      Visual Studio 2013 (12.0) 1800
      Visual Studio 2015 (14.0) 1900
      Visual Studio 2017 RTW (15.0) 1910
      Visual Studio 2017 version 15.3 1911
      Visual Studio 2017 version 15.5 1912
      Visual Studio 2017 version 15.6 1913
      Visual Studio 2017 version 15.7 1914
      Visual Studio 2017 version 15.8 1915
      Visual Studio 2017 version 15.9 1916
      Visual Studio 2019 RTW (16.0) 1920
      Visual Studio 2019 version 16.1 1921
      Visual Studio 2019 version 16.2 1922
      Visual Studio 2019 version 16.3 1923
    • _MSVC_LANG Defined as an integer literal that specifies the C++ language standard targeted by the compiler. It’s set only in code compiled as C++. The macro is the integer literal value 201402L by default, or when the /std:c++14 compiler option is specified. The macro is set to 201703L if the /std:c++17 compiler option is specified. It’s set to a higher, unspecified value when the /std:c++latest option is specified. Otherwise, the macro is undefined. The _MSVC_LANG macro and /std (Specify Language Standard Version) compiler options are available beginning in Visual Studio 2015 Update 3.

    • _MT Defined as 1 when /MD or /MDd (Multithreaded DLL) or /MT or /MTd (Multithreaded) is specified. Otherwise, undefined.

    • _WIN32 Defined as 1 when the compilation target is 32-bit ARM, 64-bit ARM, x86, or x64. Otherwise, undefined.

    • _WIN64 Defined as 1 when the compilation target is 64-bit ARM or x64. Otherwise, undefined.

    GNU 编译器

    gcc/g++的--as-needed

    gcc/g++提供了-Wl,--as-needed-Wl,--no-as-needed两个选项,这两个选项一个是开启特性,一个是取消该特性。

    在生成可执行文件的时候,通过 -lxxx 选项指定需要链接的库文件。以动态库为例,如果我们指定了一个需要链接的库,则连接器会在可执行文件的文件头中会记录下该库的信息。而后,在可执行文件运行的时候,动态加载器会读取文件头信息,并加载所有的链接库。在这个过程中,如果用户指定链接了一个毫不相关的库,则这个库在最终的可执行程序运行时也会被加载,如果类似这样的不相关库很多,会明显拖慢程序启动过程。

    这时,通过指定-Wl,--as-needed选项,链接过程中,链接器会检查所有的依赖库,没有实际被引用的库,不再写入可执行文件头。最终生成的可执行文件头中包含的都是必要的链接库信息。-Wl,--no-as-needed选项不会做这样的检查,会把用户指定的链接库完全写入可执行文件中。

    Reference: GCC/G++选项 -Wl,–as-needed

    -rdynamic

    Pass the flag `-export-dynamic` to the ELF linker, on targets that support
    it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of `dlopen` or to allow obtaining backtraces from within a program.
    

    关键的不同是:-Wl,--export-dynamic -pthread -Wl:指示后面的选项是给链接器的 -pthread: 链接程序的时包含libpthread.so --export-dynamic:就是这个选项让主程序内定义的全局函数对库函数可见。

    Reference: gcc链接选项–export-dynamic的一次问题记录

    _GLIBCXX_USE_CXX11_ABI

    在GCC 5.1版本中,libstdc++引入了一个新的ABI,其中包括std::string和std::list的新实现。为了符合2011年c++标准,这些更改是必要的,该标准禁止复制即写字符串,并要求列表跟踪字符串的大小。 为了保持与libstdc++链接的现有代码的向后兼容性,库的soname没有更改,并且仍然支持与新实现并行的旧实现。这是通过在内联命名空间中定义新的实现来实现的,因此它们具有不同的用于链接目的的名称,例如,std::list的新版本实际上定义为std:: _cxx11::list。因为新实现的符号有不同的名称,所以两个版本的定义可以出现在同一个库中。 _GLIBCXX_USE_CXX11_ABI宏控制库头中的声明是使用旧ABI还是新ABI。因此,可以为正在编译的每个源文件分别决定使用哪个ABI。使用GCC的默认配置选项,宏的默认值为1,这将导致新的ABI处于活动状态,因此要使用旧的ABI,必须在包含任何库头之前显式地将宏定义为0。(注意,一些GNU/Linux发行版对GCC 5的配置不同,因此宏的默认值是0,用户必须将它定义为1才能启用新的ABI)。

    IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.1")
    	ADD_DEFINITIONS(-D_GLIBCXX_USE_CXX11_ABI=0)
    ENDIF()
    

    -Wl,–allow-shlib-undefined

    在交叉编译程序过程中,往往会有这样的情况,依赖的target系统上的动态库(例如android上的OpenCL.so)又依赖其他的许多动态库,这个时候,我们希望链接target系统上的这个动态库的时候,我们可以不要去找OpenCL相关的依赖符号。

    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-shlib-undefined")

    Linking errors with “-Wl,–no-undefined -Wl,–no-allow-shlib-undefined”

    第二个参数的默认值是--allow-shlib-undefined。如果您选择该选项,代码可能会生成。 第二个参数处理构建时检查,启用它意味着检查您所链接的库是否在构建时连接了其依赖项。

    第一个参数确保您没有忘记声明对运行时库的依赖项(也可能是运行时库对另一个运行时库的依赖项)。 例如,如果您调用的函数的实现位于示例运行时库“libfunc”中。然后这个库会调用另一个运行时库中的函数libext。然后通过声明对libfunc的“func”和“ext”的依赖关系。因此,将在内部生成一个对libext的依赖引用。 如果您省略--no undefined并忘记添加依赖项声明,那么构建仍然会成功,因为您相信运行时链接器将在运行时解析依赖项。 由于构建成功了,您可能会相信一切都会好起来,而不知道构建已经将责任推迟到运行时链接器。 但大多数情况下,运行时链接器的设计目的不是搜索未解析的引用,而是希望找到运行时库中声明的此类依赖项。如果没有这样的引用,您将得到一个运行时错误。 运行时错误通常比解决编译时错误要昂贵得多。

    target_link_libraries 会将需要链接的库作为属性挂在目标库上, 后面用户用到这个库的时候可以通过get_target_property(interface_link_libs ${} TARGET_LINK_LIBRARIES)进行获取相应的值。

    GCC不同版本中一些东西

    GCC4.9.4

    The -Wdate-time option has been added for the C, C++ and Fortran compilers, which warns when the __DATE__, __TIME__ or __TIMESTAMP__ macros are used. Those macros might prevent bit-wise-identical reproducible compilations.

    With the new #pragma GCC ivdep, the user can assert that there are no loop-carried dependencies which would prevent concurrent execution of consecutive iterations using SIMD (single instruction multiple data) instructions.

    Inter-procedural optimization improvements:

    • New type inheritance analysis module improving devirtualization. Devirtualization now takes into account anonymous name-spaces and the C++11 final keyword.
    • New speculative devirtualization pass (controlled by -fdevirtualize-speculatively.
    • Calls that were speculatively made direct are turned back to indirect where direct call is not cheaper.
    • Local aliases are introduced for symbols that are known to be semantically equivalent across shared libraries improving dynamic linking times.

    Feedback directed optimization improvements:

    • Profiling of programs using C++ inline functions is now more reliable.
    • New time profiling determines typical order in which functions are executed.
    • A new function reordering pass (controlled by -freorder-functions) significantly reduces startup time of large applications. Until binutils support is completed, it is effective only with link-time optimization.
    • Feedback driven indirect call removal and devirtualization now handle cross-module calls when link-time optimization is enabled.

    https://gcc.gnu.org/gcc-4.9/porting_to.html

    GCC 5.4

    • The default mode for C is now -std=gnu11 instead of -std=gnu89.
    • The C++ runtime library (libstdc++) uses a new ABI by default (see below).
    • The non-standard C++0x type traits has_trivial_default_constructor, has_trivial_copy_constructor and has_trivial_copy_assign have been deprecated and will be removed in a future version. The standard C++11 traits is_trivially_default_constructible, is_trivially_copy_constructible and is_trivially_copy_assignable should be used instead.

    • 添加-fipa-icf的配置项目

      An Identical Code Folding (ICF) pass (controlled via -fipa-icf) has been added. Compared to the identical code folding performed by the Gold linker this pass does not require function sections. It also performs merging before inlining, so inter-procedural optimizations are aware of the code re-use. On the other hand not all unifications performed by a linker are doable by GCC which must honor aliasing information.

    • The devirtualization pass was significantly improved by adding better support for speculative devirtualization and dynamic type detection.

    • 虚表进行了优化以减少动态链接时间 Virtual tables are now optimized. Local aliases are used to reduce dynamic linking time of C++ virtual tables on ELF targets and data alignment has been reduced to limit data segment bloat.

    • 添加针对不允许插入导出符号的shared库,添加了控制项目以提高代码质量

      A new -fno-semantic-interposition option can be used to improve code quality of shared libraries where interposition of exported symbols is not allowed.

    • 内联可以控制

      With profile feedback the function inliner can now bypass –param inline-insns-auto and –param inline-insns-single limits for hot calls.

    • 常量的过程间传播现在也传播指针参数的对齐。

      The interprocedural propagation of constants now also propagates alignments of pointer parameters. This for example means that the vectorizer often does not need to generate loop prologues and epilogues to make up for potential misalignments.

    • 内存使用上一些优化

      Memory usage and link times were improved. Tree merging was sped up, memory usage of GIMPLE declarations and types was reduced, and, support for on-demand streaming of variable constructors was added.

    libstd++上的优化

    • Dual ABI
    • A new implementation of std::string is enabled by default, using the small string optimization(SSO) instead of copy-on-write(COW) reference counting.
    • A new implementation of std::list is enabled by default, with an O(1) size() function;

    GCC dump preprocessor defines

    • 最常用的输出编译器预定义的宏

    gcc -dM -E - < /dev/null

    g++ -dM -E -x c++ - < /dev/null

    • How do I dump preprocessor macros coming from a particular header file?

    echo "#include <sys/socket.h>" | gcc -E -dM -

    • 添加某些options之后的

    gcc -dM -E -msse4 - < /dev/null | grep SSE[34]

    #define SSE3 1 \ #define SSE4_1 1 \ #define SSE4_2 1 \ #define SSSE3 1

    TODO

    • 常用的交叉编译的选项
    • -O3和-O2之间的差别
    • 不同平台之间之间的差别
    • 如何给不同版本的gcc打补丁

    在文章[Algorithm-Optimization]2中介绍了一些有利于优化性能的函数,感兴趣可以结合不同平台的优化指令一起学习使用。

    GCC different platform的配置项

    [Using static and shared libraries across platforms]3

    @ @

    更多C++内容

    • http://deepindeed.cn/2018/11/28/gnu-cpp-Relearn/
    • http://deepindeed.cn/2019/03/18/cpp-program-trick/
    • libstdc++关于dual ABI文档: https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

    其他

    • [gcc与g++的区别]4
    • [ARM?华为?]5
    • himix100的交叉编译链
      ➜  arm-himix100-linux tree -L 2 ./host_bin 
      ./host_bin
      ├── arm-linux-androideabi-addr2line
      ├── arm-linux-androideabi-ar
      ├── arm-linux-androideabi-as
      ├── arm-linux-androideabi-c++
      ├── arm-linux-androideabi-c++filt
      ├── arm-linux-androideabi-cpp
      ├── arm-linux-androideabi-elfedit
      ├── arm-linux-androideabi-g++
      ├── arm-linux-androideabi-gcc
      ├── arm-linux-androideabi-gcc-6.3.0
      ├── arm-linux-androideabi-gcc-ar
      ├── arm-linux-androideabi-gcc-nm
      ├── arm-linux-androideabi-gcc-ranlib
      ├── arm-linux-androideabi-gcov
      ├── arm-linux-androideabi-gcov-tool
      ├── arm-linux-androideabi-gdb
      ├── arm-linux-androideabi-gprof
      ├── arm-linux-androideabi-ld
      ├── arm-linux-androideabi-ld.bfd
      ├── arm-linux-androideabi-nm
      ├── arm-linux-androideabi-objcopy
      ├── arm-linux-androideabi-objdump
      ├── arm-linux-androideabi-ranlib
      ├── arm-linux-androideabi-readelf
      ├── arm-linux-androideabi-run
      ├── arm-linux-androideabi-size
      ├── arm-linux-androideabi-strings
      ├── arm-linux-androideabi-strip
      
    1. https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2017 “Predefined macros” 

    2. http://deepindeed.cn/2017/03/17/Algorithm-Optimization/ 

    3. http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html “Using static and shared libraries across platforms” 

    4. https://www.cnblogs.com/liushui-sky/p/7729838.html “gcc和g++的区别” 

    5. https://news.mydrivers.com/1/628/628308.htm 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    上一篇 混合精度训练

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    混合精度训练
    机遇 research之路其修远兮,我将上下而求索

    混合精度训练

    2019-04-07
    cwlseu

    引言

    CUDA在推出7.5的时候提出了 可以计算16位浮点数据的新特性。定义了两种新的数据类型halfhalf2. NVIDIA GPUs implement the IEEE 754 floating point standard (2008), which defines half-precision numbers as follows (see Figure 1).

    • Sign: 1 bit
    • Exponent width: 5 bits
    • Significand precision: 11 bits (10 explicitly stored) The range of half-precision numbers is approximately $5.96 \times 10^{-8} \ldots 6.55 \times 10^4$. half2 structures store two half values in the space of a single 32-bit word, as the bottom of Figure 1 shows.

    @Figure 1:16-bit half-precision data formats. Top: single `half` value. Bottom: `half2` vector representation.

    CUDA-9中已经开始支持混合精度训练1,TensorRT作为NVIDIA的inference引擎,同样支持混合精度的神经网络inference计算. 之前在网上看到半精度memory copy与计算,发现copy的代价会减少一半,而计算的提升并不是很理想。后来看到了《why cublasHgemm is slower more than cublasSgemm when I use?》这个帖子,终于发现其中的一点规律。

    问题的提出者问,为什么在GTX1070上运行cublasHgemm(半精度计算) 比 cublasSgemm(单精度计算)计算的慢呢?NVIDIA官方的回答说,当前Pascal架构的GPU只有的P100的FP16计算快于FP32。并且给出了编程手册的吞吐量的表2

    Alibaba PAI: Auto-Mixed Precision Training Techniques

    随着NVIDIA release的APEX3,利用Volta架构和混合精度在Pytorch上进行拓展,实现了训练的精度混合。腾讯4和百度5分别发表关于混合精度训练的文章.PAI-TAO是alibaba内部一个关于混合精度训练的一个研究项目。 在整个AI模型的生命周期中的位置如下:

    @PAI-TAO

    从中可以看出,自动混合精度主要是在训练过程中,为了加快计算节点之间的数据交换和层之间的数据交换与计算,采用FP16来替换FP32,这样在计算结果精度几乎不损失的情况下,带了数据交换和计算速度方面的性能提升,从而加快模型训练速度。

    而这项任务的成功,与CUDA9中支持TensorCore的特性是息息相关的。下面对TensorCode进行简单介绍。

    @tensor core

    TensorCore是NVIDIA在Volta architecture下引入的,专门针对计算4x4矩阵的计算模块。 以前NVIDIA的GPU中只有FP32和FP64计算单元,在TensorCore中,特别针对FP16做了相应的补充, 来补充在半精度浮点方面的不足。TensorCore相比较直接进行FP32的计算,速度有了很大的提升。

    为什么采用AMP(Auto mixed-precision)

    Mixed-precision的优势

    • 充分发挥Volta架构引入的TensorCore计算性能 (15->120TFLOPs, 8X)
    • 减少了访存带宽

    No free-lunch

    • 用户模型改写的人力负担
    • 精度调优问题
    • 充分利用TensorCore的技术tricks
      • 数据尺寸对齐问题
      • Layout问题
    • TensorCore将计算密集部分比例降低以后的进一步优化空间挖掘

    如何AMP:Design Philosophy

    • 精度问题
      • 模型以FP32进行保存
      • 不同算子的区别处理
        • 计算密集型算子(MatMul/Conv) 输入为FP16,FP32累加中间结果,输出为FP32,计算基于TensorCore
        • 访存密集型算法(Add/Reduce/…) 输入输出均为FP16,计算为FP16/FP32, 不使用TensorCore,访存量减少
      • Loss scaling策略解决gradient underflow问题
      • 表达精度问题: FP32->FP16
        • 尾数位减少: precision gap in sum (Solution: 模型以FP32进行保存)
        • 指数位减少: gradient underflow

    @scale在训练过程中的作用

    • 速度及易用性问题
      • 通过图优化pass自动完成混合精度所需的图转换工作

    结果

    • No laborious FP32/FP16 casting work anymore
    • Already supporting diversified internal workloads: NLP/CNN/Bert/Graph Embedding
    • 1.3~3x time-to-accuracy speed-up 与PAI-TAO Compiler联合使用可以达到1+1>2的加速收益

    题外思考

    现在我们的训练应该是没有引入混合精度训练的,而且inference框架中没有混合精度的苗头。 我们的inference应该可以先支持起混合精度的,然后后面慢慢地在训练框架中添加相关功能。 然后重构节点之间的数据交换代码,加大对混合精度训练的时候并行度,进一步降低训练模型的成本。 尤其是弱计算能力的芯片上,通过添加混合计算功能,能够在加速的同时,追求更高的精度。 现在很多AI推理芯片如华为himix200中,支持int8和int16的计算,而且同一个模型可以混合int8和int16的精度类型。

    参考文献

    1. https://docs.nvidia.com/deeplearning/sdk/pdf/Training-Mixed-Precision-User-Guide.pdf “Training-Mixed-Precision-User-Guide” 

    2. https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#arithmetic-instructions “throughputs of the arithmetic instructions” 

    3. https://cloud.tencent.com/developer/news/254121 “混合精度训练之APEX” 

    4. http://m.elecfans.com/article/721085.html “一种具有混合精度的高度可扩展的深度学习训练系统” 

    5. https://arxiv.org/pdf/1710.03740.pdf “百度和NVIDIA联合出品:MIXED PRECISION TRAINING” 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    约束优化方法:拉格朗日乘子法与KKT条件
    机遇 research之路其修远兮,我将上下而求索

    约束优化方法:拉格朗日乘子法与KKT条件

    2019-03-23
    cwlseu

    引言

    最速下降法、拟牛顿法等都是求解准则函数(即无约束优化问题)的算法,这就需要有一个前提:怎样得到无约束准则函数?而拉格朗日乘子,将有限制条件的优化问题转化为无限制的优化问题,可见拉格朗日乘子搭建了一个桥梁:将有限制的准则函数,转化为无限制准则函数,进而借助最速下降法、拟牛顿法等求参算法进行求解,在这里汇总一下拉格朗日乘子法是有必要的,全文包括:

    • 含有等式约束的拉格朗日乘子法;
    • 拉格朗日对偶方法;

    不同类型的约束下的优化问题

    无约束优化

    如果不带任何约束的优化问题,对于变量$x \in \mathbb{R}^N$,无约束的优化问题 这个问题直接找到使目标函数的导数为0的点即可,$\nabla_xf(x) = 0$,如果没有解析解的话,可以使用 梯度下降法或者牛顿法等迭代手段来使$x$沿梯度方向逐步逼近极小值点。

    等式约束优化

    当目标函数加上约束条件之后:

    约束条件会将解的范围限定在一个可行域,此时不一定能找到使得 $\nabla_xf(x)$为 0 的点,只需找到在可行域内使得$f(x)$最小的值即可, 常用的方法即为拉格朗日乘子法,该方法首先引入Lagrange Multiplier $\alpha \in \mathbb{R}^m$,构建 Lagrangian 如下:

    求解方法,首先对Lagrangian关于$\alpha$和$x$求导数,令导数为0:

    求得$x, \alpha$的值以后,将$x$带入$f(x)$即为在约束条件$h_i(x)$下的可行解。

    看一个示例,对于二维情况下的目标函数是$f(x,y)$, 在平面中画出$f(x,y)$的等高线,如下图的虚线所示,并只给出一个约束等式$g(x,y)=c$, 如下图的红线所示, 目标函数$f(x,y)$与约束函数$g(x,y)$只有三种情况,相交、相切或者没有交集, 没交集肯定不是解,只有相交或者相切可能是解, 但相交得到的一定不是最优值,因为相交意味着肯定还存在其它的等高线在该条等高线的内部或者外部, 使得新的等高线与目标函数的交点的值更大或者更小,这就意味着只有等高线与目标函数的曲线相切的时候, 才可能得到可行解.

    @来自Wikipedia的图片

    因此给出结论:拉格朗日乘子法取得极值的必要条件是目标函数与约束函数相切,这时两者的法向量是平行的,即 $\nabla _xf(x) – \alpha \nabla_x g(x) = 0$

    不等式约束

    当约束加上不等式之后,情况变得更加复杂,首先来看一个简单的情况,给定如下不等式约束问题

    对应的 Lagrangian 与图形分别如下所示,这时的可行解必须落在约束区域$g(x)$之内,下图给出了目标函数的等高线与约束

    @拉格朗日不等式的情况 由图可见可行解$x$只能在$g(x)\le 0$的区域里取得:

    • 当可行解$x$落在$g(x)<0$的区域内,此时直接极小化$f(x)$即可;
    • 当可行解$x$落在$g(x)=0$即边界上,此时等价于等式约束优化问题。

    当约束区域包含目标函数原有的的可行解时,此时加上约束可行解仍落在约束区域内部,对应$g(x)<0$的情况,这时约束条件不起作用; 当约束区域不包含目标函数原有的可行解时,此时加上约束后可行解落在边界$g(x)=0$上。 下图分别描述了两种情况,右图表示加上约束可行解会落在约束区域的边界上。

    @约束区域内是否包含目标函数的原有的可行解

    以上两种情况就是说,要么可行解落在约束边界上即得$g(x)=0$, 要么可行解落在约束区域内部,此时约束不起作用,令$\lambda=0$消去约束即可, 所以无论哪种情况都会得到: $\lambda g(x)=0$

    还有一个问题是$\lambda$的取值,在等式约束优化中,约束函数与目标函数的梯度 只要满足平行即可,而在不等式约束中则不然,若$\lambda \ne 0$, 这便说明可行解$x$是落在约束区域的边界上的,这时可行解应尽量靠近无约束时的解, 所以在约束边界上,目标函数的负梯度方向应该远离约束区域朝向无约束时的解, 此时正好可得约束函数的梯度方向与目标函数的负梯度方向应相同

    上式需要满足的要求是拉格朗日乘子$\lambda>0$ ,这个问题可以举一个形象的例子,假设你去爬山,目标是山顶,但有一个障碍挡住了通向山顶的路,所以只能沿着障碍爬到尽可能靠近山顶的位置,然后望着山顶叹叹气,这里山顶便是目标函数的可行解,障碍便是约束函数的边界,此时的梯度方向一定是指向山顶的,与障碍的梯度同向,下图描述了这种情况:

    左图中这个$-\nabla_x f(x)$局部最小值指向可行区域($g(x) \le 0$),也就是还有使得更小的点存在。 而右图中的$-\nabla_x f(x)$局部最小值是远离可行区域的。

    KKT条件

    任何不等式约束条件的函数凸优化问题,都可以转化为约束方程小于0且语义不变的形式,以便于使用KKT条件.
    

    可见对于不等式约束,只要满足一定的条件,依然可以使用拉格朗日乘子法解决,这里的条件便是KKT条件。接下来给出形式化的KKT条件 首先给出形式化的不等式约束优化问题:

    列出 Lagrangian 得到无约束优化问题:

    经过之前的分析,便得知加上不等式约束后可行解$x$需要满足的就是以下的 KKT 条件:

    满足 KKT 条件后极小化 Lagrangian 即可得到在不等式约束条件下的可行解。 KKT 条件看起来很多,其实很好理解:

    (1). 拉格朗日取得可行解的必要条件;

    (2). 这就是以上分析的一个比较有意思的约束,称作松弛互补条件;

    (3)-(4). 初始的约束条件;

    (5). 不等式约束的 Lagrange Multiplier 需满足的条件。

    主要的KKT条件便是 (3) 和 (5) ,只要满足这俩个条件便可直接用拉格朗日乘子法, SVM 中的支持向量便是来自于此。

    拉格朗日对偶问题

    https://www.cnblogs.com/ooon/p/5723725.html#4200596 未完,待续

    参考链接

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    下一篇 混合精度训练

    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    神经网络模型训练提升成果总结
    机遇 research之路其修远兮,我将上下而求索

    神经网络模型训练提升成果总结

    2019-03-12
    cwlseu

    引言

    深度学习通过前向计算和反向传播,不断调整参数,来提取最优特征,以达到预测的目的。其中调整的参数就是weight和bias,简写为w和b。根据奥卡姆剃刀法则,模型越简单越好,我们以线性函数这种最简单的表达式来提取特征,也就是

    深度学习训练时几乎所有的工作量都是来求解神经网络中的$w$和$b$。模型训练本质上就是调整$w$和$b$的过程。训练$w$和$b$的过程中,多种因素影响着最终模型的好坏,下面就来说说训练深度神经网络模型中的一些问题。

    问题: foreground-background class imbalance

    OHEM:Training Region-based Object Detectors with Online Hard Example Mining

    • intro: CVPR 2016 Oral. Online hard example mining (OHEM)
    • arxiv: http://arxiv.org/abs/1604.03540
    • paper: http://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Shrivastava_Training_Region-Based_Object_CVPR_2016_paper.pdf
    • github(Official): https://github.com/abhi2610/ohem
    • author page: http://abhinav-shrivastava.info/ paper里直接说的最初的思想就是想把Bootstrapping移植到dl当中来,所以产生了ohem。由于bootstrapping本身是迭代算法,直接应用到dl当中,会使dl的训练变得非常慢。为此,作者借用了其核心思想–让hard example起更大的作用,提出了ohem。 具体的方法就是先让所有样本通过dl计算出loss,以loss大为hard example的标准,从而选出hard example来,然后再组成一组batch,进行训练。 @OHEM设计架构

    Focal Loss for Dense Object Detection

    • 论文地址: https://arxiv.org/abs/1708.02002
    • 主要观点: 提出Single stage detector不好的原因完全在于:
      • 极度不平衡的正负样本比例: anchor近似于sliding window的方式会使正负样本接近1000:1,而且绝大部分负样本都是easy example,这就导致下面一个问题:
      • gradient被easy example dominant的问题:往往这些easy example虽然loss很低,但由于数量众多,对于loss依旧有很大贡献,从而导致收敛到不够好的一个结果。所以作者的解决方案也很直接:直接按照loss decay掉那些easy example的权重,这样使训练更加bias到更有意义的样本中去。 @Focal Loss v.s. Cross Enctroy Loss train performance

    Gradient Harmonized Single-stage Detector

    • 论文地址:https://arxiv.org/pdf/1811.05181.pdf
    • 作者:Buyu Li, Yu Liu and Xiaogang Wang
    • 针对的的痛点:Huge difference in quantity between positive and negative examples as well as between easy and hard examples.
    • Abstract GHM can be easily embedded into both classification loss function like cross-entropy (CE) and regression loss function like smooth-L1 (SL1) loss.two novel loss functions called GHM-C and GHM-R are designed to balancing the gradient flow for anchor classification and bounding box refinement

    A-Fast-RCNN: Hard positive generation via adversary for object detection

    从更好的利用数据的角度出发,OHEM和S-OHEM都是发现困难样本,而A-Fast-RCNN的方法则是通过GAN的方式在特征空间产生具有部分遮挡和形变的困难样本

    其他参考链接

    问题:训练时间长

    训练深度学习模型是反复调整模型参数的过程,得力于GPU等硬件性能的提升,使得复杂的深度学习训练成为了可能。收敛速度过慢,训练时间过长, 一方面使得相同总训练时间内的迭代次数变少,从而影响准确率, 另一方面使得训练次数变少,从而减少了尝试不同超参数的机会。因此,加快收敛速度是一大痛点。

    初始化如何影响训练时间

    模型权重的初始化对于网络的训练很重要, 不好的初始化参数会导致梯度传播问题, 降低训练速度; 而好的初始化参数, 能够加速收敛, 并且更可能找到较优解。如果权重一开始很小,信号到达最后也会很小;如果权重一开始很大,信号到达最后也会很大。不合适的权重初始化会使得隐藏层的输入的方差过大,从而在经$sigmoid$这种非线性层时离中心较远(导数接近0),因此过早地出现梯度消失。如使用均值0,标准差为1的正态分布初始化在隐藏层的方差仍会很大。不初始化为0的原因是若初始化为0,所有的神经元节点开始做的都是同样的计算,最终同层的每个神经元得到相同的参数。

      初始化方法 公式 备注
    1 高斯分布分布 W=0.01 * np.random.randn(D,H) 然而只适用于小型网络,对于深层次网络,权重小导致反向传播计算中梯度也小,梯度”信号”被削弱
    2 截断高斯分布 $X\sim N(\mu, \sigma^2), X \in [-a, a]$ 我们只关心在某一个范围内的样本的分布时,会考虑使用截断的方法。
    3 MSRA $var = \sqrt{4\over n_{in}+n_{out}}$的高斯分布 适用于激活函数ReLU。对于ReLU激活函数,其使一半数据变成0,初始时这一半的梯度为0,而tanh和sigmoid等的输出初始时梯度接近于1。因此使用ReLU的网络的参数方差可能会波动。为此,HeKaiming等放大一倍方差来保持方差的平稳
    4 xavier $[-{\sqrt{6\over m+n}},{\sqrt{6\over m+n}}]$ 算法根据输入和输出神经元的数量自动决定初始化的范围: 定义参数所在的层的输入维度为$n$,输出维度为$m$, xavier权重初始化的作用,初始化方式为使每层方差一致,从而不会发生前向传播爆炸和反向传播梯度消失等问题, 使得信号在经过多层神经元后保持在合理的范围(不至于太小或太大),适用于激活函数是$sigmoid$和$tanh$

    上述初始化方式的1,2仅考虑每层输入的方差, 而后两种方式考虑输入与输出的方差, 保持每层的输入与输出方差相等. 4方法中针对ReLU激活函数, 放大了一倍的方差.

    学习率

    模型训练就是不断尝试和调整不同的$w$和$b$,那么每次调整的幅度是多少,就是学习率。$w$和$b$是在一定范围内调整的,那么增大学习率不就减少了迭代次数,也就加快了训练速度了吗? 学习率太小,会增加迭代次数,加大训练时间。但学习率太大,容易越过局部最优点,降低准确率。

    那有没有两全的解决方法? 我们可以一开始学习率大一些,从而加速收敛。训练后期学习率小一点,从而稳定的落入局部最优解。 使用AdamAdagrad等自适应优化算法,就可以实现学习率的自适应调整,从而保证准确率的同时加快收敛速度。

    网络节点输入值正则化

    神经网络训练时,每一层的输入分布都在变化。不论输入值大还是小,我们的学习率都是相同的,这显然是很浪费效率的。而且当输入值很小时,为了保证对它的精细调整,学习率不能设置太大。那有没有办法让输入值标准化得落到某一个范围内,比如$[0, 1]$之间呢,这样我们就再也不必为太小的输入值而发愁了。

    办法当然是有的,那就是正则化!由于我们学习的是输入的特征分布,而不是它的绝对值,故可以对每一个mini-batch数据内部进行标准化,使他们规范化到$[0, 1]$内。这就是Batch Normalization,简称BN。由大名鼎鼎的inception V2提出。它在每个卷积层后,使用一个BN层,从而使得学习率可以设定为一个较大的值。使用了BN的inceptionV2,只需要以前的1/14的迭代次数就可以达到之前的准确率,大大加快了收敛速度。

    优化结构

    训练速度慢,归根结底还是网络结构的参数量过多导致的。减少参数量,可以大大加快收敛速度。采用先进的网络结构,可以用更少的参数量达到更高的精度。如inceptionV1参数量仅仅为500万,是AlexNet的1/12, 但top-5准确率却提高了一倍多。如何使用较少的参数量达到更高的精度,一直是神经网络结构研究中的难点。目前大致有如下几种方式

    • 使用小卷积核来代替大卷积核。VGGNet全部使用3x3的小卷积核,来代替AlexNet中11x11和5x5等大卷积核。小卷积核虽然参数量较少,但也会带来特征面积捕获过小的问题。inception net认为越往后的卷积层,应该捕获更多更高阶的抽象特征。因此它在靠后的卷积层中使用的5x5等大面积的卷积核的比率较高,而在前面几层卷积中,更多使用的是1x1和3x3的卷积核。
    • 使用两个串联小卷积核来代替一个大卷积核。inceptionV2中创造性的提出了两个3x3的卷积核代替一个5x5的卷积核。在效果相同的情况下,参数量仅为原先的3x3x2 / 5x5 = 18/25
    • 1x1卷积核的使用。1x1的卷积核可以说是性价比最高的卷积了,没有之一。它在参数量为1的情况下,同样能够提供线性变换,relu激活,输入输出channel变换等功能。VGGNet创造性的提出了1x1的卷积核
    • 非对称卷积核的使用。inceptionV3中将一个7x7的卷积拆分成了一个1x7和一个7x1, 卷积效果相同的情况下,大大减少了参数量,同时还提高了卷积的多样性。
    • depthwise卷积的使用。mobileNet中将一个3x3的卷积拆分成了串联的一个3x3 depthwise卷积和一个1x1正常卷积。对于输入channel为M,输出为N的卷积,正常情况下,每个输出channel均需要M个卷积核对输入的每个channel进行卷积,并叠加。也就是需要MxN个卷积核。而在depthwise卷积中,输出channel和输入相同,每个输入channel仅需要一个卷积核。而将channel变换的工作交给了1x1的卷积。这个方法在参数量减少到之前1/9的情况下,精度仍然能达到80%。
    • 全局平均池化代替全连接层。这个才是大杀器!AlexNet和VGGNet中,全连接层几乎占据了90%的参数量。inceptionV1创造性的使用全局平均池化来代替最后的全连接层,使得其在网络结构更深的情况下(22层,AlexNet仅8层),参数量只有500万,仅为AlexNet的1/12
    • 网络结构的推陈出新,先进设计思想的不断提出,使得减少参数量的同时提高准确度变为了现实。

    梯度弥散和梯度爆炸

    https://yq.aliyun.com/articles/598429 深度神经网络的反向传播过程中,随着越向回传播,权重的梯度变得越来越小,越靠前的层训练的越慢,导致结果收敛的很慢,损失函数的优化很慢,有的甚至会终止网络的训练。

    训练过程中的过拟合

    什么是过拟合

    过拟合就是训练模型的过程中,模型过度拟合训练数据,而不能很好的泛化到测试数据集上。出现over-fitting的原因是多方面的:

    • 训练数据过少,数据量与数据噪声是成反比的,少量数据导致噪声很大
    • 特征数目过多导致模型过于复杂

    如何避免过拟合

    • 控制特征的数目,可以通过特征组合,或者模型选择算法
    • Regularization,保持所有特征,但是减小每个特征的参数向量$\theta$的大小,使其对分类y所做的贡献很小

    Lasso & 岭回归

    http://www.cnblogs.com/ooon/p/4964441.html

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Object Detection Metrics
    机遇 research之路其修远兮,我将上下而求索

    Object Detection Metrics

    2019-03-11
    cwlseu

    物体检测效果评估相关的定义 1

    Intersection Over Union (IOU)

    Intersection Over Union (IOU) is measure based on Jaccard Index that evaluates the overlap between two bounding boxes. It requires a ground truth bounding box $B_{gt}$and a predicted bounding box $B_p$ By applying the IOU we can tell if a detection is valid (True Positive) or not (False Positive).
    IOU is given by the overlapping area between the predicted bounding box and the ground truth bounding box divided by the area of union between them:

    The image below illustrates the IOU between a ground truth bounding box (in green) and a detected bounding box (in red).

    True Positive, False Positive, False Negative and True Negative2

    Some basic concepts used by the metrics:

    • True Positive (TP): A correct detection. Detection with IOU ≥ _threshold_
    • False Positive (FP): A wrong detection. Detection with IOU < _threshold_
    • False Negative (FN): A ground truth not detected
    • True Negative (TN): Does not apply. It would represent a corrected misdetection. In the object detection task there are many possible bounding boxes that should not be detected within an image. Thus, TN would be all possible bounding boxes that were corrrectly not detected (so many possible boxes within an image). That’s why it is not used by the metrics.

    _threshold_: depending on the metric, it is usually set to 50%, 75% or 95%.

    Precision

    Precision is the ability of a model to identify only the relevant objects. It is the percentage of correct positive predictions and is given by:

    Recall

    Recall is the ability of a model to find all the relevant cases (all ground truth bounding boxes). It is the percentage of true positive detected among all relevant ground truths and is given by: @混淆矩阵

    评估方法Metrics345

    • Receiver operating characteristics (ROC) curve
    • Precision x Recall curve
    • Average Precision
      • 11-point interpolation
      • Interpolating all points

    物体检测中的损失函数

    【机器学习者都应该知道的五种损失函数!】 我们假设有$n$个样本, 其中$x_i$的gt值为$y_i$, 算法$f(x)$的预测结果为$y_i^p$

    均方误差 —— L2损失

    均方误差(MSE)是回归损失函数中最常用的误差,它是预测值与目标值之间差值的平方和,公式如下

    平均绝对误差——L1损失函数

    平均绝对误差(MAE)是另一种常用的回归损失函数,它是目标值与预测值之差绝对值的和,表示了预测值的平均误差幅度,而不需要考虑误差的方向(注:平均偏差误差MBE则是考虑的方向的误差,是残差的和),范围是0到$\infin$

    L1 v.s L2损失函数6

    通常,利用均方差更容易求解,但平方绝对误差则对于异常值更稳健。

    下面让我们对这两种损失函数进行具体的分析。无论哪一种机器学习模型,目标都是找到能使目标函数最小的点。在最小值处每一种损失函数都会得到最小值。

    可以运行相关代码进行分析7

    由于均方误差(MSE)在误差较大点时的损失远大于平均绝对误差(MAE),它会给异常值赋予更大的权重,模型会全力减小异常值造成的误差,从而使得模型的整体表现下降。所以当训练数据中含有较多的异常值时,平均绝对误差(MAE)更为有效。当我们对所有观测值进行处理时,如果利用MSE进行优化则我们会得到所有观测的均值,而使用MAE则能得到所有观测的中值。与均值相比,中值对于异常值的鲁棒性更好,这就意味着平均绝对误差对于异常值有着比均方误差更好的鲁棒性。

    但MAE也存在一个问题,特别是对于神经网络来说,它的梯度在极值点处会有很大的跃变,及时很小的损失值也会长生很大的误差,这很不利于学习过程。为了解决这个问题,需要在解决极值点的过程中动态减小学习率。MSE在极值点却有着良好的特性,及时在固定学习率下也能收敛。MSE的梯度随着损失函数的减小而减小,这一特性使得它在最后的训练过程中能得到更精确的结果。

    在实际训练过程中,如果异常值对于实际业务十分重要需要进行检测,MSE是更好的选择,而如果在异常值极有可能是坏点的情况下MAE则会带来更好的结果。

    总结:L1损失对于异常值更鲁棒,但它的导数不连续使得寻找最优解的过程低效;L2损失对于异常值敏感,但在优化过程中更为稳定和准确。更详细的L1和L2不同比较可以参考这篇文章。

    但现实中还存在两种损失都很难处理的问题。例如某个任务中90%的数据都符合目标值——150,而其余的10%数据取值则在0-30之间。那么利用MAE优化的模型将会得到150的预测值而忽略的剩下的10%(倾向于中值);而对于MSE来说由于异常值会带来很大的损失,将使得模型倾向于在0-30的方向取值。这两种结果在实际的业务场景中都是我们不希望看到的。

    Huber损失——平滑平均绝对误差

    Huber损失相比于平方损失来说对于异常值不敏感,但它同样保持了可微的特性。它基于绝对误差但在误差很小的时候变成了平方误差。我们可以使用超参数$\delta$来调节这一误差的阈值。当$\delta$趋向于0时它就退化成了MAE,而当$\delta$趋向于无穷时则退化为了MSE,其表达式如下,是一个连续可微的分段函数:

    @HuberLoss with delta change

    对于Huber损失来说,$\delta$的选择十分重要,它决定了模型处理异常值的行为。当残差大于$\delta$时使用L1损失,很小时则使用更为合适的L2损失来进行优化。

    Huber损失函数克服了MAE和MSE的缺点,不仅可以保持损失函数具有连续的导数,同时可以利用MSE梯度随误差减小的特性来得到更精确的最小值,也对异常值具有更好的鲁棒性。

    而Huber损失函数的良好表现得益于精心训练的超参数$\delta$.

    参考文献

    1. https://github.com/cwlseu/Object-Detection-Metrics “评估标准” 

    2. https://acutecaretesting.org/en/articles/precision-recall-curves-what-are-they-and-how-are-they-used “Precision-recall curves – what are they and how are they used” 

    3. https://www.jianshu.com/p/c61ae11cc5f6 “机器学习之分类性能度量指标 : ROC曲线、AUC值、正确率、召回率” 

    4. https://machinelearningmastery.com/roc-curves-and-precision-recall-curves-for-classification-in-python/ “How and When to Use ROC Curves and Precision-Recall Curves for Classification in Python” 

    5. https://www.zhihu.com/question/30643044 “精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么?” 

    6. https://yq.aliyun.com/articles/602858?utm_content=m_1000002415 “机器学习者都应该知道的五种损失函数!” 

    7. http://rishy.github.io/ml/2015/07/28/l1-vs-l2-loss/?spm=a2c4e.10696291.0.0.170b19a44a9JnP 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    上一篇 高通芯片笔记

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    高通芯片笔记
    机遇 research之路其修远兮,我将上下而求索

    高通芯片笔记

    2019-03-01
    cwlseu

    引言

    从2011年甚至更早开始,智能手机,智能终端,车载芯片等等智能终端中,高通芯片无处不在。相比较Intel,高通抓住了移动处理器中续航的问题,不断推出低功耗移动处理器,从而抓住移动处理器的市场。日常工作中接触到很多冠以高通之名的产品,记录以习之。

    性能排行榜

    收集了一下2018年高通骁龙CPU处理器排行榜各种手机品牌的处理器性能对比,从中可以看出,骁龙系列 处理器也是分为高中低端处理器的,其中去年最常见的845系列,占据较大的市场份额。与之争锋麒麟 980虽然在HUWEI Meta 20 Pro的跑分汇总获得更高名次,性能前10中高通独占8席。

    骁龙

    为什么要选择骁龙处理器? 骁龙移动处理器是Qualcomm开发的完整片上系统解决方案系列产品,该系列适应用户需求而提供卓越的用户体验和更长的电池寿命。利用骁龙处理器先进的处理能力和并发性能,您可以同时运行多个高级应用,而对电池的消耗却可以降到最少。

    骁龙处理器经过发展,早已不再仅仅支持先进的手机,还可在各种智能产品和互连设备上看到它的身影,包括可穿戴设备、智能家电、智能电话亭和数字标识系统等。我们的一系列软硬件解决方案专门提供您所需要的,以帮助您最大限度地利用采用骁龙处理器的设备。我们的SDK、Profiler分析器和调试器能帮助您分析和提升应用性能、打造创新特性和创造新的互连体验。我们甚至能帮助您开始按照您自身的设计打造设备(从原型设计到生产的全过程)。如果您要打造下一代设备,采用骁龙处理器的开发设备,您便已经可以将未来握在手中了。

    高通公司官网开发文档

    CPU

    有了高品质的处理内核,骁龙处理器中经优化的CPU是专为让您的应用运行得更快、更流畅而设计。我们所有CPU的目标是将世界级的移动体验带进生活,同时智能地控制电池寿命。但是如果没有能完全发挥其特性的软件,即使是最高性能的CPU也不能开发出自身的全部潜力。采用骁龙LLVM编译器编译的代码在骁龙处理器上会执行的更好,因为它具有独特的优化处理和漏洞修复。

    GPU

    图形性能对于现代移动体验是一个重要部分,这就是为什么我们的Qualcomm骁龙处理器要内置开拓性的Adreno™图形处理器的原因。Adreno是目前最先进的移动图形处理背后的发电站,它能加速游戏、用户界面和网络浏览器中复杂几何体的渲染。快来下载Adreno SDK,优化您针对Adreno GPU的应用,该SDK含打造沉浸式手机游戏体验所需的工具、库、示例、文档和辅导资料。您还可利用Adreno Profiler分析器来分析和优化您应用的图形性能。该分析器具有的特性包括:基于硬件的性能监视器、渲染调用指标、Shader原型设计等。

    DSP

    在最适合的处理引擎上运行适当的任务能为开发者带来性能优势。这就是为什么开发Hexagon DSP的原因,该产品专为优化调制解调器和多媒体应用而设计,具有的特性包括硬件辅助多线程。Hexagon SDK使您能最大化发挥DSP的性能,提供一个用于生成动态Hexagon DSP代码模块的环境,并且使您能访问Hexagon DSP上的内置计算资源。该SDK是专为帮助确保处理效率而设计,这意味着它具备更高的流动性、更低的延迟和卓越的应用性能。

    CSDN中高通专栏

    【中科创达-王庆民】关于Hexagon DSP功能介绍

    Qualcomm的晓龙芯片从创立之几乎一直内置Hexagon DSP芯片,它是移动异构计算必需的处理引擎。Hexagon架构设计的核心在于如何在低功耗的情况下能够高性能的处理各种各样的应用,它具有的特性包括多线程,特权级,VLIW,SIMD以及专门适应于信号处理的指令。该CPU可以在单个时间周期中依序快速的将四个指令(已打包好)处理为执行单元。硬件多线程则由 TMT(TemporalMultiThreading,时间多线程)来实现,在这种模式下,频率600MHz的物理核心可以被抽象成三个频率200MHz的核心。许多体验如声音和图像增强功能以及高级摄像头和传感器功能都包括信号处理任务,而DSP尤其擅长在低功耗下处理这些任务。起初,Hexagon DSP作为处理引擎,主要用于语音和简单的音频播放。现在,Hexagon DSP的作用已经扩展至多种用途,如图像增强、计算机视觉、扩增实境、视频处理和传感器处理。随着智能手机使用需求的不断加大,现在包括摄像头和传感器功能都包括信号处理任务都需要借助DSP来完成,相比强大的CPU,DSP尤其擅长在低功耗下处理这些任务。

    @Qualcomm最新发布的Hexagon 680 DSP版本新特性

    高清图像处理,低功耗——Qualcomm® Hexagon™ Vector eXtensions (HVX)

    摘要:过去几年,开发人员一直在利用 Hexagon SDK,量身定制 DSP,处理音频、图像与计算 。在 HotChips 半导体会议上,我们揭开了即将上市的 Snapdragon 820 处理器中全新 Hexagon DSP 的部分面纱。这款 Hexagon 680 DSP ,集成宽幅向量处理 Hexagon 向量扩展(HVX)核心,充分利用新的DSP 应用实例。 英文原版High-Res Image Processing, Low Power Consumption – Qualcomm® Hexagon™ Vector eXtensions (VX) 关于HVX技术,可以参考如下介绍 https://www.hotchips.org/wp-content/uploads/hc_archives/hc27/HC27.24-Monday-Epub/HC27.24.20-Multimedia-Epub/HC27.24.211-Hexagon680-Codrescu-Qualcomm.pdf

    高通向量拓展技术的概括 与NEON编程模型相类似,在计算机视觉应用领域 Alt text

    指令和CPU的NEON指令相比,指令简单,更低功耗 Alt text

    性能方面,CPU使用NEON优化虽然能够提升1~3的速度,但是单pixel功耗方面大约是DSP的4~18倍。 @Benchmark

    Snapdragon Neural Processing Engine (SNPE)

    Capabilities

    The Snapdragon Neural Processing Engine (SNPE) is a Qualcomm Snapdragon software accelerated runtime for the execution of deep neural networks. With SNPE, users can:

    • Execute an arbitrarily deep neural network
    • Execute the network on the SnapdragonTM CPU, the AdrenoTM GPU or the HexagonTM DSP.
    • Debug the network execution on x86 Ubuntu Linux
    • Convert Caffe, Caffe2, ONNXTM and TensorFlowTM models to a SNPE Deep Learning Container (DLC) file
    • Quantize DLC files to 8 bit fixed point for running on the Hexagon DSP
    • Debug and analyze the performance of the network with SNPE tools
    • Integrate a network into applications and other code via C++ or Java

    Workflow

    Model training is performed on a popular deep learning framework (Caffe, Caffe2, ONNX and TensorFlow models are supported by SNPE.) After training is complete the trained model is converted into a DLC file that can be loaded into the SNPE runtime. This DLC file can then be used to perform forward inference passes using one of the Snapdragon accelerated compute cores. The basic SNPE workflow consists of only a few steps:

    @SNPE运行模型的工作流

    • Convert the network model to a DLC file that can be loaded by SNPE.
    • Optionally quantize the DLC file for running on the Hexagon DSP.
    • Prepare input data for the model.
    • Load and execute the model using SNPE runtime.

    测试模型

    1. 添加环境变量
      #include <cstdlib>
      #if defined(__linux__) || defined(__ANDROID__)
      bool SetAdspLibraryPath(std::string nativeLibPath) {
       std::stringstream path;
       path << nativeLibPath << ";/system/lib/rfsa/adsp;/system/vendor/lib/rfsa/adsp;/dsp";
       return setenv("ADSP_LIBRARY_PATH", path.str().c_str(), 1 /*override*/) == 0;
      }
      #else
      #error "the platform not support dsp"
      #endif
      

    ./snpe-net-run --container ./modelname.dlc --input_list list.one --use_dsp

    参考链接

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    上一篇 CVPR2019的文章

    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    CVPR2019的文章
    机遇 research之路其修远兮,我将上下而求索

    CVPR2019的文章

    2019-02-27
    cwlseu

    引言

    今年CVRP投稿总量在上新高,录取总量突破1000大关。

    Segmentation

    1. Attention-guided Unified Network for Panoptic Segmentation
      • 作者:Yanwei Li, Xinze Chen, Zheng Zhu, Lingxi Xie, Guan Huang, Dalong Du, Xingang Wang
      • 论文链接:https://arxiv.org/abs/1812.03904
      • 摘要: This paper studies panoptic segmentation, a recently proposed task which segments foreground (FG) objects at the instance level as well as background (BG) contents at the semantic level. Existing methods mostly dealt with these two problems separately, but in this paper, we reveal the underlying relationship between them, in particular, FG objects provide complementary cues to assist BG understanding. Our approach, named the Attention-guided Unified Network (AUNet), is an unified framework with two branches for FG and BG segmentation simultaneously. Two sources of attentions are added to the BG branch, namely, RPN and FG segmentation mask to provide object-level and pixel-level attentions, respectively. Our approach is generalized to different backbones with consistent accuracy gain in both FG and BG segmentation, and also sets new stateof-the-arts in the MS-COCO (46.5% PQ) benchmarks.
      • 任务Panoptic Segment @Panoptic Segment任务介绍
    • 框架图 @基于Attention机制的Panoptic Segment算法框架

    • 小结

      • 任务新
      • 特征是FPN特征,使用两种Proposal Attention Module
      • 在Mask-RCNN中的基础上,对ROIAlign进行改进,丰富了不同抽象层次特征之间的交流
      • 后面是不是可以使用这个作文本生成?
    1. FEELVOS: Fast End-to-End Embedding Learning for Video Object Segmentation
      • 作者:Paul Voigtlaender, Yuning Chai, Florian Schroff, Hartwig Adam, Bastian Leibe, Liang-Chieh Chen
      • 论文链接:https://arxiv.org/abs/1902.09513
    2. Associatively Segmenting Instances and Semantics in Point Clouds(点云分割,开源)
      • 作者:Xinlong Wang, Shu Liu, Xiaoyong Shen, Chunhua Shen, Jiaya Jia
      • 论文链接:https://arxiv.org/abs/1902.09852
      • 代码链接:https://github.com/WXinlong/ASIS

    Pose Estimation

    1. Deep High-Resolution Representation Learning for Human Pose Estimation(目前SOTA,已经开源)
      • 作者:Ke Sun, Bin Xiao, Dong Liu, Jingdong Wang
      • 论文链接:https://128.84.21.199/abs/1902.09212
      • 代码链接:https://github.com/leoxiaobin/deep-high-resolution-net.pytorch
      • Project: https://jingdongwang2017.github.io/Projects/HRNet/index.html
      • 任务:Human Pose Estimation
      • 摘要 In this paper, we are interested in the human pose estimation problem with a focus on learning reliable highresolution representations. Most existing methods recover high-resolution representations from low-resolution representations produced by a high-to-low resolution network. Instead, our proposed network maintains high-resolution representations through the whole process. We start from a high-resolution subnetwork as the first stage, gradually add high-to-low resolution subnetworks one by one to form more stages, and connect the mutliresolution subnetworks in parallel. We conduct repeated multi-scale fusions such that each of the high-to-low resolution representations receives information from other parallel representations over and over, leading to rich highresolution representations. As a result, the predicted keypoint heatmap is potentially more accurate and spatially more precise. We empirically demonstrate the effectiveness of our network through the superior pose estimation results over two benchmark datasets: the COCO keypoint detection dataset and the MPII Human Pose dataset. In addition, we show the superiority of our network in pose tracking on the PoseTrack dataset.
      • 主要设计 @ @
    2. DenseFusion: 6D Object Pose Estimation by Iterative Dense Fusion
      • 作者:Chen Wang, Danfei Xu, Yuke Zhu, Roberto Martín-Martín, Cewu Lu, Li Fei-Fei, Silvio Savarese
      • 论文链接:https://arxiv.org/abs/1901.04780
    3. Improving the Performance of Unimodal Dynamic Hand-Gesture Recognition with Multimodal Training
      • 作者:Mahdi Abavisani, Hamid Reza Vaezi Joze, Vishal M. Patel — Microsoft
      • 链接:https://arxiv.org/abs/1812.06145
      • 摘要 We present an efficient approach for leveraging the knowledge from multiple modalities in training unimodal 3D convolutional neural networks (3D-CNNs) for the task of dynamic hand gesture recognition. Instead of explicitly combining multimodal information, which is commonplace in many state-of-the-art methods, we propose a different framework in which we embed the knowledge of multiple modalities in individual networks so that each unimodal network can achieve an improved performance. In particular, we dedicate separate networks per available modality and enforce them to collaborate and learn to develop networks with common semantics and better representations. We introduce a “spatiotemporal semantic alignment” loss (SSA) to align the content of the features from different networks. In addition, we regularize this loss with our proposed “focal regularization parameter” to avoid negative knowledge transfer. Experimental results show that our framework improves the test time recognition accuracy of unimodal networks, and provides the state-of-the-art performance on various dynamic hand gesture recognition datasets
      • spatiotemporal semantic alignment (SSA) loss
      • dataset
    dataset名称 size 描述
    VIVA hand gestures 885 visible RGB and depth video sequences (RGB-D) of 19 hand gesture classes, collected from 8 subjects multimodal dynamic hand gesture dataset specifically designed with difficult settings of cluttered background, volatile illumination, and frequent occlusion for studying natural human activities in real-world driving settings. This dataset was captured using a Microsoft Kinect device
    EgoGesture This dataset contains 24,161 hand gesture clips of 83 classes of gestures, performed by 50 subjects. Videos in this dataset include both static and dynamic gestures captured with an Intel RealSense SR300 device in RGB-D modalities across multiple indoor and outdoor scenes. a large multimodal hand gesture dataset collected for the task of egocentric gesture recognition.
    NVGestures It contains 1532 dynamic hand gestures recorded from 20 subjects inside a car simulator with artificial lighting conditions. This dataset includes 25 classes of hand gestures. The gestures were recorded with SoftKinetic DS325 device as the RGB-D sensor and DUO-3D for the infrared streams. been captured with multiple sensors and from multiple viewpoints for studying human-computer interfaces
    1. 3D-SIS: 3D Semantic Instance Segmentation of RGB-D Scans
      • 作者:Ji Hou Angela Dai Matthias Nießner
      • 论文链接:https://niessnerlab.org/projects/hou20183dsis.html
      • YouTube视频:https://youtu.be/IH9rNLD1-JE
    2. RepNet: Weakly Supervised Training of an Adversarial Reprojection Network for 3D Human Pose Estimation
      • 作者:Bastian Wandt, Bodo Rosenhahn
      • 论文链接:https://arxiv.org/abs/1902.09868

    Visual Question Answering & cross-multi-model data

    1. MUREL: Multimodal Relational Reasoning for Visual Question Answering
      • 作者:Remi Cadene, Hedi Ben-younes, Matthieu Cord, Nicolas Thome
      • 论文链接:https://arxiv.org/abs/1902.09487
    2. An Attention Enhanced Graph Convolutional LSTM Network for Skeleton-Based Action Recognition
      • 作者:Chenyang Si, Wentao Chen, Wei Wang, Liang Wang, Tieniu Tan
      • 论文链接:https://arxiv.org/abs/1902.09130
    3. End-to-End Multi-Task Learning with Attention
      • 作者:Shikun Liu, Edward Johns, Andrew J. Davison
      • 论文链接:https://arxiv.org/abs/1803.10704
    4. 24.Image-Question-Answer Synergistic Network for Visual Dialog
      • 作者:Dalu Guo, Chang Xu, Dacheng Tao
      • 论文链接:https://arxiv.org/abs/1902.09774
    5. Reinforced Cross-Modal Matching and Self-Supervised Imitation Learning for Vision-Language Navigation
      • 作者:Xin Wang, Qiuyuan Huang, Asli Celikyilmaz, Jianfeng Gao, Dinghan Shen, Yuan-Fang Wang, William Yang Wang, Lei Zhang
      • 论文链接:https://arxiv.org/abs/1811.10092
    6. MUREL: Multimodal Relational Reasoning for Visual Question Answering
      • 作者:Remi Cadene, Hedi Ben-younes, Matthieu Cord, Nicolas Thome
      • 论文链接:https://arxiv.org/abs/1902.09487
      • github链接:https://github.com/Cadene/murel.bootstrap.pytorch
    7. MAN: Moment Alignment Network for Natural Language Moment Retrieval via Iterative Graph Adjustment
      • 作者:Da Zhang, Xiyang Dai, Xin Wang, Yuan-Fang Wang, Larry S. Davis
      • 论文链接:https://arxiv.org/pdf/1812.00087.pdf

    3D

    1. SpherePHD: Applying CNNs on a Spherical PolyHeDron Representation of 360 degree Images
      • 作者:Yeon Kun Lee, Jaeseok Jeong, Jong Seob Yun, Cho Won June, Kuk-Jin Yoon
      • 论文链接:https://arxiv.org/abs/1811.08196
    2. The Perfect Match: 3D Point Cloud Matching with Smoothed Densities
      • 作者:Zan Gojcic, Caifa Zhou, Jan D. Wegner, Andreas Wieser
      • 论文链接:https://arxiv.org/abs/1811.06879
    3. Disentangled Representation Learning for 3D Face Shape
      • 作者:Baris Gecer, Stylianos Ploumpis, Irene Kotsia, Stefanos Zafeiriou
      • 论文链接:https://arxiv.org/abs/1902.05978
    4. Stereo R-CNN based 3D Object Detection for Autonomous Driving(3D检测)
      • 作者:Peiliang Li, Xiaozhi Chen, Shaojie Shen
      • 论文链接:https://arxiv.org/abs/1902.09738
    5. GANFIT: Generative Adversarial Network Fitting for High Fidelity 3D Face Reconstruction
      • 作者:Baris Gecer, Stylianos Ploumpis, Irene Kotsia, Stefanos Zafeiriou
      • 论文链接:https://arxiv.org/abs/1902.05978
      • github链接:https://github.com/barisgecer/ganfit
    6. Single-Image Piece-wise Planar 3D Reconstruction via Associative Embedding(开源)
      • 作者:Zehao Yu, Jia Zheng, Dongze Lian, Zihan Zhou, Shenghua Gao
      • 论文链接:https://arxiv.org/abs/1902.09777
      • 代码链接:https://github.com/svip-lab/PlanarReconstruction
      • 来源:https://mp.weixin.qq.com/s/mamDhLUw6O9v8gldyIOPUA
    7. Disentangled Representation Learning for 3D Face Shape
      • 作者:Zi-Hang Jiang, Qianyi Wu, Keyu Chen, Juyong Zhang
      • 论文链接:https://arxiv.org/abs/1902.09887

    Generation

    1. Event-based High Dynamic Range Image and Very High Frame Rate Video Generation using Conditional Generative Adversarial Networks
      • 作者:S. Mohammad Mostafavi I., Lin Wang, Yo-Sung Ho, Kuk-Jin Yoon
      • 论文链接:https://arxiv.org/abs/1811.08230
    2. Mixture Density Generative Adversarial Networks
      • 作者:Hamid Eghbal-zadeh, Werner Zellinger, Gerhard Widmer
      • 论文链接:https://arxiv.org/abs/1811.00152

    AutoDriving

    1. Pseudo-LiDAR from Visual Depth Estimation: Bridging the Gap in 3D Object Detection for Autonomous Driving
      • 作者:Yan Wang, Wei-Lun Chao, Divyansh Garg, Bharath Hariharan, Mark Campbell, Kilian Q. Weinberger
      • 论文链接:https://arxiv.org/abs/1812.07179

    Detection

    1. ROI-10D: Monocular Lifting of 2D Detection to 6D Pose and Metric Shape
      • 作者:Fabian Manhardt, Wadim Kehl, Adrien Gaidon
      • 论文链接:https://arxiv.org/abs/1812.02781

    其他

    1. Neural Task Graphs: Generalizing to Unseen Tasks from a Single Video Demonstration
      • 作者:De-An Huang, Suraj Nair, Danfei Xu, Yuke Zhu, Animesh Garg, Li Fei-Fei, Silvio Savarese, Juan Carlos Niebles
      • 论文链接:https://arxiv.org/abs/1807.03480
    2. A Neurobiological Evaluation Metric for Neural Network Model Search
      • 作者:Nathaniel Blanchard, Jeffery Kinnison, Brandon RichardWebster, Pouya Bashivan, Walter J. Scheirer
      • 论文链接:https://arxiv.org/pdf/1805.10726.pdf
      • 一种Evaluation Metric
    3. Variational Bayesian Dropout
      • 作者:Yuhang Liu, Wenyong Dong, Lei Zhang, Dong Gong, Qinfeng Shi
      • 论文链接:https://arxiv.org/abs/1811.07533
    4. Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression(检测)
      • 作者:Hamid Rezatofighi, Nathan Tsoi, JunYoung Gwak, Amir Sadeghian, Ian Reid, Silvio Savarese
      • 论文链接:https://arxiv.org/abs/1902.09630
      • 来源:https://mp.weixin.qq.com/s/mamDhLUw6O9v8gldyIOPUA
    5. Learning a Deep ConvNet for Multi-label Classification with Partial Labels(分类)
      • 作者:Thibaut Durand, Nazanin Mehrasa, Greg Mori
      • 论文链接:https://arxiv.org/abs/1902.09720
      • 来源:https://mp.weixin.qq.com/s/mamDhLUw6O9v8gldyIOPUA
    6. LiFF: Light Field Features in Scale and Depth
      • 作者:Donald G. Dansereau, Bernd Girod, Gordon Wetzstein
      • 论文链接:https://arxiv.org/abs/1901.03916
    7. Classification-Reconstruction Learning for Open-Set Recognition
      • 作者:Ryota Yoshihashi, Wen Shao, Rei Kawakami, Shaodi You, Makoto Iida, Takeshi Naemura
      • 论文链接:https://arxiv.org/abs/1812.04246
    8. Weakly Supervised Deep Image Hashing through Tag Embeddings
      • 作者:Vijetha Gattupalli, Yaoxin Zhuo, Baoxin Li
      • 论文链接:https://arxiv.org/abs/1806.05804
      • 摘要 Many approaches to semantic image hashing have been formulated as supervised learning problems that utilize images and label information to learn the binary hash codes. However, large-scale labelled image data is expensive to obtain, thus imposing a restriction on the usage of such algorithms. On the other hand, unlabelled image data is abundant due to the existence of many Web image repositories. Such Web images may often come with images tags that contains useful information, although raw tags in general do not readily lead to semantic labels. Motivated by this scenario, we formulate the problem of semantic image hashing as a weakly-supervised learning problem. We utilize the information contained in the user-generated tags associated with the images to learn the hash codes. More specifically, we extract the word2vec semantic embeddings of the tags and use the information contained in them for constraining the learning. Accordingly, we name our model Weakly Supervised Deep Hashing using Tag Embeddings (WDHT). WDHT is tested for the task of semantic image retrieval and is compared against several state-of-art models. Results show that our approach sets a new state-of-art in the area of weekly supervised image hashing.
    9. InverseRenderNet: Learning single image inverse rendering
      • 作者:Ye Yu, William A. P. Smith
      • 论文链接:https://arxiv.org/abs/1811.12328
    10. Iterative Residual CNNs for Burst Photography Applications
      • 作者:Filippos Kokkinos   Stamatis Lefkimmiatis
      • 论文链接:https://arxiv.org/abs/1811.12197
    11. Taking A Closer Look at Domain Shift: Category-level Adversaries for Semantics Consistent Domain Adaptation
      • 作者:Yawei Luo, Liang Zheng, Tao Guan, Junqing Yu, Yi Yang
      • 论文链接:https://arxiv.org/abs/1809.09478

    原文链接:https://github.com/extreme-assistant/cvpr2019.git

    cvpr2019 accepted papers list:
    http://cvpr2019.thecvf.com/files/cvpr_2019_final_accept_list.txt

    链接:https://pan.baidu.com/s/1s4FuLscWcslN5rQQvP92JA 提取码:osvy

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    下一篇 高通芯片笔记

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    一起来看数据增强
    机遇 research之路其修远兮,我将上下而求索

    一起来看数据增强

    2019-02-25
    cwlseu

    引言

    从AlexNet夺取ImageNet的冠军,到RCNN的出现,再到后来的SSD算法,数据增强仿佛像是一位功成名就的老者,虽然数据增强对于算法性能的提升起到重要的作用,但是他从来不居功,默默在背后付出”众里寻他千百度”,只为让你”蓦然回首,她在灯火阑珊处”。

    数据增强(Data Augmentation)的目的与作用

    卷积神经网络能够鲁棒地将物体分类,即便物体放置在不同的方向上,这也就是所说不变性的性质,即使卷积神经网络被放在不同方向上,它也能进行对象分类。更具体的说,卷积神经网络对平移、视角、尺寸或照度(或以上组合)保持不变性。 这就是数据增强的本质前提。在现实世界中,我们可能会有一组在有限的条件下拍摄的图像 。但是,我们的目标应用可能是在多变的环境中,例如,不同的方向、位置、比例、亮度等。我们通过使用经综合修改过的数据来训练神经网络,以应对这些情形。

    数据少的负面影响:

    1. 模型训练的时候可能无法收敛,少量训练数据难以提供足够的信息给模型学习
    2. 过拟合,模型容易将训练数据的完全不相关信息学习进去,如噪声
    3. 容易陷入局部最优值
    4. 难以衡量模型好坏,除了训练数据,测试数据也非常少,少量数据整的与否可能对结果产生较大影响。

    数据不平衡的负面影响: 最常见的就是模型的权值更新被数据多的一个方向带跑偏了。

    数据增强的作用

    1. 补充数据样本不足
    2. 减少网络的过拟合现象,通过对训练图片进行变换可以得到泛化能力更强的网络,更好的适应应用场景。

    基本方法

    现在最常用的数据方案是 数据增强的基本方法无非就是图像的基本操作进行排列组合,生成千万种数据增强的可能性:

    • 旋转/反射变换(Rotation/reflection): 随机旋转图像一定角度; 改变图像内容的朝向;
    • 翻转变换(flip): 沿着水平或者垂直方向翻转图像;
    • 缩放变换(zoom): 按照一定的比例放大或者缩小图像;
    • 平移变换(shift): 在图像平面上对图像以一定方式进行平移;
    • 可以采用随机或人为定义的方式指定平移范围和平移步长, 沿水平或竖直方向进行平移. 改变图像内容的位置;
    • 尺度变换(scale): 对图像按照指定的尺度因子, 进行放大或缩小; 或者参照SIFT特征提取思想, 利用指定的尺度因子对图像滤波构造尺度空间. 改变图像内容的大小或模糊程度;
    • 对比度变换(contrast): 在图像的HSV颜色空间,改变饱和度S和V亮度分量,保持色调H不变. 对每个像素的S和V分量进行指数运算(指数因子在0.25到4之间), 增加光照变化;
    • 噪声扰动(noise): 对图像的每个像素RGB进行随机扰动, 常用的噪声模式是椒盐噪声和高斯噪声;
    • 颜色变化:在图像通道上添加随机扰动。
    • PCA Jittering 首先,按照 RGB 三个颜色通道计算均值和方差,规范网络输入数据; 然后,计算整个训练数据集的协方差矩阵,进行特征分解,得到特征向量和特征值,以作 PCA Jittering.

    caffe中的数据增强

    caffe/src/caffe/data_transformer.cpp 只发现mirror、scale、crop三种。 其中Data_Transformer被调用的时候,会采用1/2的随机镜像,以及对应输入参数的scale和crop进行生成新的样本,输出到下一层网络中。因此,我们使用caffe训练的时候,只训练一个epoch就可以的情况是万万不能的。即使是同一个图片,同一套参数,也要进行多次采样才行。每个epoch进行shuffle一次,每次的batch中的分布就会发生变化,同样一张图片,虽然是同一套参数,也可能会出现不同的结果。在训练过程中的数据采样,随机性让样本不至于将噪声过度的学习。

    SSD中的数据增强

    SSD中的数据采样,在caffe中数据采样的基础上,进行了充分扩充,增强方式包括resizecropdistort,… 更重要的是引入BatchSampler, 以Batch中的数据基础,达到真正的增加不同overlap的数据的目的,使得检测能力极大增强。因此,我一度认为,SSD的成功不是One-Stage在Detection的突破,而是数据增强方法的提升。

    // Sample a batch of bboxes with provided constraints.
    message BatchSampler {
      // 是否使用原来的图片
      optional bool use_original_image = 1 [default = true];
      // sampler的参数
      optional Sampler sampler = 2;
      // 对于采样box的限制条件,决定一个采样数据positive or negative
      optional SampleConstraint sample_constraint = 3;
      // 当采样总数满足条件时,直接结束
      optional uint32 max_sample = 4;
      // 为了避免死循环,采样最大try的次数.
      optional uint32 max_trials = 5 [default = 100];
    }
    

    更多内容,参考博客:http://deepindeed.cn/2017/04/05/SSD-Data-Augmentation/

    海康威视MSCOCO比赛中的数据增强

    • 第一,对颜色的数据增强,包括色彩的饱和度、亮度和对比度等方面,主要从Facebook的代码里改过来的。
    • 第二,PCA Jittering,最早是由Alex在他2012年赢得ImageNet竞赛的那篇NIPS中提出来的. 我们首先按照RGB三个颜色通道计算了均值和标准差,对网络的输入数据进行规范化,随后我们在整个训练集上计算了协方差矩阵,进行特征分解,得到特征向量和特征值,用来做PCA Jittering。
    • 第三,在图像进行裁剪和缩放的时候,我们采用了随机的图像差值方式。
    • 第四, Crop Sampling,就是怎么从原始图像中进行缩放裁剪获得网络的输入。比较常用的有2种方法:
      • 一是使用Scale Jittering,VGG和ResNet模型的训练都用了这种方法。
      • 二是尺度和长宽比增强变换,最早是Google提出来训练他们的Inception网络的。我们对其进行了改进,提出Supervised Data Augmentation方法。

    学习的数据增强策略

    在分类模型中,常见的数据增广策略有尺度、平移、旋转。在目标检测任务中,较多使用镜像和多尺度训练进行数据增广。除此以外,一些方法在图像上随机增加噪声、遮挡等,或者在训练图像上增加新物体。当前大多数图像分类器使用人工数据增广方法,目前有一些工作1不再使用人工数据增广方法,而是使用从数据中学习到的策略以提升图像分类模型的性能。学习到的数据增广策略对小数据有较大帮助,避免过拟合。对于一个增广策略,将其分解成K个子策略,在训练过程中随机选择每个子策略,将该策略应用到当前图像上。其中,每个子策略包括N个图像变换。将搜寻最佳数据增广策略的问题就转换成在搜索空间中的离散优化问题。当前存在许多解决离散优化问题的方法,包括强化学习,基于序列模型的优化等。2将离散优化问题构建为RNN的输出空间,并采用强化学习来更新模型的权重。3

    启发点

    • 并不是越多越好,要在多的基础上保持随机性,因为应用场景的不是固定的输入
    • 结合新的方法,例如GAN进行生成图片等技术,进一步扩充训练集合
    • 合理性采样降低样本不均衡的影响

    小结

    同样的算法,数据增强能够显著提升算法的性能。不仅仅是因为我们采集的数据不够全面,而是我们专注的这个CV领域就是一个受多种因素影响的领域,光照,人物姿势,拍照角度,旋转角度等等。想要我们的CNN算子将所有这些影响因素都考虑进去,这是几乎不可能的。只有可能让它多学一点,多看一点,少犯一点错罢了。而数据增强就是能够让它可以多学一点不一样的东西,少一点死板在里面。 https://github.com/mdbloice/Augmentor

    可参考链接

    案例-医学图像分割的数据增广

    Data augmentation using learned transforms for one-shot medical image segmentation

    github: https://github.com/xamyzhao/brainstorm

    Biomedical image segmentation is an important task in many medical applications. Segmentation methods based on convolutional neural networks attain state-of-the-art accuracy; however, they typically rely on supervised training with large labeled datasets. Labeling datasets of medical images requires significant expertise and time, and is infeasible at large scales. To tackle the lack of labeled data, researchers use techniques such as hand-engineered preprocessing steps, hand-tuned architectures, and data augmentation. However, these techniques involve costly engineering efforts, and are typically dataset-specific. We present an automated data augmentation method for medical images. We demonstrate our method on the task of segmenting magnetic resonance imaging (MRI) brain scans, focusing on the one-shot segmentation scenario -- a practical challenge in many medical applications. Our method requires only a single segmented scan, and leverages other unlabeled scans in a semi-supervised approach. We learn a model of transforms from the images, and use the model along with the labeled example to synthesize additional labeled training examples for supervised segmentation. Each transform is comprised of a spatial deformation field and an intensity change, enabling the synthesis of complex effects such as variations in anatomy and image acquisition procedures. Augmenting the training of a supervised segmenter with these new examples provides significant improvements over state-of-the-art methods for one-shot biomedical image segmentation.
    

    医学图像segment中U-Net

    we train the network to discriminate between a set of surrogate classes. 
    Each surrogate class is formed by applying a variety of transformations 
    to a randomly sampled ’seed’ image patch. In contrast to supervised network 
    training, the resulting feature representation is not class specific. 
    It rather provides robustness to the transformations that have been applied 
    during training. This generic feature representation allows for classification 
    results that outperform the state of the art for unsupervised learning on 
    several popular datasets (STL-10, CIFAR-10, Caltech-101, Caltech-256). 
    While such generic features cannot compete with class specific features 
    from supervised training on a classification task, we show that they are 
    advantageous on geometric matching problems, where they also outperform the 
    SIFT descriptor.
    
    1. https://arxiv.org/pdf/1805.09501.pdf “AutoAugment:Learning Augmentation Strategies from Data” 

    2. https://arxiv.org/pdf/1906.11172.pdf “Learning Data Augmentation Strategies for Object Detection” 

    3. https://zhuanlan.zhihu.com/p/76446741 “目标检测之Data Augmentation” 

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    下一篇 CVPR2019的文章

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Generative Adeversarial Networks: Overview
    机遇 research之路其修远兮,我将上下而求索

    Generative Adeversarial Networks: Overview

    2019-02-01
    cwlseu

    引言

    电影《a beautiful mind》中文译作《美丽心灵》,mind既有头脑的意思,又有心灵的意思,应该是导演故意让它产生了歧义。哦,跑偏了,这部电影的主人公约翰-纳什通过战胜同学们的种种鄙视,压力等,在去追美女的过程中想到了博弈论的原型。 而这个博弈论就是今天学习的GAN的理论基础。

    博弈这个词,在中国文化中经常见到,可以想象成两位老者在下棋,正可谓棋逢对手,真是都想杀的对方片子不留,最后以平局收场。还有《古董局中局》中的斗宝, 双方分别拿出自己的最得意的一个赝品,让对方进行判断,这是真的还是假的,假在哪里等等。GAN的训练其实就是在这么一个不断斗宝的过程,不过是一个是高高手,一个是学徒,GAN训练过程就是学徒成长为高高手的过程。等到结束的时候,这个学徒造的赝品已经达到了这个高高手不能识别出来的程度。

    定义

    GANs是半监督和无监督中的新兴技术。通过竞争学习一对神经网络模型来实现对数据的高纬度表示。在其中通过 骗子(Genrator G)与专家(Discriminator D)之间的博弈,骗子想绘制出真品的来,专家来鉴定两个作品哪个真品哪个是赝品,差距在哪里。两个网络都是在学习的,就像骗子模仿技术越来越厉害,但是专家也是越来越强的,“魔高一尺,道高一丈”.

    $G: G(z) -> R^{|x|}$

    $D: D(x) -> (0, 1)$

    GANs的组成

    1. Fully Connected GANs: G和D都是使用全连接神经网络

    2. Convolutional GANs 特别适合与Image data的生成,但是使用相同表达能力的CNNs作为生成器和判别器,是很难训练的。其中LAP-GAN(Laplacian pyramid of adversarial networks)使用多尺度思想,将G的generation 过程分解为生成一个laplacian pyramid的过程.如果卷积网络使用deep convolution的话,即使DCGANs,通过利用stride和fractionally-strided convolutions在空间域中下采样和上采样操作。

    Generative Adversarial Networks (GANs)

    Lists (Table is borrowed from tensorflow-generative-model-collections)

    Name Paper Link Value Function
    GAN Arxiv
    LSGAN Arxiv
    WGAN Arxiv
    WGAN_GP Arxiv
    DRAGAN Arxiv
    CGAN Arxiv
    infoGAN Arxiv
    ACGAN Arxiv
    EBGAN Arxiv
    BEGAN Arxiv

    GAN的应用场景

    图像生成

    图像转换

    场景合成

    人脸合成

    文本到图像的合成

    风格迁移

    图像超分辨率

    图像域的转换

    图像修复

    MaskGAN

    GAN在图像领域建树颇多,但是在文本领域作用并不是很大,主要是NLP中的词的数据都是离散数据,GAN不适合学习离散的数据分布,但是并不意味着没法学,Google brain的团队发明了一个结合强化学习的MaskGAN,可以用作完型填空,具体任务是补全句子中的缺失部分。

    参考链接

    [1].GAN-collections

    [2]. https://blog.csdn.net/qq_25737169/article/details/80874717

    [3]. MaskGAN: Better Text Generation via Filling in the____

    The GAN Zoo

    Every week, new GAN papers are coming out and it’s hard to keep track of them all, not to mention the incredibly creative ways in which researchers are naming these GANs! So, here’s a list of what started as a fun activity compiling all named GANs!

    You can also check out the same data in a tabular format with functionality to filter by year or do a quick search by title here.

    Contributions are welcome. Add links through pull requests in gans.tsv file in the same format or create an issue to lemme know something I missed or to start a discussion.

    Check out Deep Hunt - my weekly AI newsletter for this repo as blogpost and follow me on Twitter.

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    相似博文

    欢迎评论

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Android手机上GDB调试
    机遇 research之路其修远兮,我将上下而求索

    Android手机上GDB调试

    2019-01-15
    cwlseu

    前言

    在android开发C++过程,除了使用logcat进行追踪程序之外,更加便捷的方式便是像在linux上开发使用gdb程序进行调试一样调试android程序,只不过程序不是运行在linux机器上,而是在某个android手机上。 常见的android手机上程序调试有:

    1. 通过打印log,这种方式对于比较庞大的项目有利于迅速定位问题的模块,但是,如果引用第三方库,某些程序调试起来会很无力。而且打印log的程序往往比较大,不利于部署发布,因此release版本往往都没有log
    2. 通过ssh连接,使用gdb进行调试,这种便于团队开发。
    3. 直接将手机usb连接在电脑上进行调试,这种情况适合个人开发

    SSH连接进行调试

    1. 将相关运行程序和依赖库拷贝到手机某个目录下,例如我将sdk_xxx拷贝到root@10.1.42.15:/data/data/berserker.android.apps.sshdroid/home/cwl/sdk_xxx
    2. 从本地机器中交叉编译链中查找gdb 例如我的机器上是在$NDK_DIR/prebuilt/android-arm64/gdbserver 到手机某个位置下,例如我放在跟项目相同目录下
    3. andorid手机上运行 gdbserver [port] [exe file] 运行该程序之前,先确认该[exe file]是否需要动态链接其他库,如果需要添加动态库路径到LD_LIBRARY_PATH 执行export LD_LIBRARY_PATH=./target/android-aarch64/test 然后再执行如下程序 ./gdbserver :5039 target/android-aarch64/test_sdk_xxx 将test_sdk_xxx与端口5039绑定

    4. 在本地查找对应的gdb程序进行调试例如 $NDK_DIR/android-aarch64/bin/aarch64-linux-android-gdb ./target/android-aarch64/test/test_sdk_xxx 如果ndk14b找不该程序,可以使用ndk10里面的gdb进行调试 ``` (gdb) help target target core – Use a core file as a target target exec – Use an executable file as a target target extended-remote – Use a remote computer via a serial line target record – Log program while executing and replay execution from log target record-btrace – Collect control-flow trace and provide the execution history target record-core – Log program while executing and replay execution from log target record-full – Log program while executing and replay execution from log target remote – Use a remote computer via a serial line target tfile – Use a trace file as a target

    Type “help target” followed by target subcommand name for full documentation. Type “apropos word” to search for commands related to “word”. Command name abbreviations are allowed if unambiguous.

    
    

    (gdb) target remote 10.1.42.15:5039 (gdb) continue (gdb) bt ```

    连接真机gdb

    查看手机usb

    cwl@ubuntu:~$ lsusb 
    Bus 002 Device 004: ID 18c3:6255  
    Bus 002 Device 002: ID 8087:0020 Intel Corp. Integrated Rate Matching Hub
    Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    Bus 001 Device 005: ID 22b8:41db Motorola PCS Motorola Droid (USB Debug)
    Bus 001 Device 004: ID 04d9:a06b Holtek Semiconductor, Inc. 
    

    添加udev规则

    udev就是一个动态硬件管理服务

    cwl@ubuntu:/etc/udev/rules.d$ cd /etc/udev/rules.d/
    cwl@ubuntu:/etc/udev/rules.d$ sudo vi 50-android-usb.rules
    

    编辑规则文件并保存 SUBSYSTEM=="usb", SYSFS("Motorola PCS Motorola Droid (USB Debug)")=="22b8",MODE="0666" 其中,sysfs括号内是自己android手机的实际描述信息,==后面的是id号,mode是读取模式,0666是所有人可以访问,以上的信息都是lsusb查处来的。

    设置规则文件权限并重启udev

    cwl@ubuntu:/etc/udev/rules.d$ sudo chmod a+rx /etc/udev/rules.d/50-android-usb.rules 
    cwl@ubuntu:/etc/udev/rules.d$ sudo /etc/init.d/udev restart 
    

    会看到udev相关的提示信息 adb push target/android-aarch64/test/test_sdk_xxx /data/local/tmp/sdk_xxx

    其他可能问题

    在手机里面执行文件的时候提示can't execute: Permission denied 一开始以为是没有root权限,自己傻逼了,错误意思是,不能执行,权限定义,

    解决办法

    chmod +x filename给文件可执行就可以。 一般把文件放到 /data/local/tmp/目录下 然后 chmod +x file

    小结

    交叉编译和开源项目,使得交叉编译、跨平台开发等问题越来容易,才能够有这种在android 调试程序和在linux上调试程序毫无间隙地切换。

    参考链接

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    Make & CMake 进阶
    机遇 research之路其修远兮,我将上下而求索

    Make & CMake 进阶

    2019-01-10
    cwlseu

    引言

    当下流行的IDE,将源代码生成可执行文件的过程都封装起来,对于开发着来说方便使用。 但是对于初学者来说,蒙蔽了源代码到可执行文件过程。源代码预处理,编译,打包,链接等步骤, 才能形成IDE中的一步到位的可执行文件target。而Makefile是直白的描述一个源代码如何被操作 才能成为target的一种文件格式。而CMake是一种可以通过配置的方式生成Makefile的脚本. 如果只是简单的开发一个.cpp进行测试,Makefile是首选。 本文中不对Makefile的基本语法进行介绍,要学习基本语法可以参看陈皓老师的Makefile中文教程进行学习。

    Makefile

    ifeqifneq之后要有个空格,否则不识别

    ifeq ($(UNAME), linux)
         $(info "")
    else
          $(warning "")
         $(error $(HAVE_SSHSERVER))
    endif 
    

    定义变量

    HAVE_THE_VALUE := # 新定义一个变量 HAVE_THE_VALUE ?= # 如果没有定义,则定义一个新变量 HAVE_THE_VALUE += # 往变量中append数据

    这个地方有点像pascal,不要与shell中混淆了

    变量赋值

    后面一定不要有空格,回车之类的空白符号,否则可能会将你整疯了的。 就拿caffe中的Makefile.config中

    USE_LEVELDB := 1

    USE_LEVELDB := 1

    这两行的区别在于,第二行赋值操作后面有一个空格。在Makefile中通过如下代码进行添加编译需要的宏。

    
    ifeq ($(USE_LEVELDB), 1)
      CXX_FLAGS += -DUSE_LEVELDB
    endif
    

    结果编译的时候打开的开关会与设想的不一样。

    Makefile案例

    #! Makefile
    
    SRCS := PAPI_flops.c
    OBJECTS := $(patsubst %.c, %.o, $(SRCS))
    STATIC_LIB := /usr/local/lib/libpapi.a
    INCLUDE_DIR := -I/usr/local/include
    CC := gcc
    
    
    all: PAPI_flops
    
    PAPI_flops: $(OBJECTS)
         $(CC) -O0 $< $(STATIC_LIB) -o $@
    
    $(OBJECTS): $(SRCS)
         $(CC) $(INCLUDE_DIR) -O0 -c $<
    
    test:
         echo "----Running the PAPI_flops-----"
         @./PAPI_flops
    
    clean:
         rm -rf PAPI_flops
         rm -rf *.o
    

    makefile中调用.a库的编写

    #!Makefile
    CC = g++
    
    TINYCV_DIR = /home/cwl/TinyCV
    TINYCV_INCLUDE_DIR = $(TINYCV_DIR)/include
    LIB_DIR = $(TINYCV_DIR)/build
    
    CXX_FLAG = -O3 -std=c++11 -Wall -Werror -fPIC
    
    all: main
    
    main: main.o
      $(CC) $< $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@
    
    main.o: main.cpp
      $(CC) $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -c $<
    
    clean:
      rm -f *.o main
    

    需要注意的是下面这句中$<是指输入文件main.o,此处紧跟gcc

    main: main.o
      $(CC) $< $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@
    

    但是如果变为如下情形,就会出现后面中的错误

    main: main.o
      $(CC) $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@  $<
    

    错误:

    caowenlong@Server-NF5280M3:~/Test$ make
    g++ -O3 -std=c++11 -Wall -Werror -fPIC -I/home/cwl/TinyCV/include -c main.cpp
    g++ -O3 -std=c++11 -Wall -Werror -fPIC -I/home/cwl/TinyCV/include -L/home/cwl/TinyCV/build -ltinycv -o main main.o
    main.o:在函数‘main’中:
    main.cpp:(.text.startup+0x3b):对‘tinycv::imread(std::string const&, int)’未定义的引用
    main.cpp:(.text.startup+0x43):对‘tinycv::Mat<unsigned char>::Mat()’未定义的引用
    main.cpp:(.text.startup+0x63):对‘double tinycv::threshold<unsigned char>(tinycv::Mat<unsigned char> const&, tinycv::Mat<unsigned char>&, double, double, int)’未定义的引用
    collect2: error: ld returned 1 exit status
    make: *** [main] 错误 1
    

    makefile中的全局自变量

    $@目标文件名 @^所有前提名,除副本 @+所有前提名,含副本 @<一个前提名 @?所有新于目标文件的前提名 @*目标文件的基名称

    是否输出执行过程

    #! Makefile
    SAMPLE_ENABLE ?= 1
    
    ifeq ($(SAMPLE_ENABLE), 1)
    	EXEC ?= @echo "[@]"
    endif
    
    target: target2
    	echo "hehe, this is target"
    
    target2:
    	echo "this is target2"
    clean:
    	rm -rf out.o
    

    CMake

    CMake 入门案例

    PROJECT(sdk_common_samples)
    cmake_minimum_required(VERSION 3.0)
    
    # 查找已经安装的包
    FIND_PACKAGE(OpenCV 2)
    
    # SET 指令的语法是:
    # SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
    
    SET(
    	SDK_COMMON_INCLUDE_DIR
    	${CMAKE_CURRENT_SOURCE_DIR}/../../include
    	CACHE PATH
    	"SDK_COMMON HEADER FILE PATH"
    )
    
    # MESSAGE 指令的语法是:
    # MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
    # 这个指令用于向终端输出用户定义的信息,包含了三种类型:
    # SEND_ERROR,产生错误,生成过程被跳过。
    # SATUS ,输出前缀为 — 的信息。
    # FATAL_ERROR,立即终止所有 cmake 过程.
    
    MESSAGE("Find libs in ${SDK_COMMON_LIB_DIR}")
    
    # INCLUDE_DIRECTORIES,其完整语法为:
    # INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
    # 这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割,如果路径
    # 中包含了空格,可以使用双引号将它括起来,默认的行为是追加到当前的头文件搜索路径的
    # 后面,你可以通过两种方式来进行控制搜索路径添加的方式:
    # 1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过 SET 这个 cmake 变量为 on,可以
    # 将添加的头文件搜索路径放在已有路径的前面。
    # 2,通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。
    INCLUDE_DIRECTORIES(
    	${PROJECT_SOURCE_DIR}
    	${SDK_COMMON_INCLUDE_DIR}
    	${OpenCV_INCLUDE_DIRS}
    )
    
    # 添加链接库的文件夹路径
    LINK_DIRECTORIES(${SDK_COMMON_LIB_DIR})
    
    # set最长用的方法,就像shell中export一个变量一样
    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2 -std=gnu++0x")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2 -std=gnu++0x")
    
    # 查找在相对路径下与*.cpp所匹配的模式的所有文件,保存到变量samples中
    FILE(GLOB samples ${PROJECT_SOURCE_DIR}/*.cpp)
    
    # 针对samples中的所有元素进行操作
    FOREACH (sample ${samples})
    	STRING(REGEX MATCH "[^/]+$" sample_file ${sample})
    	STRING(REPLACE ".cpp" "" sample_basename ${sample_file})
    	ADD_EXECUTABLE(test_${sample_basename} ${sample})
    	# 添加执行时的需要链接的lib: common OpenCV_Libs
    	TARGET_LINK_LIBRARIES(test_${sample_basename}
    	sdk_common ${OpenCV_LIBS})
    	# 另外,如果不是再window下的话需要添加线程库 -lpthread
    	if (NOT WIN32)
    		TARGET_LINK_LIBRARIES(test_${sample_basename} pthread)
    	endif()
    	
    	INSTALL(TARGETS test_${sample_basename} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
    ENDFOREACH() # foreach 结束
    
    

    windows指定编译器

    cmake \
    -DCMAKE_MODULE_PATH:PATH=Y:\\cmake  -DCMAKE_CONFIGURATION_TYPES=release \
    -DCMAKE_INSTALL_PREFIX=C:\\cygwin\\data\\windows-x86_64\\test \
    -G "Visual Studio 12 Win64" -T "v120_xp" ..
    
    cmake -G"Visual Studio 12 2013" -A x64 -DCMAKE_BUILD_TYPE=RELEASE ..
    cmake -G"Visual Studio 12 2013" -A Win32 -DCMAKE_BUILD_TYPE=RELEASE ..
    

    有的时候在windows下,buildtype为debug和release表现不同,而且概率还是比较高的。

    官网提供的入门教程中的案例

    cmake_minimum_required (VERSION 2.6)
    project (Tutorial)
    
    # should we use our own math functions?
    option (USE_MYMATH 
      "Use tutorial provided math implementation" ON) 
    
    # The version number.
    set (Tutorial_VERSION_MAJOR 1)
    set (Tutorial_VERSION_MINOR 0)
    
    # configure a header file to pass some of the CMake settings
    # to the source code
    configure_file (
      "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
      "${PROJECT_BINARY_DIR}/TutorialConfig.h"
      )
    
    # add the binary tree to the search path for include files
    # so that we will find TutorialConfig.h
    include_directories("${PROJECT_BINARY_DIR}")
    
    
    if (USE_MYMATH)
      include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
      add_subdirectory (MathFunctions)
      set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
    endif (USE_MYMATH)
    
    # add the executable
    add_executable(Tutorial main.cpp)
    target_link_libraries (Tutorial ${EXTRA_LIBS})
    
    # add the install targets
    install (TARGETS Tutorial DESTINATION bin)
    install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
      DESTINATION include)
    
    
    include(CTest)
    # does it sqrt of 25
    add_test (TutorialComp25 Tutorial 25)
    set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")
    # does it handle negative numbers
    #add_test (TutorialNegative Tutorial -25)
    #set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")
    
    # does it handle small numbers
    add_test (TutorialSmall Tutorial 0.0001)
    set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")
    
    # does the usage message work?
    add_test (TutorialUsage Tutorial)
    set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")
    
    #define a macro to simplify adding tests, then use it
    macro (do_test arg result)
      add_test (TutorialComp${arg} Tutorial ${arg})
      set_tests_properties (TutorialComp${arg}
      PROPERTIES PASS_REGULAR_EXPRESSION ${result})
    endmacro (do_test)
    
    do_test (81 "81 is 9")
    # do a bunch of result based tests
    do_test (25 "25 is 5")
    do_test (-25 "-25 is 0")
    

    CMake 特点

    • 跨平台,并且可以生成响应的编译配置文件,如在linux平台下生成makefile,在苹果下生成xcode,在windows下可以生成MSVC的工程文件
    • 开源,使用类BSD许可发布
    • 简化管理大型项目
    • 简化编译构建过程和编译过程cmake + make
    • 可拓展,可以编写特定功能的模块

    CMake问题

    • cmake编写的过程实际上是编程,每个目录一个CMakeLists.txt,使用cmake语言和语法
    • 一些拓展可以使用,但是配合起来可能不是很理想
    • 针对大型项目,如果项目比较小,还是直接编写makefile比较好

    定义变量

    1. 命令行中 cmake -DCUDA_USE_STATIC_CUDA_RUNTIME=1 ..
    2. cmake 中set的使用
    # 普通变量定义
    SET(DIDBUILD_TARGET_OS LINUX)
    # 强制覆盖
    SET(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE BOOL "fix cuda compiling error" FORCE)
    # 有则忽略,否则定义变量
    SET(DIDBUILD_TARGET_ARCH X86_64 CACHE STRING "default arch is x86_64")
    # 设置环境变量
    SET(ENV{LD_LIBRARY_PATH} /usr/local/lib64)
    

    字符串处理

    STRING(FIND $Origin_str $substr $target_str)

    此外,FIND,REPLACE,REGEX MATCHAPPEND string(CONCAT <output variable> [<input>...])

    Concatenate all the input arguments together and store the result in the named output variable.

    string(TOLOWER <string1> <output variable>)

    Convert string to lower characters.

    string(LENGTH <string> <output variable>)

    Store in an output variable a given string’s length.

    string(SUBSTRING <string> <begin> <length> <output variable>)

    Store in an output variable a substring of a given string. If length is -1 the remainder of the string starting at begin will be returned. If string is shorter than length then end of string is used instead.

    string(STRIP <string> <output variable>)

    Store in an output variable a substring of a given string with leading and trailing spaces removed.

    string(COMPARE LESS <string1> <string2> <output variable>)
    string(COMPARE EQUAL <string1> <string2> <output variable>)
    string(<HASH> <output variable> <input>)
    

    Compute a cryptographic hash of the input string. The supported <HASH> algorithm names are: 很多

    STREQUAL

    make VERBOSE=1

    可以将cmake中定义的变量打印

    Object Libraries

    The OBJECT library type is also not linked to. It defines a non-archival collection of object files resulting from compiling the given source files. The object files collection can be used as source inputs to other targets:

    add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)
    add_library(archiveExtras STATIC $<TARGET_OBJECTS:archive> extras.cpp)
    add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
    

    OBJECT libraries may only be used locally as sources in a buildsystem – they may not be installed, exported, or used in the right hand side of target_link_libraries(). They also may not be used as the TARGET in a use of the add_custom_command(TARGET) command signature.

    Although object libraries may not be named directly in calls to the target_link_libraries() command, they can be “linked” indirectly by using an Interface Library whose INTERFACE_SOURCES target property is set to name $<TARGET_OBJECTS:objlib>.

    ExternalProject,通过url配置依赖第三方库

    cmake/DownloadGoogleBenchmark.cmake

    INCLUDE(ExternalProject)
    ExternalProject_Add(googletest
    	URL https://github.com/google/googletest/archive/release-1.8.0.zip
    	URL_HASH SHA256=f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf
    	SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googletest"
    	BINARY_DIR "${CONFU_DEPENDENCIES_BINARY_DIR}/googletest"
    	CONFIGURE_COMMAND ""
    	BUILD_COMMAND ""
    	INSTALL_COMMAND ""
    	TEST_COMMAND ""
    )
    

    主CMakeLists.txt中的使用

    IF(PTHREADPOOL_BUILD_BENCHMARKS AND NOT DEFINED GOOGLEBENCHMARK_SOURCE_DIR)
         MESSAGE(STATUS "Downloading Google Benchmark to     ${CONFU_DEPENDENCIES_SOURCE_DIR}/googlebenchmark (define GOOGLEBENCHMARK_SOURCE_DIR to avoid it)")
         # 添加其他依赖路径
         CONFIGURE_FILE(cmake/DownloadGoogleBenchmark.cmake "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download/CMakeLists.txt")
         EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
         WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download")
         EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
         WORKING_DIRECTORY "${CONFU_DEPENDENCIES_BINARY_DIR}/googlebenchmark-download")
         SET(GOOGLEBENCHMARK_SOURCE_DIR "${CONFU_DEPENDENCIES_SOURCE_DIR}/googlebenchmark" CACHE STRING "Google Benchmark source directory")
    ENDIF()
    

    CMakeLists中的高级用法

    INSTALL(TARGETS libdeepindeed
      LIBRARY DESTINATION lib
      RUNTIME DESTINATION bin
      ARCHIVE DESTINATION lib)
    

    参考资料

    CMake manual

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    CUDA并行编程学习笔记
    机遇 research之路其修远兮,我将上下而求索

    CUDA并行编程学习笔记

    2019-01-01
    cwlseu

    名词

    • SIMD: 单指令多数据,是基于一个处理器核的,128位
    • MMX:多媒体拓展
    • AVX 高级适量拓展, 256位

    计算机架构

    冯诺依曼计算机架构

    • 内存受限型
    • QPI (quick path interconnect) 快速通道互联

    连接机

    采用4096个16核的CPU组装到一台机器上,也就是说64K个处理器来完成一个任务。连接机采用SIMD型并行处理,但是处理器之间的同步和通讯是很大的问题

    Cell处理器(众核)

    用一个常规处理器作为监管处理器(PowerPC),该处理器与大量高速流处理(SPE)相连。

    • 每个流处理单元SPE调用执行一个程序
    • 通过共享的网络,SPE之间和SPE与PowerPC之间进行相互通讯
    • 国产申威 26010 处理器架构图

    多点计算

    集群,当前最流行的莫过于Hadoop和spark了,一个是分布式文件系统,一个是分布式计算框架,这两个工具使得多点计算的方法充分发挥。

    GPU架构

    CUDA编程基础知识

    学习CUDA C,可以在异构计算平台中实现高性能的应用。CUD的编译原则–基于虚拟指令集的运行时编译。

    计算能力—高性能硬件与技术

    GPU在高性能计算和深度学习加速中扮演着非常重要的角色, GPU的强大的并行计算能力,大大提升了运算性能。随着运算数据量的不断攀升,GPU间需要大量的交换数据,GPU通信性能成为了非常重要的指标。NVIDIA推出的GPUDirect就是一组提升GPU通信性能的技术。但GPUDirect受限于PCI Expresss总线协议以及拓扑结构的一些限制,无法做到更高的带宽,为了解决这个问题,NVIDIA提出了NVLink总线协议。

    GPUDirect P2P

    GPUDirect Peer-to-Peer(P2P) 技术主要用于单机GPU间的高速通信,它使得GPU可以通过PCI Express直接访问目标GPU的显存,避免了通过拷贝到CPU host memory作为中转,大大降低了数据交换的延迟。 以深度学习应用为例,主流的开源深度学习框架如TensorFlow、MXNet都提供了对GPUDirect P2P的支持,NVIDIA开发的NCCL(NVIDIA Collective Communications Library)也提供了针对GPUDirect P2P的特别优化。 通过使用GPUDirect P2P技术可以大大提升深度学习应用单机多卡的扩展性,使得深度学习框架可以获得接近线性的训练性能加速比

    首先我们简单看下NVIDIA对NVLink的介绍:NVLink能在多GPU之间和GPU与CPU之间实现非凡的连接带宽。带宽有多大?2016发布的P100是搭载NVLink的第一款产品,单个GPU具有160GB/s的带宽,相当于PCIe Gen3 * 16带宽的5倍。去年GTC 2017上发布的V100搭载的NVLink 2.0更是将GPU带宽提升到了300G/s,差不多是PCIe的10倍了。

    NVLINK网络拓扑结构

    RDMA原理介绍

    前面介绍的GPUDirect P2P和NVLink技术可以大大提升GPU服务器单机的GPU通信性能,当前深度学习模型越来越复杂,计算数据量暴增,对于大规模深度学习训练任务,单机已经无法满足计算要求,多机多卡的分布式训练成为了必要的需求,这个时候多机间的通信成为了分布式训练性能的重要指标。

    多机通讯RMDA架构图 如上图所示,传统的TCP/IP协议,应用程序需要要经过多层复杂的协议栈解析,才能获取到网卡中的数据包,而使用RDMA协议,应用程序可以直接旁路内核获取到网卡中的数据包。RDMA可以简单理解为利用相关的硬件和网络技术,服务器1的网卡可以直接读写服务器2的内存,最终达到高带宽、低延迟和低资源利用率的效果。 应用RMDA技术的应用拓扑图 所谓GPUDirect RDMA,就是计算机1的GPU可以直接访问计算机2的GPU内存。而在没有这项技术之前,GPU需要先将数据从GPU内存搬移到系统内存,然后再利用RDMA传输到计算机2,计算机2的GPU还要做一次数据从系统内存到GPU内存的搬移动作。GPUDirect RDMA技术使得进一步减少了GPU通信的数据复制次数,通信延迟进一步降低。

    CUDA的基础入门

    函数的类型

    __host__ float HostFunc() 默认情况下,被host函数调用在CPU上执行

    __devide__ float DeviceFunc() 被GPU设备执行调用

    __global__ void Kernelfunc() 被host函数调用,在设备上执行

    Note:
    * __global__函数返回值必须为void
    * 在设备上执行的函数不能是递归,函数参数是固定的,不能再函数内部使用static变量
    

    变量类型

    __shared__ A[4];//在share memory,块内线程共享。 设备上的函数,声明的变量都是存在register上的,存不下的放到local memory; cudaMalloc()的空间是在设备的global memory上的。

    CUDA几个头文件

    #include<cuda_runtime.h>  // cuda程序运行必须的头文件
    

    CUDA routine

    1. cudaError_t err = cudaSuccess; cudaError_t类型,表示错误类型。cudaSuccess表示成功。一般cuda routine的返回值都是cudaError_t类型,表示函数是否执行成功。

    2. printf("%s\n", cudaGetErrorString(cudaGetLastError())); 输出错误时,使用以上函数转化为string。

    3. err = cudaMalloc((void **)&d_A, size); 动态内存申请函数,在设备的global memory上申请size个字节空间。

    4. err = cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);or err = cudaMemcpy(h_A, d_A, size, cudaMemcpyDeviceToHost); //内存拷贝函数:从cpu上的内存h_A上拷贝size个字节数据到gpu上的内存d_A。反之,一样。

    5. int threadsPerBlock = 256; int blocksPerGrid =(nElements + threadsPerBlock - 1) / threadsPerBlock; vectorAdd<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, nElements); //前2句,表示Grid,block都是1维时,设置网格内的块数,每块内的线程数。 //最后一句,启动kernel(运行在gpu端的函数)函数。 //注意前2句可以改成。dim3 threadsPerBlock(256);这种形式。

    6. err = cudaGetLastError(); //启动kernel函数时,并没有返回值,通过这个调用这个函数,查看kernel函数是否启动成功。

    7. err = cudaFree(d_A); //释放使用cudaMalloc申请的空间。

    8. err = cudaMemset(d_a, 0, size) //类似于memset函数。将d_A的size个字节置0.

    /**
     * CUDA device properties
     */
    struct __device_builtin__ cudaDeviceProp
    {
        char   name[256];                  /**< ASCII string identifying device */
        size_t totalGlobalMem;             /**< Global memory available on device in bytes */
        size_t sharedMemPerBlock;          /**< Shared memory available per block in bytes */
        int    regsPerBlock;               /**< 32-bit registers available per block */
        int    warpSize;                   /**< Warp size in threads */
        size_t memPitch;                   /**< Maximum pitch in bytes allowed by memory copies */
        int    maxThreadsPerBlock;         /**< Maximum number of threads per block */
        int    maxThreadsDim[3];           /**< Maximum size of each dimension of a block */
        int    maxGridSize[3];             /**< Maximum size of each dimension of a grid */
        int    clockRate;                  /**< Clock frequency in kilohertz */
        size_t totalConstMem;              /**< Constant memory available on device in bytes */
        int    major;                      /**< Major compute capability */
        int    minor;                      /**< Minor compute capability */
        size_t textureAlignment;           /**< Alignment requirement for textures */
        size_t texturePitchAlignment;      /**< Pitch alignment requirement for texture references bound to pitched memory */
        int    deviceOverlap;              /**< Device can concurrently copy memory and execute a kernel. Deprecated. Use instead asyncEngineCount. */
        int    multiProcessorCount;        /**< Number of multiprocessors on device */
        int    kernelExecTimeoutEnabled;   /**< Specified whether there is a run time limit on kernels */
        int    integrated;                 /**< Device is integrated as opposed to discrete */
        int    canMapHostMemory;           /**< Device can map host memory with cudaHostAlloc/cudaHostGetDevicePointer */
        int    computeMode;                /**< Compute mode (See ::cudaComputeMode) */
        int    maxTexture1D;               /**< Maximum 1D texture size */
        int    maxTexture1DMipmap;         /**< Maximum 1D mipmapped texture size */
        int    maxTexture1DLinear;         /**< Maximum size for 1D textures bound to linear memory */
        int    maxTexture2D[2];            /**< Maximum 2D texture dimensions */
        int    maxTexture2DMipmap[2];      /**< Maximum 2D mipmapped texture dimensions */
        int    maxTexture2DLinear[3];      /**< Maximum dimensions (width, height, pitch) for 2D textures bound to pitched memory */
        int    maxTexture2DGather[2];      /**< Maximum 2D texture dimensions if texture gather operations have to be performed */
        int    maxTexture3D[3];            /**< Maximum 3D texture dimensions */
        int    maxTexture3DAlt[3];         /**< Maximum alternate 3D texture dimensions */
        int    maxTextureCubemap;          /**< Maximum Cubemap texture dimensions */
        int    maxTexture1DLayered[2];     /**< Maximum 1D layered texture dimensions */
        int    maxTexture2DLayered[3];     /**< Maximum 2D layered texture dimensions */
        int    maxTextureCubemapLayered[2];/**< Maximum Cubemap layered texture dimensions */
        int    maxSurface1D;               /**< Maximum 1D surface size */
        int    maxSurface2D[2];            /**< Maximum 2D surface dimensions */
        int    maxSurface3D[3];            /**< Maximum 3D surface dimensions */
        int    maxSurface1DLayered[2];     /**< Maximum 1D layered surface dimensions */
        int    maxSurface2DLayered[3];     /**< Maximum 2D layered surface dimensions */
        int    maxSurfaceCubemap;          /**< Maximum Cubemap surface dimensions */
        int    maxSurfaceCubemapLayered[2];/**< Maximum Cubemap layered surface dimensions */
        size_t surfaceAlignment;           /**< Alignment requirements for surfaces */
        int    concurrentKernels;          /**< Device can possibly execute multiple kernels concurrently */
        int    ECCEnabled;                 /**< Device has ECC support enabled */
        int    pciBusID;                   /**< PCI bus ID of the device */
        int    pciDeviceID;                /**< PCI device ID of the device */
        int    pciDomainID;                /**< PCI domain ID of the device */
        int    tccDriver;                  /**< 1 if device is a Tesla device using TCC driver, 0 otherwise */
        int    asyncEngineCount;           /**< Number of asynchronous engines */
        int    unifiedAddressing;          /**< Device shares a unified address space with the host */
        int    memoryClockRate;            /**< Peak memory clock frequency in kilohertz */
        int    memoryBusWidth;             /**< Global memory bus width in bits */
        int    l2CacheSize;                /**< Size of L2 cache in bytes */
        int    maxThreadsPerMultiProcessor;/**< Maximum resident threads per multiprocessor */
        int    streamPrioritiesSupported;  /**< Device supports stream priorities */
        int    globalL1CacheSupported;     /**< Device supports caching globals in L1 */
        int    localL1CacheSupported;      /**< Device supports caching locals in L1 */
        size_t sharedMemPerMultiprocessor; /**< Shared memory available per multiprocessor in bytes */
        int    regsPerMultiprocessor;      /**< 32-bit registers available per multiprocessor */
        int    managedMemory;              /**< Device supports allocating managed memory on this system */
        int    isMultiGpuBoard;            /**< Device is on a multi-GPU board */
        int    multiGpuBoardGroupID;       /**< Unique identifier for a group of devices on the same multi-GPU board */
    };
    

    常见问题

    NVCC没有配置,导致undefined reference HEADER DIR没有配置,导致找不到头文件

    |版权声明:本文为博主原创文章,未经博主允许不得转载。


    欢迎评论

    Content

    本站记录我视觉之旅的沿途风景!

    Contact me at:

    本站总访问量次,本站访客数人次,本文总阅读量

    Site powered by Jekyll & Github Pages. Theme designed by HyG.

    NCNN: 应用于手机上的卷积加速