2016年的总结与展望

今年的最后一天,在公司的值班中度过。现在忙完了工作,可以静下心来,对今年做个回顾和总结,对明年做个规划和展望。

总结

在生活上,今年完成了自己的人生大事,又穿插着小半年的学驾照,天津的故地重游。生活上一直是简简单单的,和媳妇看电影、运动、养花养鱼。业余时间翻译了一本半书(有一本是和别人合译的),也写一些样稿。

在工作上,今年主要在各种文档和API中折腾,这一年的折腾,也让golang和ngx_lua的积累越来越多。同时,也更多的开始学习架构设计方面的知识,并有意识的在项目中使用。看别人的文档和API,也会思考下这么设计的好处和缺点。

下半年开始带应届生,一直鼓励他多看多折腾多总结,最近让他重构一个PHP的项目,看到他可以在不到一周的时间上手ngx_lua并基本完成这个项目的重构,还是很为他高兴的。

lua-resty-redis 返回空值的问题记录

背景

我们的服务本来使用一组redis,以一致性哈希的方式来使用,现在打算替换为云平台的redis集群服务,因此需要设计一个平滑过渡的方案。解决方案并不难,两种方式可以使用不同的key,对于一种key使用ring_redis,另一种使用redis集群,这样只需要在redis库的接口内部进行key的解析,就无需对其他代码做过多改动了。

实现并不难,但在测试时,遇到个很诡异的问题:从redis中取一个不存在的key时,返回的值(正常情况是json格式的字符串)在不存在的情况下,会导致nginx 500错误,通过日志中的trace看到,是返回的字符串无法被cjson解析导致,返回的字符串是userdata:NULL。这个返回的字符串引起我的好奇心,userdata是什么鬼?

什么是userdata

userdata是Lua中C API的一个基本类型,可以把任意的C数据存储在lua变量中,除了赋值和相等的判断外,没有其他的lua预定义的操作。userdata常用来表示由C应用或者库创建的新类型。

仔细看了lua-resty-redis的代码,才发现空值返回的是ngx.null这个变量。在nginx-api-for-lua中,ngx.null的含义如下:

The ngx.null constant is a NULL light userdata usually used to represent nil values in Lua tables etc and is similar to the lua-cjson library’s cjson.null constant. This constant was first introduced in the v0.5.0rc5 release.

cgo 的使用总结

背景

最近正在基于机器学习搭建一个多媒体分析平台,一方面鉴于组内成员多则有近两年的Go使用经验,少则也有半年的Go使用经验, 另一方面由于Go的格式统一、工程系统能力强大,所以选择Go为主要的开发语言。而对于多媒体分析,第一步就是图片视频的编解码,图片好说,而视频就比较难了。普通的编解码可以使用exec调用ffmpeg,但要获取视频每帧的数据内容,就需要使用ffmpeg的API了。通过github,我们找到了go-libav这个库,相比其他的go binding of ffmpeg libraries,这个库有以下几个优点:

  • 支持ffmpeg 3,也支持ffmpeg 2,但已废弃
  • 更加面向对象的编程方法
  • Go-Style,不是对ffmpeg API 的简单封装,而是以更加go的形式进行封装
  • 更简单的垃圾回收

其中第二点和第三点是我最欣赏这个库的主要原因,相比与其他ffmpeg库的直接封装,go-libav库加入了更多的语言易用性的思考。但是,目前这个库还在持续的开发中,还存在下面几个问题:

  • 支持的库有限,目前只有avcodec avfilter avformat avutil这四个库的一些基础API
  • 缺少样例,若没有使用ffmpeg API的经验,上手较难
  • 单元测试覆盖率只有32%,有可能测试不充分

我们近期已经为avutil扩展了一些功能,正在添加examples和单元测试,后续会提Merge Request反馈到这个库。在使用这个库的过程中,我们踩了一些cgo的坑,在这里总结一下cgo的使用方法和注意问题。

[翻译] 神经网络的直观解释

这篇文章原地址为An Intuitive Explanation of Convolutional Neural Networks,卷积神经网络的讲解非常通俗易懂。

什么是卷积神经网络?为什么它们很重要?

卷积神经网络(ConvNets 或者 CNNs)属于神经网络的范畴,已经在诸如图像识别和分类的领域证明了其高效的能力。卷积神经网络可以成功识别人脸、物体和交通信号,从而为机器人和自动驾驶汽车提供视力。

图 1

在上图中,卷积神经网络可以识别场景,也可以提供相关的标签,比如“桥梁”、“火车”和“网球”;而下图展示了卷积神经网络可以用来识别日常物体、人和动物。最近,卷积神经网络也在一些自然语言处理任务(比如语句分类)上面展示了良好的效果。

图 2

因此,卷积神经网络对于今天大多数的机器学习用户来说都是一个重要的工具。然而,理解卷积神经网络以及首次学习使用它们有时会很痛苦。那本篇博客的主要目的就是让我们对卷积神经网络如何处理图像有一个基本的了解。

如果你是神经网络的新手,我建议你阅读下这篇短小的多层感知器的教程,在进一步阅读前对神经网络有一定的理解。在本篇博客中,多层感知器叫做“全连接层”。

[翻译]梯度下降优化算法总结(2)

原文地址:optimizing-gradient-descent。如果熟悉英文的话,强烈推荐阅读原文,毕竟翻译过程中因为个人理解有限,可能会有谬误,还望读者能不吝指出。另外,由于原文太长,分了两部分翻译,上篇主要是梯度下降优化算法的总结,本篇将会是随机梯度的并行和分布式,以及优化策略的总结。

SGD 的并行和分布式

由于大规模数据解决方案和低档集群的存在,使用分布式 SGD 进行进一步加速是明显的选择。

SGD 本身属性是串行的:一步一步地,我们逐渐靠近最小值。运行它可以提供较好的收敛结果,但在大数据集上会非常慢。相反,异步运行 SGD 更快,但各个 worker 间的非优交互会导致收敛结果变差。而且,我们也可以在一台机器上,而无需大量的计算集群来并行化 SGD。接下来的部分就是已经提出来的优化并行和分布式 SGD 的算法和架构。

Hogwild!

Niu et al. [23] 引入了一个叫做 Hogwild! 的更新策略,可以使 SGD 可以在多 CPU 上并行更新。处理器在无需对参数加锁的情况下就可以访问共享内存。但仅在输入的是稀疏数据时才有效,因为每次更新仅修改所有参数的一小部分。他们展示了在这种情况下,更新策略几乎可以达到一个最优的收敛率,因为处理器不太可能覆盖掉有用的信息。

[翻译]梯度下降优化算法总结(1)

原文地址:optimizing-gradient-descent。如果熟悉英文的话,强烈推荐阅读原文,毕竟翻译过程中因为个人理解有限,可能会有谬误,还望读者能不吝指出。另外,由于原文太长,分了两部分翻译,本篇主要是梯度下降优化算法的总结,下篇将会是随机梯度的并行和分布式,以及优化策略的总结。

梯度下降是优化中最流行的算法之一,也是目前用于优化神经网络最常用到的方法。同时,每个优秀的深度学习库都包含了优化梯度下降的多种算法的实现(比如,lasagnecaffekeras 的文档)。然而,这些算法一般被封装成优化器,如黑盒一般,因此很难得到它们实际能力和缺点的解释。

本篇博客的目标是为读者提供不同梯度下降优化算法的直观解释,希望读者可以学以致用。我们会先了解下梯度下降的不同变种。然后会对训练过程的问题进行简单总结。接着,我们会介绍最常用的优化算法,展示它们解决这些问题的动机,以及它们对应更新规则变化的原因。我们也就会简单回顾在并行和分布式的情况下,梯度下降优化的算法和架构。最后,我们也会聊聊有助于优化梯度下降的其他策略。

梯度下降是最小化以模型参数 $\theta \in \mathbb{R}^d$ 构建的目标函数 $J(\theta)$ 的一种方法,它通过按目标函数 $\nabla_\theta J(\theta)$ 在参数梯度的相反方向更新参数。学习率 $\eta$ 决定了我们到达(局部)最小所需的步数的大小。换成通俗的话说,我们会沿着目标函数所构建的表面坡度的方向往下走,直到我们到达一个谷底。如果你还不熟悉梯度下降,你可以参考这篇优化神经网络的入门介绍