Skip to content

Commit 43314c8

Browse files
authored
Merge pull request #779 from duyiqi17/mind_fix
fix random.seed problem && make capsual_layer's implementation same t…
2 parents c3f4873 + f1d786f commit 43314c8

File tree

5 files changed

+75
-45
lines changed

5 files changed

+75
-45
lines changed

models/recall/mind/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,15 @@ python -u static_infer.py -m config.yaml -top_n 50 #对测试数据进行预测
107107
在全量数据下模型的指标如下:
108108
| 模型 | batch_size | epoch_num| Recall@50 | NDCG@50 | HitRate@50 |Time of each epoch |
109109
| :------| :------ | :------ | :------| :------ | :------| :------ |
110-
| mind | 128 | 20 | 8.43% | 13.28% | 17.22% | 398.64s(CPU) |
111-
110+
| mind(paddle实现) | 128 | 50 | 5.52% | 4.31% | 11.49% | 356.43s(CPU) |
112111

113112
1. 确认您当前所在目录为PaddleRec/models/recall/mind
114113
2. 进入paddlerec/datasets/AmazonBook目录下执行run.sh脚本,会下载处理完成的AmazonBook数据集,并解压到指定目录
115114
```bash
116115
cd ../../../datasets/AmazonBook
117116
sh run.sh
118117
```
118+
119119
3. 安装依赖,我们使用[faiss](https://github.com/facebookresearch/faiss)来进行向量召回
120120
```bash
121121
# CPU-only version(pip)

models/recall/mind/config_bigdata.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ runner:
1818
use_gpu: False
1919
use_auc: False
2020
train_batch_size: 128
21-
epochs: 20
21+
epochs: 50
2222
print_interval: 500
2323
model_save_path: "output_model_mind_all"
2424
infer_batch_size: 128
2525
infer_reader_path: "mind_infer_reader" # importlib format
2626
test_data_dir: "../../../datasets/AmazonBook/valid"
2727
infer_load_path: "output_model_mind_all"
28-
infer_start_epoch: 19
29-
infer_end_epoch: 20
28+
infer_start_epoch: 49
29+
infer_end_epoch: 50
3030

3131
# distribute_config
3232
# sync_mode: "async"
@@ -39,7 +39,7 @@ hyper_parameters:
3939
# optimizer config
4040
optimizer:
4141
class: Adam
42-
learning_rate: 0.005
42+
learning_rate: 0.001
4343
# strategy: async
4444
# user-defined <key, value> pairs
4545
item_count: 367983

models/recall/mind/infer.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def main(args):
110110
batch_data, config)
111111

112112
user_embs = user_embs.numpy()
113+
# print(user_embs)
113114
target_items = np.squeeze(batch_data[-1].numpy(), axis=1)
114115

115116
if len(user_embs.shape) == 2:
@@ -119,8 +120,9 @@ def main(args):
119120
dcg = 0.0
120121
item_list = set(I[i])
121122
iid_list = list(filter(lambda x: x != 0, list(iid_list)))
122-
for no, iid in enumerate(iid_list):
123-
if iid in item_list:
123+
true_item_set = set(iid_list)
124+
for no, iid in enumerate(I[i]):
125+
if iid in true_item_set:
124126
recall += 1
125127
dcg += 1.0 / math.log(no + 2, 2)
126128
idcg = 0.0
@@ -138,6 +140,7 @@ def main(args):
138140
recall = 0
139141
dcg = 0.0
140142
item_list_set = set()
143+
item_cor_list = []
141144
item_list = list(
142145
zip(
143146
np.reshape(I[i * ni:(i + 1) * ni], -1),
@@ -147,13 +150,15 @@ def main(args):
147150
if item_list[j][0] not in item_list_set and item_list[
148151
j][0] != 0:
149152
item_list_set.add(item_list[j][0])
153+
item_cor_list.append(item_list[j][0])
150154
if len(item_list_set) >= args.top_n:
151155
break
152156
iid_list = list(filter(lambda x: x != 0, list(iid_list)))
153-
for no, iid in enumerate(iid_list):
157+
true_item_set = set(iid_list)
158+
for no, iid in enumerate(item_cor_list):
154159
if iid == 0:
155160
break
156-
if iid in item_list_set:
161+
if iid in true_item_set:
157162
recall += 1
158163
dcg += 1.0 / math.log(no + 2, 2)
159164
idcg = 0.0

models/recall/mind/mind_reader.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from paddle.io import IterableDataset
1818
import random
1919

20+
random.seed(12345)
21+
2022

2123
class RecDataset(IterableDataset):
2224
def __init__(self, file_list, config):
@@ -51,7 +53,7 @@ def init(self):
5153
self.items = list(self.items)
5254

5355
def __iter__(self):
54-
random.seed(12345)
56+
# random.seed(12345)
5557
while True:
5658
user_id_list = random.sample(self.users, self.batch_size)
5759
if self.count >= self.batches_per_epoch * self.batch_size:
@@ -61,7 +63,7 @@ def __iter__(self):
6163
item_list = self.graph[user_id]
6264
if len(item_list) <= 4:
6365
continue
64-
random.seed(12345)
66+
# random.seed(12345)
6567
k = random.choice(range(4, len(item_list)))
6668
item_id = item_list[k]
6769

models/recall/mind/net.py

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(self,
4545
self.new_prob = paddle.assign(self.prob.astype("float32"))
4646
self.log_q = paddle.log(-(paddle.exp((-paddle.log1p(self.new_prob) * 2
4747
* n_sample)) - 1.0))
48+
self.loss = nn.CrossEntropyLoss(soft_label=True)
4849

4950
def sample(self, labels):
5051
"""Random sample neg_samples
@@ -65,6 +66,7 @@ def forward(self, inputs, labels, weights, bias):
6566
# weights.stop_gradient = False
6667
embedding_dim = paddle.shape(weights)[-1]
6768
true_log_probs, samp_log_probs, neg_samples = self.sample(labels)
69+
# print(neg_samples)
6870
n_sample = neg_samples.shape[0]
6971

7072
b1 = paddle.shape(labels)[0]
@@ -82,33 +84,33 @@ def forward(self, inputs, labels, weights, bias):
8284
sample_b = all_b[-n_sample:]
8385

8486
# [B, D] * [B, 1,D]
85-
true_logist = paddle.matmul(
86-
true_w, inputs.unsqueeze(1), transpose_y=True).squeeze(1) + true_b
87+
true_logist = paddle.sum(paddle.multiply(true_w, inputs.unsqueeze(1)),
88+
axis=-1) + true_b
89+
# print(true_logist)
8790

8891
sample_logist = paddle.matmul(
89-
inputs.unsqueeze(1), sample_w, transpose_y=True) + sample_b
90-
91-
if self.subtract_log_q:
92-
true_logist = true_logist - true_log_probs.unsqueeze(1)
93-
sample_logist = sample_logist - samp_log_probs
92+
inputs, sample_w, transpose_y=True) + sample_b
9493

9594
if self.remove_accidental_hits:
96-
hit = (paddle.equal(labels[:, :], neg_samples)).unsqueeze(1)
95+
hit = (paddle.equal(labels[:, :], neg_samples))
9796
padding = paddle.ones_like(sample_logist) * -1e30
9897
sample_logist = paddle.where(hit, padding, sample_logist)
9998

100-
sample_logist = sample_logist.squeeze(1)
99+
if self.subtract_log_q:
100+
true_logist = true_logist - true_log_probs.unsqueeze(1)
101+
sample_logist = sample_logist - samp_log_probs
102+
101103
out_logist = paddle.concat([true_logist, sample_logist], axis=1)
102104
out_label = paddle.concat(
103105
[
104106
paddle.ones_like(true_logist) / self.num_true,
105107
paddle.zeros_like(sample_logist)
106108
],
107109
axis=1)
110+
out_label.stop_gradient = True
108111

109-
sampled_loss = F.softmax_with_cross_entropy(
110-
logits=out_logist, label=out_label, soft_label=True)
111-
return sampled_loss, out_logist, out_label
112+
loss = self.loss(out_logist, out_label)
113+
return loss, out_logist, out_label
112114

113115

114116
class Mind_Capsual_Layer(nn.Layer):
@@ -148,6 +150,7 @@ def __init__(self,
148150
name="bilinear_mapping_matrix", trainable=True),
149151
default_initializer=nn.initializer.Normal(
150152
mean=0.0, std=self.init_std))
153+
self.relu_layer = nn.Linear(self.output_units, self.output_units)
151154

152155
def squash(self, Z):
153156
"""squash
@@ -164,8 +167,10 @@ def sequence_mask(self, lengths, maxlen=None, dtype="bool"):
164167
batch_size = paddle.shape(lengths)[0]
165168
if maxlen is None:
166169
maxlen = lengths.max()
167-
row_vector = paddle.arange(0, maxlen, 1).unsqueeze(0).expand(
168-
shape=(batch_size, maxlen)).reshape((batch_size, -1, maxlen))
170+
row_vector = paddle.arange(
171+
0, maxlen,
172+
1).unsqueeze(0).expand(shape=(batch_size, maxlen)).reshape(
173+
(batch_size, -1, maxlen))
169174
lengths = lengths.unsqueeze(-1)
170175
mask = row_vector < lengths
171176
return mask.astype(dtype)
@@ -182,39 +187,50 @@ def forward(self, item_his_emb, seq_len):
182187

183188
mask = self.sequence_mask(seq_len_tile, self.maxlen)
184189
pad = paddle.ones_like(mask, dtype="float32") * (-2**32 + 1)
185-
186190
# S*e
187191
low_capsule_new = paddle.matmul(item_his_emb,
188192
self.bilinear_mapping_matrix)
189193

190-
low_capsule_new_nograd = paddle.assign(low_capsule_new)
194+
low_capsule_new_tile = paddle.tile(low_capsule_new, [1, 1, self.k_max])
195+
low_capsule_new_tile = paddle.reshape(
196+
low_capsule_new_tile,
197+
[-1, self.maxlen, self.k_max, self.output_units])
198+
low_capsule_new_tile = paddle.transpose(low_capsule_new_tile,
199+
[0, 2, 1, 3])
200+
low_capsule_new_tile = paddle.reshape(
201+
low_capsule_new_tile,
202+
[-1, self.k_max, self.maxlen, self.output_units])
203+
low_capsule_new_nograd = paddle.assign(low_capsule_new_tile)
191204
low_capsule_new_nograd.stop_gradient = True
192205

193206
B = paddle.tile(self.routing_logits,
194207
[paddle.shape(item_his_emb)[0], 1, 1])
208+
B.stop_gradient = True
195209

196210
for i in range(self.iters - 1):
197211
B_mask = paddle.where(mask, B, pad)
198212
# print(B_mask)
199213
W = F.softmax(B_mask, axis=1)
214+
W = paddle.unsqueeze(W, axis=2)
200215
high_capsule_tmp = paddle.matmul(W, low_capsule_new_nograd)
216+
# print(low_capsule_new_nograd.shape)
201217
high_capsule = self.squash(high_capsule_tmp)
202218
B_delta = paddle.matmul(
203-
high_capsule, low_capsule_new_nograd, transpose_y=True)
204-
B += B_delta / paddle.maximum(
205-
paddle.norm(
206-
B_delta, p=2, axis=-1, keepdim=True),
207-
paddle.ones_like(B_delta))
219+
low_capsule_new_nograd,
220+
paddle.transpose(high_capsule, [0, 1, 3, 2]))
221+
B_delta = paddle.reshape(
222+
B_delta, shape=[-1, self.k_max, self.maxlen])
223+
B += B_delta
208224

209225
B_mask = paddle.where(mask, B, pad)
210226
W = F.softmax(B_mask, axis=1)
211-
# paddle.static.Print(W)
212-
high_capsule_tmp = paddle.matmul(W, low_capsule_new)
213-
# high_capsule_tmp.stop_gradient = False
214-
215-
high_capsule = self.squash(high_capsule_tmp)
216-
# high_capsule.stop_gradient = False
227+
W = paddle.unsqueeze(W, axis=2)
228+
interest_capsule = paddle.matmul(W, low_capsule_new_tile)
229+
interest_capsule = self.squash(interest_capsule)
230+
high_capsule = paddle.reshape(interest_capsule,
231+
[-1, self.k_max, self.output_units])
217232

233+
high_capsule = F.relu(self.relu_layer(high_capsule))
218234
return high_capsule, W, seq_len
219235

220236

@@ -246,6 +262,7 @@ def __init__(self,
246262
name="item_emb",
247263
initializer=nn.initializer.XavierUniform(
248264
fan_in=item_count, fan_out=embedding_dim)))
265+
# print(self.item_emb.weight)
249266
self.embedding_bias = self.create_parameter(
250267
shape=(item_count, ),
251268
is_bias=True,
@@ -267,11 +284,17 @@ def __init__(self,
267284
def label_aware_attention(self, keys, query):
268285
"""label_aware_attention
269286
"""
270-
weight = paddle.sum(keys * query, axis=-1, keepdim=True)
271-
weight = paddle.pow(weight, self.pow_p) # [x,k_max,1]
272-
weight = F.softmax(weight, axis=1)
273-
output = paddle.sum(keys * weight, axis=1)
274-
return output, weight
287+
weight = paddle.matmul(keys,
288+
paddle.reshape(query, [
289+
-1, paddle.shape(query)[-1], 1
290+
])) #[B, K, dim] * [B, dim, 1] == [B, k, 1]
291+
weight = paddle.squeeze(weight, axis=-1)
292+
weight = paddle.pow(weight, self.pow_p) # [x,k_max]
293+
weight = F.softmax(weight) #[x, k_max]
294+
weight = paddle.unsqueeze(weight, 1) #[B, 1, k_max]
295+
output = paddle.matmul(
296+
weight, keys) #[B, 1, k_max] * [B, k_max, dim] => [B, 1, dim]
297+
return output.squeeze(1), weight
275298

276299
def forward(self, hist_item, seqlen, labels=None):
277300
"""forward
@@ -281,7 +304,7 @@ def forward(self, hist_item, seqlen, labels=None):
281304
seqlen : [B, 1]
282305
target : [B, 1]
283306
"""
284-
307+
# print(hist_item)
285308
hit_item_emb = self.item_emb(hist_item) # [B, seqlen, embed_dim]
286309
user_cap, cap_weights, cap_mask = self.capsual_layer(hit_item_emb,
287310
seqlen)

0 commit comments

Comments
 (0)