From da6b1dc5826d87ae853559cc88943e0b382cbf69 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Sun, 9 Apr 2023 18:50:52 +0800 Subject: [PATCH 01/12] create file --- recbole/model/context_aware_recommender/fm2.py | 13 +++++++++++++ recbole/properties/model/FM2.yaml | 0 2 files changed, 13 insertions(+) create mode 100644 recbole/model/context_aware_recommender/fm2.py create mode 100644 recbole/properties/model/FM2.yaml diff --git a/recbole/model/context_aware_recommender/fm2.py b/recbole/model/context_aware_recommender/fm2.py new file mode 100644 index 000000000..7e35d2a09 --- /dev/null +++ b/recbole/model/context_aware_recommender/fm2.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# @Time : 2023/4/9 +# @Author : Yilin Liu +# @Email : liu_elaine2022@outlook.com +# @File : fm2.py + +r""" +FmFM +##################################################### +Reference: + Sun Y, Pan J, Zhang A, et al. “FM2: Field-matrixed Factorization Machines for Recommender Systems.” in WWW 2021. +""" +import torch diff --git a/recbole/properties/model/FM2.yaml b/recbole/properties/model/FM2.yaml new file mode 100644 index 000000000..e69de29bb From 2ed27298ede11bbb82ca3af770d7e8e383181ffd Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Sun, 9 Apr 2023 19:14:03 +0800 Subject: [PATCH 02/12] add --- recbole/model/context_aware_recommender/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/recbole/model/context_aware_recommender/__init__.py b/recbole/model/context_aware_recommender/__init__.py index 7ec7b8fc2..5b9ff3b96 100644 --- a/recbole/model/context_aware_recommender/__init__.py +++ b/recbole/model/context_aware_recommender/__init__.py @@ -6,6 +6,7 @@ from recbole.model.context_aware_recommender.dssm import DSSM from recbole.model.context_aware_recommender.ffm import FFM from recbole.model.context_aware_recommender.fm import FM +from recbole.model.context_aware_recommender.fm2 import FM2 from recbole.model.context_aware_recommender.fnn import FNN from recbole.model.context_aware_recommender.fwfm import FwFM from recbole.model.context_aware_recommender.lr import LR @@ -15,3 +16,4 @@ from recbole.model.context_aware_recommender.xdeepfm import xDeepFM from recbole.model.context_aware_recommender.fignn import FiGNN from recbole.model.context_aware_recommender.kd_dagfm import KD_DAGFM + From 99b579652b091ca194cae99e8505aac222c46592 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Sun, 16 Apr 2023 23:05:15 +0800 Subject: [PATCH 03/12] add --- .../model/context_aware_recommender/fm2.py | 137 ++++++++++++++++++ recbole/properties/model/FM2.yaml | 3 + 2 files changed, 140 insertions(+) diff --git a/recbole/model/context_aware_recommender/fm2.py b/recbole/model/context_aware_recommender/fm2.py index 7e35d2a09..0852301b8 100644 --- a/recbole/model/context_aware_recommender/fm2.py +++ b/recbole/model/context_aware_recommender/fm2.py @@ -10,4 +10,141 @@ Reference: Sun Y, Pan J, Zhang A, et al. “FM2: Field-matrixed Factorization Machines for Recommender Systems.” in WWW 2021. """ + import torch +import torch.nn as nn +from torch.nn.init import xavier_normal_, constant_ +from recbole.model.abstract_recommender import ContextRecommender + +class FM2(ContextRecommender): + """""" + def __init__(self, config, dataset): + super(FM2, self).__init__(config, dataset) + + # self.embedding_layer = EmbeddingLayer(feature_map, embedding_dim) + self.embedding_dim = config["embedding_dim"] + + self.num_fields = self.num_feature_field + + self.interact_dim = int(self.num_fields * (self.num_fields - 1) / 2) # + + + # self.fields = config["fields"] + # self.num_features = self.num_feature_field + + # self.embedding_dim = config["embedding_dim"] + + self.sigmoid = nn.Sigmoid() + self.loss = nn.BCEWithLogitsLoss() + + self.weight = torch.randn( + self.interact_dim, self.embedding_dim, self.embedding_dim, requires_grad=True, device=self.device + ) + # parameters initialization + self.apply(self._init_weights) + + self.triu_index = torch.triu(torch.ones(self.num_fields, self.num_fields), 1).nonzero().to(self.device) + + # self.feature_names = ( + # self.token_field_names, + # self.token_seq_field_names, + # self.float_field_names, + # ) + # self.feat_dims = ( + # self.token_field_dims, + # self.token_seq_field_dims, + # self.float_field_dims, + # ) + # self.interaction_weight = nn.Parameter(torch.Tensor(self.interact_dim, self.embedding_dim, self.embedding_dim)) + + + + + def _init_weights(self, module): + if isinstance(module, nn.Embedding): + xavier_normal_(module.weight.data) + elif isinstance(module, nn.Linear): + xavier_normal_(module.weight.data) + if module.bias is not None: + constant_(module.bias.data, 0) + + def fm2_matrix(self, infeature): + + # batch_size = infeature.shape[0] + # fm2_inter = [] + # for i, feature_emb in enumerate(infeature): + # + # left_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 0]) + # right_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 1]) + # left_emb = torch.matmul(left_emb.unsqueeze(2), self.weight).squeeze(2) + # fm2_in = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) + # fm2_inter.append(fm2_in) + + feature_emb = infeature + left_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 0]) + right_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 1]) + left_emb = torch.matmul(left_emb, self.weight).squeeze(2) + fm2_output = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) + + # # Reduce to [N, 1] + # fm2_output = torch.sum(fm2_inter, dim=1, keepdim=True) # [batch_size, 1] + + # weight = self.weight.expand(batch_size, -1, -1, -1) + # print(infeature) + + + + + # l_left, l_right = [], [] + # field_order = sorted(self.feature_dims.items(), key=lambda x: (-x[1], x[0])) + # for idx_l, (feat_l, dim_l) in enumerate(field_order): + # for idx_r, (feat_r, dim_r) in enumerate(field_order[idx_l + 1:]): + # idx_r += (idx_l + 1) + # name = '%s_%s' % (feat_l, feat_r) + # name_alt = '%s_%s' % (feat_r, feat_l) + # if self.cross_fields and name not in self.cross_fields and name_alt not in self.cross_fields: + # continue + # + # l_left.append(torch.matmul(self.xv[feat_l], w)) + # l_right.append(self.xv[feat_r]) + # + # l_left = torch.cat(l_left, 1) + # l_right = torch.cat(l_right, 1) + # fm2_inter = torch.mul(l_left, l_right) + # + # + # # Reduce to [N, 1] + # fm2_output = torch.sum(fm2_inter, dim=1, keepdim=True) # [batch_size, 1] + # + # batch_size = infeature.shape[0] + # weight = self.weight.expand(batch_size, -1, -1, -1) + # + # fwfm_inter = list() # [batch_size, num_fields, emb_dim] + # for i in range(self.num_features - 1): + # for j in range(i + 1, self.num_features): + # Fi, Fj = self.feature2field[i], self.feature2field[j] + # fwfm_inter.append(infeature[:, i] * infeature[:, j] * weight[:, Fi, Fj]) + # fwfm_inter = torch.stack(fwfm_inter, dim=1) + # fwfm_inter = torch.sum(fwfm_inter, dim=1) # [batch_size, emb_dim] + + return fm2_output + + def forward(self, interaction): + fm2_all_embeddings = self.concat_embed_input_fields( + interaction + ) # [batch_size, num_field, embed_dim] + + output = self.first_order_linear(interaction) + self.fm2_matrix( + fm2_all_embeddings + ) + + return output.squeeze(-1) + + + def calculate_loss(self, interaction): + label = interaction[self.LABEL] + output = self.forward(interaction) + return self.loss(output, label) + + def predict(self, interaction): + return self.sigmoid(self.forward(interaction)) \ No newline at end of file diff --git a/recbole/properties/model/FM2.yaml b/recbole/properties/model/FM2.yaml index e69de29bb..b3a62cd5d 100644 --- a/recbole/properties/model/FM2.yaml +++ b/recbole/properties/model/FM2.yaml @@ -0,0 +1,3 @@ +#fields: ~ # (dict) key: field's id, value: features in this field. +embedding_dim: 128 +embedding_size: 128 # (int) The embedding size of features. \ No newline at end of file From 3fb16fc5f085f8b5b15cc16d15eb293ea062eae4 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Mon, 17 Apr 2023 13:26:38 +0800 Subject: [PATCH 04/12] run successful --- .../model/context_aware_recommender/fm2.py | 100 +++--------------- recbole/properties/model/FM2.yaml | 4 +- 2 files changed, 16 insertions(+), 88 deletions(-) diff --git a/recbole/model/context_aware_recommender/fm2.py b/recbole/model/context_aware_recommender/fm2.py index 0852301b8..a047c854a 100644 --- a/recbole/model/context_aware_recommender/fm2.py +++ b/recbole/model/context_aware_recommender/fm2.py @@ -17,22 +17,16 @@ from recbole.model.abstract_recommender import ContextRecommender class FM2(ContextRecommender): - """""" + """ + Field-matrixed Factorization Machines (FmFM, or 𝐹M^2 ), propose a novel approach FmFM to model the +interactions of field pairs as a matrix. + """ def __init__(self, config, dataset): super(FM2, self).__init__(config, dataset) - # self.embedding_layer = EmbeddingLayer(feature_map, embedding_dim) - self.embedding_dim = config["embedding_dim"] - + self.embedding_dim = config["embedding_size"] self.num_fields = self.num_feature_field - - self.interact_dim = int(self.num_fields * (self.num_fields - 1) / 2) # - - - # self.fields = config["fields"] - # self.num_features = self.num_feature_field - - # self.embedding_dim = config["embedding_dim"] + self.interact_dim = int(self.num_fields * (self.num_fields - 1) / 2) self.sigmoid = nn.Sigmoid() self.loss = nn.BCEWithLogitsLoss() @@ -40,26 +34,13 @@ def __init__(self, config, dataset): self.weight = torch.randn( self.interact_dim, self.embedding_dim, self.embedding_dim, requires_grad=True, device=self.device ) + # parameters initialization self.apply(self._init_weights) + # used to mark cross items self.triu_index = torch.triu(torch.ones(self.num_fields, self.num_fields), 1).nonzero().to(self.device) - # self.feature_names = ( - # self.token_field_names, - # self.token_seq_field_names, - # self.float_field_names, - # ) - # self.feat_dims = ( - # self.token_field_dims, - # self.token_seq_field_dims, - # self.float_field_dims, - # ) - # self.interaction_weight = nn.Parameter(torch.Tensor(self.interact_dim, self.embedding_dim, self.embedding_dim)) - - - - def _init_weights(self, module): if isinstance(module, nn.Embedding): xavier_normal_(module.weight.data) @@ -69,63 +50,13 @@ def _init_weights(self, module): constant_(module.bias.data, 0) def fm2_matrix(self, infeature): - - # batch_size = infeature.shape[0] - # fm2_inter = [] - # for i, feature_emb in enumerate(infeature): - # - # left_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 0]) - # right_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 1]) - # left_emb = torch.matmul(left_emb.unsqueeze(2), self.weight).squeeze(2) - # fm2_in = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) - # fm2_inter.append(fm2_in) - - feature_emb = infeature - left_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 0]) - right_emb = torch.index_select(feature_emb, 1, self.triu_index[:, 1]) - left_emb = torch.matmul(left_emb, self.weight).squeeze(2) - fm2_output = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) - - # # Reduce to [N, 1] - # fm2_output = torch.sum(fm2_inter, dim=1, keepdim=True) # [batch_size, 1] - - # weight = self.weight.expand(batch_size, -1, -1, -1) - # print(infeature) - - - - - # l_left, l_right = [], [] - # field_order = sorted(self.feature_dims.items(), key=lambda x: (-x[1], x[0])) - # for idx_l, (feat_l, dim_l) in enumerate(field_order): - # for idx_r, (feat_r, dim_r) in enumerate(field_order[idx_l + 1:]): - # idx_r += (idx_l + 1) - # name = '%s_%s' % (feat_l, feat_r) - # name_alt = '%s_%s' % (feat_r, feat_l) - # if self.cross_fields and name not in self.cross_fields and name_alt not in self.cross_fields: - # continue - # - # l_left.append(torch.matmul(self.xv[feat_l], w)) - # l_right.append(self.xv[feat_r]) - # - # l_left = torch.cat(l_left, 1) - # l_right = torch.cat(l_right, 1) - # fm2_inter = torch.mul(l_left, l_right) - # - # - # # Reduce to [N, 1] - # fm2_output = torch.sum(fm2_inter, dim=1, keepdim=True) # [batch_size, 1] - # - # batch_size = infeature.shape[0] - # weight = self.weight.expand(batch_size, -1, -1, -1) - # - # fwfm_inter = list() # [batch_size, num_fields, emb_dim] - # for i in range(self.num_features - 1): - # for j in range(i + 1, self.num_features): - # Fi, Fj = self.feature2field[i], self.feature2field[j] - # fwfm_inter.append(infeature[:, i] * infeature[:, j] * weight[:, Fi, Fj]) - # fwfm_inter = torch.stack(fwfm_inter, dim=1) - # fwfm_inter = torch.sum(fwfm_inter, dim=1) # [batch_size, emb_dim] + """ + FmFM interaction terms calculation + """ + left_emb = torch.index_select(infeature, 1, self.triu_index[:, 0]) # [batch_size, interact_dim, embed_dim] + right_emb = torch.index_select(infeature, 1, self.triu_index[:, 1]) + left_emb = torch.matmul(left_emb.unsqueeze(2), self.weight).squeeze(2) + fm2_output = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) # [batch_size, 1] return fm2_output @@ -140,7 +71,6 @@ def forward(self, interaction): return output.squeeze(-1) - def calculate_loss(self, interaction): label = interaction[self.LABEL] output = self.forward(interaction) diff --git a/recbole/properties/model/FM2.yaml b/recbole/properties/model/FM2.yaml index b3a62cd5d..741a494f2 100644 --- a/recbole/properties/model/FM2.yaml +++ b/recbole/properties/model/FM2.yaml @@ -1,3 +1 @@ -#fields: ~ # (dict) key: field's id, value: features in this field. -embedding_dim: 128 -embedding_size: 128 # (int) The embedding size of features. \ No newline at end of file +embedding_size: 10 # (int) The embedding size of features. \ No newline at end of file From 91714be2893b1ab00371e2e782d789e1c10bda9d Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Tue, 18 Apr 2023 13:09:31 +0800 Subject: [PATCH 05/12] add --- tests/model/test_model_auto.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/model/test_model_auto.py b/tests/model/test_model_auto.py index dea05cec5..26eaa4362 100644 --- a/tests/model/test_model_auto.py +++ b/tests/model/test_model_auto.py @@ -408,6 +408,13 @@ def test_kd_dagfm(self): } quick_test(config_dict) + def test_fm2(self): + config_dict = { + "model": "FM2", + "threshold": {"rating": 4}, + } + quick_test(config_dict) + class TestSequentialRecommender(unittest.TestCase): def test_din(self): From e51b21cc93f1616761b4110d83f11555b6e0db48 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Tue, 18 Apr 2023 15:24:18 +0800 Subject: [PATCH 06/12] add --- .../model/context_aware_recommender/fm2.py | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/recbole/model/context_aware_recommender/fm2.py b/recbole/model/context_aware_recommender/fm2.py index a047c854a..8d1121b11 100644 --- a/recbole/model/context_aware_recommender/fm2.py +++ b/recbole/model/context_aware_recommender/fm2.py @@ -5,7 +5,7 @@ # @File : fm2.py r""" -FmFM +FM2 ##################################################### Reference: Sun Y, Pan J, Zhang A, et al. “FM2: Field-matrixed Factorization Machines for Recommender Systems.” in WWW 2021. @@ -16,11 +16,13 @@ from torch.nn.init import xavier_normal_, constant_ from recbole.model.abstract_recommender import ContextRecommender + class FM2(ContextRecommender): """ Field-matrixed Factorization Machines (FmFM, or 𝐹M^2 ), propose a novel approach FmFM to model the interactions of field pairs as a matrix. """ + def __init__(self, config, dataset): super(FM2, self).__init__(config, dataset) @@ -43,7 +45,7 @@ def __init__(self, config, dataset): def _init_weights(self, module): if isinstance(module, nn.Embedding): - xavier_normal_(module.weight.data) + xavier_normal_(module.weight.data) elif isinstance(module, nn.Linear): xavier_normal_(module.weight.data) if module.bias is not None: @@ -53,21 +55,17 @@ def fm2_matrix(self, infeature): """ FmFM interaction terms calculation """ - left_emb = torch.index_select(infeature, 1, self.triu_index[:, 0]) # [batch_size, interact_dim, embed_dim] + left_emb = torch.index_select(infeature, 1, self.triu_index[:, 0]) # [batch_size, interact_dim, embed_dim] right_emb = torch.index_select(infeature, 1, self.triu_index[:, 1]) left_emb = torch.matmul(left_emb.unsqueeze(2), self.weight).squeeze(2) - fm2_output = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) # [batch_size, 1] + fm2_output = (left_emb * right_emb).sum(dim=-1).sum(dim=-1, keepdim=True) # [batch_size, 1] return fm2_output def forward(self, interaction): - fm2_all_embeddings = self.concat_embed_input_fields( - interaction - ) # [batch_size, num_field, embed_dim] + fm2_all_embeddings = self.concat_embed_input_fields(interaction) # [batch_size, num_field, embed_dim] - output = self.first_order_linear(interaction) + self.fm2_matrix( - fm2_all_embeddings - ) + output = self.first_order_linear(interaction) + self.fm2_matrix(fm2_all_embeddings) return output.squeeze(-1) @@ -77,4 +75,4 @@ def calculate_loss(self, interaction): return self.loss(output, label) def predict(self, interaction): - return self.sigmoid(self.forward(interaction)) \ No newline at end of file + return self.sigmoid(self.forward(interaction)) From 0037592a8a64059decf98b9ad6bef4cd9c2a0b64 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Tue, 18 Apr 2023 16:06:58 +0800 Subject: [PATCH 07/12] add --- recbole/model/context_aware_recommender/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/recbole/model/context_aware_recommender/__init__.py b/recbole/model/context_aware_recommender/__init__.py index 5b9ff3b96..bc5cd4e54 100644 --- a/recbole/model/context_aware_recommender/__init__.py +++ b/recbole/model/context_aware_recommender/__init__.py @@ -15,5 +15,4 @@ from recbole.model.context_aware_recommender.widedeep import WideDeep from recbole.model.context_aware_recommender.xdeepfm import xDeepFM from recbole.model.context_aware_recommender.fignn import FiGNN -from recbole.model.context_aware_recommender.kd_dagfm import KD_DAGFM - +from recbole.model.context_aware_recommender.kd_dagfm import KD_DAGFM \ No newline at end of file From 7e0b28b6a0ec552a9195345619bc64a47401529a Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Wed, 19 Apr 2023 21:57:14 +0800 Subject: [PATCH 08/12] add --- docs/source/user_guide/model/context/fm2.rst | 82 ++++++++++++++++++++ docs/source/user_guide/model_intro.rst | 1 + 2 files changed, 83 insertions(+) create mode 100644 docs/source/user_guide/model/context/fm2.rst diff --git a/docs/source/user_guide/model/context/fm2.rst b/docs/source/user_guide/model/context/fm2.rst new file mode 100644 index 000000000..f197e4504 --- /dev/null +++ b/docs/source/user_guide/model/context/fm2.rst @@ -0,0 +1,82 @@ +FM2 +=========== + +Introduction +--------------------- + +`[paper] `_ + +**Title:** FM^2: Field-matrixed Factorization Machines for Recommender Systems + +**Authors:** Yang Sun, Junwei Pan, Alex Zhang, Aaron Flores + +**Abstract:** Click-through rate (CTR) prediction plays a critical role in recom- +mender systems and online advertising. The data used in these +applications are multi-field categorical data, where each feature +belongs to one field. Field information is proved to be important +and there are several works considering fields in their models. In +this paper, we proposed a novel approach to model the field in- +formation effectively and efficiently. The proposed approach is +a direct improvement of FwFM, and is named as Field-matrixed +Factorization Machines (FmFM, or 𝐹 𝑀 2 ). We also proposed a new +explanation of FM and FwFM within the FmFM framework, and +compared it with the FFM. Besides pruning the cross terms, our +model supports field-specific variable dimensions of embedding +vectors, which acts as a soft pruning. We also proposed an efficient +way to minimize the dimension while keeping the model perfor- +mance. The FmFM model can also be optimized further by caching +the intermediate vectors, and it only takes thousands floating-point +operations (FLOPs) to make a prediction. Our experiment results +show that it can out-perform the FFM, which is more complex. The +FmFM model’s performance is also comparable to DNN models +which require much more FLOPs in runtime. + +Running with RecBole +------------------------- + +**Model Hyper-Parameters:** + +- ``embedding_size (int)`` : The embedding size of users, items and entities. Defaults to ``10``. + +**A Running Example:** + +Write the following code to a python file, such as `run.py` + +.. code:: python + + from recbole.quick_start import run_recbole + + run_recbole(model='FM2', dataset='ml-100k') + +And then: + +.. code:: bash + + python run.py + +Tuning Hyper Parameters +------------------------- + +If you want to use ``HyperTuning`` to tune hyper parameters of this model, you can copy the following settings and name it as ``hyper.test``. + +.. code:: bash + + learning_rate choice [0.01,0.005,0.001,0.0005,0.0001] + +Note that we just provide these hyper parameter ranges for reference only, and we can not guarantee that they are the optimal range of this model. + +Then, with the source code of RecBole (you can download it from GitHub), you can run the ``run_hyper.py`` to tuning: + +.. code:: bash + + python run_hyper.py --model=[model_name] --dataset=[dataset_name] --config_files=[config_files_path] --params_file=hyper.test + +For more details about Parameter Tuning, refer to :doc:`../../../user_guide/usage/parameter_tuning`. + + +If you want to change parameters, dataset or evaluation settings, take a look at + +- :doc:`../../../user_guide/config_settings` +- :doc:`../../../user_guide/data_intro` +- :doc:`../../../user_guide/train_eval_intro` +- :doc:`../../../user_guide/usage` \ No newline at end of file diff --git a/docs/source/user_guide/model_intro.rst b/docs/source/user_guide/model_intro.rst index 16968c406..b53a41d87 100644 --- a/docs/source/user_guide/model_intro.rst +++ b/docs/source/user_guide/model_intro.rst @@ -74,6 +74,7 @@ are also support for these models. And evaluation is always conducted in the way model/context/lightgbm model/context/kd_dagfm model/context/fignn + model/context/fm2 Sequential Recommendation From 6c8bf630887624bdb983217d2e0f27e2cd755d91 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Wed, 19 Apr 2023 22:13:38 +0800 Subject: [PATCH 09/12] add --- docs/source/user_guide/model/context/fm2.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/source/user_guide/model/context/fm2.rst b/docs/source/user_guide/model/context/fm2.rst index f197e4504..15b7b694c 100644 --- a/docs/source/user_guide/model/context/fm2.rst +++ b/docs/source/user_guide/model/context/fm2.rst @@ -4,7 +4,7 @@ FM2 Introduction --------------------- -`[paper] `_ +`[paper] `_ **Title:** FM^2: Field-matrixed Factorization Machines for Recommender Systems @@ -31,6 +31,10 @@ show that it can out-perform the FFM, which is more complex. The FmFM model’s performance is also comparable to DNN models which require much more FLOPs in runtime. +.. image:: ../../../asset/fm2.png + :width: 600 + :align: center + Running with RecBole ------------------------- From 5b2ea22dc528c393346c9bfd1bb44ae9eb4e6a8d Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Thu, 20 Apr 2023 12:45:00 +0800 Subject: [PATCH 10/12] add --- docs/source/user_guide/model/context/fm2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/user_guide/model/context/fm2.rst b/docs/source/user_guide/model/context/fm2.rst index 15b7b694c..776693b5c 100644 --- a/docs/source/user_guide/model/context/fm2.rst +++ b/docs/source/user_guide/model/context/fm2.rst @@ -32,7 +32,7 @@ FmFM model’s performance is also comparable to DNN models which require much more FLOPs in runtime. .. image:: ../../../asset/fm2.png - :width: 600 + :width: 500 :align: center Running with RecBole From 5c413b428fdbd1e3c8a37aa191b3a5059081e4aa Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Thu, 20 Apr 2023 12:55:20 +0800 Subject: [PATCH 11/12] add --- docs/source/asset/fm2.png | Bin 0 -> 34971 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/asset/fm2.png diff --git a/docs/source/asset/fm2.png b/docs/source/asset/fm2.png new file mode 100644 index 0000000000000000000000000000000000000000..8e43c9117eba94f46fb1f306d2acb55ec0b5dffa GIT binary patch literal 34971 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 literal 0 HcmV?d00001 From aa5cdb4eb879431300c69443c87e38f203f66023 Mon Sep 17 00:00:00 2001 From: ElaineL610 Date: Thu, 20 Apr 2023 13:01:32 +0800 Subject: [PATCH 12/12] add --- docs/source/index.rst | 2 +- docs/source/user_guide/model_intro.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index bdbcde087..290b360c6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -11,7 +11,7 @@ Introduction RecBole is a unified, comprehensive and efficient framework developed based on PyTorch. It aims to help the researchers to reproduce and develop recommendation models. -In the lastest release, our library includes 86 recommendation algorithms `[Model List]`_, covering four major categories: +In the lastest release, our library includes 87 recommendation algorithms `[Model List]`_, covering four major categories: - General Recommendation - Sequential Recommendation diff --git a/docs/source/user_guide/model_intro.rst b/docs/source/user_guide/model_intro.rst index b53a41d87..7849b3e17 100644 --- a/docs/source/user_guide/model_intro.rst +++ b/docs/source/user_guide/model_intro.rst @@ -1,6 +1,6 @@ Model Introduction ===================== -We implement 86 recommendation models covering general recommendation, sequential recommendation, +We implement 87 recommendation models covering general recommendation, sequential recommendation, context-aware recommendation and knowledge-based recommendation. A brief introduction to these models are as follows: