README.md 6.2 KB
Newer Older
C
add tdm  
chengmo 已提交
1 2
# Paddle-TDM-DEMO

C
add doc  
chengmo 已提交
3
本代码仅作tdm组网示例,使用fake数据集,用于快速调研paddle-tdm。
C
add tdm  
chengmo 已提交
4 5 6

## 代码结构

C
add doc  
chengmo 已提交
7 8 9 10 11

## 树结构的准备
### 名词概念

为防止概念混淆,让我们明确tdm中名词的概念:
C
chengmo 已提交
12

C
chengmo 已提交
13 14 15
<p align="center">
<img align="center" src="img/demo_tree.png" height="240px" width="940px">
<p>
C
add doc  
chengmo 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

- **item**:具有实际物理含义,是我们希望通过tdm检索最后得到的结果,如一个商品,一篇文章,一个关键词等等,在tdm模型中,item位于树的叶子节点。item有其自身的ID,我们姑且称之为 `item_id`
- **节点(node)**:tdm树的任意节点。我们完成聚类后,会生成一颗树,树的叶子节点对应着item。而非叶子节点,则是一种类别上的概括,从大方向的兴趣,不断细分到小方向的兴趣。我们希望这棵树的结构满足最大堆树的性质。同样,节点也有其自身的ID,我们称之为node_id。如上图,最左下方的节点,它的node_id是14,而对应的item_id是0.
- **Node-Embedding**:注意,此处的Embedding,并非我们已有的item-embedding,而是构建完成的树的节点对应的Embedding,由item-embedding通过规则生成,是我们的网络主要训练的目标。ID范围为所有0->节点数-1。我们同时也需准备一个映射表,来告诉模型,item_id到node_id的映射关系。
- **Travel**:是指叶子节点从root开始直到其自身的遍历路径,如上图,14号节点的Travel:0->1->3->7->14
- **Layer**:指树的层,如上图,共有4层。
  
> Paddle-TDM在训练时,不会改动树的结构,只会改动Node-Embedding。


### 树的准备流程

让我们以上图给出的简单树结构为例,来介绍TDM的模型准备流程。假设我们已经完成了树的聚类,并得到了如上图所示的树结构:

- 问题一:叶子节点的Embedding值是多少?答:叶子节点的node-embedding与对应的item的embedding值一致
- 问题二:非叶子节点的Embedding值是多少?答:非叶子节点的Embedding值初始化目前有两种方案:1、随机初始化。2、使用其子节点的emb均值。
- 问题三:树一定要求二叉树吗?答:没有这样的硬性要求。
- 问题四:若有item不在最后一层,树不平衡怎么办?答:树尽量平衡,不在最后一层也没有关系,我们可以通过其他方式让网络正常训练。
- 问题五:是每个用户都有一棵树,还是所有用户共享一颗树?答:只有一棵树,通过每一层的模型牵引节点的emb,使其尽量满足最大堆性质。

完成以上步骤,我们已经得到了树的结构,与每个节点的全部信息,现在让我们将其转换为Paddle-TDM训练所需的格式。我们需要产出四个数据:
#### Layer_list:记录了每一层都有哪些节点。训练用
```bash
# Layer list
1,2
3,4,5,6
7,8,9,10,11,12,13
14,15,16,17,18,19,20,21,22,23,24,25
```
#### Travel_list:记录每个叶子节点的Travel路径。训练用
```bash
# Travel list
1,3,7,14
1,3,7,15
1,3,8,16
...
2,5,12,25
2,6,13,0
```

#### Tree_Info:记录了每个节点的信息,主要为:是否是item/item_id,所在层级,父节点,子节点。检索用
```bash
0,0,0,1,2
0,1,0,3,4
0,1,0,5,6
0,2,1,7,8
...
10,4,12,0,0
11,4,12,0,0
```

#### Tree_Embedding:记录所有节点的Embedding表,格式如正常表。训练及检索用

以上数据设计的初衷是为了高效,在paddle网络中以Tensor的形式参与训练,运行时,不再需要进行频繁的树的结构的遍历,直接根据已有信息进行快速查找与训练。以上数据可以明文保存,但最终都需要转成ndarray,参与网络的初始化。
结合示例树,数据可以组织如右,下面介绍一些细节:

- Layer list从第2(index=1)层开始即可,因为0号节点不参与训练也不参与检索;
- Travel list的按照item_id的顺序组织,如第一行对应着item_id=0的遍历信息,同样,也不需要包含0号节点;
- Travel_list每行的长度必须相等,遇到不在最后一层的item,需要padding 0 直至长度和其他item一致;
- Tree_info包含了0号节点的信息,主要考量是,当我们拿到node_id查找其信息时,可以根据id在该数据中寻找第id行;
- Tree_info各列的含义是:itme_id(若无则为0),层级Layer,父节点node_id(无则为0),子节点node_id(若无则为0,若子节点数量不满,则需要paddding 0)

## 数据准备
如前所述,若我们关心的是输入一个user emb,得到他所感兴趣的item id,那我们就准备user_emb + 正样本item的格式的数据,负采样会通过paddle的tdm_sampler op得到。数据的准备不涉及树的结构,因而可以快速复用其他任务的训练数据来验证TDM效果。

```bash
# emb(float) \t item_id (int)
-0.9480544328689575 0.8702829480171204 -0.5691063404083252 ...... -0.04391402751207352 -0.5352795124053955 -0.9972627758979797 0.9397293329238892   4690780
```

## TDM网络设计
假设输入数据是 Emb + item_id,下面让我们开始介绍一个最简单的网络设计。
C
chengmo 已提交
88

C
chengmo 已提交
89 90 91
<p align="center">
<img align="center" src="img/demo_network.png" height="320px" width="940px">
<p>
C
chengmo 已提交
92

C
add doc  
chengmo 已提交
93
上图给出了一个非常简单的TDM示例网络,没有添加任何复杂的逻辑,纯用DNN实现。
C
chengmo 已提交
94
TDM的组网,宏观上,可以概括为三个部分
C
add doc  
chengmo 已提交
95 96 97 98 99 100
- 第一部分,输入侧的组网,如果想要对user/query进行一些预处理,或者添加Attention结构,通常都是在这一层次实现。
- 第二部分,每层的输入与节点信息交互的组网,这一部分是将user/query的信息与node信息结合,在树的不同层下,进行不同粒度兴趣的学习。通常而言,第一部分与第二部分具有紧密的联系,可以统一为一个部分。
- 第三部分,最终的判别组网,将每层交互得到的信息进行最终的概率判决。但这一层也不是必须的,并不要求所有层的信息都经过一个统一的分类器,可以各层拥有独立的概率判决器。为了逻辑划分更加清晰,我们在示例中添加了这个层次的组网,方便您更加直观的理解tdm网络。
再次强调,该示例组网仅为展示tdm的基本运行逻辑,请基于这个框架,升级改进您自己的网络。

### TDM代码细节