存档在 ‘神经网络’ 分类

机器学习利用 Elasticsearch 进行更智能搜索

2017年3月23日

众所周知,机器学习正在引领许多行业的变革。对于曾疲于用人工调整搜索相关性来捕捉细微差别的搜索行业就更是如此。人工调整已经实现了其能达到的最好效果,成熟的搜索公司不满足于此,试图建立更加智能和自动化的搜索系统。

因此,  Elasticsearch 学习排序插件 发布后我们非常激动。那么,学习排序是什么?用学习排序方法,一个团队就可以训练机器学习模型来判断用户行为的相关性。

在实现排名学习的时候,你需要:

  • 通过分析来衡量用户对相关度的评价, 以构建出一个评价列表,将文档分为与查询精确相关、适度相关以及完全无关,这几个等级。

  • 猜测那些特性可能对相关性的预测有所帮助, 比如指定域匹配的 TF*IDF , 新近程度, 搜索用户的个性特征等等。

  • 对一个模型进行训练使其能够精确地将特性匹配到一个相关度等级上去。

  • 将模型部署到你的搜索设施上去,利用它来在生产环境中对搜索结果进行排名。

不要被假象欺骗。上述这些步骤,其中的每一个底层都是复杂的、技术上实现起来比较困难的,以及非技术性的问题。实施起来仍然不会有捷径可循。如我们在  相关度搜索 中所提过的, 对搜索结果的手工调整会遇到跟应用一个好的排名学习解决方案相比许多相同的挑战。以后我们会在博文中就成熟的排名学习解决方案中关于基础设施、技术以及非技术性的挑战发表更多的意见。

在本篇博文中,我想告诉你关于我们将机器学习集成到 Elasticsearch 中的排名系统中去,所做的一些工作。客户在几乎  每一次的相关咨询会议 中都要问我们这项技术是否能帮助到他们。然而,虽然在   Solr 中 Bloomberg 使其有了一个应用此技术的明确途径,但在 Elasticsearch 仍然没有。许多的客户想要的是 Elasticsearch 能满足更加与时俱进的可用性需求, 却发现在为他们的搜索技术栈选择该项技术方案时存在关键性的缺失。

诚然, Elasticsearch 的 DSL 查询可以利用强大的能力和复杂的架构来实现对结果的排名。一名熟练的相关领域的工程师可以利用查询 DSL 来计算出各种也许会标识出相关性的查询时间特性, 然后给出如下一些定量问题的回答:

  1. 标题中提到的搜索字条有多少?

  2. 文章、影片等等是多久之前发布的?

  3. 文档是如何同用户的浏览习惯相关联的?

  4. 该产品的价格相对于买房的预期是贵了还是便宜?

  5. 用户在搜索是使用的词条与文章主题之间的概念性相关度几何?

这些特性大部分都不是搜索引擎文档的静态属性。相反,它们是依赖于查询的,即计量用户、用户查询和某个文档的相关度。请  关联搜索 的读者知悉,这就是我们在书中提到的标记。

因此问题就变成了,如何将机器学习和 elasticsearch 提供的 Query DSL 查询相结合?这就是我们的插件要完成的工作:在用户向一个机器学习模型输入特征值的时候使用 Elasticsearch Query DSL 查询。

如何工作?

这个插件集成了  RankLib 和 Elasticsearch。Ranklib 的输入是一个评分文件,它以易读格式输出一个内置的模型。我们需要通过编程或者命令行训练这个模型。有了模型以后,Elasticsearch 插件会包含如下内容:

  • 一个自定义的 Elasticsearch 脚本语音  ranklib ,它可以接受 ranklib 的模型作为 Elasticsearch 脚本

  • 一个自定义查询  ltr query ,它的输入是包含了 Query DSL 查询(特征值)和模型名称(上一步那个)还有分数结果的列表。

鉴于排名学习模型的实现成本极高,你可能永远不会想要使用 ltr query,而是会像下面这样给前 N 个结果  重新打分 :

 

{
 "query": { /*a simple base query goes here*/ },
 "rescore": {
  "window_size": 100,
  "query": {
   "rescore_query": {
    "ltr": {
     "model": {
      "stored": "dummy"
     },
     "features": [{
        "match": {
         "title": < users keyword search >
        }
       }...

你可以到项目的  scripts 目录仔细研究这个功能完整的样例。这个例子封装严密,使用了 TMDB 的电影的手工评分。我用 Elasticsearch 索引了 TMDB 来检索相应特征,然后用这些检索和特征的相应分扩大了评分文件,并在命令行训练了一个 Ranklib 模型。这个模型被我存储进 Elasticsearch,并用它执行了一条检索脚本。

别被这个简单的例子忽悠了。真实的排名学习方案是大量的工作的结果,包括研究用户、处理分析、数据工程和特征处理等。我这么说不是要吓退你,而是你只要想想你的所得就明白你的付出是值得的。小型企业使用手工调整的 ROI 可能更好一些。

训练和加载排名学习模型

咱们就用我提供的这个手动创建的、迷你的排名列表来看一下我如何训练模型。

Ranklib 评分列表有十分严格的格式。第一列是文档评分,从 0 到 4。第二列是查询 id,比如 “qid:1.” 后面的列是检索文档对的特征值:左边的是基于 1 的特征索引,右边的是特征值。 下面是Ranklib README 中的数据:

3 qid:1 1:1 2:1 3:0 4:0.2 5:0 # 1A 2 qid:1 1:0 2:0 3:1 4:0.1 5:1 # 1B 1 qid:1 1:0 2:1 3:0 4:0.4 5:0 # 1C 1 qid:1 1:0 2:0 3:1 4:0.3 5:0 # 1D 1 qid:2 1:0 2:0 3:1 4:0.2 5:0 # 2A

注意一下注释(用井号开头的),是评分的文档标识。这个标识对于 Ranklib 没用,不过对应我们阅读很有用。后面我们会看到通过 Elasticsearch 检索也会用到这类标识符。

我们用一个最小版本的文件举例 (看  这里 )。我们需要从文件的削减版开始,这个文件仅仅含有一级,查询 id 和文档 id 元组. 像这样:

4 qid:1 # 7555 3 qid:1 # 1370 3 qid:1 # 1369 3 qid:1 # 1368 0 qid:1 # 136278 ...

如上所述,我们为分级的文件提供 Elasticsearch _id,作为每行的注释。

我们必须将每个查询 id (qid:1) 与实际的关键字查询 (“Rambo”) 相匹配,以便用关键字生成特征值。我们在例子代码的开头提供匹配关系:

# 在下面加入你的关键字, 特征脚本将会它们安置于查询模板 
# # qid:1: rambo # qid:2: rocky # qid:3: bullwinkle # # https://sourceforge.net/p/lemur/wiki/RankLib%20File%20Format/ # # 4 qid:1 # 7555 3 qid:1 # 1370 3 qid:1 # 1369 3 qid:1 # 1368 0 qid:1 # 136278 ...

为使大家更好地了解,我将要把 ranklib”查询” (qid:1 等等) 作为关键字来区分 Elasticsearch Query DSL 查询 ,Elasticsearch Query DSL 查询是 Elasticsearch 用于生成特征值的明确的结构。

上述不是完整的 Ranklib 判断列表。当给定关键字查询文档时,它仅仅是相关性等级的极简案例。要成为完整的训练集,它需要包含上述值的特征,在每行第一个判断列表显示后包含 1:0 2:1 … 等等。

为生成那些特征值,我们需要提出与电影相关的特征属性。正如我们刚才所述,有 Elasticsearch 查询。Elasticsearch 查询的分数将填充上述的判断列表。上述例子中,我们用 jinja 模板与每个特征数字相对应。例如, 文件  1.json.jinja 是下面的 Query DSL 查询:

{ "query": { "match": { "title": "" } } }

换言之,对于我们的电影检索系统,当用户的关键字与标题字段匹配时,我们决定把特征 1 作为 TF*IDF 相关分数。文件  2.jinja.json , 遍及多个文本字段,做了更复杂的查询:

{ "query": { "multi_match": { "query": "", "type": "cross_fields", "fields": ["overview", "genres.name", "title", "tagline", "belongs_to_collection.name", "cast.name", "directors.name"], "tie_breaker": 1.0 } } }

学习排名的乐趣之一是假设特征的相关性。举例来说,在任意 Elasticsearch 查询中,你可以改变特征 1 和 2,你也可以通过增加额外的特征来实验。特征太多就会出现问题,你需要充分的训练样本来覆盖所有合理的特征值。在后续文章中,我们将讨论更多关于训练与测试学习来排名模型。

通过精简版判断列表和 Query DSL 查询/特征 集这两个因素,我们要为 Ranklib 生成更多的判断列表,将 Ranklib 生成模型加载进 Elasticsearch。这意味着:

  1. 为特征和关键字/文档对获取相关分数。又称,向 Elasticsearch 发出查询,记录相关分数。

  2. 输出全量的判断文件,不仅关于级别以及关键字查询ids,而且有步骤 1 中的特征值:

    • 运行 Ranklib 训练模型。

    • 在查询时,加载模型至 Elasticsearch。

所有代码均在  train.py ,我建议你进行拆分,在执行:

    • RankLib.jar 下载至 scripts 文件夹.

    • 安装 Elasticsearch and Jinja2 Python 包(有一个 requirements.txt 文件)。

机器学习系列:递归神经网络

2017年1月23日

前言

BP神经网络,训练的时候,给定一组输入和输出,不断的对权值进行训练,使得输出达到稳定。但BP神经网络并不是适合所有的场景,并不真正的体现出某些场景的真正特点。回到经典的概率论问题,抛硬币问题,假设你已经抛了100次的,90次是正面的,10次是反面的,问现在继续在抛一次,出现正面的概率是多少?如果没有前面几次的经验,很正常的会认为再次出现正面的概率是50%,但由于我们之前有对这个进行了实验,即有了经验了,按照贝叶斯定律,出现正面的概率肯定会大于50%。BP神经网络也少了对前面结果的一种反馈。

常见,易懂的受到前位影响的算法,加法算法。十位的结果,所到个位结果的影响,因为可能有进位,同样,百位的结果所到十位的影响。

这种受到前位影响的算法非常的常见,而经典BP神经网络并不能很好的反映这种算法的特性,需要就经典的BP神经网络进行优化和改造,也就是引进前位,历史数据对网络的影响,使其具备时序性。通过历史数据的关联来推测后续的事情。

递归神经网络RNN

从前面加法算法的动态图中,对现有的 BP 神经网络进行改造,也就是加入前位的结果对于后续网络的影响。

这里把 BP 神经网络设计成上图的形式,很形象的揭示了递归神经网络的特点,前向的结果,作为下一个输入,影响下一个网络的结果。递归神经网络,在很多方向已经取得了很好的成果。而一种特殊的递归神经网络 Long Short Term 网络(LSTM),取到的结果最为璀璨,是这个方向的明星。

来看看LSTM的实现。

LSTM 网络

1997年 Hochreiter & Schmidhuber 提出了Long Short Term 网络,它是一种 RNN 的实现形式,在很多问题上,LSTM 取得了相当大的成功,在许多的领域上都有很好的成果。

最简单的 LSTM 网络:

把前位的输出结果当成后位的输入,经过 tanh 层,相当于扩充了原来BP神经网络的另一个输入。这样一次的进行训练。

在简化一点的方式如下图:

如果去掉 layer1 层,那么就是一个最简单的 BP神经网络了。这里引入了 layer1 层,使得经典的 BP 神经网络多了一个输入,layer_1 层在加法算法中,表示的是前一个输入就可以反映出加法算法的特性,从结构来看,这个 LSTM 的变形并不是非常的复杂,但现在就重要的就是如何计算出各个层次的增量,然后进行迭代了。

这里主要需要解决导数问题 python 的代码实现:

变量的更新:

其中 layer1delta 变量为两个变量的和:

完整的迭代过程在:

https://iamtrask.github.io/2015/11/15/anyone-can-code-lstm/

在递归神经网络中,跟经典的BP神经网络在结构上并没有太多的不同,最关键的点,还是在求解增量,进行迭代。

回头再想,如果仅仅用BP神经网络的算法能不能实现出加法算法,我觉得是可以的,但是速度和准确性不会有LSTM高。因此,LSTM的结构也是可以改进算法,不同的结构方式可以避免算法的很多缺陷。

更一般的LSTM结构:

算法的迭代过程在:

http://nicodjimenez.github.io/2014/08/08/lstm.html

https://github.com/nicodjimenez/lstm

算法跟BP神经网络没有太大的不同,但要注意的还是各个变量的增量和迭代问题。

递归神经网络的应用

递归神经网络跟BP神经网络,最大的不同是引进了时序,可以根据以往的数据来推测未来的事件。这是现在比较热门的一个方向。比较多的应用实在语音和文本的处理上,网上有相当多的关于递归神经网络的应用,比如写出像汪峰一样的歌词,默写唐诗,写冷段子等。但要写出像样的歌词和诗词,还需要做很多的处理,如果把递归神经网络应用在推荐系统里,也会得到不错的效果。

参考