# 1、RippleNet原理

## 1.1 RippleNet背景

Ripple是波纹的意思，RippleNet就是模拟用户兴趣在知识图谱上的一个传播过程，如下图所示：

## 1.2 RippleNet网络结构

Ripple Set：用户u的k-hop ripple set被定义为以k-1 Relevant Entity 为head的相关三元组：

# 2、RippleNet的Tensorflow实现

rating_final.txt数据形式如下，三列分别是user-id，item-id以及label（0是通过负采样得到的，正负样本比例为1:1）。

kg_final.txt格式如下，三类分别代表h，r，t(这里entity和item用的是同一套id)：

### 网络输入

```def _build_inputs(self):
self.items = tf.placeholder(dtype=tf.int32, shape=[None], name="items")
self.labels = tf.placeholder(dtype=tf.float64, shape=[None], name="labels")
self.memories_h = []
self.memories_r = []
self.memories_t = []

for hop in range(self.n_hop):
self.memories_h.append(
tf.placeholder(dtype=tf.int32, shape=[None, self.n_memory], name="memories_h_" + str(hop)))
self.memories_r.append(
tf.placeholder(dtype=tf.int32, shape=[None, self.n_memory], name="memories_r_" + str(hop)))
self.memories_t.append(
tf.placeholder(dtype=tf.int32, shape=[None, self.n_memory], name="memories_t_" + str(hop)))```

### embedding层构建

```def _build_embeddings(self):
self.entity_emb_matrix = tf.get_variable(name="entity_emb_matrix", dtype=tf.float64,
shape=[self.n_entity, self.dim],
initializer=tf.contrib.layers.xavier_initializer())
self.relation_emb_matrix = tf.get_variable(name="relation_emb_matrix", dtype=tf.float64,
shape=[self.n_relation, self.dim, self.dim],
initializer=tf.contrib.layers.xavier_initializer())```

### 模型构建

```def _build_model(self):
# transformation matrix for updating item embeddings at the end of each hop
self.transform_matrix = tf.get_variable(name="transform_matrix", shape=[self.dim, self.dim], dtype=tf.float64,
initializer=tf.contrib.layers.xavier_initializer())

# [batch size, dim]
self.item_embeddings = tf.nn.embedding_lookup(self.entity_emb_matrix, self.items)

self.h_emb_list = []
self.r_emb_list = []
self.t_emb_list = []
for i in range(self.n_hop):
# [batch size, n_memory, dim]
self.h_emb_list.append(tf.nn.embedding_lookup(self.entity_emb_matrix, self.memories_h[i]))

# [batch size, n_memory, dim, dim]
self.r_emb_list.append(tf.nn.embedding_lookup(self.relation_emb_matrix, self.memories_r[i]))

# [batch size, n_memory, dim]
self.t_emb_list.append(tf.nn.embedding_lookup(self.entity_emb_matrix, self.memories_t[i]))

o_list = self._key_addressing()

self.scores = tf.squeeze(self.predict(self.item_embeddings, o_list))
self.scores_normalized = tf.sigmoid(self.scores)```

_key_addressing()是用来的到我们的olist的，即我们在RippleNet中的绿色矩形表示的向量：

```def _key_addressing(self):
o_list = []
for hop in range(self.n_hop):
# [batch_size, n_memory, dim, 1]
h_expanded = tf.expand_dims(self.h_emb_list[hop], axis=3)
# [batch_size, n_memory, dim]
Rh = tf.squeeze(tf.matmul(self.r_emb_list[hop], h_expanded), axis=3)
# [batch_size, dim, 1]
v = tf.expand_dims(self.item_embeddings, axis=2)
# [batch_size, n_memory]
probs = tf.squeeze(tf.matmul(Rh, v), axis=2)
# [batch_size, n_memory]
probs_normalized = tf.nn.softmax(probs)
# [batch_size, n_memory, 1]
probs_expanded = tf.expand_dims(probs_normalized, axis=2)
# [batch_size, dim]
o = tf.reduce_sum(self.t_emb_list[hop] * probs_expanded, axis=1)

self.item_embeddings = self.update_item_embedding(self.item_embeddings, o)
o_list.append(o)
return o_list```

```def update_item_embedding(self, item_embeddings, o):
if self.item_update_mode == "replace":
item_embeddings = o
elif self.item_update_mode == "plus":
item_embeddings = item_embeddings + o
elif self.item_update_mode == "replace_transform":
item_embeddings = tf.matmul(o, self.transform_matrix)
elif self.item_update_mode == "plus_transform":
item_embeddings = tf.matmul(item_embeddings + o, self.transform_matrix)
else:
raise Exception("Unknown item updating mode: " + self.item_update_mode)
return item_embeddings```

```def predict(self, item_embeddings, o_list):
y = o_list[-1]
if self.using_all_hops:
for i in range(self.n_hop - 1):
y += o_list[i]

# [batch_size]
scores = tf.reduce_sum(item_embeddings * y, axis=1)
return scores```

### 计算损失

```def _build_loss(self):
self.base_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=self.labels, logits=self.scores))

self.kge_loss = 0
for hop in range(self.n_hop):
h_expanded = tf.expand_dims(self.h_emb_list[hop], axis=2)
t_expanded = tf.expand_dims(self.t_emb_list[hop], axis=3)
hRt = tf.squeeze(tf.matmul(tf.matmul(h_expanded, self.r_emb_list[hop]), t_expanded))
self.kge_loss += tf.reduce_mean(tf.sigmoid(hRt))
self.kge_loss = -self.kge_weight * self.kge_loss

self.l2_loss = 0
for hop in range(self.n_hop):
self.l2_loss += tf.reduce_mean(tf.reduce_sum(self.h_emb_list[hop] * self.h_emb_list[hop]))
self.l2_loss += tf.reduce_mean(tf.reduce_sum(self.t_emb_list[hop] * self.t_emb_list[hop]))
self.l2_loss += tf.reduce_mean(tf.reduce_sum(self.r_emb_list[hop] * self.r_emb_list[hop]))
if self.item_update_mode == "replace nonlinear" or self.item_update_mode == "plus nonlinear":
self.l2_loss += tf.nn.l2_loss(self.transform_matrix)
self.l2_loss = self.l2_weight * self.l2_loss

self.loss = self.base_loss + self.kge_loss + self.l2_loss```

0 条评论

• ### 推荐系统遇上深度学习(十一)--神经协同过滤NCF原理及实战

好久没更新该系列了，最近看到了一篇关于神经协同过滤的论文，感觉还不错，跟大家分享下。

• ### DQN三大改进(二)-Prioritised replay

Prioritised replay原文：https://arxiv.org/pdf/1511.05952.pdf 代码地址：https://github.co...

• ### 推荐系统遇上深度学习(二十三)--大一统信息检索模型IRGAN在推荐领域的应用

信息检索领域的一个重要任务就是针对用户的一个请求query，返回一组排好序的召回列表。

• ### 封装与扩展性

封装在于明确区分内外，使得类实现者可以修改封装内的东西而不影响外部调用者的代码；而外部使用用者只知道一个接口(函数)，只要接口（函数）名、参数不变，使用者的代码...

• ### 再议Python协程——从yield到asyncio

协程，英文名Coroutine。 前面介绍Python的多线程，以及用多线程实现并发（参见这篇文章【浅析Python多线程】），今天介绍的协程也是常用的并发手段...

• ### What？废柴， 模拟登陆，代码控制滑动验证真的很难吗？Are you kidding？？？

在前边的python接口自动化的时候，我们由于博客园的登录机制的改变，没有用博客园的登录测试接口。那么博客园现在变成了滑动验证登录，而且现在绝大多数的登录都变成...

• ### Selenium2+python自动化48-登录方法（参数化）

前言 登录这个场景在写用例的时候经常会有，我们可以把登录封装成一个方法，然后把账号和密码参数化，这样以后用的登录的时候，只需调用这个方法就行了 一、登录方法 1...

• ### Django(三)：HttpReques

当一个请求连接进来时，django会创建一个HttpRequest对象来封装和保存所有请求相关的信息，并且会根据请求路由载入匹配的视图函数。每个请求的视图函...

• ### python unittest初探

class Request:    url = ""    method = ""    paras = {}    def __init__(self...

• ### 昨晚家里停网后，我写了一段代码破解了隔壁小姐姐的wifi密码...

昨晚，家里停网了，对于码农而言，停网了，这能忍？打电话给修网络的，说太晚了，要第二天才能过来...