Repository: RUCAIBox/RecBole (language: python)

Issue:
FIX: Update docs of sequential model

[💡SUG] EasyDict support
Access directory values as attributes, For example

```python
class EasyDict():
    def __init__(self, d):
        for k, v in d.items():
            setattr(self, k, v)

# before
def forward(self, interaction)
    user_ids = interaction['user_ids']

# after
interaction = EasyDict(interaction)
...
def forward(self, interaction)
    user_ids = interaction.user_ids
```

Just one level seems to be ok and the introduction of this feature will help IntelliSense for IDE.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml
index 87f1f3ce1..1cbad9317 100644
--- a/.github/workflows/python-package.yml
+++ b/.github/workflows/python-package.yml
@@ -36,6 +36,9 @@ jobs:
         if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
         
     # Use "python -m pytest" instead of "pytest" to fix imports
+    - name: Test Overall
+      run: |
+        python run_recbole.py --model=BPR --epochs=2
     - name: Test metrics
       run: |
         python -m pytest -v tests/metrics
@@ -52,5 +55,5 @@ jobs:
       run: |
         python -m pytest -v tests/config/test_config.py
         export PYTHONPATH=.
-        python tests/config/test_command_line.py --use_gpu=False --valid_metric=Recall@10 --split_ratio=[0.7,0.2,0.1] --metrics=['Recall@10'] --epochs=200 --eval_setting='LO_RS' --learning_rate=0.3
+        python tests/config/test_command_line.py --use_gpu=False --valid_metric=Recall@10 --split_ratio=[0.7,0.2,0.1] --metrics='["Recall"]' --topk=[10] --epochs=200 --eval_setting='LO_RS' --learning_rate=0.3
 
diff --git a/.gitignore b/.gitignore
index 660977853..f6f7e3498 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 .idea/
 *.pyc
 *.log
+log_tensorboard/*
 saved/
 *.lprof
 *.egg-info/
diff --git a/conda/meta.yaml b/conda/meta.yaml
index de10469f1..9c39b5bfe 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -9,29 +9,29 @@ requirements:
   build:
     - python
   host:
-    - python
+    - python >=3.6
     - numpy >=1.17.2
     - scipy ==1.6.0
     - pandas >=1.0.5
     - tqdm >=4.48.2
     - pyyaml >=5.1.0
-    - matplotlib >=3.1.3
     - scikit-learn >=0.23.2
-    - pytorch
+    - pytorch >=1.7.0
     - colorlog==4.7.2
     - colorama==0.4.4
+    - tensorboard >=2.5.0
   run:
-    - python
+    - python >=3.6
     - numpy >=1.17.2
     - scipy ==1.6.0
     - pandas >=1.0.5
     - tqdm >=4.48.2
     - pyyaml >=5.1.0
-    - matplotlib >=3.1.3
     - scikit-learn >=0.23.2
-    - pytorch
+    - pytorch >=1.7.0
     - colorlog==4.7.2
     - colorama==0.4.4
+    - tensorboard >=2.5.0
 test:
   imports:
     - recbole
diff --git a/docs/source/asset/framework.png b/docs/source/asset/framework.png
new file mode 100644
index 000000000..add0b8028
Binary files /dev/null and b/docs/source/asset/framework.png differ
diff --git a/docs/source/asset/logo.png b/docs/source/asset/logo.png
new file mode 100644
index 000000000..047e61bcf
Binary files /dev/null and b/docs/source/asset/logo.png differ
diff --git a/docs/source/asset/tensorboard_1.png b/docs/source/asset/tensorboard_1.png
new file mode 100644
index 000000000..1a48d6dcd
Binary files /dev/null and b/docs/source/asset/tensorboard_1.png differ
diff --git a/docs/source/asset/tensorboard_2.png b/docs/source/asset/tensorboard_2.png
new file mode 100644
index 000000000..3a8a19e98
Binary files /dev/null and b/docs/source/asset/tensorboard_2.png differ
diff --git a/docs/source/developer_guide/customize_dataloaders.rst b/docs/source/developer_guide/customize_dataloaders.rst
index 6565dcedf..510aced2b 100644
--- a/docs/source/developer_guide/customize_dataloaders.rst
+++ b/docs/source/developer_guide/customize_dataloaders.rst
@@ -1,90 +1,77 @@
 Customize DataLoaders
 ======================
 Here, we present how to develop a new DataLoader, and apply it into our tool. If we have a new model,
-and there is no special requirement for loading the data, then we need to design a new DataLoader.
+and there is special requirement for loading the data, then we need to design a new DataLoader.
 
 
 Abstract DataLoader
 --------------------------
-In this project, there are three abstracts: :class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader`,
-:class:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin`, :class:`~recbole.data.dataloader.neg_sample_mixin.NegSampleByMixin`.
+In this project, there are two abstract dataloaders:
+:class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader`,
+:class:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader`.
 
-In general, the new dataloader should inherit from the above three abstract classes.
-If one only needs to modify existing DataLoader, you can also inherit from the it.
+In general, the new dataloader should inherit from the above two abstract classes.
+If one only needs to modify existing DataLoader, you can also inherit from it.
 The documentation of dataloader: :doc:`../../recbole/recbole.data.dataloader`
 
 
 AbstractDataLoader
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 :class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader` is the most basic abstract class,
-which includes three functions: :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr_end`,
+which includes three important attributes:
+:attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr`,
+:attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.batch_size` and
+:attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.step`.
+The :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr`
+represents the pointer of this dataloader.
+The :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.batch_size`
+represents the upper bound of the number of interactions in one single batch.
+And the :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.step`
+represents the increment of :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.pr` for each batch.
+
+And :class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader` includes four functions to be implemented:
+:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._init_batch_size_and_step`,
+:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr_end`,
 :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._shuffle`
 and :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._next_batch_data`.
+:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._init_batch_size_and_step` is used to
+initialize :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.batch_size` and
+:attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataloader.step`.
 :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr_end` is the max
 :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.pr` plus 1.
-:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._shuffle` is leverage to permute the dataset,
+:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._shuffle` is leveraged to permute the dataset,
 which will be invoked by :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.__iter__`
 if the parameter :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.shuffle` is True.
 :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._next_batch_data` is used to
 load the next batch data, and return the :class:`~recbole.data.interaction.Interaction` format,
 which will be invoked in :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.__next__`.
 
-In :class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader`,
-there are two functions to assist the conversion of :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._next_batch_data`,
-one is :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._dataframe_to_interaction`,
-and the other is :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader._dict_to_interaction`.
-They both use the functions with the same name in :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.dataset`.
-The :class:`pandas.DataFrame` or :class:`dict` is converted into :class:`~recbole.data.interaction.Interaction`.
-
-In addition to the above three functions, two other functions can also be rewrite,
-that is :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.setup`
-and :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.data_preprocess`.
-
-:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.setup` is used to tackle the problems except initializing the parameters.
-For example, reset the :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.batch_size`,
-examine the :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.shuffle` setting.
-All these things can be rewritten in the subclass.
-:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.data_preprocess` is used to process the data,
-e.g., negative sampling.
-
-At the end of :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.__init__`,
-:meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.setup` will be invoked,
-and then if :attr:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.real_time` is ``True``,
-then :meth:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader.data_preprocess` is recalled.
-
-NegSampleMixin
+
+NegSampleDataLoader
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
-:class:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin` inherent from
+:class:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader` inherents from
 :class:`~recbole.data.dataloader.abstract_dataloader.AbstractDataLoader`, which is used for negative sampling.
-It has three additional functions upon its father class:
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin._batch_size_adaptation`,
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin._neg_sampling`
-and :meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.get_pos_len_list`.
-
-Since the positive and negative samples should be framed in the same batch,
-the original batch size can be not appropriate.
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin._batch_size_adaptation` is used to reset the batch size,
-such that the positive and negative samples can be in the same batch.
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin._neg_sampling` is used for negative sampling,
-which should be implemented by the subclass.
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.get_pos_len_list` returns the positive sample number for each user.
-
-In addition, :meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.setup`
-and :meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.data_preprocess` are also changed.
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.setup` will
-call :meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin._batch_size_adaptation`,
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin.data_preprocess` is used for negative sampling
-which should be implemented in the subclass.
-
-NegSampleByMixin
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-:class:`~recbole.data.dataloader.neg_sample_mixin.NegSampleByMixin` inherent
-from :class:`~recbole.data.dataloader.neg_sample_mixin.NegSampleMixin`,
-which is used for negative sampling by ratio.
-It supports two strategies, the first one is ``pair-wise sampling``, the other is ``point-wise sampling``.
-Then based on the parent class, two functions are added:
-:meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleByMixin._neg_sample_by_pair_wise_sampling`
-and :meth:`~recbole.data.dataloader.neg_sample_mixin.NegSampleByMixin._neg_sample_by_point_wise_sampling`.
+It has four additional functions upon its parent class:
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._set_neg_sample_args`,
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sampling`,
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_pair_wise_sampling`,
+and :meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_point_wise_sampling`.
+These four functions don't need to be implemented, they are just auxiliary functions to
+:class:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader`.
+
+In current studies, there have only two sampling strategies,
+the first one is ``pair-wise sampling``, the other is ``point-wise sampling``.
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_pair_wise_sampling`,
+and :meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_point_wise_sampling`
+are implemented according to these two sampling strategies.
+
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._set_neg_sample_args` is used to
+set the negative sampling args like the sampling strategies, sampling functions and so on.
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sampling` is used for negative sampling,
+which will generate negative items and invoke
+:meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_pair_wise_sampling`,
+or :meth:`~recbole.data.dataloader.abstract_dataloader.NegSampleDataLoader._neg_sample_by_point_wise_sampling`
+according to the sampling strategies.
 
 
 Example
@@ -96,29 +83,32 @@ this dataloader returns user id, which is leveraged to train the user representa
 Implement __init__()
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :meth:`__init__` can be used to initialize some of the necessary parameters.
-Here, we just need to record :attr:`uid_field`.
+Here, we just need to record :attr:`uid_field` and generate :attr:`user_list` which contains all user ids.
+And because of some training requirements, :attr:`shuffle` should be set to ``True``.
 
 .. code:: python
 
-    def __init__(self, config, dataset,
-                 batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
-        self.uid_field = dataset.uid_field
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        if shuffle is False:
+            shuffle = True
+            self.logger.warning('UserDataLoader must shuffle the data.')
 
-        super().__init__(config=config, dataset=dataset,
-                         batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+        self.uid_field = dataset.uid_field
+        self.user_list = Interaction({self.uid_field: torch.arange(dataset.user_num)})
 
-Implement setup()
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Because of some training requirement, :attr:`self.shuffle` should be true.
-Then we can check and revise :attr:`self.shuffle` in :meth:`~recbole.data.dataloader.user_dataloader.setup`.
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
 
+Implement _init_batch_size_and_step()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Because :class:`~recbole.data.dataloader.user_dataloader.UserDataLoader` don't need negative sampling,
+so the :attr:`batch_size` and :attr:`step` can be both set to :attr:`self.config['train_batch_size']`.
 
 .. code:: python
 
-    def setup(self):
-        if self.shuffle is False:
-            self.shuffle = True
-            self.logger.warning('UserDataLoader must shuffle the data')
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['train_batch_size']
+        self.step = batch_size
+        self.set_batch_size(batch_size)
 
 Implement pr_end() and _shuffle()
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,24 +118,22 @@ Since this dataloader only returns user id, these function can be implemented re
 
     @property
     def pr_end(self):
-        return len(self.dataset.user_feat)
+        return len(self.user_list)
 
     def _shuffle(self):
-        self.dataset.user_feat = self.dataset.user_feat.sample(frac=1).reset_index(drop=True)
+        self.user_list.shuffle()
 
 Implement _next_batch_data
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-This function only require return user id from :attr:`user_feat`,
-we only have to select one column, and use :meth:`_dataframe_to_interaction` to convert
-:class:`pandas.DataFrame` into :class:`~recbole.data.interaction.Interaction`.
-
+This function only requires to return user id from :attr:`user_list`,
+we just select corresponding slice of :attr:`user_list` and return this slice.
 
 .. code:: python
 
     def _next_batch_data(self):
-        cur_data = self.dataset.user_feat[[self.uid_field]][self.pr: self.pr + self.step]
+        cur_data = self.user_list[self.pr:self.pr + self.step]
         self.pr += self.step
-        return self._dataframe_to_interaction(cur_data)
+        return cur_data
 
 
 Complete Code
@@ -159,43 +147,42 @@ Complete Code
         Args:
             config (Config): The config of dataloader.
             dataset (Dataset): The dataset of dataloader.
-            batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-            dl_format (InputType, optional): The input type of dataloader. Defaults to
-                :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
+            sampler (Sampler): The sampler of dataloader.
             shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
 
         Attributes:
             shuffle (bool): Whether the dataloader will be shuffle after a round.
                 However, in :class:`UserDataLoader`, it's guaranteed to be ``True``.
         """
+
         dl_type = DataLoaderType.ORIGIN
 
-        def __init__(self, config, dataset,
-                     batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
+        def __init__(self, config, dataset, sampler, shuffle=False):
+            if shuffle is False:
+                shuffle = True
+                self.logger.warning('UserDataLoader must shuffle the data.')
+
             self.uid_field = dataset.uid_field
+            self.user_list = Interaction({self.uid_field: torch.arange(dataset.user_num)})
 
-            super().__init__(config=config, dataset=dataset,
-                             batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+            super().__init__(config, dataset, sampler, shuffle=shuffle)
 
-        def setup(self):
-            """Make sure that the :attr:`shuffle` is True. If :attr:`shuffle` is False, it will be changed to True
-            and give a warning to user.
-            """
-            if self.shuffle is False:
-                self.shuffle = True
-                self.logger.warning('UserDataLoader must shuffle the data')
+        def _init_batch_size_and_step(self):
+            batch_size = self.config['train_batch_size']
+            self.step = batch_size
+            self.set_batch_size(batch_size)
 
         @property
         def pr_end(self):
-            return len(self.dataset.user_feat)
+            return len(self.user_list)
 
         def _shuffle(self):
-            self.dataset.user_feat = self.dataset.user_feat.sample(frac=1).reset_index(drop=True)
+            self.user_list.shuffle()
 
         def _next_batch_data(self):
-            cur_data = self.dataset.user_feat[[self.uid_field]][self.pr: self.pr + self.step]
+            cur_data = self.user_list[self.pr:self.pr + self.step]
             self.pr += self.step
-            return self._dataframe_to_interaction(cur_data)
+            return cur_data
 
 
 Other more complex Dataloader development can refer to the source code.
diff --git a/docs/source/developer_guide/customize_metrics.rst b/docs/source/developer_guide/customize_metrics.rst
new file mode 100644
index 000000000..15db8be99
--- /dev/null
+++ b/docs/source/developer_guide/customize_metrics.rst
@@ -0,0 +1,94 @@
+Customize Metrics
+======================
+Here we present how to develop a new metric, and apply it into RecBole.
+Users can implement their customized metrics and combine the metrics with others for personal evaluation.
+
+Here, it only takes three steps to incorporate a new metric and we introduce them step by step.
+
+Create a New Metric Class
+--------------------------
+Then, we create a new class in the file :file:`~recbole.evaluator.metrics` and define the parameter in ``__init__()``:
+
+.. code:: python
+
+    from recbole.evaluator.base_metric import AbstractMetric
+    class MyMetric(AbstractMetric):
+        def __init__(self, config):
+
+Set properties of the metric
+-----------------------------
+After that, we set the properties of metrics:
+
+Set ``metric_need``
+###################
+It is a list that contains one or multiple string that corresponding to needed input of metrics.
+For now, we support 9 inputs for metrics including both recommendation results and information of
+dataset which are listed below.
+
+==================       ========================================================
+ Notation                   Explanation
+==================       ========================================================
+  rec.items                        K recommended items for each user
+  rec.topk                         Boolean matrix indicating the existence of a recommended item in the test set
+                                   and number of positive items for each user
+  rec.meanrank                        Mean ranking of positive items for each user
+  rec.score                        Pure output score
+  data.num_items                      Number of item in dataset
+  data.num_users                      Number of user in dataset
+  data.count_items                    Interaction number of each item in training data
+  data.count_users                    Interaction number of each user in training data
+  data.label                          Pure label field of input data (Usually used with rec.score together)
+==================       ========================================================
+
+Set ``metric_type``
+###################
+It indicates whether the scores required by metric are grouped by user,
+range in ``EvaluatorType.RANKING`` (for grouped ones) and ``EvaluatorType.VALUE`` (for non-grouped ones).
+In current RecBole, all the "grouped" metrics are ranking-based and all the "non-grouped"
+metrics are value-based. To keep with our paper, we adopted the more formal terms: ``RANKING`` and ``VALUE``.
+
+Set ``smaller``
+###############
+It indicates whether the smaller metric value represents better performance, range in
+``True`` and ``False``,  default to ``False``.
+
+Example
+#######
+If we want to add a ranking-based metric named ``YourMetric`` which needs the recommended items and the
+total item number, and the smaller ``YourMetric`` indicates better model performance, the code is shown below:
+
+.. code:: python
+
+    from recbole.evaluator.base_metric import AbstractMetric
+    from recbole.utils import EvaluatorType
+    class MyMetric(AbstractMetric):
+        metric_type = EvaluatorType.RANKING
+        metric_need = ['rec.items', 'data.num_items']
+        smaller = True
+
+        def __init__(self, config):
+
+Implement calculate_metric(self, dataobject)
+---------------------------------------------
+All the computational process is defined in this function. The args is a packaged data object that
+contains all the result above. We can treat it as a dict and get data from it by
+``rec_items = dataobject.get('rec.items')`` . The returned value should be a dict with key of metric name
+and value of final result. Note that the metric name should be lowercase.
+
+Example code:
+
+.. code:: python
+
+    def calculate_metric(self, dataobject):
+        """Get the dictionary of a metric.
+
+        Args:
+            dataobject(DataStruct): it contains all the information needed to calculate metrics.
+
+        Returns:
+            dict: such as ``{'mymetric@10': 3153, 'mymetric@20': 0.3824}``
+        """
+        rec_items = dataobject.get('rec.items')
+        # Add the logic of your metric here.
+
+        return result_dict
diff --git a/docs/source/developer_guide/customize_samplers.rst b/docs/source/developer_guide/customize_samplers.rst
index 3c37797cc..fb94d0eb5 100644
--- a/docs/source/developer_guide/customize_samplers.rst
+++ b/docs/source/developer_guide/customize_samplers.rst
@@ -1,8 +1,22 @@
 Customize Samplers
 ======================
+In RecBole, sampler module is designed to select negative items for training and evaluation.
+
 Here we present how to develop a new sampler, and apply it into RecBole.
 The new sampler is used when we need complex sampling method.
 
+In RecBole, we now only support two kinds of sampling strategies: **random negative sampling (RNS)** and **popularity-biased negative sampling (PNS)**.
+RNS is to select the negative items in uniform distribution, and PNS is to select the negative item in a popularity-biased distribution. 
+For PNS, we set the popularity-biased distribution based on the total number of items' interactions.
+
+In our framework, if you want to create a new sampler, you need to inherit the :class:`~recbole.sampler.sampler.AbstractSampler`, implement
+:meth:`~recbole.sampler.sampler.AbstractSampler.__init__`,
+rewrite three functions: :meth:`~recbole.sampler.sampler.AbstractSampler._uni_sampling`,
+:meth:`~recbole.sampler.sampler.AbstractSampler._get_candidates_list`,
+:meth:`~recbole.sampler.sampler.AbstractSampler.get_used_ids`
+and create a new sampling function.
+
+
 Here, we take the :class:`~recbole.sampler.sampler.KGSampler` as an example.
 
 
@@ -19,7 +33,7 @@ To begin with, we create a new sampler based on :class:`~recbole.sampler.sampler
 
 Implement __init__()
 -----------------------
-Then, we implement :meth:`~recbole.sampler.sampler.KGSampler.__init__()`, in this method, we can flexibly define and initialize the parameters,
+Then, we implement :meth:`~recbole.sampler.sampler.KGSampler.__init__`, in this method, we can flexibly define and initialize the parameters,
 where we only need to invoke :obj:`super.__init__(distribution)`.
 
 .. code:: python
@@ -37,59 +51,67 @@ where we only need to invoke :obj:`super.__init__(distribution)`.
 
         super().__init__(distribution=distribution)
 
+Implement _uni_sampling()
+-------------------------------
+To implement the RNS for KGSampler, we need to rewrite the :meth:`~recbole.sampler.sampler.AbstractSampler._uni_sampling`.
+Here we use the :meth:`numpy.random.randint` to help us randomly select the ``entity_id``. This function will return the
+selected samples' id (here is ``entity_id``).
 
-Implement get_random_list()
-------------------------------
-We do not use the random function in python or numpy due to their lower efficiency.
-Instead, we realize our own :meth:`~recbole.sampler.sampler.AbstractSampler.random` function, where the key method is to combine the random list with the pointer.
-The pointer point to some element in the random list. When one calls :meth:`self.random`, the element is returned, and moves the pointer backward by one element.
-If the pointer point to the last element, then it will return to the head of the element.
+Example code:
+
+.. code:: python
 
-In :class:`~recbole.sampler.sampler.AbstractSampler`, the :meth:`~recbole.sampler.sampler.AbstractSampler.__init__` will call :meth:`~recbole.sampler.sampler.AbstractSampler.get_random_list`, and shuffle the results.
-We only need to return a list including all the elements.
+    def _uni_sampling(self, sample_num):
+        return np.random.randint(1, self.entity_num, sample_num)
 
-It should be noted ``0`` can be the token used for padding, thus one should remain this value.
+Implement _get_candidates_list()
+-------------------------------------
+To implement PNS for KGSampler, we need to rewrite the :meth:`~recbole.sampler.sampler.AbstractSampler._get_candidates_list`.
+This function is used to get a candidate list for PNS, and we will set the sampling distribution based on 
+:obj:`Counter(candidate_list)`. This function will return a list of candidates' id.
 
 Example code:
 
 .. code:: python
 
-    def get_random_list(self):
-        if self.distribution == 'uniform':
-            return list(range(1, self.entity_num))
-        elif self.distribution == 'popularity':
-            return list(self.hid_list) + list(self.tid_list)
-        else:
-            raise NotImplementedError('Distribution [{}] has not been implemented'.format(self.distribution))
+    def _get_candidates_list(self):
+        return list(self.hid_list) + list(self.tid_list)
 
 
 Implement get_used_ids()
 ----------------------------
-For negative sampling, we do not want to sample positive instance, this function is used to compute the positive sample.
-The function will return numpy, and the index is the ID. The return value will be saved in :attr:`self.used_ids`.
+For negative sampling, we do not want to sample positive instance, this function is used to record the positive sample.
+The function will return numpy, and the index is the ID. The returned value will be saved in :attr:`self.used_ids`.
 
 Example code:
 
 .. code:: python
 
     def get_used_ids(self):
-        used_tail_entity_id = np.array([set() for i in range(self.entity_num)])
+       used_tail_entity_id = np.array([set() for _ in range(self.entity_num)])
         for hid, tid in zip(self.hid_list, self.tid_list):
             used_tail_entity_id[hid].add(tid)
+
+        for used_tail_set in used_tail_entity_id:
+            if len(used_tail_set) + 1 == self.entity_num:  # [pad] is a entity.
+                raise ValueError(
+                    'Some head entities have relation with all entities, '
+                    'which we can not sample negative entities for them.'
+                )
         return used_tail_entity_id
 
 
-Implementing the sampling function
+Implement the sampling function
 -----------------------------------
 In :class:`~recbole.sampler.sampler.AbstractSampler`, we have implemented :meth:`~recbole.sampler.sampler.AbstractSampler.sample_by_key_ids` function,
 where we have three parameters: :attr:`key_ids`, :attr:`num` and :attr:`used_ids`.
-:attr:`Key_ids` is the candidate objective ID list, :attr:`num` is the number of samples, :attr:`used_ids` are the positive sample list.
+:attr:`Key_ids` is the candidate objective ID list, :attr:`num` is the number of samples, :attr:`used_ids` is the positive sample list.
 
 In the function, we sample :attr:`num` instances for each element in :attr:`key_ids`. The function finally return :class:`numpy.ndarray`,
 the index of 0, len(key_ids), len(key_ids) * 2, …, len(key_ids) * (num - 1) is the result of key_ids[0].
 The index of 1, len(key_ids) + 1, len(key_ids) * 2 + 1, …, len(key_ids) * (num - 1) + 1 is the result of key_ids[1].
 
-One can also design her own sampler, if the above process is not appropriate.
+One can also design his own sampler, if the above process is not appropriate.
 
 Example code:
 
@@ -109,12 +131,6 @@ Complete Code
 .. code:: python
 
     class KGSampler(AbstractSampler):
-        """:class:`KGSampler` is used to sample negative entities in a knowledge graph.
-
-        Args:
-            dataset (Dataset): The knowledge graph dataset, which contains triplets in a knowledge graph.
-            distribution (str, optional): Distribution of the negative entities. Defaults to 'uniform'.
-        """
         def __init__(self, dataset, distribution='uniform'):
             self.dataset = dataset
 
@@ -128,47 +144,31 @@ Complete Code
 
             super().__init__(distribution=distribution)
 
-        def get_random_list(self):
-            """
-            Returns:
-                np.ndarray or list: Random list of entity_id.
-            """
-            if self.distribution == 'uniform':
-                return list(range(1, self.entity_num))
-            elif self.distribution == 'popularity':
-                return list(self.hid_list) + list(self.tid_list)
-            else:
-                raise NotImplementedError('Distribution [{}] has not been implemented'.format(self.distribution))
+        def _uni_sampling(self, sample_num):
+            return np.random.randint(1, self.entity_num, sample_num)
+
+        def _get_candidates_list(self):
+            return list(self.hid_list) + list(self.tid_list)
 
         def get_used_ids(self):
-            """
-            Returns:
-                np.ndarray: Used entity_ids is the same as tail_entity_ids in knowledge graph.
-                Index is head_entity_id, and element is a set of tail_entity_ids.
-            """
-            used_tail_entity_id = np.array([set() for i in range(self.entity_num)])
+            used_tail_entity_id = np.array([set() for _ in range(self.entity_num)])
             for hid, tid in zip(self.hid_list, self.tid_list):
                 used_tail_entity_id[hid].add(tid)
+
+            for used_tail_set in used_tail_entity_id:
+                if len(used_tail_set) + 1 == self.entity_num:  # [pad] is a entity.
+                    raise ValueError(
+                        'Some head entities have relation with all entities, '
+                        'which we can not sample negative entities for them.'
+                    )
             return used_tail_entity_id
 
         def sample_by_entity_ids(self, head_entity_ids, num=1):
-            """Sampling by head_entity_ids.
-
-            Args:
-                head_entity_ids (np.ndarray or list): Input head_entity_ids.
-                num (int, optional): Number of sampled entity_ids for each head_entity_id. Defaults to ``1``.
-
-            Returns:
-                np.ndarray: Sampled entity_ids.
-                entity_ids[0], entity_ids[len(head_entity_ids)], entity_ids[len(head_entity_ids) * 2], ...,
-                entity_id[len(head_entity_ids) * (num - 1)] is sampled for head_entity_ids[0];
-                entity_ids[1], entity_ids[len(head_entity_ids) + 1], entity_ids[len(head_entity_ids) * 2 + 1], ...,
-                entity_id[len(head_entity_ids) * (num - 1) + 1] is sampled for head_entity_ids[1]; ...; and so on.
-            """
             try:
-                return self.sample_by_key_ids(head_entity_ids, num, self.used_ids[head_entity_ids])
+                return self.sample_by_key_ids(head_entity_ids, num)
             except IndexError:
                 for head_entity_id in head_entity_ids:
                     if head_entity_id not in self.head_entities:
-                        raise ValueError('head_entity_id [{}] not exist'.format(head_entity_id))
+                        raise ValueError(f'head_entity_id [{head_entity_id}] not exist.')
+
 
diff --git a/docs/source/developer_guide/customize_trainers.rst b/docs/source/developer_guide/customize_trainers.rst
index fbd6df60e..108e4054c 100644
--- a/docs/source/developer_guide/customize_trainers.rst
+++ b/docs/source/developer_guide/customize_trainers.rst
@@ -8,11 +8,11 @@ The function used to train the model is :meth:`fit`, it will call :meth:`_train_
 
 The function used to evaluate the model is :meth:`evaluate`, it will call :meth:`_valid_epoch` to evaluate the model.
 
-If the developed model need more complex training method,
+If the developed model needs more complex training method,
 then one can inherent the :class:`~recbole.trainer.trainer.Trainer`,
 and revise :meth:`~recbole.trainer.trainer.Trainer.fit` or :meth:`~recbole.trainer.trainer.Trainer._train_epoch`.
 
-If the developed model need more complex evaluation method,
+If the developed model needs more complex evaluation method,
 then one can inherent the :class:`~recbole.trainer.trainer.Trainer`,
 and revise :meth:`~recbole.trainer.trainer.Trainer.evaluate` or :meth:`~recbole.trainer.trainer.Trainer._valid_epoch`.
 
diff --git a/docs/source/get_started/install.rst b/docs/source/get_started/install.rst
index b798defcc..f2a8bcdeb 100644
--- a/docs/source/get_started/install.rst
+++ b/docs/source/get_started/install.rst
@@ -11,7 +11,7 @@ RecBole is compatible with the following operating systems:
 * Windows 10
 * macOS X
 
-Python 3.6 (or later), torch 1.6.0 (or later) are required to install our library. If you want to use RecBole with GPU,
+Python 3.6 (or later), torch 1.7.0 (or later) are required to install our library. If you want to use RecBole with GPU,
 please ensure that CUDA or CUDAToolkit version is 9.2 or later.
 This requires NVIDIA driver version >= 396.26 (for Linux) or >= 397.44 (for Windows10).
 
@@ -54,3 +54,62 @@ Run the following command to install:
 .. code:: bash
 
     pip install -e . --verbose
+
+Try to run：
+-------------------------
+To check if you have successfully installed the RecBole, you can create a new python file (e.g., `run.py`),
+and write the following code:
+
+.. code:: python
+
+    from recbole.quick_start import run_recbole
+
+    run_recbole(model='BPR', dataset='ml-100k')
+
+
+Then run the following command:
+
+.. code:: bash
+
+    python run.py
+
+This will perform the training and test of the BPR model on the ml-100k dataset, and you will obtain some output like:
+
+.. code:: none
+
+    05 Aug 02:16    INFO  ml-100k
+    The number of users: 944
+    Average actions of users: 106.04453870625663
+    The number of items: 1683
+    Average actions of items: 59.45303210463734
+    The number of inters: 100000
+    The sparsity of the dataset: 93.70575143257098%
+    Remain Fields: ['user_id', 'item_id', 'rating', 'timestamp']
+    05 Aug 02:16    INFO  [Training]: train_batch_size = [2048] negative sampling: [{'uniform': 1}]
+    05 Aug 02:16    INFO  [Evaluation]: eval_batch_size = [4096] eval_args: [{'split': {'RS': [0.8, 0.1, 0.1]}, 'group_by': 'user', 'order': 'RO', 'mode': 'full'}]
+    05 Aug 02:16    INFO  BPR(
+    (user_embedding): Embedding(944, 64)
+    (item_embedding): Embedding(1683, 64)
+    (loss): BPRLoss()
+    )
+    Trainable parameters: 168128
+    Train     0: 100%|████████████████████████| 40/40 [00:00<00:00, 219.54it/s, GPU RAM: 0.01 G/11.91 G]
+    05 Aug 02:16    INFO  epoch 0 training [time: 0.19s, train loss: 27.7228]
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 506.11it/s, GPU RAM: 0.01 G/11.91 G]
+    05 Aug 02:16    INFO  epoch 0 evaluating [time: 0.94s, valid_score: 0.020500]
+    05 Aug 02:16    INFO  valid result: 
+    recall@10 : 0.0067    mrr@10 : 0.0205    ndcg@10 : 0.0086    hit@10 : 0.0732    precision@10 : 0.0081    
+
+    ...
+
+    Train    96: 100%|████████████████████████| 40/40 [00:00<00:00, 230.65it/s, GPU RAM: 0.01 G/11.91 G]
+    05 Aug 02:19    INFO  epoch 96 training [time: 0.18s, train loss: 3.7170]
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 800.46it/s, GPU RAM: 0.01 G/11.91 G]
+    05 Aug 02:19    INFO  epoch 96 evaluating [time: 0.60s, valid_score: 0.375200]
+    05 Aug 02:19    INFO  valid result: 
+    recall@10 : 0.2162    mrr@10 : 0.3752    ndcg@10 : 0.2284    hit@10 : 0.7508    precision@10 : 0.1602    
+    05 Aug 02:19    INFO  Finished training, best eval result in epoch 85
+    05 Aug 02:19    INFO  Loading model structure and parameters from saved/BPR-Aug-05-2021_02-17-51.pth
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 832.85it/s, GPU RAM: 0.01 G/11.91 G]
+    05 Aug 02:19    INFO  best valid : {'recall@10': 0.2195, 'mrr@10': 0.3871, 'ndcg@10': 0.2344, 'hit@10': 0.7582, 'precision@10': 0.1627}
+    05 Aug 02:19    INFO  test result: {'recall@10': 0.2523, 'mrr@10': 0.4855, 'ndcg@10': 0.292, 'hit@10': 0.7953, 'precision@10': 0.1962}
\ No newline at end of file
diff --git a/docs/source/get_started/introduction.rst b/docs/source/get_started/introduction.rst
deleted file mode 100644
index 406fa98b7..000000000
--- a/docs/source/get_started/introduction.rst
+++ /dev/null
@@ -1,31 +0,0 @@
-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 first release, our library includes 65 recommendation algorithms `[Model List]`_, covering four major categories:
-
-- General Recommendation
-- Sequential Recommendation
-- Context-aware Recommendation
-- Knowledge-based Recommendation
-
-We design a unified and flexible data file format, and provide the support for 28 benchmark recommendation datasets `[Collected Datasets]`_. A user can apply the provided script to process the original data copy, or simply download the processed datasets by our team.
-
-Features:
-
-- General and extensible data structure
-    We deign general and extensible data structures to unify the formatting and usage of various recommendation datasets.
-- Comprehensive benchmark models and datasets
-    We implement 65 commonly used recommendation algorithms, and provide the formatted copies of 28 recommendation datasets.
-- Efficient GPU-accelerated execution
-    We design many tailored strategies in the GPU environment to enhance the efficiency of our library.
-- Extensive and standard evaluation protocols
-    We support a series of commonly used evaluation protocols or settings for testing and comparing recommendation algorithms.
-
-.. _[Collected Datasets]:
-    /dataset_list.html
-
-.. _[Model List]:
-    /model_list.html
diff --git a/docs/source/get_started/quick_start.rst b/docs/source/get_started/quick_start.rst
index 9a97a8a15..07075af72 100644
--- a/docs/source/get_started/quick_start.rst
+++ b/docs/source/get_started/quick_start.rst
@@ -1,112 +1,183 @@
 Quick Start
 ===============
-Here is a quick-start example for using RecBole.
+Here is a quick-start example for using RecBole. We will show you how to train and test **BPR** model on the **ml-100k** dataset from both **API**
+and **source code**.
 
-Quick-start From Source
+
+Quick-start From API
 --------------------------
-With the source code of `RecBole <https://github.com/RUCAIBox/RecBole>`_,
-the following script can be used to run a toy example of our library.
 
-.. code:: bash
+1. Prepare your data:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Before running a model, firstly you need to prepare and load data. To help users quickly get start, 
+RecBole has a build-in dataset **ml-100k** and you can directly use it. However, if you want to use other datasets, you can read
+:doc:`../usage/running_new_dataset` for more information.
 
-    python run_recbole.py
+Then, you need to set data config for data loading. You can create a `yaml` file called `test.yaml` and write the following settings:
 
-This script will run the BPR model on the ml-100k dataset.
+.. code:: yaml
 
-Typically, this example takes less than one minute. We will obtain some output like:
+    # dataset config
+    USER_ID_FIELD: user_id
+    ITEM_ID_FIELD: item_id
+    load_col:
+        inter: [user_id, item_id]
 
-.. code:: none
+For more details of data config, please refer to :doc:`../user_guide/config/data_settings`.
 
-    INFO ml-100k
-    The number of users: 944
-    Average actions of users: 106.04453870625663
-    The number of items: 1683
-    Average actions of items: 59.45303210463734
-    The number of inters: 100000
-    The sparsity of the dataset: 93.70575143257098%
+2. Choose a model:
+>>>>>>>>>>>>>>>>>>>>>>>>>
+In RecBole, we implement 73 recommendation models covering general recommendation, sequential recommendation,
+context-aware recommendation and knowledge-based recommendation. You can choose a model from our :doc:`../user_guide/model_intro`.
+Here we choose BPR model to train and test. 
 
-    INFO Evaluation Settings:
-    Group by user_id
-    Ordering: {'strategy': 'shuffle'}
-    Splitting: {'strategy': 'by_ratio', 'ratios': [0.8, 0.1, 0.1]}
-    Negative Sampling: {'strategy': 'full', 'distribution': 'uniform'}
+Then, you need to set the parameter for BPR model. You can check the :doc:`../user_guide/model/general/bpr` and add the model settings into the `test.yaml`, like:
 
-    INFO BPRMF(
-        (user_embedding): Embedding(944, 64)
-        (item_embedding): Embedding(1683, 64)
-        (loss): BPRLoss()
-    )
-    Trainable parameters: 168128
+.. code:: yaml
 
-    INFO epoch 0 training [time: 0.27s, train loss: 27.7231]
-    INFO epoch 0 evaluating [time: 0.12s, valid_score: 0.021900]
-    INFO valid result:
-    recall@10: 0.0073  mrr@10: 0.0219  ndcg@10: 0.0093  hit@10: 0.0795  precision@10: 0.0088
+    # model config
+    embedding_size: 64
 
-    ...
+If you want to run different models, you can read :doc:`../user_guide/usage/running_different_models` for more information.
 
-    INFO epoch 63 training [time: 0.19s, train loss: 4.7660]
-    INFO epoch 63 evaluating [time: 0.08s, valid_score: 0.394500]
-    INFO valid result:
-    recall@10: 0.2156  mrr@10: 0.3945  ndcg@10: 0.2332  hit@10: 0.7593  precision@10: 0.1591
+3. Set training and evaluation config:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+In RecBole, we support multiple training and evaluation methods. You can choose how to train and test model by simply setting the config.
 
-    INFO Finished training, best eval result in epoch 52
-    INFO Loading model structure and parameters from saved/***.pth
-    INFO best valid result:
-    recall@10: 0.2169  mrr@10: 0.4005  ndcg@10: 0.235  hit@10: 0.7582  precision@10: 0.1598
-    INFO test result:
-    recall@10: 0.2368  mrr@10: 0.4519  ndcg@10: 0.2768  hit@10: 0.7614  precision@10: 0.1901
+Here we want to train and test the BPR model in training-validation-test method (optimize model parameters on the training set, do parameter selection according to the results on the validation set,
+and finally report the results on the test set) and evaluate the model performance by full ranking with all item candidates, 
+so we can add the following settings into the `test.yaml`.
 
-Note that using the quick start pipeline we provide, the original dataset will be divided into training set, validation set and test set by default.
-We optimize model parameters on the training set, do parameter selection according to the results on the validation set,
-and finally report the results on the test set.
+.. code:: yaml
 
-If you want to change the parameters, such as ``learning_rate``, ``embedding_size``,
-just set the additional command parameters as you need:
+    # Training and evaluation config
+    epochs: 500
+    train_batch_size: 4096
+    eval_batch_size: 4096
+    neg_sampling:
+        uniform: 1
+    eval_args:
+        group_by: user
+        order: RO
+        split: {'RS': [0.8,0.1,0.1]}
+        mode: full
+    metrics: ['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']
+    topk: 10 
+    valid_metric: MRR@10
+    metric_decimal_place: 4
 
-.. code:: bash
+For more details of training and evaluation config, please refer to :doc:`../user_guide/config/training_settings` and :doc:`../user_guide/config/evaluation_settings`.
 
-    python run_recbole.py --learning_rate=0.0001 --embedding_size=128
+4. Run the model and collect the result
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+Now you have finished all the preparations, it's time to run the model!
 
+You can create a new python file (e.g., `run.py`), and write the following code:
 
-If you want to change the models, just run the script by setting additional command parameters:
+.. code:: python
 
-.. code:: bash
+    from recbole.quick_start import run_recbole
 
-    python run_recbole.py --model=[model_name]
+    run_recbole(model='BPR', dataset='ml-100k')
 
-``model_name`` indicates the model to be initialized.
-RecBole has implemented four categories of recommendation algorithms
-including general recommendation, context-aware recommendation,
-sequential recommendation and knowledge-based recommendation.
-More details can be found in :doc:`../user_guide/model_intro`.
 
+Then run the following command:
 
-The datasets can be changed according to :doc:`../user_guide/data_intro`.
+.. code:: bash
 
+    python run.py --config_files=test.yaml
 
-Quick-start From API
--------------------------
-If RecBole is installed from ``pip`` or ``conda``, you can create a new python file (e.g., `run.py`),
-and write the following code:
+And you will obtain the output like:
 
-.. code:: python
+.. code:: none
 
-    from recbole.quick_start import run_recbole
+    24 Aug 01:46    INFO  ml-100k
+    The number of users: 944
+    Average actions of users: 106.04453870625663
+    The number of items: 1683
+    Average actions of items: 59.45303210463734
+    The number of inters: 100000
+    The sparsity of the dataset: 93.70575143257098%
+    Remain Fields: ['user_id', 'item_id', 'rating', 'timestamp']
+    24 Aug 01:46    INFO  [Training]: train_batch_size = [2048] negative sampling: [{'uniform': 1}]
+    24 Aug 01:46    INFO  [Evaluation]: eval_batch_size = [4096] eval_args: [{'split': {'RS': [0.8, 0.1, 0.1]}, 'group_by': 'user', 'order': 'RO', 'mode': 'full'}]
+    24 Aug 01:46    INFO  BPR(
+    (user_embedding): Embedding(944, 64)
+    (item_embedding): Embedding(1683, 64)
+    (loss): BPRLoss()
+    )
+    Trainable parameters: 168128
+    Train     0: 100%|████████████████████████| 40/40 [00:00<00:00, 200.47it/s, GPU RAM: 0.01 G/11.91 G]
+    24 Aug 01:46    INFO  epoch 0 training [time: 0.21s, train loss: 27.7228]
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 518.65it/s, GPU RAM: 0.01 G/11.91 G]
+    24 Aug 01:46    INFO  epoch 0 evaluating [time: 0.92s, valid_score: 0.020500]
+    ......
+    Train    96: 100%|████████████████████████| 40/40 [00:00<00:00, 229.26it/s, GPU RAM: 0.01 G/11.91 G]
+    24 Aug 01:47    INFO  epoch 96 training [time: 0.18s, train loss: 3.7170]
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 857.00it/s, GPU RAM: 0.01 G/11.91 G]
+    24 Aug 01:47    INFO  epoch 96 evaluating [time: 0.56s, valid_score: 0.375200]
+    24 Aug 01:47    INFO  valid result: 
+    recall@10 : 0.2162    mrr@10 : 0.3752    ndcg@10 : 0.2284    hit@10 : 0.7508    precision@10 : 0.1602    
+    24 Aug 01:47    INFO  Finished training, best eval result in epoch 85
+    24 Aug 01:47    INFO  Loading model structure and parameters from saved/BPR-Aug-24-2021_01-46-43.pth
+    Evaluate   : 100%|██████████████████████| 472/472 [00:00<00:00, 866.53it/s, GPU RAM: 0.01 G/11.91 G]
+    24 Aug 01:47    INFO  best valid : {'recall@10': 0.2195, 'mrr@10': 0.3871, 'ndcg@10': 0.2344, 'hit@10': 0.7582, 'precision@10': 0.1627}
+    24 Aug 01:47    INFO  test result: {'recall@10': 0.2523, 'mrr@10': 0.4855, 'ndcg@10': 0.292, 'hit@10': 0.7953, 'precision@10': 0.1962}
+
+Finally you will get the model's performance on the test set and the model file will be saved under the `/saved`. Besides, 
+RecBole allows tracking and visualizing train loss and valid score with TensorBoard, please read the :doc:`../user_guide/usage/use_tensorboard` for more details.
+
+The above is the whole process of running a model in RecBole, and you can read other docs for depth usage. 
 
-    run_recbole()
 
+Quick-start From Source
+--------------------------
+Besides using API, you can also directly run the source code of `RecBole <https://github.com/RUCAIBox/RecBole>`_. 
+The whole process is similar to Quick-start From API. 
+You can create a `yaml` file called `test.yaml` and set all the config as follow:
+
+.. code:: yaml
+
+    # dataset config 
+    USER_ID_FIELD: user_id
+    ITEM_ID_FIELD: item_id
+    load_col:
+        inter: [user_id, item_id]
+    
+    # model config
+    embedding_size: 64
+
+    # Training and evaluation config
+    epochs: 500
+    train_batch_size: 4096
+    eval_batch_size: 4096
+    neg_sampling:
+        uniform: 1
+    eval_args:
+        group_by: user
+        order: RO
+        split: {'RS': [0.8,0.1,0.1]}
+        mode: full
+    metrics: ['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']
+    topk: 10 
+    valid_metric: MRR@10
+    metric_decimal_place: 4
 
 Then run the following command:
 
 .. code:: bash
 
-    python run.py --dataset=ml-100k --model=BPR
+    python run_recbole.py --model=BPR --dataset=ml-100k --config_files=test.yaml
+
+And you will get the output of running the BPR model on the ml-100k dataset.
+
+If you want to change the parameters, such as ``embedding_size``,
+just set the additional command parameters as you need:
+
+.. code:: bash
 
-This will perform the training and test of the BPR model on the ml-100k dataset.
+    python run_recbole.py --model=BPR --dataset=ml-100k --config_files=test.yaml --embedding_size=0.0001 
 
-One can also use similar methods as mentioned above to run different models, parameters or datasets,
-the operations are same with `Quick-start From Source`_.
 
 
 In-depth Usage
@@ -116,5 +187,5 @@ For a more in-depth usage about RecBole, take a look at
 - :doc:`../user_guide/config_settings`
 - :doc:`../user_guide/data_intro`
 - :doc:`../user_guide/model_intro`
-- :doc:`../user_guide/evaluation_support`
+- :doc:`../user_guide/train_eval_intro`
 - :doc:`../user_guide/usage`
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 96c20bbe7..851b8a8cb 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,15 +1,51 @@
 .. RecBole documentation master file.
+.. title:: RecBole v1.0.0
+.. image:: asset/logo.png
 
-RecBole v0.2.0
 =========================================================
 
 `HomePage <https://recbole.io/>`_ | `Docs <https://recbole.io/docs/>`_ | `GitHub <https://github.com/RUCAIBox/RecBole>`_ | `Datasets <https://github.com/RUCAIBox/RecDatasets>`_ | `v0.1.2 </docs/v0.1.2/>`_
 
+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 73 recommendation algorithms `[Model List]`_, covering four major categories:
+
+- General Recommendation
+- Sequential Recommendation
+- Context-aware Recommendation
+- Knowledge-based Recommendation
+
+We design a unified and flexible data file format, and provide the support for 28 benchmark recommendation datasets `[Collected Datasets]`_. A user can apply the provided script to process the original data copy, or simply download the processed datasets by our team.
+
+.. image:: asset/framework.png
+    :width: 600
+    :align: center
+
+Features:
+
+- General and extensible data structure
+    We deign general and extensible data structures to unify the formatting and usage of various recommendation datasets.
+- Comprehensive benchmark models and datasets
+    We implement 73 commonly used recommendation algorithms, and provide the formatted copies of 28 recommendation datasets.
+- Efficient GPU-accelerated execution
+    We design many tailored strategies in the GPU environment to enhance the efficiency of our library.
+- Extensive and standard evaluation protocols
+    We support a series of commonly used evaluation protocols or settings for testing and comparing recommendation algorithms.
+
+.. _[Collected Datasets]:
+    /dataset_list.html
+
+.. _[Model List]:
+    /model_list.html
+
+
 .. toctree::
    :maxdepth: 1
    :caption: Get Started
 
-   get_started/introduction
    get_started/install
    get_started/quick_start
 
@@ -20,7 +56,7 @@ RecBole v0.2.0
    user_guide/config_settings
    user_guide/data_intro
    user_guide/model_intro
-   user_guide/evaluation_support
+   user_guide/train_eval_intro
    user_guide/usage
 
 
@@ -32,13 +68,14 @@ RecBole v0.2.0
    developer_guide/customize_trainers
    developer_guide/customize_dataloaders
    developer_guide/customize_samplers
+   developer_guide/customize_metrics
 
 
 .. toctree::
    :maxdepth: 1
    :caption: API REFERENCE:
 
-   recbole/recbole.config
+   recbole/recbole.config.configurator
    recbole/recbole.data
    recbole/recbole.evaluator
    recbole/recbole.model
@@ -51,9 +88,19 @@ RecBole v0.2.0
    recbole/recbole.utils.logger
    recbole/recbole.utils.utils
 
+The Team
+------------------
+RecBole is developed and maintained by `RUC, BUPT, ECNU  <https://www.recbole.io/about.html>`_.
+
+Here is the list of our lead developers in each development phase. They are the souls of RecBole and have made outstanding contributions.
 
-Indices and tables
-==================
+======================   ===============   =============================================
+Time                     Version 	        Lead Developers
+======================   ===============   =============================================
+June 2020 ~ Nov. 2020    v0.1.1            `Shanlei Mu <https://github.com/ShanleiMu>`_, `Yupeng Hou <https://github.com/@hyp1231>`_, `Zihan Lin <https://github.com/linzihan-backforward>`_, `Kaiyuan Li <https://github.com/tsotfsk>`_
+Nov. 2020 ~ Now          v0.1.2 ~ v1.0.0   `Yushuo Chen <https://github.com/https://github.com/chenyushuo>`_, `Xingyu Pan <https://github.com/2017pxy>`_
+======================   ===============   =============================================
 
-* :ref:`genindex`
-* :ref:`search`
+License
+------------
+RecBole uses `MIT License <https://github.com/RUCAIBox/RecBole/blob/master/LICENSE>`_.
\ No newline at end of file
diff --git a/docs/source/recbole/recbole.config.rst b/docs/source/recbole/recbole.config.rst
deleted file mode 100644
index 1b58676fc..000000000
--- a/docs/source/recbole/recbole.config.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-recbole.config
-======================
-
-.. toctree::
-   :maxdepth: 4
-
-   recbole.config.configurator
-   recbole.config.eval_setting
diff --git a/docs/source/recbole/recbole.data.dataloader.context_dataloader.rst b/docs/source/recbole/recbole.data.dataloader.context_dataloader.rst
deleted file mode 100644
index f46d5ee0c..000000000
--- a/docs/source/recbole/recbole.data.dataloader.context_dataloader.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-.. automodule:: recbole.data.dataloader.context_dataloader
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/docs/source/recbole/recbole.data.dataloader.neg_sample_mixin.rst b/docs/source/recbole/recbole.data.dataloader.neg_sample_mixin.rst
deleted file mode 100644
index 67fdd0e93..000000000
--- a/docs/source/recbole/recbole.data.dataloader.neg_sample_mixin.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-.. automodule:: recbole.data.dataloader.neg_sample_mixin
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/docs/source/recbole/recbole.data.dataloader.rst b/docs/source/recbole/recbole.data.dataloader.rst
index 1dc37ef3d..5db4daf65 100644
--- a/docs/source/recbole/recbole.data.dataloader.rst
+++ b/docs/source/recbole/recbole.data.dataloader.rst
@@ -5,9 +5,6 @@ recbole.data.dataloader
    :maxdepth: 4
 
    recbole.data.dataloader.abstract_dataloader
-   recbole.data.dataloader.context_dataloader
    recbole.data.dataloader.general_dataloader
    recbole.data.dataloader.knowledge_dataloader
-   recbole.data.dataloader.neg_sample_mixin
-   recbole.data.dataloader.sequential_dataloader
    recbole.data.dataloader.user_dataloader
diff --git a/docs/source/recbole/recbole.data.dataloader.sequential_dataloader.rst b/docs/source/recbole/recbole.data.dataloader.sequential_dataloader.rst
deleted file mode 100644
index 94ab388e9..000000000
--- a/docs/source/recbole/recbole.data.dataloader.sequential_dataloader.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-.. automodule:: recbole.data.dataloader.sequential_dataloader
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/docs/source/recbole/recbole.data.dataset.rst b/docs/source/recbole/recbole.data.dataset.rst
index 64d432fae..58a17e800 100644
--- a/docs/source/recbole/recbole.data.dataset.rst
+++ b/docs/source/recbole/recbole.data.dataset.rst
@@ -9,4 +9,3 @@ recbole.data.dataset
    recbole.data.dataset.kg_dataset
    recbole.data.dataset.kg_seq_dataset
    recbole.data.dataset.sequential_dataset
-   recbole.data.dataset.social_dataset
diff --git a/docs/source/recbole/recbole.evaluator.abstract_evaluator.rst b/docs/source/recbole/recbole.evaluator.abstract_evaluator.rst
deleted file mode 100644
index 66de59e49..000000000
--- a/docs/source/recbole/recbole.evaluator.abstract_evaluator.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-.. automodule:: recbole.evaluator.abstract_evaluator
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/docs/source/recbole/recbole.evaluator.proxy_evaluator.rst b/docs/source/recbole/recbole.evaluator.base_metric.rst
similarity index 51%
rename from docs/source/recbole/recbole.evaluator.proxy_evaluator.rst
rename to docs/source/recbole/recbole.evaluator.base_metric.rst
index c4689d43a..323aacf1b 100644
--- a/docs/source/recbole/recbole.evaluator.proxy_evaluator.rst
+++ b/docs/source/recbole/recbole.evaluator.base_metric.rst
@@ -1,4 +1,4 @@
-.. automodule:: recbole.evaluator.proxy_evaluator
+.. automodule:: recbole.evaluator.base_metric
    :members:
    :undoc-members:
    :show-inheritance:
diff --git a/docs/source/recbole/recbole.config.eval_setting.rst b/docs/source/recbole/recbole.evaluator.collector.rst
similarity index 55%
rename from docs/source/recbole/recbole.config.eval_setting.rst
rename to docs/source/recbole/recbole.evaluator.collector.rst
index cd78d6dca..b67ab72fc 100644
--- a/docs/source/recbole/recbole.config.eval_setting.rst
+++ b/docs/source/recbole/recbole.evaluator.collector.rst
@@ -1,4 +1,4 @@
-.. automodule:: recbole.config.eval_setting
+.. automodule:: recbole.evaluator.collector
    :members:
    :undoc-members:
    :show-inheritance:
diff --git a/docs/source/recbole/recbole.evaluator.evaluators.rst b/docs/source/recbole/recbole.evaluator.evaluator.rst
similarity index 54%
rename from docs/source/recbole/recbole.evaluator.evaluators.rst
rename to docs/source/recbole/recbole.evaluator.evaluator.rst
index 8aeca9804..39c00e545 100644
--- a/docs/source/recbole/recbole.evaluator.evaluators.rst
+++ b/docs/source/recbole/recbole.evaluator.evaluator.rst
@@ -1,4 +1,4 @@
-.. automodule:: recbole.evaluator.evaluators
+.. automodule:: recbole.evaluator.evaluator
    :members:
    :undoc-members:
    :show-inheritance:
diff --git a/docs/source/recbole/recbole.data.dataset.social_dataset.rst b/docs/source/recbole/recbole.evaluator.register.rst
similarity index 50%
rename from docs/source/recbole/recbole.data.dataset.social_dataset.rst
rename to docs/source/recbole/recbole.evaluator.register.rst
index 47db01c07..6c642d099 100644
--- a/docs/source/recbole/recbole.data.dataset.social_dataset.rst
+++ b/docs/source/recbole/recbole.evaluator.register.rst
@@ -1,4 +1,4 @@
-.. automodule:: recbole.data.dataset.social_dataset
+.. automodule:: recbole.evaluator.register
    :members:
    :undoc-members:
    :show-inheritance:
diff --git a/docs/source/recbole/recbole.evaluator.rst b/docs/source/recbole/recbole.evaluator.rst
index 0f3c99793..49f09b114 100644
--- a/docs/source/recbole/recbole.evaluator.rst
+++ b/docs/source/recbole/recbole.evaluator.rst
@@ -4,8 +4,9 @@ recbole.evaluator
 .. toctree::
    :maxdepth: 4
 
-   recbole.evaluator.abstract_evaluator
-   recbole.evaluator.evaluators
+   recbole.evaluator.base_metric
+   recbole.evaluator.collector
+   recbole.evaluator.evaluator
    recbole.evaluator.metrics
-   recbole.evaluator.proxy_evaluator
+   recbole.evaluator.register
    recbole.evaluator.utils
diff --git a/docs/source/user_guide/data/data_args.rst b/docs/source/user_guide/config/data_settings.rst
similarity index 70%
rename from docs/source/user_guide/data/data_args.rst
rename to docs/source/user_guide/config/data_settings.rst
index 497eb65e6..b8e10cf2a 100644
--- a/docs/source/user_guide/data/data_args.rst
+++ b/docs/source/user_guide/config/data_settings.rst
@@ -1,4 +1,4 @@
-Args for Data
+Data settings
 =========================
 
 RecBole provides several arguments for describing:
@@ -24,7 +24,7 @@ Common Features
 - ``ITEM_ID_FIELD (str)`` : Field name of item ID feature. Defaults to ``item_id``.
 - ``RATING_FIELD (str)`` : Field name of rating feature. Defaults to ``rating``.
 - ``TIME_FIELD (str)`` : Field name of timestamp feature. Defaults to ``timestamp``.
-- ``seq_len (dict)`` : Keys are field names of sequence features, values are maximum length of each sequence (which means sequences too long will be cut off). If not set, the sequences will not be cut off. Defaults to ``None``.
+- ``seq_len (dict)`` : Keys are field names of sequence features, values are maximum length of each sequence (which means too long sequences will be cut off). If not set, the sequences will not be cut off. Defaults to ``None``.
 
 Label for Point-wise DataLoader
 '''''''''''''''''''''''''''''''''''
@@ -58,7 +58,7 @@ Selectively Loading
 
 - ``load_col (dict)`` : Keys are the suffix of loaded atomic files, values are the list of field names to be loaded. If a suffix doesn't exist in ``load_col``, the corresponding atomic file will not be loaded. Note that if ``load_col`` is ``None``, then all the existed atomic files will be loaded. Defaults to ``{inter: [user_id, item_id]}``.
 - ``unload_col (dict)`` : Keys are suffix of loaded atomic files, values are list of field names NOT to be loaded. Note that ``load_col`` and ``unload_col`` can not be set at the same time. Defaults to ``None``.
-- ``unused_col (dict)`` : Keys are suffix of loaded atomic files, values are list of field names which is loaded for data processing but will not used in model. E.g. the ``time_field`` may used for time ordering but model does not use this field. Defaults to ``None``.
+- ``unused_col (dict)`` : Keys are suffix of loaded atomic files, values are list of field names which is loaded for data processing but will not be used in model. E.g. the ``time_field`` may be used for time ordering but model does not use this field. Defaults to ``None``.
 - ``additional_feat_suffix (list)``: Control loading additional atomic files. E.g. if you want to load features from ``ml-100k.hello``, just set this arg as ``additional_feat_suffix: [hello]``. Features of additional features will be stored in ``Dataset.feat_list``. Defaults to ``None``.
 
 Filtering
@@ -67,15 +67,12 @@ Filtering
 Remove duplicated user-item interactions
 ''''''''''''''''''''''''''''''''''''''''
 
-- ``rm_dup_inter (str)`` : Whether to remove duplicated user-item interactions. If ``time_field`` exists, ``inter_feat`` will be sorted by ``time_field`` in ascending order. Otherwise it will remain unchanged. After that, if ``rm_dup_inter ==  first``, we will keep the first user-item interaction in duplicates; if ``rm_dup_inter ==  last``, we will keep the last user-item interaction in duplicates. Defaults to ``None``.
+- ``rm_dup_inter (str)`` : Whether to remove duplicated user-item interactions. If ``time_field`` exists, ``inter_feat`` will be sorted by ``time_field`` in ascending order. Otherwise it will remain unchanged. After that, if ``rm_dup_inter ==  first``, we will keep the first user-item interaction in duplicates; if ``rm_dup_inter == last``, we will keep the last user-item interaction in duplicates. Defaults to ``None``.
 
 Filter by value
 ''''''''''''''''''
 
-- ``lowest_val (dict)`` : Has the format ``{k (str): v (float)}, ...``. The rows whose ``feat[k] < v`` will be filtered. Defaults to ``None``.
-- ``highest_val (dict)`` : Has the format ``{k (str): v (float)}, ...``. The rows whose ``feat[k] > v`` will be filtered. Defaults to ``None``.
-- ``equal_val (dict)`` : Has the format ``{k (str): v (float)}, ...``. The rows whose ``feat[k] != v`` will be filtered. Defaults to ``None``.
-- ``not_equal_val (dict)`` : Has the format ``{k (str): v (float)}, ...``. The rows whose ``feat[k] == v`` will be filtered. Defaults to ``None``.
+- ``val_interval (dict)``: Has the format ``{k (str): interval (str), ...}``, where ``interval`` can be set as ``[A,B]`` / ``[A,B)`` / ``(A,B)`` / ``(A,B]``. The rows whose ``feat[k]`` is in the interval ``interval`` will be retained. If you want to specify more than one interval, separate them with semicolon(s). For instance, ``{k: "[A,B);(C,D]"}`` can be adopted and rows whose ``feat[k]`` is in any specified interval will be retained. Defaults to ``None``, which means all rows will be retained.
 
 Remove interation by user or item
 '''''''''''''''''''''''''''''''''''
@@ -85,17 +82,18 @@ Remove interation by user or item
 Filter by number of interactions
 ''''''''''''''''''''''''''''''''''''
 
-- ``max_user_inter_num (int)`` : Users whose number of interactions is more than ``max_user_inter_num`` will be filtered. Defaults to ``None``.
-- ``min_user_inter_num (int)`` : Users whose number of interactions is less than ``min_user_inter_num`` will be filtered. Defaults to ``0``.
-- ``max_item_inter_num (int)`` : Items whose number of interactions is more than ``max_item_inter_num`` will be filtered. Defaults to ``None``.
-- ``min_item_inter_num (int)`` : Items whose number of interactions is less than ``min_item_inter_num`` will be filtered. Defaults to ``0``.
+- ``user_inter_num_interval (str)`` : Has the interval format, such as ``[A,B]`` / ``[A,B)`` / ``(A,B)`` / ``(A,B]``,  where ``A`` and ``B`` are the endpoints of the interval and ``A <= B``. Users whose number of interactions is in the interval will be retained. Defaults to ``[0,inf)``.
+- ``item_inter_num_interval (str)`` : Has the interval format, such as ``[A,B]`` / ``[A,B)`` / ``(A,B)`` / ``(A,B]``,  where ``A`` and ``B`` are the endpoints of the interval and ``A <= B``. Items whose number of interactions is in the interval will be retained. Defaults to ``[0,inf)``.
 
 Preprocessing
 -----------------
 
-- ``fields_in_same_space (list)`` : List of spaces. Space is a list of string similar to the fields' names. The fields in the same space will be remapped into the same index system. Note that if you want to make some fields remapped in the same space with entities, then just set ``fields_in_same_space = [entity_id, xxx, ...]``. (if ``ENTITY_ID_FIELD != 'entity_id'``, then change the ``'entity_id'`` in the above example.) Defaults to ``None``.
-- ``preload_weight (dict)`` : Has the format ``{k (str): v (float)}, ...``. ``k`` if a token field, representing the IDs of each row of preloaded weight matrix. ``v`` is a float like fields. Each pair of ``u`` and ``v`` should be from the same atomic file. This arg can be used to load pretrained vectors. Defaults to ``None``.
-- ``normalize_field (list)`` : List of filed names to be normalized. Note that only float like fields can be normalized. Defaults to ``None``.
+- ``alias_of_user_id (list)``: List of fields' names, which will be remapped into the same index system with ``USER_ID_FIELD``. Defaults to ``None``.
+- ``alias_of_item_id (list)``: List of fields' names, which will be remapped into the same index system with ``ITEM_ID_FIELD``. Defaults to ``None``.
+- ``alias_of_entity_id (list)``: List of fields' names, which will be remapped into the same index system with ``ENTITY_ID_FIELD``, ``HEAD_ENTITY_ID_FIELD`` and ``TAIL_ENTITY_ID_FIELD``. Defaults to ``None``.
+- ``alias_of_relation_id (list)``: List of fields' names, which will be remapped into the same index system with ``RELATION_ID_FIELD``. Defaults to ``None``.
+- ``preload_weight (dict)`` : Has the format ``{k (str): v (float)}, ...``. ``k`` is a token field, representing the IDs of each row of preloaded weight matrix. ``v`` is a float-like field. Each pair of ``k`` and ``v`` should be from the same atomic file. This arg can be used to load pretrained vectors. Defaults to ``None``.
+- ``normalize_field (list)`` : List of filed names to be normalized. Note that only float-like fields can be normalized. Defaults to ``None``.
 - ``normalize_all (bool)`` : Normalize all the float like fields if ``True``. Defaults to ``True``.
 
 Benchmark file
diff --git a/docs/source/user_guide/config/environment_settings.rst b/docs/source/user_guide/config/environment_settings.rst
new file mode 100644
index 000000000..51b311823
--- /dev/null
+++ b/docs/source/user_guide/config/environment_settings.rst
@@ -0,0 +1,28 @@
+Environment settings
+===========================
+Environment settings are designed to set basic parameters of running environment.
+
+- ``gpu_id (int or str)`` : The id of GPU device. Defaults to ``0``.
+- ``use_gpu (bool)`` : Whether or not to use GPU. If True, using GPU, else using CPU.
+  Defaults to ``True``.
+- ``seed (int)`` : Random seed. Defaults to ``2020``.
+- ``state (str)`` : Logging level. Defaults to ``'INFO'``.
+  Range in ``['INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL']``.
+- ``encoding (str)``: Encoding to use for reading atomic files. Defaults to ``'utf-8'``.
+  The available encoding can be found in `here <https://docs.python.org/3/library/codecs.html#standard-encodings>`__.
+- ``reproducibility (bool)`` : If True, the tool will use deterministic
+  convolution algorithms, which makes the result reproducible. If False,
+  the tool will benchmark multiple convolution algorithms and select the fastest one,
+  which makes the result not reproducible but can speed up model training in
+  some case. Defaults to ``True``.
+- ``data_path (str)`` : The path of input dataset. Defaults to ``'dataset/'``.
+- ``checkpoint_dir (str)`` : The path to save checkpoint file.
+  Defaults to ``'saved/'``.
+- ``show_progress (bool)`` : Show the progress of training epoch and evaluate epoch.
+  Defaults to ``True``.
+- ``save_dataset (bool)``: Whether or not save filtered dataset.
+  If True, save filtered dataset, otherwise it will not be saved.
+  Defaults to ``False``.
+- ``save_dataloaders (bool)``: Whether or not save split dataloaders.
+  If True, save split dataloaders, otherwise they will not be saved.
+  Defaults to ``False``.
diff --git a/docs/source/user_guide/config/evaluation_settings.rst b/docs/source/user_guide/config/evaluation_settings.rst
new file mode 100644
index 000000000..0f575493e
--- /dev/null
+++ b/docs/source/user_guide/config/evaluation_settings.rst
@@ -0,0 +1,38 @@
+Evaluation Settings
+===========================
+Evaluation settings are designed to set parameters about model evaluation.
+
+
+
+- ``eval_args (dict)``:  This parameter have 4 keys: ``group_by``, ``order``, ``split``, and ``mode``, 
+  which respectively control the data grouping strategy, data ordering strategy, data splitting strategy
+  and evaluation mode for model evaluation.   
+  
+  - ``group_by (str)``: decides how we group the data in `.inter`. Now we support two kinds of grouping strategies: ``['user', 'none']``. If the value of ``group_by`` is ``user``, the data will be grouped by the column of ``USER_ID_FIELD`` and split in user dimension. If the value is ``none``, the data won't be grouped. The default value is ``user``.   
+
+  - ``order (str)``: decides how we sort the data in `.inter`. Now we support two kinds of ordering strategies: ``['RO', 'TO']``, which denotes the random ordering and temporal ordering. For ``RO``, we will shuffle the data and then split them in this order. For ``TO``, we will sort the data by the column of `TIME_FIELD` in ascending order and the split them in this order. The default value is ``RO``.
+  
+  - ``split (dict)``: decides how we split the data in `.inter`. Now we support two kinds of splitting strategies: ``['RS','LS']``, which denotes the ratio-based data splitting and leave-one-out data splitting. If the key of ``split`` is ``RS``, you need to set the splitting ratio like ``[0.8,0.1,0.1]``, ``[7,2,1]`` or ``[8,0,2]``, which denotes the ratio of training set, validation set and testing set respectively. If the key of ``split`` is ``LS``, now we support three kinds of ``LS`` mode: ``['valid_and_test', 'valid_only', 'test_only']`` and you should choose one mode as the value of ``LS``.  The default value of ``split`` is ``{'RS': [0.8,0.1,0.1]}``.
+  
+  - ``mode (str)``: decides the data range which we evaluate the model on. Now we support four kinds of evaluation mode: ``['full','unixxx','popxxx','labeled']``. ``full`` , ``unixxx`` and ``popxxx`` are designed for the evaluation on implicit feedback (data without label). For implicit feedback, we regard the items with observed interactions as positive items and those without observed interactions as negative items. ``full`` means evaluating the model on the set of all items. ``unixxx``, for example ``uni100``,  means uniformly sample 100 negative items for each positive item in testing set, and evaluate the model on these positive items with their sampled negative items. ``popxxx``, for example ``pop100``, means sample 100 negative items for each positive item in testing set based on item popularity (:obj:`Counter(item)` in `.inter` file), and evaluate the model on these positive items with their sampled negative items. Here the `xxx` must be an integer. For explicit feedback (data with label), you should set the mode as ``None`` and we will evaluate the model based on your label. The default value is ``full``.
+
+- ``repeatable (bool)``: Whether to evaluate the result with a repeatable recommendation scene. Note that it is disabled for sequential models as the recommendation is already repeatable. For other models, defaults to ``False``.
+- ``metrics (list or str)``: Evaluation metrics. Defaults to
+  ``['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']``. Range in the following table:
+
+  ==============    =================================================
+  Type              Metrics 
+  ==============    =================================================
+  Ranking-based     Recall, MRR, NDCG, Hit, MAP, Precision, GAUC, ItemCoverage, AveragePopularity, GiniIndex, ShannonEntropy, TailPercentage
+  value-based       AUC, MAE, RMSE, LogLoss      
+  ==============    =================================================
+  
+  Note that value-based metrics and ranking-based metrics can not be used together.
+
+- ``topk (list or int or None)``: The value of k for topk evaluation metrics.
+  Defaults to ``10``.
+- ``valid_metric (str)``: The evaluation metrics for early stopping. 
+  It must be one of used ``metrics``. Defaults to ``'MRR@10'``.
+- ``eval_batch_size (int)``: The evaluation batch size. Defaults to ``4096``.
+- ``metric_decimal_place(int)``: The decimal place of metric score. Defaults to ``4``.
+
diff --git a/docs/source/user_guide/config/parameters_configuration.rst b/docs/source/user_guide/config/parameters_configuration.rst
new file mode 100644
index 000000000..a0c57411d
--- /dev/null
+++ b/docs/source/user_guide/config/parameters_configuration.rst
@@ -0,0 +1,149 @@
+Parameters Configuration
+------------------------------
+RecBole supports three types of parameter configurations: Config files,
+Parameter Dicts and Command Line. The parameters are assigned via the
+Configuration module.
+
+Config Files
+^^^^^^^^^^^^^^^^
+Config Files should be organized in the format of yaml.
+The users should write their parameters according to the rules aligned with
+yaml, and the final config files are processed by the configuration module
+to complete the parameter settings.
+
+To begin with, we write the parameters into the yaml files (e.g. `example.yaml`).
+
+.. code:: yaml
+
+    gpu_id: 1
+    training_batch_size: 1024
+
+Then, the yaml files are conveyed to the configuration module to finish the
+parameter settings.
+
+.. code:: python
+
+    from recbole.config import Config
+
+    config = Config(model='BPR', dataset='ml-100k', config_file_list=['example.yaml'])
+    print('gpu_id: ', config['gpu_id'])
+    print('training_batch_size: ', config['training_batch_size'])
+
+
+output:
+
+.. code:: bash
+
+    gpu_id: 1
+    training_batch_size: 1024
+
+The parameter ``config_file_list`` supports multiple yaml files.
+
+For more details on yaml, please refer to YAML_.
+
+.. _YAML: https://yaml.org/
+
+When using our toolkit, the parameters belonging to **Dataset parameters** and
+Evaluation Settings of **Basic Parameters** are recommended to be written into
+the config files, which may be convenient for reusing the configurations.
+
+Parameter Dicts
+^^^^^^^^^^^^^^^^^^
+Parameter Dict is realized by the dict data structure in python, where the key
+is the parameter name, and the value is the parameter value. The users can write their
+parameters into a dict, and input it into the configuration module.
+
+An example is as follows:
+
+.. code:: python
+
+    from recbole.config import Config
+
+    parameter_dict = {
+        'gpu_id': 2,
+        'training_batch_size': 512
+    }
+    config = Config(model='BPR', dataset='ml-100k', config_dict=parameter_dict)
+    print('gpu_id: ', config['gpu_id'])
+    print('training_batch_size: ', config['training_batch_size'])
+
+output:
+
+.. code:: bash
+
+    gpu_id: 2
+    training_batch_size: 512
+
+
+Command Line
+^^^^^^^^^^^^^^^^^^^^^^^^
+We can also assign parameters based on the command line.
+The parameters in the command line can be read from the configuration module.
+The format is: `-–parameter_name=[parameter_value]`.
+
+Write the following code to the python file (e.g. `run.py`):
+
+.. code:: python
+
+    from recbole.config import Config
+
+    config = Config(model='BPR', dataset='ml-100k')
+    print('gpu_id: ', config['gpu_id'])
+    print('training_batch_size: ', config['training_batch_size'])
+
+Running:
+
+.. code:: bash
+
+    python run.py --gpu_id=3 --training_batch_size=256
+
+output:
+
+.. code:: bash
+
+    gpu_id: 3
+    training_batch_size: 256
+
+
+Priority
+^^^^^^^^^^^^^^^^^
+RecBole supports the combination of three types of parameter configurations.
+
+The priority of the configuration methods is: Command Line > Parameter Dicts
+> Config Files > Default Settings
+
+A example is as follows:
+
+`example.yaml`:
+
+.. code:: yaml
+
+    gpu_id: 1
+    training_batch_size: 1024
+
+`run.py`:
+
+.. code:: python
+
+    from recbole.config import Config
+
+    parameter_dict = {
+        'gpu_id': 2,
+        'training_batch_size': 512
+    }
+    config = Config(model='BPR', dataset='ml-100k', config_file_list=['example.yaml'], config_dict=parameter_dict)
+    print('gpu_id: ', config['gpu_id'])
+    print('training_batch_size: ', config['training_batch_size'])
+
+Running:
+
+.. code:: bash
+
+    python run.py --gpu_id=3 --training_batch_size=256
+
+output:
+
+.. code:: bash
+
+    gpu_id: 3
+    training_batch_size: 256
diff --git a/docs/source/user_guide/config/training_settings.rst b/docs/source/user_guide/config/training_settings.rst
new file mode 100644
index 000000000..2e3a51499
--- /dev/null
+++ b/docs/source/user_guide/config/training_settings.rst
@@ -0,0 +1,24 @@
+Training Settings
+===========================
+Training settings are designed to set parameters about model training.
+
+
+- ``epochs (int)`` : The number of training epochs. Defaults to ``300``.
+- ``train_batch_size (int)`` : The training batch size. Defaults to ``2048``.
+- ``learner (str)`` : The name of used optimizer. Defaults to ``'adam'``.
+  Range in ``['adam', 'sgd', 'adagrad', 'rmsprop', 'sparse_adam']``.
+- ``learning_rate (float)`` : Learning rate. Defaults to ``0.001``.
+- ``neg_sampling(dict)``: This parameter controls the negative sampling for model training.
+  The key range is ``['uniform', 'popularity']``, which decides the distribution of negative items in sampling pools.
+  ``uniform`` means uniformly select negative items while ``popularity`` means select negative items based on 
+  their popularity (Counter(item) in `.inter` file). Note that if your data is labeled, you need to set this parameter as ``None``.
+  The default value of this parameter is ``{'uniform': 1}``. 
+- ``eval_step (int)`` : The number of training epochs before an evaluation
+  on the valid dataset. If it is less than 1, the model will not be
+  evaluated on the valid dataset. Defaults to ``1``.
+- ``stopping_step (int)`` : The threshold for validation-based early stopping.
+  Defaults to ``10``.
+- ``clip_grad_norm (dict)`` : The args of `clip_grad_norm_ <https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_norm_.html>`_
+  which will clip gradient norm of model. Defaults to ``None``.
+- ``loss_decimal_place(int)``: The decimal place of training loss. Defaults to ``4``.
+- ``weight_decay (float)`` : The weight decay (L2 penalty), used for `optimizer <https://pytorch.org/docs/stable/optim.html?highlight=weight_decay>`_. Default to ``0.0``.
\ No newline at end of file
diff --git a/docs/source/user_guide/config_settings.rst b/docs/source/user_guide/config_settings.rst
index aab967cdb..bb317f161 100644
--- a/docs/source/user_guide/config_settings.rst
+++ b/docs/source/user_guide/config_settings.rst
@@ -1,253 +1,32 @@
-Config Settings
+Config Introduction
 ===================
 RecBole is able to config different parameters for controlling the experiment
 setup (e.g., data processing, data splitting, training and evaluation).
 The users can select the settings according to their own requirements.
 
-The introduction of different parameter configurations are presented as follows:
-
-Parameters Introduction
+Config settings
 -----------------------------
-The parameters in RecBole can be divided into three categories:
-Basic Parameters, Dataset Parameters and Model Parameters.
-
-Basic Parameters
-^^^^^^^^^^^^^^^^^^^^^^
-Basic parameters are used to build the general environment including the settings for
-model training and evaluation.
-
-**Environment Setting**
-
-- ``gpu_id (int or str)`` : The id of GPU device. Defaults to ``0``.
-- ``use_gpu (bool)`` : Whether or not to use GPU. If True, using GPU, else using CPU.
-  Defaults to ``True``.
-- ``seed (int)`` : Random seed. Defaults to ``2020``.
-- ``state (str)`` : Logging level. Defaults to ``'INFO'``.
-  Range in ``['INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL']``.
-- ``reproducibility (bool)`` : If True, the tool will use deterministic
-  convolution algorithms, which makes the result reproducible. If False,
-  the tool will benchmark multiple convolution algorithms and select the fastest one,
-  which makes the result not reproducible but can speed up model training in
-  some case. Defaults to ``True``.
-- ``data_path (str)`` : The path of input dataset. Defaults to ``'dataset/'``.
-- ``checkpoint_dir (str)`` : The path to save checkpoint file.
-  Defaults to ``'saved/'``.
-- ``show_progress (bool)`` : Show the progress of training epoch and evaluate epoch.
-  Defaults to ``True``.
-
-**Training Setting**
-
-- ``epochs (int)`` : The number of training epochs. Defaults to ``300``.
-- ``train_batch_size (int)`` : The training batch size. Defaults to ``2048``.
-- ``learner (str)`` : The name of used optimizer. Defaults to ``'adam'``.
-  Range in ``['adam', 'sgd', 'adagrad', 'rmsprop', 'sparse_adam']``.
-- ``learning_rate (float)`` : Learning rate. Defaults to ``0.001``.
-- ``training_neg_sample_num (int)`` : The number of negative samples during
-  training. If it is set to 0, the negative sampling operation will not be
-  performed. Defaults to ``1``.
-- ``training_neg_sample_distribution(str)`` : Distribution of the negative items
-  in training phase. Default to ``uniform``. Range in ``['uniform', 'popularity']``.
-- ``eval_step (int)`` : The number of training epochs before a evaluation
-  on the valid dataset. If it is less than 1, the model will not be
-  evaluated on the valid dataset. Defaults to ``1``.
-- ``stopping_step (int)`` : The threshold for validation-based early stopping.
-  Defaults to ``10``.
-- ``clip_grad_norm (dict)`` : The args of `clip_grad_norm_ <https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_norm_.html>`_
-  which will clips gradient norm of model. Defaults to ``None``.
-- ``loss_decimal_place(int)``: The decimal place of training loss. Defaults to ``4``.
-- ``weight_decay (float)`` : The weight decay (L2 penalty) of `optimizer <https://pytorch.org/docs/stable/optim.html?highlight=weight_decay>`_, which acts on all trainable parameters. Default to ``0.0``.
-- ``draw_loss_pic (bool)``: Draw the training loss line graph of model if it's ``True``, the pic is a PDF file and will be saved in your run directory after model training. Default to ``False``.
-
-
-**Evaluation Setting**
-
-- ``eval_setting (str)``: The evaluation settings. Defaults to ``'RO_RS,full'``.
-  The parameter has two parts. The first part control the splitting methods,
-  the range is ``['RO_RS','TO_LS','RO_LS','TO_RS']``. The second part(optional)
-  control the ranking mechanism, the range is ``['full','uni100','uni1000','pop100','pop1000']``.
-- ``group_by_user (bool)``: Whether or not to group the users.
-  It must be ``True`` when ``eval_setting`` is in ``['RO_LS', 'TO_LS']``.
-  Defaults to ``True``.
-- ``split_ratio (list)``: The split ratio between train data, valid data and
-  test data. It only take effects when the first part of ``eval_setting``
-  is in ``['RO_RS', 'TO_RS']``. Defaults to ``[0.8, 0.1, 0.1]``.
-- ``leave_one_num (int)``: It only take effects when the first part of
-  ``eval_setting`` is in ``['RO_LS', 'TO_LS']``. Defaults to ``2``.
-
-- ``metrics (list or str)``: Evaluation metrics. Defaults to
-  ``['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']``. Range in
-  ``['Recall', 'MRR', 'NDCG', 'Hit', 'MAP', 'Precision', 'AUC', 'GAUC',
-  'MAE', 'RMSE', 'LogLoss']``.
-- ``topk (list or int or None)``: The value of k for topk evaluation metrics.
-  Defaults to ``10``.
-- ``valid_metric (str)``: The evaluation metrics for early stopping. 
-  It must be one of used ``metrics``. Defaults to ``'MRR@10'``.
-- ``eval_batch_size (int)``: The evaluation batch size. Defaults to ``4096``.
-- ``metric_decimal_place(int)``: The decimal place of metric score. Defaults to ``4``.
-
-Pleaser refer to :doc:`evaluation_support` for more details about the parameters
-in Evaluation Setting.
-
-Dataset Parameters
-^^^^^^^^^^^^^^^^^^^^^^^
-Dataset Parameters are used to describe the dataset information and control
-the dataset loading and filtering.
-
-Please refer to :doc:`data/data_args` for more details.
-
-Model Parameters
-^^^^^^^^^^^^^^^^^^^^^
-Model Parameters are used to describe the model structures.
-
-Please refer to :doc:`model_intro` for more details.
-
-
-Parameters Configuration
-------------------------------
-RecBole supports three types of parameter configurations: Config files,
-Parameter Dicts and Command Line. The parameters are assigned via the
-Configuration module.
-
-Config Files
-^^^^^^^^^^^^^^^^
-Config Files should be organized in the format of yaml.
-The users should write their parameters according to the rules aligned with
-yaml, and the final config files are processed by the configuration module
-to complete the parameter settings.
-
-To begin with, we write the parameters into the yaml files (e.g. `example.yaml`).
-
-.. code:: yaml
-
-    gpu_id: 1
-    training_batch_size: 1024
-
-Then, the yaml files are conveyed to the configuration module to finish the
-parameter settings.
-
-.. code:: python
-
-    from recbole.config import Config
-
-    config = Config(model='BPR', dataset='ml-100k', config_file_list=['example.yaml'])
-    print('gpu_id: ', config['gpu_id'])
-    print('training_batch_size: ', config['training_batch_size'])
-
-
-output:
-
-.. code:: bash
-
-    gpu_id: 1
-    training_batch_size: 1024
-
-The parameter ``config_file_list`` supports multiple yaml files.
-
-For more details on yaml, please refer to YAML_.
-
-.. _YAML: https://yaml.org/
+We split all the config settings into five parts: environment settings, data settings, model settings, training settings and evaluation settings.
+The introduction of different parameter configurations are presented as follows (for model settings, please read the specific model page in :doc:`model_intro`):
 
-When using our toolkit, the parameters belonging to **Dataset parameters** and
-Evaluation Settings of **Basic Parameters** are recommended to be written into
-the config files, which may be convenient for reusing the configurations.
+.. toctree::
+   :maxdepth: 1
 
-Parameter Dicts
-^^^^^^^^^^^^^^^^^^
-Parameter Dict is realized by the dict data structure in python, where the key
-is the parameter name, and the value is the parameter value. The users can write their
-parameters into a dict, and input it into the configuration module.
+   config/environment_settings
+   config/data_settings
+   config/training_settings
+   config/evaluation_settings
 
-An example is as follows:
-
-.. code:: python
-
-    from recbole.config import Config
-
-    parameter_dict = {
-        'gpu_id': 2,
-        'training_batch_size': 512
-    }
-    config = Config(model='BPR', dataset='ml-100k', config_dict=parameter_dict)
-    print('gpu_id: ', config['gpu_id'])
-    print('training_batch_size: ', config['training_batch_size'])
-
-output:
-
-.. code:: bash
-
-    gpu_id: 2
-    training_batch_size: 512
-
-
-Command Line
-^^^^^^^^^^^^^^^^^^^^^^^^
-We can also assign parameters based on the command line.
-The parameters in the command line can be read from the configuration module.
-The format is: `-–parameter_name=[parameter_value]`.
-
-Write the following code to the python file (e.g. `run.py`):
-
-.. code:: python
-
-    from recbole.config import Config
-
-    config = Config(model='BPR', dataset='ml-100k')
-    print('gpu_id: ', config['gpu_id'])
-    print('training_batch_size: ', config['training_batch_size'])
-
-Running:
-
-.. code:: bash
-
-    python run.py --gpu_id=3 --training_batch_size=256
-
-output:
-
-.. code:: bash
-
-    gpu_id: 3
-    training_batch_size: 256
-
-
-Priority
-^^^^^^^^^^^^^^^^^
-RecBole supports the combination of three types of parameter configurations.
-
-The priority of the configuration methods is: Command Line > Parameter Dicts
-> Config Files > Default Settings
-
-A example is as follows:
-
-`example.yaml`:
-
-.. code:: yaml
-
-    gpu_id: 1
-    training_batch_size: 1024
-
-`run.py`:
-
-.. code:: python
-
-    from recbole.config import Config
-
-    parameter_dict = {
-        'gpu_id': 2,
-        'training_batch_size': 512
-    }
-    config = Config(model='BPR', dataset='ml-100k', config_file_list=['example.yaml'], config_dict=parameter_dict)
-    print('gpu_id: ', config['gpu_id'])
-    print('training_batch_size: ', config['training_batch_size'])
-
-Running:
+How to set config?
+-----------------------------
+RecBole supports three types of parameter configurations: Config files, Parameter Dicts and Command Line. 
+The parameters are assigned via the Configuration module.
 
-.. code:: bash
+For more details about setting config, please read 
 
-    python run.py --gpu_id=3 --training_batch_size=256
+.. toctree::
+   :maxdepth: 1
 
-output:
+   config/parameters_configuration
 
-.. code:: bash
 
-    gpu_id: 3
-    training_batch_size: 256
diff --git a/docs/source/user_guide/data/atomic_files.rst b/docs/source/user_guide/data/atomic_files.rst
index 9e74dd4d7..ebac34ce3 100644
--- a/docs/source/user_guide/data/atomic_files.rst
+++ b/docs/source/user_guide/data/atomic_files.rst
@@ -141,4 +141,4 @@ For example, if you want to map the tokens of ``ent_id`` into the same space of
         # inter/user/item/...: As usual
         ent: [ent_id, ent_emb]
 
-    fields_in_same_space: [[ent_id, entity_id]]
+    alias_of_entity_id: [ent_id]
diff --git a/docs/source/user_guide/data/dataset_download.rst b/docs/source/user_guide/data/dataset_download.rst
new file mode 100644
index 000000000..fffaf70d5
--- /dev/null
+++ b/docs/source/user_guide/data/dataset_download.rst
@@ -0,0 +1,39 @@
+Dataset Download
+================================
+
+In RecBole, we have collected and released 28 commonly-used publiced dataset (detailed as `Dataset List </dataset_list.html>`_).
+Users can freely download these datasets in the following three ways:
+
+1. Automatically downloading
+-----------------------------
+For the convenience of users, we implement automatically downloading module in RecBole and now we support to download the :doc:`atomic_files` of 28 commonly-used
+publiced datasets (detailed as `Dataset List </dataset_list.html>`_). If you want to run models on a dataset, you just need to set the
+`dataset` and then the data files will be automatically downloaded.
+
+For example, if you want to run BPR model on the ml-1m dataset but you don't prepare the :doc:`atomic_files` of ml-1m dataset,
+you can use our automatically downloading module to download the data. 
+All you need is to run the model as normal, and RecBole will automatically check if you have the data files, if not, it will begin to download the data files
+and you will get the output like this:
+
+.. code:: none
+
+    23 Aug 10:02    INFO  Prepare to download dataset [ml-1m] from [https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-1m.zip].
+    23 Aug 10:02    INFO  Downloading https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-1m.zip
+    Downloaded 0.01 GB: 100%|█████████████████████████████████████████████████████████████████████████████| 7/7 [04:16<00:00, 36.65s/it]
+    23 Aug 10:06    INFO  Extracting dataset/ml-1m/ml-1m.zip
+    23 Aug 10:06    INFO  Downloading done.
+
+And next time you can directly run other models on ml-1m dataset.
+
+2. Download from cloud disk
+-----------------------------
+Besides automatically downloading, we also upload our collected and converted atomic files of 28 datasets in `Google Drive <https://drive.google.com/drive/folders/1so0lckI6N6_niVEYaBu-LIcpOdZf99kj?usp=sharing>`_ and `Baidu Wangpan <https://pan.baidu.com/s/1p51sWMgVFbAaHQmL4aD_-g>`_ (Password: e272).
+You can also download the data from these two resources by yourself.
+
+3. Covert the raw data 
+-----------------------------
+If you have already download the raw data, you can also covert them into atomic files format by yourself. 
+And we have already publiced some converting scripts in `RecDatasets <https://github.com/RUCAIBox/RecDatasets>`_.
+
+
+
diff --git a/docs/source/user_guide/data/interaction.rst b/docs/source/user_guide/data/interaction.rst
index 43e5c0356..5781c92b5 100644
--- a/docs/source/user_guide/data/interaction.rst
+++ b/docs/source/user_guide/data/interaction.rst
@@ -5,7 +5,7 @@ Interaction
 
 It is implemented as a new abstract data type based on :class:`python.dict`. The keys correspond to features from input, which can be conveniently referenced with feature names when writing the recommendation algorithms; and the values correspond to tensors (implemented by :class:`torch.Tensor`), which will be used for the update and computation in learning algorithms. Specially, the value entry for a specific key stores all the corresponding tensor data in a batch or mini-batch.
 
-With such a data structure, our library provides a friendly interface to write the recommendation algorithms in a batch-based mode. For example, we can read all the user embeddings and items embeddings from an instantiated :class:`~recbole.data.interaction.Interaction` object ``inter`` simply based on the feature names:
+With such a data structure, our library provides a friendly interface to write the recommendation algorithms in a batch-based mode. For example, we can read all the user embeddings and item embeddings from an instantiated :class:`~recbole.data.interaction.Interaction` object ``inter`` simply based on the feature names:
 
 .. code:: python
 
diff --git a/docs/source/user_guide/data/label_of_data.rst b/docs/source/user_guide/data/label_of_data.rst
new file mode 100644
index 000000000..b777ee9d9
--- /dev/null
+++ b/docs/source/user_guide/data/label_of_data.rst
@@ -0,0 +1,90 @@
+Label of data
+=========================
+In recommendation filed, there are two kinds of data scenes: explicit feedback scene and implicit feedback scene. 
+
+Explicit feedback, like rating for items, has explicit label for model training. While for implicit feedback, like clicks and purchases, 
+the label of data is vague, and generally we will regard all the observed interaction as the positive samples and select negative samples from
+unobserved interactions (known as negative sampling).    
+
+To supports both explicit feedback scene and implicit feedback scene, RecBole design three ways to set label of data.
+
+1. Set label field
+-----------------------------
+If your data has already been labeled, you only need to set ``LABEL_FIELD`` to tell the model 
+which column represents the label of data, and then set `neg_sampling` as `None`.
+
+For example, if your `.inter` file is like:
+
+=============   =============   ============   ===============
+user_id:token   item_id:token   label:float    timestamp:float
+=============   =============   ============   ===============
+1               1193            1              978300760
+1               661             0              978302109
+2               11              1              978302009  
+2               112             1              978312344 
+2               555             0              978302321 
+3               234             1              978302109 
+=============   =============   ============   ===============
+
+Then, you can set the config like:
+
+.. code:: yaml
+
+    LABEL_FIELD: label
+    neg_sampling: None
+
+Note that the value of your label column should only be 0 or 1 (0 represents the negative label and 
+1 represents the positive label). 
+
+2. Set threshold
+------------------------------
+
+If your data doesn't have labels but has users' feedback information (like rating for items) to show their preferences, 
+a general way to label them is to set threshold. 
+
+For example, if you `.inter` file is like:
+
+=============   =============   ============   ===============
+user_id:token   item_id:token   rating:float   timestamp:float
+=============   =============   ============   ===============
+1               1193            5              978300760
+1               661             1              978302109
+2               11              4              978302009  
+2               112             4              978312344 
+2               555             1              978302321 
+3               234             3              978302109 
+=============   =============   ============   ===============
+
+To set label for these interactions, you can set `3` as the threshold of rating, and 
+the interactions will be labeled as positive if their rating no less than 3.
+
+You can set the config like:
+
+.. code:: yaml
+
+    threshold: 
+        rating: 3
+    neg_sampling: None
+
+And then RecBole will automatically set label for interactions based on their rating column. 
+    
+3. Negative sampling
+------------------------------
+If your only have implicit feedback data, without label or users' feedback information.
+A general way to label these kinds of data is negative sampling. We will assume that for each user, all the observed interactions are positive,
+and the unobserved ones are negative. And then, we will set positive label for all the observed interactions, 
+and select some negative samples from the unobserved interactions according to a certain strategy.
+
+You can set the config like:
+
+.. code:: yaml
+
+    neg_sampling: 
+        uniform: 1
+
+And then, RecBole will automatically select one negative sample for each positive sample uniformly from the unobserved interactions.
+
+At last, for more details about the label config, please read :doc:`../config/data_settings` and :doc:`../config/training_settings`.
+
+
+
diff --git a/docs/source/user_guide/data_intro.rst b/docs/source/user_guide/data_intro.rst
index f84d2c04e..83d04a2fa 100644
--- a/docs/source/user_guide/data_intro.rst
+++ b/docs/source/user_guide/data_intro.rst
@@ -1,12 +1,31 @@
-Data Introduction
-===================
+Data Module Introduction
+=========================
 
-Here we introduce the whole dataflow and highlight its key features.
+RecBole not only implements lots of popular recommender models, but also collects and releases 28 commonly-used publiced datasets. 
+You can freely download these datasets following our docs :doc:`data/dataset_download`.
+
+For extensibility and reusability, Recbole has a flexible and extensible data module.  
+Our data module designs an elegant data flow that transforms raw data
+into the model input. Detailed as :doc:`data/data_flow`.
+In order to characterize most forms of the input data
+required by different recommendation tasks, RecBole designs an input data format called :doc:`data/atomic_files`. All the input data should be 
+converted into `Atomic Files` format. 
+Besides, we design a data structure called :doc:`data/interaction` to provides a unified internal data representation for different
+recommendation algorithms.
+
+Plus, RecBole supports both explicit feedback (labeled data) scenes and implicit feedback (unlabeled data) scenes. For explicit feedback scenes,
+users can set the `LABEL_FIELD` in the config and RecBole will train and test model based on the label. For implicit feedback scenes, RecBole will
+regard all the observed interactions as positive samples and automatically select the negative samples from the unobserved interactions (which is known as negative sampling).
+For more information about label setting in RecBole,
+please read :doc:`data/label_of_data`.
+
+Here are the related docs for data module:
 
 .. toctree::
    :maxdepth: 1
 
+   data/dataset_download
    data/data_flow
    data/atomic_files
    data/interaction
-   data/data_args
+   data/label_of_data
\ No newline at end of file
diff --git a/docs/source/user_guide/evaluation_support.rst b/docs/source/user_guide/evaluation_support.rst
deleted file mode 100644
index 39cc2167c..000000000
--- a/docs/source/user_guide/evaluation_support.rst
+++ /dev/null
@@ -1,65 +0,0 @@
-Evaluation Support
-===========================
-
-The function of evaluation module is to implement commonly used evaluation
-protocols for recommender systems. Since different models can be compared under
-the same evaluation modules, RecBole standardizes the evaluation of recommender
-systems.
-
-
-Evaluation Settings
------------------------
-The evaluation settings supported by RecBole is as following. Among them, the
-first four rows correspond to the dataset splitting methods, while the last two
-rows correspond to the ranking mechanism, namely a full ranking over all the
-items or a sampled-based ranking.
-
-==================       ========================================================
- Notation                   Explanation
-==================       ========================================================
-  RO_RS                     Random Ordering + Ratio-based Splitting
-  TO_LS                     Temporal Ordering + Leave-one-out Splitting
-  RO_LS                     Random Ordering + Leave-one-out Splitting
-  TO_RS                     Temporal Ordering + Ratio-based Splitting
-  full                      full ranking with all item candidates
-  uniN                      sample-based ranking: each positive item is paired with N sampled negative items in uniform distribution
-  popN                      sample-based ranking: each positive item is paired with N sampled negative items in popularity distribution
-==================       ========================================================
-
-The parameters used to control the evaluation settings are as follows:
-
-- ``eval_setting (str)``: The evaluation settings. Defaults to ``'RO_RS,full'``.
-  The parameter has two parts. The first part control the splitting methods,
-  range in ``['RO_RS','TO_LS','RO_LS','TO_RS']``. The second part(optional)
-  control the ranking mechanism, range in ``['full','uni100','uni1000','pop100','pop1000']``.
-- ``group_by_user (bool)``: Whether the users are grouped.
-  It must be ``True`` when ``eval_setting`` is in ``['RO_LS', 'TO_LS']``.
-  Defaults to ``True``.
-- ``spilt_ratio (list)``: The split ratio between train data, valid data and
-  test data. It only take effects when the first part of ``eval_setting``
-  is in ``['RO_RS', 'TO_RS']``. Defaults to ``[0.8, 0.1, 0.1]``.
-- ``leave_one_num (int)``: It only take effects when the first part of
-  ``eval_setting`` is in ``['RO_LS', 'TO_LS']``. Defaults to ``2``.
-
-Evaluation Metrics
------------------------
-
-RecBole supports both value-based and ranking-based evaluation metrics.
-
-The value-based metrics (i.e., for rating prediction) include ``RMSE``, ``MAE``,
-``AUC`` and ``LogLoss``, measuring the prediction difference between the true
-and predicted values.
-
-The ranking-based metrics (i.e., for top-k item recommendation) include the most
-common ranking-aware metrics, such as ``Recall``, ``Precision``, ``Hit``,
-``NDCG``, ``MAP`` and ``MRR``, measuring the ranking performance of the
-generated recommendation lists by an algorithm.
-
-The parameters used to control the evaluation metrics are as follows:
-
-- ``metrics (list or str)``: Evaluation metrics. Defaults to
-  ``['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']``. Range in
-  ``['Recall', 'MRR', 'NDCG', 'Hit', 'MAP', 'Precision', 'AUC',
-  'MAE', 'RMSE', 'LogLoss']``.
-- ``topk (list or int or None)``: The value of k for topk evaluation metrics.
-  Defaults to ``10``.
diff --git a/docs/source/user_guide/model/context/afm.rst b/docs/source/user_guide/model/context/afm.rst
index b67e6fa43..560d21859 100644
--- a/docs/source/user_guide/model/context/afm.rst
+++ b/docs/source/user_guide/model/context/afm.rst
@@ -69,5 +69,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/autoint.rst b/docs/source/user_guide/model/context/autoint.rst
index 664bdb281..f5a510abd 100644
--- a/docs/source/user_guide/model/context/autoint.rst
+++ b/docs/source/user_guide/model/context/autoint.rst
@@ -71,5 +71,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/dcn.rst b/docs/source/user_guide/model/context/dcn.rst
index 49206b533..8117b332f 100644
--- a/docs/source/user_guide/model/context/dcn.rst
+++ b/docs/source/user_guide/model/context/dcn.rst
@@ -87,5 +87,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/deepfm.rst b/docs/source/user_guide/model/context/deepfm.rst
index bf6817b24..958effa0f 100644
--- a/docs/source/user_guide/model/context/deepfm.rst
+++ b/docs/source/user_guide/model/context/deepfm.rst
@@ -68,5 +68,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/dien.rst b/docs/source/user_guide/model/context/dien.rst
index 0fad39609..8efa98626 100644
--- a/docs/source/user_guide/model/context/dien.rst
+++ b/docs/source/user_guide/model/context/dien.rst
@@ -79,5 +79,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/din.rst b/docs/source/user_guide/model/context/din.rst
index 90018241d..c83e33861 100644
--- a/docs/source/user_guide/model/context/din.rst
+++ b/docs/source/user_guide/model/context/din.rst
@@ -13,8 +13,8 @@ Yanghui Yan, Junqi Jin, Han Li, Kun Gai
 
 **Abstract:** Click-through rate prediction is an essential task in industrial
 applications, such as online advertising. Recently deep learning
-based models have been proposed, which follow a similar Embedding&
-MLP paradigm. In these methods large scale sparse input
+based models have been proposed, which follow a similar Embedding&MLP 
+paradigm. In these methods large scale sparse input
 features are first mapped into low dimensional embedding vectors,
 and then transformed into fixed-length vectors in a group-wise
 manner, finally concatenated together to fed into a multilayer perceptron
@@ -96,5 +96,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/dssm.rst b/docs/source/user_guide/model/context/dssm.rst
index 55da708e4..dd2641702 100644
--- a/docs/source/user_guide/model/context/dssm.rst
+++ b/docs/source/user_guide/model/context/dssm.rst
@@ -74,5 +74,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/ffm.rst b/docs/source/user_guide/model/context/ffm.rst
index 95119ae48..110787dda 100644
--- a/docs/source/user_guide/model/context/ffm.rst
+++ b/docs/source/user_guide/model/context/ffm.rst
@@ -68,6 +68,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/context/fm.rst b/docs/source/user_guide/model/context/fm.rst
index 6565fac29..9e3579434 100644
--- a/docs/source/user_guide/model/context/fm.rst
+++ b/docs/source/user_guide/model/context/fm.rst
@@ -63,5 +63,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/fnn.rst b/docs/source/user_guide/model/context/fnn.rst
index 358287123..a241201bf 100644
--- a/docs/source/user_guide/model/context/fnn.rst
+++ b/docs/source/user_guide/model/context/fnn.rst
@@ -67,5 +67,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/fwfm.rst b/docs/source/user_guide/model/context/fwfm.rst
index 15c41be3e..13a8d0017 100644
--- a/docs/source/user_guide/model/context/fwfm.rst
+++ b/docs/source/user_guide/model/context/fwfm.rst
@@ -69,6 +69,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/context/lightgbm.rst b/docs/source/user_guide/model/context/lightgbm.rst
index 7eaab47dc..152efaff4 100644
--- a/docs/source/user_guide/model/context/lightgbm.rst
+++ b/docs/source/user_guide/model/context/lightgbm.rst
@@ -47,5 +47,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/context/lr.rst b/docs/source/user_guide/model/context/lr.rst
index 77b8e615a..6eab7cd93 100644
--- a/docs/source/user_guide/model/context/lr.rst
+++ b/docs/source/user_guide/model/context/lr.rst
@@ -63,5 +63,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/nfm.rst b/docs/source/user_guide/model/context/nfm.rst
index 0c4e8472c..a5950abd9 100644
--- a/docs/source/user_guide/model/context/nfm.rst
+++ b/docs/source/user_guide/model/context/nfm.rst
@@ -71,5 +71,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/pnn.rst b/docs/source/user_guide/model/context/pnn.rst
index 75fe48d13..3824353f4 100644
--- a/docs/source/user_guide/model/context/pnn.rst
+++ b/docs/source/user_guide/model/context/pnn.rst
@@ -71,5 +71,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/context/widedeep.rst b/docs/source/user_guide/model/context/widedeep.rst
index 8428a281e..eb644640e 100644
--- a/docs/source/user_guide/model/context/widedeep.rst
+++ b/docs/source/user_guide/model/context/widedeep.rst
@@ -68,6 +68,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/context/xdeepfm.rst b/docs/source/user_guide/model/context/xdeepfm.rst
index 8efbaef0a..fe75ba189 100644
--- a/docs/source/user_guide/model/context/xdeepfm.rst
+++ b/docs/source/user_guide/model/context/xdeepfm.rst
@@ -18,7 +18,7 @@ in web-scale systems. Factorization based models, which measure
 interactions in terms of vector product, can learn patterns of combinatorial
 features automatically and generalize to unseen features
 as well. With the great success of deep neural networks (DNNs)
-in various fields, recently researchers have proposed several DNNbased
+in various fields, recently researchers have proposed several DNN-based
 factorization model to learn both low- and high-order feature
 interactions. Despite the powerful ability of learning an arbitrary
 function from data, plain DNNs generate feature interactions implicitly
@@ -97,6 +97,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/context/xgboost.rst b/docs/source/user_guide/model/context/xgboost.rst
index c290aafbb..4215a3fc7 100644
--- a/docs/source/user_guide/model/context/xgboost.rst
+++ b/docs/source/user_guide/model/context/xgboost.rst
@@ -47,5 +47,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/bpr.rst b/docs/source/user_guide/model/general/bpr.rst
index ee9c6492d..9546dfb25 100644
--- a/docs/source/user_guide/model/general/bpr.rst
+++ b/docs/source/user_guide/model/general/bpr.rst
@@ -76,5 +76,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/cdae.rst b/docs/source/user_guide/model/general/cdae.rst
index 441664d1f..51b543546 100644
--- a/docs/source/user_guide/model/general/cdae.rst
+++ b/docs/source/user_guide/model/general/cdae.rst
@@ -39,7 +39,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='CDAE', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -49,7 +49,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -73,5 +73,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/convncf.rst b/docs/source/user_guide/model/general/convncf.rst
index 36cd1303b..fe6b823b3 100644
--- a/docs/source/user_guide/model/general/convncf.rst
+++ b/docs/source/user_guide/model/general/convncf.rst
@@ -75,5 +75,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/dgcf.rst b/docs/source/user_guide/model/general/dgcf.rst
index 01f30c0c1..822282d63 100644
--- a/docs/source/user_guide/model/general/dgcf.rst
+++ b/docs/source/user_guide/model/general/dgcf.rst
@@ -106,5 +106,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/dmf.rst b/docs/source/user_guide/model/general/dmf.rst
index 6972b28fb..5c92dfb7f 100644
--- a/docs/source/user_guide/model/general/dmf.rst
+++ b/docs/source/user_guide/model/general/dmf.rst
@@ -49,7 +49,7 @@ And then:
 - The last value in ``user_hidden_size_list`` and ``item_hidden_size_list`` must be the same.
 
 - If you set ``inter_matrix_type='rating'``, the 'rating' field from \*.inter atomic files must be remained
-which means that the `rating` cannot be included in ``unload_col`` or ``unused_col``.
+  which means that the `rating` cannot be included in ``unload_col`` or ``unused_col``.
 
 Tuning Hyper Parameters
 -------------------------
@@ -77,5 +77,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/ease.rst b/docs/source/user_guide/model/general/ease.rst
index 41a264cdf..fd12ecb50 100644
--- a/docs/source/user_guide/model/general/ease.rst
+++ b/docs/source/user_guide/model/general/ease.rst
@@ -64,5 +64,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/enmf.rst b/docs/source/user_guide/model/general/enmf.rst
index 4ce17bde2..e85bce7ba 100644
--- a/docs/source/user_guide/model/general/enmf.rst
+++ b/docs/source/user_guide/model/general/enmf.rst
@@ -37,7 +37,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='ENMF', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -47,7 +47,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -75,5 +75,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/fism.rst b/docs/source/user_guide/model/general/fism.rst
index c93eaf00d..756ddd88d 100644
--- a/docs/source/user_guide/model/general/fism.rst
+++ b/docs/source/user_guide/model/general/fism.rst
@@ -78,5 +78,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/gcmc.rst b/docs/source/user_guide/model/general/gcmc.rst
index efb985579..29dd89b6b 100644
--- a/docs/source/user_guide/model/general/gcmc.rst
+++ b/docs/source/user_guide/model/general/gcmc.rst
@@ -85,5 +85,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/general/itemknn.rst b/docs/source/user_guide/model/general/itemknn.rst
index 1f63e6228..723954d9f 100644
--- a/docs/source/user_guide/model/general/itemknn.rst
+++ b/docs/source/user_guide/model/general/itemknn.rst
@@ -77,5 +77,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/lightgcn.rst b/docs/source/user_guide/model/general/lightgcn.rst
index 01127d929..1dbcc36b5 100644
--- a/docs/source/user_guide/model/general/lightgcn.rst
+++ b/docs/source/user_guide/model/general/lightgcn.rst
@@ -11,7 +11,7 @@ Introduction
 **Authors:** Xiangnan He, Kuan Deng, Xiang Wang, Yan Li, Yongdong Zhang, Meng Wang
 
 **Abstract:**
-Graph Convolution Network (GCN) has become new state-ofthe-art for collaborative filtering. Nevertheless, the reasons of
+Graph Convolution Network (GCN) has become new state-of-the-art for collaborative filtering. Nevertheless, the reasons of
 its effectiveness for recommendation are not well understood.
 Existing work that adapts GCN to recommendation lacks thorough
 ablation analyses on GCN, which is originally designed for graph
@@ -97,6 +97,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/general/line.rst b/docs/source/user_guide/model/general/line.rst
index c154154b2..55300b4a3 100644
--- a/docs/source/user_guide/model/general/line.rst
+++ b/docs/source/user_guide/model/general/line.rst
@@ -50,7 +50,7 @@ If you want to use ``HyperTuning`` to tune hyper parameters of this model, you c
 .. code:: bash
 
    learning_rate choice [0.01,0.005,0.001,0.0005,0.0001]
-   training_neg_sample_num choice [1,3,5]
+   neg_sampling choice [{'uniform':1}, {'uniform':3}, {'uniform':5}]
    second_order_loss_weight choice [0.3,0.6,1]
 
 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.
@@ -68,5 +68,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/macridvae.rst b/docs/source/user_guide/model/general/macridvae.rst
index 96b0c6db0..ced4fbb9b 100644
--- a/docs/source/user_guide/model/general/macridvae.rst
+++ b/docs/source/user_guide/model/general/macridvae.rst
@@ -28,7 +28,8 @@ of the representations to independently reflect an isolated low-level factor (e.
 the size or the color of a shirt). Empirical results show that our approach can
 achieve substantial improvement over the state-of-the-art baselines. We further
 demonstrate that the learned representations are interpretable and controllable,
-which can potentially lead to a new paradigm for recommendation where users a
+which can potentially lead to a new paradigm for recommendation where users are given 
+fine-grained control over targeted aspects of the recommendation lists.
 
 .. image:: ../../../asset/macridvae.png
     :width: 500
@@ -49,7 +50,6 @@ Running with RecBole
 - ``anneal_cap (float)`` : The super parameter of the weight of KL loss. Defaults to ``0.2``.
 - ``total_anneal_steps (int)`` : The maximum steps of anneal update. Defaults to ``200000``.
 - ``reg_weights (list)`` : L2 regularization. Defaults to ``[0.0,0.0]``.
-- ``training_neg_sample (int)`` : The negative sample num for training. Defaults to ``0``.
 
 
 **A Running Example:**
@@ -61,7 +61,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='MacridVAE', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -71,7 +71,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -98,5 +98,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/multidae.rst b/docs/source/user_guide/model/general/multidae.rst
index 0a310c700..291f7c3d3 100644
--- a/docs/source/user_guide/model/general/multidae.rst
+++ b/docs/source/user_guide/model/general/multidae.rst
@@ -24,7 +24,6 @@ Running with RecBole
 - ``latent_dimendion (int)`` : The latent dimension of auto-encoder. Defaults to ``64``.
 - ``mlp_hidden_size (list)`` : The MLP hidden layer. Defaults to ``[600]``.
 - ``dropout_prob (float)`` : The drop out probability of input. Defaults to ``0.5``.
-- ``training_neg_sample (int)`` : The negative sample num for training. Defaults to ``0``.
 
 
 **A Running Example:**
@@ -36,7 +35,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='MultiDAE', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -46,7 +45,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -72,5 +71,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/multivae.rst b/docs/source/user_guide/model/general/multivae.rst
index 618047da9..9de499f60 100644
--- a/docs/source/user_guide/model/general/multivae.rst
+++ b/docs/source/user_guide/model/general/multivae.rst
@@ -26,7 +26,6 @@ Running with RecBole
 - ``dropout_prob (float)`` : The drop out probability of input. Defaults to ``0.5``.
 - ``anneal_cap (float)`` : The super parameter of the weight of KL loss. Defaults to ``0.2``.
 - ``total_anneal_steps (int)`` : The maximum steps of anneal update. Defaults to ``200000``.
-- ``training_neg_sample (int)`` : The negative sample num for training. Defaults to ``0``.
 
 
 **A Running Example:**
@@ -38,7 +37,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='MultiVAE', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -48,7 +47,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -74,5 +73,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/nais.rst b/docs/source/user_guide/model/general/nais.rst
index 2e0f60ea7..44ff9c010 100644
--- a/docs/source/user_guide/model/general/nais.rst
+++ b/docs/source/user_guide/model/general/nais.rst
@@ -91,5 +91,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/neumf.rst b/docs/source/user_guide/model/general/neumf.rst
index 3ff4548a2..d8ba4d533 100644
--- a/docs/source/user_guide/model/general/neumf.rst
+++ b/docs/source/user_guide/model/general/neumf.rst
@@ -77,5 +77,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/ngcf.rst b/docs/source/user_guide/model/general/ngcf.rst
index b1e12ae01..f084cfdab 100644
--- a/docs/source/user_guide/model/general/ngcf.rst
+++ b/docs/source/user_guide/model/general/ngcf.rst
@@ -12,7 +12,7 @@ Introduction
 
 **Abstract:** Learning vector representations (aka. embeddings) of users and items lies at the core of modern recommender systems. Ranging from early matrix factorization to recently emerged deep learning based methods, existing efforts typically obtain a user's (or an item's) embedding by mapping from pre-existing features that describe the user (or the item), such as ID and attributes. We argue that an inherent drawback of such methods is that, the collaborative signal, which is latent in user-item interactions, is not encoded in the embedding process. As such, the resultant embeddings may not be sufficient to capture the collaborative filtering effect.
 
-In this work, we propose to integrate the user-item interactions - more specifically the bipartite graph structure - into the embedding process. We develop a new recommendation framework Neural Graph Collaborative Filtering (NGCF), which exploits the user-item graph structure by propagating embeddings on it. This leads to the expressive modeling of high-order connectivity in user-item graph, effectively injecting the collaborative signal into the embedding process in an explicit manner. We conduct extensive experiments on three public benchmarks, demonstrating significant improvements over several state-of-the-art models like HOP-Rec  and Collaborative Memory Network . Further analysis verifies the importance of embedding propagation for learning better user and item representations, justifying the rationality and effectiveness of NGCF.
+In this work, we propose to integrate the user-item interactions - more specifically the bipartite graph structure - into the embedding process. We develop a new recommendation framework Neural Graph Collaborative Filtering (NGCF), which exploits the user-item graph structure by propagating embeddings on it. This leads to the expressive modeling of high-order connectivity in user-item graph, effectively injecting the collaborative signal into the embedding process in an explicit manner. We conduct extensive experiments on three public benchmarks, demonstrating significant improvements over several state-of-the-art models like HOP-Rec and Collaborative Memory Network. Further analysis verifies the importance of embedding propagation for learning better user and item representations, justifying the rationality and effectiveness of NGCF.
 
 .. image:: ../../../asset/ngcf.jpg
     :width: 500
@@ -75,5 +75,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/nncf.rst b/docs/source/user_guide/model/general/nncf.rst
index ade50a986..e6d574ade 100644
--- a/docs/source/user_guide/model/general/nncf.rst
+++ b/docs/source/user_guide/model/general/nncf.rst
@@ -80,5 +80,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/general/pop.rst b/docs/source/user_guide/model/general/pop.rst
index 7171fe4a1..037ab2904 100644
--- a/docs/source/user_guide/model/general/pop.rst
+++ b/docs/source/user_guide/model/general/pop.rst
@@ -35,5 +35,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/ract.rst b/docs/source/user_guide/model/general/ract.rst
index 1dc0a6300..82a3076bb 100644
--- a/docs/source/user_guide/model/general/ract.rst
+++ b/docs/source/user_guide/model/general/ract.rst
@@ -29,9 +29,9 @@ Running with RecBole
 - ``critic_layers (list)`` : The layers of critic network. Defaults to ``[100,100,10]``.
 - ``metrics_k (int)`` : The parameter of NDCG for critic network training. Defaults to ``100``.
 - ``train_stage (str)`` : The training stage. Defaults to ``'actor_pretrain'``. Range in ``['actor_pretrain', 'critic_pretrain', 'finetune']``.
-- ``pretrain_epochs (int)`` : The pretrain epochs of actor pre-training or critic-pretraining. Defaults to '150'
+- ``pretrain_epochs (int)`` : The pretrain epochs of actor pre-training or critic-pretraining. Defaults to '150'.
+- ``save_step (int)`` : Save pre-trained model every ``save_step`` pre-training epochs. Defaults to ``10``.
 - ``pre_model_path (str)`` : The path of pretrained model. Defaults to ``''``.
-- ``training_neg_sample (int)`` : The negative sample num for training. Defaults to ``0``.
 
 
 **A Running Example:**
@@ -45,7 +45,7 @@ Running with RecBole
    config_dict = {
        'train_stage': 'actor_pretrain',
        'pretrain_epochs': 150,
-       'training_neg_sample_num': 0,
+       'neg_sampling': None,
    }
    run_recbole(model='RaCT', dataset='ml-100k',
         config_dict=config_dict, saved=False)
@@ -66,7 +66,7 @@ And then:
        'train_stage': 'critic_pretrain',
        'pretrain_epochs': 50,
        'pre_model_path': './saved/RaCT-ml-100k-150.pth',
-       'training_neg_sample_num': 0,
+       'neg_sampling': None,
    }
    run_recbole(model='RaCT', dataset='ml-100k',
         config_dict=config_dict, saved=False)
@@ -86,7 +86,7 @@ And then:
    config_dict = {
        'train_stage': 'finetune',
        'pre_model_path': './saved/RaCT-ml-100k-50.pth',
-       'training_neg_sample_num': 0,
+       'neg_sampling': None,
    }
    run_recbole(model='RaCT', dataset='ml-100k',
         config_dict=config_dict)
@@ -100,7 +100,7 @@ And then:
 
 **Notes:**
 
-- Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+- Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 - In the actor pre-training and critic pre-training stage, the pre-trained model would be saved , named as ``RaCT-[dataset_name]-[pretrain_epochs].pth`` (e.g. RaCT-ml-100k-100.pth) and saved to ``./saved/``.
 
@@ -133,5 +133,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/recvae.rst b/docs/source/user_guide/model/general/recvae.rst
index 0bb8b5ecb..68bff133b 100644
--- a/docs/source/user_guide/model/general/recvae.rst
+++ b/docs/source/user_guide/model/general/recvae.rst
@@ -29,7 +29,6 @@ Running with RecBole
 - ``mixture_weights (list)`` : The mixture weights of three composite priors. Defaults to ``[0.15, 0.75, 0.1]``.
 - ``n_enc_epochs (int)`` : The training times of encoder per epoch. Defaults to ``3``.
 - ``n_dec_epochs (int)`` : The training times of decoder per epoch. Defaults to ``1``.
-- ``training_neg_sample (int)`` : The negative sample num for training. Defaults to ``0``.
 
 
 **A Running Example:**
@@ -41,7 +40,7 @@ Write the following code to a python file, such as `run.py`
    from recbole.quick_start import run_recbole
 
    parameter_dict = {
-      'training_neg_sample_num': 0 
+      'neg_sampling': None,
    }
    run_recbole(model='RecVAE', dataset='ml-100k', config_dict=parameter_dict)
 
@@ -51,7 +50,7 @@ And then:
 
    python run.py
 
-**Note**: Because this model is a non-sampling model, so you must set ``training_neg_sample=0`` when you run this model. 
+**Note**: Because this model is a non-sampling model, so you must set ``neg_sampling=None`` when you run this model.
 
 Tuning Hyper Parameters
 -------------------------
@@ -78,5 +77,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/slimelastic.rst b/docs/source/user_guide/model/general/slimelastic.rst
index be1583616..b80f09287 100644
--- a/docs/source/user_guide/model/general/slimelastic.rst
+++ b/docs/source/user_guide/model/general/slimelastic.rst
@@ -71,5 +71,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/general/spectralcf.rst b/docs/source/user_guide/model/general/spectralcf.rst
index b222c6f14..0d2735c90 100644
--- a/docs/source/user_guide/model/general/spectralcf.rst
+++ b/docs/source/user_guide/model/general/spectralcf.rst
@@ -76,6 +76,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/knowledge/cfkg.rst b/docs/source/user_guide/model/knowledge/cfkg.rst
index 220897e92..2bd5455fc 100644
--- a/docs/source/user_guide/model/knowledge/cfkg.rst
+++ b/docs/source/user_guide/model/knowledge/cfkg.rst
@@ -85,5 +85,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/knowledge/cke.rst b/docs/source/user_guide/model/knowledge/cke.rst
index 336542f4c..c2d50057b 100644
--- a/docs/source/user_guide/model/knowledge/cke.rst
+++ b/docs/source/user_guide/model/knowledge/cke.rst
@@ -84,5 +84,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/knowledge/kgat.rst b/docs/source/user_guide/model/knowledge/kgat.rst
index 84c6aac65..e9a66108c 100644
--- a/docs/source/user_guide/model/knowledge/kgat.rst
+++ b/docs/source/user_guide/model/knowledge/kgat.rst
@@ -105,5 +105,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/knowledge/kgcn.rst b/docs/source/user_guide/model/knowledge/kgcn.rst
index 79a9fdc15..cea78c861 100644
--- a/docs/source/user_guide/model/knowledge/kgcn.rst
+++ b/docs/source/user_guide/model/knowledge/kgcn.rst
@@ -81,6 +81,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/knowledge/kgnnls.rst b/docs/source/user_guide/model/knowledge/kgnnls.rst
index 915633f47..2967a46e7 100644
--- a/docs/source/user_guide/model/knowledge/kgnnls.rst
+++ b/docs/source/user_guide/model/knowledge/kgnnls.rst
@@ -81,6 +81,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/knowledge/ktup.rst b/docs/source/user_guide/model/knowledge/ktup.rst
index b3ed4b760..5fe623eac 100644
--- a/docs/source/user_guide/model/knowledge/ktup.rst
+++ b/docs/source/user_guide/model/knowledge/ktup.rst
@@ -99,5 +99,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/knowledge/mkr.rst b/docs/source/user_guide/model/knowledge/mkr.rst
index 62633f5fb..6e23bca3b 100644
--- a/docs/source/user_guide/model/knowledge/mkr.rst
+++ b/docs/source/user_guide/model/knowledge/mkr.rst
@@ -74,5 +74,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/knowledge/ripplenet.rst b/docs/source/user_guide/model/knowledge/ripplenet.rst
index f1fadbd28..df76cae81 100644
--- a/docs/source/user_guide/model/knowledge/ripplenet.rst
+++ b/docs/source/user_guide/model/knowledge/ripplenet.rst
@@ -12,7 +12,7 @@ Introduction
 
 **Abstract:** To address the sparsity and cold start problem of collaborative filtering, researchers usually make use of side information, such as social
 networks or item attributes, to improve recommendation performance. This paper considers the knowledge graph as the source of
-side information. To address the limitations of existing embeddingbased and path-based methods for knowledge-graph-aware recommendation, we propose RippleNet, an end-to-end framework that
+side information. To address the limitations of existing embedding-based and path-based methods for knowledge-graph-aware recommendation, we propose RippleNet, an end-to-end framework that
 naturally incorporates the knowledge graph into recommender
 systems. Similar to actual ripples propagating on the water, RippleNet stimulates the propagation of user preferences over the set
 of knowledge entities by automatically and iteratively extending a
@@ -65,7 +65,7 @@ If you want to use ``HyperTuning`` to tune hyper parameters of this model, you c
 
    learning_rate choice [0.01,0.005,0.001,0.0005,0.0001]
    n_memory choice [4, 8. 16. 32]
-   training_neg_sample_num choice [1, 2, 5, 10]
+   neg_sampling choice [{'uniform':1}, {'uniform':2}, {'uniform':5}, {'uniform':10}]
 
 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.
 
@@ -82,5 +82,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/bert4rec.rst b/docs/source/user_guide/model/sequential/bert4rec.rst
index f6c6210ae..39f86546f 100644
--- a/docs/source/user_guide/model/sequential/bert4rec.rst
+++ b/docs/source/user_guide/model/sequential/bert4rec.rst
@@ -47,7 +47,7 @@ Running with RecBole
 - ``layer_norm_eps (float)`` : A value added to the denominator for numerical stability. Defaults to ``1e-12``.
 - ``initializer_range (float)`` : The standard deviation for normal initialization. Defaults to ``0.02``.
 - ``mask_ratio (float)`` : The probability for a item replaced by MASK token. Defaults to ``0.2``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform':1}" ``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -58,7 +58,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='BERT4Rec', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='BERT4Rec', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -94,5 +97,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/caser.rst b/docs/source/user_guide/model/sequential/caser.rst
index c502e0299..e5bf9450a 100644
--- a/docs/source/user_guide/model/sequential/caser.rst
+++ b/docs/source/user_guide/model/sequential/caser.rst
@@ -10,7 +10,7 @@ Introduction
 
 **Authors:** Jiaxi Tang, Ke Wang
 
-**Abstract:**  Top-N sequential recommendation models each user as a sequence of items interacted in the past and aims to predict top-N ranked items that a user will likely interact in a “near future”. The order of interaction implies that sequential patterns play an important role where more recent items in a sequence have a larger impact on the next item. In this paper, we propose a Convolutional Sequence Embedding Recommendation Model (Caser) as a solution to address this requirement. The idea is to embed a sequence of recent items into an “image” in the time and latent spaces and learn sequential patterns as local features of the image using convolutional filters. This approach provides a unified and flexible network structure for capturing both general preferences and sequential patterns. The ex- periments on public data sets demonstrated that Caser consistently outperforms state-of-the-art sequential recommendation methods on a variety of common evaluation metrics.
+**Abstract:**  Top-N sequential recommendation models each user as a sequence of items interacted in the past and aims to predict top-N ranked items that a user will likely interact in a “near future”. The order of interaction implies that sequential patterns play an important role where more recent items in a sequence have a larger impact on the next item. In this paper, we propose a Convolutional Sequence Embedding Recommendation Model (Caser) as a solution to address this requirement. The idea is to embed a sequence of recent items into an “image” in the time and latent spaces and learn sequential patterns as local features of the image using convolutional filters. This approach provides a unified and flexible network structure for capturing both general preferences and sequential patterns. The experiments on public data sets demonstrated that Caser consistently outperforms state-of-the-art sequential recommendation methods on a variety of common evaluation metrics.
 
 .. image:: ../../../asset/caser.png
     :width: 600
@@ -26,7 +26,7 @@ Running with RecBole
 - ``n_v (int)`` : The number of vertical Convolutional filters. Defaults to ``8``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``1e-4``.
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.4``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform':1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -36,7 +36,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='Caser', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='Caser', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -74,6 +77,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/fdsa.rst b/docs/source/user_guide/model/sequential/fdsa.rst
index 90ee4aec5..65a895ba8 100644
--- a/docs/source/user_guide/model/sequential/fdsa.rst
+++ b/docs/source/user_guide/model/sequential/fdsa.rst
@@ -45,7 +45,7 @@ Running with RecBole
 - ``initializer_range (float)`` : The standard deviation for normal initialization. Defaults to ``0.02``.
 - ``selected_features (list)`` : The list of selected item features. Defaults to ``['class']`` for ml-100k dataset.
 - ``pooling_mode (str)``: The intra-feature pooling mode. Defaults to ``'mean'``. Range in ``['max', 'mean', 'sum']``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -56,7 +56,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='FDSA', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='FDSA', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -96,5 +99,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/fossil.rst b/docs/source/user_guide/model/sequential/fossil.rst
index f05e5dd71..3beef6145 100644
--- a/docs/source/user_guide/model/sequential/fossil.rst
+++ b/docs/source/user_guide/model/sequential/fossil.rst
@@ -13,8 +13,8 @@ Introduction
 **Abstract:**  Abstract—Predicting personalized sequential behavior is a
 key task for recommender systems. In order to predict user
 actions such as the next product to purchase, movie to watch,
-or place to visit, it is essential to take into account both long-
-term user preferences and sequential patterns (i.e., short-term
+or place to visit, it is essential to take into account both long-term 
+user preferences and sequential patterns (i.e., short-term
 dynamics). Matrix Factorization and Markov Chain methods
 have emerged as two separate but powerful paradigms for
 modeling the two respectively. Combining these ideas has led
@@ -46,7 +46,7 @@ Running with RecBole
 - ``order_len (int)`` : The last N items . Defaults to ``3``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``0.00``.
 - ``alpha (float)`` : The parameter of alpha in calculate the similarity. Defaults to ``0.6``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -56,7 +56,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='FOSSIL', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='FOSSIL', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -96,6 +99,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/fpmc.rst b/docs/source/user_guide/model/sequential/fpmc.rst
index 6f759d8f5..c03bd537f 100644
--- a/docs/source/user_guide/model/sequential/fpmc.rst
+++ b/docs/source/user_guide/model/sequential/fpmc.rst
@@ -62,7 +62,7 @@ And then:
 
 **Notes:**
 
-- Different from other sequential models, FPMC must be optimized in pair-wise way using negative sampling, so it needs ``training_neg_sample_num=1``.
+- Different from other sequential models, FPMC must be optimized in pair-wise way using negative sampling, so it needs ``neg_sampling="{'uniform': 1}"``.
 
 Tuning Hyper Parameters
 -------------------------
@@ -88,6 +88,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/gcsan.rst b/docs/source/user_guide/model/sequential/gcsan.rst
index 3707767d4..be79f495f 100644
--- a/docs/source/user_guide/model/sequential/gcsan.rst
+++ b/docs/source/user_guide/model/sequential/gcsan.rst
@@ -15,7 +15,7 @@ anonymous sessions, is a key task in many online
 services (e:g:; e-commerce, media streaming). Recently, Self-Attention Network (SAN) has achieved
 significant success in various sequence modeling
 tasks without using either recurrent or convolutional network. However, SAN lacks local dependencies that exist over adjacent items and limits its capacity for learning contextualized representations of items in sequences. In this paper, we propose a graph contextualized self-attention model
-(GC-SAN), which utilizes both graph neural network and self-attention mechanism, for sessionbased recommendation. In GC-SAN, we dynamically construct a graph structure for session sequences and capture rich local dependencies via graph neural network (GNN). Then each session learns long-range dependencies by applying
+(GC-SAN), which utilizes both graph neural network and self-attention mechanism, for session-based recommendation. In GC-SAN, we dynamically construct a graph structure for session sequences and capture rich local dependencies via graph neural network (GNN). Then each session learns long-range dependencies by applying
 the self-attention mechanism. Finally, each session
 is represented as a linear combination of the global
 preference and the current interest of that session.
@@ -43,7 +43,7 @@ Running with RecBole
 - ``step (int)`` : The number of layers in GNN. Defaults to ``1``.
 - ``weight (float)`` : The weight parameter controls the contribution of self-attention representation and the last-clicked action, the original paper suggests that setting w to a value of 0.4 to 0.8 is more desirable. Defaults to ``0.6``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``[5e-5]``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -53,7 +53,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='GCSAN', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='GCSAN', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -97,5 +100,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/sequential/gru4rec.rst b/docs/source/user_guide/model/sequential/gru4rec.rst
index 8139db4e6..a89860757 100644
--- a/docs/source/user_guide/model/sequential/gru4rec.rst
+++ b/docs/source/user_guide/model/sequential/gru4rec.rst
@@ -33,7 +33,7 @@ Running with RecBole
 - ``hidden_size (int)`` : The number of features in the hidden state. Defaults to ``128``.
 - ``num_layers (int)`` : The number of layers in GRU. Defaults to ``1``.
 - ``dropout_prob (float)``: The dropout rate. Defaults to ``0.3``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -44,7 +44,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='GRU4Rec', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='GRU4Rec', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -79,5 +82,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/sequential/gru4recf.rst b/docs/source/user_guide/model/sequential/gru4recf.rst
index 488546ba8..71b341753 100644
--- a/docs/source/user_guide/model/sequential/gru4recf.rst
+++ b/docs/source/user_guide/model/sequential/gru4recf.rst
@@ -42,7 +42,7 @@ Running with RecBole
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.3``.
 - ``selected_features (list)`` : The list of selected item features. Defaults to ``['class']`` for ml-100k dataset.
 - ``pooling_mode (str)`` : The intra-feature pooling mode. Defaults to ``'sum'``. Range in ``['max', 'mean', 'sum']``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -53,7 +53,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='GRU4RecF', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='GRU4RecF', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -91,5 +94,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/sequential/gru4reckg.rst b/docs/source/user_guide/model/sequential/gru4reckg.rst
index f1653cabf..4273eaf2f 100644
--- a/docs/source/user_guide/model/sequential/gru4reckg.rst
+++ b/docs/source/user_guide/model/sequential/gru4reckg.rst
@@ -16,7 +16,7 @@ Running with RecBole
 - ``num_layers (int)`` : The number of layers in GRU. Defaults to ``1``.
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.1``.
 - ``freeze_kg (bool)`` : Whether to freeze the pre-trained knowledge embedding feature. Defaults to ``True``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -27,7 +27,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='GRU4RecKG', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='GRU4RecKG', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -46,9 +49,7 @@ And then:
             kg: [head_id, relation_id, tail_id]
             link: [item_id, entity_id]
             ent_feature: [ent_id, ent_vec]
-        fields_in_same_space: [
-            [ent_id, entity_id]
-        ]
+        alias_of_entity_id: [ent_id]
         preload_weight:
             ent_id: ent_vec
         additional_feat_suffix: [ent_feature]
@@ -84,5 +85,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/hgn.rst b/docs/source/user_guide/model/sequential/hgn.rst
index 630fcb445..0610731db 100644
--- a/docs/source/user_guide/model/sequential/hgn.rst
+++ b/docs/source/user_guide/model/sequential/hgn.rst
@@ -15,10 +15,10 @@ in many recommender systems, where the items that users will
 interact may largely depend on those items that users just accessed
 recently. However, with the tremendous increase of users and items,
 sequential recommender systems still face several challenging problems: (1) the hardness of modeling the long-term user interests from
-sparse implicit feedback; (2) the difficulty of capturing the short-
-term user interests given several items the user just accessed. To
-cope with these challenges, we propose a hierarchical gating net-
-work (HGN), integrated with the Bayesian Personalized Ranking
+sparse implicit feedback; (2) the difficulty of capturing the short-term 
+user interests given several items the user just accessed. To
+cope with these challenges, we propose a hierarchical gating network 
+(HGN), integrated with the Bayesian Personalized Ranking
 (BPR) to capture both the long-term and short-term user interests.
 Our HGN consists of a feature gating module, an instance gating
 module, and an item-item product module. In particular, our feature
@@ -42,7 +42,7 @@ Running with RecBole
 - ``embedding_size (int)`` : The embedding size of users and items. Defaults to ``64``.
 - ``pooling_type (str)`` : The type of pooling include average pooling and max pooling . Defaults to ``average``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``[0.00,0.00]``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -91,6 +91,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/hrm.rst b/docs/source/user_guide/model/sequential/hrm.rst
index 766d9b21a..3c2f1761f 100644
--- a/docs/source/user_guide/model/sequential/hrm.rst
+++ b/docs/source/user_guide/model/sequential/hrm.rst
@@ -10,18 +10,18 @@ Introduction
 
 **Authors:** Pengfei Wang
 
-**Abstract:**  Next basket recommendation is a crucial task in market bas-
-ket analysis. Given a user’s purchase history, usually a sequence of transaction data, one attempts to build a recom-
-mender that can predict the next few items that the us-
-er most probably would like. Ideally, a good recommender
-should be able to explore the sequential behavior (i.e., buy-
-ing one item leads to buying another next), as well as ac-
-count for users’ general taste (i.e., what items a user is typically interested in) for recommendation. Moreover, these
-two factors may interact with each other to influence users’
-next purchase. To tackle the above problems, in this pa-
-per, we introduce a novel recommendation approach, name-
-ly hierarchical representation model (HRM). HRM can well
-capture both sequential behavior and users’ general taste by
+**Abstract:**  Next basket recommendation is a crucial task in market basket 
+analysis. Given a user's purchase history, usually a sequence of transaction data, one attempts to build a 
+recommender that can predict the next few items that the user 
+most probably would like. Ideally, a good recommender
+should be able to explore the sequential behavior (i.e., buying 
+one item leads to buying another next), as well as account 
+for users' general taste (i.e., what items a user is typically interested in) for recommendation. Moreover, these
+two factors may interact with each other to influence users'
+next purchase. To tackle the above problems, in this paper, 
+we introduce a novel recommendation approach, namely 
+hierarchical representation model (HRM). HRM can well
+capture both sequential behavior and users' general taste by
 involving transaction and user representations in prediction.
 Meanwhile, the flexibility of applying different aggregation
 operations, especially nonlinear operations, on representations allows us to model complicated interactions among
@@ -46,7 +46,7 @@ Running with RecBole
 - ``pooling_type_layer_1 (str)`` : The type of pooling in the first floor include average pooling and max pooling . Defaults to ``max``.
 - ``pooling_type_layer_2 (str)`` : The type of pooling in the second floor include average pooling and max pooling . Defaults to ``max``.
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.2``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -56,7 +56,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='HRM', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='HRM', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -97,6 +100,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/ksr.rst b/docs/source/user_guide/model/sequential/ksr.rst
index 8085e71b4..de86f2bfb 100644
--- a/docs/source/user_guide/model/sequential/ksr.rst
+++ b/docs/source/user_guide/model/sequential/ksr.rst
@@ -27,7 +27,7 @@ Running with RecBole
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.1``.
 - ``freeze_kg (bool)`` : Whether to freeze the pre-trained knowledge embedding feature. Defaults to ``True``.
 - ``gamma (float)`` : The scaling factor used in read operation when calculating the attention weights of user preference on attributes. Defaults to ``10``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -38,7 +38,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='KSR', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='KSR', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -58,10 +61,8 @@ And then:
             link: [item_id, entity_id]
             ent_feature: [ent_id, ent_vec]
             rel_feature: [rel_id, rel_vec]
-        fields_in_same_space: [
-            [ent_id, entity_id]
-            [rel_id, relation_id]
-        ]
+        alias_of_entity_id: [ent_id]
+        alias_of_relation_id: [rel_id]
         preload_weight:
             ent_id: ent_vec
             rel_id: rel_vec
@@ -98,5 +99,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/narm.rst b/docs/source/user_guide/model/sequential/narm.rst
index d9bd60460..b29475bea 100644
--- a/docs/source/user_guide/model/sequential/narm.rst
+++ b/docs/source/user_guide/model/sequential/narm.rst
@@ -10,7 +10,7 @@ Introduction
 
 **Authors:** Jing Li, Pengjie Ren, Zhumin Chen, Zhaochun Ren, Tao Lian, Jun Ma
 
-**Abstract:**  Given e-commerce scenarios that user profiles are invisible, sessionbased recommendation is proposed to generate recommendation
+**Abstract:**  Given e-commerce scenarios that user profiles are invisible, session-based recommendation is proposed to generate recommendation
 results from short sessions. Previous work only considers the
 user’s sequential behavior in the current session, whereas the
 user’s main purpose in the current session is not emphasized. In
@@ -43,7 +43,7 @@ Running with RecBole
 - ``n_layers (int)`` : The number of layers in GRU. Defaults to ``1``.
 - ``dropout_probs (list of float)`` : The dropout rate, there are two values,
   the former is for embedding layer and the latter is for concatenation of the vector obtained by the local encoder and the vector obtained by the global encoder. Defaults to ``[0.25,0.5]``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -53,7 +53,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='NARM', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='NARM', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -88,5 +91,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/nextitnet.rst b/docs/source/user_guide/model/sequential/nextitnet.rst
index 2dcd97da5..b556512f2 100644
--- a/docs/source/user_guide/model/sequential/nextitnet.rst
+++ b/docs/source/user_guide/model/sequential/nextitnet.rst
@@ -10,7 +10,7 @@ Introduction
 
 **Authors:** Fajie Yuan, Alexandros Karatzoglou, Ioannis Arapakis, Joemon M Jose, Xiangnan He
 
-**Abstract:**  Convolutional Neural Networks (CNNs) have been recently intro- duced in the domain of session-based next item recommendation. An ordered collection of past items the user has interacted with in a session (or sequence) are embedded into a 2-dimensional latent matrix, and treated as an image. The convolution and pooling opera- tions are then applied to the mapped item embeddings. In this paper, we first examine the typical session-based CNN recommender and show that both the generative model and network architecture are suboptimal when modeling long-range dependencies in the item sequence. To address the issues, we introduce a simple, but very effective generative model that is capable of learning high-level representation from both short- and long-range item dependencies. The network architecture of the proposed model is formed of a stack of holed convolutional layers, which can efficiently increase the receptive fields without relying on the pooling operation. Another contribution is the effective use of residual block structure in recom- mender systems, which can ease the optimization for much deeper networks. The proposed generative model attains state-of-the-art accuracy with less training time in the next item recommendation task. It accordingly can be used as a powerful recommendation baseline to beat in future, especially when there are long sequences of user feedback.
+**Abstract:**  Convolutional Neural Networks (CNNs) have been recently introduced in the domain of session-based next item recommendation. An ordered collection of past items the user has interacted with in a session (or sequence) are embedded into a 2-dimensional latent matrix, and treated as an image. The convolution and pooling operations are then applied to the mapped item embeddings. In this paper, we first examine the typical session-based CNN recommender and show that both the generative model and network architecture are suboptimal when modeling long-range dependencies in the item sequence. To address the issues, we introduce a simple, but very effective generative model that is capable of learning high-level representation from both short- and long-range item dependencies. The network architecture of the proposed model is formed of a stack of holed convolutional layers, which can efficiently increase the receptive fields without relying on the pooling operation. Another contribution is the effective use of residual block structure in recommender systems, which can ease the optimization for much deeper networks. The proposed generative model attains state-of-the-art accuracy with less training time in the next item recommendation task. It accordingly can be used as a powerful recommendation baseline to beat in future, especially when there are long sequences of user feedback.
 
 .. image:: ../../../asset/nextitnet.png
     :width: 600
@@ -26,7 +26,7 @@ Running with RecBole
 - ``block_num (int)`` : The number of residual blocks. Defaults to ``5``.
 - ``dilations (list)`` : Control the spacing between the kernel points. Defaults to ``[1,4]``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``1e-5``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -36,7 +36,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='NextItNet', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='NextItNet', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -75,5 +78,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/sequential/npe.rst b/docs/source/user_guide/model/sequential/npe.rst
index 0cf9ca655..dfd5efe37 100644
--- a/docs/source/user_guide/model/sequential/npe.rst
+++ b/docs/source/user_guide/model/sequential/npe.rst
@@ -21,8 +21,8 @@ for cold-users and can learn effective representations of items. It models a use
 in two terms: the personal preference of the user
 for the item, and the relationships between this
 item and other items clicked by the user. We show
-that NPE outperforms competing methods for top-
-N recommendations, specially for cold-user recommendations. We also performed a qualitative analysis that shows the effectiveness
+that NPE outperforms competing methods for top-N 
+recommendations, specially for cold-user recommendations. We also performed a qualitative analysis that shows the effectiveness
 of the representations learned by the model.
 
 .. image:: ../../../asset/npe.jpg
@@ -36,7 +36,7 @@ Running with RecBole
 
 - ``embedding_size (int)`` : The embedding size of users and items. Defaults to ``64``.
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.3``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -46,7 +46,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='NPE', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='NPE', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -84,6 +87,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/repeatnet.rst b/docs/source/user_guide/model/sequential/repeatnet.rst
index 47dcc5325..bf05c5ae6 100644
--- a/docs/source/user_guide/model/sequential/repeatnet.rst
+++ b/docs/source/user_guide/model/sequential/repeatnet.rst
@@ -11,19 +11,19 @@ Introduction
 **Authors:** Pengjie Ren, Zhumin Chen, Jing Li, Zhaochun Ren, Jun Ma, Maarten de Rijke
 
 **Abstract:**  Recurrent neural networks for session-based recommendation have attracted a lot of attention recently because of
-their promising performance. repeat consumption is a com-mon phenomenon in many recommendation scenarios (e.g.,e-commerce, music, and TV program recommendations),
+their promising performance. repeat consumption is a common phenomenon in many recommendation scenarios (e.g.,e-commerce, music, and TV program recommendations),
 where the same item is re-consumed repeatedly over time.
 However, no previous studies have emphasized repeat consumption with neural networks. An effective neural approach
 is needed to decide when to perform repeat recommendation. In this paper, we incorporate a repeat-explore mechanism into neural networks and propose a new model, called
-RepeatNet, with an encoder-decoder structure. RepeatNet integrates a regular neural recommendation approach in the de-
-coder with a new repeat recommendation mechanism that can
+RepeatNet, with an encoder-decoder structure. RepeatNet integrates a regular neural recommendation approach in the decoder 
+with a new repeat recommendation mechanism that can
 choose items from a user’s history and recommends them at
 the right time. We report on extensive experiments on three
 benchmark datasets. RepeatNet outperforms state-of-the-art
 baselines on all three datasets in terms of MRR and Recall.
 Furthermore, as the dataset size and the repeat ratio increase,
-the improvements of RepeatNet over the baselines also in-
-crease, which demonstrates its advantage in handling repeat
+the improvements of RepeatNet over the baselines also increase, 
+which demonstrates its advantage in handling repeat
 recommendation scenarios.
 
 .. image:: ../../../asset/repeatnet.jpg
@@ -39,7 +39,7 @@ Running with RecBole
 - ``hidden_size (int)`` : The number of features in the hidden state. Defaults to ``64``.
 - ``joint_train (bool)`` : The indicator whether the train loss should add the repeat_explore_loss. Defaults to ``False``.
 - ``dropout_prob (float)`` : The dropout rate. Defaults to ``0.5``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -49,7 +49,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='RepeatNet', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='RepeatNet', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -89,6 +92,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/s3rec.rst b/docs/source/user_guide/model/sequential/s3rec.rst
index db93fa360..99b4ca8f2 100644
--- a/docs/source/user_guide/model/sequential/s3rec.rst
+++ b/docs/source/user_guide/model/sequential/s3rec.rst
@@ -6,7 +6,7 @@ Introduction
 
 `[paper] <https://dl.acm.org/doi/abs/10.1145/3340531.3411954>`_
 
-**Title:** S^3-Rec: Self-Supervised Learning for Sequential
+**Title:** S<sup>3</sup>-Rec: Self-Supervised Learning for Sequential
 Recommendation with Mutual Information Maximization
 
 **Authors:** Kun Zhou, Hui Wang, Wayne Xin Zhao, Yutao Zhu, Sirui Wang, Fuzheng Zhang, Zhongyuan Wang, Ji-Rong Wen
@@ -17,7 +17,7 @@ trained with this loss is prone to suffer from data sparsity problem.
 Since it overemphasizes the final performance, the association or
 fusion between context data and sequence data has not been well
 captured and utilized for sequential recommendation.
-To tackle this problem, we propose the model S3-Rec, which
+To tackle this problem, we propose the model S<sup>3</sup>-Rec, which
 stands for Self-Supervised learning for Sequential Recommendation,
 based on the self-attentive neural architecture. The main idea of
 our approach is to utilize the intrinsic data correlation to derive
@@ -58,9 +58,10 @@ Running with RecBole
 - ``sp_weight (float)`` : The weight for Segment Prediction loss. Defaults to ``0.5``.
 - ``train_stage (str)`` : The training stage. Defaults to ``'pretrain'``. Range in ``['pretrain', 'finetune']``.
 - ``item_attribute (str)`` : The item features used as attributes for pre-training. Defaults to ``'class'`` for ml-100k dataset.
+- ``pretrain_epochs (int)`` : The epochs of pre-training. Defaults to '500'.
 - ``save_step (int)`` : Save pre-trained model every ``save_step`` pre-training epochs. Defaults to ``10``.
 - ``pre_model_path (str)`` : The path of pretrained model. Defaults to ``''``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -93,6 +94,7 @@ And then:
    config_dict = {
        'train_stage': 'finetune',
        'pre_model_path': './saved/S3Rec-ml-100k-100.pth',
+       'neg_sampling': None
    }
    run_recbole(model='S3Rec', dataset='ml-100k',
         config_dict=config_dict)
@@ -125,7 +127,7 @@ Then, with the source code of RecBole (you can download it from GitHub), you can
 
 .. code:: bash
 
-	python run_hyper.py --model=[model_name] --dataset=[dataset_name] --config_files=[config_files_path] --params_file=hyper.test
+    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`.
 
@@ -134,5 +136,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model/sequential/sasrec.rst b/docs/source/user_guide/model/sequential/sasrec.rst
index b67d2f3f0..e5037fd0c 100644
--- a/docs/source/user_guide/model/sequential/sasrec.rst
+++ b/docs/source/user_guide/model/sequential/sasrec.rst
@@ -46,7 +46,7 @@ Running with RecBole
 - ``hidden_act (str)`` : The activation function in feed-forward layer. Defaults to ``'gelu'``. Range in ``['gelu', 'relu', 'swish', 'tanh', 'sigmoid']``.
 - ``layer_norm_eps (float)`` : A value added to the denominator for numerical stability, Defaults to ``1e-12``.
 - ``initializer_range (float)`` : The standard deviation for normal initialization. Defaults to 0.02``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -57,7 +57,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='SASRec', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='SASRec', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -93,5 +96,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/sasrecf.rst b/docs/source/user_guide/model/sequential/sasrecf.rst
index ecf8bab8a..966d4642e 100644
--- a/docs/source/user_guide/model/sequential/sasrecf.rst
+++ b/docs/source/user_guide/model/sequential/sasrecf.rst
@@ -22,7 +22,7 @@ Running with RecBole
 - ``initializer_range (float)`` : The standard deviation for normal initialization. Defaults to ``0.02``.
 - ``selected_features (list)`` : The list of selected item features. Defaults to ``['class']`` for ml-100k dataset.
 - ``pooling_mode (str)`` : intra-feature pooling mode. Defaults to ``'sum'``. Range in ``['max', 'mean', 'sum']``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 
 **A Running Example:**
@@ -33,7 +33,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='SASRecF', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='SASRecF', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -73,5 +76,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
\ No newline at end of file
diff --git a/docs/source/user_guide/model/sequential/shan.rst b/docs/source/user_guide/model/sequential/shan.rst
index 6e97a1b0d..8cbe68c45 100644
--- a/docs/source/user_guide/model/sequential/shan.rst
+++ b/docs/source/user_guide/model/sequential/shan.rst
@@ -10,17 +10,17 @@ Introduction
 
 **Authors:** Ying, H
 
-**Abstract:**  With a large amount of user activity data accumulated, it is crucial to exploit user sequential behavior for sequential recommendations. Convention-
-ally, user general taste and recent demand are combined to promote recommendation performances.
+**Abstract:**  With a large amount of user activity data accumulated, it is crucial to exploit user sequential behavior for sequential recommendations. Conventionally, 
+user general taste and recent demand are combined to promote recommendation performances.
 However, existing methods often neglect that user
 long-term preference keep evolving over time, and
 building a static representation for user general
-taste may not adequately reflect the dynamic characters. Moreover, they integrate user-item or item-
-item interactions through a linear way which lim-
-its the capability of model. To this end, in this
+taste may not adequately reflect the dynamic characters. Moreover, they integrate user-item or item-item 
+interactions through a linear way which limits 
+the capability of model. To this end, in this
 paper, we propose a novel two-layer hierarchical
-attention network, which takes the above proper-
-ties into account, to recommend the next item user
+attention network, which takes the above properties 
+into account, to recommend the next item user
 might be interested. Specifically, the first attention
 layer learns user long-term preferences based on
 the historical purchased item representation, while
@@ -42,7 +42,7 @@ Running with RecBole
 - ``embedding_size (int)`` : The embedding size of users and items. Defaults to ``64``.
 - ``short_item_length (int)`` : The last N items . Defaults to ``2``.
 - ``reg_weight (float)`` : The L2 regularization weight. Defaults to ``[0.01,0.0001]``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -52,7 +52,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='SHAN', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='SHAN', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -91,6 +94,6 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
diff --git a/docs/source/user_guide/model/sequential/srgnn.rst b/docs/source/user_guide/model/sequential/srgnn.rst
index 64bdfb9a4..4eec2f093 100644
--- a/docs/source/user_guide/model/sequential/srgnn.rst
+++ b/docs/source/user_guide/model/sequential/srgnn.rst
@@ -35,7 +35,7 @@ Running with RecBole
 
 - ``embedding_size (int)`` : The embedding size of items. Defaults to ``64``.
 - ``step (int)`` : The number of layers in GNN. Defaults to ``1``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -45,7 +45,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='SRGNN', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='SRGNN', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -78,7 +81,7 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
 
diff --git a/docs/source/user_guide/model/sequential/stamp.rst b/docs/source/user_guide/model/sequential/stamp.rst
index 448c68745..2a390e53e 100644
--- a/docs/source/user_guide/model/sequential/stamp.rst
+++ b/docs/source/user_guide/model/sequential/stamp.rst
@@ -38,7 +38,7 @@ Running with RecBole
 **Model Hyper-Parameters:**
 
 - ``embedding_size (int)`` : The embedding size of items. Defaults to ``64``.
-- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``training_neg_sample_num = 1``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
+- ``loss_type (str)`` : The type of loss function. If it set to ``'CE'``, the training task is regarded as a multi-classification task and the target item is the ground truth. In this way, negative sampling is not needed. If it set to ``'BPR'``, the training task will be optimized in the pair-wise way, which maximize the difference between positive item and negative item. In this way, negative sampling is necessary, such as setting ``--neg_sampling="{'uniform': 1}"``. Defaults to ``'CE'``. Range in ``['BPR', 'CE']``.
 
 **A Running Example:**
 
@@ -48,7 +48,10 @@ Write the following code to a python file, such as `run.py`
 
    from recbole.quick_start import run_recbole
 
-   run_recbole(model='STAMP', dataset='ml-100k')
+   parameter_dict = {
+      'neg_sampling': None,
+   }
+   run_recbole(model='STAMP', dataset='ml-100k', config_dict=parameter_dict)
 
 And then:
 
@@ -81,7 +84,7 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
 
 
diff --git a/docs/source/user_guide/model/sequential/transrec.rst b/docs/source/user_guide/model/sequential/transrec.rst
index 5e6839b5d..2c20a6521 100644
--- a/docs/source/user_guide/model/sequential/transrec.rst
+++ b/docs/source/user_guide/model/sequential/transrec.rst
@@ -53,7 +53,7 @@ And then:
 
 **Notes:**
 
-- Different from other sequential models, TransRec must be optimized in pair-wise way using negative sampling, so it needs ``training_neg_sample_num=1``.
+- Different from other sequential models, TransRec must be optimized in pair-wise way using negative sampling, so it needs ``neg_sampling={'uniform': 1}``.
 
 Tuning Hyper Parameters
 -------------------------
@@ -80,5 +80,5 @@ 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/evaluation_support`
+- :doc:`../../../user_guide/train_eval_intro`
 - :doc:`../../../user_guide/usage`
diff --git a/docs/source/user_guide/model_intro.rst b/docs/source/user_guide/model_intro.rst
index fcdadef90..6933277e9 100644
--- a/docs/source/user_guide/model_intro.rst
+++ b/docs/source/user_guide/model_intro.rst
@@ -1,11 +1,14 @@
 Model Introduction
 =====================
-We implement 65 recommendation models covering general recommendation, sequential recommendation,
+We implement 73 recommendation models covering general recommendation, sequential recommendation,
 context-aware recommendation and knowledge-based recommendation. A brief introduction to these models are as follows:
 
 
 General Recommendation
 --------------------------
+In the class of general recommendation, the interaction of users and items(.inter file) is the only data
+that can be used by model. Usually, the models are trained on implicit feedback data and evaluated under the
+task of top-n recommendation. All the collaborative filter(CF) based models are classified in this class.
 
 .. toctree::
    :maxdepth: 1
@@ -38,6 +41,9 @@ General Recommendation
 
 Context-aware Recommendation
 -------------------------------
+Context-aware recommendation can be seen as an extension of click-through rate prediction. All the model in this
+class can be used for CTR prediction. Usually, the dataset is explicit and contains label field. Other feature fields
+are also support for these models. And evaluation is always conducted in the way of binary classification.
 
 .. toctree::
    :maxdepth: 1
@@ -64,6 +70,9 @@ Context-aware Recommendation
 
 Sequential Recommendation
 ---------------------------------
+The task of sequential recommendation(next-item recommendation) is the same as general recommendation which sorts a list of items according
+to preference. While the history interactions are organized in sequences and the model tends to characterize
+the sequential data. The models of session-based recommendation are also included in this class.
 
 .. toctree::
    :maxdepth: 1
@@ -96,6 +105,7 @@ Sequential Recommendation
 
 Knowledge-based Recommendation
 ---------------------------------
+Knowledge-based recommendation introduces an external knowledge graph to enhance general or sequential recommendation.
 
 .. toctree::
    :maxdepth: 1
diff --git a/docs/source/user_guide/train_eval_intro.rst b/docs/source/user_guide/train_eval_intro.rst
new file mode 100644
index 000000000..2ae097f38
--- /dev/null
+++ b/docs/source/user_guide/train_eval_intro.rst
@@ -0,0 +1,100 @@
+Training & Evaluation Introduction
+===================================
+
+Training introduction
+-----------------------
+Multiple training strategies are supported by RecBole. For traditional CPU-based
+collaborative filter models, non-gradient training is naturally applied. For
+main-stream neural-based models, automatic gradient descent is well equipped
+and set as default training strategy. Also two-stage training strategy is prepared
+for pretraining-based models. In addition, users who need an unusual training strategy
+can customize the ``Trainer`` and please refer to :doc:`../developer_guide/customize_trainers`
+for more details.
+
+Apart from flexible training strategies, an automatic hyper-parameter searching is
+also supported. The implement of searching is fully based on `hyperopt <https://github.com/hyperopt/hyperopt>`_. 
+Users can set the range of hyper-parameters in a config file with format of hyperopt
+and the optimal hyper-parameter and result will be output. 
+You can read :doc:`usage/parameter_tuning` for more information about hyper-parameter-tuning in RecBole.
+
+To control the training method, we design a series of training parameters in config,
+and you can read the :doc:`config/training_settings` for more information.
+
+
+Evaluation introduction
+-----------------------
+The function of evaluation module is to implement commonly used evaluation
+protocols for recommender systems. Since different models can be compared under
+the same evaluation modules, RecBole standardizes the evaluation of recommender
+systems.
+
+Evaluation method
+>>>>>>>>>>>>>>>>>>>>>>>
+
+The evaluation method supported by RecBole is as following. Among them, the
+first four rows correspond to the dataset splitting methods, while the last two
+rows correspond to the ranking mechanism, namely a full ranking over all the
+items or a sampled-based ranking.
+
+==================       ========================================================
+ Notation                   Explanation
+==================       ========================================================
+  RO                        Random Ordering
+  TO                        Temporal Ordering
+  LS                        Leave-one-out Splitting
+  RS                        Ratio-based Splitting
+  full                      full ranking with all item candidates
+  uniN                      sample-based ranking: each positive item is paired with N sampled negative items in uniform distribution
+  popN                      sample-based ranking: each positive item is paired with N sampled negative items in popularity distribution
+==================       ========================================================
+
+The parameters used to control the evaluation method are as follows:
+
+- ``eval_args (dict)``: The overall evaluation settings. It contains all the setting of evaluation
+  including ``split``, ``group_by``, ``order`` and ``mode``.
+
+  - ``split (dict)``:  Control the splitting of dataset and the split ratio. The key is splitting method
+    and value is the list of split ratio. The range of key is ``[RO,TO]``. Defaults to ``{'RO':[0.8, 0.1, 0.1]}``
+  - ``group_by (str)``: Whether to split dataset with the group of user.
+    Range in ``[None, user]`` and defaults to ``user``.
+  - ``order (str)``: Control the ordering of data and affect the splitting of data.
+    Range in ``['RS', 'LS']`` and defaults to ``RS``.
+  - ``mode (str)``: Control different candidates of ranking.
+    Range in ``[labeled, full, unixxx, popxxx]`` and defaults to ``full``.
+ 
+- ``repeatable (bool)``: Whether to evaluate the result with a repeatable recommendation scene. Note that it is disabled for sequential models as the recommendation is already repeatable. For other models, defaults to ``False``.
+
+Evaluation metrics
+>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+RecBole supports both value-based and ranking-based evaluation metrics.
+
+The value-based metrics (i.e., for rating prediction) include ``RMSE``, ``MAE``,
+``AUC`` and ``LogLoss``, measuring the prediction difference between the true
+and predicted values.
+
+The ranking-based metrics (i.e., for top-k item recommendation) include the most
+common ranking-aware metrics, such as ``Recall``, ``Precision``, ``Hit``,
+``NDCG``, ``MAP``, ``MRR`` and ``GAUC``, measuring the ranking performance of the
+generated recommendation lists by an algorithm. Besides, several ranking-based
+non-accuracy metrics are supported to evaluate in different views, such as
+``ItemCoverage``, ``AveragePopularity``, ``GiniIndex``, ``ShannonEntropy`` and ``TailPercentage``. 
+More details about metrics can refer to :doc:`/recbole/recbole.evaluator.metrics`.
+
+The parameters used to control the evaluation metrics are as follows:
+
+- ``metrics (list or str)``: Evaluation metrics. Defaults to
+  ``['Recall', 'MRR', 'NDCG', 'Hit', 'Precision']``. Range in the following table:
+
+  ==============    =================================================
+  Type              Metrics
+  ==============    =================================================
+  Ranking-based     Recall, MRR, NDCG, Hit, MAP, Precision, GAUC, ItemCoverage, AveragePopularity, GiniIndex, ShannonEntropy, TailPercentage
+  value-based       AUC, MAE, RMSE, LogLoss
+  ==============    =================================================
+
+  Note that value-based metrics and ranking-based metrics can not be used together.
+- ``topk (list or int or None)``: The value of k for topk evaluation metrics.
+  Defaults to ``10``.
+
+For more details about evaluation settings, please read :doc:`config/evaluation_settings`
diff --git a/docs/source/user_guide/usage.rst b/docs/source/user_guide/usage.rst
index f98dd081a..3aca00a84 100644
--- a/docs/source/user_guide/usage.rst
+++ b/docs/source/user_guide/usage.rst
@@ -1,6 +1,7 @@
 Usage
 ===================
-Here we introduce how to use RecBole.
+In order to help users learn the depth usage of RecBole, we write the following usage docs 
+to give a detailed introduction about RecBole's features.
 
 .. toctree::
    :maxdepth: 1
@@ -10,5 +11,8 @@ Here we introduce how to use RecBole.
    usage/parameter_tuning
    usage/running_new_dataset
    usage/running_different_models
-   usage/qa
-   usage/load_pretrained_embedding
\ No newline at end of file
+   usage/load_pretrained_embedding
+   usage/save_and_load_data_and_model
+   usage/case_study
+   usage/use_tensorboard
+   usage/qa
\ No newline at end of file
diff --git a/docs/source/user_guide/usage/case_study.rst b/docs/source/user_guide/usage/case_study.rst
new file mode 100644
index 000000000..e6ab618e0
--- /dev/null
+++ b/docs/source/user_guide/usage/case_study.rst
@@ -0,0 +1,81 @@
+Case study
+=============
+
+Case study is an in-depth study of the performance of a specific recommendation algorithm,
+which will analysis the recommendation result of some users.
+In RecBole, we implemented :meth:`~recbole.utils.case_study.full_sort_scores`
+and :meth:`~recbole.utils.case_study.full_sort_topk` for case study purpose.
+In this section, we will present a typical usage of these two functions.
+
+Reload model
+-------------
+
+First, we need to reload the recommendation model,
+we can use :meth:`~recbole.quick_start.quick_start.load_data_and_model` to load saved data and model.
+
+.. code:: python3
+
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+    )  # Here you can replace it by your model path.
+
+Convert external user id into internal user id
+-------------------------------------------------
+
+Then, we need to use :meth:`~recbole.data.dataset.dataset.Dataset.token2id`
+to convert external user id which we want to do case study into internal user id.
+
+.. code:: python3
+
+    uid_series = dataset.token2id(dataset.uid_field, ['196', '186'])
+
+Get scores of every user-item pairs
+-------------------------------------
+
+If we want to calculate the scores of every user-item pairs for given user,
+we can call :meth:`~recbole.utils.case_study.full_sort_scores` function to get the scores matrix.
+
+.. code:: python3
+
+    score = full_sort_scores(uid_series, model, test_data, device=config['device'])
+    print(score)  # score of all items
+    print(score[0, dataset.token2id(dataset.iid_field, ['242', '302'])])
+    # score of item ['242', '302'] for user '196'.
+
+The output will be like this:
+
+.. code:: none
+
+    tensor([[   -inf,    -inf,  0.1074,  ..., -0.0966, -0.1217, -0.0966],
+            [   -inf, -0.0013,    -inf,  ..., -0.1115, -0.1089, -0.1196]],
+           device='cuda:0')
+    tensor([  -inf, 0.1074], device='cuda:0')
+
+Note that the score of ``[pad]`` and history items (for non-repeatable recommendation) will be set into ``-inf``.
+
+Get the top ranked item for each user
+--------------------------------------
+
+If we want to get the top ranked item for given user,
+we can call :meth:`~recbole.utils.case_study.full_sort_topk` function to get the scores and internal ids of these items.
+
+.. code:: python3
+
+    topk_score, topk_iid_list = full_sort_topk(uid_series, model, test_data, k=10, device=config['device'])
+    print(topk_score)  # scores of top 10 items
+    print(topk_iid_list)  # internal id of top 10 items
+    external_item_list = dataset.id2token(dataset.iid_field, topk_iid_list.cpu())
+    print(external_item_list)  # external tokens of top 10 items
+
+The output will be like this:
+
+.. code:: none
+
+    tensor([[0.1985, 0.1947, 0.1850, 0.1849, 0.1822, 0.1770, 0.1770, 0.1765, 0.1752,
+             0.1744],
+            [0.2487, 0.2379, 0.2351, 0.2311, 0.2293, 0.2239, 0.2215, 0.2156, 0.2137,
+             0.2114]], device='cuda:0')
+    tensor([[ 50,  32, 158, 210,  13, 100, 201,  61, 167, 312],
+            [102, 312, 358, 100,  32,  53, 167, 472, 162, 201]], device='cuda:0')
+    [['100' '98' '258' '7' '222' '496' '318' '288' '216' '176']
+     ['174' '176' '50' '496' '98' '181' '216' '28' '172' '318']]
diff --git a/docs/source/user_guide/usage/load_pretrained_embedding.rst b/docs/source/user_guide/usage/load_pretrained_embedding.rst
index c8f3c010a..2e50a31ed 100644
--- a/docs/source/user_guide/usage/load_pretrained_embedding.rst
+++ b/docs/source/user_guide/usage/load_pretrained_embedding.rst
@@ -22,9 +22,9 @@ Secondly, update the args as (suppose that ``USER_ID_FIELD: user_id``):
     load_col:
         # inter/user/item/...: As usual
         useremb: [uid, user_emb]
-    fields_in_same_space: [[uid, user_id]]
+    alias_of_user_id: [uid]
     preload_weight: 
-    	uid: user_emb
+        uid: user_emb
 
 Then, this additional embedding feature file will be loaded into the :class:`Dataset` object. These new features can be accessed as following:
 
@@ -39,6 +39,6 @@ In your model, user embedding matrix can be initialized by your pre-trained embe
 
     class YourModel(GeneralRecommender):
         def __init__(self, config, dataset):
-        	pretrained_user_emb = dataset.get_preload_weight('uid')
-        	self.user_embedding = nn.Embedding.from_pretrained(torch.from_numpy(pretrained_user_emb))
+            pretrained_user_emb = dataset.get_preload_weight('uid')
+            self.user_embedding = nn.Embedding.from_pretrained(torch.from_numpy(pretrained_user_emb))
 
diff --git a/docs/source/user_guide/usage/parameter_tuning.rst b/docs/source/user_guide/usage/parameter_tuning.rst
index 5c8168432..4cfda7560 100644
--- a/docs/source/user_guide/usage/parameter_tuning.rst
+++ b/docs/source/user_guide/usage/parameter_tuning.rst
@@ -6,7 +6,7 @@ a given model according to the provided hyper-parameter spaces.
 
 The general steps are given as follows:
 
-To begin with, the user has to claim an
+To begin with, the user has to claim a
 :class:`~recbole.trainer.hyper_tuning.HyperTuning`
 instance in the running python file (e.g., `run.py`):
 
@@ -18,7 +18,7 @@ instance in the running python file (e.g., `run.py`):
     hp = HyperTuning(objective_function=objective_function, algo='exhaustive',
                     params_file='model.hyper', fixed_config_file_list=['example.yaml'])
 
-:attr:`objective_function`　is the optimization objective,
+:attr:`objective_function` is the optimization objective,
 the input of :attr:`objective_function` is the parameter,
 and the output is the optimal result of these parameters.
 The users can design this :attr:`objective_function` according to their own requirements.
@@ -44,7 +44,7 @@ The user can also use an encapsulated :attr:`objective_function`, that is:
             'test_result': test_result
         }
 
-:attr:`algo` is the optimization algorithm. RecBole realize this module based
+:attr:`algo` is the optimization algorithm. RecBole realizes this module based
 on hyperopt_. In addition, we also support grid search tunning method.
 
 .. code:: python
@@ -66,7 +66,7 @@ on hyperopt_. In addition, we also support grid search tunning method.
     embedding_size choice [64,96,128]
     mlp_hidden_size choice ['[64,64,64]','[128,128]']
 
-Each line represent a parameter and the corresponding search range.
+Each line represents a parameter and the corresponding search range.
 There are three components: parameter name, range type, range.
 
 :class:`~recbole.trainer.hyper_tuning.HyperTuning` supports four range types,
diff --git a/docs/source/user_guide/usage/qa.rst b/docs/source/user_guide/usage/qa.rst
index f088c6802..451a9c753 100644
--- a/docs/source/user_guide/usage/qa.rst
+++ b/docs/source/user_guide/usage/qa.rst
@@ -22,15 +22,3 @@ For more rigorous evaluation, those user-item interaction records in validation
 Thus the distribution of validation & test sets may be inconsistent.
 
 However, this doesn't affect the comparison between models.
-
-**Q3**
-
-Why do I receive a warning about ``batch_size changed``? What is the meaning of :attr:`batch_size` in dataloader?
-
-**A3**
-
-In RecBole's dataloader, the meaning of :attr:`batch_size` is the upper bound of the number of **interactions** in one single batch.
-
-On the one hand, it's easy to calculate and control the usage of GPU memories. E.g., while comparing between different datasets, you don't need to change the value of :attr:`batch_size`, because the usage of GPU memories will not change a lot.
-
-On the other hand, in RecBole's top-k evaluation, we need the interactions of each user grouped in one batch. In other words, the interactions of any user should not be separated into multiple batches. We try to feed more interactions into one batch, but due to the above rules, the :attr:`batch_size` is just an upper bound. And :meth:`_batch_size_adaptation` is designed to adapt the actual batch size dynamically. Thus, while executing :meth:`_batch_size_adaptation`, you will receive a warning message.
diff --git a/docs/source/user_guide/usage/run_recbole.rst b/docs/source/user_guide/usage/run_recbole.rst
index 90b979481..54b9092e2 100644
--- a/docs/source/user_guide/usage/run_recbole.rst
+++ b/docs/source/user_guide/usage/run_recbole.rst
@@ -24,7 +24,7 @@ into the file.
 :attr:`config_dict` is the parameter dict.
 The two variables are used to config parameters in our toolkit.
 If you do not want to use the two variables to config parameters,
-please ignore them. In addition, we can also support ot control the parameters
+please ignore them. In addition, we also support to control parameters
 by the command line.
 
 Please refer to :doc:`../config_settings` for more details about config settings.
diff --git a/docs/source/user_guide/usage/running_different_models.rst b/docs/source/user_guide/usage/running_different_models.rst
index e262a940d..99d60cec9 100644
--- a/docs/source/user_guide/usage/running_different_models.rst
+++ b/docs/source/user_guide/usage/running_different_models.rst
@@ -1,19 +1,14 @@
 Running Different Models
 ==========================
-Here, we present how to run different models in RecBole.
+In RecBole, we have 4 categories of models, namely general recommendation, context-aware
+recommendation, sequential recommendation and knowledge-based recommendation. Since different categories of models have different requirements for data
+processing and evaluation setting, we need to configure these settings appropriately.
 
-Proper Parameters Configuration
-----------------------------------
-Since different categories of models have different requirements for data
-processing and evaluation setting, we need to configure these settings
-appropriately.
+Here, we present some examples to show how to these four categories models in RecBole.
 
-The following will introduce the parameter configuration of these four
-categories of models: namely general recommendation, context-aware
-recommendation, sequential recommendation and knowledge-based recommendation.
 
 General Recommendation
-^^^^^^^^^^^^^^^^^^^^^^^^^^
+---------------------------------
 
 **specify and load the user and item columns**
 
@@ -34,20 +29,22 @@ corresponding column names.
 
 **training and evaluation settings**
 
-General recommendation models usually needs to group data by user and perform
-negative sampling.
+General recommendation models usually need to group data by user and perform
+negative sampling. You can set the config like this:
 
 .. code:: yaml
 
-    group_by_user: True
-    training_neg_sample_num: 1
+    eval_args:
+        group_by: user
+    neg_sampling:
+        uniform: 1
 
 Context-aware Recommendation
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+------------------------------------
 
 **load the feature columns**
 
-Context-aware recommendation models utilize the features of users, items and
+Generally, context-aware recommendation models utilize the features of users, items and
 interactions to make CTR predictions, so it needs to load the used features.
 
 .. code:: yaml
@@ -62,53 +59,25 @@ inter atomic file.
 
 **label setting**
 
-We also need to configure `LABEL_FIELD`, which represents the label column in
-the CTR prediction. For the Context-aware recommendation models, the setting of
-`LABEL_FIELD` is divided into two cases:
+In general, context-aware recommendation models are mainly used in explicit feedback scenes, 
+so your data should have explicit feedback information and you need to set label for them. For more information about label setting, 
+please read the :doc:`../data/label_of_data`.
 
-1) There is a label field in atomic file, and the value is in 0/1, we only need to
-set as follows:
+**evaluation settings**
 
-.. code:: yaml
-
-    LABEL_FIELD: label
-
-2) There is no label field in atomic file, we need to generate label field based
-on some information.
-
-.. code:: yaml
-
-    LABEL_FIELD: label
-    threshold:
-        rating: 3
-
-`rating` is a column in atomic file and is loaded (by ``load_col``). In this way,
-the label of the interaction with ``rating >= 3`` is set to 1, the reset are
-set to 0.
-
-**training and evaluation settings**
-
-Context-aware recommendation models usually does not need to group data by user and
-perform negative sampling.
-
-.. code:: yaml
-
-    group_by_user: False
-    training_neg_sample_num: 0
-
-Since there is no need to rank the results, ``eval_setting`` only needs to set
-the first part, for example:
-
-.. code:: yaml
-
-    eval_setting: RO_RS
-
-The evaluation metrics are generally set to `AUC` and `LogLoss`.
+If you want to apply context-aware recommendation models for CTR predictions, you can set the config like:
 
 .. code:: yaml
 
+    eval_args:
+        group_by: None
+        mode: labeled
     metrics: ['AUC', 'LogLoss']
+    valid_metric: AUC
 
+Note that RecBole also supports to evaluate the context-aware recommendation models by full-ranking like general recommendation models,
+but you need to make sure that your ``.inter`` file can not load any other context information column.  
+    
 
 Sequential Recommendation
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/docs/source/user_guide/usage/running_new_dataset.rst b/docs/source/user_guide/usage/running_new_dataset.rst
index b986567f5..fc7d04cec 100644
--- a/docs/source/user_guide/usage/running_new_dataset.rst
+++ b/docs/source/user_guide/usage/running_new_dataset.rst
@@ -1,21 +1,23 @@
 Running New Dataset
 =======================
-Here, we present how to use a new dataset in RecBole.
+RecBole has a build-in dataset **ml-100k** for users to quickly get start. 
+However, if you want to use new dataset, here, we present how to use a new dataset in RecBole.
 
 
-Convert to Atomic Files
+Prepare atomic files
 -------------------------
 
-If the user use the collected datasets, she can choose one of the following ways:
+In order to characterize most forms of the input data required by different recommendation tasks, 
+RecBole designs an input data format called :doc:`../data/atomic_files` and 
+you need to convert your raw data into Atomic Files format before data loading. 
 
-1. Download the converted atomic files from `Google Drive <https://drive.google.com/drive/folders/1so0lckI6N6_niVEYaBu-LIcpOdZf99kj?usp=sharing>`_ or `Baidu Wangpan <https://pan.baidu.com/s/1p51sWMgVFbAaHQmL4aD_-g>`_ (Password: e272).
-2. Find the converting script from RecDatasets_, and transform them to atomic files.
+For the convenience of users, we have collected more than
+28 commonly used datasets (detailed as `Dataset List </dataset_list.html>`_.) and released their Atomic Files format 
+for users to download them freely. More information of downloading our prepared datasets can be found in :doc:`../data/dataset_download`.
 
-If the user use other datasets, she should format the data according to the format of the atomic files.
+However, if you use other datasets, you should convert your data into the Atomic Files by yourself.
 
-.. _RecDatasets: https://github.com/RUCAIBox/RecDatasets
-
-For the dataset of ml-1m, the converting file is:
+For the ml-1m dataset, the converted atomic files are like:
 
 **ml-1m.inter**
 
@@ -45,11 +47,11 @@ item_id:token   movie_title:token_seq   release_year:token   genre:token_seq
 =============   =====================   ==================   ============================
 
 
-Local Path
+Set data path
 ---------------
-Name of atomic files, name of dir that containing atomic files and ``config['dataset']`` should be the same.
-
-``config['data_path']`` should be the parent dir of the dir that containing atomic files.
+You need to set the data path in config when you want to use new dataset. 
+The name of atomic files, name of dir that containing atomic files and ``config['dataset']`` should be the same, and
+the ``data_path`` in your config should be the parent dir of the directory that contains atomic files.
 
 For example:
 
@@ -75,6 +77,7 @@ Suppose we use ml-1m to train BPR.
 
 According to the dataset information, the user should set the dataset information and filtering parameters in the configuration file `ml-1m.yaml`.
 For example, we conduct 10-core filtering, removing the ratings which are smaller than 3, the time of the record should be earlier than 97830000, and we only load inter data.
+The ``yaml`` file should be like:
 
 .. code:: yaml
 
@@ -86,11 +89,11 @@ For example, we conduct 10-core filtering, removing the ratings which are smalle
     load_col:
         inter: [user_id, item_id, rating, timestamp]
 
-    min_user_inter_num: 10
-    min_item_inter_num: 10
-    lowest_val:
-        rating: 3
-        timestamp: 97830000
+    user_inter_num_interval: "[10,inf)"
+    item_inter_num_interval: "[10,inf)"
+    val_interval:
+        rating: "[3,inf)"
+        timestamp: "[97830000, inf)"
 
 
 .. code:: python
@@ -108,14 +111,16 @@ Convert to Dataloader
 Here, we present how to convert :class:`~recbole.data.dataset.dataset.Dataset` into :obj:`Dataloader`.
 
 We firstly set the parameters in the configuration file `ml-1m.yaml`.
-We leverage random ordering + ratio-based splitting and full ranking with all item candidates, the splitting ratio is set as 8:1:1.
+Suppose we want to leverage random ordering, ratio-based splitting and full ranking with all item candidates, the splitting ratio is set as 8:1:1.
+You can add the following config in your `ml-1m.yaml`:
 
 .. code:: yaml
 
-    ...
-
-    eval_setting: RO_RS,full
-    split_ratio: [0.8,0.1,0.1]
+    eval_args:
+        split: {'RS': [8,1,1]}
+        group_by: user
+        order: RO
+        mode: full
 
 
 .. code:: python
diff --git a/docs/source/user_guide/usage/save_and_load_data_and_model.rst b/docs/source/user_guide/usage/save_and_load_data_and_model.rst
new file mode 100644
index 000000000..2ae7e0610
--- /dev/null
+++ b/docs/source/user_guide/usage/save_and_load_data_and_model.rst
@@ -0,0 +1,67 @@
+Save and load data and model
+==============================
+
+In this section, we will present how to save and load data and model.
+
+Save data and model
+--------------------
+
+When we use the :meth:`~recbole.quick_start.quick_start.run_recbole` function mentioned in :doc:`run_recbole`,
+it will save the best model parameters in training process and its corresponding config settings.
+If you want to save filtered dataset and split dataloaders,
+you can set parameter :attr:`save_dataset` and parameter :attr:`save_dataloaders` to ``True``
+to save filtered dataset and split dataloaders.
+
+You can refer to :doc:`../config_settings` for more details about :attr:`save_dataset` and :attr:`save_dataloaders`.
+
+Here we present a typical output when two parameters above is ``True``:
+
+.. code:: none
+
+    21 Aug 13:05    INFO  Saving filtered dataset into [saved/ml-100k-dataset.pth]
+    21 Aug 13:05    INFO  ml-100k
+    The number of users: 944
+    Average actions of users: 106.04453870625663
+    The number of items: 1683
+    Average actions of items: 59.45303210463734
+    The number of inters: 100000
+    The sparsity of the dataset: 93.70575143257098%
+    Remain Fields: ['user_id', 'item_id', 'rating', 'timestamp']
+    21 Aug 13:05    INFO  Saved split dataloaders: saved/ml-100k-for-BPR-dataloader.pth
+    21 Aug 13:06    INFO  BPR(
+        (user_embedding): Embedding(944, 64)
+        (item_embedding): Embedding(1683, 64)
+        (loss): BPRLoss()
+    )
+    Trainable parameters: 168128
+    Train     0: 100%|█████████████████████████| 40/40 [00:01<00:00, 32.52it/s, GPU RAM: 0.01 G/11.91 G]
+    21 Aug 13:06    INFO  epoch 0 training [time: 1.24s, train loss: 27.7228]
+    Evaluate   : 100%|███████████████████████| 472/472 [00:04<00:00, 94.53it/s, GPU RAM: 0.01 G/11.91 G]
+    21 Aug 13:06    INFO  epoch 0 evaluating [time: 5.00s, valid_score: 0.020500]
+    21 Aug 13:06    INFO  valid result:
+    recall@10 : 0.0067    mrr@10 : 0.0205    ndcg@10 : 0.0086    hit@10 : 0.0732    precision@10 : 0.0081
+    21 Aug 13:06    INFO  Saving current best: saved/BPR-Aug-21-2021_13-06-00.pth
+
+    ...
+
+As we can see, the filtered dataset is saved to ``saved/ml-100k-dataset.pth``,
+the split dataloaders are saved to ``saved/ml-100k-for-BPR-dataloader.pth``,
+and the model is saved to ``saved/BPR-Aug-21-2021_13-06-00.pth``.
+
+Load data and model
+--------------------
+
+If you want to reload the data and model,
+you can apply :meth:`~recbole.quick_start.quick_start.load_data_and_model` to get them.
+You can also pass :attr:`dataset_file` and :attr:`dataloader_file` to this function to reload data from file,
+which can reduce the time of data filtering and data splitting.
+
+Here we present a typical usage of :meth:`~recbole.quick_start.quick_start.load_data_and_model`:
+
+.. code:: python3
+
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='saved/BPR-Aug-21-2021_13-06-00.pth',
+    )
+    # Here you can replace it by your model path.
+    # And you can also pass 'dataset_file' and 'dataloader_file' to this function.
diff --git a/docs/source/user_guide/usage/use_tensorboard.rst b/docs/source/user_guide/usage/use_tensorboard.rst
new file mode 100644
index 000000000..97088560b
--- /dev/null
+++ b/docs/source/user_guide/usage/use_tensorboard.rst
@@ -0,0 +1,21 @@
+Use Tensorboard
+====================
+
+In the latest release, RecBole allows tracking and visualizing train loss and valid score with TensorBoard. 
+
+In Recbole, TensorBoard output to `./log_tensorboard/` directory by default. You can start TensorBoard with:
+
+.. code:: sh
+
+    $ tensorboard --logdir=log_tensorboard
+
+Then, go to the URL it provides OR to http://localhost:6006/. You can see the following page.
+
+.. image:: ../../asset/tensorboard_1.png
+
+This dashboard shows how the train loss and valid score change with every epoch. 
+
+You can also compare hyperparameters by switching to the  'HPAPAMS' page 
+from the header menu. It’s helpful to compare these metrics across different training runs to improve your model.
+
+.. image:: ../../asset/tensorboard_2.png
\ No newline at end of file
diff --git a/recbole/config/__init__.py b/recbole/config/__init__.py
index e4ee33c03..71e55a8ea 100644
--- a/recbole/config/__init__.py
+++ b/recbole/config/__init__.py
@@ -1,2 +1,1 @@
 from recbole.config.configurator import Config
-from recbole.config.eval_setting import EvalSetting
diff --git a/recbole/config/configurator.py b/recbole/config/configurator.py
index 854b42dc1..c7307818c 100644
--- a/recbole/config/configurator.py
+++ b/recbole/config/configurator.py
@@ -3,9 +3,9 @@
 # @Email  : linzihan.super@foxmail.com
 
 # UPDATE
-# @Time   : 2020/10/04, 2021/3/2, 2021/2/17
-# @Author : Shanlei Mu, Yupeng Hou, Jiawei Guan
-# @Email  : slmu@ruc.edu.cn, houyupeng@ruc.edu.cn, Guanjw@ruc.edu.cn
+# @Time   : 2020/10/04, 2021/3/2, 2021/2/17, 2021/6/30
+# @Author : Shanlei Mu, Yupeng Hou, Jiawei Guan, Xingyu Pan
+# @Email  : slmu@ruc.edu.cn, houyupeng@ruc.edu.cn, Guanjw@ruc.edu.cn, xy_pan@foxmail.com
 
 """
 recbole.config.configurator
@@ -19,10 +19,9 @@
 import torch
 from logging import getLogger
 
-from recbole.evaluator import group_metrics, individual_metrics
+from recbole.evaluator import metric_types, smaller_metrics
 from recbole.utils import get_model, Enum, EvaluatorType, ModelType, InputType, \
-    general_arguments, training_arguments, evaluation_arguments, dataset_arguments
-from recbole.utils.utils import set_color
+    general_arguments, training_arguments, evaluation_arguments, dataset_arguments, set_color
 
 
 class Config(object):
@@ -79,6 +78,7 @@ def __init__(self, model=None, dataset=None, config_file_list=None, config_dict=
         self._set_default_parameters()
         self._init_device()
         self._set_train_neg_sample_args()
+        self._set_eval_neg_sample_args()
 
     def _init_parameters_category(self):
         self.parameters = dict()
@@ -113,7 +113,7 @@ def _convert_config_dict(self, config_dict):
                 continue
             try:
                 value = eval(param)
-                if not isinstance(value, (str, int, float, list, tuple, dict, bool, Enum)):
+                if value is not None and not isinstance(value, (str, int, float, list, tuple, dict, bool, Enum)):
                     value = param
             except (NameError, SyntaxError, TypeError):
                 if isinstance(param, str):
@@ -263,7 +263,6 @@ def _get_final_config_dict(self):
         return final_config_dict
 
     def _set_default_parameters(self):
-
         self.final_config_dict['dataset'] = self.dataset
         self.final_config_dict['model'] = self.model
         if self.dataset == 'ml-100k':
@@ -276,37 +275,72 @@ def _set_default_parameters(self):
             self.final_config_dict['MODEL_INPUT_TYPE'] = self.model_class.input_type
         elif 'loss_type' in self.final_config_dict:
             if self.final_config_dict['loss_type'] in ['CE']:
-                if self.final_config_dict['MODEL_TYPE'] == ModelType.SEQUENTIAL and self.final_config_dict['training_neg_sample_num'] > 0:
-                    raise ValueError("training_neg_sample_num should be 0 when the loss_type is CE")
+                if self.final_config_dict['MODEL_TYPE'] == ModelType.SEQUENTIAL and \
+                   self.final_config_dict['neg_sampling'] is not None:
+                    raise ValueError(f"neg_sampling [{self.final_config_dict['neg_sampling']}] should be None "
+                                     f"when the loss_type is CE.")
                 self.final_config_dict['MODEL_INPUT_TYPE'] = InputType.POINTWISE
             elif self.final_config_dict['loss_type'] in ['BPR']:
                 self.final_config_dict['MODEL_INPUT_TYPE'] = InputType.PAIRWISE
         else:
             raise ValueError('Either Model has attr \'input_type\',' 'or arg \'loss_type\' should exist in config.')
 
-        eval_type = None
+        metrics = self.final_config_dict['metrics']
+        if isinstance(metrics, str):
+            self.final_config_dict['metrics'] = [metrics]
+
+        eval_type = set()
         for metric in self.final_config_dict['metrics']:
-            if metric.lower() in individual_metrics:
-                if eval_type is not None and eval_type == EvaluatorType.RANKING:
-                    raise RuntimeError('Ranking metrics and other metrics can not be used at the same time.')
-                else:
-                    eval_type = EvaluatorType.INDIVIDUAL
-            if metric.lower() in group_metrics:
-                if eval_type is not None and eval_type == EvaluatorType.INDIVIDUAL:
-                    raise RuntimeError('Ranking metrics and other metrics can not be used at the same time.')
-                else:
-                    eval_type = EvaluatorType.RANKING
-        self.final_config_dict['eval_type'] = eval_type
+            if metric.lower() in metric_types:
+                eval_type.add(metric_types[metric.lower()])
+            else:
+                raise NotImplementedError(f"There is no metric named '{metric}'")
+        if len(eval_type) > 1:
+            raise RuntimeError('Ranking metrics and value metrics can not be used at the same time.')
+        self.final_config_dict['eval_type'] = eval_type.pop()
+
+        if self.final_config_dict['MODEL_TYPE'] == ModelType.SEQUENTIAL and not self.final_config_dict['repeatable']:
+            raise ValueError('Sequential models currently only support repeatable recommendation, '
+                             'please set `repeatable` as `True`.')
 
-        smaller_metric = ['rmse', 'mae', 'logloss']
         valid_metric = self.final_config_dict['valid_metric'].split('@')[0]
-        self.final_config_dict['valid_metric_bigger'] = False if valid_metric.lower() in smaller_metric else True
+        self.final_config_dict['valid_metric_bigger'] = False if valid_metric.lower() in smaller_metrics else True
+
+        topk = self.final_config_dict['topk']
+        if isinstance(topk, (int, list)):
+            if isinstance(topk, int):
+                topk = [topk]
+            for k in topk:
+                if k <= 0:
+                    raise ValueError(
+                        f'topk must be a positive integer or a list of positive integers, but get `{k}`'
+                    )
+            self.final_config_dict['topk'] = topk
+        else:
+            raise TypeError(f'The topk [{topk}] must be a integer, list')
 
         if 'additional_feat_suffix' in self.final_config_dict:
             ad_suf = self.final_config_dict['additional_feat_suffix']
             if isinstance(ad_suf, str):
                 self.final_config_dict['additional_feat_suffix'] = [ad_suf]
 
+        # eval_args checking
+        default_eval_args = {
+            'split': {'RS': [0.8, 0.1, 0.1]},
+            'order': 'RO',
+            'group_by': 'user',
+            'mode': 'full'
+        }
+        if not isinstance(self.final_config_dict['eval_args'], dict):
+            raise ValueError(f"eval_args:[{self.final_config_dict['eval_args']}] should be a dict.")
+        for op_args in default_eval_args:
+            if op_args not in self.final_config_dict['eval_args']:
+                self.final_config_dict['eval_args'][op_args] = default_eval_args[op_args]
+
+        if (self.final_config_dict['eval_args']['mode'] == 'full'
+                and self.final_config_dict['eval_type'] == EvaluatorType.VALUE):
+            raise NotImplementedError('Full sort evaluation do not match value-based metrics!')
+
     def _init_device(self):
         use_gpu = self.final_config_dict['use_gpu']
         if use_gpu:
@@ -314,20 +348,57 @@ def _init_device(self):
         self.final_config_dict['device'] = torch.device("cuda" if torch.cuda.is_available() and use_gpu else "cpu")
 
     def _set_train_neg_sample_args(self):
-        if self.final_config_dict['training_neg_sample_num']:
+        neg_sampling = self.final_config_dict['neg_sampling']
+        if neg_sampling is None:
+            self.final_config_dict['train_neg_sample_args'] = {'strategy': 'none'}
+        else:
+            if not isinstance(neg_sampling, dict):
+                raise ValueError(f"neg_sampling:[{neg_sampling}] should be a dict.")
+            if len(neg_sampling) > 1:
+                raise ValueError(f"the len of neg_sampling [{neg_sampling}] should be 1.")
+
+            distribution = list(neg_sampling.keys())[0]
+            sample_num = neg_sampling[distribution]
+            if distribution not in ['uniform', 'popularity']:
+                raise ValueError(f"The distribution [{distribution}] of neg_sampling "
+                                 f"should in ['uniform', 'popularity']")
+
             self.final_config_dict['train_neg_sample_args'] = {
                 'strategy': 'by',
-                'by': self.final_config_dict['training_neg_sample_num'],
-                'distribution': self.final_config_dict['training_neg_sample_distribution'] or 'uniform'
+                'by': sample_num,
+                'distribution': distribution
             }
+
+    def _set_eval_neg_sample_args(self):
+        eval_mode = self.final_config_dict['eval_args']['mode']
+        if not isinstance(eval_mode, str):
+            raise ValueError(f"mode [{eval_mode}] in eval_args should be a str.")
+        if eval_mode == 'labeled':
+            eval_neg_sample_args = {'strategy': 'none', 'distribution': 'none'}
+        elif eval_mode == 'full':
+            eval_neg_sample_args = {'strategy': 'full', 'distribution': 'uniform'}
+        elif eval_mode[0:3] == 'uni':
+            sample_by = int(eval_mode[3:])
+            eval_neg_sample_args = {'strategy': 'by', 'by': sample_by, 'distribution': 'uniform'}
+        elif eval_mode[0:3] == 'pop':
+            sample_by = int(eval_mode[3:])
+            eval_neg_sample_args = {'strategy': 'by', 'by': sample_by, 'distribution': 'popularity'}
         else:
-            self.final_config_dict['train_neg_sample_args'] = {'strategy': 'none'}
+            raise ValueError(f'the mode [{eval_mode}] in eval_args is not supported.')
+        self.final_config_dict['eval_neg_sample_args'] = eval_neg_sample_args
 
     def __setitem__(self, key, value):
         if not isinstance(key, str):
             raise TypeError("index must be a str.")
         self.final_config_dict[key] = value
 
+    def __getattr__(self, item):
+        if 'final_config_dict' not in self.__dict__:
+            raise AttributeError(f"'Config' object has no attribute 'final_config_dict'")
+        if item in self.final_config_dict:
+            return self.final_config_dict[item]
+        raise AttributeError(f"'Config' object has no attribute '{item}'")
+
     def __getitem__(self, item):
         if item in self.final_config_dict:
             return self.final_config_dict[item]
diff --git a/recbole/config/eval_setting.py b/recbole/config/eval_setting.py
deleted file mode 100644
index c67386ded..000000000
--- a/recbole/config/eval_setting.py
+++ /dev/null
@@ -1,391 +0,0 @@
-# @Time   : 2020/7/20
-# @Author : Yupeng Hou
-# @Email  : houyupeng@ruc.edu.cn
-
-# UPDATE:
-# @Time   : 2020/10/22, 2020/8/31, 2021/3/1
-# @Author : Yupeng Hou, Yushuo Chen, Jiawei Guan
-# @Email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, guanjw@ruc.edu.cn
-
-"""
-recbole.config.eval_setting
-################################
-"""
-
-from recbole.utils.utils import set_color
-
-
-class EvalSetting(object):
-    """Class containing settings about model evaluation.
-
-    Evaluation setting contains four parts:
-        * Group
-        * Sort
-        * Split
-        * Negative Sample
-
-    APIs are provided for users to set up or modify their evaluation setting easily and clearly.
-
-    Besides, some presets are provided, which is more recommended.
-
-    For example:
-        RO: Random Ordering
-        TO: Temporal Ordering
-
-        RS: Ratio-based Splitting
-        LS: Leave-one-out Splitting
-
-        full: adopt the entire item set (excluding ground-truth items) for ranking
-        uniXX: uniform sampling XX items while negative sampling
-        popXX: popularity-based sampling XX items while negative sampling
-
-    Note that records are grouped by user_id by default if you use these presets.
-
-    Thus you can use `RO_RS, full` to represent Shuffle, Grouped by user, Ratio-based Splitting
-    and Evaluate all non-ground-truth items.
-
-    Check out *Revisiting Alternative Experimental Settings for Evaluating Top-N Item Recommendation Algorithms*
-    Wayne Xin Zhao et.al. CIKM 2020 to figure out the details about presets of evaluation settings.
-
-    Args:
-        config (Config): Global configuration object.
-
-    Attributes:
-        group_field (str or None): Don't group if ``None``, else group by field before splitting.
-            Usually records are grouped by user id.
-
-        ordering_args (dict): Args about ordering.
-            Usually records are sorted by timestamp, or shuffled.
-
-        split_args (dict): Args about splitting.
-            usually records are split by ratio (eg. 8:1:1),
-            or by 'leave one out' strategy, which means the last purchase record
-            of one user is used for evaluation.
-
-        neg_sample_args (dict): Args about negative sampling.
-            Negative sample is used wildly in training and evaluating.
-
-            We provide two strategies:
-
-            - ``neg_sample_by``:  sample several negative records for each positive records.
-            - ``full_sort``:      don't negative sample, while all unused items are used for evaluation.
-
-    """
-
-    def __init__(self, config):
-        self.config = config
-
-        self.group_field = None
-        self.ordering_args = None
-        self.split_args = None
-        self.neg_sample_args = {'strategy': 'none'}
-
-        self.es_str = [_.strip() for _ in config['eval_setting'].split(',')]
-        self.set_ordering_and_splitting(self.es_str[0])
-        if len(self.es_str) > 1:
-            if getattr(self, self.es_str[1], None) == None:
-                raise ValueError('Incorrect setting of negative sampling.')
-            getattr(self, self.es_str[1])()
-        presetting_args = ['group_field', 'ordering_args', 'split_args', 'neg_sample_args']
-        for args in presetting_args:
-            if config[args] is not None:
-                setattr(self, args, config[args])
-
-    def __str__(self):
-        info = [set_color('Evaluation Setting:', 'pink')]
-
-        if self.group_field:
-            info.append(set_color('Group by', 'blue') + f' {self.group_field}')
-        else:
-            info.append(set_color('No Grouping', 'yellow'))
-
-        if self.ordering_args is not None and self.ordering_args['strategy'] != 'none':
-            info.append(set_color('Ordering', 'blue') + f': {self.ordering_args}')
-        else:
-            info.append(set_color('No Ordering', 'yellow'))
-
-        if self.split_args is not None and self.split_args['strategy'] != 'none':
-            info.append(set_color('Splitting', 'blue') + f': {self.split_args}')
-        else:
-            info.append(set_color('No Splitting', 'yellow'))
-
-        if self.neg_sample_args is not None and self.neg_sample_args['strategy'] != 'none':
-            info.append(set_color('Negative Sampling', 'blue') + f': {self.neg_sample_args}')
-        else:
-            info.append(set_color('No Negative Sampling', 'yellow'))
-
-        return '\n\t'.join(info)
-
-    def __repr__(self):
-        return self.__str__()
-
-    def group_by(self, field=None):
-        """Setting about group
-
-        Args:
-            field (str): The field of dataset grouped by, default None (Not Grouping)
-
-        Example:
-            >>> es.group_by('month')
-            >>> es.group_by_user()
-        """
-        self.group_field = field
-
-    def group_by_user(self):
-        """Group by user
-
-        Note:
-            Requires ``USER_ID_FIELD`` in config
-        """
-        self.group_field = self.config['USER_ID_FIELD']
-
-    def set_ordering(self, strategy='none', **kwargs):
-        """Setting about ordering
-
-        Args:
-            strategy (str): Either ``none``, ``shuffle`` or ``by``
-            field (str or list of str): Name or list of names
-            ascending (bool or list of bool): Sort ascending vs. descending. Specify list for multiple sort orders.
-                If this is a list of bools, must match the length of the field
-
-        Example:
-            >>> es.set_ordering('shuffle')
-            >>> es.set_ordering('by', field='timestamp')
-            >>> es.set_ordering('by', field=['timestamp', 'price'], ascending=[True, False])
-
-        or
-
-            >>> es.random_ordering()
-            >>> es.sort_by('timestamp') # ascending default
-            >>> es.sort_by(field=['timestamp', 'price'], ascending=[True, False])
-        """
-        legal_strategy = {'none', 'shuffle', 'by'}
-        if strategy not in legal_strategy:
-            raise ValueError('Ordering Strategy [{}] should in {}'.format(strategy, list(legal_strategy)))
-        self.ordering_args = {'strategy': strategy}
-        self.ordering_args.update(kwargs)
-
-    def random_ordering(self):
-        """Shuffle Setting
-        """
-        self.set_ordering('shuffle')
-
-    def sort_by(self, field, ascending=True):
-        """Setting about Sorting.
-
-        Similar with pandas' sort_values_
-
-        .. _sort_values: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_values.html?highlight=sort_values#pandas.DataFrame.sort_values
-
-        Args:
-            field (str or list of str): Name or list of names
-            ascending (bool or list of bool): Sort ascending vs. descending. Specify list for multiple sort orders.
-                If this is a list of bool, must match the length of the field
-        """
-        self.set_ordering('by', field=field, ascending=ascending)
-
-    def temporal_ordering(self):
-        """Setting about Sorting by timestamp.
-
-        Note:
-            Requires `TIME_FIELD` in config
-        """
-        self.sort_by(field=self.config['TIME_FIELD'])
-
-    def set_splitting(self, strategy='none', **kwargs):
-        """Setting about split method
-
-        Args:
-            strategy (str): Either ``none``, ``by_ratio``, ``by_value`` or ``loo``.
-            ratios (list of float): Dataset will be splited into `len(ratios)` parts.
-            field (str): Split by values of field.
-            values (list of float or float): Dataset will be splited into `len(values) + 1` parts.
-                The first part will be interactions whose field value in (\\*, values[0]].
-            ascending (bool): Order of values after splitting.
-
-        Example:
-            >>> es.leave_one_out()
-            >>> es.split_by_ratio(ratios=[0.8, 0.1, 0.1])
-            >>> es.split_by_value(field='month', values=[6, 7], ascending=False)    # (*, 7], (7, 6], (6, *)
-        """
-        legal_strategy = {'none', 'by_ratio', 'by_value', 'loo'}
-        if strategy not in legal_strategy:
-            raise ValueError('Split Strategy [{}] should in {}'.format(strategy, list(legal_strategy)))
-        if strategy == 'loo' and self.group_field is None:
-            raise ValueError('Leave-One-Out request group firstly')
-        self.split_args = {'strategy': strategy}
-        self.split_args.update(kwargs)
-
-    def leave_one_out(self, leave_one_num=1):
-        """ Setting about Splitting by 'leave-one-out' strategy.
-
-        Note:
-            Requires setting group by.
-
-        Args:
-            leave_one_num (int): number of sub datasets for evaluation.
-                E.g. ``leave_one_num = 2`` if you have one validation dataset and one test dataset.
-        """
-        if self.group_field is None:
-            raise ValueError('Leave one out request grouped dataset, please set group field.')
-        self.set_splitting(strategy='loo', leave_one_num=leave_one_num)
-
-    def split_by_ratio(self, ratios):
-        """ Setting about Ratio-based Splitting.
-
-        Args:
-            ratios (list of float): ratio of each part.
-                No need to normalize. It's ok with either `[0.8, 0.1, 0.1]`, `[8, 1, 1]` or `[56, 7, 7]`
-        """
-        if not isinstance(ratios, list):
-            raise ValueError('ratios [{}] should be list'.format(ratios))
-        self.set_splitting(strategy='by_ratio', ratios=ratios)
-
-    def _split_by_value(self, field, values, ascending=True):
-        raise NotImplementedError('Split by value has not been implemented.')
-        if not isinstance(field, str):
-            raise ValueError('field [{}] should be str'.format(field))
-        if not isinstance(values, list):
-            values = [values]
-        values.sort(reverse=(not ascending))
-        self.set_splitting(strategy='by_value', values=values, ascending=ascending)
-
-    def set_neg_sampling(self, strategy='none', distribution='uniform', **kwargs):
-        """Setting about negative sampling
-
-        Args:
-            strategy (str): Either ``none``, ``full`` or ``by``.
-            by (int): Negative Sampling `by` neg cases for one pos case.
-            distribution (str): distribution of sampler, either 'uniform' or 'popularity'.
-
-        Example:
-            >>> es.full()
-            >>> es.neg_sample_by(1)
-        """
-        legal_strategy = {'none', 'full', 'by'}
-        if strategy not in legal_strategy:
-            raise ValueError('Negative Sampling Strategy [{}] should in {}'.format(strategy, list(legal_strategy)))
-        if strategy == 'full' and distribution != 'uniform':
-            raise ValueError('Full Sort can not be sampled by distribution [{}]'.format(distribution))
-        self.neg_sample_args = {'strategy': strategy, 'distribution': distribution}
-        self.neg_sample_args.update(kwargs)
-
-    def neg_sample_by(self, by, distribution='uniform'):
-        """Setting about negative sampling by, which means sample several negative records for each positive records.
-
-        Args:
-            by (int): The number of neg cases for one pos case.
-            distribution (str): distribution of sampler, either ``uniform`` or ``popularity``.
-        """
-        self.set_neg_sampling(strategy='by', by=by, distribution=distribution)
-
-    def set_ordering_and_splitting(self, es_str):
-        """Setting about ordering and split method.
-
-        Args:
-            es_str (str): Ordering and splitting method string. Either ``RO_RS``, ``RO_LS``, ``TO_RS`` or ``TO_LS``.
-        """
-        args = es_str.split('_')
-        if len(args) != 2:
-            raise ValueError(f'`{es_str}` is invalid eval_setting.')
-        ordering_args, split_args = args
-
-        if self.config['group_by_user']:
-            self.group_by_user()
-
-        if ordering_args == 'RO':
-            self.random_ordering()
-        elif ordering_args == 'TO':
-            self.temporal_ordering()
-        else:
-            raise NotImplementedError(f'Ordering args `{ordering_args}` is not implemented.')
-
-        if split_args == 'RS':
-            ratios = self.config['split_ratio']
-            if ratios is None:
-                raise ValueError('`ratios` should be set if `RS` is set.')
-            self.split_by_ratio(ratios)
-        elif split_args == 'LS':
-            leave_one_num = self.config['leave_one_num']
-            if leave_one_num is None:
-                raise ValueError('`leave_one_num` should be set if `LS` is set.')
-            self.leave_one_out(leave_one_num=leave_one_num)
-        else:
-            raise NotImplementedError(f'Split args `{split_args}` is not implemented.')
-
-    def RO_RS(self, ratios=(0.8, 0.1, 0.1), group_by_user=True):
-        """Preset about Random Ordering and Ratio-based Splitting.
-
-        Args:
-            ratios (list of float): ratio of each part.
-                No need to normalize. It's ok with either ``[0.8, 0.1, 0.1]``, ``[8, 1, 1]`` or ``[56, 7, 7]``
-            group_by_user (bool): set group field to user_id if True
-        """
-        if group_by_user:
-            self.group_by_user()
-        self.random_ordering()
-        self.split_by_ratio(ratios)
-
-    def TO_RS(self, ratios=(0.8, 0.1, 0.1), group_by_user=True):
-        """Preset about Temporal Ordering and Ratio-based Splitting.
-
-        Args:
-            ratios (list of float): ratio of each part.
-                No need to normalize. It's ok with either ``[0.8, 0.1, 0.1]``, ``[8, 1, 1]`` or ``[56, 7, 7]``
-            group_by_user (bool): set group field to user_id if True
-        """
-        if group_by_user:
-            self.group_by_user()
-        self.temporal_ordering()
-        self.split_by_ratio(ratios)
-
-    def RO_LS(self, leave_one_num=1, group_by_user=True):
-        """Preset about Random Ordering and Leave-one-out Splitting.
-
-        Args:
-            leave_one_num (int): number of sub datasets for evaluation.
-                E.g. ``leave_one_num=2`` if you have one validation dataset and one test dataset.
-            group_by_user (bool): set group field to user_id if True
-        """
-        if group_by_user:
-            self.group_by_user()
-        self.random_ordering()
-        self.leave_one_out(leave_one_num=leave_one_num)
-
-    def TO_LS(self, leave_one_num=1, group_by_user=True):
-        """Preset about Temporal Ordering and Leave-one-out Splitting.
-
-        Args:
-            leave_one_num (int): number of sub datasets for evaluation.
-                E.g. ``leave_one_num=2`` if you have one validation dataset and one test dataset.
-            group_by_user (bool): set group field to user_id if True
-        """
-        if group_by_user:
-            self.group_by_user()
-        self.temporal_ordering()
-        self.leave_one_out(leave_one_num=leave_one_num)
-
-    def uni100(self):
-        """Preset about uniform sampling 100 items for each positive records while negative sampling.
-        """
-        self.neg_sample_by(100)
-
-    def pop100(self):
-        """Preset about popularity-based sampling 100 items for each positive records while negative sampling.
-        """
-        self.neg_sample_by(100, distribution='popularity')
-
-    def uni1000(self):
-        """Preset about uniform sampling 1000 items for each positive records while negative sampling.
-        """
-        self.neg_sample_by(1000)
-
-    def pop1000(self):
-        """Preset about popularity-based sampling 1000 items for each positive records while negative sampling.
-        """
-        self.neg_sample_by(1000, distribution='popularity')
-
-    def full(self):
-        """Preset about adopt the entire item set (excluding ground-truth items) for ranking.
-        """
-        self.set_neg_sampling(strategy='full')
diff --git a/recbole/data/dataloader/__init__.py b/recbole/data/dataloader/__init__.py
index dce69e125..d0a3a0a31 100644
--- a/recbole/data/dataloader/__init__.py
+++ b/recbole/data/dataloader/__init__.py
@@ -1,9 +1,4 @@
 from recbole.data.dataloader.abstract_dataloader import *
-from recbole.data.dataloader.neg_sample_mixin import *
 from recbole.data.dataloader.general_dataloader import *
-from recbole.data.dataloader.context_dataloader import *
-from recbole.data.dataloader.sequential_dataloader import *
-from recbole.data.dataloader.dien_dataloader import *
 from recbole.data.dataloader.knowledge_dataloader import *
-from recbole.data.dataloader.decisiontree_dataloader import *
 from recbole.data.dataloader.user_dataloader import *
diff --git a/recbole/data/dataloader/abstract_dataloader.py b/recbole/data/dataloader/abstract_dataloader.py
index 73e642472..f69997097 100644
--- a/recbole/data/dataloader/abstract_dataloader.py
+++ b/recbole/data/dataloader/abstract_dataloader.py
@@ -15,10 +15,13 @@
 import math
 from logging import getLogger
 
-from recbole.utils import InputType
+import torch
 
+from recbole.data.interaction import Interaction
+from recbole.utils import InputType, FeatureType, FeatureSource
 
-class AbstractDataLoader(object):
+
+class AbstractDataLoader:
     """:class:`AbstractDataLoader` is an abstract object which would return a batch of data which is loaded by
     :class:`~recbole.data.interaction.Interaction` when it is iterated.
     And it is also the ancestor of all other dataloader.
@@ -26,58 +29,30 @@ class AbstractDataLoader(object):
     Args:
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
+        sampler (Sampler): The sampler of dataloader.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
 
     Attributes:
         dataset (Dataset): The dataset of this dataloader.
         shuffle (bool): If ``True``, dataloader will shuffle before every epoch.
-        real_time (bool): If ``True``, dataloader will do data pre-processing,
-            such as neg-sampling and data-augmentation.
         pr (int): Pointer of dataloader.
         step (int): The increment of :attr:`pr` for each batch.
         batch_size (int): The max interaction number for all batch.
     """
-    dl_type = None
 
-    def __init__(self, config, dataset, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
+    def __init__(self, config, dataset, sampler, shuffle=False):
         self.config = config
         self.logger = getLogger()
         self.dataset = dataset
-        self.batch_size = batch_size
-        self.step = batch_size
-        self.dl_format = dl_format
+        self.sampler = sampler
+        self.batch_size = self.step = None
         self.shuffle = shuffle
         self.pr = 0
-        self.real_time = config['real_time_process']
-        if self.real_time is None:
-            self.real_time = True
-
-        for dataset_attr in self.dataset._dataloader_apis:
-            try:
-                flag = hasattr(self.dataset, dataset_attr)
-                if flag:
-                    setattr(self, dataset_attr, getattr(self.dataset, dataset_attr))
-            except:
-                continue
-
-        self.setup()
-        if not self.real_time:
-            self.data_preprocess()
-
-    def setup(self):
-        """This function can be used to deal with some problems after essential args are initialized,
-        such as the batch-size-adaptation when neg-sampling is needed, and so on. By default, it will do nothing.
-        """
-        pass
+        self._init_batch_size_and_step()
 
-    def data_preprocess(self):
-        """This function is used to do some data preprocess, such as pre-data-augmentation.
-        By default, it will do nothing.
-        """
-        pass
+    def _init_batch_size_and_step(self):
+        """Initializing :attr:`step` and :attr:`batch_size`."""
+        raise NotImplementedError('Method [init_batch_size_and_step] should be implemented')
 
     def __len__(self):
         return math.ceil(self.pr_end / self.step)
@@ -95,11 +70,11 @@ def __next__(self):
 
     @property
     def pr_end(self):
-        """This property marks the end of dataloader.pr which is used in :meth:`__next__()`."""
+        """This property marks the end of dataloader.pr which is used in :meth:`__next__`."""
         raise NotImplementedError('Method [pr_end] should be implemented')
 
     def _shuffle(self):
-        """Shuffle the order of data, and it will be called by :meth:`__iter__()` if self.shuffle is True.
+        """Shuffle the order of data, and it will be called by :meth:`__iter__` if self.shuffle is True.
         """
         raise NotImplementedError('Method [shuffle] should be implemented.')
 
@@ -119,15 +94,79 @@ def set_batch_size(self, batch_size):
         """
         if self.pr != 0:
             raise PermissionError('Cannot change dataloader\'s batch_size while iteration')
-        if self.batch_size != batch_size:
-            self.batch_size = batch_size
-            self.logger.warning(f'Batch size is changed to {batch_size}.')
+        self.batch_size = batch_size
 
-    def upgrade_batch_size(self, batch_size):
-        """Upgrade the batch_size of the dataloader, if input batch_size is bigger than current batch_size.
 
-        Args:
-            batch_size (int): the new batch_size of dataloader.
-        """
-        if self.batch_size < batch_size:
-            self.set_batch_size(batch_size)
+class NegSampleDataLoader(AbstractDataLoader):
+    """:class:`NegSampleDataLoader` is an abstract class which can sample negative examples by ratio.
+    It has two neg-sampling method, the one is 1-by-1 neg-sampling (pair wise),
+    and the other is 1-by-multi neg-sampling (point wise).
+
+    Args:
+        config (Config): The config of dataloader.
+        dataset (Dataset): The dataset of dataloader.
+        sampler (Sampler): The sampler of dataloader.
+        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
+    """
+
+    def __init__(self, config, dataset, sampler, shuffle=True):
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
+
+    def _set_neg_sample_args(self, config, dataset, dl_format, neg_sample_args):
+        self.uid_field = dataset.uid_field
+        self.iid_field = dataset.iid_field
+        self.dl_format = dl_format
+        self.neg_sample_args = neg_sample_args
+        self.times = 1
+        if self.neg_sample_args['strategy'] == 'by':
+            self.neg_sample_num = self.neg_sample_args['by']
+
+            if self.dl_format == InputType.POINTWISE:
+                self.times = 1 + self.neg_sample_num
+                self.sampling_func = self._neg_sample_by_point_wise_sampling
+
+                self.label_field = config['LABEL_FIELD']
+                dataset.set_field_property(self.label_field, FeatureType.FLOAT, FeatureSource.INTERACTION, 1)
+            elif self.dl_format == InputType.PAIRWISE:
+                self.times = self.neg_sample_num
+                self.sampling_func = self._neg_sample_by_pair_wise_sampling
+
+                self.neg_prefix = config['NEG_PREFIX']
+                self.neg_item_id = self.neg_prefix + self.iid_field
+
+                columns = [self.iid_field] if dataset.item_feat is None else dataset.item_feat.columns
+                for item_feat_col in columns:
+                    neg_item_feat_col = self.neg_prefix + item_feat_col
+                    dataset.copy_field_property(neg_item_feat_col, item_feat_col)
+            else:
+                raise ValueError(f'`neg sampling by` with dl_format [{self.dl_format}] not been implemented.')
+
+        elif self.neg_sample_args['strategy'] != 'none':
+            raise ValueError(f'`neg_sample_args` [{self.neg_sample_args["strategy"]}] is not supported!')
+
+    def _neg_sampling(self, inter_feat):
+        if self.neg_sample_args['strategy'] == 'by':
+            user_ids = inter_feat[self.uid_field]
+            item_ids = inter_feat[self.iid_field]
+            neg_item_ids = self.sampler.sample_by_user_ids(user_ids, item_ids, self.neg_sample_num)
+            return self.sampling_func(inter_feat, neg_item_ids)
+        else:
+            return inter_feat
+
+    def _neg_sample_by_pair_wise_sampling(self, inter_feat, neg_item_ids):
+        inter_feat = inter_feat.repeat(self.times)
+        neg_item_feat = Interaction({self.iid_field: neg_item_ids})
+        neg_item_feat = self.dataset.join(neg_item_feat)
+        neg_item_feat.add_prefix(self.neg_prefix)
+        inter_feat.update(neg_item_feat)
+        return inter_feat
+
+    def _neg_sample_by_point_wise_sampling(self, inter_feat, neg_item_ids):
+        pos_inter_num = len(inter_feat)
+        new_data = inter_feat.repeat(self.times)
+        new_data[self.iid_field][pos_inter_num:] = neg_item_ids
+        new_data = self.dataset.join(new_data)
+        labels = torch.zeros(pos_inter_num * self.times)
+        labels[:pos_inter_num] = 1.0
+        new_data.update(Interaction({self.label_field: labels}))
+        return new_data
diff --git a/recbole/data/dataloader/context_dataloader.py b/recbole/data/dataloader/context_dataloader.py
deleted file mode 100644
index 9ca4fc4df..000000000
--- a/recbole/data/dataloader/context_dataloader.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# @Time   : 2020/7/7
-# @Author : Yupeng Hou
-# @Email  : houyupeng@ruc.edu.cn
-
-# UPDATE
-# @Time   : 2020/9/9, 2020/9/16
-# @Author : Yupeng Hou, Yushuo Chen
-# @email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn
-
-"""
-recbole.data.dataloader.context_dataloader
-################################################
-"""
-
-from recbole.data.dataloader.general_dataloader import GeneralDataLoader, GeneralNegSampleDataLoader, \
-    GeneralFullDataLoader
-
-
-class ContextDataLoader(GeneralDataLoader):
-    """:class:`ContextDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
-
-
-class ContextNegSampleDataLoader(GeneralNegSampleDataLoader):
-    """:class:`ContextNegSampleDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralNegSampleDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
-
-
-class ContextFullDataLoader(GeneralFullDataLoader):
-    """:class:`ContextFullDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralFullDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
diff --git a/recbole/data/dataloader/decisiontree_dataloader.py b/recbole/data/dataloader/decisiontree_dataloader.py
deleted file mode 100644
index 996b720a8..000000000
--- a/recbole/data/dataloader/decisiontree_dataloader.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# @Time   : 2020/11/19
-# @Author : Chen Yang
-# @Email  : 254170321@qq.com
-
-# UPDATE:
-# @Time   : 2020/11/19
-# @Author : Chen Yang
-# @Email  : 254170321@qq.com
-
-"""
-recbole.data.dataloader.decisiontree_dataloader
-################################################
-"""
-
-from recbole.data.dataloader.general_dataloader import GeneralDataLoader, GeneralNegSampleDataLoader, \
-    GeneralFullDataLoader
-
-
-class DecisionTreeDataLoader(GeneralDataLoader):
-    """:class:`DecisionTreeDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
-
-
-class DecisionTreeNegSampleDataLoader(GeneralNegSampleDataLoader):
-    """:class:`DecisionTreeNegSampleDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralNegSampleDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
-
-
-class DecisionTreeFullDataLoader(GeneralFullDataLoader):
-    """:class:`DecisionTreeFullDataLoader` is inherit from
-    :class:`~recbole.data.dataloader.general_dataloader.GeneralFullDataLoader`,
-    and didn't add/change anything at all.
-    """
-    pass
diff --git a/recbole/data/dataloader/dien_dataloader.py b/recbole/data/dataloader/dien_dataloader.py
deleted file mode 100644
index 6fb06b321..000000000
--- a/recbole/data/dataloader/dien_dataloader.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# @Time   : 2021/2/25
-# @Author : Zhichao Feng
-# @Email  : fzcbupt@gmail.com
-
-# UPDATE
-# @Time   : 2021/3/19
-# @Author : Zhichao Feng
-# @email  : fzcbupt@gmail.com
-
-"""
-recbole.data.dataloader.dien_dataloader
-################################################
-"""
-
-import torch
-
-from recbole.data.dataloader.sequential_dataloader import SequentialDataLoader, SequentialNegSampleDataLoader, SequentialFullDataLoader
-from recbole.data.interaction import Interaction, cat_interactions
-from recbole.utils import DataLoaderType, FeatureSource, FeatureType, InputType
-from recbole.sampler import SeqSampler
-
-
-class DIENDataLoader(SequentialDataLoader):
-    """:class:`DIENDataLoader` is used for DIEN model. It is different from :class:`SequentialDataLoader` in
-    `augmentation`. It add users' negative item list to interaction.
-    It will do data augmentation for the origin data. And its returned data contains the following:
-
-        - user id
-        - history items list
-        - history negative item list
-        - history items' interaction time list
-        - item to be predicted
-        - the interaction time of item to be predicted
-        - history list length
-        - other interaction information of item to be predicted
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-    dl_type = DataLoaderType.ORIGIN
-
-    def __init__(self, config, dataset, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
-
-        list_suffix = config['LIST_SUFFIX']
-        neg_prefix = config['NEG_PREFIX']
-
-        self.seq_sampler = SeqSampler(dataset)
-        self.iid_field = dataset.iid_field
-        self.neg_item_list_field = neg_prefix + self.iid_field + list_suffix
-        self.neg_item_list = self.seq_sampler.sample_neg_sequence(dataset.inter_feat[self.iid_field])
-
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
-
-    def augmentation(self, item_list_index, target_index, item_list_length):
-        """Data augmentation.
-
-        Args:
-            item_list_index (numpy.ndarray): the index of history items list in interaction.
-            target_index (numpy.ndarray): the index of items to be predicted in interaction.
-            item_list_length (numpy.ndarray): history list length.
-
-        Returns:
-            dict: the augmented data.
-        """
-        new_length = len(item_list_index)
-        new_data = self.dataset.inter_feat[target_index]
-        new_dict = {
-            self.item_list_length_field: torch.tensor(item_list_length),
-        }
-
-        for field in self.dataset.inter_feat:
-            if field != self.uid_field:
-                list_field = getattr(self, f'{field}_list_field')
-                list_len = self.dataset.field2seqlen[list_field]
-                shape = (new_length, list_len) if isinstance(list_len, int) else (new_length,) + list_len
-                list_ftype = self.dataset.field2type[list_field]
-                dtype = torch.int64 if list_ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ] else torch.float64
-                new_dict[list_field] = torch.zeros(shape, dtype=dtype)
-
-                value = self.dataset.inter_feat[field]
-                for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
-                    new_dict[list_field][i][:length] = value[index]
-
-                if field == self.iid_field:
-                    new_dict[self.neg_item_list_field] = torch.zeros(shape, dtype=dtype)
-                    for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
-                        new_dict[self.neg_item_list_field][i][:length] = self.neg_item_list[index]
-
-        new_data.update(Interaction(new_dict))
-        return new_data
-
-
-class DIENNegSampleDataLoader(SequentialNegSampleDataLoader, DIENDataLoader):
-    """:class:`DIENNegSampleDataLoader` is sequential-dataloader with negative sampling for DIEN.
-    Like :class:`~recbole.data.dataloader.general_dataloader.GeneralNegSampleDataLoader`, for the result of every batch,
-    we permit that every positive interaction and its negative interaction must be in the same batch. Beside this,
-    when it is in the evaluation stage, and evaluator is topk-like function, we also permit that all the interactions
-    corresponding to each user are in the same batch and positive interactions are before negative interactions.
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
-
-
-class DIENFullDataLoader(SequentialFullDataLoader, DIENDataLoader):
-    """:class:`DIENFullDataLoader` is a sequential-dataloader with full sort for DIEN. In order to speed up calculation,
-    this dataloader would only return then user part of interactions, positive items and used items.
-    It would not return negative items.
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-    dl_type = DataLoaderType.FULL
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
diff --git a/recbole/data/dataloader/general_dataloader.py b/recbole/data/dataloader/general_dataloader.py
index 818571586..aaefdb6e5 100644
--- a/recbole/data/dataloader/general_dataloader.py
+++ b/recbole/data/dataloader/general_dataloader.py
@@ -3,9 +3,9 @@
 # @Email  : houyupeng@ruc.edu.cn
 
 # UPDATE
-# @Time   : 2020/9/9, 2020/9/29
-# @Author : Yupeng Hou, Yushuo Chen
-# @email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn
+# @Time   : 2020/9/9, 2020/9/29, 2021/7/15
+# @Author : Yupeng Hou, Yushuo Chen, Xingyu Pan
+# @email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, xy_pan@foxmail.com
 
 """
 recbole.data.dataloader.general_dataloader
@@ -15,27 +15,38 @@
 import numpy as np
 import torch
 
-from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader
-from recbole.data.dataloader.neg_sample_mixin import NegSampleMixin, NegSampleByMixin
+from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader, NegSampleDataLoader
 from recbole.data.interaction import Interaction, cat_interactions
-from recbole.utils import DataLoaderType, InputType
+from recbole.utils import InputType, ModelType
 
 
-class GeneralDataLoader(AbstractDataLoader):
-    """:class:`GeneralDataLoader` is used for general model and it just return the origin data.
+class TrainDataLoader(NegSampleDataLoader):
+    """:class:`TrainDataLoader` is a dataloader for training.
+    It can generate negative interaction when :attr:`training_neg_sample_num` is not zero.
+    For the result of every batch, we permit that every positive interaction and its negative interaction
+    must be in the same batch.
 
     Args:
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
+        sampler (Sampler): The sampler of dataloader.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
     """
-    dl_type = DataLoaderType.ORIGIN
 
-    def __init__(self, config, dataset, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        self._set_neg_sample_args(config, dataset, config['MODEL_INPUT_TYPE'], config['train_neg_sample_args'])
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
+
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['train_batch_size']
+        if self.neg_sample_args['strategy'] == 'by':
+            batch_num = max(batch_size // self.times, 1)
+            new_batch_size = batch_num * self.times
+            self.step = batch_num
+            self.set_batch_size(new_batch_size)
+        else:
+            self.step = batch_size
+            self.set_batch_size(batch_size)
 
     @property
     def pr_end(self):
@@ -45,48 +56,32 @@ def _shuffle(self):
         self.dataset.shuffle()
 
     def _next_batch_data(self):
-        cur_data = self.dataset[self.pr:self.pr + self.step]
+        cur_data = self._neg_sampling(self.dataset[self.pr:self.pr + self.step])
         self.pr += self.step
         return cur_data
 
 
-class GeneralNegSampleDataLoader(NegSampleByMixin, AbstractDataLoader):
-    """:class:`GeneralNegSampleDataLoader` is a general-dataloader with negative sampling.
-    For the result of every batch, we permit that every positive interaction and its negative interaction
-    must be in the same batch. Beside this, when it is in the evaluation stage, and evaluator is topk-like function,
-    we also permit that all the interactions corresponding to each user are in the same batch
+class NegSampleEvalDataLoader(NegSampleDataLoader):
+    """:class:`NegSampleEvalDataLoader` is a dataloader for neg-sampling evaluation.
+    It is similar to :class:`TrainDataLoader` which can generate negative items,
+    and this dataloader also permits that all the interactions corresponding to each user are in the same batch
     and positive interactions are before negative interactions.
 
     Args:
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
         sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
     """
 
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        self.uid_field = dataset.uid_field
-        self.iid_field = dataset.iid_field
-        self.uid_list, self.uid2index, self.uid2items_num = None, None, None
-
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
-
-    def setup(self):
-        if self.user_inter_in_one_batch:
-            uid_field = self.dataset.uid_field
-            user_num = self.dataset.user_num
-            self.dataset.sort(by=uid_field, ascending=True)
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        self._set_neg_sample_args(config, dataset, InputType.POINTWISE, config['eval_neg_sample_args'])
+        if self.neg_sample_args['strategy'] == 'by':
+            user_num = dataset.user_num
+            dataset.sort(by=dataset.uid_field, ascending=True)
             self.uid_list = []
             start, end = dict(), dict()
-            for i, uid in enumerate(self.dataset.inter_feat[uid_field].numpy()):
+            for i, uid in enumerate(dataset.inter_feat[dataset.uid_field].numpy()):
                 if uid not in start:
                     self.uid_list.append(uid)
                     start[uid] = i
@@ -97,97 +92,66 @@ def setup(self):
                 self.uid2index[uid] = slice(start[uid], end[uid] + 1)
                 self.uid2items_num[uid] = end[uid] - start[uid] + 1
             self.uid_list = np.array(self.uid_list)
-        self._batch_size_adaptation()
 
-    def _batch_size_adaptation(self):
-        if self.user_inter_in_one_batch:
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
+
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['eval_batch_size']
+        if self.neg_sample_args['strategy'] == 'by':
             inters_num = sorted(self.uid2items_num * self.times, reverse=True)
             batch_num = 1
             new_batch_size = inters_num[0]
             for i in range(1, len(inters_num)):
-                if new_batch_size + inters_num[i] > self.batch_size:
+                if new_batch_size + inters_num[i] > batch_size:
                     break
                 batch_num = i + 1
                 new_batch_size += inters_num[i]
             self.step = batch_num
-            self.upgrade_batch_size(new_batch_size)
+            self.set_batch_size(new_batch_size)
         else:
-            batch_num = max(self.batch_size // self.times, 1)
-            new_batch_size = batch_num * self.times
-            self.step = batch_num
-            self.upgrade_batch_size(new_batch_size)
+            self.step = batch_size
+            self.set_batch_size(batch_size)
 
     @property
     def pr_end(self):
-        if self.user_inter_in_one_batch:
+        if self.neg_sample_args['strategy'] == 'by':
             return len(self.uid_list)
         else:
             return len(self.dataset)
 
     def _shuffle(self):
-        if self.user_inter_in_one_batch:
-            np.random.shuffle(self.uid_list)
-        else:
-            self.dataset.shuffle()
+        self.logger.warnning('NegSampleEvalDataLoader can\'t shuffle')
 
     def _next_batch_data(self):
-        if self.user_inter_in_one_batch:
+        if self.neg_sample_args['strategy'] == 'by':
             uid_list = self.uid_list[self.pr:self.pr + self.step]
             data_list = []
-            for uid in uid_list:
+            idx_list = []
+            positive_u = []
+            positive_i = torch.tensor([], dtype=torch.int64)
+
+            for idx, uid in enumerate(uid_list):
                 index = self.uid2index[uid]
                 data_list.append(self._neg_sampling(self.dataset[index]))
+                idx_list += [idx for i in range(self.uid2items_num[uid] * self.times)]
+                positive_u += [idx for i in range(self.uid2items_num[uid])]
+                positive_i = torch.cat((positive_i, self.dataset[index][self.iid_field]), 0)
+
             cur_data = cat_interactions(data_list)
-            pos_len_list = self.uid2items_num[uid_list]
-            user_len_list = pos_len_list * self.times
-            cur_data.set_additional_info(list(pos_len_list), list(user_len_list))
+            idx_list = torch.from_numpy(np.array(idx_list))
+            positive_u = torch.from_numpy(np.array(positive_u))
+
             self.pr += self.step
-            return cur_data
+
+            return cur_data, idx_list, positive_u, positive_i
         else:
             cur_data = self._neg_sampling(self.dataset[self.pr:self.pr + self.step])
             self.pr += self.step
-            return cur_data
-
-    def _neg_sampling(self, inter_feat):
-        uids = inter_feat[self.uid_field]
-        neg_iids = self.sampler.sample_by_user_ids(uids, self.neg_sample_by)
-        return self.sampling_func(inter_feat, neg_iids)
-
-    def _neg_sample_by_pair_wise_sampling(self, inter_feat, neg_iids):
-        inter_feat = inter_feat.repeat(self.times)
-        neg_item_feat = Interaction({self.iid_field: neg_iids})
-        neg_item_feat = self.dataset.join(neg_item_feat)
-        neg_item_feat.add_prefix(self.neg_prefix)
-        inter_feat.update(neg_item_feat)
-        return inter_feat
-
-    def _neg_sample_by_point_wise_sampling(self, inter_feat, neg_iids):
-        pos_inter_num = len(inter_feat)
-        new_data = inter_feat.repeat(self.times)
-        new_data[self.iid_field][pos_inter_num:] = neg_iids
-        new_data = self.dataset.join(new_data)
-        labels = torch.zeros(pos_inter_num * self.times)
-        labels[:pos_inter_num] = 1.0
-        new_data.update(Interaction({self.label_field: labels}))
-        return new_data
-
-    def get_pos_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of positive item for each user in a training/evaluating epoch.
-        """
-        return self.uid2items_num[self.uid_list]
-
-    def get_user_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of all item for each user in a training/evaluating epoch.
-        """
-        return self.uid2items_num[self.uid_list] * self.times
-
-
-class GeneralFullDataLoader(NegSampleMixin, AbstractDataLoader):
-    """:class:`GeneralFullDataLoader` is a general-dataloader with full sort. In order to speed up calculation,
+            return cur_data, None, None, None
+
+
+class FullSortEvalDataLoader(AbstractDataLoader):
+    """:class:`FullSortEvalDataLoader` is a dataloader for full-sort evaluation. In order to speed up calculation,
     this dataloader would only return then user part of interactions, positive items and used items.
     It would not return negative items.
 
@@ -195,105 +159,87 @@ class GeneralFullDataLoader(NegSampleMixin, AbstractDataLoader):
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
         sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
     """
-    dl_type = DataLoaderType.FULL
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        if neg_sample_args['strategy'] != 'full':
-            raise ValueError('neg_sample strategy in GeneralFullDataLoader() should be `full`')
-
-        uid_field = dataset.uid_field
-        iid_field = dataset.iid_field
-        user_num = dataset.user_num
-        self.uid_list = []
-        self.uid2items_num = np.zeros(user_num, dtype=np.int64)
-        self.uid2swap_idx = np.array([None] * user_num)
-        self.uid2rev_swap_idx = np.array([None] * user_num)
-        self.uid2history_item = np.array([None] * user_num)
-
-        dataset.sort(by=uid_field, ascending=True)
-        last_uid = None
-        positive_item = set()
-        uid2used_item = sampler.used_ids
-        for uid, iid in zip(dataset.inter_feat[uid_field].numpy(), dataset.inter_feat[iid_field].numpy()):
-            if uid != last_uid:
-                self._set_user_property(last_uid, uid2used_item[last_uid], positive_item)
-                last_uid = uid
-                self.uid_list.append(uid)
-                positive_item = set()
-            positive_item.add(iid)
-        self._set_user_property(last_uid, uid2used_item[last_uid], positive_item)
-        self.uid_list = torch.tensor(self.uid_list, dtype=torch.int64)
-        self.user_df = dataset.join(Interaction({uid_field: self.uid_list}))
-
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
+
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        self.uid_field = dataset.uid_field
+        self.iid_field = dataset.iid_field
+        self.is_sequential = config['MODEL_TYPE'] == ModelType.SEQUENTIAL
+        if not self.is_sequential:
+            user_num = dataset.user_num
+            self.uid_list = []
+            self.uid2items_num = np.zeros(user_num, dtype=np.int64)
+            self.uid2positive_item = np.array([None] * user_num)
+            self.uid2history_item = np.array([None] * user_num)
+
+            dataset.sort(by=self.uid_field, ascending=True)
+            last_uid = None
+            positive_item = set()
+            uid2used_item = sampler.used_ids
+            for uid, iid in zip(dataset.inter_feat[self.uid_field].numpy(), dataset.inter_feat[self.iid_field].numpy()):
+                if uid != last_uid:
+                    self._set_user_property(last_uid, uid2used_item[last_uid], positive_item)
+                    last_uid = uid
+                    self.uid_list.append(uid)
+                    positive_item = set()
+                positive_item.add(iid)
+            self._set_user_property(last_uid, uid2used_item[last_uid], positive_item)
+            self.uid_list = torch.tensor(self.uid_list, dtype=torch.int64)
+            self.user_df = dataset.join(Interaction({self.uid_field: self.uid_list}))
+
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
 
     def _set_user_property(self, uid, used_item, positive_item):
         if uid is None:
             return
         history_item = used_item - positive_item
-        positive_item_num = len(positive_item)
-        self.uid2items_num[uid] = positive_item_num
-        swap_idx = torch.tensor(sorted(set(range(positive_item_num)) ^ positive_item))
-        self.uid2swap_idx[uid] = swap_idx
-        self.uid2rev_swap_idx[uid] = swap_idx.flip(0)
+        self.uid2positive_item[uid] = torch.tensor(list(positive_item), dtype=torch.int64)
+        self.uid2items_num[uid] = len(positive_item)
         self.uid2history_item[uid] = torch.tensor(list(history_item), dtype=torch.int64)
 
-    def _batch_size_adaptation(self):
-        batch_num = max(self.batch_size // self.dataset.item_num, 1)
-        new_batch_size = batch_num * self.dataset.item_num
-        self.step = batch_num
-        self.upgrade_batch_size(new_batch_size)
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['eval_batch_size']
+        if not self.is_sequential:
+            batch_num = max(batch_size // self.dataset.item_num, 1)
+            new_batch_size = batch_num * self.dataset.item_num
+            self.step = batch_num
+            self.set_batch_size(new_batch_size)
+        else:
+            self.step = batch_size
+            self.set_batch_size(batch_size)
 
     @property
     def pr_end(self):
-        return len(self.uid_list)
+        if not self.is_sequential:
+            return len(self.uid_list)
+        else:
+            return len(self.dataset)
 
     def _shuffle(self):
-        self.logger.warnning('GeneralFullDataLoader can\'t shuffle')
+        self.logger.warnning('FullSortEvalDataLoader can\'t shuffle')
 
     def _next_batch_data(self):
-        user_df = self.user_df[self.pr:self.pr + self.step]
-        cur_data = self._neg_sampling(user_df)
-        self.pr += self.step
-        return cur_data
+        if not self.is_sequential:
+            user_df = self.user_df[self.pr:self.pr + self.step]
+            uid_list = list(user_df[self.uid_field])
+
+            history_item = self.uid2history_item[uid_list]
+            positive_item = self.uid2positive_item[uid_list]
+
+            history_u = torch.cat([torch.full_like(hist_iid, i) for i, hist_iid in enumerate(history_item)])
+            history_i = torch.cat(list(history_item))
 
-    def _neg_sampling(self, user_df):
-        uid_list = list(user_df[self.dataset.uid_field])
-        pos_len_list = self.uid2items_num[uid_list]
-        user_len_list = np.full(len(uid_list), self.item_num)
-        user_df.set_additional_info(pos_len_list, user_len_list)
-
-        history_item = self.uid2history_item[uid_list]
-        history_row = torch.cat([torch.full_like(hist_iid, i) for i, hist_iid in enumerate(history_item)])
-        history_col = torch.cat(list(history_item))
-
-        swap_idx = self.uid2swap_idx[uid_list]
-        rev_swap_idx = self.uid2rev_swap_idx[uid_list]
-        swap_row = torch.cat([torch.full_like(swap, i) for i, swap in enumerate(swap_idx)])
-        swap_col_after = torch.cat(list(swap_idx))
-        swap_col_before = torch.cat(list(rev_swap_idx))
-        return user_df, (history_row, history_col), swap_row, swap_col_after, swap_col_before
-
-    def get_pos_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of positive item for each user in a training/evaluating epoch.
-        """
-        return self.uid2items_num[self.uid_list]
-
-    def get_user_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of all item for each user in a training/evaluating epoch.
-        """
-        return np.full(self.pr_end, self.item_num)
+            positive_u = torch.cat([torch.full_like(pos_iid, i) for i, pos_iid in enumerate(positive_item)])
+            positive_i = torch.cat(list(positive_item))
+
+            self.pr += self.step
+            return user_df, (history_u, history_i), positive_u, positive_i
+        else:
+            interaction = self.dataset[self.pr:self.pr + self.step]
+            inter_num = len(interaction)
+            positive_u = torch.arange(inter_num)
+            positive_i = interaction[self.iid_field]
+
+            self.pr += self.step
+            return interaction, None, positive_u, positive_i
diff --git a/recbole/data/dataloader/knowledge_dataloader.py b/recbole/data/dataloader/knowledge_dataloader.py
index 6b6bb00ac..db09c2bde 100644
--- a/recbole/data/dataloader/knowledge_dataloader.py
+++ b/recbole/data/dataloader/knowledge_dataloader.py
@@ -11,8 +11,8 @@
 recbole.data.dataloader.knowledge_dataloader
 ################################################
 """
-
-from recbole.data.dataloader import AbstractDataLoader, GeneralNegSampleDataLoader
+from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader
+from recbole.data.dataloader.general_dataloader import TrainDataLoader
 from recbole.data.interaction import Interaction
 from recbole.utils import InputType, KGDataLoaderState
 
@@ -25,9 +25,6 @@ class KGDataLoader(AbstractDataLoader):
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
         sampler (KGSampler): The knowledge graph sampler of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.InputType.PAIRWISE`.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
 
     Attributes:
@@ -35,8 +32,11 @@ class KGDataLoader(AbstractDataLoader):
             However, in :class:`KGDataLoader`, it's guaranteed to be ``True``.
     """
 
-    def __init__(self, config, dataset, sampler, batch_size=1, dl_format=InputType.PAIRWISE, shuffle=False):
-        self.sampler = sampler
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        if shuffle is False:
+            shuffle = True
+            self.logger.warning('kg based dataloader must shuffle the data')
+
         self.neg_sample_num = 1
 
         self.neg_prefix = config['NEG_PREFIX']
@@ -47,15 +47,12 @@ def __init__(self, config, dataset, sampler, batch_size=1, dl_format=InputType.P
         self.neg_tid_field = self.neg_prefix + self.tid_field
         dataset.copy_field_property(self.neg_tid_field, self.tid_field)
 
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
 
-    def setup(self):
-        """Make sure that the :attr:`shuffle` is True. If :attr:`shuffle` is False, it will be changed to True
-        and give a warning to user.
-        """
-        if self.shuffle is False:
-            self.shuffle = True
-            self.logger.warning('kg based dataloader must shuffle the data')
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['train_batch_size']
+        self.step = batch_size
+        self.set_batch_size(batch_size)
 
     @property
     def pr_end(self):
@@ -65,16 +62,13 @@ def _shuffle(self):
         self.dataset.kg_feat.shuffle()
 
     def _next_batch_data(self):
-        cur_data = self._neg_sampling(self.dataset.kg_feat[self.pr:self.pr + self.step])
+        cur_data = self.dataset.kg_feat[self.pr:self.pr + self.step]
+        head_ids = cur_data[self.hid_field]
+        neg_tail_ids = self.sampler.sample_by_entity_ids(head_ids, self.neg_sample_num)
+        cur_data.update(Interaction({self.neg_tid_field: neg_tail_ids}))
         self.pr += self.step
         return cur_data
 
-    def _neg_sampling(self, kg_feat):
-        hids = kg_feat[self.hid_field]
-        neg_tids = self.sampler.sample_by_entity_ids(hids, self.neg_sample_num)
-        kg_feat.update(Interaction({self.neg_tid_field: neg_tids}))
-        return kg_feat
-
 
 class KnowledgeBasedDataLoader(AbstractDataLoader):
     """:class:`KnowledgeBasedDataLoader` is used for knowledge based model.
@@ -88,21 +82,18 @@ class KnowledgeBasedDataLoader(AbstractDataLoader):
         dataset (Dataset): The dataset of dataloader.
         sampler (Sampler): The sampler of dataloader.
         kg_sampler (KGSampler): The knowledge graph sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
 
     Attributes:
-        state (KGDataLoaderState): 
+        state (KGDataLoaderState):
             This dataloader has three states:
 
                 - :obj:`~recbole.utils.enum_type.KGDataLoaderState.RS`
                 - :obj:`~recbole.utils.enum_type.KGDataLoaderState.KG`
                 - :obj:`~recbole.utils.enum_type.KGDataLoaderState.RSKG`
 
-            In the first state, this dataloader would only return the triplets with negative examples in a knowledge graph.
+            In the first state, this dataloader would only return the triplets with negative
+            examples in a knowledge graph.
 
             In the second state, this dataloader would only return the user-item interaction.
 
@@ -110,37 +101,20 @@ class KnowledgeBasedDataLoader(AbstractDataLoader):
             and user-item interaction information.
     """
 
-    def __init__(
-        self,
-        config,
-        dataset,
-        sampler,
-        kg_sampler,
-        neg_sample_args,
-        batch_size=1,
-        dl_format=InputType.POINTWISE,
-        shuffle=False
-    ):
+    def __init__(self, config, dataset, sampler, kg_sampler, shuffle=False):
 
         # using sampler
-        self.general_dataloader = GeneralNegSampleDataLoader(
-            config=config,
-            dataset=dataset,
-            sampler=sampler,
-            neg_sample_args=neg_sample_args,
-            batch_size=batch_size,
-            dl_format=dl_format,
-            shuffle=shuffle
-        )
-
-        # using kg_sampler and dl_format is pairwise
-        self.kg_dataloader = KGDataLoader(
-            config, dataset, kg_sampler, batch_size=batch_size, dl_format=InputType.PAIRWISE, shuffle=True
-        )
+        self.general_dataloader = TrainDataLoader(config, dataset, sampler, shuffle=shuffle)
+
+        # using kg_sampler
+        self.kg_dataloader = KGDataLoader(config, dataset, kg_sampler, shuffle=True)
 
         self.state = None
 
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
+
+    def _init_batch_size_and_step(self):
+        pass
 
     def __iter__(self):
         if self.state is None:
diff --git a/recbole/data/dataloader/neg_sample_mixin.py b/recbole/data/dataloader/neg_sample_mixin.py
deleted file mode 100644
index e21d614ac..000000000
--- a/recbole/data/dataloader/neg_sample_mixin.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# @Time   : 2020/7/7
-# @Author : Yupeng Hou
-# @Email  : houyupeng@ruc.edu.cn
-
-# UPDATE
-# @Time   : 2020/9/9, 2020/9/17
-# @Author : Yupeng Hou, Yushuo Chen
-# @email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn
-
-"""
-recbole.data.dataloader.neg_sample_mixin
-################################################
-"""
-
-from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader
-from recbole.utils import DataLoaderType, EvaluatorType, FeatureSource, FeatureType, InputType
-
-
-class NegSampleMixin(AbstractDataLoader):
-    """:class:`NegSampleMixin` is a abstract class, all dataloaders that need negative sampling should inherit
-    this class. This class provides some necessary parameters and method for negative sampling, such as
-    :attr:`neg_sample_args` and :meth:`_neg_sampling()` and so on.
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-    dl_type = DataLoaderType.NEGSAMPLE
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        if neg_sample_args['strategy'] not in ['by', 'full']:
-            raise ValueError(f"Neg_sample strategy [{neg_sample_args['strategy']}] has not been implemented.")
-
-        self.sampler = sampler
-        self.neg_sample_args = neg_sample_args
-
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
-
-    def setup(self):
-        """Do batch size adaptation.
-        """
-        self._batch_size_adaptation()
-
-    def _batch_size_adaptation(self):
-        """Adjust the batch size to ensure that each positive and negative interaction can be in a batch.
-        """
-        raise NotImplementedError('Method [batch_size_adaptation] should be implemented.')
-
-    def _neg_sampling(self, inter_feat):
-        """
-        Args:
-            inter_feat: The origin user-item interaction table.
-
-        Returns:
-            The user-item interaction table with negative example.
-        """
-        raise NotImplementedError('Method [neg_sampling] should be implemented.')
-
-    def get_pos_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of positive item for each user in a training/evaluating epoch.
-        """
-        raise NotImplementedError('Method [get_pos_len_list] should be implemented.')
-
-    def get_user_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of all item for each user in a training/evaluating epoch.
-        """
-        raise NotImplementedError('Method [get_user_len_list] should be implemented.')
-
-
-class NegSampleByMixin(NegSampleMixin):
-    """:class:`NegSampleByMixin` is an abstract class which can sample negative examples by ratio.
-    It has two neg-sampling method, the one is 1-by-1 neg-sampling (pair wise),
-    and the other is 1-by-multi neg-sampling (point wise).
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        if neg_sample_args['strategy'] != 'by':
-            raise ValueError('neg_sample strategy in GeneralInteractionBasedDataLoader() should be `by`')
-
-        self.user_inter_in_one_batch = (sampler.phase != 'train') and (config['eval_type'] != EvaluatorType.INDIVIDUAL)
-        self.neg_sample_by = neg_sample_args['by']
-
-        if dl_format == InputType.POINTWISE:
-            self.times = 1 + self.neg_sample_by
-            self.sampling_func = self._neg_sample_by_point_wise_sampling
-
-            self.label_field = config['LABEL_FIELD']
-            dataset.set_field_property(self.label_field, FeatureType.FLOAT, FeatureSource.INTERACTION, 1)
-        elif dl_format == InputType.PAIRWISE:
-            self.times = self.neg_sample_by
-            self.sampling_func = self._neg_sample_by_pair_wise_sampling
-
-            self.neg_prefix = config['NEG_PREFIX']
-            iid_field = config['ITEM_ID_FIELD']
-            self.neg_item_id = self.neg_prefix + iid_field
-
-            columns = [iid_field] if dataset.item_feat is None else dataset.item_feat.columns
-            for item_feat_col in columns:
-                neg_item_feat_col = self.neg_prefix + item_feat_col
-                dataset.copy_field_property(neg_item_feat_col, item_feat_col)
-        else:
-            raise ValueError(f'`neg sampling by` with dl_format [{dl_format}] not been implemented.')
-
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
-
-    def _neg_sample_by_pair_wise_sampling(self, *args):
-        """Pair-wise sampling.
-        """
-        raise NotImplementedError('Method [neg_sample_by_pair_wise_sampling] should be implemented.')
-
-    def _neg_sample_by_point_wise_sampling(self, *args):
-        """Point-wise sampling.
-        """
-        raise NotImplementedError('Method [neg_sample_by_point_wise_sampling] should be implemented.')
diff --git a/recbole/data/dataloader/sequential_dataloader.py b/recbole/data/dataloader/sequential_dataloader.py
deleted file mode 100644
index 51d3a845d..000000000
--- a/recbole/data/dataloader/sequential_dataloader.py
+++ /dev/null
@@ -1,294 +0,0 @@
-# @Time   : 2020/7/7
-# @Author : Yupeng Hou
-# @Email  : houyupeng@ruc.edu.cn
-
-# UPDATE
-# @Time   : 2020/10/6, 2020/9/17
-# @Author : Yupeng Hou, Yushuo Chen
-# @email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn
-
-"""
-recbole.data.dataloader.sequential_dataloader
-################################################
-"""
-
-import numpy as np
-import torch
-
-from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader
-from recbole.data.dataloader.neg_sample_mixin import NegSampleByMixin, NegSampleMixin
-from recbole.data.interaction import Interaction, cat_interactions
-from recbole.utils import DataLoaderType, FeatureSource, FeatureType, InputType
-
-
-class SequentialDataLoader(AbstractDataLoader):
-    """:class:`SequentialDataLoader` is used for sequential model. It will do data augmentation for the origin data.
-    And its returned data contains the following:
-
-        - user id
-        - history items list
-        - history items' interaction time list
-        - item to be predicted
-        - the interaction time of item to be predicted
-        - history list length
-        - other interaction information of item to be predicted
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-    dl_type = DataLoaderType.ORIGIN
-
-    def __init__(self, config, dataset, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
-        self.uid_field = dataset.uid_field
-        self.iid_field = dataset.iid_field
-        self.time_field = dataset.time_field
-        self.max_item_list_len = config['MAX_ITEM_LIST_LENGTH']
-
-        list_suffix = config['LIST_SUFFIX']
-        for field in dataset.inter_feat:
-            if field != self.uid_field:
-                list_field = field + list_suffix
-                setattr(self, f'{field}_list_field', list_field)
-                ftype = dataset.field2type[field]
-
-                if ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ]:
-                    list_ftype = FeatureType.TOKEN_SEQ
-                else:
-                    list_ftype = FeatureType.FLOAT_SEQ
-
-                if ftype in [FeatureType.TOKEN_SEQ, FeatureType.FLOAT_SEQ]:
-                    list_len = (self.max_item_list_len, dataset.field2seqlen[field])
-                else:
-                    list_len = self.max_item_list_len
-
-                dataset.set_field_property(list_field, list_ftype, FeatureSource.INTERACTION, list_len)
-
-        self.item_list_length_field = config['ITEM_LIST_LENGTH_FIELD']
-        dataset.set_field_property(self.item_list_length_field, FeatureType.TOKEN, FeatureSource.INTERACTION, 1)
-
-        self.uid_list = dataset.uid_list
-        self.item_list_index = dataset.item_list_index
-        self.target_index = dataset.target_index
-        self.item_list_length = dataset.item_list_length
-        self.pre_processed_data = None
-
-        super().__init__(config, dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
-
-    def data_preprocess(self):
-        """Do data augmentation before training/evaluation.
-        """
-        self.pre_processed_data = self.augmentation(self.item_list_index, self.target_index, self.item_list_length)
-
-    @property
-    def pr_end(self):
-        return len(self.uid_list)
-
-    def _shuffle(self):
-        if self.real_time:
-            new_index = torch.randperm(self.pr_end)
-            self.uid_list = self.uid_list[new_index]
-            self.item_list_index = self.item_list_index[new_index]
-            self.target_index = self.target_index[new_index]
-            self.item_list_length = self.item_list_length[new_index]
-        else:
-            self.pre_processed_data.shuffle()
-
-    def _next_batch_data(self):
-        cur_data = self._get_processed_data(slice(self.pr, self.pr + self.step))
-        self.pr += self.step
-        return cur_data
-
-    def _get_processed_data(self, index):
-        if self.real_time:
-            cur_data = self.augmentation(
-                self.item_list_index[index], self.target_index[index], self.item_list_length[index]
-            )
-        else:
-            cur_data = self.pre_processed_data[index]
-        return cur_data
-
-    def augmentation(self, item_list_index, target_index, item_list_length):
-        """Data augmentation.
-
-        Args:
-            item_list_index (numpy.ndarray): the index of history items list in interaction.
-            target_index (numpy.ndarray): the index of items to be predicted in interaction.
-            item_list_length (numpy.ndarray): history list length.
-
-        Returns:
-            dict: the augmented data.
-        """
-        new_length = len(item_list_index)
-        new_data = self.dataset.inter_feat[target_index]
-        new_dict = {
-            self.item_list_length_field: torch.tensor(item_list_length),
-        }
-
-        for field in self.dataset.inter_feat:
-            if field != self.uid_field:
-                list_field = getattr(self, f'{field}_list_field')
-                list_len = self.dataset.field2seqlen[list_field]
-                shape = (new_length, list_len) if isinstance(list_len, int) else (new_length,) + list_len
-                list_ftype = self.dataset.field2type[list_field]
-                dtype = torch.int64 if list_ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ] else torch.float64
-                new_dict[list_field] = torch.zeros(shape, dtype=dtype)
-
-                value = self.dataset.inter_feat[field]
-                for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
-                    new_dict[list_field][i][:length] = value[index]
-
-        new_data.update(Interaction(new_dict))
-        return new_data
-
-
-class SequentialNegSampleDataLoader(NegSampleByMixin, SequentialDataLoader):
-    """:class:`SequentialNegSampleDataLoader` is sequential-dataloader with negative sampling.
-    Like :class:`~recbole.data.dataloader.general_dataloader.GeneralNegSampleDataLoader`, for the result of every batch,
-    we permit that every positive interaction and its negative interaction must be in the same batch. Beside this,
-    when it is in the evaluation stage, and evaluator is topk-like function, we also permit that all the interactions
-    corresponding to each user are in the same batch and positive interactions are before negative interactions.
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
-
-    def _batch_size_adaptation(self):
-        batch_num = max(self.batch_size // self.times, 1)
-        new_batch_size = batch_num * self.times
-        self.step = batch_num
-        self.upgrade_batch_size(new_batch_size)
-
-    def _next_batch_data(self):
-        cur_data = self._get_processed_data(slice(self.pr, self.pr + self.step))
-        cur_data = self._neg_sampling(cur_data)
-        self.pr += self.step
-
-        if self.user_inter_in_one_batch:
-            cur_data_len = len(cur_data[self.uid_field])
-            pos_len_list = np.ones(cur_data_len // self.times, dtype=np.int64)
-            user_len_list = pos_len_list * self.times
-            cur_data.set_additional_info(list(pos_len_list), list(user_len_list))
-        return cur_data
-
-    def _neg_sampling(self, data):
-        if self.user_inter_in_one_batch:
-            data_len = len(data[self.uid_field])
-            data_list = []
-            for i in range(data_len):
-                uids = data[self.uid_field][i:i + 1]
-                neg_iids = self.sampler.sample_by_user_ids(uids, self.neg_sample_by)
-                cur_data = data[i:i + 1]
-                data_list.append(self.sampling_func(cur_data, neg_iids))
-            return cat_interactions(data_list)
-        else:
-            uids = data[self.uid_field]
-            neg_iids = self.sampler.sample_by_user_ids(uids, self.neg_sample_by)
-            return self.sampling_func(data, neg_iids)
-
-    def _neg_sample_by_pair_wise_sampling(self, data, neg_iids):
-        new_data = data.repeat(self.times)
-        new_data.update(Interaction({self.neg_item_id: neg_iids}))
-        return new_data
-
-    def _neg_sample_by_point_wise_sampling(self, data, neg_iids):
-        pos_inter_num = len(data)
-        new_data = data.repeat(self.times)
-        new_data[self.iid_field][pos_inter_num:] = neg_iids
-        labels = torch.zeros(pos_inter_num * self.times)
-        labels[:pos_inter_num] = 1.0
-        new_data.update(Interaction({self.label_field: labels}))
-        return new_data
-
-    def get_pos_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of positive item for each user in a training/evaluating epoch.
-        """
-        return np.ones(self.pr_end, dtype=np.int64)
-
-    def get_user_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of all item for each user in a training/evaluating epoch.
-        """
-        return np.full(self.pr_end, self.times)
-
-
-class SequentialFullDataLoader(NegSampleMixin, SequentialDataLoader):
-    """:class:`SequentialFullDataLoader` is a sequential-dataloader with full sort. In order to speed up calculation,
-    this dataloader would only return then user part of interactions, positive items and used items.
-    It would not return negative items.
-
-    Args:
-        config (Config): The config of dataloader.
-        dataset (Dataset): The dataset of dataloader.
-        sampler (Sampler): The sampler of dataloader.
-        neg_sample_args (dict): The neg_sample_args of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
-        shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
-    """
-    dl_type = DataLoaderType.FULL
-
-    def __init__(
-        self, config, dataset, sampler, neg_sample_args, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False
-    ):
-        super().__init__(
-            config, dataset, sampler, neg_sample_args, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle
-        )
-
-    def _batch_size_adaptation(self):
-        pass
-
-    def _neg_sampling(self, inter_feat):
-        pass
-
-    def _shuffle(self):
-        self.logger.warnning('SequentialFullDataLoader can\'t shuffle')
-
-    def _next_batch_data(self):
-        interaction = super()._next_batch_data()
-        inter_num = len(interaction)
-        pos_len_list = np.ones(inter_num, dtype=np.int64)
-        user_len_list = np.full(inter_num, self.item_num)
-        interaction.set_additional_info(pos_len_list, user_len_list)
-        scores_row = torch.arange(inter_num).repeat(2)
-        padding_idx = torch.zeros(inter_num, dtype=torch.int64)
-        positive_idx = interaction[self.iid_field]
-        scores_col_after = torch.cat((padding_idx, positive_idx))
-        scores_col_before = torch.cat((positive_idx, padding_idx))
-        return interaction, None, scores_row, scores_col_after, scores_col_before
-
-    def get_pos_len_list(self):
-        """
-        Returns:
-            numpy.ndarray or list: Number of positive item for each user in a training/evaluating epoch.
-        """
-        return np.ones(self.pr_end, dtype=np.int64)
-
-    def get_user_len_list(self):
-        """
-        Returns:
-            numpy.ndarray: Number of all item for each user in a training/evaluating epoch.
-        """
-        return np.full(self.pr_end, self.item_num)
diff --git a/recbole/data/dataloader/user_dataloader.py b/recbole/data/dataloader/user_dataloader.py
index 2d2fd62a0..e49529ca2 100644
--- a/recbole/data/dataloader/user_dataloader.py
+++ b/recbole/data/dataloader/user_dataloader.py
@@ -13,9 +13,8 @@
 """
 import torch
 
-from recbole.data.dataloader import AbstractDataLoader
+from recbole.data.dataloader.abstract_dataloader import AbstractDataLoader
 from recbole.data.interaction import Interaction
-from recbole.utils.enum_type import DataLoaderType, InputType
 
 
 class UserDataLoader(AbstractDataLoader):
@@ -24,30 +23,28 @@ class UserDataLoader(AbstractDataLoader):
     Args:
         config (Config): The config of dataloader.
         dataset (Dataset): The dataset of dataloader.
-        batch_size (int, optional): The batch_size of dataloader. Defaults to ``1``.
-        dl_format (InputType, optional): The input type of dataloader. Defaults to
-            :obj:`~recbole.utils.enum_type.InputType.POINTWISE`.
+        sampler (Sampler): The sampler of dataloader.
         shuffle (bool, optional): Whether the dataloader will be shuffle after a round. Defaults to ``False``.
 
     Attributes:
         shuffle (bool): Whether the dataloader will be shuffle after a round.
             However, in :class:`UserDataLoader`, it's guaranteed to be ``True``.
     """
-    dl_type = DataLoaderType.ORIGIN
 
-    def __init__(self, config, dataset, batch_size=1, dl_format=InputType.POINTWISE, shuffle=False):
+    def __init__(self, config, dataset, sampler, shuffle=False):
+        if shuffle is False:
+            shuffle = True
+            self.logger.warning('UserDataLoader must shuffle the data.')
+
         self.uid_field = dataset.uid_field
         self.user_list = Interaction({self.uid_field: torch.arange(dataset.user_num)})
 
-        super().__init__(config=config, dataset=dataset, batch_size=batch_size, dl_format=dl_format, shuffle=shuffle)
+        super().__init__(config, dataset, sampler, shuffle=shuffle)
 
-    def setup(self):
-        """Make sure that the :attr:`shuffle` is True. If :attr:`shuffle` is False, it will be changed to True
-        and give a warning to user.
-        """
-        if self.shuffle is False:
-            self.shuffle = True
-            self.logger.warning('UserDataLoader must shuffle the data')
+    def _init_batch_size_and_step(self):
+        batch_size = self.config['train_batch_size']
+        self.step = batch_size
+        self.set_batch_size(batch_size)
 
     @property
     def pr_end(self):
diff --git a/recbole/data/dataset/__init__.py b/recbole/data/dataset/__init__.py
index 739e86e46..e1f9d8c82 100644
--- a/recbole/data/dataset/__init__.py
+++ b/recbole/data/dataset/__init__.py
@@ -1,7 +1,6 @@
 from recbole.data.dataset.dataset import Dataset
 from recbole.data.dataset.sequential_dataset import SequentialDataset
 from recbole.data.dataset.kg_dataset import KnowledgeBasedDataset
-from recbole.data.dataset.social_dataset import SocialDataset
-from recbole.data.dataset.kg_seq_dataset import Kg_Seq_Dataset
+from recbole.data.dataset.kg_seq_dataset import KGSeqDataset
 from recbole.data.dataset.decisiontree_dataset import DecisionTreeDataset
 from recbole.data.dataset.customized_dataset import *
diff --git a/recbole/data/dataset/customized_dataset.py b/recbole/data/dataset/customized_dataset.py
index d1e34bab2..f002c79d2 100644
--- a/recbole/data/dataset/customized_dataset.py
+++ b/recbole/data/dataset/customized_dataset.py
@@ -2,6 +2,11 @@
 # @Author : Yupeng Hou
 # @Email  : houyupeng@ruc.edu.cn
 
+# UPDATE
+# @Time   : 2021/7/9
+# @Author : Yupeng Hou
+# @Email  : houyupeng@ruc.edu.cn
+
 """
 recbole.data.customized_dataset
 ##################################
@@ -11,16 +16,120 @@
 Customized datasets named ``[Model Name]Dataset`` can be automatically called.
 """
 
-from recbole.data.dataset import Kg_Seq_Dataset
+import numpy as np
+import torch
+
+from recbole.data.dataset import KGSeqDataset, SequentialDataset
+from recbole.data.interaction import Interaction
+from recbole.sampler import SeqSampler
+from recbole.utils.enum_type import FeatureType
+
+
+class GRU4RecKGDataset(KGSeqDataset):
+
+    def __init__(self, config):
+        super().__init__(config)
 
 
-class GRU4RecKGDataset(Kg_Seq_Dataset):
+class KSRDataset(KGSeqDataset):
 
     def __init__(self, config):
         super().__init__(config)
 
 
-class KSRDataset(Kg_Seq_Dataset):
+class DIENDataset(SequentialDataset):
+    """:class:`DIENDataset` is based on :class:`~recbole.data.dataset.sequential_dataset.SequentialDataset`.
+    It is different from :class:`SequentialDataset` in `data_augmentation`.
+    It add users' negative item list to interaction.
+
+    The original version of sampling negative item list is implemented by Zhichao Feng (fzcbupt@gmail.com) in 2021/2/25,
+    and he updated the codes in 2021/3/19. In 2021/7/9, Yupeng refactored SequentialDataset & SequentialDataLoader,
+    then refactored DIENDataset, either.
+
+    Attributes:
+        augmentation (bool): Whether the interactions should be augmented in RecBole.
+        seq_sample (recbole.sampler.SeqSampler): A sampler used to sample negative item sequence.
+        neg_item_list_field (str): Field name for negative item sequence.
+        neg_item_list (torch.tensor): all users' negative item history sequence.
+    """
 
     def __init__(self, config):
         super().__init__(config)
+
+        list_suffix = config['LIST_SUFFIX']
+        neg_prefix = config['NEG_PREFIX']
+        self.seq_sampler = SeqSampler(self)
+        self.neg_item_list_field = neg_prefix + self.iid_field + list_suffix
+        self.neg_item_list = self.seq_sampler.sample_neg_sequence(self.inter_feat[self.iid_field])
+
+    def data_augmentation(self):
+        """Augmentation processing for sequential dataset.
+
+        E.g., ``u1`` has purchase sequence ``<i1, i2, i3, i4>``,
+        then after augmentation, we will generate three cases.
+
+        ``u1, <i1> | i2``
+
+        (Which means given user_id ``u1`` and item_seq ``<i1>``,
+        we need to predict the next item ``i2``.)
+
+        The other cases are below:
+
+        ``u1, <i1, i2> | i3``
+
+        ``u1, <i1, i2, i3> | i4``
+        """
+        self.logger.debug('data_augmentation')
+
+        self._aug_presets()
+
+        self._check_field('uid_field', 'time_field')
+        max_item_list_len = self.config['MAX_ITEM_LIST_LENGTH']
+        self.sort(by=[self.uid_field, self.time_field], ascending=True)
+        last_uid = None
+        uid_list, item_list_index, target_index, item_list_length = [], [], [], []
+        seq_start = 0
+        for i, uid in enumerate(self.inter_feat[self.uid_field].numpy()):
+            if last_uid != uid:
+                last_uid = uid
+                seq_start = i
+            else:
+                if i - seq_start > max_item_list_len:
+                    seq_start += 1
+                uid_list.append(uid)
+                item_list_index.append(slice(seq_start, i))
+                target_index.append(i)
+                item_list_length.append(i - seq_start)
+
+        uid_list = np.array(uid_list)
+        item_list_index = np.array(item_list_index)
+        target_index = np.array(target_index)
+        item_list_length = np.array(item_list_length, dtype=np.int64)
+
+        new_length = len(item_list_index)
+        new_data = self.inter_feat[target_index]
+        new_dict = {
+            self.item_list_length_field: torch.tensor(item_list_length),
+        }
+
+        for field in self.inter_feat:
+            if field != self.uid_field:
+                list_field = getattr(self, f'{field}_list_field')
+                list_len = self.field2seqlen[list_field]
+                shape = (new_length, list_len) if isinstance(list_len, int) else (new_length,) + list_len
+                list_ftype = self.field2type[list_field]
+                dtype = torch.int64 if list_ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ] else torch.float64
+                new_dict[list_field] = torch.zeros(shape, dtype=dtype)
+
+                value = self.inter_feat[field]
+                for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
+                    new_dict[list_field][i][:length] = value[index]
+
+                # DIEN
+                if field == self.iid_field:
+                    new_dict[self.neg_item_list_field] = torch.zeros(shape, dtype=dtype)
+                    for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
+                        new_dict[self.neg_item_list_field][i][:length] = self.neg_item_list[index]
+
+        new_data.update(Interaction(new_dict))
+        self.inter_feat = new_data
diff --git a/recbole/data/dataset/dataset.py b/recbole/data/dataset/dataset.py
index 6b3bb2c75..f016ab2fb 100644
--- a/recbole/data/dataset/dataset.py
+++ b/recbole/data/dataset/dataset.py
@@ -3,9 +3,9 @@
 # @Email  : houyupeng@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/10/28 2020/10/13, 2020/11/10
+# @Time   : 2021/7/14 2021/7/1, 2020/11/10
 # @Author : Yupeng Hou, Xingyu Pan, Yushuo Chen
-# @Email  : houyupeng@ruc.edu.cn, panxy@ruc.edu.cn, chenyushuo@ruc.edu.cn
+# @Email  : houyupeng@ruc.edu.cn, xy_pan@foxmail.com, chenyushuo@ruc.edu.cn
 
 """
 recbole.data.dataset
@@ -15,7 +15,8 @@
 import copy
 import pickle
 import os
-from collections import Counter
+import yaml
+from collections import Counter, defaultdict
 from logging import getLogger
 
 import numpy as np
@@ -25,9 +26,8 @@
 from scipy.sparse import coo_matrix
 
 from recbole.data.interaction import Interaction
-from recbole.data.utils import dlapi
-from recbole.utils import FeatureSource, FeatureType, get_local_time
-from recbole.utils.utils import set_color
+from recbole.utils import FeatureSource, FeatureType, get_local_time, set_color
+from recbole.utils.url import decide_download, download_url, extract_zip, makedirs, rename_atomic_files
 
 
 class Dataset(object):
@@ -36,7 +36,7 @@ class Dataset(object):
     imputation. Features are stored as :class:`pandas.DataFrame` inside :class:`~recbole.data.dataset.dataset.Dataset`.
     General and Context-aware Models can use this class.
 
-    By calling method :meth:`~recbole.data.dataset.dataset.Dataset.build()`, it will processing dataset into
+    By calling method :meth:`~recbole.data.dataset.dataset.Dataset.build`, it will processing dataset into
     DataLoaders, according to :class:`~recbole.config.eval_setting.EvalSetting`.
 
     Args:
@@ -93,8 +93,6 @@ def __init__(self, config):
         self.config = config
         self.dataset_name = config['dataset']
         self.logger = getLogger()
-        self._dataloader_apis = {'field2type', 'field2source', 'field2id_token'}
-        self._dataloader_apis.update(dlapi.dataloader_apis)
         self._from_scratch()
 
     def _from_scratch(self):
@@ -106,6 +104,7 @@ def _from_scratch(self):
         self._get_preset()
         self._get_field_from_config()
         self._load_data(self.dataset_name, self.dataset_path)
+        self._init_alias()
         self._data_processing()
 
     def _get_preset(self):
@@ -118,6 +117,7 @@ def _get_preset(self):
         self.field2id_token = {}
         self.field2token_id = {}
         self.field2seqlen = self.config['seq_len'] or {}
+        self.alias = {}
         self._preloaded_weight = {}
         self.benchmark_filename_list = self.config['benchmark_filename']
 
@@ -198,6 +198,40 @@ def _build_feat_name_list(self):
                     feat_name_list.append(f'{suf}_feat')
         return feat_name_list
 
+    def _get_download_url(self, url_file, allow_none=False):
+        current_path = os.path.dirname(os.path.realpath(__file__))
+        with open(os.path.join(current_path, f'../../properties/dataset/{url_file}.yaml')) as f:
+            dataset2url = yaml.load(f.read(), Loader=self.config.yaml_loader)
+
+        if self.dataset_name in dataset2url:
+            url = dataset2url[self.dataset_name]
+            return url
+        elif allow_none:
+            return None
+        else:
+            raise ValueError(
+                f'Neither [{self.dataset_path}] exists in the device'
+                f'nor [{self.dataset_name}] a known dataset name.'
+            )
+
+    def _download(self):
+        url = self._get_download_url('url')
+        self.logger.info(f'Prepare to download dataset [{self.dataset_name}] from [{url}].')
+
+        if decide_download(url):
+            makedirs(self.dataset_path)
+            path = download_url(url, self.dataset_path)
+            extract_zip(path, self.dataset_path)
+            os.unlink(path)
+
+            basename = os.path.splitext(os.path.basename(path))[0]
+            rename_atomic_files(self.dataset_path, basename, self.dataset_name)
+
+            self.logger.info('Downloading done.')
+        else:
+            self.logger.info('Stop download.')
+            exit(-1)
+
     def _load_data(self, token, dataset_path):
         """Load features.
 
@@ -208,6 +242,8 @@ def _load_data(self, token, dataset_path):
             token (str): dataset name.
             dataset_path (str): path of dataset dir.
         """
+        if not os.path.exists(dataset_path):
+            self._download()
         self._load_inter_feat(token, dataset_path)
         self.user_feat = self._load_user_or_item_feat(token, dataset_path, FeatureSource.USER, 'uid_field')
         self.item_feat = self._load_user_or_item_feat(token, dataset_path, FeatureSource.ITEM, 'iid_field')
@@ -237,16 +273,20 @@ def _load_inter_feat(self, token, dataset_path):
         else:
             sub_inter_lens = []
             sub_inter_feats = []
+            overall_field2seqlen = defaultdict(int)
             for filename in self.benchmark_filename_list:
                 file_path = os.path.join(dataset_path, f'{token}.{filename}.inter')
                 if os.path.isfile(file_path):
                     temp = self._load_feat(file_path, FeatureSource.INTERACTION)
                     sub_inter_feats.append(temp)
                     sub_inter_lens.append(len(temp))
+                    for field in self.field2seqlen:
+                        overall_field2seqlen[field] = max(overall_field2seqlen[field], self.field2seqlen[field])
                 else:
                     raise ValueError(f'File {file_path} not exist.')
-            inter_feat = pd.concat(sub_inter_feats)
+            inter_feat = pd.concat(sub_inter_feats, ignore_index=True)
             self.inter_feat, self.file_size_list = inter_feat, sub_inter_lens
+            self.field2seqlen = overall_field2seqlen
 
     def _load_user_or_item_feat(self, token, dataset_path, source, field_name):
         """Load user/item features.
@@ -287,7 +327,7 @@ def _load_additional_feat(self, token, dataset_path):
 
         For those additional features, e.g. pretrained entity embedding, user can set them
         as ``config['additional_feat_suffix']``, then they will be loaded and stored in
-        :attr:`feat_name_list`. See :doc:`../user_guide/data/data_args` for details.
+        :attr:`feat_name_list`. See :doc:`../user_guide/data/data_settings` for details.
 
         Args:
             token (str): dataset name.
@@ -307,7 +347,7 @@ def _load_additional_feat(self, token, dataset_path):
 
     def _get_load_and_unload_col(self, source):
         """Parsing ``config['load_col']`` and ``config['unload_col']`` according to source.
-        See :doc:`../user_guide/data/data_args` for detail arg setting.
+        See :doc:`../user_guide/config/data_settings` for detail arg setting.
 
         Args:
             source (FeatureSource): source of input file.
@@ -366,7 +406,8 @@ def _load_feat(self, filepath, source):
         columns = []
         usecols = []
         dtype = {}
-        with open(filepath, 'r') as f:
+        encoding = self.config['encoding']
+        with open(filepath, 'r', encoding=encoding) as f:
             head = f.readline()[:-1]
         for field_type in head.split(field_separator):
             field, ftype = field_type.split(':')
@@ -391,7 +432,9 @@ def _load_feat(self, filepath, source):
             self.logger.warning(f'No columns has been loaded from [{source}]')
             return None
 
-        df = pd.read_csv(filepath, delimiter=self.config['field_separator'], usecols=usecols, dtype=dtype)
+        df = pd.read_csv(
+            filepath, delimiter=self.config['field_separator'], usecols=usecols, dtype=dtype, encoding=encoding
+        )
         df.columns = columns
 
         seq_separator = self.config['seq_separator']
@@ -407,6 +450,38 @@ def _load_feat(self, filepath, source):
             self.field2seqlen[field] = max(map(len, df[field].values))
         return df
 
+    def _set_alias(self, alias_name, default_value):
+        alias = self.config[f'alias_of_{alias_name}'] or []
+        alias = np.array(list(filter(None, default_value)) + alias)
+        _, idx = np.unique(alias, return_index=True)
+        self.alias[alias_name] = alias[np.sort(idx)]
+
+    def _init_alias(self):
+        """Set :attr:`alias_of_user_id` and :attr:`alias_of_item_id`. And set :attr:`_rest_fields`.
+        """
+        self._set_alias('user_id', [self.uid_field])
+        self._set_alias('item_id', [self.iid_field])
+
+        for alias_name_1, alias_1 in self.alias.items():
+            for alias_name_2, alias_2 in self.alias.items():
+                if alias_name_1 != alias_name_2:
+                    intersect = np.intersect1d(alias_1, alias_2, assume_unique=True)
+                    if len(intersect) > 0:
+                        raise ValueError(
+                            f'`alias_of_{alias_name_1}` and `alias_of_{alias_name_2}` '
+                            f'should not have the same field {list(intersect)}.'
+                        )
+
+        self._rest_fields = self.token_like_fields
+        for alias_name, alias in self.alias.items():
+            isin = np.isin(alias, self._rest_fields, assume_unique=True)
+            if isin.all() is False:
+                raise ValueError(
+                    f'`alias_of_{alias_name}` should not contain '
+                    f'non-token-like field {list(alias[~isin])}.'
+                )
+            self._rest_fields = np.setdiff1d(self._rest_fields, alias, assume_unique=True)
+
     def _user_item_feat_preparation(self):
         """Sort :attr:`user_feat` and :attr:`item_feat` by ``user_id`` or ``item_id``.
         Missing values will be filled later.
@@ -418,7 +493,7 @@ def _user_item_feat_preparation(self):
         if self.item_feat is not None:
             new_item_df = pd.DataFrame({self.iid_field: np.arange(self.item_num)})
             self.item_feat = pd.merge(new_item_df, self.item_feat, on=self.iid_field, how='left')
-            self.logger.debug(set_color('ordering item features by user id.', 'green'))
+            self.logger.debug(set_color('ordering item features by item id.', 'green'))
 
     def _preload_weight_matrix(self):
         """Transfer preload weight features into :class:`numpy.ndarray` with shape ``[id_token_length]``
@@ -430,8 +505,7 @@ def _preload_weight_matrix(self):
 
         self.logger.debug(f'Preload weight matrix for {preload_fields}.')
 
-        for preload_id_field in preload_fields:
-            preload_value_field = preload_fields[preload_id_field]
+        for preload_id_field, preload_value_field in preload_fields.items():
             if preload_id_field not in self.field2source:
                 raise ValueError(f'Preload id field [{preload_id_field}] not exist.')
             if preload_value_field not in self.field2source:
@@ -444,40 +518,35 @@ def _preload_weight_matrix(self):
                     f'while preload value field [{preload_value_field}] is from source [{pv_source}], '
                     f'which should be the same.'
                 )
-            for feat_name in self.feat_name_list:
-                feat = getattr(self, feat_name)
-                if preload_id_field in feat:
-                    id_ftype = self.field2type[preload_id_field]
-                    if id_ftype != FeatureType.TOKEN:
-                        raise ValueError(
-                            f'Preload id field [{preload_id_field}] should be type token, but is [{id_ftype}].'
-                        )
-                    value_ftype = self.field2type[preload_value_field]
-                    token_num = self.num(preload_id_field)
-                    if value_ftype == FeatureType.FLOAT:
-                        matrix = np.zeros(token_num)
-                        preload_ids = feat[preload_id_field].values
-                        preload_values = feat[preload_value_field].values
-                        for pid, pv in zip(preload_ids, preload_values):
-                            matrix[pid] = pv
-                    elif value_ftype == FeatureType.FLOAT_SEQ:
-                        max_len = self.field2seqlen[preload_value_field]
-                        matrix = np.zeros((token_num, max_len))
-                        preload_ids = feat[preload_id_field].values
-                        preload_values = feat[preload_value_field].to_list()
-                        for pid, prow in zip(preload_ids, preload_values):
-                            length = len(prow)
-                            if length <= max_len:
-                                matrix[pid, :length] = prow
-                            else:
-                                matrix[pid] = prow[:max_len]
+
+            id_ftype = self.field2type[preload_id_field]
+            value_ftype = self.field2type[preload_value_field]
+            if id_ftype != FeatureType.TOKEN:
+                raise ValueError(f'Preload id field [{preload_id_field}] should be type token, but is [{id_ftype}].')
+            if value_ftype not in {FeatureType.FLOAT, FeatureType.FLOAT_SEQ}:
+                self.logger.warning(
+                    f'Field [{preload_value_field}] with type [{value_ftype}] is not `float` or `float_seq`, '
+                    f'which will not be handled by preload matrix.'
+                )
+                continue
+
+            token_num = self.num(preload_id_field)
+            feat = self.field2feats(preload_id_field)[0]
+            if value_ftype == FeatureType.FLOAT:
+                matrix = np.zeros(token_num)
+                matrix[feat[preload_id_field]] = feat[preload_value_field]
+            else:
+                max_len = self.field2seqlen[preload_value_field]
+                matrix = np.zeros((token_num, max_len))
+                preload_ids = feat[preload_id_field].values
+                preload_values = feat[preload_value_field].to_list()
+                for pid, prow in zip(preload_ids, preload_values):
+                    length = len(prow)
+                    if length <= max_len:
+                        matrix[pid, :length] = prow
                     else:
-                        self.logger.warning(
-                            f'Field [{preload_value_field}] with type [{value_ftype}] is not `float` or `float_seq`, '
-                            f'which will not be handled by preload matrix.'
-                        )
-                        continue
-                    self._preloaded_weight[preload_id_field] = matrix
+                        matrix[pid] = prow[:max_len]
+            self._preloaded_weight[preload_id_field] = matrix
 
     def _fill_nan(self):
         """Missing value imputation.
@@ -518,10 +587,10 @@ def _normalize(self):
         if self.config['normalize_field']:
             fields = self.config['normalize_field']
             for field in fields:
-                ftype = self.field2type[field]
                 if field not in self.field2type:
                     raise ValueError(f'Field [{field}] does not exist.')
-                elif ftype != FeatureType.FLOAT and ftype != FeatureType.FLOAT_SEQ:
+                ftype = self.field2type[field]
+                if ftype != FeatureType.FLOAT and ftype != FeatureType.FLOAT_SEQ:
                     self.logger.warning(f'{field} is not a FLOAT/FLOAT_SEQ feat, which will not be normalized.')
         elif self.config['normalize_all']:
             fields = self.float_like_fields
@@ -530,31 +599,24 @@ def _normalize(self):
 
         self.logger.debug(set_color('Normalized fields', 'blue') + f': {fields}')
 
-        for feat_name in self.feat_name_list:
-            feat = getattr(self, feat_name)
-            for field in feat:
-                if field not in fields:
-                    continue
-                ftype = self.field2type[field]
-                if ftype == FeatureType.FLOAT:
-                    lst = feat[field].values
-                    mx, mn = max(lst), min(lst)
+        for field in fields:
+            for feat in self.field2feats(field):
+
+                def norm(arr):
+                    mx, mn = max(arr), min(arr)
                     if mx == mn:
                         self.logger.warning(f'All the same value in [{field}] from [{feat}_feat].')
-                        feat[field] = 1.0
+                        arr = 1.0
                     else:
-                        feat[field] = (lst - mn) / (mx - mn)
+                        arr = (arr - mn) / (mx - mn)
+                    return arr
+
+                ftype = self.field2type[field]
+                if ftype == FeatureType.FLOAT:
+                    feat[field] = norm(feat[field].values)
                 elif ftype == FeatureType.FLOAT_SEQ:
                     split_point = np.cumsum(feat[field].agg(len))[:-1]
-                    lst = feat[field].agg(np.concatenate)
-                    mx, mn = max(lst), min(lst)
-                    if mx == mn:
-                        self.logger.warning(f'All the same value in [{field}] from [{feat}_feat].')
-                        lst = 1.0
-                    else:
-                        lst = (lst - mn) / (mx - mn)
-                    lst = np.split(lst, split_point)
-                    feat[field] = lst
+                    feat[field] = np.split(norm(feat[field].agg(np.concatenate)), split_point)
 
     def _filter_nan_user_or_item(self):
         """Filter NaN user_id and item_id
@@ -605,45 +667,35 @@ def _remove_duplication(self):
     def _filter_by_inter_num(self):
         """Filter by number of interaction.
 
-        Upper/Lower bounds can be set, only users/items between upper/lower bounds can be remained.
+        The interval of the number of interactions can be set, and only users/items whose number 
+        of interactions is in the specified interval can be retained.
         See :doc:`../user_guide/data/data_args` for detail arg setting.
 
         Note:
-            Lower bound is also called k-core filtering, which means this method will filter loops
-            until all the users and items has at least k interactions.
+            Lower bound of the interval is also called k-core filtering, which means this method 
+            will filter loops until all the users and items has at least k interactions.
         """
         if self.uid_field is None or self.iid_field is None:
             return
 
-        max_user_inter_num = self.config['max_user_inter_num']
-        min_user_inter_num = self.config['min_user_inter_num']
-        max_item_inter_num = self.config['max_item_inter_num']
-        min_item_inter_num = self.config['min_item_inter_num']
+        user_inter_num_interval = self._parse_intervals_str(self.config['user_inter_num_interval'])
+        item_inter_num_interval = self._parse_intervals_str(self.config['item_inter_num_interval'])
 
-        if max_user_inter_num is None and min_user_inter_num is None:
-            user_inter_num = Counter()
-        else:
-            user_inter_num = Counter(self.inter_feat[self.uid_field].values)
-
-        if max_item_inter_num is None and min_item_inter_num is None:
-            item_inter_num = Counter()
-        else:
-            item_inter_num = Counter(self.inter_feat[self.iid_field].values)
+        user_inter_num = Counter(self.inter_feat[self.uid_field].values) if user_inter_num_interval else Counter()
+        item_inter_num = Counter(self.inter_feat[self.iid_field].values) if item_inter_num_interval else Counter()
 
         while True:
             ban_users = self._get_illegal_ids_by_inter_num(
                 field=self.uid_field,
                 feat=self.user_feat,
                 inter_num=user_inter_num,
-                max_num=max_user_inter_num,
-                min_num=min_user_inter_num
+                inter_interval=user_inter_num_interval
             )
             ban_items = self._get_illegal_ids_by_inter_num(
                 field=self.iid_field,
                 feat=self.item_feat,
                 inter_num=item_inter_num,
-                max_num=max_item_inter_num,
-                min_num=min_item_inter_num
+                inter_interval=item_inter_num_interval
             )
 
             if len(ban_users) == 0 and len(ban_items) == 0:
@@ -670,44 +722,94 @@ def _filter_by_inter_num(self):
             self.logger.debug(f'[{len(dropped_index)}] dropped interactions.')
             self.inter_feat.drop(dropped_index, inplace=True)
 
-    def _get_illegal_ids_by_inter_num(self, field, feat, inter_num, max_num=None, min_num=None):
+    def _get_illegal_ids_by_inter_num(self, field, feat, inter_num, inter_interval=None):
         """Given inter feat, return illegal ids, whose inter num out of [min_num, max_num]
 
         Args:
             field (str): field name of user_id or item_id.
             feat (pandas.DataFrame): interaction feature.
             inter_num (Counter): interaction number counter.
-            max_num (int, optional): max number of interaction. Defaults to ``None``.
-            min_num (int, optional): min number of interaction. Defaults to ``None``.
+            inter_interval (list, optional): the allowed interval(s) of the number of interactions. 
+                                              Defaults to ``None``.
 
         Returns:
-            set: illegal ids, whose inter num out of [min_num, max_num]
+            set: illegal ids, whose inter num out of inter_intervals.
         """
         self.logger.debug(
-            set_color('get_illegal_ids_by_inter_num', 'blue') +
-            f': field=[{field}], max_num=[{max_num}], min_num=[{min_num}]'
+            set_color('get_illegal_ids_by_inter_num', 'blue') + f': field=[{field}], inter_interval=[{inter_interval}]'
         )
 
-        max_num = max_num or np.inf
-        min_num = min_num or -1
+        if inter_interval is not None:
+            if len(inter_interval) > 1:
+                self.logger.warning(f'More than one interval of interaction number are given!')
 
-        ids = {id_ for id_ in inter_num if inter_num[id_] < min_num or inter_num[id_] > max_num}
+        ids = {id_ for id_ in inter_num if not self._within_intervals(inter_num[id_], inter_interval)}
 
         if feat is not None:
+            min_num = inter_interval[0][1] if inter_interval else -1
             for id_ in feat[field].values:
                 if inter_num[id_] < min_num:
                     ids.add(id_)
         self.logger.debug(f'[{len(ids)}] illegal_ids_by_inter_num, field=[{field}]')
         return ids
 
+    def _parse_intervals_str(self, intervals_str):
+        """Given string of intervals, return the list of endpoints tuple, where a tuple corresponds to an interval.
+
+        Args:
+            intervals_str (str): the string of intervals, such as "(0,1];[3,4)".
+
+        Returns:
+            list of endpoint tuple, such as [('(', 0, 1.0 , ']'), ('[', 3.0, 4.0 , ')')].
+        """
+        if intervals_str is None:
+            return None
+
+        endpoints = []
+        for endpoint_pair_str in str(intervals_str).split(';'):
+            endpoint_pair_str = endpoint_pair_str.strip()
+            left_bracket, right_bracket = endpoint_pair_str[0], endpoint_pair_str[-1]
+            endpoint_pair = endpoint_pair_str[1:-1].split(',')
+            if not (len(endpoint_pair) == 2 and left_bracket in ['(', '['] and right_bracket in [')', ']']):
+                self.logger.warning(f'{endpoint_pair_str} is an illegal interval!')
+                continue
+
+            left_point, right_point = float(endpoint_pair[0]), float(endpoint_pair[1])
+            if left_point > right_point:
+                self.logger.warning(f'{endpoint_pair_str} is an illegal interval!')
+
+            endpoints.append((left_bracket, left_point, right_point, right_bracket))
+        return endpoints
+
+    def _within_intervals(self, num, intervals):
+        """ return Ture if the num is in the intervals.
+
+        Note:
+            return true when the intervals is None.
+        """
+        result = True
+        for i, (left_bracket, left_point, right_point, right_bracket) in enumerate(intervals):
+            temp_result = num >= left_point if left_bracket == '[' else num > left_point
+            temp_result &= num <= right_point if right_bracket == ']' else num < right_point
+            result = temp_result if i == 0 else result | temp_result
+        return result
+
     def _filter_by_field_value(self):
         """Filter features according to its values.
         """
-        filter_field = []
-        filter_field += self._drop_by_value(self.config['lowest_val'], lambda x, y: x < y)
-        filter_field += self._drop_by_value(self.config['highest_val'], lambda x, y: x > y)
-        filter_field += self._drop_by_value(self.config['equal_val'], lambda x, y: x != y)
-        filter_field += self._drop_by_value(self.config['not_equal_val'], lambda x, y: x == y)
+
+        val_intervals = [] if self.config['val_interval'] is None else self.config['val_interval']
+        self.logger.debug(set_color('drop_by_value', 'blue') + f': val={val_intervals}')
+
+        for field in val_intervals:
+            if field not in self.field2type:
+                raise ValueError(f'Field [{field}] not defined in dataset.')
+            if self.field2type[field] not in {FeatureType.FLOAT, FeatureType.FLOAT_SEQ}:
+                raise ValueError(f'Field [{field}] is not float-like field in dataset, which can\'t be filter.')
+
+            field_val_interval = self._parse_intervals_str(val_intervals[field])
+            for feat in self.field2feats(field):
+                feat.drop(feat.index[~self._within_intervals(feat[field].values, field_val_interval)], inplace=True)
 
     def _reset_index(self):
         """Reset index for all feats in :attr:`feat_name_list`.
@@ -718,33 +820,6 @@ def _reset_index(self):
                 raise ValueError('Some feat is empty, please check the filtering settings.')
             feat.reset_index(drop=True, inplace=True)
 
-    def _drop_by_value(self, val, cmp):
-        """Drop illegal rows by value.
-
-        Args:
-            val (dict): value that compared to.
-            cmp (Callable): return False if a row need to be dropped
-
-        Returns:
-            field names that used to compare with val.
-        """
-        if val is None:
-            return []
-
-        self.logger.debug(set_color('drop_by_value', 'blue') + f': val={val}')
-        filter_field = []
-        for field in val:
-            if field not in self.field2type:
-                raise ValueError(f'Field [{field}] not defined in dataset.')
-            if self.field2type[field] not in {FeatureType.FLOAT, FeatureType.FLOAT_SEQ}:
-                raise ValueError(f'Field [{field}] is not float-like field in dataset, which can\'t be filter.')
-            for feat_name in self.feat_name_list:
-                feat = getattr(self, feat_name)
-                if field in feat:
-                    feat.drop(feat.index[cmp(feat[field].values, val[field])], inplace=True)
-            filter_field.append(field)
-        return filter_field
-
     def _del_col(self, feat, field):
         """Delete columns
 
@@ -807,41 +882,7 @@ def _set_label_by_threshold(self):
                 raise ValueError(f'Field [{field}] not in inter_feat.')
             self._del_col(self.inter_feat, field)
 
-    def _get_fields_in_same_space(self):
-        """Parsing ``config['fields_in_same_space']``. See :doc:`../user_guide/data/data_args` for detail arg setting.
-
-        Note:
-            - Each field can only exist ONCE in ``config['fields_in_same_space']``.
-            - user_id and item_id can not exist in ``config['fields_in_same_space']``.
-            - only token-like fields can exist in ``config['fields_in_same_space']``.
-        """
-        fields_in_same_space = self.config['fields_in_same_space'] or []
-        fields_in_same_space = [set(_) for _ in fields_in_same_space]
-        additional = []
-        token_like_fields = self.token_like_fields
-        for field in token_like_fields:
-            count = 0
-            for field_set in fields_in_same_space:
-                if field in field_set:
-                    count += 1
-            if count == 0:
-                additional.append({field})
-            elif count == 1:
-                continue
-            else:
-                raise ValueError(f'Field [{field}] occurred in `fields_in_same_space` more than one time.')
-
-        for field_set in fields_in_same_space:
-            if self.uid_field in field_set and self.iid_field in field_set:
-                raise ValueError('uid_field and iid_field can\'t in the same ID space')
-            for field in field_set:
-                if field not in token_like_fields:
-                    raise ValueError(f'Field [{field}] is not a token-like field.')
-
-        fields_in_same_space.extend(additional)
-        return fields_in_same_space
-
-    def _get_remap_list(self, field_set):
+    def _get_remap_list(self, field_list):
         """Transfer set of fields in the same remapping space into remap list.
 
         If ``uid_field`` or ``iid_field`` in ``field_set``,
@@ -849,7 +890,7 @@ def _get_remap_list(self, field_set):
         then field in :attr:`user_feat` or :attr:`item_feat` will be remapped next, finally others.
 
         Args:
-            field_set (set): Set of fields in the same remapping space
+            field_list (numpy.ndarray): List of fields in the same remapping space.
 
         Returns:
             list:
@@ -859,29 +900,23 @@ def _get_remap_list(self, field_set):
 
             They will be concatenated in order, and remapped together.
         """
+
         remap_list = []
-        for field, feat in zip([self.uid_field, self.iid_field], [self.user_feat, self.item_feat]):
-            if field in field_set:
-                field_set.remove(field)
-                remap_list.append((self.inter_feat, field, FeatureType.TOKEN))
-                if feat is not None:
-                    remap_list.append((feat, field, FeatureType.TOKEN))
-        for field in field_set:
-            source = self.field2source[field]
-            if isinstance(source, FeatureSource):
-                source = source.value
-            feat = getattr(self, f'{source}_feat')
+        for field in field_list:
             ftype = self.field2type[field]
-            remap_list.append((feat, field, ftype))
+            for feat in self.field2feats(field):
+                remap_list.append((feat, field, ftype))
         return remap_list
 
     def _remap_ID_all(self):
-        """Get ``config['fields_in_same_space']`` firstly, and remap each.
+        """Remap all token-like fields.
         """
-        fields_in_same_space = self._get_fields_in_same_space()
-        self.logger.debug(set_color('fields_in_same_space', 'blue') + f': {fields_in_same_space}')
-        for field_set in fields_in_same_space:
-            remap_list = self._get_remap_list(field_set)
+        for alias in self.alias.values():
+            remap_list = self._get_remap_list(alias)
+            self._remap(remap_list)
+
+        for field in self._rest_fields:
+            remap_list = self._get_remap_list(np.array([field]))
             self._remap(remap_list)
 
     def _concat_remaped_tokens(self, remap_list):
@@ -911,6 +946,8 @@ def _remap(self, remap_list):
         Args:
             remap_list (list): See :meth:`_get_remap_list` for detail.
         """
+        if len(remap_list) == 0:
+            return
         tokens, split_point = self._concat_remaped_tokens(remap_list)
         new_ids_list, mp = pd.factorize(tokens)
         new_ids_list = np.split(new_ids_list + 1, split_point)
@@ -934,7 +971,6 @@ def _change_feat_format(self):
             feat = getattr(self, feat_name)
             setattr(self, feat_name, self._dataframe_to_interaction(feat))
 
-    @dlapi.set()
     def num(self, field):
         """Given ``field``, for token-like fields, return the number of different tokens after remapping,
         for float-like fields, return ``1``.
@@ -952,22 +988,25 @@ def num(self, field):
         else:
             return len(self.field2id_token[field])
 
-    @dlapi.set()
-    def fields(self, ftype=None):
-        """Given type of features, return all the field name of this type.
-        if ``ftype = None``, return all the fields.
+    def fields(self, ftype=None, source=None):
+        """Given type and source of features, return all the field name of this type and source.
+        If ``ftype == None``, the type of returned fields is not restricted.
+        If ``source == None``, the source of returned fields is not restricted.
 
         Args:
-            ftype (FeatureType, optional): Type of features.
+            ftype (FeatureType, optional): Type of features. Defaults to ``None``.
+            source (FeatureSource, optional): Source of features. Defaults to ``None``.
 
         Returns:
             list: List of field names.
         """
         ftype = set(ftype) if ftype is not None else set(FeatureType)
+        source = set(source) if source is not None else set(FeatureSource)
         ret = []
         for field in self.field2type:
             tp = self.field2type[field]
-            if tp in ftype:
+            src = self.field2source[field]
+            if tp in ftype and src in source:
                 ret.append(field)
         return ret
 
@@ -979,7 +1018,7 @@ def float_like_fields(self):
         Returns:
             list: List of field names.
         """
-        return self.fields([FeatureType.FLOAT, FeatureType.FLOAT_SEQ])
+        return self.fields(ftype=[FeatureType.FLOAT, FeatureType.FLOAT_SEQ])
 
     @property
     def token_like_fields(self):
@@ -989,7 +1028,7 @@ def token_like_fields(self):
         Returns:
             list: List of field names.
         """
-        return self.fields([FeatureType.TOKEN, FeatureType.TOKEN_SEQ])
+        return self.fields(ftype=[FeatureType.TOKEN, FeatureType.TOKEN_SEQ])
 
     @property
     def seq_fields(self):
@@ -999,7 +1038,7 @@ def seq_fields(self):
         Returns:
             list: List of field names.
         """
-        return self.fields([FeatureType.FLOAT_SEQ, FeatureType.TOKEN_SEQ])
+        return self.fields(ftype=[FeatureType.FLOAT_SEQ, FeatureType.TOKEN_SEQ])
 
     @property
     def non_seq_fields(self):
@@ -1009,7 +1048,7 @@ def non_seq_fields(self):
         Returns:
             list: List of field names.
         """
-        return self.fields([FeatureType.FLOAT, FeatureType.TOKEN])
+        return self.fields(ftype=[FeatureType.FLOAT, FeatureType.TOKEN])
 
     def set_field_property(self, field, field_type, field_source, field_seqlen):
         """Set a new field's properties.
@@ -1036,7 +1075,24 @@ def copy_field_property(self, dest_field, source_field):
         self.field2source[dest_field] = self.field2source[source_field]
         self.field2seqlen[dest_field] = self.field2seqlen[source_field]
 
-    @dlapi.set()
+    def field2feats(self, field):
+        if field not in self.field2source:
+            raise ValueError(f'Field [{field}] not defined in dataset.')
+        if field == self.uid_field:
+            feats = [self.inter_feat]
+            if self.user_feat is not None:
+                feats.append(self.user_feat)
+        elif field == self.iid_field:
+            feats = [self.inter_feat]
+            if self.item_feat is not None:
+                feats.append(self.item_feat)
+        else:
+            source = self.field2source[field]
+            if not isinstance(source, str):
+                source = source.value
+            feats = [getattr(self, f'{source}_feat')]
+        return feats
+
     def token2id(self, field, tokens):
         """Map external tokens to internal ids.
 
@@ -1051,13 +1107,12 @@ def token2id(self, field, tokens):
             if tokens in self.field2token_id[field]:
                 return self.field2token_id[field][tokens]
             else:
-                raise ValueError(f'token [{token}] is not existed in {field}')
+                raise ValueError(f'token [{tokens}] is not existed in {field}')
         elif isinstance(tokens, (list, np.ndarray)):
             return np.array([self.token2id(field, token) for token in tokens])
         else:
-            raise TypeError(f'The type of tokens [{token}] is not supported')
+            raise TypeError(f'The type of tokens [{tokens}] is not supported')
 
-    @dlapi.set()
     def id2token(self, field, ids):
         """Map internal ids to external tokens.
 
@@ -1076,8 +1131,48 @@ def id2token(self, field, ids):
             else:
                 raise ValueError(f'[{ids}] is not a valid ids.')
 
+    def counter(self, field):
+        """Given ``field``, if it is a token field in ``inter_feat``,
+        return the counter containing the occurrences times in ``inter_feat`` of different tokens,
+        for other cases, raise ValueError.
+
+        Args:
+            field (str): field name to get token counter.
+
+        Returns:
+            Counter: The counter of different tokens.
+        """
+        if field not in self.inter_feat:
+            raise ValueError(f'Field [{field}] is not defined in ``inter_feat``.')
+        if self.field2type[field] == FeatureType.TOKEN:
+            if isinstance(self.inter_feat, pd.DataFrame):
+                return Counter(self.inter_feat[field].values)
+            else:
+                return Counter(self.inter_feat[field].numpy())
+        else:
+            raise ValueError(f'Field [{field}] is not a token field.')
+
+    @property
+    def user_counter(self):
+        """Get the counter containing the occurrences times in ``inter_feat`` of different users.
+
+        Returns:
+            Counter: The counter of different users.
+        """
+        self._check_field('uid_field')
+        return self.counter(self.uid_field)
+
+    @property
+    def item_counter(self):
+        """Get the counter containing the occurrences times in ``inter_feat`` of different items.
+
+        Returns:
+            Counter: The counter of different items.
+        """
+        self._check_field('iid_field')
+        return self.counter(self.iid_field)
+
     @property
-    @dlapi.set()
     def user_num(self):
         """Get the number of different tokens of ``self.uid_field``.
 
@@ -1088,7 +1183,6 @@ def user_num(self):
         return self.num(self.uid_field)
 
     @property
-    @dlapi.set()
     def item_num(self):
         """Get the number of different tokens of ``self.iid_field``.
 
@@ -1150,7 +1244,6 @@ def _check_field(self, *field_names):
             if getattr(self, field_name, None) is None:
                 raise ValueError(f'{field_name} isn\'t set.')
 
-    @dlapi.set()
     def join(self, df):
         """Given interaction feature, join user/item feature into it.
 
@@ -1315,23 +1408,32 @@ def _split_index_by_leave_one_out(self, grouped_index, leave_one_num):
                 pr += 1
         return next_index
 
-    def leave_one_out(self, group_by, leave_one_num=1):
+    def leave_one_out(self, group_by, leave_one_mode):
         """Split interaction records by leave one out strategy.
 
         Args:
             group_by (str): Field name that interaction records should grouped by before splitting.
-            leave_one_num (int, optional): Number of parts whose length is expected to be ``1``.
-                Defaults to ``1``.
+            leave_one_mode (str): The way to leave one out. It can only take three values:
+                'valid_and_test', 'valid_only' and 'test_only'.
 
         Returns:
             list: List of :class:`~Dataset`, whose interaction features has been split.
         """
-        self.logger.debug(f'leave one out, group_by=[{group_by}], leave_one_num=[{leave_one_num}]')
+        self.logger.debug(f'leave one out, group_by=[{group_by}], leave_one_mode=[{leave_one_mode}]')
         if group_by is None:
             raise ValueError('leave one out strategy require a group field')
 
         grouped_inter_feat_index = self._grouped_index(self.inter_feat[group_by].numpy())
-        next_index = self._split_index_by_leave_one_out(grouped_inter_feat_index, leave_one_num)
+        if leave_one_mode == 'valid_and_test':
+            next_index = self._split_index_by_leave_one_out(grouped_inter_feat_index, leave_one_num=2)
+        elif leave_one_mode == 'valid_only':
+            next_index = self._split_index_by_leave_one_out(grouped_inter_feat_index, leave_one_num=1)
+            next_index.append([])
+        elif leave_one_mode == 'test_only':
+            next_index = self._split_index_by_leave_one_out(grouped_inter_feat_index, leave_one_num=1)
+            next_index = [next_index[0], [], next_index[1]]
+        else:
+            raise NotImplementedError(f'The leave_one_mode [{leave_one_mode}] has not been implemented.')
 
         self._drop_unused_col()
         next_df = [self.inter_feat[index] for index in next_index]
@@ -1353,14 +1455,10 @@ def sort(self, by, ascending=True):
         """
         self.inter_feat.sort(by=by, ascending=ascending)
 
-    def build(self, eval_setting):
+    def build(self):
         """Processing dataset according to evaluation setting, including Group, Order and Split.
         See :class:`~recbole.config.eval_setting.EvalSetting` for details.
 
-        Args:
-            eval_setting (:class:`~recbole.config.eval_setting.EvalSetting`):
-                Object contains evaluation settings, which guide the data processing procedure.
-
         Returns:
             list: List of built :class:`Dataset`.
         """
@@ -1371,41 +1469,49 @@ def build(self, eval_setting):
             datasets = [self.copy(self.inter_feat[start:end]) for start, end in zip([0] + cumsum[:-1], cumsum)]
             return datasets
 
-        ordering_args = eval_setting.ordering_args
-        if ordering_args['strategy'] == 'shuffle':
+        # ordering
+        ordering_args = self.config['eval_args']['order']
+        if ordering_args == 'RO':
             self.shuffle()
-        elif ordering_args['strategy'] == 'by':
-            self.sort(by=ordering_args['field'], ascending=ordering_args['ascending'])
-
-        group_field = eval_setting.group_field
-
-        split_args = eval_setting.split_args
-        if split_args['strategy'] == 'by_ratio':
-            datasets = self.split_by_ratio(split_args['ratios'], group_by=group_field)
-        elif split_args['strategy'] == 'by_value':
-            raise NotImplementedError()
-        elif split_args['strategy'] == 'loo':
-            datasets = self.leave_one_out(group_by=group_field, leave_one_num=split_args['leave_one_num'])
+        elif ordering_args == 'TO':
+            self.sort(by=self.time_field)
+        else:
+            raise NotImplementedError(f'The ordering_method [{ordering_args}] has not been implemented.')
+
+        # splitting & grouping
+        split_args = self.config['eval_args']['split']
+        if split_args is None:
+            raise ValueError('The split_args in eval_args should not be None.')
+        if not isinstance(split_args, dict):
+            raise ValueError(f'The split_args [{split_args}] should be a dict.')
+
+        split_mode = list(split_args.keys())[0]
+        assert len(split_args.keys()) == 1
+        group_by = self.config['eval_args']['group_by']
+        if split_mode == 'RS':
+            if not isinstance(split_args['RS'], list):
+                raise ValueError(f'The value of "RS" [{split_args}] should be a list.')
+            if group_by is None or group_by.lower() == 'none':
+                datasets = self.split_by_ratio(split_args['RS'], group_by=None)
+            elif group_by == 'user':
+                datasets = self.split_by_ratio(split_args['RS'], group_by=self.uid_field)
+            else:
+                raise NotImplementedError(f'The grouping method [{group_by}] has not been implemented.')
+        elif split_mode == 'LS':
+            datasets = self.leave_one_out(group_by=self.uid_field, leave_one_mode=split_args['LS'])
         else:
-            datasets = self
+            raise NotImplementedError(f'The splitting_method [{split_mode}] has not been implemented.')
 
         return datasets
 
-    def save(self, filepath):
-        """Saving this :class:`Dataset` object to local path.
-
-        Args:
-            filepath (str): path of saved dir.
+    def save(self):
+        """Saving this :class:`Dataset` object to :attr:`config['checkpoint_dir']`.
         """
-        if (filepath is None) or (not os.path.isdir(filepath)):
-            raise ValueError(f'Filepath [{filepath}] need to be a dir.')
-
-        file = os.path.join(filepath, f'{self.config["dataset"]}-dataset.pth')
+        file = os.path.join(self.config['checkpoint_dir'], f'{self.config["dataset"]}-dataset.pth')
         self.logger.info(set_color('Saving filtered dataset into ', 'pink') + f'[{file}]')
         with open(file, 'wb') as f:
             pickle.dump(self, f)
 
-    @dlapi.set()
     def get_user_feature(self):
         """
         Returns:
@@ -1417,7 +1523,6 @@ def get_user_feature(self):
         else:
             return self.user_feat
 
-    @dlapi.set()
     def get_item_feature(self):
         """
         Returns:
@@ -1514,7 +1619,6 @@ def _create_graph(self, tensor_feat, source_field, target_field, form='dgl', val
         else:
             raise NotImplementedError(f'Graph format [{form}] has not been implemented.')
 
-    @dlapi.set()
     def inter_matrix(self, form='coo', value_field=None):
         """Get sparse matrix that describe interactions between user_id and item_id.
 
@@ -1596,7 +1700,6 @@ def _history_matrix(self, row, value_field=None):
 
         return torch.LongTensor(history_matrix), torch.FloatTensor(history_value), torch.LongTensor(history_len)
 
-    @dlapi.set()
     def history_item_matrix(self, value_field=None):
         """Get dense matrix describe user's history interaction records.
 
@@ -1621,7 +1724,6 @@ def history_item_matrix(self, value_field=None):
         """
         return self._history_matrix(row='user', value_field=value_field)
 
-    @dlapi.set()
     def history_user_matrix(self, value_field=None):
         """Get dense matrix describe item's history interaction records.
 
@@ -1646,7 +1748,6 @@ def history_user_matrix(self, value_field=None):
         """
         return self._history_matrix(row='item', value_field=value_field)
 
-    @dlapi.set()
     def get_preload_weight(self, field):
         """Get preloaded weight matrix, whose rows are sorted by token ids.
 
@@ -1656,7 +1757,7 @@ def get_preload_weight(self, field):
             field (str): preloaded feature field name.
 
         Returns:
-            numpy.ndarray: preloaded weight matrix. See :doc:`../user_guide/data/data_args` for details.
+            numpy.ndarray: preloaded weight matrix. See :doc:`../user_guide/config/data_settings` for details.
         """
         if field not in self._preloaded_weight:
             raise ValueError(f'Field [{field}] not in preload_weight')
diff --git a/recbole/data/dataset/kg_dataset.py b/recbole/data/dataset/kg_dataset.py
index 5a41336b5..c43dfcd56 100644
--- a/recbole/data/dataset/kg_dataset.py
+++ b/recbole/data/dataset/kg_dataset.py
@@ -20,9 +20,8 @@
 from scipy.sparse import coo_matrix
 
 from recbole.data.dataset import Dataset
-from recbole.data.utils import dlapi
-from recbole.utils import FeatureSource, FeatureType
-from recbole.utils.utils import set_color
+from recbole.utils import FeatureSource, FeatureType, set_color
+from recbole.utils.url import decide_download, download_url, extract_zip
 
 
 class KnowledgeBasedDataset(Dataset):
@@ -59,7 +58,7 @@ class KnowledgeBasedDataset(Dataset):
 
     Note:
         :attr:`entity_field` doesn't exist exactly. It's only a symbol,
-        representing entity features. E.g. it can be written into ``config['fields_in_same_space']``.
+        representing entity features.
 
         ``[UI-Relation]`` is a special relation token.
     """
@@ -67,10 +66,6 @@ class KnowledgeBasedDataset(Dataset):
     def __init__(self, config):
         super().__init__(config)
 
-    def _get_preset(self):
-        super()._get_preset()
-        self.field2ent_level = {}
-
     def _get_field_from_config(self):
         super()._get_field_from_config()
 
@@ -84,10 +79,6 @@ def _get_field_from_config(self):
         self.logger.debug(set_color('relation_field', 'blue') + f': {self.relation_field}')
         self.logger.debug(set_color('entity_field', 'blue') + f': {self.entity_field}')
 
-    def _data_processing(self):
-        self._set_field2ent_level()
-        super()._data_processing()
-
     def _data_filtering(self):
         super()._data_filtering()
         self._filter_link()
@@ -111,6 +102,31 @@ def _filter_link(self):
         for ent in illegal_ent:
             del self.entity2item[ent]
 
+    def _download(self):
+        super()._download()
+
+        url = self._get_download_url('kg_url', allow_none=True)
+        if url is None:
+            return
+        self.logger.info(f'Prepare to download linked knowledge graph from [{url}].')
+
+        if decide_download(url):
+            # No need to create dir, as `super()._download()` has created one.
+            path = download_url(url, self.dataset_path)
+            extract_zip(path, self.dataset_path)
+            os.unlink(path)
+            self.logger.info(
+                f'\nLinked KG for [{self.dataset_name}] requires additional conversion '
+                f'to atomic files (.kg and .link).\n'
+                f'Please refer to https://github.com/RUCAIBox/RecSysDatasets/tree/master/conversion_tools#knowledge-aware-datasets '
+                f'for detailed instructions.\n'
+                f'You can run RecBole after the conversion, see you soon.'
+            )
+            exit(0)
+        else:
+            self.logger.info('Stop download.')
+            exit(-1)
+
     def _load_data(self, token, dataset_path):
         super()._load_data(token, dataset_path)
         self.kg_feat = self._load_kg(self.dataset_name, self.dataset_path)
@@ -132,12 +148,6 @@ def _build_feat_name_list(self):
             feat_name_list.append('kg_feat')
         return feat_name_list
 
-    def _restore_saved_dataset(self, saved_dataset):
-        raise NotImplementedError()
-
-    def save(self, filepath):
-        raise NotImplementedError()
-
     def _load_kg(self, token, dataset_path):
         self.logger.debug(set_color(f'Loading kg from [{dataset_path}].', 'green'))
         kg_path = os.path.join(dataset_path, f'{token}.kg')
@@ -172,199 +182,90 @@ def _check_link(self, link):
         assert self.entity_field in link, link_warn_message.format(self.entity_field)
         assert self.iid_field in link, link_warn_message.format(self.iid_field)
 
-    def _get_fields_in_same_space(self):
-        """Parsing ``config['fields_in_same_space']``. See :doc:`../user_guide/data/data_args` for detail arg setting.
-
-        Note:
-            - Each field can only exist ONCE in ``config['fields_in_same_space']``.
-            - user_id and item_id can not exist in ``config['fields_in_same_space']``.
-            - only token-like fields can exist in ``config['fields_in_same_space']``.
-            - ``head_entity_id`` and ``target_entity_id`` should be remapped with ``item_id``.
-        """
-        fields_in_same_space = super()._get_fields_in_same_space()
-        fields_in_same_space = [_ for _ in fields_in_same_space if not self._contain_ent_field(_)]
-        ent_fields = self._get_ent_fields_in_same_space()
-        for field_set in fields_in_same_space:
-            if self.iid_field in field_set:
-                field_set.update(ent_fields)
-        return fields_in_same_space
-
-    def _contain_ent_field(self, field_set):
-        """Return True if ``field_set`` contains entity fields.
-        """
-        flag = False
-        flag |= self.head_entity_field in field_set
-        flag |= self.tail_entity_field in field_set
-        flag |= self.entity_field in field_set
-        return flag
-
-    def _get_ent_fields_in_same_space(self):
-        """Return ``field_set`` that should be remapped together with entities.
-        """
-        fields_in_same_space = super()._get_fields_in_same_space()
-
-        ent_fields = {self.head_entity_field, self.tail_entity_field}
-        for field_set in fields_in_same_space:
-            if self._contain_ent_field(field_set):
-                field_set = self._remove_ent_field(field_set)
-                ent_fields.update(field_set)
-        self.logger.debug(set_color('ent_fields', 'blue') + f': {fields_in_same_space}')
-        return ent_fields
-
-    def _remove_ent_field(self, field_set):
-        """Delete entity fields from ``field_set``.
-        """
-        for field in [self.head_entity_field, self.tail_entity_field, self.entity_field]:
-            if field in field_set:
-                field_set.remove(field)
-        return field_set
-
-    def _set_field2ent_level(self):
-        """For fields that remapped together with ``item_id``,
-        set their levels as ``rec``, otherwise as ``ent``.
-        """
-        fields_in_same_space = self._get_fields_in_same_space()
-        for field_set in fields_in_same_space:
-            if self.iid_field in field_set:
-                for field in field_set:
-                    self.field2ent_level[field] = 'rec'
-        ent_fields = self._get_ent_fields_in_same_space()
-        for field in ent_fields:
-            self.field2ent_level[field] = 'ent'
-
-    def _fields_by_ent_level(self, ent_level):
-        """Given ``ent_level``, return all the field name of this level.
-        """
-        ret = []
-        for field in self.field2ent_level:
-            if self.field2ent_level[field] == ent_level:
-                ret.append(field)
-        return ret
-
-    @property
-    @dlapi.set()
-    def rec_level_ent_fields(self):
-        """Get entity fields remapped together with ``item_id``.
-
-        Returns:
-            list: List of field names.
+    def _init_alias(self):
+        """Add :attr:`alias_of_entity_id`, :attr:`alias_of_relation_id` and update :attr:`_rest_fields`.
         """
-        return self._fields_by_ent_level('rec')
-
-    @property
-    @dlapi.set()
-    def ent_level_ent_fields(self):
-        """Get entity fields remapped together with ``entity_id``.
+        self._set_alias('entity_id', [self.head_entity_field, self.tail_entity_field])
+        self._set_alias('relation_id', [self.relation_field])
 
-        Returns:
-            list: List of field names.
-        """
-        return self._fields_by_ent_level('ent')
+        super()._init_alias()
 
-    def _remap_entities_by_link(self):
-        """Map entity tokens from fields in ``ent`` level
-        to item tokens according to ``.link``.
-        """
-        for ent_field in self.ent_level_ent_fields:
-            source = self.field2source[ent_field]
-            if not isinstance(source, str):
-                source = source.value
-            feat = getattr(self, f'{source}_feat')
-            entity_list = feat[ent_field].values
-            for i, entity_id in enumerate(entity_list):
-                if entity_id in self.entity2item:
-                    entity_list[i] = self.entity2item[entity_id]
-            feat[ent_field] = entity_list
+        self._rest_fields = np.setdiff1d(self._rest_fields, [self.entity_field], assume_unique=True)
 
     def _get_rec_item_token(self):
         """Get set of entity tokens from fields in ``rec`` level.
         """
-        field_set = set(self.rec_level_ent_fields)
-        remap_list = self._get_remap_list(field_set)
+        remap_list = self._get_remap_list(self.alias['item_id'])
         tokens, _ = self._concat_remaped_tokens(remap_list)
         return set(tokens)
 
     def _get_entity_token(self):
         """Get set of entity tokens from fields in ``ent`` level.
         """
-        field_set = set(self.ent_level_ent_fields)
-        remap_list = self._get_remap_list(field_set)
+        remap_list = self._get_remap_list(self.alias['entity_id'])
         tokens, _ = self._concat_remaped_tokens(remap_list)
         return set(tokens)
 
-    def _reset_ent_remapID(self, field, new_id_token):
-        token2id = {}
-        for i, token in enumerate(new_id_token):
-            token2id[token] = i
-        idmap = {}
-        for i, token in enumerate(self.field2id_token[field]):
-            if token not in token2id:
-                continue
-            new_idx = token2id[token]
-            idmap[i] = new_idx
-        source = self.field2source[field]
-        if not isinstance(source, str):
-            source = source.value
-        if source == 'item_id':
-            feats = [self.inter_feat]
-            if self.item_feat is not None:
-                feats.append(self.item_feat)
-        else:
-            feats = [getattr(self, f'{source}_feat')]
-        for feat in feats:
-            old_idx = feat[field].values
-            new_idx = np.array([idmap[_] for _ in old_idx])
-            feat[field] = new_idx
-
-    def _sort_remaped_entities(self, item_tokens):
-        item2order = {}
-        for token in self.field2id_token[self.iid_field]:
-            if token == '[PAD]':
-                item2order[token] = 0
-            elif token in item_tokens and token not in self.item2entity:
-                item2order[token] = 1
-            elif token in self.item2entity or token in self.entity2item:
-                item2order[token] = 2
+    def _reset_ent_remapID(self, field, idmap, id2token, token2id):
+        self.field2id_token[field] = id2token
+        self.field2token_id[field] = token2id
+        for feat in self.field2feats(field):
+            ftype = self.field2type[field]
+            if ftype == FeatureType.TOKEN:
+                old_idx = feat[field].values
             else:
-                item2order[token] = 3
-        item_ent_token_list = list(self.field2id_token[self.iid_field])
-        item_ent_token_list.sort(key=lambda t: item2order[t])
-        item_ent_token_list = np.array(item_ent_token_list)
-        order_list = [item2order[_] for _ in item_ent_token_list]
-        order_cnt = Counter(order_list)
-        layered_num = []
-        for i in range(4):
-            layered_num.append(order_cnt[i])
-        layered_num = np.cumsum(np.array(layered_num))
-        new_id_token = item_ent_token_list[:layered_num[-2]]
-        new_token_id = {t: i for i, t in enumerate(new_id_token)}
-        for field in self.rec_level_ent_fields:
-            self._reset_ent_remapID(field, new_id_token)
-            self.field2id_token[field] = new_id_token
-            self.field2token_id[field] = new_token_id
-        new_id_token = item_ent_token_list[:layered_num[-1]]
-        new_id_token = [self.item2entity[_] if _ in self.item2entity else _ for _ in new_id_token]
-        new_token_id = {t: i for i, t in enumerate(new_id_token)}
-        for field in self.ent_level_ent_fields:
-            self._reset_ent_remapID(field, item_ent_token_list[:layered_num[-1]])
-            self.field2id_token[field] = new_id_token
-            self.field2token_id[field] = new_token_id
-        self.field2id_token[self.entity_field] = new_id_token
-        self.field2token_id[self.entity_field] = new_token_id
+                old_idx = feat[field].agg(np.concatenate)
 
-    def _remap_ID_all(self):
-        """Firstly, remap entities and items all together. Then sort entity tokens,
-        then three kinds of entities can be apart away from each other.
+            new_idx = idmap[old_idx]
+
+            if ftype == FeatureType.TOKEN:
+                feat[field] = new_idx
+            else:
+                split_point = np.cumsum(feat[field].agg(len))[:-1]
+                feat[field] = np.split(new_idx, split_point)
+
+    def _merge_item_and_entity(self):
+        """Merge item-id and entity-id into the same id-space.
         """
-        self._remap_entities_by_link()
-        item_tokens = self._get_rec_item_token()
+        item_token = self.field2id_token[self.iid_field]
+        entity_token = self.field2id_token[self.head_entity_field]
+        item_num = len(item_token)
+        link_num = len(self.item2entity)
+        entity_num = len(entity_token)
+
+        # reset item id
+        item_priority = np.array([token in self.item2entity for token in item_token])
+        item_order = np.argsort(item_priority, kind='stable')
+        item_id_map = np.zeros_like(item_order)
+        item_id_map[item_order] = np.arange(item_num)
+        new_item_id2token = item_token[item_order]
+        new_item_token2id = {t: i for i, t in enumerate(new_item_id2token)}
+        for field in self.alias['item_id']:
+            self._reset_ent_remapID(field, item_id_map, new_item_id2token, new_item_token2id)
+
+        # reset entity id
+        entity_priority = np.array([token != '[PAD]' and token not in self.entity2item for token in entity_token])
+        entity_order = np.argsort(entity_priority, kind='stable')
+        entity_id_map = np.zeros_like(entity_order)
+        for i in entity_order[1:link_num + 1]:
+            entity_id_map[i] = new_item_token2id[self.entity2item[entity_token[i]]]
+        entity_id_map[entity_order[link_num + 1:]] = np.arange(item_num, item_num + entity_num - link_num - 1)
+        new_entity_id2token = np.concatenate([new_item_id2token, entity_token[entity_order[link_num + 1:]]])
+        for i in range(item_num - link_num, item_num):
+            new_entity_id2token[i] = self.item2entity[new_entity_id2token[i]]
+        new_entity_token2id = {t: i for i, t in enumerate(new_entity_id2token)}
+        for field in self.alias['entity_id']:
+            self._reset_ent_remapID(field, entity_id_map, new_entity_id2token, new_entity_token2id)
+        self.field2id_token[self.entity_field] = new_entity_id2token
+        self.field2token_id[self.entity_field] = new_entity_token2id
+
+    def _remap_ID_all(self):
         super()._remap_ID_all()
-        self._sort_remaped_entities(item_tokens)
+        self._merge_item_and_entity()
         self.field2token_id[self.relation_field]['[UI-Relation]'] = len(self.field2id_token[self.relation_field])
         self.field2id_token[self.relation_field] = np.append(self.field2id_token[self.relation_field], '[UI-Relation]')
 
     @property
-    @dlapi.set()
     def relation_num(self):
         """Get the number of different tokens of ``self.relation_field``.
 
@@ -374,7 +275,6 @@ def relation_num(self):
         return self.num(self.relation_field)
 
     @property
-    @dlapi.set()
     def entity_num(self):
         """Get the number of different tokens of entities, including virtual entities.
 
@@ -384,7 +284,6 @@ def entity_num(self):
         return self.num(self.entity_field)
 
     @property
-    @dlapi.set()
     def head_entities(self):
         """
         Returns:
@@ -393,7 +292,6 @@ def head_entities(self):
         return self.kg_feat[self.head_entity_field].numpy()
 
     @property
-    @dlapi.set()
     def tail_entities(self):
         """
         Returns:
@@ -402,7 +300,6 @@ def tail_entities(self):
         return self.kg_feat[self.tail_entity_field].numpy()
 
     @property
-    @dlapi.set()
     def relations(self):
         """
         Returns:
@@ -411,7 +308,6 @@ def relations(self):
         return self.kg_feat[self.relation_field].numpy()
 
     @property
-    @dlapi.set()
     def entities(self):
         """
         Returns:
@@ -419,7 +315,6 @@ def entities(self):
         """
         return np.arange(self.entity_num)
 
-    @dlapi.set()
     def kg_graph(self, form='coo', value_field=None):
         """Get graph or sparse matrix that describe relations between entities.
 
@@ -520,7 +415,6 @@ def _create_ckg_graph(self, form='dgl', show_relation=False):
         else:
             raise NotImplementedError(f'Graph format [{form}] has not been implemented.')
 
-    @dlapi.set()
     def ckg_graph(self, form='coo', value_field=None):
         """Get graph or sparse matrix that describe relations of CKG,
         which combines interactions and kg triplets into the same graph.
diff --git a/recbole/data/dataset/kg_seq_dataset.py b/recbole/data/dataset/kg_seq_dataset.py
index ac4ecf108..288c95a03 100644
--- a/recbole/data/dataset/kg_seq_dataset.py
+++ b/recbole/data/dataset/kg_seq_dataset.py
@@ -10,7 +10,7 @@
 from recbole.data.dataset import SequentialDataset, KnowledgeBasedDataset
 
 
-class Kg_Seq_Dataset(SequentialDataset, KnowledgeBasedDataset):
+class KGSeqDataset(SequentialDataset, KnowledgeBasedDataset):
     """Containing both processing of Sequential Models and Knowledge-based Models.
 
     Inherit from :class:`~recbole.data.dataset.sequential_dataset.SequentialDataset` and
diff --git a/recbole/data/dataset/sequential_dataset.py b/recbole/data/dataset/sequential_dataset.py
index 103c81296..82146b123 100644
--- a/recbole/data/dataset/sequential_dataset.py
+++ b/recbole/data/dataset/sequential_dataset.py
@@ -3,20 +3,21 @@
 # @Email  : chenyushuo@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/9/16
-# @Author : Yushuo Chen
-# @Email  : chenyushuo@ruc.edu.cn
+# @Time   : 2020/9/16, 2021/7/1, 2021/7/11
+# @Author : Yushuo Chen, Xingyu Pan, Yupeng Hou
+# @Email  : chenyushuo@ruc.edu.cn, xy_pan@foxmail.com, houyupeng@ruc.edu.cn
 
 """
 recbole.data.sequential_dataset
 ###############################
 """
 
-import copy
-
 import numpy as np
+import torch
 
 from recbole.data.dataset import Dataset
+from recbole.data.interaction import Interaction
+from recbole.utils.enum_type import FeatureType, FeatureSource
 
 
 class SequentialDataset(Dataset):
@@ -25,20 +26,51 @@ class SequentialDataset(Dataset):
     which can accelerate the data loader.
 
     Attributes:
-        uid_list (numpy.ndarray): List of user id after augmentation.
+        max_item_list_len (int): Max length of historical item list.
+        item_list_length_field (str): Field name for item lists' length.
+    """
 
-        item_list_index (numpy.ndarray): List of indexes of item sequence after augmentation.
+    def __init__(self, config):
+        self.max_item_list_len = config['MAX_ITEM_LIST_LENGTH']
+        self.item_list_length_field = config['ITEM_LIST_LENGTH_FIELD']
+        super().__init__(config)
+        if config['benchmark_filename'] is not None:
+            self._benchmark_presets()
 
-        target_index (numpy.ndarray): List of indexes of target item id after augmentation.
+    def _change_feat_format(self):
+        """Change feat format from :class:`pandas.DataFrame` to :class:`Interaction`,
+           then perform data augmentation.
+        """
+        super()._change_feat_format()
 
-        item_list_length (numpy.ndarray): List of item sequences' length after augmentation.
+        if self.config['benchmark_filename'] is not None:
+            return
+        self.logger.debug('Augmentation for sequential recommendation.')
+        self.data_augmentation()
 
-    """
+    def _aug_presets(self):
+        list_suffix = self.config['LIST_SUFFIX']
+        for field in self.inter_feat:
+            if field != self.uid_field:
+                list_field = field + list_suffix
+                setattr(self, f'{field}_list_field', list_field)
+                ftype = self.field2type[field]
 
-    def __init__(self, config):
-        super().__init__(config)
+                if ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ]:
+                    list_ftype = FeatureType.TOKEN_SEQ
+                else:
+                    list_ftype = FeatureType.FLOAT_SEQ
 
-    def prepare_data_augmentation(self):
+                if ftype in [FeatureType.TOKEN_SEQ, FeatureType.FLOAT_SEQ]:
+                    list_len = (self.max_item_list_len, self.field2seqlen[field])
+                else:
+                    list_len = self.max_item_list_len
+
+                self.set_field_property(list_field, list_ftype, FeatureSource.INTERACTION, list_len)
+
+        self.set_field_property(self.item_list_length_field, FeatureType.TOKEN, FeatureSource.INTERACTION, 1)
+
+    def data_augmentation(self):
         """Augmentation processing for sequential dataset.
 
         E.g., ``u1`` has purchase sequence ``<i1, i2, i3, i4>``,
@@ -54,14 +86,10 @@ def prepare_data_augmentation(self):
         ``u1, <i1, i2> | i3``
 
         ``u1, <i1, i2, i3> | i4``
-
-        Note:
-            Actually, we do not really generate these new item sequences.
-            One user's item sequence is stored only once in memory.
-            We store the index (slice) of each item sequence after augmentation,
-            which saves memory and accelerates a lot.
         """
-        self.logger.debug('prepare_data_augmentation')
+        self.logger.debug('data_augmentation')
+
+        self._aug_presets()
 
         self._check_field('uid_field', 'time_field')
         max_item_list_len = self.config['MAX_ITEM_LIST_LENGTH']
@@ -81,34 +109,41 @@ def prepare_data_augmentation(self):
                 target_index.append(i)
                 item_list_length.append(i - seq_start)
 
-        self.uid_list = np.array(uid_list)
-        self.item_list_index = np.array(item_list_index)
-        self.target_index = np.array(target_index)
-        self.item_list_length = np.array(item_list_length, dtype=np.int64)
-        self.mask = np.ones(len(self.inter_feat), dtype=np.bool)
-
-    def leave_one_out(self, group_by, leave_one_num=1):
-        self.logger.debug(f'Leave one out, group_by=[{group_by}], leave_one_num=[{leave_one_num}].')
-        if group_by is None:
-            raise ValueError('Leave one out strategy require a group field.')
-        if group_by != self.uid_field:
-            raise ValueError('Sequential models require group by user.')
-
-        self.prepare_data_augmentation()
-        grouped_index = self._grouped_index(self.uid_list)
-        next_index = self._split_index_by_leave_one_out(grouped_index, leave_one_num)
-
-        self._drop_unused_col()
-        next_ds = []
-        for index in next_index:
-            ds = copy.copy(self)
-            for field in ['uid_list', 'item_list_index', 'target_index', 'item_list_length']:
-                setattr(ds, field, np.array(getattr(ds, field)[index]))
-            setattr(ds, 'mask', np.ones(len(self.inter_feat), dtype=np.bool))
-            next_ds.append(ds)
-        next_ds[0].mask[self.target_index[next_index[1] + next_index[2]]] = False
-        next_ds[1].mask[self.target_index[next_index[2]]] = False
-        return next_ds
+        uid_list = np.array(uid_list)
+        item_list_index = np.array(item_list_index)
+        target_index = np.array(target_index)
+        item_list_length = np.array(item_list_length, dtype=np.int64)
+
+        new_length = len(item_list_index)
+        new_data = self.inter_feat[target_index]
+        new_dict = {
+            self.item_list_length_field: torch.tensor(item_list_length),
+        }
+
+        for field in self.inter_feat:
+            if field != self.uid_field:
+                list_field = getattr(self, f'{field}_list_field')
+                list_len = self.field2seqlen[list_field]
+                shape = (new_length, list_len) if isinstance(list_len, int) else (new_length,) + list_len
+                list_ftype = self.field2type[list_field]
+                dtype = torch.int64 if list_ftype in [FeatureType.TOKEN, FeatureType.TOKEN_SEQ] else torch.float64
+                new_dict[list_field] = torch.zeros(shape, dtype=dtype)
+
+                value = self.inter_feat[field]
+                for i, (index, length) in enumerate(zip(item_list_index, item_list_length)):
+                    new_dict[list_field][i][:length] = value[index]
+
+        new_data.update(Interaction(new_dict))
+        self.inter_feat = new_data
+
+    def _benchmark_presets(self):
+        list_suffix = self.config['LIST_SUFFIX']
+        for field in self.inter_feat:
+            if field + list_suffix in self.inter_feat:
+                list_field = field + list_suffix
+                setattr(self, f'{field}_list_field', list_field)
+        self.set_field_property(self.item_list_length_field, FeatureType.TOKEN, FeatureSource.INTERACTION, 1)
+        self.inter_feat[self.item_list_length_field] = self.inter_feat[self.item_id_list_field].agg(len)
 
     def inter_matrix(self, form='coo', value_field=None):
         """Get sparse matrix that describe interactions between user_id and item_id.
@@ -127,29 +162,33 @@ def inter_matrix(self, form='coo', value_field=None):
         if not self.uid_field or not self.iid_field:
             raise ValueError('dataset does not exist uid/iid, thus can not converted to sparse matrix.')
 
-        self.logger.warning(
-            'Load interaction matrix may lead to label leakage from testing phase, this implementation '
-            'only provides the interactions corresponding to specific phase'
-        )
-        local_inter_feat = self.inter_feat[self.mask]  # TODO: self.mask will applied to _history_matrix() in future
+        l1_idx = (self.inter_feat[self.item_list_length_field] == 1)
+        l1_inter_dict = self.inter_feat[l1_idx].interaction
+        new_dict = {}
+        list_suffix = self.config['LIST_SUFFIX']
+        candidate_field_set = set()
+        for field in l1_inter_dict:
+            if field != self.uid_field and field + list_suffix in l1_inter_dict:
+                candidate_field_set.add(field)
+                new_dict[field] = torch.cat([self.inter_feat[field], l1_inter_dict[field + list_suffix][:, 0]])
+            elif (not field.endswith(list_suffix)) and (field != self.item_list_length_field):
+                new_dict[field] = torch.cat([self.inter_feat[field], l1_inter_dict[field]])
+        local_inter_feat = Interaction(new_dict)
         return self._create_sparse_matrix(local_inter_feat, self.uid_field, self.iid_field, form, value_field)
 
-    def build(self, eval_setting):
-        self._change_feat_format()
-
-        ordering_args = eval_setting.ordering_args
-        if ordering_args['strategy'] == 'shuffle':
-            raise ValueError('Ordering strategy `shuffle` is not supported in sequential models.')
-        elif ordering_args['strategy'] == 'by':
-            if ordering_args['field'] != self.time_field:
-                raise ValueError('Sequential models require `TO` (time ordering) strategy.')
-            if ordering_args['ascending'] is not True:
-                raise ValueError('Sequential models require `time_field` to sort in ascending order.')
-
-        group_field = eval_setting.group_field
-
-        split_args = eval_setting.split_args
-        if split_args['strategy'] == 'loo':
-            return self.leave_one_out(group_by=group_field, leave_one_num=split_args['leave_one_num'])
-        else:
-            ValueError('Sequential models require `loo` (leave one out) split strategy.')
+    def build(self):
+        """Processing dataset according to evaluation setting, including Group, Order and Split.
+        See :class:`~recbole.config.eval_setting.EvalSetting` for details.
+
+        Args:
+            eval_setting (:class:`~recbole.config.eval_setting.EvalSetting`):
+                Object contains evaluation settings, which guide the data processing procedure.
+
+        Returns:
+            list: List of built :class:`Dataset`.
+        """
+        ordering_args = self.config['eval_args']['order']
+        if ordering_args != 'TO':
+            raise ValueError(f'The ordering args for sequential recommendation has to be \'TO\'')
+
+        return super().build()
diff --git a/recbole/data/dataset/social_dataset.py b/recbole/data/dataset/social_dataset.py
deleted file mode 100644
index 0710e878e..000000000
--- a/recbole/data/dataset/social_dataset.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# @Time   : 2020/9/3
-# @Author : Yupeng Hou
-# @Email  : houyupeng@ruc.edu.cn
-
-# UPDATE:
-# @Time   : 2020/10/9, 2020/9/15, 2020/9/22
-# @Author : Yupeng Hou, Xingyu Pan, Yushuo Chen
-# @Email  : houyupeng@ruc.edu.cn, panxy@ruc.edu.cn, chenyushuo@ruc.edu.cn
-
-"""
-recbole.data.social_dataset
-#############################
-"""
-
-import os
-
-from recbole.data.dataset import Dataset
-from recbole.data.utils import dlapi
-from recbole.utils import FeatureSource
-from recbole.utils.utils import set_color
-
-
-class SocialDataset(Dataset):
-    """:class:`SocialDataset` is based on :class:`~recbole.data.dataset.dataset.Dataset`,
-    and load ``.net`` additionally.
-
-    It also provides several interfaces to transfer ``.net`` features into coo sparse matrix,
-    csr sparse matrix, :class:`DGL.Graph` or :class:`PyG.Data`.
-
-    Attributes:
-        source_field (str): The same as ``config['SOURCE_ID_FIELD']``.
-
-        target_field (str): The same as ``config['TARGET_ID_FIELD']``.
-
-        net_feat (pandas.DataFrame): Internal data structure stores the network features.
-            It's loaded from file ``.net``.
-    """
-
-    def __init__(self, config):
-        super().__init__(config)
-
-    def _get_field_from_config(self):
-        super()._get_field_from_config()
-
-        self.source_field = self.config['SOURCE_ID_FIELD']
-        self.target_field = self.config['TARGET_ID_FIELD']
-        self._check_field('source_field', 'target_field')
-
-        self.logger.debug(set_color('source_id_field', 'blue') + f': {self.source_field}')
-        self.logger.debug(set_color('target_id_field', 'blue') + f': {self.target_field}')
-
-    def _load_data(self, token, dataset_path):
-        """Load ``.net`` additionally.
-        """
-        super()._load_data(token, dataset_path)
-        self.net_feat = self._load_net(self.dataset_name, self.dataset_path)
-
-    def _build_feat_name_list(self):
-        feat_name_list = super()._build_feat_name_list()
-        if self.net_feat is not None:
-            feat_name_list.append('net_feat')
-        return feat_name_list
-
-    def _load_net(self, dataset_name, dataset_path):
-        net_file_path = os.path.join(dataset_path, f'{dataset_name}.net')
-        if os.path.isfile(net_file_path):
-            net_feat = self._load_feat(net_file_path, FeatureSource.NET)
-            if net_feat is None:
-                raise ValueError('.net file exist, but net_feat is None, please check your load_col')
-            return net_feat
-        else:
-            raise ValueError(f'File {net_file_path} not exist.')
-
-    def _get_fields_in_same_space(self):
-        """Parsing ``config['fields_in_same_space']``. See :doc:`../user_guide/data/data_args` for detail arg setting.
-
-        Note:
-            - Each field can only exist ONCE in ``config['fields_in_same_space']``.
-            - user_id and item_id can not exist in ``config['fields_in_same_space']``.
-            - only token-like fields can exist in ``config['fields_in_same_space']``.
-            - ``source_id`` and ``target_id`` should be remapped with ``user_id``.
-        """
-        fields_in_same_space = super()._get_fields_in_same_space()
-        fields_in_same_space = [
-            _ for _ in fields_in_same_space if (self.source_field not in _) and (self.target_field not in _)
-        ]
-        for field_set in fields_in_same_space:
-            if self.uid_field in field_set:
-                field_set.update({self.source_field, self.target_field})
-
-        return fields_in_same_space
-
-    @dlapi.set()
-    def net_graph(self, form='coo', value_field=None):
-        """Get graph or sparse matrix that describe relations between users.
-
-        For an edge of <src, tgt>, ``graph[src, tgt] = 1`` if ``value_field`` is ``None``,
-        else ``graph[src, tgt] = self.net_feat[value_field][src, tgt]``.
-
-        Currently, we support graph in `DGL`_ and `PyG`_,
-        and two type of sparse matrices, ``coo`` and ``csr``.
-
-        Args:
-            form (str, optional): Format of sparse matrix, or library of graph data structure.
-                Defaults to ``coo``.
-            value_field (str, optional): edge attributes of graph, or data of sparse matrix,
-                Defaults to ``None``.
-
-        Returns:
-            Graph / Sparse matrix of relations.
-
-        .. _DGL:
-            https://www.dgl.ai/
-
-        .. _PyG:
-            https://github.com/rusty1s/pytorch_geometric
-        """
-        args = [self.net_feat, self.source_field, self.target_field, form, value_field]
-        if form in ['coo', 'csr']:
-            return self._create_sparse_matrix(*args)
-        elif form in ['dgl', 'pyg']:
-            return self._create_graph(*args)
-        else:
-            raise NotImplementedError('net graph format [{}] has not been implemented.')
-
-    def __str__(self):
-        info = [super().__str__(), f'The number of connections of social network: {len(self.net_feat)}']
-        return '\n'.join(info)
diff --git a/recbole/data/interaction.py b/recbole/data/interaction.py
index 218b8b035..7a557888d 100644
--- a/recbole/data/interaction.py
+++ b/recbole/data/interaction.py
@@ -13,7 +13,31 @@
 """
 
 import numpy as np
+import pandas as pd
 import torch
+import torch.nn.utils.rnn as rnn_utils
+
+
+def _convert_to_tensor(data):
+    """This function can convert common data types (list, pandas.Series, numpy.ndarray, torch.Tensor) into torch.Tensor.
+
+    Args:
+        data (list, pandas.Series, numpy.ndarray, torch.Tensor): Origin data.
+
+    Returns:
+        torch.Tensor: Converted tensor from `data`.
+    """
+    elem = data[0]
+    if isinstance(elem, (float, int, np.float, np.int64)):
+        new_data = torch.as_tensor(data)
+    elif isinstance(elem, (list, tuple, pd.Series, np.ndarray, torch.Tensor)):
+        seq_data = [torch.as_tensor(d) for d in data]
+        new_data = rnn_utils.pad_sequence(seq_data, batch_first=True)
+    else:
+        raise ValueError(f'[{type(elem)}] is not supported!')
+    if new_data.dtype == torch.float64:
+        new_data = new_data.float()
+    return new_data
 
 
 class Interaction(object):
@@ -68,38 +92,40 @@ class Interaction(object):
             =======     =======     =======     ========
 
     Attributes:
-        interaction (dict): keys are meaningful str (also can be called field name),
+        interaction (dict or pandas.DataFrame): keys are meaningful str (also can be called field name),
             and values are Torch Tensor of numpy Array with shape (batch_size, \\*).
-
-        pos_len_list (list, optional): length of the list is the number of users in this batch,
-            each value represents the number of a user's **positive** records. The order of the
-            represented users should correspond to the order in the interaction.
-
-        user_len_list (list, optional): length of the list is the number of users in this batch,
-            each value represents the number of a user's **all** records. The order of the
-            represented users should correspond to the order in the interaction.
     """
 
-    def __init__(self, interaction, pos_len_list=None, user_len_list=None):
-        self.interaction = interaction
-        self.pos_len_list = self.user_len_list = None
-        self.set_additional_info(pos_len_list, user_len_list)
-        for k in self.interaction:
-            if not isinstance(self.interaction[k], torch.Tensor):
-                raise ValueError(f'Interaction [{interaction}] should only contains torch.Tensor')
+    def __init__(self, interaction):
+        self.interaction = dict()
+        if isinstance(interaction, dict):
+            for key, value in interaction.items():
+                if isinstance(value, (list, np.ndarray)):
+                    self.interaction[key] = _convert_to_tensor(value)
+                elif isinstance(value, torch.Tensor):
+                    self.interaction[key] = value
+                else:
+                    raise ValueError(f'The type of {key}[{type(value)}] is not supported!')
+        elif isinstance(interaction, pd.DataFrame):
+            for key in interaction:
+                value = interaction[key].values
+                self.interaction[key] = _convert_to_tensor(value)
+        else:
+            raise ValueError(f'[{type(interaction)}] is not supported for initialize `Interaction`!')
         self.length = -1
         for k in self.interaction:
             self.length = max(self.length, self.interaction[k].shape[0])
 
-    def set_additional_info(self, pos_len_list=None, user_len_list=None):
-        self.pos_len_list = pos_len_list
-        self.user_len_list = user_len_list
-        if (self.pos_len_list is None) ^ (self.user_len_list is None):
-            raise ValueError('pos_len_list and user_len_list should be both None or valued.')
-
     def __iter__(self):
         return self.interaction.__iter__()
 
+    def __getattr__(self, item):
+        if 'interaction' not in self.__dict__:
+            raise AttributeError(f"'Interaction' object has no attribute 'interaction'")
+        if item in self.interaction:
+            return self.interaction[item]
+        raise AttributeError(f"'Interaction' object has no attribute '{item}'")
+
     def __getitem__(self, index):
         if isinstance(index, str):
             return self.interaction[index]
@@ -208,13 +234,8 @@ def repeat(self, sizes):
         """
         ret = {}
         for k in self.interaction:
-            if len(self.interaction[k].shape) == 1:
-                ret[k] = self.interaction[k].repeat(sizes)
-            else:
-                ret[k] = self.interaction[k].repeat([sizes, 1])
-        new_pos_len_list = self.pos_len_list * sizes if self.pos_len_list else None
-        new_user_len_list = self.user_len_list * sizes if self.user_len_list else None
-        return Interaction(ret, new_pos_len_list, new_user_len_list)
+            ret[k] = self.interaction[k].repeat([sizes] + [1] * (len(self.interaction[k].shape) - 1))
+        return Interaction(ret)
 
     def repeat_interleave(self, repeats, dim=0):
         """Similar to repeat_interleave of PyTorch.
@@ -229,9 +250,7 @@ def repeat_interleave(self, repeats, dim=0):
         ret = {}
         for k in self.interaction:
             ret[k] = self.interaction[k].repeat_interleave(repeats, dim=dim)
-        new_pos_len_list = list(np.multiply(self.pos_len_list, repeats)) if self.pos_len_list else None
-        new_user_len_list = list(np.multiply(self.user_len_list, repeats)) if self.user_len_list else None
-        return Interaction(ret, new_pos_len_list, new_user_len_list)
+        return Interaction(ret)
 
     def update(self, new_inter):
         """Similar to ``dict.update()``
@@ -241,10 +260,6 @@ def update(self, new_inter):
         """
         for k in new_inter.interaction:
             self.interaction[k] = new_inter.interaction[k]
-        if new_inter.pos_len_list is not None:
-            self.pos_len_list = new_inter.pos_len_list
-        if new_inter.user_len_list is not None:
-            self.user_len_list = new_inter.user_len_list
 
     def drop(self, column):
         """Drop column in interaction.
@@ -264,10 +279,6 @@ def _reindex(self, index):
         """
         for k in self.interaction:
             self.interaction[k] = self.interaction[k][index]
-        if self.pos_len_list is not None:
-            self.pos_len_list = self.pos_len_list[index]
-        if self.user_len_list is not None:
-            self.user_len_list = self.user_len_list[index]
 
     def shuffle(self):
         """Shuffle current interaction inplace.
diff --git a/recbole/data/utils.py b/recbole/data/utils.py
index 6f1b61eba..8ff65afdd 100644
--- a/recbole/data/utils.py
+++ b/recbole/data/utils.py
@@ -3,7 +3,7 @@
 # @Email  : houyupeng@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/10/19, 2020/9/17, 2020/8/31, 2021/2/20, 2021/3/1
+# @Time   : 2021/7/9, 2020/9/17, 2020/8/31, 2021/2/20, 2021/3/1
 # @Author : Yupeng Hou, Yushuo Chen, Kaiyuan Li, Haoran Cheng, Jiawei Guan
 # @Email  : houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, tsotfsk@outlook.com, chenghaoran29@foxmail.com, guanjw@ruc.edu.cn
 
@@ -17,11 +17,9 @@
 import os
 import pickle
 
-from recbole.config import EvalSetting
 from recbole.data.dataloader import *
 from recbole.sampler import KGSampler, Sampler, RepeatableSampler
-from recbole.utils import ModelType, ensure_dir, get_local_time
-from recbole.utils.utils import set_color
+from recbole.utils import ModelType, ensure_dir, get_local_time, set_color
 
 
 def create_dataset(config):
@@ -44,9 +42,6 @@ def create_dataset(config):
         elif model_type == ModelType.KNOWLEDGE:
             from .dataset import KnowledgeBasedDataset
             return KnowledgeBasedDataset(config)
-        elif model_type == ModelType.SOCIAL:
-            from .dataset import SocialDataset
-            return SocialDataset(config)
         elif model_type == ModelType.DECISIONTREE:
             from .dataset import DecisionTreeDataset
             return DecisionTreeDataset(config)
@@ -55,125 +50,6 @@ def create_dataset(config):
             return Dataset(config)
 
 
-def data_preparation(config, dataset, save=False):
-    """Split the dataset by :attr:`config['eval_setting']` and call :func:`dataloader_construct` to create
-    corresponding dataloader.
-
-    Args:
-        config (Config): An instance object of Config, used to record parameter information.
-        dataset (Dataset): An instance object of Dataset, which contains all interaction records.
-        save (bool, optional): If ``True``, it will call :func:`save_datasets` to save split dataset.
-            Defaults to ``False``.
-
-    Returns:
-        tuple:
-            - train_data (AbstractDataLoader): The dataloader for training.
-            - valid_data (AbstractDataLoader): The dataloader for validation.
-            - test_data (AbstractDataLoader): The dataloader for testing.
-    """
-    model_type = config['MODEL_TYPE']
-
-    es = EvalSetting(config)
-
-    built_datasets = dataset.build(es)
-    train_dataset, valid_dataset, test_dataset = built_datasets
-    phases = ['train', 'valid', 'test']
-    sampler = None
-    logger = getLogger()
-    train_neg_sample_args = config['train_neg_sample_args']
-    eval_neg_sample_args = es.neg_sample_args
-
-    # Training
-    train_kwargs = {
-        'config': config,
-        'dataset': train_dataset,
-        'batch_size': config['train_batch_size'],
-        'dl_format': config['MODEL_INPUT_TYPE'],
-        'shuffle': True,
-    }
-    if train_neg_sample_args['strategy'] != 'none':
-        if dataset.label_field in dataset.inter_feat:
-            raise ValueError(
-                f'`training_neg_sample_num` should be 0 '
-                f'if inter_feat have label_field [{dataset.label_field}].'
-            )
-        if model_type != ModelType.SEQUENTIAL:
-            sampler = Sampler(phases, built_datasets, train_neg_sample_args['distribution'])
-        else:
-            sampler = RepeatableSampler(phases, dataset, train_neg_sample_args['distribution'])
-        train_kwargs['sampler'] = sampler.set_phase('train')
-        train_kwargs['neg_sample_args'] = train_neg_sample_args
-        if model_type == ModelType.KNOWLEDGE:
-            kg_sampler = KGSampler(dataset, train_neg_sample_args['distribution'])
-            train_kwargs['kg_sampler'] = kg_sampler
-
-    dataloader = get_data_loader('train', config, train_neg_sample_args)
-    logger.info(
-        set_color('Build', 'pink') + set_color(f' [{dataloader.__name__}]', 'yellow') + ' for ' +
-        set_color('[train]', 'yellow') + ' with format ' + set_color(f'[{train_kwargs["dl_format"]}]', 'yellow')
-    )
-    if train_neg_sample_args['strategy'] != 'none':
-        logger.info(
-            set_color('[train]', 'pink') + set_color(' Negative Sampling', 'blue') + f': {train_neg_sample_args}'
-        )
-    else:
-        logger.info(set_color('[train]', 'pink') + set_color(' No Negative Sampling', 'yellow'))
-    logger.info(
-        set_color('[train]', 'pink') + set_color(' batch_size', 'cyan') + ' = ' +
-        set_color(f'[{train_kwargs["batch_size"]}]', 'yellow') + ', ' + set_color('shuffle', 'cyan') + ' = ' +
-        set_color(f'[{train_kwargs["shuffle"]}]\n', 'yellow')
-    )
-    train_data = dataloader(**train_kwargs)
-
-    # Evaluation
-    eval_kwargs = {
-        'config': config,
-        'batch_size': config['eval_batch_size'],
-        'dl_format': InputType.POINTWISE,
-        'shuffle': False,
-    }
-    valid_kwargs = {'dataset': valid_dataset}
-    test_kwargs = {'dataset': test_dataset}
-    if eval_neg_sample_args['strategy'] != 'none':
-        if dataset.label_field in dataset.inter_feat:
-            raise ValueError(
-                f'It can not validate with `{es.es_str[1]}` '
-                f'when inter_feat have label_field [{dataset.label_field}].'
-            )
-        if sampler is None:
-            if model_type != ModelType.SEQUENTIAL:
-                sampler = Sampler(phases, built_datasets, eval_neg_sample_args['distribution'])
-            else:
-                sampler = RepeatableSampler(phases, dataset, eval_neg_sample_args['distribution'])
-        else:
-            sampler.set_distribution(eval_neg_sample_args['distribution'])
-        eval_kwargs['neg_sample_args'] = eval_neg_sample_args
-        valid_kwargs['sampler'] = sampler.set_phase('valid')
-        test_kwargs['sampler'] = sampler.set_phase('test')
-    valid_kwargs.update(eval_kwargs)
-    test_kwargs.update(eval_kwargs)
-
-    dataloader = get_data_loader('evaluation', config, eval_neg_sample_args)
-    logger.info(
-        set_color('Build', 'pink') + set_color(f' [{dataloader.__name__}]', 'yellow') + ' for ' +
-        set_color('[evaluation]', 'yellow') + ' with format ' + set_color(f'[{eval_kwargs["dl_format"]}]', 'yellow')
-    )
-    logger.info(es)
-    logger.info(
-        set_color('[evaluation]', 'pink') + set_color(' batch_size', 'cyan') + ' = ' +
-        set_color(f'[{eval_kwargs["batch_size"]}]', 'yellow') + ', ' + set_color('shuffle', 'cyan') + ' = ' +
-        set_color(f'[{eval_kwargs["shuffle"]}]\n', 'yellow')
-    )
-
-    valid_data = dataloader(**valid_kwargs)
-    test_data = dataloader(**test_kwargs)
-
-    if save:
-        save_split_dataloaders(config, dataloaders=(train_data, valid_data, test_data))
-
-    return train_data, valid_data, test_data
-
-
 def save_split_dataloaders(config, dataloaders):
     """Save split dataloaders.
 
@@ -204,169 +80,146 @@ def load_split_dataloaders(saved_dataloaders_file):
     return dataloaders
 
 
-def get_data_loader(name, config, neg_sample_args):
-    """Return a dataloader class according to :attr:`config` and :attr:`eval_setting`.
+def data_preparation(config, dataset, save=False):
+    """Split the dataset by :attr:`config['eval_args']` and create training, validation and test dataloader.
 
     Args:
-        name (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
         config (Config): An instance object of Config, used to record parameter information.
-        neg_sample_args (dict) : Settings of negative sampling.
+        dataset (Dataset): An instance object of Dataset, which contains all interaction records.
+        save (bool, optional): If ``True``, it will call :func:`save_datasets` to save split dataset.
+            Defaults to ``False``.
 
     Returns:
-        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`eval_setting`.
+        tuple:
+            - train_data (AbstractDataLoader): The dataloader for training.
+            - valid_data (AbstractDataLoader): The dataloader for validation.
+            - test_data (AbstractDataLoader): The dataloader for testing.
     """
-    register_table = {
-        'DIN': _get_DIN_data_loader,
-        'DIEN': _get_DIEN_data_loader,
-        "MultiDAE": _get_AE_data_loader,
-        "MultiVAE": _get_AE_data_loader,
-        'MacridVAE': _get_AE_data_loader,
-        'CDAE': _get_AE_data_loader,
-        'ENMF': _get_AE_data_loader,
-        'RaCT': _get_AE_data_loader,
-        'RecVAE': _get_AE_data_loader
-    }
-
-    if config['model'] in register_table:
-        return register_table[config['model']](name, config, neg_sample_args)
-
-    model_type_table = {
-        ModelType.GENERAL: 'General',
-        ModelType.TRADITIONAL: 'General',
-        ModelType.CONTEXT: 'Context',
-        ModelType.SEQUENTIAL: 'Sequential',
-        ModelType.DECISIONTREE: 'DecisionTree',
-    }
-    neg_sample_strategy_table = {
-        'none': 'DataLoader',
-        'by': 'NegSampleDataLoader',
-        'full': 'FullDataLoader',
-    }
     model_type = config['MODEL_TYPE']
-    neg_sample_strategy = neg_sample_args['strategy']
-    dataloader_module = importlib.import_module('recbole.data.dataloader')
-
-    if model_type in model_type_table and neg_sample_strategy in neg_sample_strategy_table:
-        dataloader_name = model_type_table[model_type] + neg_sample_strategy_table[neg_sample_strategy]
-        return getattr(dataloader_module, dataloader_name)
-    elif model_type == ModelType.KNOWLEDGE:
-        if neg_sample_strategy == 'by':
-            if name == 'train':
-                return KnowledgeBasedDataLoader
-            else:
-                return GeneralNegSampleDataLoader
-        elif neg_sample_strategy == 'full':
-            return GeneralFullDataLoader
-        elif neg_sample_strategy == 'none':
-            raise NotImplementedError(
-                'The use of external negative sampling for knowledge model has not been implemented'
-            )
-    else:
-        raise NotImplementedError(f'Model_type [{model_type}] has not been implemented.')
+    built_datasets = dataset.build()
+    logger = getLogger()
 
+    train_dataset, valid_dataset, test_dataset = built_datasets
+    train_sampler, valid_sampler, test_sampler = create_samplers(config, dataset, built_datasets)
 
-def _get_DIN_data_loader(name, config, neg_sample_args):
-    """Customized function for DIN to get correct dataloader class.
+    if model_type != ModelType.KNOWLEDGE:
+        train_data = get_dataloader(config, 'train')(config, train_dataset, train_sampler, shuffle=True)
+    else:
+        kg_sampler = KGSampler(dataset, config['train_neg_sample_args']['distribution'])
+        train_data = get_dataloader(config, 'train')(config, train_dataset, train_sampler, kg_sampler, shuffle=True)
 
-    Args:
-        name (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
-        config (Config): An instance object of Config, used to record parameter information.
-        neg_sample_args : Settings of negative sampling.
+    valid_data = get_dataloader(config, 'evaluation')(config, valid_dataset, valid_sampler, shuffle=False)
+    test_data = get_dataloader(config, 'evaluation')(config, test_dataset, test_sampler, shuffle=False)
+    logger.info(
+        set_color('[Training]: ', 'pink') + set_color('train_batch_size', 'cyan') + ' = ' +
+        set_color(f'[{config["train_batch_size"]}]', 'yellow') + set_color(' negative sampling', 'cyan') + ': ' +
+        set_color(f'[{config["neg_sampling"]}]', 'yellow')
+    )
+    logger.info(
+        set_color('[Evaluation]: ', 'pink') + set_color('eval_batch_size', 'cyan') + ' = ' +
+        set_color(f'[{config["eval_batch_size"]}]', 'yellow') + set_color(' eval_args', 'cyan') + ': ' +
+        set_color(f'[{config["eval_args"]}]', 'yellow')
+    )
+    if save:
+        save_split_dataloaders(config, dataloaders=(train_data, valid_data, test_data))
 
-    Returns:
-        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`eval_setting`.
-    """
-    neg_sample_strategy = neg_sample_args['strategy']
-    if neg_sample_strategy == 'none':
-        return SequentialDataLoader
-    elif neg_sample_strategy == 'by':
-        return SequentialNegSampleDataLoader
-    elif neg_sample_strategy == 'full':
-        return SequentialFullDataLoader
+    return train_data, valid_data, test_data
 
 
-def _get_DIEN_data_loader(name, config, neg_sample_args):
-    """Customized function for DIEN to get correct dataloader class.
+def get_dataloader(config, phase):
+    """Return a dataloader class according to :attr:`config` and :attr:`phase`.
 
     Args:
-        name (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
         config (Config): An instance object of Config, used to record parameter information.
-        neg_sample_args : Settings of negative sampling.
+        phase (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
 
     Returns:
-        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`eval_setting`.
+        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`phase`.
     """
-    neg_sample_strategy = neg_sample_args['strategy']
-    if neg_sample_strategy == 'none':
-        return DIENDataLoader
-    elif neg_sample_strategy == 'by':
-        return DIENNegSampleDataLoader
-    elif neg_sample_strategy == 'full':
-        return DIENFullDataLoader
+    register_table = {
+        "MultiDAE": _get_AE_dataloader,
+        "MultiVAE": _get_AE_dataloader,
+        'MacridVAE': _get_AE_dataloader,
+        'CDAE': _get_AE_dataloader,
+        'ENMF': _get_AE_dataloader,
+        'RaCT': _get_AE_dataloader,
+        'RecVAE': _get_AE_dataloader,
+    }
+
+    if config['model'] in register_table:
+        return register_table[config['model']](config, phase)
+
+    model_type = config['MODEL_TYPE']
+    if phase == 'train':
+        if model_type != ModelType.KNOWLEDGE:
+            return TrainDataLoader
+        else:
+            return KnowledgeBasedDataLoader
+    else:
+        eval_strategy = config['eval_neg_sample_args']['strategy']
+        if eval_strategy in {'none', 'by'}:
+            return NegSampleEvalDataLoader
+        elif eval_strategy == 'full':
+            return FullSortEvalDataLoader
 
 
-def _get_AE_data_loader(name, config, neg_sample_args):
-    """Customized function for Multi-DAE and Multi-VAE to get correct dataloader class.
+def _get_AE_dataloader(config, phase):
+    """Customized function for VAE models to get correct dataloader class.
 
     Args:
-        name (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
         config (Config): An instance object of Config, used to record parameter information.
-        neg_sample_args (dict): Settings of negative sampling.
+        phase (str): The stage of dataloader. It can only take two values: 'train' or 'evaluation'.
 
     Returns:
-        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`eval_setting`.
+        type: The dataloader class that meets the requirements in :attr:`config` and :attr:`phase`.
     """
-    neg_sample_strategy = neg_sample_args['strategy']
-    if name == "train":
+    if phase == 'train':
         return UserDataLoader
     else:
-        if neg_sample_strategy == 'none':
-            return GeneralDataLoader
-        elif neg_sample_strategy == 'by':
-            return GeneralNegSampleDataLoader
-        elif neg_sample_strategy == 'full':
-            return GeneralFullDataLoader
-
+        eval_strategy = config['eval_neg_sample_args']['strategy']
+        if eval_strategy in {'none', 'by'}:
+            return NegSampleEvalDataLoader
+        elif eval_strategy == 'full':
+            return FullSortEvalDataLoader
 
-class DLFriendlyAPI(object):
-    """A Decorator class, which helps copying :class:`Dataset` methods to :class:`DataLoader`.
 
-    These methods are called *DataLoader Friendly APIs*.
+def create_samplers(config, dataset, built_datasets):
+    """Create sampler for training, validation and testing.
 
-    E.g. if ``train_data`` is an object of :class:`DataLoader`,
-    and :meth:`~recbole.data.dataset.dataset.Dataset.num` is a method of :class:`~recbole.data.dataset.dataset.Dataset`,
-    Cause it has been decorated, :meth:`~recbole.data.dataset.dataset.Dataset.num` can be called directly by
-    ``train_data``.
-
-    See the example of :meth:`set` for details.
+    Args:
+        config (Config): An instance object of Config, used to record parameter information.
+        dataset (Dataset): An instance object of Dataset, which contains all interaction records.
+        built_datasets (list of Dataset): A list of split Dataset, which contains dataset for
+            training, validation and testing.
 
-    Attributes:
-        dataloader_apis (set): Register table that saves all the method names of DataLoader Friendly APIs.
+    Returns:
+        tuple:
+            - train_sampler (AbstractSampler): The sampler for training.
+            - valid_sampler (AbstractSampler): The sampler for validation.
+            - test_sampler (AbstractSampler): The sampler for testing.
     """
+    phases = ['train', 'valid', 'test']
+    train_neg_sample_args = config['train_neg_sample_args']
+    eval_neg_sample_args = config['eval_neg_sample_args']
+    sampler = None
+    train_sampler, valid_sampler, test_sampler = None, None, None
 
-    def __init__(self):
-        self.dataloader_apis = set()
-
-    def __iter__(self):
-        return self.dataloader_apis
-
-    def set(self):
-        """
-        Example:
-            .. code:: python
-
-                from recbole.data.utils import dlapi
-
-                @dlapi.set()
-                def dataset_meth():
-                    ...
-        """
-
-        def decorator(f):
-            self.dataloader_apis.add(f.__name__)
-            return f
-
-        return decorator
+    if train_neg_sample_args['strategy'] != 'none':
+        if not config['repeatable']:
+            sampler = Sampler(phases, built_datasets, train_neg_sample_args['distribution'])
+        else:
+            sampler = RepeatableSampler(phases, dataset, train_neg_sample_args['distribution'])
+        train_sampler = sampler.set_phase('train')
 
+    if eval_neg_sample_args['strategy'] != 'none':
+        if sampler is None:
+            if not config['repeatable']:
+                sampler = Sampler(phases, built_datasets, eval_neg_sample_args['distribution'])
+            else:
+                sampler = RepeatableSampler(phases, dataset, eval_neg_sample_args['distribution'])
+        else:
+            sampler.set_distribution(eval_neg_sample_args['distribution'])
+        valid_sampler = sampler.set_phase('valid')
+        test_sampler = sampler.set_phase('test')
 
-dlapi = DLFriendlyAPI()
+    return train_sampler, valid_sampler, test_sampler
diff --git a/recbole/evaluator/__init__.py b/recbole/evaluator/__init__.py
index 73f4cad5f..baa4e6f6e 100644
--- a/recbole/evaluator/__init__.py
+++ b/recbole/evaluator/__init__.py
@@ -1,4 +1,5 @@
-from recbole.evaluator.abstract_evaluator import *
-from recbole.evaluator.proxy_evaluator import *
+from recbole.evaluator.base_metric import *
 from recbole.evaluator.metrics import *
-from recbole.evaluator.evaluators import *
+from recbole.evaluator.evaluator import *
+from recbole.evaluator.register import *
+from recbole.evaluator.collector import *
diff --git a/recbole/evaluator/abstract_evaluator.py b/recbole/evaluator/abstract_evaluator.py
deleted file mode 100644
index 45254c9a6..000000000
--- a/recbole/evaluator/abstract_evaluator.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Time    :   2020/10/21
-# @Author  :   Kaiyuan Li
-# @email   :   tsotfsk@outlook.com
-
-# UPDATE
-# @Time    :   2020/10/21, 2020/12/18
-# @Author  :   Kaiyuan Li, Zhichao Feng
-# @email   :   tsotfsk@outlook.com, fzcbupt@gmail.com
-
-"""
-recbole.evaluator.abstract_evaluator
-#####################################
-"""
-
-import numpy as np
-import torch
-from torch.nn.utils.rnn import pad_sequence
-
-
-class BaseEvaluator(object):
-    """:class:`BaseEvaluator` is an object which supports
-    the evaluation of the model. It is called by :class:`Trainer`.
-
-    Note:
-        If you want to inherit this class and implement your own evaluator class,
-        you must implement the following functions.
-
-    Args:
-        config (Config): The config of evaluator.
-
-    """
-
-    def __init__(self, config, metrics):
-        self.metrics = metrics
-        self.full = ('full' in config['eval_setting'])
-        self.precision = config['metric_decimal_place']
-
-    def collect(self, *args):
-        """get the intermediate results for each batch, it is called at the end of each batch"""
-        raise NotImplementedError
-
-    def evaluate(self, *args):
-        """calculate the metrics of all batches, it is called at the end of each epoch"""
-        raise NotImplementedError
-
-    def _calculate_metrics(self, *args):
-        """ to calculate the metrics"""
-        raise NotImplementedError
-
-
-class GroupedEvaluator(BaseEvaluator):
-    """:class:`GroupedEvaluator` is an object which supports the evaluation of the model.
-
-    Note:
-        If you want to implement a new group-based metric,
-        you may need to inherit this class
-
-    """
-
-    def __init__(self, config, metrics):
-        super().__init__(config, metrics)
-        pass
-
-    def sample_collect(self, scores_tensor, user_len_list):
-        """padding scores_tensor. It is called when evaluation sample distribution is `uniform` or `popularity`.
-
-        """
-        scores_list = torch.split(scores_tensor, user_len_list, dim=0)
-        padding_score = pad_sequence(scores_list, batch_first=True, padding_value=-np.inf)  # n_users x items
-        return padding_score
-
-    def full_sort_collect(self, scores_tensor, user_len_list):
-        """it is called when evaluation sample distribution is `full`.
-
-        """
-        return scores_tensor.view(len(user_len_list), -1)
-
-    def get_score_matrix(self, scores_tensor, user_len_list):
-        """get score matrix.
-
-        Args:
-           scores_tensor (tensor): the tensor of model output with size of `(N, )`
-           user_len_list(list): number of all items
-
-       """
-        if self.full:
-            scores_matrix = self.full_sort_collect(scores_tensor, user_len_list)
-        else:
-            scores_matrix = self.sample_collect(scores_tensor, user_len_list)
-        return scores_matrix
-
-
-class IndividualEvaluator(BaseEvaluator):
-    """:class:`IndividualEvaluator` is an object which supports the evaluation of the model.
-
-    Note:
-        If you want to implement a new non-group-based metric,
-        you may need to inherit this class
-
-    """
-
-    def __init__(self, config, metrics):
-        super().__init__(config, metrics)
-        self._check_args()
-
-    def sample_collect(self, true_scores, pred_scores):
-        """It is called when evaluation sample distribution is `uniform` or `popularity`.
-
-        """
-        return torch.stack((true_scores, pred_scores.detach()), dim=1)
-
-    def full_sort_collect(self, true_scores, pred_scores):
-        """it is called when evaluation sample distribution is `full`.
-
-        """
-        raise NotImplementedError('full sort can\'t use IndividualEvaluator')
-
-    def get_score_matrix(self, true_scores, pred_scores):
-        """get score matrix
-
-        Args:
-           true_scores (tensor): the label of predicted items
-           pred_scores (tensor): the tensor of model output with a size of `(N, )`
-
-       """
-        if self.full:
-            scores_matrix = self.full_sort_collect(true_scores, pred_scores)
-        else:
-            scores_matrix = self.sample_collect(true_scores, pred_scores)
-
-        return scores_matrix
-
-    def _check_args(self):
-        if self.full:
-            raise NotImplementedError('full sort can\'t use IndividualEvaluator')
diff --git a/recbole/evaluator/base_metric.py b/recbole/evaluator/base_metric.py
new file mode 100644
index 000000000..28ed82606
--- /dev/null
+++ b/recbole/evaluator/base_metric.py
@@ -0,0 +1,131 @@
+# @Time   : 2020/10/21
+# @Author : Kaiyuan Li
+# @email  : tsotfsk@outlook.com
+
+# UPDATE
+# @Time   : 2020/10/21, 2021/8/29
+# @Author : Kaiyuan Li, Zhichao Feng
+# @email  : tsotfsk@outlook.com, fzcbupt@gmail.com
+
+"""
+recbole.evaluator.abstract_metric
+#####################################
+"""
+
+import torch
+from recbole.utils import EvaluatorType
+
+
+class AbstractMetric(object):
+    """:class:`AbstractMetric` is the base object of all metrics. If you want to
+        implement a metric, you should inherit this class.
+
+    Args:
+        config (Config): the config of evaluator.
+    """
+    smaller = False
+
+    def __init__(self, config):
+        self.decimal_place = config['metric_decimal_place']
+
+    def calculate_metric(self, dataobject):
+        """Get the dictionary of a metric.
+
+        Args:
+            dataobject(DataStruct): it contains all the information needed to calculate metrics.
+
+        Returns:
+            dict: such as ``{'metric@10': 3153, 'metric@20': 0.3824}``
+        """
+        raise NotImplementedError('Method [calculate_metric] should be implemented.')
+
+
+class TopkMetric(AbstractMetric):
+    """:class:`TopkMetric` is a base object of top-k metrics. If you want to
+    implement an top-k metric, you can inherit this class.
+
+    Args:
+        config (Config): The config of evaluator.
+    """
+    metric_type = EvaluatorType.RANKING
+    metric_need = ['rec.topk']
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
+
+    def used_info(self, dataobject):
+        """Get the bool matrix indicating whether the corresponding item is positive
+        and number of positive items for each user.
+        """
+        rec_mat = dataobject.get('rec.topk')
+        topk_idx, pos_len_list = torch.split(rec_mat, [max(self.topk), 1], dim=1)
+        return rec_mat.to(torch.bool).numpy(), pos_len_list.squeeze().numpy()
+
+    def topk_result(self, metric, value):
+        """Match the metric value to the `k` and put them in `dictionary` form.
+
+        Args:
+            metric(str): the name of calculated metric.
+            value(numpy.ndarray): metrics for each user, including values from `metric@1` to `metric@max(self.topk)`.
+
+        Returns:
+            dict: metric values required in the configuration.
+        """
+        metric_dict = {}
+        avg_result = value.mean(axis=0)
+        for k in self.topk:
+            key = '{}@{}'.format(metric, k)
+            metric_dict[key] = round(avg_result[k - 1], self.decimal_place)
+        return metric_dict
+
+    def metric_info(self, pos_index, pos_len=None):
+        """Calculate the value of the metric.
+
+        Args:
+            pos_index(numpy.ndarray): a bool matrix, shape of ``n_users * max(topk)``. The item with the (j+1)-th \
+            highest score of i-th user is positive if ``pos_index[i][j] == True`` and negative otherwise.
+            pos_len(numpy.ndarray): a vector representing the number of positive items per user, shape of ``(n_users,)``.
+
+        Returns:
+            numpy.ndarray: metrics for each user, including values from `metric@1` to `metric@max(self.topk)`.
+        """
+        raise NotImplementedError('Method [metric_info] of top-k metric should be implemented.')
+
+
+class LossMetric(AbstractMetric):
+    """:class:`LossMetric` is a base object of loss based metrics and AUC. If you want to
+    implement an loss based metric, you can inherit this class.
+
+    Args:
+        config (Config): The config of evaluator.
+    """
+    metric_type = EvaluatorType.VALUE
+    metric_need = ['rec.score', 'data.label']
+
+    def __init__(self, config):
+        super().__init__(config)
+
+    def used_info(self, dataobject):
+        """Get scores that model predicted and the ground truth."""
+        preds = dataobject.get('rec.score')
+        trues = dataobject.get('data.label')
+
+        return preds.squeeze().numpy(), trues.squeeze().numpy()
+
+    def output_metric(self, metric, dataobject):
+        preds, trues = self.used_info(dataobject)
+        result = self.metric_info(preds, trues)
+        return {metric: round(result, self.decimal_place)}
+
+    def metric_info(self, preds, trues):
+        """Calculate the value of the metric.
+
+        Args:
+            preds (numpy.ndarray): the scores predicted by model, a one-dimensional vector.
+            trues (numpy.ndarray): the label of items, which has the same shape as ``preds``.
+
+        Returns:
+            float: The value of the metric.
+        """
+        raise NotImplementedError('Method [metric_info] of loss-based metric should be implemented.')
diff --git a/recbole/evaluator/collector.py b/recbole/evaluator/collector.py
new file mode 100644
index 000000000..9f856a12d
--- /dev/null
+++ b/recbole/evaluator/collector.py
@@ -0,0 +1,210 @@
+# @Time   : 2021/6/23
+# @Author : Zihan Lin
+# @Email  : zhlin@ruc.edu.cn
+
+# UPDATE
+# @Time   : 2021/7/18
+# @Author : Zhichao Feng
+# @email  : fzcbupt@gmail.com
+
+"""
+recbole.evaluator.collector
+################################################
+"""
+
+from recbole.evaluator.register import Register
+import torch
+import copy
+
+
+class DataStruct(object):
+
+    def __init__(self):
+        self._data_dict = {}
+
+    def __getitem__(self, name: str):
+        return self._data_dict[name]
+
+    def __setitem__(self, name: str, value):
+        self._data_dict[name] = value
+
+    def __delitem__(self, name: str):
+        self._data_dict.pop(name)
+
+    def __contains__(self, key: str):
+        return key in self._data_dict
+
+    def get(self, name: str):
+        if name not in self._data_dict:
+            raise IndexError("Can not load the data without registration !")
+        return self[name]
+
+    def set(self, name: str, value):
+        self._data_dict[name] = value
+
+    def update_tensor(self, name: str, value: torch.Tensor):
+        if name not in self._data_dict:
+            self._data_dict[name] = value.cpu().clone().detach()
+        else:
+            if not isinstance(self._data_dict[name], torch.Tensor):
+                raise ValueError("{} is not a tensor.".format(name))
+            self._data_dict[name] = torch.cat((self._data_dict[name], value.cpu().clone().detach()), dim=0)
+
+    def __str__(self):
+        data_info = '\nContaining:\n'
+        for data_key in self._data_dict.keys():
+            data_info += data_key + '\n'
+        return data_info
+
+
+class Collector(object):
+    """The collector is used to collect the resource for evaluator.
+        As the evaluation metrics are various, the needed resource not only contain the recommended result
+        but also other resource from data and model. They all can be collected by the collector during the training
+        and evaluation process.
+
+        This class is only used in Trainer.
+
+    """
+
+    def __init__(self, config):
+        self.config = config
+        self.data_struct = DataStruct()
+        self.register = Register(config)
+        self.full = ('full' in config['eval_args']['mode'])
+        self.topk = self.config['topk']
+        self.device = self.config['device']
+
+    def data_collect(self, train_data):
+        """ Collect the evaluation resource from training data.
+            Args:
+                train_data (AbstractDataLoader): the training dataloader which contains the training data.
+
+        """
+        if self.register.need('data.num_items'):
+            item_id = self.config['ITEM_ID_FIELD']
+            self.data_struct.set('data.num_items', train_data.dataset.num(item_id))
+        if self.register.need('data.num_users'):
+            user_id = self.config['USER_ID_FIELD']
+            self.data_struct.set('data.num_users', train_data.dataset.num(user_id))
+        if self.register.need('data.count_items'):
+            self.data_struct.set('data.count_items', train_data.dataset.item_counter)
+        if self.register.need('data.count_users'):
+            self.data_struct.set('data.count_items', train_data.dataset.user_counter)
+
+    def _average_rank(self, scores):
+        """Get the ranking of an ordered tensor, and take the average of the ranking for positions with equal values.
+
+        Args:
+            scores(tensor): an ordered tensor, with size of `(N, )`
+
+        Returns:
+            torch.Tensor: average_rank
+
+        Example:
+            >>> average_rank(tensor([[1,2,2,2,3,3,6],[2,2,2,2,4,5,5]]))
+            tensor([[1.0000, 3.0000, 3.0000, 3.0000, 5.5000, 5.5000, 7.0000],
+            [2.5000, 2.5000, 2.5000, 2.5000, 5.0000, 6.5000, 6.5000]])
+
+        Reference:
+            https://github.com/scipy/scipy/blob/v0.17.1/scipy/stats/stats.py#L5262-L5352
+
+        """
+        length, width = scores.shape
+        true_tensor = torch.full((length, 1), True, dtype=torch.bool, device=self.device)
+
+        obs = torch.cat([true_tensor, scores[:, 1:] != scores[:, :-1]], dim=1)
+        # bias added to dense
+        bias = torch.arange(0, length, device=self.device).repeat(width).reshape(width, -1). \
+            transpose(1, 0).reshape(-1)
+        dense = obs.view(-1).cumsum(0) + bias
+
+        # cumulative counts of each unique value
+        count = torch.where(torch.cat([obs, true_tensor], dim=1))[1]
+        # get average rank
+        avg_rank = .5 * (count[dense] + count[dense - 1] + 1).view(length, -1)
+
+        return avg_rank
+
+    def eval_batch_collect(
+        self, scores_tensor: torch.Tensor, interaction, positive_u: torch.Tensor, positive_i: torch.Tensor
+    ):
+        """ Collect the evaluation resource from batched eval data and batched model output.
+            Args:
+                scores_tensor (Torch.Tensor): the output tensor of model with the shape of `(N, )`
+                interaction(Interaction): batched eval data.
+                positive_u(Torch.Tensor): the row index of positive items for each user.
+                positive_i(Torch.Tensor): the positive item id for each user.
+        """
+        if self.register.need('rec.items'):
+
+            # get topk
+            _, topk_idx = torch.topk(scores_tensor, max(self.topk), dim=-1)  # n_users x k
+            self.data_struct.update_tensor('rec.items', topk_idx)
+
+        if self.register.need('rec.topk'):
+
+            _, topk_idx = torch.topk(scores_tensor, max(self.topk), dim=-1)  # n_users x k
+            pos_matrix = torch.zeros_like(scores_tensor, dtype=torch.int)
+            pos_matrix[positive_u, positive_i] = 1
+            pos_len_list = pos_matrix.sum(dim=1, keepdim=True)
+            pos_idx = torch.gather(pos_matrix, dim=1, index=topk_idx)
+            result = torch.cat((pos_idx, pos_len_list), dim=1)
+            self.data_struct.update_tensor('rec.topk', result)
+
+        if self.register.need('rec.meanrank'):
+
+            desc_scores, desc_index = torch.sort(scores_tensor, dim=-1, descending=True)
+
+            # get the index of positive items in the ranking list
+            pos_matrix = torch.zeros_like(scores_tensor)
+            pos_matrix[positive_u, positive_i] = 1
+            pos_index = torch.gather(pos_matrix, dim=1, index=desc_index)
+
+            avg_rank = self._average_rank(desc_scores)
+            pos_rank_sum = torch.where(pos_index == 1, avg_rank, torch.zeros_like(avg_rank)).sum(dim=-1, keepdim=True)
+
+            pos_len_list = pos_matrix.sum(dim=1, keepdim=True)
+            user_len_list = desc_scores.argmin(dim=1, keepdim=True)
+            result = torch.cat((pos_rank_sum, user_len_list, pos_len_list), dim=1)
+            self.data_struct.update_tensor('rec.meanrank', result)
+
+        if self.register.need('rec.score'):
+
+            self.data_struct.update_tensor('rec.score', scores_tensor)
+
+        if self.register.need('data.label'):
+            self.label_field = self.config['LABEL_FIELD']
+            self.data_struct.update_tensor('data.label', interaction[self.label_field].to(self.device))
+
+    def model_collect(self, model: torch.nn.Module):
+        """ Collect the evaluation resource from model.
+            Args:
+                model (nn.Module): the trained recommendation model.
+        """
+        pass
+        # TODO:
+
+    def eval_collect(self, eval_pred: torch.Tensor, data_label: torch.Tensor):
+        """ Collect the evaluation resource from total output and label.
+            It was designed for those models that can not predict with batch.
+            Args:
+                eval_pred (torch.Tensor): the output score tensor of model.
+                data_label (torch.Tensor): the label tensor.
+        """
+        if self.register.need('rec.score'):
+            self.data_struct.update_tensor('rec.score', eval_pred)
+
+        if self.register.need('data.label'):
+            self.label_field = self.config['LABEL_FIELD']
+            self.data_struct.update_tensor('data.label', data_label.to(self.device))
+
+    def get_data_struct(self):
+        """ Get all the evaluation resource that been collected.
+            And reset some of outdated resource.
+        """
+        returned_struct = copy.deepcopy(self.data_struct)
+        for key in ['rec.topk', 'rec.meanrank', 'rec.score', 'rec.items', 'data.label']:
+            if key in self.data_struct:
+                del self.data_struct[key]
+        return returned_struct
diff --git a/recbole/evaluator/evaluator.py b/recbole/evaluator/evaluator.py
new file mode 100644
index 000000000..d83dda333
--- /dev/null
+++ b/recbole/evaluator/evaluator.py
@@ -0,0 +1,41 @@
+# -*- encoding: utf-8 -*-
+# @Time    :   2021/6/25
+# @Author  :   Zhichao Feng
+# @email   :   fzcbupt@gmail.com
+
+"""
+recbole.evaluator.evaluator
+#####################################
+"""
+
+from recbole.evaluator.register import metrics_dict
+from recbole.evaluator.collector import DataStruct
+
+
+class Evaluator(object):
+    """Evaluator is used to check parameter correctness, and summarize the results of all metrics.
+    """
+
+    def __init__(self, config):
+        self.config = config
+        self.metrics = [metric.lower() for metric in self.config['metrics']]
+        self.metric_class = {}
+
+        for metric in self.metrics:
+            self.metric_class[metric] = metrics_dict[metric](self.config)
+
+    def evaluate(self, dataobject: DataStruct):
+        """calculate all the metrics. It is called at the end of each epoch
+
+        Args:
+            dataobject (DataStruct): It contains all the information needed for metrics.
+
+        Returns:
+            dict: such as ``{'hit@20': 0.3824, 'recall@20': 0.0527, 'hit@10': 0.3153, 'recall@10': 0.0329, 'gauc': 0.9236}``
+
+        """
+        result_dict = {}
+        for metric in self.metrics:
+            metric_val = self.metric_class[metric].calculate_metric(dataobject)
+            result_dict.update(metric_val)
+        return result_dict
diff --git a/recbole/evaluator/evaluators.py b/recbole/evaluator/evaluators.py
deleted file mode 100644
index 8b0d97238..000000000
--- a/recbole/evaluator/evaluators.py
+++ /dev/null
@@ -1,370 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Time    :   2020/08/04
-# @Author  :   Kaiyuan Li
-# @email   :   tsotfsk@outlook.com
-
-# UPDATE
-# @Time    :   2021/01/07, 2020/08/11, 2020/12/18
-# @Author  :   Kaiyuan Li, Yupeng Hou, Zhichao Feng
-# @email   :   tsotfsk@outlook.com, houyupeng@ruc.edu.cn, fzcbupt@gmail.com
-
-"""
-recbole.evaluator.evaluators
-#####################################
-"""
-
-from collections import ChainMap
-
-import numpy as np
-import torch
-
-from recbole.evaluator.abstract_evaluator import GroupedEvaluator, IndividualEvaluator
-from recbole.evaluator.metrics import metrics_dict
-
-# These metrics are typical in topk recommendations
-topk_metrics = {metric.lower(): metric for metric in ['Hit', 'Recall', 'MRR', 'Precision', 'NDCG', 'MAP']}
-# These metrics are typical in loss recommendations
-loss_metrics = {metric.lower(): metric for metric in ['AUC', 'RMSE', 'MAE', 'LOGLOSS']}
-# For GAUC
-rank_metrics = {metric.lower(): metric for metric in ['GAUC']}
-
-# group-based metrics
-group_metrics = ChainMap(topk_metrics, rank_metrics)
-# not group-based metrics
-individual_metrics = ChainMap(loss_metrics)
-
-
-class TopKEvaluator(GroupedEvaluator):
-    r"""TopK Evaluator is mainly used in ranking tasks. Now, we support six topk metrics which
-       contain `'Hit', 'Recall', 'MRR', 'Precision', 'NDCG', 'MAP'`.
-
-    Note:
-       The metrics used calculate group-based metrics which considers the metrics scores averaged
-       across users. Some of them are also limited to k.
-
-    """
-
-    def __init__(self, config, metrics):
-        super().__init__(config, metrics)
-
-        self.topk = config['topk']
-        self._check_args()
-
-    def collect(self, interaction, scores_tensor):
-        """collect the topk intermediate result of one batch, this function mainly
-        implements padding and TopK finding. It is called at the end of each batch
-
-        Args:
-            interaction (Interaction): :class:`AbstractEvaluator` of the batch
-            scores_tensor (tensor): the tensor of model output with size of `(N, )`
-
-        Returns:
-            torch.Tensor : a matrix contain topk matrix and shape matrix
-
-       """
-        user_len_list = interaction.user_len_list
-
-        scores_matrix = self.get_score_matrix(scores_tensor, user_len_list)
-        scores_matrix = torch.flip(scores_matrix, dims=[-1])
-        shape_matrix = torch.full((len(user_len_list), 1), scores_matrix.shape[1], device=scores_matrix.device)
-
-        # get topk
-        _, topk_idx = torch.topk(scores_matrix, max(self.topk), dim=-1)  # n_users x k
-
-        # pack top_idx and shape_matrix
-        result = torch.cat((topk_idx, shape_matrix), dim=1)
-        return result
-
-    def evaluate(self, batch_matrix_list, eval_data):
-        """calculate the metrics of all batches. It is called at the end of each epoch
-
-        Args:
-            batch_matrix_list (list): the results of all batches
-            eval_data (Dataset): the class of test data
-
-        Returns:
-            dict: such as ``{'Hit@20': 0.3824, 'Recall@20': 0.0527, 'Hit@10': 0.3153, 'Recall@10': 0.0329}``
-
-        """
-        pos_len_list = eval_data.get_pos_len_list()
-        batch_result = torch.cat(batch_matrix_list, dim=0).cpu().numpy()
-
-        # unpack top_idx and shape_matrix
-        topk_idx = batch_result[:, :-1]
-        shapes = batch_result[:, -1]
-
-        assert len(pos_len_list) == len(topk_idx)
-        # get metrics
-        metric_dict = {}
-        result_list = self._calculate_metrics(pos_len_list, topk_idx, shapes)
-        for metric, value in zip(self.metrics, result_list):
-            for k in self.topk:
-                key = '{}@{}'.format(metric, k)
-                metric_dict[key] = round(value[k - 1], self.precision)
-
-        return metric_dict
-
-    def _check_args(self):
-
-        # Check topk:
-        if isinstance(self.topk, (int, list)):
-            if isinstance(self.topk, int):
-                self.topk = [self.topk]
-            for topk in self.topk:
-                if topk <= 0:
-                    raise ValueError(
-                        'topk must be a positive integer or a list of positive integers, '
-                        'but get `{}`'.format(topk)
-                    )
-        else:
-            raise TypeError('The topk must be a integer, list')
-
-    def _calculate_metrics(self, pos_len_list, topk_idx, shapes):
-        """integrate the results of each batch and evaluate the topk metrics by users
-
-        Args:
-            pos_len_list (numpy.ndarray): a list of users' positive items
-            topk_idx (numpy.ndarray): a matrix which contains the index of the topk items for users
-            shapes (numpy.ndarray): a list which contains the columns of the padded batch matrix
-
-        Returns:
-            numpy.ndarray: a matrix which contains the metrics result
-
-        """
-        pos_idx_matrix = (topk_idx >= (shapes - pos_len_list).reshape(-1, 1))
-        result_list = []
-        for metric in self.metrics:
-            metric_fuc = metrics_dict[metric.lower()]
-            result = metric_fuc(pos_idx_matrix, pos_len_list)
-            result_list.append(result)  # n_users x len(metrics) x len(ranks)
-        result = np.stack(result_list, axis=0).mean(axis=1)  # len(metrics) x len(ranks)
-        return result
-
-    def __str__(self):
-        msg = 'The TopK Evaluator Info:\n' + \
-              '\tMetrics:[' + \
-              ', '.join([topk_metrics[metric.lower()] for metric in self.metrics]) + \
-              '], TopK:[' + \
-              ', '.join(map(str, self.topk)) + \
-              ']'
-        return msg
-
-
-class RankEvaluator(GroupedEvaluator):
-    r"""Rank Evaluator is mainly used in ranking tasks except for topk tasks. Now, we support one
-    rank metric containing `'GAUC'`.
-
-    Note:
-        The metrics used calculate group-based metrics which considers the metrics scores averaged
-        across users except for top-k metrics.
-
-    """
-
-    def __init__(self, config, metrics):
-        super().__init__(config, metrics)
-        pass
-
-    def get_user_pos_len_list(self, interaction, scores_tensor):
-        """get number of positive items and all items in test set of each user
-
-        Args:
-            interaction (Interaction): :class:`AbstractEvaluator` of the batch
-            scores_tensor (tensor): the tensor of model output with size of `(N, )`
-
-        Returns:
-            list: number of positive items,
-            list: number of all items
-        """
-        pos_len_list = torch.Tensor(interaction.pos_len_list).to(scores_tensor.device)
-        user_len_list = interaction.user_len_list
-        return pos_len_list, user_len_list
-
-    def average_rank(self, scores):
-        """Get the ranking of an ordered tensor, and take the average of the ranking for positions with equal values.
-
-        Args:
-            scores(tensor): an ordered tensor, with size of `(N, )`
-
-        Returns:
-            torch.Tensor: average_rank
-
-        Example:
-            >>> average_rank(tensor([[1,2,2,2,3,3,6],[2,2,2,2,4,5,5]]))
-            tensor([[1.0000, 3.0000, 3.0000, 3.0000, 5.5000, 5.5000, 7.0000],
-            [2.5000, 2.5000, 2.5000, 2.5000, 5.0000, 6.5000, 6.5000]])
-
-        Reference:
-            https://github.com/scipy/scipy/blob/v0.17.1/scipy/stats/stats.py#L5262-L5352
-
-        """
-        length, width = scores.shape
-        device = scores.device
-        true_tensor = torch.full((length, 1), True, dtype=torch.bool, device=device)
-
-        obs = torch.cat([true_tensor, scores[:, 1:] != scores[:, :-1]], dim=1)
-        # bias added to dense
-        bias = torch.arange(0, length, device=device).repeat(width).reshape(width, -1). \
-            transpose(1, 0).reshape(-1)
-        dense = obs.view(-1).cumsum(0) + bias
-
-        # cumulative counts of each unique value
-        count = torch.where(torch.cat([obs, true_tensor], dim=1))[1]
-        # get average rank
-        avg_rank = .5 * (count[dense] + count[dense - 1] + 1).view(length, -1)
-
-        return avg_rank
-
-    def collect(self, interaction, scores_tensor):
-        """collect the rank intermediate result of one batch, this function mainly implements ranking
-        and calculating the sum of rank for positive items. It is called at the end of each batch
-
-        Args:
-            interaction (Interaction): :class:`AbstractEvaluator` of the batch
-            scores_tensor (tensor): the tensor of model output with size of `(N, )`
-
-        """
-        pos_len_list, user_len_list = self.get_user_pos_len_list(interaction, scores_tensor)
-        scores_matrix = self.get_score_matrix(scores_tensor, user_len_list)
-        desc_scores, desc_index = torch.sort(scores_matrix, dim=-1, descending=True)
-
-        # get the index of positive items in the ranking list
-        pos_index = (desc_index < pos_len_list.reshape(-1, 1))
-
-        avg_rank = self.average_rank(desc_scores)
-        pos_rank_sum = torch.where(pos_index, avg_rank, torch.zeros_like(avg_rank)).sum(axis=-1).reshape(-1, 1)
-
-        return pos_rank_sum
-
-    def evaluate(self, batch_matrix_list, eval_data):
-        """calculate the metrics of all batches. It is called at the end of each epoch
-
-        Args:
-            batch_matrix_list (list): the results of all batches
-            eval_data (Dataset): the class of test data
-
-        Returns:
-            dict: such as ``{'GAUC': 0.9286}``
-
-        """
-        pos_len_list = eval_data.get_pos_len_list()
-        user_len_list = eval_data.get_user_len_list()
-        pos_rank_sum = torch.cat(batch_matrix_list, dim=0).cpu().numpy()
-        assert len(pos_len_list) == len(pos_rank_sum)
-
-        # get metrics
-        metric_dict = {}
-        result_list = self._calculate_metrics(user_len_list, pos_len_list, pos_rank_sum)
-        for metric, value in zip(self.metrics, result_list):
-            key = '{}'.format(metric)
-            metric_dict[key] = round(value, self.precision)
-
-        return metric_dict
-
-    def _calculate_metrics(self, user_len_list, pos_len_list, pos_rank_sum):
-        """integrate the results of each batch and evaluate the topk metrics by users
-
-        Args:
-            pos_len_list (numpy.ndarray): a list of users' positive items
-            topk_idx (numpy.ndarray): a matrix which contains the index of the topk items for users
-
-        Returns:
-            numpy.ndarray: a matrix which contains the metrics result
-
-        """
-        result_list = []
-        for metric in self.metrics:
-            metric_fuc = metrics_dict[metric.lower()]
-            result = metric_fuc(user_len_list, pos_len_list, pos_rank_sum)
-            result_list.append(result)
-        return result_list
-
-    def __str__(self):
-        msg = 'The Rank Evaluator Info:\n' + \
-              '\tMetrics:[' + \
-              ', '.join([rank_metrics[metric.lower()] for metric in self.metrics]) + \
-              ']'
-        return msg
-
-
-class LossEvaluator(IndividualEvaluator):
-    r"""Loss Evaluator is mainly used in rating prediction and click through rate prediction. Now, we support four
-    loss metrics which contain `'AUC', 'RMSE', 'MAE', 'LOGLOSS'`.
-
-    Note:
-        The metrics used do not calculate group-based metrics which considers the metrics scores averaged
-        across users. They are also not limited to k. Instead, they calculate the scores on the entire
-        prediction results regardless the users.
-
-    """
-
-    def __init__(self, config, metrics):
-        super().__init__(config, metrics)
-
-        self.label_field = config['LABEL_FIELD']
-
-    def collect(self, interaction, pred_scores):
-        """collect the loss intermediate result of one batch, this function mainly
-        implements concatenating preds and trues. It is called at the end of each batch
-
-        Args:
-            interaction (Interaction): :class:`AbstractEvaluator` of the batch
-            pred_scores (tensor): the tensor of model output with a size of `(N, )`
-
-        Returns:
-            tensor : a batch of scores with a size of `(N, 2)`
-
-        """
-        true_scores = interaction[self.label_field].to(pred_scores.device)
-        assert len(true_scores) == len(pred_scores)
-        return self.get_score_matrix(true_scores, pred_scores)
-
-    def evaluate(self, batch_matrix_list, *args):
-        """calculate the metrics of all batches. It is called at the end of each epoch
-
-        Args:
-            batch_matrix_list (list): the results of all batches
-
-        Returns:
-            dict: such as {'AUC': 0.83}
-
-        """
-        concat = torch.cat(batch_matrix_list, dim=0).cpu().numpy()
-
-        trues = concat[:, 0]
-        preds = concat[:, 1]
-
-        # get metrics
-        metric_dict = {}
-        result_list = self._calculate_metrics(trues, preds)
-        for metric, value in zip(self.metrics, result_list):
-            key = '{}'.format(metric)
-            metric_dict[key] = round(value, self.precision)
-        return metric_dict
-
-    def _calculate_metrics(self, trues, preds):
-        """get metrics result
-
-        Args:
-            trues (numpy.ndarray): the true scores' list
-            preds (numpy.ndarray): the predict scores' list
-
-        Returns:
-            list: a list of metrics result
-
-        """
-        result_list = []
-        for metric in self.metrics:
-            metric_fuc = metrics_dict[metric.lower()]
-            result = metric_fuc(trues, preds)
-            result_list.append(result)
-        return result_list
-
-    def __str__(self):
-        msg = 'The Loss Evaluator Info:\n' + \
-              '\tMetrics:[' + \
-              ', '.join([loss_metrics[metric.lower()] for metric in self.metrics]) + \
-              ']'
-        return msg
-
-
-metric_eval_bind = [(topk_metrics, TopKEvaluator), (loss_metrics, LossEvaluator), (rank_metrics, RankEvaluator)]
diff --git a/recbole/evaluator/metrics.py b/recbole/evaluator/metrics.py
index 9c470e12b..e6867dc36 100644
--- a/recbole/evaluator/metrics.py
+++ b/recbole/evaluator/metrics.py
@@ -4,352 +4,742 @@
 # @email   :   tsotfsk@outlook.com
 
 # UPDATE
-# @Time    :   2020/08/12, 2020/12/21, 2020/9/16
-# @Author  :   Kaiyuan Li, Zhichao Feng, Xingyu Pan
-# @email   :   tsotfsk@outlook.com, fzcbupt@gmail.com, panxy@ruc.edu.cn
+# @Time    :   2020/08/12, 2021/8/29, 2020/9/16, 2021/7/2
+# @Author  :   Kaiyuan Li, Zhichao Feng, Xingyu Pan, Zihan Lin
+# @email   :   tsotfsk@outlook.com, fzcbupt@gmail.com, panxy@ruc.edu.cn, zhlin@ruc.edu.cn
 
-"""
+r"""
 recbole.evaluator.metrics
 ############################
+
+Suppose there is a set of :math:`n` items to be ranked. Given a user :math:`u` in the user set :math:`U`,
+we use :math:`\hat R(u)` to represent a ranked list of items that a model produces, and :math:`R(u)` to
+represent a ground-truth set of items that user :math:`u` has interacted with. For top-k recommendation, only
+top-ranked items are important to consider. Therefore, in top-k evaluation scenarios, we truncate the
+recommendation list with a length :math:`K`. Besides, in loss-based metrics, :math:`S` represents the
+set of user(u)-item(i) pairs, :math:`\hat r_{u i}` represents the score predicted by the model,
+:math:`{r}_{u i}` represents the ground-truth labels.
+
 """
 
 from logging import getLogger
 
 import numpy as np
+from collections import Counter
 from sklearn.metrics import auc as sk_auc
 from sklearn.metrics import mean_absolute_error, mean_squared_error
 
 from recbole.evaluator.utils import _binary_clf_curve
+from recbole.evaluator.base_metric import AbstractMetric, TopkMetric, LossMetric
+from recbole.utils import EvaluatorType
 
-#    TopK Metrics    #
+# TopK Metrics
 
 
-def hit_(pos_index, pos_len):
-    r"""Hit_ (also known as hit ratio at :math:`N`) is a way of calculating how many 'hits' you have
-    in an n-sized list of ranked items.
+class Hit(TopkMetric):
+    r"""HR_ (also known as truncated Hit-Ratio) is a way of calculating how many 'hits'
+    you have in an n-sized list of ranked items. If there is at least one item that falls in the ground-truth set,
+    we call it a hit.
 
-    .. _Hit: https://medium.com/@rishabhbhatia315/recommendation-system-evaluation-metrics-3f6739288870
+    .. _HR: https://medium.com/@rishabhbhatia315/recommendation-system-evaluation-metrics-3f6739288870
 
     .. math::
-        \mathrm {HR@K} =\frac{Number \space of \space Hits @K}{|GT|}
-
-    :math:`HR` is the number of users with a positive sample in the recommendation list.
-    :math:`GT` is the total number of samples in the test set.
+        \mathrm {HR@K} = \frac{1}{|U|}\sum_{u \in U} \delta(\hat{R}(u) \cap R(u) \neq \emptyset),
 
+    :math:`\delta(·)` is an indicator function. :math:`\delta(b)` = 1 if :math:`b` is true and 0 otherwise.
+    :math:`\emptyset` denotes the empty set.
     """
-    result = np.cumsum(pos_index, axis=1)
-    return (result > 0).astype(int)
 
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        pos_index, _ = self.used_info(dataobject)
+        result = self.metric_info(pos_index)
+        metric_dict = self.topk_result('hit', result)
+        return metric_dict
+
+    def metric_info(self, pos_index):
+        result = np.cumsum(pos_index, axis=1)
+        return (result > 0).astype(int)
 
-def mrr_(pos_index, pos_len):
-    r"""The MRR_ (also known as mean reciprocal rank) is a statistic measure for evaluating any process
-    that produces a list of possible responses to a sample of queries, ordered by probability of correctness.
+
+class MRR(TopkMetric):
+    r"""The MRR_ (also known as Mean Reciprocal Rank) computes the reciprocal rank
+    of the first relevant item found by an algorithm.
 
     .. _MRR: https://en.wikipedia.org/wiki/Mean_reciprocal_rank
 
     .. math::
-        \mathrm {MRR} = \frac{1}{|{U}|} \sum_{i=1}^{|{U}|} \frac{1}{rank_i}
-
-    :math:`U` is the number of users, :math:`rank_i` is the rank of the first item in the recommendation list
-    in the test set results for user :math:`i`.
+       \mathrm {MRR@K} = \frac{1}{|U|}\sum_{u \in U} \frac{1}{\operatorname{rank}_{u}^{*}}
 
+    :math:`{rank}_{u}^{*}` is the rank position of the first relevant item found by an algorithm for a user :math:`u`.
     """
-    idxs = pos_index.argmax(axis=1)
-    result = np.zeros_like(pos_index, dtype=np.float)
-    for row, idx in enumerate(idxs):
-        if pos_index[row, idx] > 0:
-            result[row, idx:] = 1 / (idx + 1)
-        else:
-            result[row, idx:] = 0
-    return result
 
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        pos_index, _ = self.used_info(dataobject)
+        result = self.metric_info(pos_index)
+        metric_dict = self.topk_result('mrr', result)
+        return metric_dict
+
+    def metric_info(self, pos_index):
+        idxs = pos_index.argmax(axis=1)
+        result = np.zeros_like(pos_index, dtype=np.float)
+        for row, idx in enumerate(idxs):
+            if pos_index[row, idx] > 0:
+                result[row, idx:] = 1 / (idx + 1)
+            else:
+                result[row, idx:] = 0
+        return result
 
-def map_(pos_index, pos_len):
-    r"""MAP_ (also known as Mean Average Precision) The MAP is meant to calculate Avg. Precision for the relevant items.
+
+class MAP(TopkMetric):
+    r"""MAP_ (also known as Mean Average Precision) is meant to calculate
+    average precision for the relevant items.
 
     Note:
-        In this case the normalization factor used is :math:`\frac{1}{\min (m,N)}`, which prevents your AP score from
-        being unfairly suppressed when your number of recommendations couldn't possibly capture all the correct ones.
+        In this case the normalization factor used is :math:`\frac{1}{min(|\hat R(u)|, K)}`, which prevents your
+        AP score from being unfairly suppressed when your number of recommendations couldn't possibly capture
+        all the correct ones.
 
-    .. _map: http://sdsawtelle.github.io/blog/output/mean-average-precision-MAP-for-recommender-systems.html#MAP-for-Recommender-Algorithms
+    .. _MAP: http://sdsawtelle.github.io/blog/output/mean-average-precision-MAP-for-recommender-systems.html#MAP-for-Recommender-Algorithms
 
     .. math::
-        \begin{align*}
-        \mathrm{AP@N} &= \frac{1}{\mathrm{min}(m,N)}\sum_{k=1}^N P(k) \cdot rel(k) \\
-        \mathrm{MAP@N}& = \frac{1}{|U|}\sum_{u=1}^{|U|}(\mathrm{AP@N})_u
-        \end{align*}
+       \mathrm{MAP@K} = \frac{1}{|U|}\sum_{u \in U} (\frac{1}{min(|\hat R(u)|, K)} \sum_{j=1}^{|\hat{R}(u)|} I\left(\hat{R}_{j}(u) \in R(u)\right) \cdot  Precision@j)
 
+    :math:`\hat{R}_{j}(u)` is the j-th item in the recommendation list of \hat R (u)).
     """
-    pre = precision_(pos_index, pos_len)
-    sum_pre = np.cumsum(pre * pos_index.astype(np.float), axis=1)
-    len_rank = np.full_like(pos_len, pos_index.shape[1])
-    actual_len = np.where(pos_len > len_rank, len_rank, pos_len)
-    result = np.zeros_like(pos_index, dtype=np.float)
-    for row, lens in enumerate(actual_len):
-        ranges = np.arange(1, pos_index.shape[1] + 1)
-        ranges[lens:] = ranges[lens - 1]
-        result[row] = sum_pre[row] / ranges
-    return result
-
-
-def recall_(pos_index, pos_len):
-    r"""Recall_ (also known as sensitivity) is the fraction of the total amount of relevant instances
-    that were actually retrieved
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.config = config
+
+    def calculate_metric(self, dataobject):
+        pos_index, pos_len = self.used_info(dataobject)
+        result = self.metric_info(pos_index, pos_len)
+        metric_dict = self.topk_result('map', result)
+        return metric_dict
+
+    def metric_info(self, pos_index, pos_len):
+        pre = pos_index.cumsum(axis=1) / np.arange(1, pos_index.shape[1] + 1)
+        sum_pre = np.cumsum(pre * pos_index.astype(np.float), axis=1)
+        len_rank = np.full_like(pos_len, pos_index.shape[1])
+        actual_len = np.where(pos_len > len_rank, len_rank, pos_len)
+        result = np.zeros_like(pos_index, dtype=np.float)
+        for row, lens in enumerate(actual_len):
+            ranges = np.arange(1, pos_index.shape[1] + 1)
+            ranges[lens:] = ranges[lens - 1]
+            result[row] = sum_pre[row] / ranges
+        return result
+
+
+class Recall(TopkMetric):
+    r"""Recall_ is a measure for computing the fraction of relevant items out of all relevant items.
 
     .. _recall: https://en.wikipedia.org/wiki/Precision_and_recall#Recall
 
     .. math::
-        \mathrm {Recall@K} = \frac{|Rel_u\cap Rec_u|}{Rel_u}
-
-    :math:`Rel_u` is the set of items relevant to user :math:`U`,
-    :math:`Rec_u` is the top K items recommended to users.
-    We obtain the result by calculating the average :math:`Recall@K` of each user.
+       \mathrm {Recall@K} = \frac{1}{|U|}\sum_{u \in U} \frac{|\hat{R}(u) \cap R(u)|}{|R(u)|}
 
+    :math:`|R(u)|` represents the item count of :math:`R(u)`.
     """
-    return np.cumsum(pos_index, axis=1) / pos_len.reshape(-1, 1)
 
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        pos_index, pos_len = self.used_info(dataobject)
+        result = self.metric_info(pos_index, pos_len)
+        metric_dict = self.topk_result('recall', result)
+        return metric_dict
 
-def ndcg_(pos_index, pos_len):
-    r"""NDCG_ (also known as normalized discounted cumulative gain) is a measure of ranking quality.
-    Through normalizing the score, users and their recommendation list results in the whole test set can be evaluated.
+    def metric_info(self, pos_index, pos_len):
+        return np.cumsum(pos_index, axis=1) / pos_len.reshape(-1, 1)
+
+
+class NDCG(TopkMetric):
+    r"""NDCG_ (also known as normalized discounted cumulative gain) is a measure of ranking quality,
+    where positions are discounted logarithmically. It accounts for the position of the hit by assigning
+    higher scores to hits at top ranks.
 
     .. _NDCG: https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG
 
     .. math::
-        \begin{gather}
-            \mathrm {DCG@K}=\sum_{i=1}^{K} \frac{2^{rel_i}-1}{\log_{2}{(i+1)}}\\
-            \mathrm {IDCG@K}=\sum_{i=1}^{K}\frac{1}{\log_{2}{(i+1)}}\\
-            \mathrm {NDCG_u@K}=\frac{DCG_u@K}{IDCG_u@K}\\
-            \mathrm {NDCG@K}=\frac{\sum \nolimits_{u \in U^{te}NDCG_u@K}}{|U^{te}|}
-        \end{gather}
-
-    :math:`K` stands for recommending :math:`K` items.
-    And the :math:`rel_i` is the relevance of the item in position :math:`i` in the recommendation list.
-    :math:`{rel_i}` equals to 1 if the item is ground truth otherwise 0.
-    :math:`U^{te}` stands for all users in the test set.
+        \mathrm {NDCG@K} = \frac{1}{|U|}\sum_{u \in U} (\frac{1}{\sum_{i=1}^{\min (|R(u)|, K)}
+        \frac{1}{\log _{2}(i+1)}} \sum_{i=1}^{K} \delta(i \in R(u)) \frac{1}{\log _{2}(i+1)})
 
+    :math:`\delta(·)` is an indicator function.
     """
-    len_rank = np.full_like(pos_len, pos_index.shape[1])
-    idcg_len = np.where(pos_len > len_rank, len_rank, pos_len)
 
-    iranks = np.zeros_like(pos_index, dtype=np.float)
-    iranks[:, :] = np.arange(1, pos_index.shape[1] + 1)
-    idcg = np.cumsum(1.0 / np.log2(iranks + 1), axis=1)
-    for row, idx in enumerate(idcg_len):
-        idcg[row, idx:] = idcg[row, idx - 1]
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        pos_index, pos_len = self.used_info(dataobject)
+        result = self.metric_info(pos_index, pos_len)
+        metric_dict = self.topk_result('ndcg', result)
+        return metric_dict
 
-    ranks = np.zeros_like(pos_index, dtype=np.float)
-    ranks[:, :] = np.arange(1, pos_index.shape[1] + 1)
-    dcg = 1.0 / np.log2(ranks + 1)
-    dcg = np.cumsum(np.where(pos_index, dcg, 0), axis=1)
+    def metric_info(self, pos_index, pos_len):
+        len_rank = np.full_like(pos_len, pos_index.shape[1])
+        idcg_len = np.where(pos_len > len_rank, len_rank, pos_len)
 
-    result = dcg / idcg
-    return result
+        iranks = np.zeros_like(pos_index, dtype=np.float)
+        iranks[:, :] = np.arange(1, pos_index.shape[1] + 1)
+        idcg = np.cumsum(1.0 / np.log2(iranks + 1), axis=1)
+        for row, idx in enumerate(idcg_len):
+            idcg[row, idx:] = idcg[row, idx - 1]
 
+        ranks = np.zeros_like(pos_index, dtype=np.float)
+        ranks[:, :] = np.arange(1, pos_index.shape[1] + 1)
+        dcg = 1.0 / np.log2(ranks + 1)
+        dcg = np.cumsum(np.where(pos_index, dcg, 0), axis=1)
 
-def precision_(pos_index, pos_len):
-    r"""Precision_ (also called positive predictive value) is the fraction of
-    relevant instances among the retrieved instances
+        result = dcg / idcg
+        return result
+
+
+class Precision(TopkMetric):
+    r"""Precision_ (also called positive predictive value) is a measure for computing the fraction of relevant items
+    out of all the recommended items. We average the metric for each user :math:`u` get the final result.
 
     .. _precision: https://en.wikipedia.org/wiki/Precision_and_recall#Precision
 
     .. math::
-        \mathrm {Precision@K} = \frac{|Rel_u \cap Rec_u|}{Rec_u}
-
-    :math:`Rel_u` is the set of items relevant to user :math:`U`,
-    :math:`Rec_u` is the top K items recommended to users.
-    We obtain the result by calculating the average :math:`Precision@K` of each user.
+        \mathrm {Precision@K} =  \frac{1}{|U|}\sum_{u \in U} \frac{|\hat{R}(u) \cap R(u)|}{|\hat {R}(u)|}
 
+    :math:`|\hat R(u)|` represents the item count of :math:`\hat R(u)`.
     """
-    return pos_index.cumsum(axis=1) / np.arange(1, pos_index.shape[1] + 1)
+
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        pos_index, _ = self.used_info(dataobject)
+        result = self.metric_info(pos_index)
+        metric_dict = self.topk_result('precision', result)
+        return metric_dict
+
+    def metric_info(self, pos_index):
+        return pos_index.cumsum(axis=1) / np.arange(1, pos_index.shape[1] + 1)
+
+
+# CTR Metrics
 
 
-def gauc_(user_len_list, pos_len_list, pos_rank_sum):
-    r"""GAUC_ (also known as Group Area Under Curve) is used to evaluate the two-class model, referring to
-    the area under the ROC curve grouped by user.
+class GAUC(AbstractMetric):
+    r"""GAUC (also known as Grouped Area Under Curve) is used to evaluate the two-class model, referring to
+    the area under the ROC curve grouped by user. We weighted the index of each user :math:`u` by the number of positive
+    samples of users to get the final result.
 
-    .. _GAUC: https://dl.acm.org/doi/10.1145/3219819.3219823
+    For further details, please refer to the `paper <https://dl.acm.org/doi/10.1145/3219819.3219823>`__
 
     Note:
         It calculates the AUC score of each user, and finally obtains GAUC by weighting the user AUC.
-        It is also not limited to k. Due to our padding for `scores_tensor` in `RankEvaluator` with
-        `-np.inf`, the padding value will influence the ranks of origin items. Therefore, we use
-        descending sort here and make an identity transformation  to the formula of `AUC`, which is
-        shown in `auc_` function. For readability, we didn't do simplification in the code.
+        It is also not limited to k. Due to our padding for `scores_tensor` with `-np.inf`, the padding
+        value will influence the ranks of origin items. Therefore, we use descending sort here and make
+        an identity transformation  to the formula of `AUC`, which is shown in `auc_` function.
+        For readability, we didn't do simplification in the code.
 
     .. math::
-        \mathrm {GAUC} = \frac {{{M} \times {(M+N+1)} - \frac{M \times (M+1)}{2}} -
-        \sum\limits_{i=1}^M rank_{i}} {{M} \times {N}}
-
-    :math:`M` is the number of positive samples.
-    :math:`N` is the number of negative samples.
-    :math:`rank_i` is the descending rank of the ith positive sample.
+        \begin{align*}
+            \mathrm {AUC(u)} &= \frac {{{|R(u)|} \times {(n+1)} - \frac{|R(u)| \times (|R(u)|+1)}{2}} -
+            \sum\limits_{i=1}^{|R(u)|} rank_{i}} {{|R(u)|} \times {(n - |R(u)|)}} \\
+            \mathrm{GAUC} &= \frac{1}{\sum_{u \in U} |R(u)|}\sum_{u \in U} |R(u)| \cdot(\mathrm {AUC(u)})
+        \end{align*}
 
+    :math:`rank_i` is the descending rank of the i-th items in :math:`R(u)`.
     """
-    neg_len_list = user_len_list - pos_len_list
-
-    # check positive and negative samples
-    any_without_pos = np.any(pos_len_list == 0)
-    any_without_neg = np.any(neg_len_list == 0)
-    non_zero_idx = np.full(len(user_len_list), True, dtype=np.bool)
-    if any_without_pos:
-        logger = getLogger()
-        logger.warning(
-            "No positive samples in some users, "
-            "true positive value should be meaningless, "
-            "these users have been removed from GAUC calculation"
-        )
-        non_zero_idx *= (pos_len_list != 0)
-    if any_without_neg:
-        logger = getLogger()
-        logger.warning(
-            "No negative samples in some users, "
-            "false positive value should be meaningless, "
-            "these users have been removed from GAUC calculation"
-        )
-        non_zero_idx *= (neg_len_list != 0)
-    if any_without_pos or any_without_neg:
-        item_list = user_len_list, neg_len_list, pos_len_list, pos_rank_sum
-        user_len_list, neg_len_list, pos_len_list, pos_rank_sum = \
-            map(lambda x: x[non_zero_idx], item_list)
-
-    pair_num = (user_len_list + 1) * pos_len_list - pos_len_list * (pos_len_list + 1) / 2 - np.squeeze(pos_rank_sum)
-    user_auc = pair_num / (neg_len_list * pos_len_list)
-    result = (user_auc * pos_len_list).sum() / pos_len_list.sum()
-
-    return result
-
-
-#    CTR Metrics    #
-def auc_(trues, preds):
+    metric_type = EvaluatorType.RANKING
+    metric_need = ['rec.meanrank']
+
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        mean_rank = dataobject.get('rec.meanrank').numpy()
+        pos_rank_sum, user_len_list, pos_len_list = np.split(mean_rank, 3, axis=1)
+        user_len_list, pos_len_list = user_len_list.squeeze(), pos_len_list.squeeze()
+        result = self.metric_info(pos_rank_sum, user_len_list, pos_len_list)
+        return {'gauc': round(result, self.decimal_place)}
+
+    def metric_info(self, pos_rank_sum, user_len_list, pos_len_list):
+        """Get the value of GAUC metric.
+
+        Args:
+            pos_rank_sum (numpy.ndarray): sum of descending rankings for positive items of each users.
+            user_len_list (numpy.ndarray): the number of predicted items for users.
+            pos_len_list (numpy.ndarray): the number of positive items for users.
+
+        Returns:
+            float: The value of the GAUC.
+        """
+        neg_len_list = user_len_list - pos_len_list
+        # check positive and negative samples
+        any_without_pos = np.any(pos_len_list == 0)
+        any_without_neg = np.any(neg_len_list == 0)
+        non_zero_idx = np.full(len(user_len_list), True, dtype=np.bool)
+        if any_without_pos:
+            logger = getLogger()
+            logger.warning(
+                "No positive samples in some users, "
+                "true positive value should be meaningless, "
+                "these users have been removed from GAUC calculation"
+            )
+            non_zero_idx *= (pos_len_list != 0)
+        if any_without_neg:
+            logger = getLogger()
+            logger.warning(
+                "No negative samples in some users, "
+                "false positive value should be meaningless, "
+                "these users have been removed from GAUC calculation"
+            )
+            non_zero_idx *= (neg_len_list != 0)
+        if any_without_pos or any_without_neg:
+            item_list = user_len_list, neg_len_list, pos_len_list, pos_rank_sum
+            user_len_list, neg_len_list, pos_len_list, pos_rank_sum = map(lambda x: x[non_zero_idx], item_list)
+
+        pair_num = (user_len_list + 1) * pos_len_list - pos_len_list * (pos_len_list + 1) / 2 - np.squeeze(pos_rank_sum)
+        user_auc = pair_num / (neg_len_list * pos_len_list)
+        result = (user_auc * pos_len_list).sum() / pos_len_list.sum()
+        return result
+
+
+class AUC(LossMetric):
     r"""AUC_ (also known as Area Under Curve) is used to evaluate the two-class model, referring to
-    the area under the ROC curve
+    the area under the ROC curve.
 
     .. _AUC: https://en.wikipedia.org/wiki/Receiver_operating_characteristic#Area_under_the_curve
 
     Note:
         This metric does not calculate group-based AUC which considers the AUC scores
         averaged across users. It is also not limited to k. Instead, it calculates the
-        scores on the entire prediction results regardless the users.
+        scores on the entire prediction results regardless the users. We call the interface
+        in `scikit-learn`, and code calculates the metric using the variation of following formula.
 
     .. math::
-        \mathrm {AUC} = \frac{\sum\limits_{i=1}^M rank_{i}
-        - \frac {{M} \times {(M+1)}}{2}} {{{M} \times {N}}}
-
-    :math:`M` is the number of positive samples.
-    :math:`N` is the number of negative samples.
-    :math:`rank_i` is the ascending rank of the ith positive sample.
+        \mathrm {AUC} = \frac {{{M} \times {(N+1)} - \frac{M \times (M+1)}{2}} -
+        \sum\limits_{i=1}^{M} rank_{i}} {{M} \times {(N - M)}}
 
+    :math:`M` denotes the number of positive items.
+    :math:`N` denotes the total number of user-item interactions.
+    :math:`rank_i` denotes the descending rank of the i-th positive item.
     """
-    fps, tps = _binary_clf_curve(trues, preds)
 
-    if len(fps) > 2:
-        optimal_idxs = np.where(np.r_[True, np.logical_or(np.diff(fps, 2), np.diff(tps, 2)), True])[0]
-        fps = fps[optimal_idxs]
-        tps = tps[optimal_idxs]
+    def __init__(self, config):
+        super().__init__(config)
+
+    def calculate_metric(self, dataobject):
+        return self.output_metric('auc', dataobject)
 
-    tps = np.r_[0, tps]
-    fps = np.r_[0, fps]
+    def metric_info(self, preds, trues):
+        fps, tps = _binary_clf_curve(trues, preds)
+        if len(fps) > 2:
+            optimal_idxs = np.where(np.r_[True, np.logical_or(np.diff(fps, 2), np.diff(tps, 2)), True])[0]
+            fps = fps[optimal_idxs]
+            tps = tps[optimal_idxs]
 
-    if fps[-1] <= 0:
-        logger = getLogger()
-        logger.warning("No negative samples in y_true, " "false positive value should be meaningless")
-        fpr = np.repeat(np.nan, fps.shape)
-    else:
-        fpr = fps / fps[-1]
+        tps = np.r_[0, tps]
+        fps = np.r_[0, fps]
 
-    if tps[-1] <= 0:
-        logger = getLogger()
-        logger.warning("No positive samples in y_true, " "true positive value should be meaningless")
-        tpr = np.repeat(np.nan, tps.shape)
-    else:
-        tpr = tps / tps[-1]
+        if fps[-1] <= 0:
+            logger = getLogger()
+            logger.warning("No negative samples in y_true, " "false positive value should be meaningless")
+            fpr = np.repeat(np.nan, fps.shape)
+        else:
+            fpr = fps / fps[-1]
+
+        if tps[-1] <= 0:
+            logger = getLogger()
+            logger.warning("No positive samples in y_true, " "true positive value should be meaningless")
+            tpr = np.repeat(np.nan, tps.shape)
+        else:
+            tpr = tps / tps[-1]
 
-    return sk_auc(fpr, tpr)
+        result = sk_auc(fpr, tpr)
+        return result
 
 
-# Loss based Metrics #
+# Loss-based Metrics
 
 
-def mae_(trues, preds):
-    r"""`Mean absolute error regression loss`__
+class MAE(LossMetric):
+    r"""MAE_ (also known as Mean Absolute Error regression loss) is used to evaluate the difference between
+    the score predicted by the model and the actual behavior of the user.
 
-    .. __: https://en.wikipedia.org/wiki/Mean_absolute_error
+    .. _MAE: https://en.wikipedia.org/wiki/Mean_absolute_error
 
     .. math::
-        \mathrm{MAE}=\frac{1}{|{T}|} \sum_{(u, i) \in {T}}\left|\hat{r}_{u i}-r_{u i}\right|
+        \mathrm{MAE}=\frac{1}{|{S}|} \sum_{(u, i) \in {S}}\left|\hat{r}_{u i}-r_{u i}\right|
+
+    :math:`|S|` represents the number of pairs in :math:`S`.
+    """
+    smaller = True
 
-    :math:`T` is the test set, :math:`\hat{r}_{u i}` is the score predicted by the model,
-    and :math:`r_{u i}` the actual score of the test set.
+    def __init__(self, config):
+        super().__init__(config)
 
+    def calculate_metric(self, dataobject):
+        return self.output_metric('mae', dataobject)
+
+    def metric_info(self, preds, trues):
+        return mean_absolute_error(trues, preds)
+
+
+class RMSE(LossMetric):
+    r"""RMSE_ (also known as Root Mean Squared Error) is another error metric like `MAE`.
+
+    .. _RMSE: https://en.wikipedia.org/wiki/Root-mean-square_deviation
+
+    .. math::
+       \mathrm{RMSE} = \sqrt{\frac{1}{|{S}|} \sum_{(u, i) \in {S}}(\hat{r}_{u i}-r_{u i})^{2}}
     """
-    return mean_absolute_error(trues, preds)
+    smaller = True
 
+    def __init__(self, config):
+        super().__init__(config)
 
-def rmse_(trues, preds):
-    r"""`Mean std error regression loss`__
+    def calculate_metric(self, dataobject):
+        return self.output_metric('rmse', dataobject)
 
-    .. __: https://en.wikipedia.org/wiki/Root-mean-square_deviation
+    def metric_info(self, preds, trues):
+        return np.sqrt(mean_squared_error(trues, preds))
+
+
+class LogLoss(LossMetric):
+    r"""Logloss_ (also known as logistic loss or cross-entropy loss) is used to evaluate the probabilistic
+    output of the two-class classifier.
+
+    .. _Logloss: http://wiki.fast.ai/index.php/Log_Loss
 
     .. math::
-        \mathrm{RMSE} = \sqrt{\frac{1}{|{T}|} \sum_{(u, i) \in {T}}(\hat{r}_{u i}-r_{u i})^{2}}
+        LogLoss = \frac{1}{|S|} \sum_{(u,i) \in S}(-((r_{u i} \ \log{\hat{r}_{u i}}) + {(1 - r_{u i})}\ \log{(1 - \hat{r}_{u i})}))
+    """
+    smaller = True
+
+    def __init__(self, config):
+        super().__init__(config)
 
-    :math:`T` is the test set, :math:`\hat{r}_{u i}` is the score predicted by the model,
-    and :math:`r_{u i}` the actual score of the test set.
+    def calculate_metric(self, dataobject):
+        return self.output_metric('logloss', dataobject)
 
+    def metric_info(self, preds, trues):
+        eps = 1e-15
+        preds = np.float64(preds)
+        preds = np.clip(preds, eps, 1 - eps)
+        loss = np.sum(-trues * np.log(preds) - (1 - trues) * np.log(1 - preds))
+        return loss / len(preds)
+
+
+class ItemCoverage(AbstractMetric):
+    r"""ItemCoverage_ computes the coverage of recommended items over all items.
+
+    .. _ItemCoverage: https://en.wikipedia.org/wiki/Coverage_(information_systems)
+
+    For further details, please refer to the `paper <https://dl.acm.org/doi/10.1145/1864708.1864761>`__
+    and `paper <https://link.springer.com/article/10.1007/s13042-017-0762-9>`__.
+
+    .. math::
+       \mathrm{Coverage@K}=\frac{\left| \bigcup_{u \in U} \hat{R}(u) \right|}{|I|}
     """
-    return np.sqrt(mean_squared_error(trues, preds))
+    metric_type = EvaluatorType.RANKING
+    metric_need = ['rec.items', 'data.num_items']
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
+
+    def used_info(self, dataobject):
+        """Get the matrix of recommendation items and number of items in total item set"""
+        item_matrix = dataobject.get('rec.items')
+        num_items = dataobject.get('data.num_items')
+        return item_matrix.numpy(), num_items
+
+    def calculate_metric(self, dataobject):
+        item_matrix, num_items = self.used_info(dataobject)
+        metric_dict = {}
+        for k in self.topk:
+            key = '{}@{}'.format('itemcoverage', k)
+            metric_dict[key] = round(self.get_coverage(item_matrix[:, :k], num_items), self.decimal_place)
+        return metric_dict
+
+    def get_coverage(self, item_matrix, num_items):
+        """Get the coverage of recommended items over all items
 
+        Args:
+            item_matrix(numpy.ndarray): matrix of items recommended to users.
+            num_items(int): the total number of items.
 
-def log_loss_(trues, preds):
-    r"""`Log loss`__, aka logistic loss or cross-entropy loss
+        Returns:
+            float: the `coverage` metric.
+        """
+        unique_count = np.unique(item_matrix).shape[0]
+        return unique_count / num_items
 
-    .. __: http://wiki.fast.ai/index.php/Log_Loss
+
+class AveragePopularity(AbstractMetric):
+    r"""AveragePopularity computes the average popularity of recommended items.
+
+    For further details, please refer to the `paper <https://arxiv.org/abs/1205.6700>`__
+    and `paper <https://link.springer.com/article/10.1007/s13042-017-0762-9>`__.
 
     .. math::
-        -\log {P(y_t|y_p)} = -(({y_t}\ \log{y_p}) + {(1-y_t)}\ \log{(1 - y_p)})
+        \mathrm{AveragePopularity@K}=\frac{1}{|U|} \sum_{u \in U } \frac{\sum_{i \in R_{u}} \phi(i)}{|R_{u}|}
 
-    For a single sample, :math:`y_t` is true label in :math:`\{0,1\}`.
-    :math:`y_p` is the estimated probability that :math:`y_t = 1`.
+    :math:`\phi(i)` is the number of interaction of item i in training data.
+    """
+    metric_type = EvaluatorType.RANKING
+    smaller = True
+    metric_need = ['rec.items', 'data.count_items']
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
+
+    def used_info(self, dataobject):
+        """Get the matrix of recommendation items and the popularity of items in training data"""
+        item_counter = dataobject.get('data.count_items')
+        item_matrix = dataobject.get('rec.items')
+        return item_matrix.numpy(), dict(item_counter)
+
+    def calculate_metric(self, dataobject):
+        item_matrix, item_count = self.used_info(dataobject)
+        result = self.metric_info(self.get_pop(item_matrix, item_count))
+        metric_dict = self.topk_result('averagepopularity', result)
+        return metric_dict
+
+    def get_pop(self, item_matrix, item_count):
+        """Convert the matrix of item id to the matrix of item popularity using a dict:{id,count}.
+
+        Args:
+            item_matrix(numpy.ndarray): matrix of items recommended to users.
+            item_count(dict): the number of interaction of items in training data.
+
+        Returns:
+            numpy.ndarray: the popularity of items in the recommended list.
+        """
+        value = np.zeros_like(item_matrix)
+        for i in range(item_matrix.shape[0]):
+            row = item_matrix[i, :]
+            for j in range(row.shape[0]):
+                value[i][j] = item_count.get(row[j], 0)
+        return value
+
+    def metric_info(self, values):
+        return values.cumsum(axis=1) / np.arange(1, values.shape[1] + 1)
+
+    def topk_result(self, metric, value):
+        """Match the metric value to the `k` and put them in `dictionary` form
+
+        Args:
+            metric(str): the name of calculated metric.
+            value(numpy.ndarray): metrics for each user, including values from `metric@1` to `metric@max(self.topk)`.
+
+        Returns:
+            dict: metric values required in the configuration.
+        """
+        metric_dict = {}
+        avg_result = value.mean(axis=0)
+        for k in self.topk:
+            key = '{}@{}'.format(metric, k)
+            metric_dict[key] = round(avg_result[k - 1], self.decimal_place)
+        return metric_dict
+
+
+class ShannonEntropy(AbstractMetric):
+    r"""ShannonEntropy_ presents the diversity of the recommendation items.
+    It is the entropy over items' distribution.
+
+    .. _ShannonEntropy: https://en.wikipedia.org/wiki/Entropy_(information_theory)
+
+    For further details, please refer to the `paper <https://arxiv.org/abs/1205.6700>`__
+    and `paper <https://link.springer.com/article/10.1007/s13042-017-0762-9>`__
+
+    .. math::
+        \mathrm {ShannonEntropy@K}=-\sum_{i=1}^{|I|} p(i) \log p(i)
 
+    :math:`p(i)` is the probability of recommending item i
+    which is the number of item i in recommended list over all items.
     """
-    eps = 1e-15
-    preds = np.float64(preds)
-    preds = np.clip(preds, eps, 1 - eps)
-    loss = np.sum(-trues * np.log(preds) - (1 - trues) * np.log(1 - preds))
+    metric_type = EvaluatorType.RANKING
+    metric_need = ['rec.items']
 
-    return loss / len(preds)
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
 
+    def used_info(self, dataobject):
+        """Get the matrix of recommendation items.
+        """
+        item_matrix = dataobject.get('rec.items')
+        return item_matrix.numpy()
 
-# Item based Metrics #
+    def calculate_metric(self, dataobject):
+        item_matrix = self.used_info(dataobject)
+        metric_dict = {}
+        for k in self.topk:
+            key = '{}@{}'.format('shannonentropy', k)
+            metric_dict[key] = round(self.get_entropy(item_matrix[:, :k]), self.decimal_place)
+        return metric_dict
 
-# TODO
-# def coverage_():
-#     raise NotImplementedError
+    def get_entropy(self, item_matrix):
+        """Get shannon entropy through the top-k recommendation list.
 
-# def gini_index_():
-#     raise NotImplementedError
+        Args:
+            item_matrix(numpy.ndarray): matrix of items recommended to users.
 
-# def shannon_entropy_():
-#     raise NotImplementedError
+        Returns:
+            float: the shannon entropy.
+        """
 
-# def diversity_():
-#     raise NotImplementedError
+        item_count = dict(Counter(item_matrix.flatten()))
+        total_num = item_matrix.shape[0] * item_matrix.shape[1]
+        result = 0.0
+        for cnt in item_count.values():
+            p = cnt / total_num
+            result += -p * np.log(p)
+        return result / len(item_count)
 
-"""Function name and function mapper.
-Useful when we have to serialize evaluation metric names
-and call the functions based on deserialized names
-"""
-metrics_dict = {
-    'ndcg': ndcg_,
-    'hit': hit_,
-    'precision': precision_,
-    'map': map_,
-    'recall': recall_,
-    'mrr': mrr_,
-    'rmse': rmse_,
-    'mae': mae_,
-    'logloss': log_loss_,
-    'auc': auc_,
-    'gauc': gauc_
-}
+
+class GiniIndex(AbstractMetric):
+    r"""GiniIndex presents the diversity of the recommendation items.
+    It is used to measure the inequality of a distribution.
+
+    .. _GiniIndex: https://en.wikipedia.org/wiki/Gini_coefficient
+
+    For further details, please refer to the `paper <https://dl.acm.org/doi/10.1145/3308560.3317303>`__.
+
+    .. math::
+        \mathrm {GiniIndex@K}=\left(\frac{\sum_{i=1}^{|I|}(2 i-|I|-1) P{(i)}}{|I| \sum_{i=1}^{|I|} P{(i)}}\right)
+
+    :math:`P{(i)}` represents the number of times all items appearing in the recommended list,
+    which is indexed in non-decreasing order (P_{(i)} \leq P_{(i+1)}).
+    """
+    metric_type = EvaluatorType.RANKING
+    smaller = True
+    metric_need = ['rec.items', 'data.num_items']
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
+
+    def used_info(self, dataobject):
+        """Get the matrix of recommendation items and number of items in total item set"""
+        item_matrix = dataobject.get('rec.items')
+        num_items = dataobject.get('data.num_items')
+        return item_matrix.numpy(), num_items
+
+    def calculate_metric(self, dataobject):
+        item_matrix, num_items = self.used_info(dataobject)
+        metric_dict = {}
+        for k in self.topk:
+            key = '{}@{}'.format('giniindex', k)
+            metric_dict[key] = round(self.get_gini(item_matrix[:, :k], num_items), self.decimal_place)
+        return metric_dict
+
+    def get_gini(self, item_matrix, num_items):
+        """Get gini index through the top-k recommendation list.
+
+        Args:
+            item_matrix(numpy.ndarray): matrix of items recommended to users.
+            num_items(int): the total number of items.
+
+        Returns:
+            float: the gini index.
+        """
+        item_count = dict(Counter(item_matrix.flatten()))
+        sorted_count = np.array(sorted(item_count.values()))
+        num_recommended_items = sorted_count.shape[0]
+        total_num = item_matrix.shape[0] * item_matrix.shape[1]
+        idx = np.arange(num_items - num_recommended_items + 1, num_items + 1)
+        gini_index = np.sum((2 * idx - num_items - 1) * sorted_count) / total_num
+        gini_index /= num_items
+        return gini_index
+
+
+class TailPercentage(AbstractMetric):
+    r"""TailPercentage_ computes the percentage of long-tail items in recommendation items.
+
+    .. _TailPercentage: https://en.wikipedia.org/wiki/Long_tail#Criticisms
+
+    For further details, please refer to the `paper <https://arxiv.org/pdf/2007.12329.pdf>`__.
+
+    .. math::
+        \mathrm {TailPercentage@K}=\frac{1}{|U|} \sum_{u \in U} \frac{\sum_{i \in R_{u}} {\delta(i \in T)}}{|R_{u}|}
+
+    :math:`\delta(·)` is an indicator function.
+    :math:`T` is the set of long-tail items,
+    which is a portion of items that appear in training data seldomly.
+
+    Note:
+        If you want to use this metric, please set the parameter 'tail_ratio' in the config
+        which can be an integer or a float in (0,1]. Otherwise it will default to 0.1.
+    """
+    metric_type = EvaluatorType.RANKING
+    metric_need = ['rec.items', 'data.count_items']
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.topk = config['topk']
+        self.tail = config['tail_ratio']
+        if self.tail is None or self.tail <= 0:
+            self.tail = 0.1
+
+    def used_info(self, dataobject):
+        """Get the matrix of recommendation items and number of items in total item set."""
+        item_matrix = dataobject.get('rec.items')
+        count_items = dataobject.get('data.count_items')
+        return item_matrix.numpy(), dict(count_items)
+
+    def get_tail(self, item_matrix, count_items):
+        """Get long-tail percentage through the top-k recommendation list.
+
+        Args:
+            item_matrix(numpy.ndarray): matrix of items recommended to users.
+            count_items(dict): the number of interaction of items in training data.
+
+        Returns:
+            float: long-tail percentage.
+        """
+        if self.tail > 1:
+            tail_items = [item for item, cnt in count_items.items() if cnt <= self.tail]
+        else:
+            count_items = sorted(count_items.items(), key=lambda kv: (kv[1], kv[0]))
+            cut = max(int(len(count_items) * self.tail), 1)
+            count_items = count_items[:cut]
+            tail_items = [item for item, cnt in count_items]
+        value = np.zeros_like(item_matrix)
+        for i in range(item_matrix.shape[0]):
+            row = item_matrix[i, :]
+            for j in range(row.shape[0]):
+                value[i][j] = 1 if row[j] in tail_items else 0
+        return value
+
+    def calculate_metric(self, dataobject):
+        item_matrix, count_items = self.used_info(dataobject)
+        result = self.metric_info(self.get_tail(item_matrix, count_items))
+        metric_dict = self.topk_result('tailpercentage', result)
+        return metric_dict
+
+    def metric_info(self, values):
+        return values.cumsum(axis=1) / np.arange(1, values.shape[1] + 1)
+
+    def topk_result(self, metric, value):
+        """Match the metric value to the `k` and put them in `dictionary` form.
+
+        Args:
+            metric(str): the name of calculated metric.
+            value(numpy.ndarray): metrics for each user, including values from `metric@1` to `metric@max(self.topk)`.
+
+        Returns:
+            dict: metric values required in the configuration.
+        """
+        metric_dict = {}
+        avg_result = value.mean(axis=0)
+        for k in self.topk:
+            key = '{}@{}'.format(metric, k)
+            metric_dict[key] = round(avg_result[k - 1], self.decimal_place)
+        return metric_dict
diff --git a/recbole/evaluator/proxy_evaluator.py b/recbole/evaluator/proxy_evaluator.py
deleted file mode 100644
index a0df5246e..000000000
--- a/recbole/evaluator/proxy_evaluator.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- encoding: utf-8 -*-
-# @Time    :   2020/12/9
-# @Author  :   Zhichao Feng
-# @email   :   fzcbupt@gmail.com
-
-# UPDATE
-# @Time    :   2020/12/9
-# @Author  :   Zhichao Feng
-# @email   :   fzcbupt@gmail.com
-
-"""
-recbole.evaluator.proxy_evaluator
-#####################################
-"""
-
-from collections import ChainMap
-
-from recbole.evaluator.evaluators import metric_eval_bind, group_metrics, individual_metrics
-
-
-class ProxyEvaluator(object):
-    r"""ProxyEvaluator is used to assign the corresponding evaluator according to the evaluation metrics,
-    for example, TopkEvaluator for top-k metrics, and summarize the results of all evaluators.
-
-   """
-
-    def __init__(self, config):
-        self.config = config
-        self.valid_metrics = ChainMap(group_metrics, individual_metrics)
-        self.metrics = self.config['metrics']
-        self._check_args()
-        self.evaluators = self.build()
-
-    def build(self):
-        """assign evaluators according to metrics.
-
-        Returns:
-            list: a list of evaluators.
-
-        """
-        evaluator_list = []
-        metrics_list = [metric.lower() for metric in self.metrics]
-        for metrics, evaluator in metric_eval_bind:
-            used_metrics = [metric for metric in metrics_list if metric in metrics]
-            if used_metrics:
-                evaluator_list.append(evaluator(self.config, used_metrics))
-        return evaluator_list
-
-    def collect(self, interaction, scores):
-        """collect the all used evaluators' intermediate result of one batch.
-
-        Args:
-            interaction (Interaction): :class:`AbstractEvaluator` of the batch
-            scores (tensor): the tensor of model output with size of `(N, )`
-
-        """
-        results = []
-        for evaluator in self.evaluators:
-            results.append(evaluator.collect(interaction, scores))
-        return results
-
-    def merge_batch_result(self, batch_matrix_list):
-        """merge all the intermediate result got in `self.collect` for used evaluators separately.
-
-        Args:
-            batch_matrix_list (list): the results of all batches not separated
-
-        Returns:
-            dict: used evaluators' results of all batches
-
-        """
-        matrix_dict = {}
-        for collect_list in batch_matrix_list:
-            for i, value in enumerate(collect_list):
-                matrix_dict.setdefault(i, []).append(value)
-
-        return matrix_dict
-
-    def evaluate(self, batch_matrix_list, eval_data):
-        """calculate the metrics of all batches. It is called at the end of each epoch
-
-        Args:
-            batch_matrix_list (list): the results of all batches
-            eval_data (Dataset): the class of test data
-
-        Returns:
-            dict: such as ``{'Hit@20': 0.3824, 'Recall@20': 0.0527, 'Hit@10': 0.3153, 'GAUC': 0.9236}``
-
-        """
-        matrix_dict = self.merge_batch_result(batch_matrix_list)
-        result_dict = {}
-        for i, evaluator in enumerate(self.evaluators):
-            res = evaluator.evaluate(matrix_dict[i], eval_data)
-            result_dict.update(res)
-        return result_dict
-
-    def _check_args(self):
-
-        # Check metrics
-        if isinstance(self.metrics, (str, list)):
-            if isinstance(self.metrics, str):
-                self.metrics = [self.metrics]
-        else:
-            raise TypeError('metrics must be str or list')
-
-        # Convert metric to lowercase
-        for m in self.metrics:
-            if m.lower() not in self.valid_metrics:
-                raise ValueError("There is no metric named {}!".format(m))
diff --git a/recbole/evaluator/register.py b/recbole/evaluator/register.py
new file mode 100644
index 000000000..fbf041878
--- /dev/null
+++ b/recbole/evaluator/register.py
@@ -0,0 +1,92 @@
+# @Time   : 2021/6/23
+# @Author : Zihan Lin
+# @Email  : zhlin@ruc.edu.cn
+
+# UPDATE
+# @Time   : 2021/8/29
+# @Author : Zhichao Feng
+# @email  : fzcbupt@gmail.com
+
+"""
+recbole.evaluator.register
+################################################
+"""
+import inspect
+import sys
+
+
+def cluster_info(module_name):
+    """Collect information of all metrics, including:
+
+        - ``metric_need``: Information needed to calculate this metric, the combination of ``rec.items, rec.topk,
+          rec.meanrank, rec.score, data.num_items, data.num_users, data.count_items, data.count_users, data.label``.
+        - ``metric_type``: Whether the scores required by metric are grouped by user, range in ``EvaluatorType.RANKING``
+          and ``EvaluatorType.VALUE``.
+        - ``smaller``: Whether the smaller metric value represents better performance,
+          range in ``True`` and ``False``, default to ``False``.
+
+    Note:
+        For ``metric_type``: in current RecBole, all the "grouped-score" metrics are ranking-based and all the
+        "non-grouped-score" metrics are value-based. To keep with our paper, we adopted the more formal terms:
+        ``RANKING`` and ``VALUE``.
+
+    Args:
+        module_name (str): the name of module ``recbole.evaluator.metrics``.
+
+    Returns:
+        dict: Three dictionaries containing the above information
+        and a dictionary matching metric names to metric classes.
+    """
+    smaller_m = []
+    m_dict, m_info, m_types = {}, {}, {}
+    metric_class = inspect.getmembers(
+        sys.modules[module_name], lambda x: inspect.isclass(x) and x.__module__ == module_name
+    )
+    for name, metric_cls in metric_class:
+        name = name.lower()
+        m_dict[name] = metric_cls
+        if hasattr(metric_cls, 'metric_need'):
+            m_info[name] = metric_cls.metric_need
+        else:
+            raise AttributeError(f"Metric '{name}' has no attribute [metric_need].")
+        if hasattr(metric_cls, 'metric_type'):
+            m_types[name] = metric_cls.metric_type
+        else:
+            raise AttributeError(f"Metric '{name}' has no attribute [metric_type].")
+        if metric_cls.smaller is True:
+            smaller_m.append(name)
+    return smaller_m, m_info, m_types, m_dict
+
+
+metric_module_name = 'recbole.evaluator.metrics'
+smaller_metrics, metric_information, metric_types, metrics_dict = cluster_info(metric_module_name)
+
+
+class Register(object):
+    """ Register module load the registry according to the metrics in config.
+        It is a member of DataCollector.
+        The DataCollector collect the resource that need for Evaluator under the guidance of Register
+    """
+
+    def __init__(self, config):
+
+        self.config = config
+        self.metrics = [metric.lower() for metric in self.config['metrics']]
+        self._build_register()
+
+    def _build_register(self):
+        for metric in self.metrics:
+            metric_needs = metric_information[metric]
+            for info in metric_needs:
+                setattr(self, info, True)
+
+    def has_metric(self, metric: str):
+        if metric.lower() in self.metrics:
+            return True
+        else:
+            return False
+
+    def need(self, key: str):
+        if hasattr(self, key):
+            return getattr(self, key)
+        return False
diff --git a/recbole/model/abstract_recommender.py b/recbole/model/abstract_recommender.py
index d9a4d7be8..2aaae77a6 100644
--- a/recbole/model/abstract_recommender.py
+++ b/recbole/model/abstract_recommender.py
@@ -19,8 +19,7 @@
 import torch.nn as nn
 
 from recbole.model.layers import FMEmbedding, FMFirstOrderLinear
-from recbole.utils import ModelType, InputType, FeatureSource, FeatureType
-from recbole.utils.utils import set_color
+from recbole.utils import ModelType, InputType, FeatureSource, FeatureType, set_color
 
 
 class AbstractRecommender(nn.Module):
@@ -66,6 +65,17 @@ def full_sort_predict(self, interaction):
         """
         raise NotImplementedError
 
+    def other_parameter(self):
+        if hasattr(self, 'other_parameter_name'):
+            return {key: getattr(self, key) for key in self.other_parameter_name}
+        return dict()
+
+    def load_other_parameter(self, para):
+        if para is None:
+            return
+        for key, value in para.items():
+            setattr(self, key, value)
+
     def __str__(self):
         """
         Model prints with number of trainable parameters
@@ -159,7 +169,15 @@ class ContextRecommender(AbstractRecommender):
     def __init__(self, config, dataset):
         super(ContextRecommender, self).__init__()
 
-        self.field_names = dataset.fields()
+        self.field_names = dataset.fields(
+            source=[
+                FeatureSource.INTERACTION,
+                FeatureSource.USER,
+                FeatureSource.USER_ID,
+                FeatureSource.ITEM,
+                FeatureSource.ITEM_ID,
+            ]
+        )
         self.LABEL = config['LABEL_FIELD']
         self.embedding_size = config['embedding_size']
         self.device = config['device']
@@ -175,13 +193,8 @@ def __init__(self, config, dataset):
         self.num_feature_field = 0
 
         if self.double_tower:
-            self.user_field_names = []
-            self.item_field_names = []
-            for field_name in self.field_names:
-                if dataset.dataset.field2source[field_name] in {FeatureSource.USER, FeatureSource.USER_ID}:
-                    self.user_field_names.append(field_name)
-                elif dataset.dataset.field2source[field_name] in {FeatureSource.ITEM, FeatureSource.ITEM_ID}:
-                    self.item_field_names.append(field_name)
+            self.user_field_names = dataset.fields(source=[FeatureSource.USER, FeatureSource.USER_ID])
+            self.item_field_names = dataset.fields(source=[FeatureSource.ITEM, FeatureSource.ITEM_ID])
             self.field_names = self.user_field_names + self.item_field_names
             self.user_token_field_num = 0
             self.user_float_field_num = 0
@@ -238,7 +251,7 @@ def embed_float_fields(self, float_fields, embed=True):
 
         Args:
             float_fields (torch.FloatTensor): The input dense tensor. shape of [batch_size, num_float_field]
-            embed (bool): Return the embedding of columns or just the columns itself. default=True
+            embed (bool): Return the embedding of columns or just the columns itself. Defaults to ``True``.
 
         Returns:
             torch.FloatTensor: The result embedding tensor of float columns.
diff --git a/recbole/model/context_aware_recommender/xdeepfm.py b/recbole/model/context_aware_recommender/xdeepfm.py
index 0af6ef770..0e5085788 100644
--- a/recbole/model/context_aware_recommender/xdeepfm.py
+++ b/recbole/model/context_aware_recommender/xdeepfm.py
@@ -54,7 +54,7 @@ def __init__(self, config, dataset):
                 )
 
         # Create a convolutional layer for each CIN layer
-        self.conv1d_list = []
+        self.conv1d_list = nn.ModuleList()
         self.field_nums = [self.num_feature_field]
         for i, layer_size in enumerate(self.cin_layer_size):
             conv1d = nn.Conv1d(self.field_nums[-1] * self.field_nums[0], layer_size, 1).to(self.device)
@@ -74,13 +74,13 @@ def __init__(self, config, dataset):
         else:
             self.final_len = sum(self.cin_layer_size[:-1]) // 2 + self.cin_layer_size[-1]
 
-        self.cin_linear = nn.Linear(self.final_len, 1, bias=False)
+        self.cin_linear = nn.Linear(self.final_len, 1)
         self.sigmoid = nn.Sigmoid()
         self.loss = nn.BCELoss()
         self.apply(self._init_weights)
 
     def _init_weights(self, module):
-        if isinstance(module, nn.Embedding):
+        if isinstance(module, nn.Embedding) or isinstance(module, nn.Conv1d):
             xavier_normal_(module.weight.data)
         elif isinstance(module, nn.Linear):
             xavier_normal_(module.weight.data)
@@ -113,7 +113,7 @@ def calculate_reg_loss(self):
             l2_reg += self.reg_loss(conv1d.named_parameters())
         return l2_reg
 
-    def compressed_interaction_network(self, input_features, activation='identity'):
+    def compressed_interaction_network(self, input_features, activation='ReLU'):
         r"""For k-th CIN layer, the output :math:`X_k` is calculated via
 
         .. math::
@@ -137,7 +137,7 @@ def compressed_interaction_network(self, input_features, activation='identity'):
         hidden_nn_layers = [input_features]
         final_result = []
         for i, layer_size in enumerate(self.cin_layer_size):
-            z_i = torch.einsum('bmd,bhd->bhmd', hidden_nn_layers[0], hidden_nn_layers[-1])
+            z_i = torch.einsum('bhd,bmd->bhmd', hidden_nn_layers[-1], hidden_nn_layers[0])
             z_i = z_i.view(batch_size, self.field_nums[0] * self.field_nums[i], embedding_size)
             z_i = self.conv1d_list[i](z_i)
 
diff --git a/recbole/model/general_recommender/dgcf.py b/recbole/model/general_recommender/dgcf.py
index 3560dd2b9..b6399bb57 100644
--- a/recbole/model/general_recommender/dgcf.py
+++ b/recbole/model/general_recommender/dgcf.py
@@ -74,7 +74,7 @@ def __init__(self, config, dataset):
         self.n_layers = config['n_layers']
         self.reg_weight = config['reg_weight']
         self.cor_weight = config['cor_weight']
-        n_batch = dataset.dataset.inter_num // config['train_batch_size'] + 1
+        n_batch = dataset.inter_num // config['train_batch_size'] + 1
         self.cor_batch_size = int(max(self.n_users / n_batch, self.n_items / n_batch))
         # ensure embedding can be divided into <n_factors> intent
         assert self.embedding_size % self.n_factors == 0
@@ -109,6 +109,7 @@ def __init__(self, config, dataset):
         self.restore_user_e = None
         self.restore_item_e = None
 
+        self.other_parameter_name = ['restore_user_e', 'restore_item_e']
         # parameters initialization
         self.apply(xavier_normal_initialization)
 
diff --git a/recbole/model/general_recommender/dmf.py b/recbole/model/general_recommender/dmf.py
index 7c0fbe57d..c74836d01 100644
--- a/recbole/model/general_recommender/dmf.py
+++ b/recbole/model/general_recommender/dmf.py
@@ -86,6 +86,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(self._init_weights)
+        self.other_parameter_name = ['i_embedding']
 
     def _init_weights(self, module):
         # We just initialize the module with normal distribution as the paper said
diff --git a/recbole/model/general_recommender/ease.py b/recbole/model/general_recommender/ease.py
index 30e14b79a..d5c6d17eb 100644
--- a/recbole/model/general_recommender/ease.py
+++ b/recbole/model/general_recommender/ease.py
@@ -61,6 +61,7 @@ def __init__(self, config, dataset):
         # so will do everything with np/scipy
         self.item_similarity = B
         self.interaction_matrix = X
+        self.other_parameter_name = ['interaction_matrix', 'item_similarity']
 
     def forward(self):
         pass
diff --git a/recbole/model/general_recommender/enmf.py b/recbole/model/general_recommender/enmf.py
index e06d91404..49e579a34 100644
--- a/recbole/model/general_recommender/enmf.py
+++ b/recbole/model/general_recommender/enmf.py
@@ -22,7 +22,7 @@
 
 class ENMF(GeneralRecommender):
     r"""ENMF is an efficient non-sampling model for general recommendation.
-    In order to run non-sampling model, please set the training_neg_sample_num parameter as 0 .
+    In order to run non-sampling model, please set the neg_sampling parameter as None .
 
     """
 
diff --git a/recbole/model/general_recommender/itemknn.py b/recbole/model/general_recommender/itemknn.py
index d1d84d4f9..1852512c6 100644
--- a/recbole/model/general_recommender/itemknn.py
+++ b/recbole/model/general_recommender/itemknn.py
@@ -176,6 +176,7 @@ def __init__(self, config, dataset):
         self.pred_mat = self.interaction_matrix.dot(self.w).tolil()
 
         self.fake_loss = torch.nn.Parameter(torch.zeros(1))
+        self.other_parameter_name = ['w', 'pred_mat']
 
     def forward(self, user, item):
         pass
diff --git a/recbole/model/general_recommender/lightgcn.py b/recbole/model/general_recommender/lightgcn.py
index b57c9b1d2..c0f77b5ed 100644
--- a/recbole/model/general_recommender/lightgcn.py
+++ b/recbole/model/general_recommender/lightgcn.py
@@ -67,6 +67,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_uniform_initialization)
+        self.other_parameter_name = ['restore_user_e', 'restore_item_e']
 
     def get_norm_adj_mat(self):
         r"""Get the normalized interaction matrix of users and items.
diff --git a/recbole/model/general_recommender/line.py b/recbole/model/general_recommender/line.py
index 9a7fbf9f3..ef08cbfbc 100644
--- a/recbole/model/general_recommender/line.py
+++ b/recbole/model/general_recommender/line.py
@@ -46,9 +46,8 @@ def __init__(self, config, dataset):
         self.embedding_size = config['embedding_size']
         self.order = config['order']
         self.second_order_loss_weight = config['second_order_loss_weight']
-        self.training_neg_sample_num = config['training_neg_sample_num']
 
-        self.interaction_feat = dataset.dataset.inter_feat
+        self.interaction_feat = dataset.inter_feat
 
         self.user_embedding = nn.Embedding(self.n_users, self.embedding_size)
         self.item_embedding = nn.Embedding(self.n_items, self.embedding_size)
diff --git a/recbole/model/general_recommender/macridvae.py b/recbole/model/general_recommender/macridvae.py
index eadc8a359..f57fa0812 100644
--- a/recbole/model/general_recommender/macridvae.py
+++ b/recbole/model/general_recommender/macridvae.py
@@ -4,7 +4,7 @@
 # @Email  : gyihong@hotmail.com
 
 # UPDATE
-# @Time    : 2021/6/30, 
+# @Time    : 2021/6/30,
 # @Author  : Xingyu Pan
 # @email   : xy_pan@foxmail.com
 
diff --git a/recbole/model/general_recommender/ngcf.py b/recbole/model/general_recommender/ngcf.py
index 8352aec53..cb82d87da 100644
--- a/recbole/model/general_recommender/ngcf.py
+++ b/recbole/model/general_recommender/ngcf.py
@@ -72,6 +72,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['restore_user_e', 'restore_item_e']
 
     def get_norm_adj_mat(self):
         r"""Get the normalized interaction matrix of users and items.
diff --git a/recbole/model/general_recommender/pop.py b/recbole/model/general_recommender/pop.py
index 6a0cc261e..464c85976 100644
--- a/recbole/model/general_recommender/pop.py
+++ b/recbole/model/general_recommender/pop.py
@@ -32,6 +32,7 @@ def __init__(self, config, dataset):
         self.item_cnt = torch.zeros(self.n_items, 1, dtype=torch.long, device=self.device, requires_grad=False)
         self.max_cnt = None
         self.fake_loss = torch.nn.Parameter(torch.zeros(1))
+        self.other_parameter_name = ['item_cnt', 'max_cnt']
 
     def forward(self):
         pass
diff --git a/recbole/model/general_recommender/slimelastic.py b/recbole/model/general_recommender/slimelastic.py
index 9139bfb3e..f28b14fca 100644
--- a/recbole/model/general_recommender/slimelastic.py
+++ b/recbole/model/general_recommender/slimelastic.py
@@ -83,6 +83,7 @@ def __init__(self, config, dataset):
                     X[:, j] = r
 
         self.item_similarity = sp.vstack(item_coeffs).T
+        self.other_parameter_name = ['interaction_matrix', 'item_similarity']
 
     def forward(self):
         pass
diff --git a/recbole/model/general_recommender/spectralcf.py b/recbole/model/general_recommender/spectralcf.py
index 83e17e076..a3333de63 100644
--- a/recbole/model/general_recommender/spectralcf.py
+++ b/recbole/model/general_recommender/spectralcf.py
@@ -80,6 +80,7 @@ def __init__(self, config, dataset):
         self.restore_user_e = None
         self.restore_item_e = None
 
+        self.other_parameter_name = ['restore_user_e', 'restore_item_e']
         # parameters initialization
         self.apply(xavier_uniform_initialization)
 
diff --git a/recbole/model/knowledge_aware_recommender/kgat.py b/recbole/model/knowledge_aware_recommender/kgat.py
index 02f4571d6..1505a2883 100644
--- a/recbole/model/knowledge_aware_recommender/kgat.py
+++ b/recbole/model/knowledge_aware_recommender/kgat.py
@@ -116,6 +116,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['restore_user_e', 'restore_entity_e']
 
     def init_graph(self):
         r"""Get the initial attention matrix through the collaborative knowledge graph
diff --git a/recbole/model/knowledge_aware_recommender/kgcn.py b/recbole/model/knowledge_aware_recommender/kgcn.py
index b8e76b025..7711ea376 100644
--- a/recbole/model/knowledge_aware_recommender/kgcn.py
+++ b/recbole/model/knowledge_aware_recommender/kgcn.py
@@ -72,6 +72,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['adj_entity', 'adj_relation']
 
     def construct_adj(self, kg_graph):
         r"""Get neighbors and corresponding relations for each entity in the KG.
diff --git a/recbole/model/knowledge_aware_recommender/kgnnls.py b/recbole/model/knowledge_aware_recommender/kgnnls.py
index 0e262a8cf..6778e23c0 100644
--- a/recbole/model/knowledge_aware_recommender/kgnnls.py
+++ b/recbole/model/knowledge_aware_recommender/kgnnls.py
@@ -60,9 +60,9 @@ def __init__(self, config, dataset):
         adj_entity, adj_relation = self.construct_adj(kg_graph)
         self.adj_entity, self.adj_relation = adj_entity.to(self.device), adj_relation.to(self.device)
 
-        inter_feat = dataset.dataset.inter_feat
-        pos_users = inter_feat[dataset.dataset.uid_field]
-        pos_items = inter_feat[dataset.dataset.iid_field]
+        inter_feat = dataset.inter_feat
+        pos_users = inter_feat[dataset.uid_field]
+        pos_items = inter_feat[dataset.iid_field]
         pos_label = torch.ones(pos_items.shape)
         pos_interaction_table, self.offset = self.get_interaction_table(pos_users, pos_items, pos_label)
         self.interaction_table = self.sample_neg_interaction(pos_interaction_table, self.offset)
@@ -85,6 +85,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['adj_entity', 'adj_relation']
 
     def get_interaction_table(self, user_id, item_id, y):
         r"""Get interaction_table that is used for fetching user-item interaction label in LS regularization.
diff --git a/recbole/model/knowledge_aware_recommender/ripplenet.py b/recbole/model/knowledge_aware_recommender/ripplenet.py
index 899d74bbc..0b531d0b8 100644
--- a/recbole/model/knowledge_aware_recommender/ripplenet.py
+++ b/recbole/model/knowledge_aware_recommender/ripplenet.py
@@ -45,9 +45,9 @@ def __init__(self, config, dataset):
         self.n_hop = config['n_hop']
         self.n_memory = config['n_memory']
         self.interaction_matrix = dataset.inter_matrix(form='coo').astype(np.float32)
-        head_entities = dataset.dataset.head_entities.tolist()
-        tail_entities = dataset.dataset.tail_entities.tolist()
-        relations = dataset.dataset.relations.tolist()
+        head_entities = dataset.head_entities.tolist()
+        tail_entities = dataset.tail_entities.tolist()
+        relations = dataset.relations.tolist()
         kg = {}
         for i in range(len(head_entities)):
             head_ent = head_entities[i]
@@ -79,6 +79,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['ripple_set']
 
     def _build_ripple_set(self):
         r"""Get the normalized interaction matrix of users and items according to A_values.
diff --git a/recbole/model/layers.py b/recbole/model/layers.py
index 3edb31568..c09fb6758 100644
--- a/recbole/model/layers.py
+++ b/recbole/model/layers.py
@@ -24,7 +24,7 @@
 import torch.nn.functional as fn
 from torch.nn.init import normal_
 
-from recbole.utils import FeatureType
+from recbole.utils import FeatureType, FeatureSource
 
 
 class MLPLayers(nn.Module):
@@ -556,15 +556,23 @@ class ContextSeqEmbAbstractLayer(nn.Module):
 
     def __init__(self):
         super(ContextSeqEmbAbstractLayer, self).__init__()
+        self.token_field_offsets = {}
+        self.token_embedding_table = {}
+        self.float_embedding_table = {}
+        self.token_seq_embedding_table = {}
+
+        self.token_field_names = None
+        self.token_field_dims = None
+        self.float_field_names = None
+        self.float_field_dims = None
+        self.token_seq_field_names = None
+        self.token_seq_field_dims = None
+        self.num_feature_field = None
 
     def get_fields_name_dim(self):
         """get user feature field and item feature field.
 
         """
-        self.token_field_offsets = {}
-        self.token_embedding_table = {}
-        self.float_embedding_table = {}
-        self.token_seq_embedding_table = {}
         self.token_field_names = {type: [] for type in self.types}
         self.token_field_dims = {type: [] for type in self.types}
         self.float_field_names = {type: [] for type in self.types}
@@ -594,7 +602,6 @@ def get_embedding(self):
             if len(self.token_field_dims[type]) > 0:
                 self.token_field_offsets[type] = np.array((0, *np.cumsum(self.token_field_dims[type])[:-1]),
                                                           dtype=np.long)
-
                 self.token_embedding_table[type] = FMEmbedding(
                     self.token_field_dims[type], self.token_field_offsets[type], self.embedding_size
                 ).to(self.device)
@@ -728,7 +735,7 @@ def embed_input_fields(self, user_idx, item_idx):
                 feature = user_item_feat[type][field_name][user_item_idx[type]]
                 float_fields.append(feature if len(feature.shape) == (2 + (type == 'item')) else feature.unsqueeze(-1))
             if len(float_fields) > 0:
-                float_fields = torch.cat(float_fields, dim=1)  # [batch_size, max_item_length, num_float_field]
+                float_fields = torch.cat(float_fields, dim=-1)  # [batch_size, max_item_length, num_float_field]
             else:
                 float_fields = None
             # [batch_size, max_item_length, num_float_field]
@@ -911,7 +918,15 @@ class FMFirstOrderLinear(nn.Module):
     def __init__(self, config, dataset, output_dim=1):
 
         super(FMFirstOrderLinear, self).__init__()
-        self.field_names = dataset.fields()
+        self.field_names = dataset.fields(
+            source=[
+                FeatureSource.INTERACTION,
+                FeatureSource.USER,
+                FeatureSource.USER_ID,
+                FeatureSource.ITEM,
+                FeatureSource.ITEM_ID,
+            ]
+        )
         self.LABEL = config['LABEL_FIELD']
         self.device = config['device']
         self.token_field_names = []
@@ -949,6 +964,7 @@ def embed_float_fields(self, float_fields, embed=True):
 
         Args:
             float_fields (torch.FloatTensor): The input tensor. shape of [batch_size, num_float_field]
+            embed (bool): Return the embedding of columns or just the columns itself. Defaults to ``True``.
 
         Returns:
             torch.FloatTensor: The first order score of float feature columns
diff --git a/recbole/model/sequential_recommender/dien.py b/recbole/model/sequential_recommender/dien.py
index 56372bee9..b1d3bd0f6 100644
--- a/recbole/model/sequential_recommender/dien.py
+++ b/recbole/model/sequential_recommender/dien.py
@@ -80,6 +80,7 @@ def __init__(self, config, dataset):
         self.loss = nn.BCELoss()
 
         self.apply(self._init_weights)
+        self.other_parameter_name = ['embedding_layer']
 
     def _init_weights(self, module):
         if isinstance(module, nn.Embedding):
@@ -92,12 +93,9 @@ def _init_weights(self, module):
     def forward(self, user, item_seq, neg_item_seq, item_seq_len, next_items):
 
         max_length = item_seq.shape[1]
-
         # concatenate the history item seq with the target item to get embedding together
         item_seq_next_item = torch.cat((item_seq, neg_item_seq, next_items.unsqueeze(1)), dim=-1)
-
         sparse_embedding, dense_embedding = self.embedding_layer(user, item_seq_next_item)
-
         # concat the sparse embedding and float embedding
         feature_table = {}
         for type in self.types:
@@ -109,7 +107,6 @@ def forward(self, user, item_seq, neg_item_seq, item_seq_len, next_items):
 
             feature_table[type] = torch.cat(feature_table[type], dim=-2)
             table_shape = feature_table[type].shape
-
             feat_num, embedding_size = table_shape[-2], table_shape[-1]
             feature_table[type] = feature_table[type].view(table_shape[:-2] + (feat_num * embedding_size,))
 
diff --git a/recbole/model/sequential_recommender/din.py b/recbole/model/sequential_recommender/din.py
index dcb7ce395..f8f601223 100644
--- a/recbole/model/sequential_recommender/din.py
+++ b/recbole/model/sequential_recommender/din.py
@@ -75,7 +75,9 @@ def __init__(self, config, dataset):
         self.sigmoid = nn.Sigmoid()
         self.loss = nn.BCELoss()
 
+        # parameters initialization
         self.apply(self._init_weights)
+        self.other_parameter_name = ['embedding_layer']
 
     def _init_weights(self, module):
         if isinstance(module, nn.Embedding):
@@ -88,12 +90,9 @@ def _init_weights(self, module):
     def forward(self, user, item_seq, item_seq_len, next_items):
 
         max_length = item_seq.shape[1]
-
         # concatenate the history item seq with the target item to get embedding together
         item_seq_next_item = torch.cat((item_seq, next_items.unsqueeze(1)), dim=-1)
-
         sparse_embedding, dense_embedding = self.embedding_layer(user, item_seq_next_item)
-
         # concat the sparse embedding and float embedding
         feature_table = {}
         for type in self.types:
@@ -105,7 +104,6 @@ def forward(self, user, item_seq, item_seq_len, next_items):
 
             feature_table[type] = torch.cat(feature_table[type], dim=-2)
             table_shape = feature_table[type].shape
-
             feat_num, embedding_size = table_shape[-2], table_shape[-1]
             feature_table[type] = feature_table[type].view(table_shape[:-2] + (feat_num * embedding_size,))
 
diff --git a/recbole/model/sequential_recommender/fdsa.py b/recbole/model/sequential_recommender/fdsa.py
index 0fba79689..f0a193b52 100644
--- a/recbole/model/sequential_recommender/fdsa.py
+++ b/recbole/model/sequential_recommender/fdsa.py
@@ -93,6 +93,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(self._init_weights)
+        self.other_parameter_name = ['feature_embed_layer']
 
     def _init_weights(self, module):
         """ Initialize the weights """
diff --git a/recbole/model/sequential_recommender/gru4recf.py b/recbole/model/sequential_recommender/gru4recf.py
index 55f8d2360..549b24b46 100644
--- a/recbole/model/sequential_recommender/gru4recf.py
+++ b/recbole/model/sequential_recommender/gru4recf.py
@@ -85,6 +85,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(xavier_normal_initialization)
+        self.other_parameter_name = ['feature_embed_layer']
 
     def forward(self, item_seq, item_seq_len):
         item_seq_emb = self.item_embedding(item_seq)
diff --git a/recbole/model/sequential_recommender/s3rec.py b/recbole/model/sequential_recommender/s3rec.py
index 1aa86184f..732bab61d 100644
--- a/recbole/model/sequential_recommender/s3rec.py
+++ b/recbole/model/sequential_recommender/s3rec.py
@@ -112,7 +112,7 @@ def __init__(self, config, dataset):
         else:
             # load pretrained model for finetune
             pretrained = torch.load(self.pre_model_path)
-            self.logger.info('Load pretrained model from', self.pre_model_path)
+            self.logger.info(f'Load pretrained model from {self.pre_model_path}')
             self.load_state_dict(pretrained['state_dict'])
 
     def _init_weights(self, module):
diff --git a/recbole/model/sequential_recommender/sasrecf.py b/recbole/model/sequential_recommender/sasrecf.py
index b6c4feb4f..1125381d0 100644
--- a/recbole/model/sequential_recommender/sasrecf.py
+++ b/recbole/model/sequential_recommender/sasrecf.py
@@ -74,6 +74,7 @@ def __init__(self, config, dataset):
 
         # parameters initialization
         self.apply(self._init_weights)
+        self.other_parameter_name = ['feature_embed_layer']
 
     def _init_weights(self, module):
         """ Initialize the weights """
diff --git a/recbole/properties/dataset/kg_url.yaml b/recbole/properties/dataset/kg_url.yaml
new file mode 100644
index 000000000..3c138cee0
--- /dev/null
+++ b/recbole/properties/dataset/kg_url.yaml
@@ -0,0 +1,11 @@
+amazon-books: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/Amazon-book-KG.zip
+lfm1b-albums-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+lfm1b-artists-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+lfm1b-tracks-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+lfm1b-albums-not-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+lfm1b-artists-not-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+lfm1b-tracks-not-merged: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/LFM-1b-KG.zip
+ml-100k: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/MovieLens-KG.zip
+ml-1m: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/MovieLens-KG.zip
+ml-10m: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/MovieLens-KG.zip
+ml-20m: https://recbole.s3-accelerate.amazonaws.com/KGDatasets/MovieLens-KG.zip
diff --git a/recbole/properties/dataset/ml-100k.yaml b/recbole/properties/dataset/ml-100k.yaml
index 9e0beff79..7c229f814 100644
--- a/recbole/properties/dataset/ml-100k.yaml
+++ b/recbole/properties/dataset/ml-100k.yaml
@@ -31,18 +31,16 @@ unused_col: ~
 
 # Filtering
 rm_dup_inter: ~
-lowest_val: ~
-highest_val: ~
-equal_val: ~
-not_equal_val: ~
+val_interval: ~
 filter_inter_by_user_or_item: True
-max_user_inter_num: ~
-min_user_inter_num: ~
-max_item_inter_num: ~
-min_item_inter_num: ~
+user_inter_num_interval: ~
+item_inter_num_interval: ~
 
 # Preprocessing
-fields_in_same_space: ~
+alias_of_user_id: ~
+alias_of_item_id: ~
+alias_of_entity_id: ~
+alias_of_relation_id: ~
 preload_weight: ~
 normalize_field: ~
 normalize_all: True
diff --git a/recbole/properties/dataset/sample.yaml b/recbole/properties/dataset/sample.yaml
index d9869e5e2..301e5b3c8 100644
--- a/recbole/properties/dataset/sample.yaml
+++ b/recbole/properties/dataset/sample.yaml
@@ -26,18 +26,16 @@ additional_feat_suffix: ~
 
 # Filtering
 rm_dup_inter: ~
-lowest_val: ~
-highest_val: ~
-equal_val: ~
-not_equal_val: ~
+val_interval: ~
 filter_inter_by_user_or_item: True
-max_user_inter_num: ~
-min_user_inter_num: 0
-max_item_inter_num: ~
-min_item_inter_num: 0
+user_inter_num_interval: "[0,inf)"
+item_inter_num_interval: "[0,inf)"
 
 # Preprocessing
-fields_in_same_space: ~
+alias_of_user_id: ~
+alias_of_item_id: ~
+alias_of_entity_id: ~
+alias_of_relation_id: ~
 preload_weight: ~
 normalize_field: ~
 normalize_all: ~
@@ -54,9 +52,5 @@ TAIL_ENTITY_ID_FIELD: tail_id
 RELATION_ID_FIELD: relation_id
 ENTITY_ID_FIELD: entity_id
 
-# Social Model Needed
-SOURCE_ID_FIELD: source_id
-TARGET_ID_FIELD: target_id
-
 # Benchmark .inter
 benchmark_filename: ~
diff --git a/recbole/properties/dataset/url.yaml b/recbole/properties/dataset/url.yaml
new file mode 100644
index 000000000..1534a5010
--- /dev/null
+++ b/recbole/properties/dataset/url.yaml
@@ -0,0 +1,89 @@
+adult: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Adult/adult.zip
+amazon-apps-for-android: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Apps_for_Android.zip
+amazon-automotive: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Automotive.zip
+amazon-baby: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Baby.zip
+amazon-beauty: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Beauty.zip
+amazon-books: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Books.zip
+amazon-cell-phones-accessories: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Cell_Phones_and_Accessories.zip
+amazon-clothing-shoes-jewelry: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Clothing_Shoes_and_Jewelry.zip
+amazon-digital-music: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Digital_Music.zip
+amazon-electronics: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Electronics.zip
+amazon-grocery-gourmet-food: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Grocery_and_Gourmet_Food.zip
+amazon-health-personal-care: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Health_and_Personal_Care.zip
+amazon-home-kitchen: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Home_and_Kitchen.zip
+amazon-instant-video: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Instant_Video.zip
+amazon-kindle-store: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Kindle_Store.zip
+amazon-musical-instruments: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Musical_Instruments.zip
+amazon-movies-tv: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Movies_and_TV.zip
+amazon-office-products: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Office_Products.zip
+amazon-patio-lawn-garden: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Patio_Lawn_and_Garden.zip
+amazon-pet-supplies: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Pet_Supplies.zip
+amazon-sports-outdoors: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Sports_and_Outdoors.zip
+amazon-tools-home-improvement: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Tools_and_Home_Improvement.zip
+amazon-toys-games: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Toys_and_Games.zip
+amazon-video-games: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Amazon_ratings/Amazon_Video_Games.zip
+anime: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Anime/anime.zip
+avazu: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Avazu/avazu.zip
+book-crossing: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Book-Crossing/book-crossing.zip
+criteo: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Criteo/criteo.zip
+diginetica-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/DIGINETICA/merged/diginetica.zip
+diginetica-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/DIGINETICA/not_merged/diginetica.zip
+douban: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Douban/douban.zip
+epinions: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Epinions/epinions.zip
+foursquare-nyc-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Foursquare/merged/foursquare_NYC.zip
+foursquare-tky-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Foursquare/merged/foursquare_TKY.zip
+foursquare-nyc-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Foursquare/not_merged/foursquare_NYC.zip
+foursquare-tky-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Foursquare/not_merged/foursquare_TKY.zip
+gowalla-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Gowalla/merged/gowalla.zip
+gowalla-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Gowalla/not_merged/gowalla.zip
+ipinyou-click-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/iPinYou/merged/ipinyou-click.zip
+ipinyou-view-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/iPinYou/merged/ipinyou-view.zip
+ipinyou-click-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/iPinYou/not_merged/ipinyou-click.zip
+ipinyou-view-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/iPinYou/not_merged/ipinyou-view.zip
+jester: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Jester/jester.zip
+kdd2010-algebra2006-2007: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/KDD2010/KDD2010-algebra2006_2007.zip
+kdd2010-algebra2008-2009: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/KDD2010/KDD2010-algebra2008_2009.zip
+kdd2010-bridge-to-algebra2006-2007: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/KDD2010/KDD2010-bridge-to-algebra2006_2007.zip
+lastfm: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LastFM/lastfm.zip
+lfm1b-albums-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/merged/lfm1b-albums.zip
+lfm1b-artists-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/merged/lfm1b-artists.zip
+lfm1b-tracks-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/merged/lfm1b-tracks.zip
+lfm1b-albums-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/not_merged/lfm1b-albums.zip
+lfm1b-artists-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/not_merged/lfm1b-artists.zip
+lfm1b-tracks-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/LFM-1b/not_merged/lfm1b-tracks.zip
+mind-large-dev: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MIND/mind_large_dev.zip
+mind-large-train: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MIND/mind_large_train.zip
+mind-small-dev: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MIND/mind_small_dev.zip
+mind-small_train: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MIND/mind_small_train.zip
+ml-100k: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-100k.zip
+ml-1m: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-1m.zip
+ml-10m: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-10m.zip
+ml-20m: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/MovieLens/ml-20m.zip
+netflix: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Netflix/netflix.zip
+phishing-website: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Phishing-websites/phishing-website.zip
+pinterest: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Pinterest/pinterest.zip
+retailrocket-addtocart-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/merged/retailrocket-addtocart.zip
+retailrocket-transaction-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/merged/retailrocket-transaction.zip
+retailrocket-view-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/merged/retailrocket-view.zip
+retailrocket-addtocart-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/not-merged/retailrocket-addtocart.zip
+retailrocket-transaction-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/not-merged/retailrocket-transaction.zip
+retailrocket-view-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Retailrocket/not-merged/retailrocket-view.zip
+steam-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Steam/merged/steam.zip
+steam-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Steam/not-merged/steam.zip
+ta-feng-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Ta-Feng/merged/ta-feng.zip
+ta-feng-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Ta-Feng/not-merged/ta-feng.zip
+tmall-buy-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Tmall/merged/tmall-buy.zip
+tmall-click-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Tmall/merged/tmall-click.zip
+tmall-buy-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Tmall/not_merged/tmall-buy.zip
+tmall-click-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Tmall/not_merged/tmall-click.zip
+yahoo-music: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Yahoo-Music/yahoo-music.zip
+yelp: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Yelp/yelp.zip
+yoochoose-buys-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/YOOCHOOSE/merged/yoochoose-buys.zip
+yoochoose-clicks-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/YOOCHOOSE/merged/yoochoose-clicks.zip
+yoochoose-buys-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/YOOCHOOSE/not-merged/yoochoose-buys.zip
+yoochoose-clicks-not-merged: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/YOOCHOOSE/not-merged/yoochoose-clicks.zip
+
+# session-based recommendation benchmarks
+diginetica-session: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/DIGINETICA/session/diginetica_session.zip
+tmall-session: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Tmall/session/tmall_session.zip
+nowplaying-session: https://recbole.s3-accelerate.amazonaws.com/ProcessedDatasets/Nowplaying/session/nowplaying_session.zip
diff --git a/recbole/properties/model/RaCT.yaml b/recbole/properties/model/RaCT.yaml
index f6f510d6f..36cbc6f02 100644
--- a/recbole/properties/model/RaCT.yaml
+++ b/recbole/properties/model/RaCT.yaml
@@ -7,4 +7,5 @@ critic_layers: [100,100,10]
 metrics_k: 100
 train_stage: 'actor_pretrain'
 pretrain_epochs: 150
+save_step: 10
 pre_model_path: ''
\ No newline at end of file
diff --git a/recbole/properties/model/S3Rec.yaml b/recbole/properties/model/S3Rec.yaml
index 614dbd92f..2f03a4859 100644
--- a/recbole/properties/model/S3Rec.yaml
+++ b/recbole/properties/model/S3Rec.yaml
@@ -14,6 +14,7 @@ mip_weight: 0.2
 map_weight: 1.0
 sp_weight: 0.5
 train_stage: 'pretrain'
+pretrain_epochs: 500
 save_step: 10
 pre_model_path: ''
 loss_type: 'CE'
\ No newline at end of file
diff --git a/recbole/properties/model/xgboost.yaml b/recbole/properties/model/xgboost.yaml
index 47d4f890f..9cd2c0bd4 100644
--- a/recbole/properties/model/xgboost.yaml
+++ b/recbole/properties/model/xgboost.yaml
@@ -19,7 +19,7 @@ xgb_params:
     eta: 1
     seed: 2020
     # nthread: -1
-xgb_num_boost_round: 500
+xgb_num_boost_round: 100
 xgb_early_stopping_rounds: ~
-xgb_verbose_eval: 100
+xgb_verbose_eval: 50
 
diff --git a/recbole/properties/overall.yaml b/recbole/properties/overall.yaml
index a99b33176..5eed6492a 100644
--- a/recbole/properties/overall.yaml
+++ b/recbole/properties/overall.yaml
@@ -7,27 +7,29 @@ reproducibility: True
 data_path: 'dataset/'
 checkpoint_dir: 'saved'
 show_progress: True
+save_dataset: False
+save_dataloaders: False
 
 # training settings
 epochs: 300
 train_batch_size: 2048
 learner: adam
 learning_rate: 0.001
-training_neg_sample_num: 1
-training_neg_sample_distribution: uniform
+neg_sampling:
+  uniform: 1
 eval_step: 1
 stopping_step: 10
 clip_grad_norm: ~
 # clip_grad_norm:  {'max_norm': 5, 'norm_type': 2}
 weight_decay: 0.0
-draw_loss_pic: False
 
 # evaluation settings
-eval_setting: RO_RS,full
-group_by_user: True
-split_ratio: [0.8,0.1,0.1]
-leave_one_num: 2
-real_time_process: False
+eval_args: 
+  split: {'RS':[0.8,0.1,0.1]}
+  group_by: user
+  order: RO
+  mode: full
+repeatable: False
 metrics: ["Recall","MRR","NDCG","Hit","Precision"]
 topk: [10]
 valid_metric: MRR@10
diff --git a/recbole/properties/quick_start_config/context-aware.yaml b/recbole/properties/quick_start_config/context-aware.yaml
index cdb71f098..06239958a 100644
--- a/recbole/properties/quick_start_config/context-aware.yaml
+++ b/recbole/properties/quick_start_config/context-aware.yaml
@@ -1,5 +1,8 @@
-eval_setting: RO_RS
-group_by_user: False
-training_neg_sample_num: 0
+eval_args:
+  split: {'RS':[0.8,0.1,0.1]}
+  order: RO
+  group_by: ~
+  mode: labeled
+neg_sampling: ~
 metrics: ['AUC', 'LogLoss']
 valid_metric: AUC
\ No newline at end of file
diff --git a/recbole/properties/quick_start_config/sequential.yaml b/recbole/properties/quick_start_config/sequential.yaml
index 87c0fa053..5e0f90dc3 100644
--- a/recbole/properties/quick_start_config/sequential.yaml
+++ b/recbole/properties/quick_start_config/sequential.yaml
@@ -1,1 +1,5 @@
-eval_setting: TO_LS,full
\ No newline at end of file
+eval_args:
+  split: {'LS': 'valid_and_test'}
+  order: TO
+  mode: full
+repeatable: True
diff --git a/recbole/properties/quick_start_config/sequential_DIN.yaml b/recbole/properties/quick_start_config/sequential_DIN.yaml
index 58b8db955..dc0991647 100644
--- a/recbole/properties/quick_start_config/sequential_DIN.yaml
+++ b/recbole/properties/quick_start_config/sequential_DIN.yaml
@@ -1,3 +1,7 @@
-eval_setting: TO_LS, uni100
+eval_args:
+  split: {'LS': 'valid_and_test'}
+  order: TO
+  mode: uni100
 metrics: ['AUC', 'LogLoss']
-valid_metric: AUC
\ No newline at end of file
+valid_metric: AUC
+repeatable: True
diff --git a/recbole/properties/quick_start_config/sequential_embedding_model.yaml b/recbole/properties/quick_start_config/sequential_embedding_model.yaml
index 59b920994..f880b5d3b 100644
--- a/recbole/properties/quick_start_config/sequential_embedding_model.yaml
+++ b/recbole/properties/quick_start_config/sequential_embedding_model.yaml
@@ -1,4 +1,5 @@
 load_col: 
     inter: ['user_id', 'item_id', 'rating', 'timestamp']
     ent: ['ent_id', 'ent_emb']
-additional_feat_suffix: ent
\ No newline at end of file
+additional_feat_suffix: ent
+repeatable: True
diff --git a/recbole/quick_start/__init__.py b/recbole/quick_start/__init__.py
index b604cec32..38a49c318 100644
--- a/recbole/quick_start/__init__.py
+++ b/recbole/quick_start/__init__.py
@@ -1,1 +1,1 @@
-from recbole.quick_start.quick_start import run_recbole, objective_function
+from recbole.quick_start.quick_start import run_recbole, objective_function, load_data_and_model
diff --git a/recbole/quick_start/quick_start.py b/recbole/quick_start/quick_start.py
index 2072d110c..05ad69129 100644
--- a/recbole/quick_start/quick_start.py
+++ b/recbole/quick_start/quick_start.py
@@ -9,10 +9,12 @@
 import logging
 from logging import getLogger
 
+import torch
+import pickle
+
 from recbole.config import Config
-from recbole.data import create_dataset, data_preparation
-from recbole.utils import init_logger, get_model, get_trainer, init_seed
-from recbole.utils.utils import set_color
+from recbole.data import create_dataset, data_preparation, save_split_dataloaders, load_split_dataloaders
+from recbole.utils import init_logger, get_model, get_trainer, init_seed, set_color
 
 
 def run_recbole(model=None, dataset=None, config_file_list=None, config_dict=None, saved=True):
@@ -20,16 +22,15 @@ def run_recbole(model=None, dataset=None, config_file_list=None, config_dict=Non
     training and testing a model on a specified dataset
 
     Args:
-        model (str): model name
-        dataset (str): dataset name
-        config_file_list (list): config files used to modify experiment parameters
-        config_dict (dict): parameters dictionary used to modify experiment parameters
-        saved (bool): whether to save the model
+        model (str, optional): Model name. Defaults to ``None``.
+        dataset (str, optional): Dataset name. Defaults to ``None``.
+        config_file_list (list, optional): Config files used to modify experiment parameters. Defaults to ``None``.
+        config_dict (dict, optional): Parameters dictionary used to modify experiment parameters. Defaults to ``None``.
+        saved (bool, optional): Whether to save the model. Defaults to ``True``.
     """
     # configurations initialization
     config = Config(model=model, dataset=dataset, config_file_list=config_file_list, config_dict=config_dict)
     init_seed(config['seed'], config['reproducibility'])
-
     # logger initialization
     init_logger(config)
     logger = getLogger()
@@ -38,13 +39,17 @@ def run_recbole(model=None, dataset=None, config_file_list=None, config_dict=Non
 
     # dataset filtering
     dataset = create_dataset(config)
+    if config['save_dataset']:
+        dataset.save()
     logger.info(dataset)
 
     # dataset splitting
     train_data, valid_data, test_data = data_preparation(config, dataset)
+    if config['save_dataloaders']:
+        save_split_dataloaders(config, dataloaders=(train_data, valid_data, test_data))
 
     # model loading and initialization
-    model = get_model(config['model'])(config, train_data).to(config['device'])
+    model = get_model(config['model'])(config, train_data.dataset).to(config['device'])
     logger.info(model)
 
     # trainer loading and initialization
@@ -73,9 +78,9 @@ def objective_function(config_dict=None, config_file_list=None, saved=True):
     r""" The default objective_function used in HyperTuning
 
     Args:
-        config_dict (dict): parameters dictionary used to modify experiment parameters
-        config_file_list (list): config files used to modify experiment parameters
-        saved (bool): whether to save the model
+        config_dict (dict, optional): Parameters dictionary used to modify experiment parameters. Defaults to ``None``.
+        config_file_list (list, optional): Config files used to modify experiment parameters. Defaults to ``None``.
+        saved (bool, optional): Whether to save the model. Defaults to ``True``.
     """
 
     config = Config(config_dict=config_dict, config_file_list=config_file_list)
@@ -83,7 +88,7 @@ def objective_function(config_dict=None, config_file_list=None, saved=True):
     logging.basicConfig(level=logging.ERROR)
     dataset = create_dataset(config)
     train_data, valid_data, test_data = data_preparation(config, dataset)
-    model = get_model(config['model'])(config, train_data).to(config['device'])
+    model = get_model(config['model'])(config, train_data.dataset).to(config['device'])
     trainer = get_trainer(config['MODEL_TYPE'], config['model'])(config, model)
     best_valid_score, best_valid_result = trainer.fit(train_data, valid_data, verbose=False, saved=saved)
     test_result = trainer.evaluate(test_data, load_best_model=saved)
@@ -94,3 +99,55 @@ def objective_function(config_dict=None, config_file_list=None, saved=True):
         'best_valid_result': best_valid_result,
         'test_result': test_result
     }
+
+
+def load_data_and_model(model_file, dataset_file=None, dataloader_file=None):
+    r"""Load filtered dataset, split dataloaders and saved model.
+
+    Args:
+        model_file (str): The path of saved model file.
+        dataset_file (str, optional): The path of filtered dataset. Defaults to ``None``.
+        dataloader_file (str, optional): The path of split dataloaders. Defaults to ``None``.
+
+    Note:
+        The :attr:`dataset` will be loaded or created according to the following strategy:
+        If :attr:`dataset_file` is not ``None``, the :attr:`dataset` will be loaded from :attr:`dataset_file`.
+        If :attr:`dataset_file` is ``None`` and :attr:`dataloader_file` is ``None``,
+        the :attr:`dataset` will be created according to :attr:`config`.
+        If :attr:`dataset_file` is ``None`` and :attr:`dataloader_file` is not ``None``,
+        the :attr:`dataset` will neither be loaded or created.
+
+        The :attr:`dataloader` will be loaded or created according to the following strategy:
+        If :attr:`dataloader_file` is not ``None``, the :attr:`dataloader` will be loaded from :attr:`dataloader_file`.
+        If :attr:`dataloader_file` is ``None``, the :attr:`dataloader` will be created according to :attr:`config`.
+
+    Returns:
+        tuple:
+            - config (Config): An instance object of Config, which record parameter information in :attr:`model_file`.
+            - model (AbstractRecommender): The model load from :attr:`model_file`.
+            - dataset (Dataset): The filtered dataset.
+            - train_data (AbstractDataLoader): The dataloader for training.
+            - valid_data (AbstractDataLoader): The dataloader for validation.
+            - test_data (AbstractDataLoader): The dataloader for testing.
+    """
+    checkpoint = torch.load(model_file)
+    config = checkpoint['config']
+    init_logger(config)
+
+    dataset = None
+    if dataset_file:
+        with open(dataset_file, 'rb') as f:
+            dataset = pickle.load(f)
+
+    if dataloader_file:
+        train_data, valid_data, test_data = load_split_dataloaders(dataloader_file)
+    else:
+        if dataset is None:
+            dataset = create_dataset(config)
+        train_data, valid_data, test_data = data_preparation(config, dataset)
+
+    model = get_model(config['model'])(config, train_data.dataset).to(config['device'])
+    model.load_state_dict(checkpoint['state_dict'])
+    model.load_other_parameter(checkpoint.get('other_parameter'))
+
+    return config, model, dataset, train_data, valid_data, test_data
diff --git a/recbole/sampler/sampler.py b/recbole/sampler/sampler.py
index 7bd282622..805226b3d 100644
--- a/recbole/sampler/sampler.py
+++ b/recbole/sampler/sampler.py
@@ -4,9 +4,9 @@
 # @File   : sampler.py
 
 # UPDATE
-# @Time   : 2020/8/17, 2020/8/31, 2020/10/6, 2020/9/18, 2021/3/19
+# @Time   : 2021/7/23, 2020/8/31, 2020/10/6, 2020/9/18, 2021/3/19
 # @Author : Xingyu Pan, Kaiyuan Li, Yupeng Hou, Yushuo Chen, Zhichao Feng
-# @email  : panxy@ruc.edu.cn, tsotfsk@outlook.com, houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, fzcbupt@gmail.com
+# @email  : xy_pan@foxmail.com, tsotfsk@outlook.com, houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, fzcbupt@gmail.com
 
 """
 recbole.sampler
@@ -16,29 +16,25 @@
 import copy
 
 import numpy as np
+from numpy.random import sample
 import torch
+from collections import Counter
 
 
 class AbstractSampler(object):
     """:class:`AbstractSampler` is a abstract class, all sampler should inherit from it. This sampler supports returning
     a certain number of random value_ids according to the input key_id, and it also supports to prohibit
-    certain key-value pairs by setting used_ids. Besides, in order to improve efficiency, we use :attr:`random_pr`
-    to move around the :attr:`random_list` to generate random numbers, so we need to implement the
-    :meth:`get_random_list` method in the subclass.
+    certain key-value pairs by setting used_ids.
 
     Args:
         distribution (str): The string of distribution, which is used for subclass.
 
     Attributes:
-        random_list (list or numpy.ndarray): The shuffled result of :meth:`get_random_list`.
         used_ids (numpy.ndarray): The result of :meth:`get_used_ids`.
     """
 
     def __init__(self, distribution):
         self.distribution = ''
-        self.random_list = []
-        self.random_pr = 0
-        self.random_list_length = 0
         self.set_distribution(distribution)
         self.used_ids = self.get_used_ids()
 
@@ -48,57 +44,101 @@ def set_distribution(self, distribution):
         Args:
             distribution (str): Distribution of the negative items.
         """
-        if self.distribution == distribution:
-            return
         self.distribution = distribution
-        self.random_list = self.get_random_list()
-        np.random.shuffle(self.random_list)
-        self.random_pr = 0
-        self.random_list_length = len(self.random_list)
+        if distribution == 'popularity':
+            self._build_alias_table()
 
-    def get_random_list(self):
-        """
+    def _uni_sampling(self, sample_num):
+        """Sample [sample_num] items in the uniform distribution.
+
+        Args:
+            sample_num (int): the number of samples.
+        
         Returns:
-            numpy.ndarray or list: Random list of value_id.
+            sample_list (np.array): a list of samples. 
         """
-        raise NotImplementedError('method [get_random_list] should be implemented')
+        raise NotImplementedError('Method [_uni_sampling] should be implemented')
+
+    def _get_candidates_list(self):
+        """Get sample candidates list for _pop_sampling()
 
-    def get_used_ids(self):
-        """
         Returns:
-            numpy.ndarray: Used ids. Index is key_id, and element is a set of value_ids.
+            candidates_list (list): a list of candidates id.
         """
-        raise NotImplementedError('method [get_used_ids] should be implemented')
+        raise NotImplementedError('Method [_get_candidates_list] should be implemented')
 
-    def random(self):
+    def _build_alias_table(self):
+        """Build alias table for popularity_biased sampling.
         """
+        candidates_list = self._get_candidates_list()
+        self.prob = dict(Counter(candidates_list))
+        self.alias = self.prob.copy()
+        large_q = []
+        small_q = []
+
+        for i in self.prob:
+            self.alias[i] = -1
+            self.prob[i] = self.prob[i] / len(candidates_list) * len(self.prob)
+            if self.prob[i] > 1:
+                large_q.append(i)
+            elif self.prob[i] < 1:
+                small_q.append(i)
+
+        while len(large_q) != 0 and len(small_q) != 0:
+            l = large_q.pop(0)
+            s = small_q.pop(0)
+            self.alias[s] = l
+            self.prob[l] = self.prob[l] - (1 - self.prob[s])
+            if self.prob[l] < 1:
+                small_q.append(l)
+            elif self.prob[l] > 1:
+                large_q.append(l)
+
+    def _pop_sampling(self, sample_num):
+        """Sample [sample_num] items in the popularity-biased distribution.
+
+        Args:
+            sample_num (int): the number of samples.
+        
         Returns:
-            value_id (int): Random value_id. Generated by :attr:`random_list`.
+            sample_list (np.array): a list of samples. 
         """
-        value_id = self.random_list[self.random_pr % self.random_list_length]
-        self.random_pr += 1
-        return value_id
 
-    def random_num(self, num):
-        """
+        keys = list(self.prob.keys())
+        random_index_list = np.random.randint(0, len(keys), sample_num)
+        random_prob_list = np.random.random(sample_num)
+        final_random_list = []
+
+        for idx, prob in zip(random_index_list, random_prob_list):
+            if self.prob[keys[idx]] > prob:
+                final_random_list.append(keys[idx])
+            else:
+                final_random_list.append(self.alias[keys[idx]])
+
+        return np.array(final_random_list)
+
+    def sampling(self, sample_num):
+        """Sampling [sample_num] item_ids.
+        
         Args:
-            num (int): Number of random value_ids.
+            sample_num (int): the number of samples.
+        
+        Returns:
+            sample_list (np.array): a list of samples and the len is [sample_num].
+        """
+        if self.distribution == 'uniform':
+            return self._uni_sampling(sample_num)
+        elif self.distribution == 'popularity':
+            return self._pop_sampling(sample_num)
+        else:
+            raise NotImplementedError(f'The sampling distribution [{self.distribution}] is not implemented.')
 
+    def get_used_ids(self):
+        """
         Returns:
-            value_ids (numpy.ndarray): Random value_ids. Generated by :attr:`random_list`.
+            numpy.ndarray: Used ids. Index is key_id, and element is a set of value_ids.
         """
-        value_id = []
-        self.random_pr %= self.random_list_length
-        while True:
-            if self.random_pr + num <= self.random_list_length:
-                value_id.append(self.random_list[self.random_pr:self.random_pr + num])
-                self.random_pr += num
-                break
-            else:
-                value_id.append(self.random_list[self.random_pr:])
-                num -= self.random_list_length - self.random_pr
-                self.random_pr = 0
-        return np.concatenate(value_id)
+        raise NotImplementedError('Method [get_used_ids] should be implemented')
 
     def sample_by_key_ids(self, key_ids, num):
         """Sampling by key_ids.
@@ -120,33 +160,18 @@ def sample_by_key_ids(self, key_ids, num):
         if (key_ids == key_ids[0]).all():
             key_id = key_ids[0]
             used = np.array(list(self.used_ids[key_id]))
-            value_ids = self.random_num(total_num)
+            value_ids = self.sampling(total_num)
             check_list = np.arange(total_num)[np.isin(value_ids, used)]
             while len(check_list) > 0:
-                value_ids[check_list] = value = self.random_num(len(check_list))
-                perm = value.argsort(kind='quicksort')
-                aux = value[perm]
-                mask = np.empty(aux.shape, dtype=np.bool_)
-                mask[:1] = True
-                mask[1:] = aux[1:] != aux[:-1]
-                value = aux[mask]
-                rev_idx = np.empty(mask.shape, dtype=np.intp)
-                rev_idx[perm] = np.cumsum(mask) - 1
-                ar = np.concatenate((value, used))
-                order = ar.argsort(kind='mergesort')
-                sar = ar[order]
-                bool_ar = (sar[1:] == sar[:-1])
-                flag = np.concatenate((bool_ar, [False]))
-                ret = np.empty(ar.shape, dtype=bool)
-                ret[order] = flag
-                mask = ret[rev_idx]
+                value_ids[check_list] = value = self.sampling(len(check_list))
+                mask = np.isin(value, used)
                 check_list = check_list[mask]
         else:
             value_ids = np.zeros(total_num, dtype=np.int64)
             check_list = np.arange(total_num)
             key_ids = np.tile(key_ids, num)
             while len(check_list) > 0:
-                value_ids[check_list] = self.random_num(len(check_list))
+                value_ids[check_list] = self.sampling(len(check_list))
                 check_list = np.array([
                     i for i, used, v in zip(check_list, self.used_ids[key_ids[check_list]], value_ids[check_list])
                     if v in used
@@ -183,25 +208,19 @@ def __init__(self, phases, datasets, distribution='uniform'):
         self.uid_field = datasets[0].uid_field
         self.iid_field = datasets[0].iid_field
 
-        self.n_users = datasets[0].user_num
-        self.n_items = datasets[0].item_num
+        self.user_num = datasets[0].user_num
+        self.item_num = datasets[0].item_num
 
         super().__init__(distribution=distribution)
 
-    def get_random_list(self):
-        """
-        Returns:
-            numpy.ndarray or list: Random list of item_id.
-        """
-        if self.distribution == 'uniform':
-            return np.arange(1, self.n_items)
-        elif self.distribution == 'popularity':
-            random_item_list = []
-            for dataset in self.datasets:
-                random_item_list.extend(dataset.inter_feat[self.iid_field].numpy())
-            return random_item_list
-        else:
-            raise NotImplementedError(f'Distribution [{self.distribution}] has not been implemented.')
+    def _get_candidates_list(self):
+        candidates_list = []
+        for dataset in self.datasets:
+            candidates_list.extend(dataset.inter_feat[self.iid_field].numpy())
+        return candidates_list
+
+    def _uni_sampling(self, sample_num):
+        return np.random.randint(1, self.item_num, sample_num)
 
     def get_used_ids(self):
         """
@@ -210,7 +229,7 @@ def get_used_ids(self):
             Key is phase, and value is a numpy.ndarray which index is user_id, and element is a set of item_ids.
         """
         used_item_id = dict()
-        last = [set() for _ in range(self.n_users)]
+        last = [set() for _ in range(self.user_num)]
         for phase, dataset in zip(self.phases, self.datasets):
             cur = np.array([set(s) for s in last])
             for uid, iid in zip(dataset.inter_feat[self.uid_field].numpy(), dataset.inter_feat[self.iid_field].numpy()):
@@ -218,11 +237,11 @@ def get_used_ids(self):
             last = used_item_id[phase] = cur
 
         for used_item_set in used_item_id[self.phases[-1]]:
-            if len(used_item_set) + 1 == self.n_items:  # [pad] is a item.
+            if len(used_item_set) + 1 == self.item_num:  # [pad] is a item.
                 raise ValueError(
                     'Some users have interacted with all items, '
                     'which we can not sample negative items for them. '
-                    'Please set `max_user_inter_num` to filter those users.'
+                    'Please set `user_inter_num_interval` to filter those users.'
                 )
         return used_item_id
 
@@ -243,11 +262,12 @@ def set_phase(self, phase):
         new_sampler.used_ids = new_sampler.used_ids[phase]
         return new_sampler
 
-    def sample_by_user_ids(self, user_ids, num):
+    def sample_by_user_ids(self, user_ids, item_ids, num):
         """Sampling by user_ids.
 
         Args:
             user_ids (numpy.ndarray or list): Input user_ids.
+            item_ids (numpy.ndarray or list): Input item_ids.
             num (int): Number of sampled item_ids for each user_id.
 
         Returns:
@@ -261,7 +281,7 @@ def sample_by_user_ids(self, user_ids, num):
             return self.sample_by_key_ids(user_ids, num)
         except IndexError:
             for user_id in user_ids:
-                if user_id < 0 or user_id >= self.n_users:
+                if user_id < 0 or user_id >= self.user_num:
                     raise ValueError(f'user_id [{user_id}] not exist.')
 
 
@@ -286,17 +306,11 @@ def __init__(self, dataset, distribution='uniform'):
 
         super().__init__(distribution=distribution)
 
-    def get_random_list(self):
-        """
-        Returns:
-            numpy.ndarray or list: Random list of entity_id.
-        """
-        if self.distribution == 'uniform':
-            return np.arange(1, self.entity_num)
-        elif self.distribution == 'popularity':
-            return list(self.hid_list) + list(self.tid_list)
-        else:
-            raise NotImplementedError(f'Distribution [{self.distribution}] has not been implemented.')
+    def _uni_sampling(self, sample_num):
+        return np.random.randint(1, self.entity_num, sample_num)
+
+    def _get_candidates_list(self):
+        return list(self.hid_list) + list(self.tid_list)
 
     def get_used_ids(self):
         """
@@ -358,22 +372,16 @@ def __init__(self, phases, dataset, distribution='uniform'):
         self.dataset = dataset
 
         self.iid_field = dataset.iid_field
-        self.n_users = dataset.user_num
-        self.n_items = dataset.item_num
+        self.user_num = dataset.user_num
+        self.item_num = dataset.item_num
 
         super().__init__(distribution=distribution)
 
-    def get_random_list(self):
-        """
-        Returns:
-            numpy.ndarray or list: Random list of item_id.
-        """
-        if self.distribution == 'uniform':
-            return np.arange(1, self.n_items)
-        elif self.distribution == 'popularity':
-            return self.dataset.inter_feat[self.iid_field].numpy()
-        else:
-            raise NotImplementedError(f'Distribution [{self.distribution}] has not been implemented.')
+    def _uni_sampling(self, sample_num):
+        return np.random.randint(1, self.item_num, sample_num)
+
+    def _get_candidates_list(self):
+        return list(self.dataset.inter_feat[self.iid_field].numpy())
 
     def get_used_ids(self):
         """
@@ -381,13 +389,14 @@ def get_used_ids(self):
             numpy.ndarray: Used item_ids is the same as positive item_ids.
             Index is user_id, and element is a set of item_ids.
         """
-        return np.array([set() for _ in range(self.n_users)])
+        return np.array([set() for _ in range(self.user_num)])
 
-    def sample_by_user_ids(self, user_ids, num):
+    def sample_by_user_ids(self, user_ids, item_ids, num):
         """Sampling by user_ids.
 
         Args:
             user_ids (numpy.ndarray or list): Input user_ids.
+            item_ids (numpy.ndarray or list): Input item_ids.
             num (int): Number of sampled item_ids for each user_id.
 
         Returns:
@@ -398,10 +407,11 @@ def sample_by_user_ids(self, user_ids, num):
             item_id[len(user_ids) * (num - 1) + 1] is sampled for user_ids[1]; ...; and so on.
         """
         try:
-            return self.sample_by_key_ids(user_ids, num)
+            self.used_ids = np.array([{i} for i in item_ids])
+            return self.sample_by_key_ids(np.arange(len(user_ids)), num)
         except IndexError:
             for user_id in user_ids:
-                if user_id < 0 or user_id >= self.n_users:
+                if user_id < 0 or user_id >= self.user_num:
                     raise ValueError(f'user_id [{user_id}] not exist.')
 
     def set_phase(self, phase):
@@ -432,21 +442,17 @@ def __init__(self, dataset, distribution='uniform'):
         self.dataset = dataset
 
         self.iid_field = dataset.iid_field
-        self.n_users = dataset.user_num
-        self.n_items = dataset.item_num
+        self.user_num = dataset.user_num
+        self.item_num = dataset.item_num
 
         super().__init__(distribution=distribution)
 
+    def _uni_sampling(self, sample_num):
+        return np.random.randint(1, self.item_num, sample_num)
+
     def get_used_ids(self):
         pass
 
-    def get_random_list(self):
-        """
-        Returns:
-            numpy.ndarray or list: Random list of item_id.
-        """
-        return np.arange(1, self.n_items)
-
     def sample_neg_sequence(self, pos_sequence):
         """For each moment, sampling one item from all the items except the one the user clicked on at that moment.
 
@@ -461,7 +467,7 @@ def sample_neg_sequence(self, pos_sequence):
         value_ids = np.zeros(total_num, dtype=np.int64)
         check_list = np.arange(total_num)
         while len(check_list) > 0:
-            value_ids[check_list] = self.random_num(len(check_list))
+            value_ids[check_list] = self.sampling(len(check_list))
             check_index = np.where(value_ids[check_list] == pos_sequence[check_list])
             check_list = check_list[check_index]
 
diff --git a/recbole/trainer/trainer.py b/recbole/trainer/trainer.py
index 64544eb0e..0b0a3cb7c 100644
--- a/recbole/trainer/trainer.py
+++ b/recbole/trainer/trainer.py
@@ -3,14 +3,14 @@
 # @Email  : slmu@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/8/7, 2020/9/26, 2020/9/26, 2020/10/01, 2020/9/16
+# @Time   : 2021/6/23, 2020/9/26, 2020/9/26, 2020/10/01, 2020/9/16
 # @Author : Zihan Lin, Yupeng Hou, Yushuo Chen, Shanlei Mu, Xingyu Pan
-# @Email  : linzihan.super@foxmail.com, houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, slmu@ruc.edu.cn, panxy@ruc.edu.cn
+# @Email  : zhlin@ruc.edu.cn, houyupeng@ruc.edu.cn, chenyushuo@ruc.edu.cn, slmu@ruc.edu.cn, panxy@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/10/8, 2020/10/15, 2020/11/20, 2021/2/20, 2021/3/3, 2021/3/5
-# @Author : Hui Wang, Xinyan Fan, Chen Yang, Yibo Li, Lanling Xu, Haoran Cheng
-# @Email  : hui.wang@ruc.edu.cn, xinyan.fan@ruc.edu.cn, 254170321@qq.com, 2018202152@ruc.edu.cn, xulanling_sherry@163.com, chenghaoran29@foxmail.com
+# @Time   : 2020/10/8, 2020/10/15, 2020/11/20, 2021/2/20, 2021/3/3, 2021/3/5, 2021/7/18
+# @Author : Hui Wang, Xinyan Fan, Chen Yang, Yibo Li, Lanling Xu, Haoran Cheng, Zhichao Feng
+# @Email  : hui.wang@ruc.edu.cn, xinyan.fan@ruc.edu.cn, 254170321@qq.com, 2018202152@ruc.edu.cn, xulanling_sherry@163.com, chenghaoran29@foxmail.com, fzcbupt@gmail.com
 
 r"""
 recbole.trainer.trainer
@@ -28,10 +28,10 @@
 from tqdm import tqdm
 
 from recbole.data.interaction import Interaction
-from recbole.evaluator import ProxyEvaluator
+from recbole.data.dataloader import FullSortEvalDataLoader
+from recbole.evaluator import Evaluator, Collector
 from recbole.utils import ensure_dir, get_local_time, early_stopping, calculate_valid_score, dict2str, \
-    DataLoaderType, KGDataLoaderState
-from recbole.utils.utils import set_color
+    EvaluatorType, KGDataLoaderState, get_tensorboard, set_color, get_gpu_usage
 
 
 class AbstractTrainer(object):
@@ -77,6 +77,7 @@ def __init__(self, config, model):
         super(Trainer, self).__init__(config, model)
 
         self.logger = getLogger()
+        self.tensorboard = get_tensorboard(self.logger)
         self.learner = config['learner']
         self.learning_rate = config['learning_rate']
         self.epochs = config['epochs']
@@ -86,13 +87,13 @@ def __init__(self, config, model):
         self.valid_metric = config['valid_metric'].lower()
         self.valid_metric_bigger = config['valid_metric_bigger']
         self.test_batch_size = config['eval_batch_size']
+        self.gpu_available = torch.cuda.is_available() and config['use_gpu']
         self.device = config['device']
         self.checkpoint_dir = config['checkpoint_dir']
         ensure_dir(self.checkpoint_dir)
         saved_model_file = '{}-{}.pth'.format(self.config['model'], get_local_time())
         self.saved_model_file = os.path.join(self.checkpoint_dir, saved_model_file)
         self.weight_decay = config['weight_decay']
-        self.draw_loss_pic = config['draw_loss_pic']
 
         self.start_epoch = 0
         self.cur_step = 0
@@ -101,7 +102,8 @@ def __init__(self, config, model):
         self.train_loss_dict = dict()
         self.optimizer = self._build_optimizer(self.model.parameters())
         self.eval_type = config['eval_type']
-        self.evaluator = ProxyEvaluator(config)
+        self.eval_collector = Collector(config)
+        self.evaluator = Evaluator(config)
         self.item_tensor = None
         self.tot_item_num = None
 
@@ -154,12 +156,13 @@ def _train_epoch(self, train_data, epoch_idx, loss_func=None, show_progress=Fals
         total_loss = None
         iter_data = (
             tqdm(
-                enumerate(train_data),
+                train_data,
                 total=len(train_data),
+                ncols=100,
                 desc=set_color(f"Train {epoch_idx:>5}", 'pink'),
-            ) if show_progress else enumerate(train_data)
+            ) if show_progress else train_data
         )
-        for batch_idx, interaction in iter_data:
+        for batch_idx, interaction in enumerate(iter_data):
             interaction = interaction.to(self.device)
             self.optimizer.zero_grad()
             losses = loss_func(interaction)
@@ -175,6 +178,8 @@ def _train_epoch(self, train_data, epoch_idx, loss_func=None, show_progress=Fals
             if self.clip_grad_norm:
                 clip_grad_norm_(self.model.parameters(), **self.clip_grad_norm)
             self.optimizer.step()
+            if self.gpu_available and show_progress:
+                iter_data.set_postfix_str(set_color('GPU RAM: ' + get_gpu_usage(self.device), 'yellow'))
         return total_loss
 
     def _valid_epoch(self, valid_data, show_progress=False):
@@ -205,6 +210,7 @@ def _save_checkpoint(self, epoch):
             'cur_step': self.cur_step,
             'best_valid_score': self.best_valid_score,
             'state_dict': self.model.state_dict(),
+            'other_parameter': self.model.other_parameter(),
             'optimizer': self.optimizer.state_dict(),
         }
         torch.save(state, self.saved_model_file)
@@ -229,6 +235,7 @@ def resume_checkpoint(self, resume_file):
                 'This may yield an exception while state_dict is being loaded.'
             )
         self.model.load_state_dict(checkpoint['state_dict'])
+        self.model.load_other_parameter(checkpoint.get('other_parameter'))
 
         # load optimizer state from checkpoint only when optimizer type is not changed
         self.optimizer.load_state_dict(checkpoint['optimizer'])
@@ -251,6 +258,36 @@ def _generate_train_loss_output(self, epoch_idx, s_time, e_time, losses):
             train_loss_output += set_color('train loss', 'blue') + ': ' + des % losses
         return train_loss_output + ']'
 
+    def _add_train_loss_to_tensorboard(self, epoch_idx, losses, tag='Loss/Train'):
+        if isinstance(losses, tuple):
+            for idx, loss in enumerate(losses):
+                self.tensorboard.add_scalar(tag + str(idx), loss, epoch_idx)
+        else:
+            self.tensorboard.add_scalar(tag, losses, epoch_idx)
+
+    def _add_hparam_to_tensorboard(self, best_valid_result):
+        # base hparam
+        hparam_dict = {
+            'learner': self.config['learner'],
+            'learning_rate': self.config['learning_rate'],
+            'train_batch_size': self.config['train_batch_size']
+        }
+        # unrecorded parameter
+        unrecorded_parameter = {
+            parameter
+            for parameters in self.config.parameters.values() for parameter in parameters
+        }.union({'model', 'dataset', 'config_files', 'device'})
+        # other model-specific hparam
+        hparam_dict.update({
+            para: val
+            for para, val in self.config.final_config_dict.items() if para not in unrecorded_parameter
+        })
+        for k in hparam_dict:
+            if hparam_dict[k] is not None and not isinstance(hparam_dict[k], (bool, str, float, int)):
+                hparam_dict[k] = str(hparam_dict[k])
+
+        self.tensorboard.add_hparams(hparam_dict, {'hparam/best_valid_result': best_valid_result})
+
     def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progress=False, callback_fn=None):
         r"""Train the model based on the train data and the valid data.
 
@@ -270,6 +307,8 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
         if saved and self.start_epoch >= self.epochs:
             self._save_checkpoint(-1)
 
+        self.eval_collector.data_collect(train_data)
+
         for epoch_idx in range(self.start_epoch, self.epochs):
             # train
             training_start_time = time()
@@ -280,6 +319,7 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
                 self._generate_train_loss_output(epoch_idx, training_start_time, training_end_time, train_loss)
             if verbose:
                 self.logger.info(train_loss_output)
+            self._add_train_loss_to_tensorboard(epoch_idx, train_loss)
 
             # eval
             if self.eval_step <= 0 or not valid_data:
@@ -307,6 +347,8 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
                 if verbose:
                     self.logger.info(valid_score_output)
                     self.logger.info(valid_result_output)
+                self.tensorboard.add_scalar('Vaild_score', valid_score, epoch_idx)
+
                 if update_flag:
                     if saved:
                         self._save_checkpoint(epoch_idx)
@@ -324,20 +366,19 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
                     if verbose:
                         self.logger.info(stop_output)
                     break
-        if self.draw_loss_pic:
-            save_path = '{}-{}-train_loss.pdf'.format(self.config['model'], get_local_time())
-            self.plot_train_loss(save_path=os.path.join(save_path))
+        self._add_hparam_to_tensorboard(self.best_valid_score)
         return self.best_valid_score, self.best_valid_result
 
     def _full_sort_batch_eval(self, batched_data):
-        interaction, history_index, swap_row, swap_col_after, swap_col_before = batched_data
+        interaction, history_index, positive_u, positive_i = batched_data
         try:
             # Note: interaction without item ids
             scores = self.model.full_sort_predict(interaction.to(self.device))
         except NotImplementedError:
+            inter_len = len(interaction)
             new_inter = interaction.to(self.device).repeat_interleave(self.tot_item_num)
             batch_size = len(new_inter)
-            new_inter.update(self.item_tensor[:batch_size])
+            new_inter.update(self.item_tensor.repeat(inter_len))
             if batch_size <= self.test_batch_size:
                 scores = self.model.predict(new_inter)
             else:
@@ -347,13 +388,24 @@ def _full_sort_batch_eval(self, batched_data):
         scores[:, 0] = -np.inf
         if history_index is not None:
             scores[history_index] = -np.inf
+        return interaction, scores, positive_u, positive_i
 
-        swap_row = swap_row.to(self.device)
-        swap_col_after = swap_col_after.to(self.device)
-        swap_col_before = swap_col_before.to(self.device)
-        scores[swap_row, swap_col_after] = scores[swap_row, swap_col_before]
+    def _neg_sample_batch_eval(self, batched_data):
+        interaction, row_idx, positive_u, positive_i = batched_data
+        batch_size = interaction.length
+        if batch_size <= self.test_batch_size:
+            origin_scores = self.model.predict(interaction.to(self.device))
+        else:
+            origin_scores = self._spilt_predict(interaction, batch_size)
 
-        return interaction, scores
+        if self.config['eval_type'] == EvaluatorType.VALUE:
+            return interaction, origin_scores, positive_u, positive_i
+        elif self.config['eval_type'] == EvaluatorType.RANKING:
+            col_idx = interaction[self.config['ITEM_ID_FIELD']]
+            batch_user_num = positive_u[-1] + 1
+            scores = torch.full((batch_user_num, self.tot_item_num), -np.inf, device=self.device)
+            scores[row_idx, col_idx] = origin_scores
+            return interaction, scores, positive_u, positive_i
 
     @torch.no_grad()
     def evaluate(self, eval_data, load_best_model=True, model_file=None, show_progress=False):
@@ -380,38 +432,37 @@ def evaluate(self, eval_data, load_best_model=True, model_file=None, show_progre
                 checkpoint_file = self.saved_model_file
             checkpoint = torch.load(checkpoint_file)
             self.model.load_state_dict(checkpoint['state_dict'])
+            self.model.load_other_parameter(checkpoint.get('other_parameter'))
             message_output = 'Loading model structure and parameters from {}'.format(checkpoint_file)
             self.logger.info(message_output)
 
         self.model.eval()
 
-        if eval_data.dl_type == DataLoaderType.FULL:
+        if isinstance(eval_data, FullSortEvalDataLoader):
+            eval_func = self._full_sort_batch_eval
             if self.item_tensor is None:
-                self.item_tensor = eval_data.get_item_feature().to(self.device).repeat(eval_data.step)
+                self.item_tensor = eval_data.dataset.get_item_feature().to(self.device)
+        else:
+            eval_func = self._neg_sample_batch_eval
+        if self.config['eval_type'] == EvaluatorType.RANKING:
             self.tot_item_num = eval_data.dataset.item_num
 
-        batch_matrix_list = []
         iter_data = (
             tqdm(
-                enumerate(eval_data),
+                eval_data,
                 total=len(eval_data),
+                ncols=100,
                 desc=set_color(f"Evaluate   ", 'pink'),
-            ) if show_progress else enumerate(eval_data)
+            ) if show_progress else eval_data
         )
-        for batch_idx, batched_data in iter_data:
-            if eval_data.dl_type == DataLoaderType.FULL:
-                interaction, scores = self._full_sort_batch_eval(batched_data)
-            else:
-                interaction = batched_data
-                batch_size = interaction.length
-                if batch_size <= self.test_batch_size:
-                    scores = self.model.predict(interaction.to(self.device))
-                else:
-                    scores = self._spilt_predict(interaction, batch_size)
-
-            batch_matrix = self.evaluator.collect(interaction, scores)
-            batch_matrix_list.append(batch_matrix)
-        result = self.evaluator.evaluate(batch_matrix_list, eval_data)
+        for batch_idx, batched_data in enumerate(iter_data):
+            interaction, scores, positive_u, positive_i = eval_func(batched_data)
+            if self.gpu_available and show_progress:
+                iter_data.set_postfix_str(set_color('GPU RAM: ' + get_gpu_usage(self.device), 'yellow'))
+            self.eval_collector.eval_batch_collect(scores, interaction, positive_u, positive_i)
+        self.eval_collector.model_collect(self.model)
+        struct = self.eval_collector.get_data_struct()
+        result = self.evaluator.evaluate(struct)
 
         return result
 
@@ -431,30 +482,6 @@ def _spilt_predict(self, interaction, batch_size):
             result_list.append(result)
         return torch.cat(result_list, dim=0)
 
-    def plot_train_loss(self, show=True, save_path=None):
-        r"""Plot the train loss in each epoch
-
-        Args:
-            show (bool, optional): Whether to show this figure, default: True
-            save_path (str, optional): The data path to save the figure, default: None.
-                                       If it's None, it will not be saved.
-        """
-        import matplotlib.pyplot as plt
-        import time
-        epochs = list(self.train_loss_dict.keys())
-        epochs.sort()
-        values = [float(self.train_loss_dict[epoch]) for epoch in epochs]
-        plt.plot(epochs, values)
-        my_x_ticks = np.arange(0, len(epochs), int(len(epochs) / 10))
-        plt.xticks(my_x_ticks)
-        plt.xlabel('Epoch')
-        plt.ylabel('Loss')
-        plt.title(self.config['model'] + ' ' + time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time())))
-        if show:
-            plt.show()
-        if save_path:
-            plt.savefig(save_path)
-
 
 class KGTrainer(Trainer):
     r"""KGTrainer is designed for Knowledge-aware recommendation methods. Some of these models need to train the
@@ -512,14 +539,15 @@ def _train_epoch(self, train_data, epoch_idx, loss_func=None, show_progress=Fals
         return rs_total_loss, kg_total_loss
 
 
-class S3RecTrainer(Trainer):
-    r"""S3RecTrainer is designed for S3Rec, which is a self-supervised learning based sequential recommenders.
-        It includes two training stages: pre-training ang fine-tuning.
-
-        """
+class PretrainTrainer(Trainer):
+    r"""PretrainTrainer is designed for pre-training.
+    It can be inherited by the trainer which needs pre-training and fine-tuning.
+    """
 
     def __init__(self, config, model):
-        super(S3RecTrainer, self).__init__(config, model)
+        super(PretrainTrainer, self).__init__(config, model)
+        self.pretrain_epochs = self.config['pretrain_epochs']
+        self.save_step = self.config['save_step']
 
     def save_pretrained_model(self, epoch, saved_model_file):
         r"""Store the model parameters information and training information.
@@ -538,8 +566,7 @@ def save_pretrained_model(self, epoch, saved_model_file):
         torch.save(state, saved_model_file)
 
     def pretrain(self, train_data, verbose=True, show_progress=False):
-
-        for epoch_idx in range(self.start_epoch, self.epochs):
+        for epoch_idx in range(self.start_epoch, self.pretrain_epochs):
             # train
             training_start_time = time()
             train_loss = self._train_epoch(train_data, epoch_idx, show_progress=show_progress)
@@ -549,8 +576,9 @@ def pretrain(self, train_data, verbose=True, show_progress=False):
                 self._generate_train_loss_output(epoch_idx, training_start_time, training_end_time, train_loss)
             if verbose:
                 self.logger.info(train_loss_output)
+            self._add_train_loss_to_tensorboard(epoch_idx, train_loss)
 
-            if (epoch_idx + 1) % self.config['save_step'] == 0:
+            if (epoch_idx + 1) % self.save_step == 0:
                 saved_model_file = os.path.join(
                     self.checkpoint_dir,
                     '{}-{}-{}.pth'.format(self.config['model'], self.config['dataset'], str(epoch_idx + 1))
@@ -562,13 +590,23 @@ def pretrain(self, train_data, verbose=True, show_progress=False):
 
         return self.best_valid_score, self.best_valid_result
 
+
+class S3RecTrainer(PretrainTrainer):
+    r"""S3RecTrainer is designed for S3Rec, which is a self-supervised learning based sequential recommenders.
+        It includes two training stages: pre-training ang fine-tuning.
+
+        """
+
+    def __init__(self, config, model):
+        super(S3RecTrainer, self).__init__(config, model)
+
     def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progress=False, callback_fn=None):
         if self.model.train_stage == 'pretrain':
             return self.pretrain(train_data, verbose, show_progress)
         elif self.model.train_stage == 'finetune':
             return super().fit(train_data, valid_data, verbose, saved, show_progress, callback_fn)
         else:
-            raise ValueError("Please make sure that the 'train_stage' is 'pretrain' or 'finetune' ")
+            raise ValueError("Please make sure that the 'train_stage' is 'pretrain' or 'finetune'!")
 
 
 class MKRTrainer(Trainer):
@@ -620,6 +658,7 @@ def __init__(self, config, model):
         super(DecisionTreeTrainer, self).__init__(config, model)
 
         self.logger = getLogger()
+        self.tensorboard = get_tensorboard(self.logger)
         self.label_field = config['LABEL_FIELD']
         self.convert_token_to_onehot = self.config['convert_token_to_onehot']
 
@@ -628,15 +667,24 @@ def __init__(self, config, model):
         self.epochs = config['epochs']
         self.eval_step = min(config['eval_step'], self.epochs)
         self.valid_metric = config['valid_metric'].lower()
-
-        self.evaluator = ProxyEvaluator(config)
+        self.eval_collector = Collector(config)
+        self.evaluator = Evaluator(config)
 
         # model saved
         self.checkpoint_dir = config['checkpoint_dir']
         ensure_dir(self.checkpoint_dir)
+        temp_file = '{}-{}-temp.pth'.format(self.config['model'], get_local_time())
+        self.temp_file = os.path.join(self.checkpoint_dir, temp_file)
+
         saved_model_file = '{}-{}.pth'.format(self.config['model'], get_local_time())
         self.saved_model_file = os.path.join(self.checkpoint_dir, saved_model_file)
 
+        self.stopping_step = config['stopping_step']
+        self.valid_metric_bigger = config['valid_metric_bigger']
+        self.cur_step = 0
+        self.best_valid_score = -np.inf if self.valid_metric_bigger else np.inf
+        self.best_valid_result = None
+
     def _interaction_to_sparse(self, dataloader):
         r"""Convert data format from interaction to sparse or numpy
 
@@ -659,7 +707,7 @@ def _interaction_to_sparse(self, dataloader):
                 else:
                     cur_data = np.hstack((cur_data, value))
 
-        if self.convert_token_to_onehot == True:
+        if self.convert_token_to_onehot:
             from scipy import sparse
             from scipy.sparse import dok_matrix
             convert_col_list = dataloader.dataset.convert_col_list
@@ -697,25 +745,27 @@ def _valid_epoch(self, valid_data):
         Args:
             valid_data (DecisionTreeDataLoader): DecisionTreeDataLoader, which is the same with GeneralDataLoader.
         """
-        valid_result = self.evaluate(valid_data)
+        valid_result = self.evaluate(valid_data, load_best_model=False)
         valid_score = calculate_valid_score(valid_result, self.valid_metric)
-        return valid_result, valid_score
+        return valid_score, valid_result
 
     def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progress=False):
-        # load model
-        if self.boost_model is not None:
-            self.model.load_model(self.boost_model)
-
-        self.best_valid_score = 0.
-        self.best_valid_result = 0.
-
         for epoch_idx in range(self.epochs):
             self._train_at_once(train_data, valid_data)
 
             if (epoch_idx + 1) % self.eval_step == 0:
                 # evaluate
                 valid_start_time = time()
-                valid_result, valid_score = self._valid_epoch(valid_data)
+                valid_score, valid_result = self._valid_epoch(valid_data)
+
+                self.best_valid_score, self.cur_step, stop_flag, update_flag = early_stopping(
+                    valid_score,
+                    self.best_valid_score,
+                    self.cur_step,
+                    max_step=self.stopping_step,
+                    bigger=self.valid_metric_bigger
+                )
+
                 valid_end_time = time()
                 valid_score_output = (set_color("epoch %d evaluating", 'green') + " [" + set_color("time", 'blue')
                                     + ": %.2fs, " + set_color("valid_score", 'blue') + ": %f]") % \
@@ -724,14 +774,30 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
                 if verbose:
                     self.logger.info(valid_score_output)
                     self.logger.info(valid_result_output)
+                self.tensorboard.add_scalar('Vaild_score', valid_score, epoch_idx)
 
-                self.best_valid_score = valid_score
-                self.best_valid_result = valid_result
+                if update_flag:
+                    if saved:
+                        self.model.save_model(self.saved_model_file)
+                        update_output = set_color('Saving current best', 'blue') + ': %s' % self.saved_model_file
+                        if verbose:
+                            self.logger.info(update_output)
+                    self.best_valid_result = valid_result
+
+                if stop_flag:
+                    stop_output = 'Finished training, best eval result in epoch %d' % \
+                                  (epoch_idx - self.cur_step * self.eval_step)
+                    if verbose:
+                        self.logger.info(stop_output)
+                    break
 
         return self.best_valid_score, self.best_valid_result
 
-    def evaluate(self, eval_data):
-        pass
+    def evaluate(self, eval_data, load_best_model=True, model_file=None, show_progress=False):
+        raise NotImplementedError
+
+    def _train_at_once(self, train_data, valid_data):
+        raise NotImplementedError
 
 
 class xgboostTrainer(DecisionTreeTrainer):
@@ -755,6 +821,8 @@ def __init__(self, config, model):
         self.evals_result = {}
         self.verbose_eval = config['xgb_verbose_eval']
         self.callbacks = None
+        self.deval = None
+        self.eval_pred = self.eval_true = None
 
     def _interaction_to_lib_datatype(self, dataloader):
         r"""Convert data format from interaction to DMatrix
@@ -789,72 +857,34 @@ def _train_at_once(self, train_data, valid_data):
             callbacks=self.callbacks
         )
 
-        self.model.save_model(self.saved_model_file)
-        self.boost_model = self.saved_model_file
+        self.model.save_model(self.temp_file)
+        self.boost_model = self.temp_file
 
     def evaluate(self, eval_data, load_best_model=True, model_file=None, show_progress=False):
-        self.eval_pred = torch.Tensor()
-        self.eval_true = torch.Tensor()
+        if load_best_model:
+            if model_file:
+                checkpoint_file = model_file
+            else:
+                checkpoint_file = self.saved_model_file
+            self.model.load_model(checkpoint_file)
 
         self.deval = self._interaction_to_lib_datatype(eval_data)
         self.eval_true = torch.Tensor(self.deval.get_label())
         self.eval_pred = torch.Tensor(self.model.predict(self.deval))
 
-        batch_matrix_list = [[torch.stack((self.eval_true, self.eval_pred), 1)]]
-        result = self.evaluator.evaluate(batch_matrix_list, eval_data)
+        self.eval_collector.eval_collect(self.eval_pred, self.eval_true)
+        result = self.evaluator.evaluate(self.eval_collector.get_data_struct())
         return result
 
 
-class RaCTTrainer(Trainer):
+class RaCTTrainer(PretrainTrainer):
     r"""RaCTTrainer is designed for RaCT, which is an actor-critic reinforcement learning based general recommenders.
-        It includes three training stages: actor pre-training, critic pre-training and actor-critic training. 
+        It includes three training stages: actor pre-training, critic pre-training and actor-critic training.
 
         """
 
     def __init__(self, config, model):
         super(RaCTTrainer, self).__init__(config, model)
-        self.pretrain_epochs = self.config['pretrain_epochs']
-
-    def save_pretrained_model(self, epoch, saved_model_file):
-        r"""Store the model parameters information and training information.
-
-        Args:
-            epoch (int): the current epoch id
-            saved_model_file (str): file name for saved pretrained model
-
-        """
-        state = {
-            'config': self.config,
-            'epoch': epoch,
-            'state_dict': self.model.state_dict(),
-            'optimizer': self.optimizer.state_dict(),
-        }
-        torch.save(state, saved_model_file)
-
-    def pretrain(self, train_data, verbose=True, show_progress=False):
-
-        for epoch_idx in range(self.start_epoch, self.pretrain_epochs):
-            # train
-            training_start_time = time()
-            train_loss = self._train_epoch(train_data, epoch_idx, show_progress=show_progress)
-            self.train_loss_dict[epoch_idx] = sum(train_loss) if isinstance(train_loss, tuple) else train_loss
-            training_end_time = time()
-            train_loss_output = \
-                self._generate_train_loss_output(epoch_idx, training_start_time, training_end_time, train_loss)
-            if verbose:
-                self.logger.info(train_loss_output)
-
-            if (epoch_idx + 1) % self.pretrain_epochs == 0:
-                saved_model_file = os.path.join(
-                    self.checkpoint_dir,
-                    '{}-{}-{}.pth'.format(self.config['model'], self.config['dataset'], str(epoch_idx + 1))
-                )
-                self.save_pretrained_model(epoch_idx, saved_model_file)
-                update_output = 'Saving current: %s' % saved_model_file
-                if verbose:
-                    self.logger.info(update_output)
-
-        return self.best_valid_score, self.best_valid_result
 
     def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progress=False, callback_fn=None):
         if self.model.train_stage == 'actor_pretrain':
@@ -864,7 +894,10 @@ def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progre
         elif self.model.train_stage == 'finetune':
             return super().fit(train_data, valid_data, verbose, saved, show_progress, callback_fn)
         else:
-            raise ValueError("Please make sure that the 'train_stage' is 'pretrain' or 'finetune' ")
+            raise ValueError(
+                "Please make sure that the 'train_stage' is "
+                "'actor_pretrain', 'critic_pretrain' or 'finetune'!"
+            )
 
 
 class lightgbmTrainer(DecisionTreeTrainer):
@@ -888,6 +921,8 @@ def __init__(self, config, model):
         self.verbose_eval = config['lgb_verbose_eval']
         self.learning_rates = config['lgb_learning_rates']
         self.callbacks = None
+        self.deval_data = self.deval_label = None
+        self.eval_pred = self.eval_true = None
 
     def _interaction_to_lib_datatype(self, dataloader):
         r"""Convert data format from interaction to Dataset
@@ -923,19 +958,23 @@ def _train_at_once(self, train_data, valid_data):
             callbacks=self.callbacks
         )
 
-        self.model.save_model(self.saved_model_file)
-        self.boost_model = self.saved_model_file
+        self.model.save_model(self.temp_file)
+        self.boost_model = self.temp_file
 
     def evaluate(self, eval_data, load_best_model=True, model_file=None, show_progress=False):
-        self.eval_pred = torch.Tensor()
-        self.eval_true = torch.Tensor()
+        if load_best_model:
+            if model_file:
+                checkpoint_file = model_file
+            else:
+                checkpoint_file = self.saved_model_file
+            self.model = self.lgb.Booster(model_file=checkpoint_file)
 
         self.deval_data, self.deval_label = self._interaction_to_sparse(eval_data)
         self.eval_true = torch.Tensor(self.deval_label)
         self.eval_pred = torch.Tensor(self.model.predict(self.deval_data))
 
-        batch_matrix_list = [[torch.stack((self.eval_true, self.eval_pred), 1)]]
-        result = self.evaluator.evaluate(batch_matrix_list, eval_data)
+        self.eval_collector.eval_collect(self.eval_pred, self.eval_true)
+        result = self.evaluator.evaluate(self.eval_collector.get_data_struct())
         return result
 
 
@@ -949,117 +988,21 @@ def __init__(self, config, model):
         self.n_enc_epochs = config['n_enc_epochs']
         self.n_dec_epochs = config['n_dec_epochs']
 
-    def _train_epoch(
-        self, train_data, epoch_idx, n_epochs, optimizer, encoder_flag, loss_func=None, show_progress=False
-    ):
-        self.model.train()
-        loss_func = loss_func or self.model.calculate_loss
-        total_loss = None
-        iter_data = (
-            tqdm(
-                enumerate(train_data),
-                total=len(train_data),
-                desc=set_color(f"Train {epoch_idx:>5}", 'pink'),
-            ) if show_progress else enumerate(train_data)
-        )
-        for epoch in range(n_epochs):
-            for batch_idx, interaction in iter_data:
-                interaction = interaction.to(self.device)
-                optimizer.zero_grad()
-                losses = loss_func(interaction, encoder_flag=encoder_flag)
-                if isinstance(losses, tuple):
-                    loss = sum(losses)
-                    loss_tuple = tuple(per_loss.item() for per_loss in losses)
-                    total_loss = loss_tuple if total_loss is None else tuple(map(sum, zip(total_loss, loss_tuple)))
-                else:
-                    loss = losses
-                    total_loss = losses.item() if total_loss is None else total_loss + losses.item()
-                self._check_nan(loss)
-                loss.backward()
-                if self.clip_grad_norm:
-                    clip_grad_norm_(self.model.parameters(), **self.clip_grad_norm)
-                optimizer.step()
-
-        return total_loss
-
-    def fit(self, train_data, valid_data=None, verbose=True, saved=True, show_progress=False, callback_fn=None):
-        if saved and self.start_epoch >= self.epochs:
-            self._save_checkpoint(-1)
+        self.optimizer_encoder = self._build_optimizer(self.model.encoder.parameters())
+        self.optimizer_decoder = self._build_optimizer(self.model.decoder.parameters())
 
-        encoder_params = set(self.model.encoder.parameters())
-        decoder_params = set(self.model.decoder.parameters())
-
-        optimizer_encoder = self._build_optimizer(encoder_params)
-        optimizer_decoder = self._build_optimizer(decoder_params)
-
-        for epoch_idx in range(self.start_epoch, self.epochs):
-            # alternate training
-            training_start_time = time()
-            train_loss = self._train_epoch(
-                train_data,
-                epoch_idx,
-                show_progress=show_progress,
-                n_epochs=self.n_enc_epochs,
-                encoder_flag=True,
-                optimizer=optimizer_encoder
-            )
-            self.model.update_prior()
-            train_loss = self._train_epoch(
-                train_data,
-                epoch_idx,
-                show_progress=show_progress,
-                n_epochs=self.n_dec_epochs,
-                encoder_flag=False,
-                optimizer=optimizer_decoder
+    def _train_epoch(self, train_data, epoch_idx, loss_func=None, show_progress=False):
+        self.optimizer = self.optimizer_encoder
+        encoder_loss_func = lambda data: self.model.calculate_loss(data, encoder_flag=True)
+        for epoch in range(self.n_enc_epochs):
+            super()._train_epoch(train_data, epoch_idx, loss_func=encoder_loss_func, show_progress=show_progress)
+
+        self.model.update_prior()
+        loss = 0.0
+        self.optimizer = self.optimizer_decoder
+        decoder_loss_func = lambda data: self.model.calculate_loss(data, encoder_flag=False)
+        for epoch in range(self.n_dec_epochs):
+            loss += super()._train_epoch(
+                train_data, epoch_idx, loss_func=decoder_loss_func, show_progress=show_progress
             )
-            self.train_loss_dict[epoch_idx] = sum(train_loss) if isinstance(train_loss, tuple) else train_loss
-            training_end_time = time()
-            train_loss_output = \
-                self._generate_train_loss_output(epoch_idx, training_start_time, training_end_time, train_loss)
-            if verbose:
-                self.logger.info(train_loss_output)
-
-            # eval
-            if self.eval_step <= 0 or not valid_data:
-                if saved:
-                    self._save_checkpoint(epoch_idx)
-                    update_output = 'Saving current: %s' % self.saved_model_file
-                    if verbose:
-                        self.logger.info(update_output)
-                continue
-            if (epoch_idx + 1) % self.eval_step == 0:
-                valid_start_time = time()
-                valid_score, valid_result = self._valid_epoch(valid_data, show_progress=show_progress)
-                self.best_valid_score, self.cur_step, stop_flag, update_flag = early_stopping(
-                    valid_score,
-                    self.best_valid_score,
-                    self.cur_step,
-                    max_step=self.stopping_step,
-                    bigger=self.valid_metric_bigger
-                )
-                valid_end_time = time()
-                valid_score_output = (set_color("epoch %d evaluating", 'green') + " [" + set_color("time", 'blue')
-                                    + ": %.2fs, " + set_color("valid_score", 'blue') + ": %f]") % \
-                                     (epoch_idx, valid_end_time - valid_start_time, valid_score)
-                valid_result_output = set_color('valid result', 'blue') + ': \n' + dict2str(valid_result)
-                if verbose:
-                    self.logger.info(valid_score_output)
-                    self.logger.info(valid_result_output)
-                if update_flag:
-                    if saved:
-                        self._save_checkpoint(epoch_idx)
-                        update_output = set_color('Saving current best', 'blue') + ': %s' % self.saved_model_file
-                        if verbose:
-                            self.logger.info(update_output)
-                    self.best_valid_result = valid_result
-
-                if callback_fn:
-                    callback_fn(epoch_idx, valid_score)
-
-                if stop_flag:
-                    stop_output = 'Finished training, best eval result in epoch %d' % \
-                                  (epoch_idx - self.cur_step * self.eval_step)
-                    if verbose:
-                        self.logger.info(stop_output)
-                    break
-        return self.best_valid_score, self.best_valid_result
+        return loss
diff --git a/recbole/utils/__init__.py b/recbole/utils/__init__.py
index 22240e0aa..5b6ef50b3 100644
--- a/recbole/utils/__init__.py
+++ b/recbole/utils/__init__.py
@@ -1,12 +1,12 @@
-from recbole.utils.logger import init_logger
+from recbole.utils.logger import init_logger, set_color
 from recbole.utils.utils import get_local_time, ensure_dir, get_model, get_trainer, \
-    early_stopping, calculate_valid_score, dict2str, init_seed
+    early_stopping, calculate_valid_score, dict2str, init_seed, get_tensorboard, get_gpu_usage
 from recbole.utils.enum_type import *
 from recbole.utils.argument_list import *
 
 __all__ = [
     'init_logger', 'get_local_time', 'ensure_dir', 'get_model', 'get_trainer', 'early_stopping',
-    'calculate_valid_score', 'dict2str', 'Enum', 'ModelType', 'DataLoaderType', 'KGDataLoaderState', 'EvaluatorType',
-    'InputType', 'FeatureType', 'FeatureSource', 'init_seed', 'general_arguments', 'training_arguments',
-    'evaluation_arguments', 'dataset_arguments'
+    'calculate_valid_score', 'dict2str', 'Enum', 'ModelType', 'KGDataLoaderState', 'EvaluatorType', 'InputType',
+    'FeatureType', 'FeatureSource', 'init_seed', 'general_arguments', 'training_arguments', 'evaluation_arguments',
+    'dataset_arguments', 'get_tensorboard', 'set_color', 'get_gpu_usage'
 ]
diff --git a/recbole/utils/argument_list.py b/recbole/utils/argument_list.py
index 632f442bd..9b13d6c08 100644
--- a/recbole/utils/argument_list.py
+++ b/recbole/utils/argument_list.py
@@ -10,7 +10,11 @@
     'reproducibility',
     'state',
     'data_path',
+    'benchmark_filename',
     'show_progress',
+    'config_file',
+    'save_dataset',
+    'save_dataloaders',
 ]
 
 training_arguments = [
@@ -22,16 +26,12 @@
     'checkpoint_dir',
     'clip_grad_norm',
     'loss_decimal_place',
-    'weight_decay',
-    'draw_loss_pic'
+    'weight_decay'
 ]
 
 evaluation_arguments = [
-    'eval_setting',
-    'group_by_user',
-    'split_ratio', 'leave_one_num',
-    'real_time_process',
-    'metrics', 'topk', 'valid_metric',
+    'eval_args',
+    'metrics', 'topk', 'valid_metric', 'valid_metric_bigger',
     'eval_batch_size',
     'metric_decimal_place'
 ]
@@ -45,9 +45,9 @@
     'ITEM_LIST_LENGTH_FIELD', 'LIST_SUFFIX', 'MAX_ITEM_LIST_LENGTH', 'POSITION_FIELD',
     'HEAD_ENTITY_ID_FIELD', 'TAIL_ENTITY_ID_FIELD', 'RELATION_ID_FIELD', 'ENTITY_ID_FIELD',
     'load_col', 'unload_col', 'unused_col', 'additional_feat_suffix',
-    'max_user_inter_num', 'min_user_inter_num', 'max_item_inter_num', 'min_item_inter_num',
-    'lowest_val', 'highest_val', 'equal_val', 'not_equal_val',
-    'fields_in_same_space',
+    'filter_inter_by_user_or_item', 'rm_dup_inter',
+    'val_interval', 'user_inter_num_interval', 'item_inter_num_interval',
+    'alias_of_user_id', 'alias_of_item_id', 'alias_of_entity_id', 'alias_of_relation_id',
     'preload_weight',
     'normalize_field', 'normalize_all'
 ]
diff --git a/recbole/utils/case_study.py b/recbole/utils/case_study.py
index d8a3b38de..5430f5cb1 100644
--- a/recbole/utils/case_study.py
+++ b/recbole/utils/case_study.py
@@ -15,51 +15,49 @@
 import numpy as np
 import torch
 
-from recbole.data.dataloader.general_dataloader import GeneralFullDataLoader
-from recbole.data.dataloader.sequential_dataloader import SequentialFullDataLoader
-
 
 @torch.no_grad()
-def full_sort_scores(uid_series, model, test_data):
+def full_sort_scores(uid_series, model, test_data, device=None):
     """Calculate the scores of all items for each user in uid_series.
 
     Note:
         The score of [pad] and history items will be set into -inf.
 
     Args:
-        uid_series (numpy.ndarray): User id series
-        model (AbstractRecommender): Model to predict
-        test_data (AbstractDataLoader): The test_data of model
+        uid_series (numpy.ndarray or list): User id series.
+        model (AbstractRecommender): Model to predict.
+        test_data (FullSortEvalDataLoader): The test_data of model.
+        device (torch.device, optional): The device which model will run on. Defaults to ``None``.
+            Note: ``device=None`` is equivalent to ``device=torch.device('cpu')``.
 
     Returns:
         torch.Tensor: the scores of all items for each user in uid_series.
     """
+    device = device or torch.device('cpu')
+    uid_series = np.array(uid_series)
     uid_field = test_data.dataset.uid_field
     dataset = test_data.dataset
     model.eval()
 
-    if isinstance(test_data, GeneralFullDataLoader):
+    if not test_data.is_sequential:
         index = np.isin(test_data.user_df[uid_field].numpy(), uid_series)
         input_interaction = test_data.user_df[index]
-        history_item = test_data.uid2history_item[input_interaction[uid_field].numpy()]
+        history_item = test_data.uid2history_item[uid_series]
         history_row = torch.cat([torch.full_like(hist_iid, i) for i, hist_iid in enumerate(history_item)])
         history_col = torch.cat(list(history_item))
         history_index = history_row, history_col
-    elif isinstance(test_data, SequentialFullDataLoader):
-        index = np.isin(test_data.uid_list, uid_series)
-        input_interaction = test_data.augmentation(
-            test_data.item_list_index[index], test_data.target_index[index], test_data.item_list_length[index]
-        )
-        history_index = None
     else:
-        raise NotImplementedError
+        index = np.isin(dataset[uid_field].numpy(), uid_series)
+        input_interaction = dataset[index]
+        history_index = None
 
     # Get scores of all items
+    input_interaction = input_interaction.to(device)
     try:
         scores = model.full_sort_predict(input_interaction)
     except NotImplementedError:
         input_interaction = input_interaction.repeat(dataset.item_num)
-        input_interaction.update(test_data.get_item_feature().repeat(len(uid_series)))
+        input_interaction.update(test_data.dataset.get_item_feature().to(device).repeat(len(uid_series)))
         scores = model.predict(input_interaction)
 
     scores = scores.view(-1, dataset.item_num)
@@ -70,19 +68,24 @@ def full_sort_scores(uid_series, model, test_data):
     return scores
 
 
-def full_sort_topk(uid_series, model, test_data, k):
+def full_sort_topk(uid_series, model, test_data, k, device=None):
     """Calculate the top-k items' scores and ids for each user in uid_series.
 
+    Note:
+        The score of [pad] and history items will be set into -inf.
+
     Args:
-        uid_series (numpy.ndarray): User id series
-        model (AbstractRecommender): Model to predict
-        test_data (AbstractDataLoader): The test_data of model
+        uid_series (numpy.ndarray): User id series.
+        model (AbstractRecommender): Model to predict.
+        test_data (FullSortEvalDataLoader): The test_data of model.
         k (int): The top-k items.
+        device (torch.device, optional): The device which model will run on. Defaults to ``None``.
+            Note: ``device=None`` is equivalent to ``device=torch.device('cpu')``.
 
     Returns:
         tuple:
             - topk_scores (torch.Tensor): The scores of topk items.
             - topk_index (torch.Tensor): The index of topk items, which is also the internal ids of items.
     """
-    scores = full_sort_scores(uid_series, model, test_data)
+    scores = full_sort_scores(uid_series, model, test_data, device)
     return torch.topk(scores, k)
diff --git a/recbole/utils/enum_type.py b/recbole/utils/enum_type.py
index ebc1faea7..1b07fc23f 100644
--- a/recbole/utils/enum_type.py
+++ b/recbole/utils/enum_type.py
@@ -24,22 +24,8 @@ class ModelType(Enum):
     SEQUENTIAL = 2
     CONTEXT = 3
     KNOWLEDGE = 4
-    SOCIAL = 5
-    TRADITIONAL = 6
-    DECISIONTREE = 7
-
-
-class DataLoaderType(Enum):
-    """Type of DataLoaders.
-
-    - ``ORIGIN``: Original DataLoader
-    - ``FULL``: DataLoader for full-sort evaluation
-    - ``NEGSAMPLE``: DataLoader for negative sample evaluation
-    """
-
-    ORIGIN = 1
-    FULL = 2
-    NEGSAMPLE = 3
+    TRADITIONAL = 5
+    DECISIONTREE = 6
 
 
 class KGDataLoaderState(Enum):
@@ -58,12 +44,12 @@ class KGDataLoaderState(Enum):
 class EvaluatorType(Enum):
     """Type for evaluation metrics.
 
-    - ``RANKING``: Ranking metrics like NDCG, Recall, etc.
-    - ``INDIVIDUAL``: Individual metrics like AUC, etc.
+    - ``RANKING``: Ranking-based metrics like NDCG, Recall, etc.
+    - ``VALUE``: Value-based metrics like AUC, etc.
     """
 
     RANKING = 1
-    INDIVIDUAL = 2
+    VALUE = 2
 
 
 class InputType(Enum):
diff --git a/recbole/utils/logger.py b/recbole/utils/logger.py
index f3fb17185..d5d5d52ca 100644
--- a/recbole/utils/logger.py
+++ b/recbole/utils/logger.py
@@ -16,6 +16,7 @@
 import logging
 import os
 import colorlog
+import re
 
 from recbole.utils.utils import get_local_time, ensure_dir
 from colorama import init
@@ -28,6 +29,30 @@
 }
 
 
+class RemoveColorFilter(logging.Filter):
+
+    def filter(self, record):
+        if record:
+            ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
+            record.msg = ansi_escape.sub('', str(record.msg))
+        return True
+
+
+def set_color(log, color, highlight=True):
+    color_set = ['black', 'red', 'green', 'yellow', 'blue', 'pink', 'cyan', 'white']
+    try:
+        index = color_set.index(color)
+    except:
+        index = len(color_set) - 1
+    prev_log = '\033['
+    if highlight:
+        prev_log += '1;3'
+    else:
+        prev_log += '0;3'
+    prev_log += str(index) + 'm'
+    return prev_log + log + '\033[0m'
+
+
 def init_logger(config):
     """
     A logger that can show a message on standard output and write it into the
@@ -70,12 +95,15 @@ def init_logger(config):
         level = logging.CRITICAL
     else:
         level = logging.INFO
+
     fh = logging.FileHandler(logfilepath)
     fh.setLevel(level)
     fh.setFormatter(fileformatter)
+    remove_color_filter = RemoveColorFilter()
+    fh.addFilter(remove_color_filter)
 
     sh = logging.StreamHandler()
     sh.setLevel(level)
     sh.setFormatter(sformatter)
 
-    logging.basicConfig(level=level, handlers=[fh, sh])
+    logging.basicConfig(level=level, handlers=[sh, fh])
diff --git a/recbole/utils/url.py b/recbole/utils/url.py
new file mode 100644
index 000000000..cd7b99f8b
--- /dev/null
+++ b/recbole/utils/url.py
@@ -0,0 +1,114 @@
+'''
+recbole.utils.url
+################################
+Reference code:
+    https://github.com/snap-stanford/ogb/blob/master/ogb/utils/url.py
+'''
+
+import urllib.request as ur
+import zipfile
+import os
+import os.path as osp
+import errno
+from logging import getLogger
+
+from tqdm import tqdm
+
+GBFACTOR = float(1 << 30)
+
+
+def decide_download(url):
+    d = ur.urlopen(url)
+    size = int(d.info()['Content-Length']) / GBFACTOR
+
+    ### confirm if larger than 1GB
+    if size > 1:
+        return input('This will download %.2fGB. Will you proceed? (y/N)\n' % (size)).lower() == 'y'
+    else:
+        return True
+
+
+def makedirs(path):
+    try:
+        os.makedirs(osp.expanduser(osp.normpath(path)))
+    except OSError as e:
+        if e.errno != errno.EEXIST and osp.isdir(path):
+            raise e
+
+
+def download_url(url, folder):
+    '''Downloads the content of an URL to a specific folder.
+
+    Args:
+        url (string): The url.
+        folder (string): The folder.
+    '''
+
+    filename = url.rpartition('/')[2]
+    path = osp.join(folder, filename)
+    logger = getLogger()
+
+    if osp.exists(path) and osp.getsize(path) > 0:  # pragma: no cover
+        logger.info(f'Using exist file {filename}')
+        return path
+
+    logger.info(f'Downloading {url}')
+
+    makedirs(folder)
+    data = ur.urlopen(url)
+
+    size = int(data.info()['Content-Length'])
+
+    chunk_size = 1024 * 1024
+    num_iter = int(size / chunk_size) + 2
+
+    downloaded_size = 0
+
+    try:
+        with open(path, 'wb') as f:
+            pbar = tqdm(range(num_iter))
+            for i in pbar:
+                chunk = data.read(chunk_size)
+                downloaded_size += len(chunk)
+                pbar.set_description('Downloaded {:.2f} GB'.format(float(downloaded_size) / GBFACTOR))
+                f.write(chunk)
+    except:
+        if os.path.exists(path):
+            os.remove(path)
+        raise RuntimeError('Stopped downloading due to interruption.')
+
+    return path
+
+
+def extract_zip(path, folder):
+    '''Extracts a zip archive to a specific folder.
+
+    Args:
+        path (string): The path to the tar archive.
+        folder (string): The folder.
+    '''
+    logger = getLogger()
+    logger.info(f'Extracting {path}')
+    with zipfile.ZipFile(path, 'r') as f:
+        f.extractall(folder)
+
+
+def rename_atomic_files(folder, old_name, new_name):
+    '''Rename all atomic files in a given folder.
+
+    Args:
+        folder (string): The folder.
+        old_name (string): Old name for atomic files.
+        new_name (string): New name for atomic files.
+    '''
+    files = os.listdir(folder)
+    for f in files:
+        base, suf = os.path.splitext(f)
+        if not old_name in base:
+            continue
+        assert suf in {'.inter', '.user', '.item'}
+        os.rename(os.path.join(folder, f), os.path.join(folder, base.replace(old_name, new_name) + suf))
+
+
+if __name__ == '__main__':
+    pass
diff --git a/recbole/utils/utils.py b/recbole/utils/utils.py
index 6070f2e57..02c4714df 100644
--- a/recbole/utils/utils.py
+++ b/recbole/utils/utils.py
@@ -20,6 +20,7 @@
 
 import numpy as np
 import torch
+from torch.utils.tensorboard import SummaryWriter
 
 from recbole.utils.enum_type import ModelType
 
@@ -192,16 +193,43 @@ def init_seed(seed, reproducibility):
         torch.backends.cudnn.deterministic = False
 
 
-def set_color(log, color, highlight=True):
-    color_set = ['black', 'red', 'green', 'yellow', 'blue', 'pink', 'cyan', 'white']
-    try:
-        index = color_set.index(color)
-    except:
-        index = len(color_set) - 1
-    prev_log = '\033['
-    if highlight:
-        prev_log += '1;3'
-    else:
-        prev_log += '0;3'
-    prev_log += str(index) + 'm'
-    return prev_log + log + '\033[0m'
+def get_tensorboard(logger):
+    r""" Creates a SummaryWriter of Tensorboard that can log PyTorch models and metrics into a directory for 
+    visualization within the TensorBoard UI.
+    For the convenience of the user, the naming rule of the SummaryWriter's log_dir is the same as the logger.
+
+    Args:
+        logger: its output filename is used to name the SummaryWriter's log_dir.
+                If the filename is not available, we will name the log_dir according to the current time.
+
+    Returns:
+        SummaryWriter: it will write out events and summaries to the event file.
+    """
+    base_path = 'log_tensorboard'
+
+    dir_name = None
+    for handler in logger.handlers:
+        if hasattr(handler, "baseFilename"):
+            dir_name = os.path.basename(getattr(handler, 'baseFilename')).split('.')[0]
+            break
+    if dir_name is None:
+        dir_name = '{}-{}'.format('model', get_local_time())
+
+    dir_path = os.path.join(base_path, dir_name)
+    writer = SummaryWriter(dir_path)
+    return writer
+
+
+def get_gpu_usage(device=None):
+    r""" Return the reserved memory and total memory of given device in a string.
+    Args:
+        device: cuda.device. It is the device that the model run on.
+
+    Returns:
+        str: it contains the info about reserved memory and total memory of given device.
+    """
+
+    reserved = torch.cuda.max_memory_reserved(device) / 1024 ** 3
+    total = torch.cuda.get_device_properties(device).total_memory / 1024 ** 3
+
+    return '{:.2f} G/{:.2f} G'.format(reserved, total)
diff --git a/requirements.txt b/requirements.txt
index 9cf90921e..eccaef92e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
-matplotlib>=3.1.3
 torch>=1.7.0
 numpy>=1.17.2
 scipy==1.6.0
@@ -8,4 +7,5 @@ tqdm>=4.48.2
 scikit_learn>=0.23.2
 pyyaml>=5.1.0
 colorlog==4.7.2
-colorama==0.4.4
\ No newline at end of file
+colorama==0.4.4
+tensorboard>=2.5.0
\ No newline at end of file
diff --git a/run_example/case_study_example.py b/run_example/case_study_example.py
index e739fab97..c23ff9b09 100644
--- a/run_example/case_study_example.py
+++ b/run_example/case_study_example.py
@@ -11,40 +11,26 @@
 
 
 import torch
-from recbole.config import Config
-from recbole.data import create_dataset, data_preparation
-from recbole.utils import get_model, init_seed
 from recbole.utils.case_study import full_sort_topk, full_sort_scores
+from recbole.quick_start import load_data_and_model
 
 
 if __name__ == '__main__':
-    # this part is to load saved model.
-    config_dict = {
-        # here you can set some parameters such as `gpu_id` and so on.
-    }
-    config = Config(model='BPR', dataset='ml-100k', config_dict=config_dict)
-    init_seed(config['seed'], config['reproducibility'])
-    dataset = create_dataset(config)
-    train_data, valid_data, test_data = data_preparation(config, dataset)
-    # Here you can also use `load_split_dataloaders` to load data.
-    # The example code for `load_split_dataloaders` can be found in `save_and_load_example.py`.
-
-    model = get_model(config['model'])(config, train_data)
-    checkpoint = torch.load('RecBole/saved/BPR-Dec-08-2020_15-37-37.pth')  # Here you can replace it by your model path.
-    model.load_state_dict(checkpoint['state_dict'])
-    model.eval()
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+    )  # Here you can replace it by your model path.
 
     # uid_series = np.array([1, 2])  # internal user id series
     # or you can use dataset.token2id to transfer external user token to internal user id
-    uid_series = dataset.token2id(dataset.uid_field, ['200'])
+    uid_series = dataset.token2id(dataset.uid_field, ['196', '186'])
 
-    topk_score, topk_iid_list = full_sort_topk(uid_series, model, test_data, k=10)
+    topk_score, topk_iid_list = full_sort_topk(uid_series, model, test_data, k=10, device=config['device'])
     print(topk_score)  # scores of top 10 items
     print(topk_iid_list)  # internal id of top 10 items
-    external_item_list = dataset.id2token(dataset.iid_field, topk_iid_list)
+    external_item_list = dataset.id2token(dataset.iid_field, topk_iid_list.cpu())
     print(external_item_list)  # external tokens of top 10 items
     print()
 
-    score = full_sort_scores(uid_series, model, test_data)
+    score = full_sort_scores(uid_series, model, test_data, device=config['device'])
     print(score)  # score of all items
     print(score[0, dataset.token2id(dataset.iid_field, ['242', '302'])])  # score of item ['242', '302'] for user '196'.
diff --git a/run_example/save_and_load_example.py b/run_example/save_and_load_example.py
index 7b59b3583..ce4f2c5ac 100644
--- a/run_example/save_and_load_example.py
+++ b/run_example/save_and_load_example.py
@@ -10,69 +10,47 @@
 The path to saved data or model can be found in the output of RecBole.
 """
 
-import pickle
-from logging import getLogger
 
-import torch
-
-from recbole.config import Config
-from recbole.data import create_dataset, data_preparation, save_split_dataloaders, load_split_dataloaders
-from recbole.utils import init_seed, init_logger, get_model, get_trainer
+from recbole.quick_start import run_recbole, load_data_and_model
 
 
 def save_example():
     # configurations initialization
     config_dict = {
-        'checkpoint_dir': '../saved'
+        'checkpoint_dir': '../saved',
+        'save_dataset': True,
+        'save_dataloaders': True,
     }
-    config = Config(model='BPR', dataset='ml-100k', config_dict=config_dict)
-    init_seed(config['seed'], config['reproducibility'])
-    init_logger(config)
-
-    # dataset filtering
-    dataset = create_dataset(config)
-    dataset.save('../saved/')
-
-    # dataset splitting
-    train_data, valid_data, test_data = data_preparation(config, dataset)
-    save_split_dataloaders(config, dataloaders=(train_data, valid_data, test_data))
-
-    model = get_model(config['model'])(config, train_data).to(config['device'])
-
-    # trainer loading and initialization
-    trainer = get_trainer(config['MODEL_TYPE'], config['model'])(config, model)
-
-    # model training
-    # the best model will be saved in here
-    best_valid_score, best_valid_result = trainer.fit(
-        train_data, valid_data, saved=True, show_progress=config['show_progress']
-    )
+    run_recbole(model='BPR', dataset='ml-100k', config_dict=config_dict)
 
 
 def load_example():
-    # configurations initialization
-    config_dict = {
-        'checkpoint_dir': '../saved'
-    }
-    config = Config(model='BPR', dataset='ml-100k', config_dict=config_dict)
-    init_seed(config['seed'], config['reproducibility'])
-    init_logger(config)
-    logger = getLogger()
+    # Filtered dataset and split dataloaders are created according to 'config'.
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+    )
 
-    with open('../saved/ml-100k-dataset.pth', 'rb') as f:  # You can use your filtered data path here.
-        dataset = pickle.load(f)
+    # Filtered dataset is loaded from file, and split dataloaders are created according to 'config'.
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+        dataset_file='../saved/ml-100k-dataset.pth',
+    )
 
-    train_data, valid_data, test_data = load_split_dataloaders('../saved/ml-100k-for-BPR-dataloader.pth')
-    # You can use your split data path here.
+    # Dataset is neither created nor loaded, and split dataloaders are loaded from file.
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+        dataloader_file='../saved/ml-100k-for-BPR-dataloader.pth',
+    )
+    assert dataset is None
 
-    model = get_model(config['model'])(config, train_data).to(config['device'])
-    checkpoint = torch.load('../saved/BPR-Mar-20-2021_17-11-05.pth')  # Here you can replace it by your model path.
-    model.load_state_dict(checkpoint['state_dict'])
-    logger.info(model)
-    logger.info(train_data.dataset)
-    logger.info(valid_data.dataset)
-    logger.info(test_data.dataset)
+    # Filtered dataset and split dataloaders are loaded from file.
+    config, model, dataset, train_data, valid_data, test_data = load_data_and_model(
+        model_file='../saved/BPR-Aug-20-2021_03-32-13.pth',
+        dataset_file='../saved/ml-100k-dataset.pth',
+        dataloader_file='../saved/ml-100k-for-BPR-dataloader.pth',
+    )
 
 
 if __name__ == '__main__':
     save_example()
+    # load_example()
diff --git a/run_example/session_based_rec_example.py b/run_example/session_based_rec_example.py
new file mode 100644
index 000000000..0b6d05018
--- /dev/null
+++ b/run_example/session_based_rec_example.py
@@ -0,0 +1,88 @@
+# @Time   : 2021/7/14
+# @Author : Yupeng Hou
+# @Email  : houyupeng@ruc.edu.cn
+
+# UPDATE
+# @Time   : 2021/7/21
+# @Author : Yupeng Hou
+# @Email  : houyupeng@ruc.edu.cn
+
+"""
+session-based recommendation example
+========================
+Here is the sample code for running session-based recommendation benchmarks using RecBole.
+
+args.dataset can be one of diginetica-session/tmall-session/nowplaying-session
+"""
+
+import argparse
+from logging import getLogger
+
+from recbole.config import Config
+from recbole.data import create_dataset
+from recbole.data.utils import get_dataloader
+from recbole.utils import init_logger, init_seed, get_model, get_trainer, set_color
+
+
+def get_args():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--model', '-m', type=str, default='GRU4Rec', help='Model for session-based rec.')
+    parser.add_argument('--dataset', '-d', type=str, default='diginetica-session', help='Benchmarks for session-based rec.')
+    parser.add_argument('--validation', action='store_true', help='Whether evaluating on validation set (split from train set), otherwise on test set.')
+    parser.add_argument('--valid_portion', type=float, default=0.1, help='ratio of validation set.')
+    return parser.parse_known_args()[0]
+
+
+if __name__ == '__main__':
+    args = get_args()
+
+    # configurations initialization
+    config_dict = {
+        'USER_ID_FIELD': 'session_id',
+        'load_col': None,
+        'neg_sampling': None,
+        'benchmark_filename': ['train', 'test'],
+        'alias_of_item_id': ['item_id_list'],
+        'topk': [20],
+        'metrics': ['Recall', 'MRR'],
+        'valid_metric': 'MRR@20'
+    }
+
+    config = Config(model=args.model, dataset=f'{args.dataset}', config_dict=config_dict)
+    init_seed(config['seed'], config['reproducibility'])
+
+    # logger initialization
+    init_logger(config)
+    logger = getLogger()
+
+    logger.info(args)
+    logger.info(config)
+
+    # dataset filtering
+    dataset = create_dataset(config)
+    logger.info(dataset)
+
+    # dataset splitting
+    train_dataset, test_dataset = dataset.build()
+    if args.validation:
+        train_dataset.shuffle()
+        new_train_dataset, new_test_dataset = train_dataset.split_by_ratio([1 - args.valid_portion, args.valid_portion])
+        train_data = get_dataloader(config, 'train')(config, new_train_dataset, None, shuffle=True)
+        test_data = get_dataloader(config, 'test')(config, new_test_dataset, None, shuffle=False)
+    else:
+        train_data = get_dataloader(config, 'train')(config, train_dataset, None, shuffle=True)
+        test_data = get_dataloader(config, 'test')(config, test_dataset, None, shuffle=False)
+
+    # model loading and initialization
+    model = get_model(config['model'])(config, train_data.dataset).to(config['device'])
+    logger.info(model)
+
+    # trainer loading and initialization
+    trainer = get_trainer(config['MODEL_TYPE'], config['model'])(config, model)
+
+    # model training and evaluation
+    test_score, test_result = trainer.fit(
+        train_data, test_data, saved=True, show_progress=config['show_progress']
+    )
+
+    logger.info(set_color('test result', 'yellow') + f': {test_result}')
diff --git a/setup.py b/setup.py
index 9e7b017ed..f99a82b63 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@
 
 install_requires = ['numpy>=1.17.2', 'torch>=1.7.0', 'scipy==1.6.0', 'pandas>=1.0.5', 'tqdm>=4.48.2',
                     'colorlog==4.7.2','colorama==0.4.4',
-                    'scikit_learn>=0.23.2', 'pyyaml>=5.1.0', 'matplotlib>=3.1.3']
+                    'scikit_learn>=0.23.2', 'pyyaml>=5.1.0', 'tensorboard>=2.5.0']
 
 setup_requires = []
 


Test patch:
diff --git a/asset/time_test_result/Context-aware_recommendation.md b/asset/time_test_result/Context-aware_recommendation.md
index 5c1167e3a..979e14d01 100644
--- a/asset/time_test_result/Context-aware_recommendation.md
+++ b/asset/time_test_result/Context-aware_recommendation.md
@@ -2,21 +2,21 @@
 
 ### Datasets information:
 
-| Dataset | #Interaction | #Feature Field | #Feature |
-| ------- | ------------: | --------------: | --------: |
-| ml-1m   | 1,000,209    | 5              | 134      |
-| Criteo  | 2,292,530    | 39             | 2,572,192 |
-| Avazu   | 4,218,938    | 21             | 1,326,631 |
+| Dataset | #Interaction | #Feature Field | #Feature   |
+| ------- | -----------: | -------------: | ---------: |
+| ml-1m   |   1,000,209  |             5  |       134  |
+| Criteo  |   1,000,000  |            39  | 2,572,192  |
+| Avazu   |   4,218,938  |            21  | 1,326,631  |
 
 ### Device information
 
 ```
 OS:                   Linux
-Python Version:       3.8.3
-PyTorch Version:      1.7.0
+Python Version:       3.8.10
+PyTorch Version:      1.8.1
 cudatoolkit Version:  10.1
-GPU:                  TITAN RTX（24GB）
-Machine Specs:        32 CPU machine, 64GB RAM
+GPU:                  TITAN V（12GB）
+Machine Specs:        14 CPU machine, 256GB RAM
 ```
 
 ### 1) ml-1m dataset:
@@ -24,22 +24,22 @@ Machine Specs:        32 CPU machine, 64GB RAM
 #### Time and memory cost on ml-1m dataset:
 
 | Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -----------------: | -----------------: | -----------: |
-| LR        | 18.34             | 2.18              | 0.82        |
-| DIN       | 20.37             | 2.26              | 1.16        |
-| DSSM      | 21.93             | 2.24              | 0.95        |
-| FM        | 19.33             | 2.34              | 0.83        |
-| DeepFM    | 20.42             | 2.27              | 0.91        |
-| Wide&Deep | 26.13             | 2.95              | 0.89        |
-| NFM       | 23.36             | 2.26              | 0.89        |
-| AFM       | 20.08             | 2.26              | 0.92        |
-| AutoInt   | 22.41             | 2.34              | 0.94        |
-| DCN       | 28.33             | 2.97              | 0.93        |
-| FNN(DNN)  | 19.51             | 2.21              | 0.91        |
-| PNN       | 22.29             | 2.23              | 0.91        |
-| FFM       | 22.98             | 2.47              | 0.87        |
-| FwFM      | 23.38             | 2.50              | 0.85        |
-| xDeepFM   | 24.40             | 2.30              | 1.06        |
+| --------- | ------------------------: | --------------------------: | --------------: |
+| LR        |                     1.02  |                       1.38  |           0.03  |
+| DIN       |                    24.26  |                       0.87  |           4.61  |
+| DSSM      |                     5.69  |                       1.17  |           0.19  |
+| FM        |                     1.08  |                       1.34  |           0.03  |
+| DeepFM    |                     2.08  |                       1.50  |           0.06  |
+| Wide&Deep |                     2.12  |                       1.25  |           0.03  |
+| NFM       |                     3.79  |                       1.12  |           0.05  |
+| AFM       |                     1.77  |                       1.36  |           0.15  |
+| AutoInt   |                     3.84  |                       1.44  |           0.17  |
+| DCN       |                     4.98  |                       1.12  |           0.16  |
+| FNN(DNN)  |                     1.95  |                       1.32  |           0.10  |
+| PNN       |                     2.45  |                       1.50  |           0.13  |
+| FFM       |                     2.39  |                       1.17  |           0.13  |
+| FwFM      |                     2.25  |                       1.22  |           0.10  |
+| xDeepFM   |                     7.20  |                       1.17  |           0.87  |
 
 #### Config file of ml-1m dataset:
 
@@ -49,24 +49,30 @@ field_separator: "\t"
 seq_separator: " "
 USER_ID_FIELD: user_id
 ITEM_ID_FIELD: item_id
+RATING_FIELD: rating
+NEG_PREFIX: neg_
 LABEL_FIELD: label
 threshold:
-  rating: 4.0
-unused_col: 
-  inter: [rating]
+    rating: 4
 load_col:
-  inter: [user_id, item_id, rating]
-  item: [item_id, release_year, genre]
-  user: [user_id, age, gender, occupation]
+    inter: [user_id, item_id, rating]
+    user: [user_id, age, gender, occupation]
+    item: [item_id, genre]
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
-eval_setting: RO_RS
-group_by_user: False
+train_batch_size: 4096
+eval_batch_size: 25600
+eval_args:
+  split: {'RS':[0.8, 0.1, 0.1]}
+  group_by: ~
+  mode: labeled
+  order: RO
 valid_metric: AUC
 metrics: ['AUC', 'LogLoss']
+
+# model
+embedding_size: 10
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -76,22 +82,22 @@ Other parameters (including model parameters) are default value.
 #### Time and memory cost on Criteo dataset:
 
 | Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -------------------------: | ---------------------------: | ---------------: |
-| LR        | 7.65                      | 0.61                        | 1.11            |
-| DIN       | -                         | -                           | -               |
-| DSSM      | -                         | -                           | -               |
-| FM        | 9.77                      | 0.73                        | 1.45            |
-| DeepFM    | 13.64                     | 0.83                        | 1.72            |
-| Wide&Deep | 13.58                     | 0.80                        | 1.72            |
-| NFM       | 13.36                     | 0.75                        | 1.72            |
-| AFM       | 19.40                     | 1.02                        | 2.34            |
-| AutoInt   | 19.40                     | 0.98                        | 2.06            |
-| DCN       | 16.25                     | 0.78                        | 1.67            |
-| FNN(DNN)  | 10.03                     | 0.64                        | 1.63            |
-| PNN       | 12.92                     | 0.72                        | 1.85            |
-| FFM       | -                         | -                           | Out of Memory               |
-| FwFM      | 1175.24                   | 8.90                        | 2.12            |
-| xDeepFM   | 32.27                     | 1.34                        | 2.25            |
+| --------- | ------------------------: | --------------------------: | --------------: |
+| LR        |                     1.16  |                       0.10  |           0.10  |
+| DIN       |                         - |                           - |               - |
+| DSSM      |                         - |                           - |               - |
+| FM        |                     1.67  |                       0.13  |           0.34  |
+| DeepFM    |                     3.55  |                       0.13  |           0.34  |
+| Wide&Deep |                     3.41  |                       0.13  |           0.34  |
+| NFM       |                     3.58  |                       0.14  |           0.35  |
+| AFM       |                     5.69  |                       0.27  |           2.13  |
+| AutoInt   |                     5.42  |                       0.22  |           1.14  |
+| DCN       |                     4.20  |                       0.15  |           0.42  |
+| FNN(DNN)  |                     2.16  |                       0.11  |           0.36  |
+| PNN       |                     3.32  |                       0.14  |           0.77  |
+| FFM       |                    57.66  |                       0.71  |           8.60  |
+| FwFM      |                   482.04  |                       3.21  |           1.59  |
+| xDeepFM   |                    10.55  |                       0.34  |           1.91  |
 
 Note: Criteo dataset is not suitable for DIN model and DSSM model.
 #### Config file of Criteo dataset:
@@ -107,26 +113,21 @@ LABEL_FIELD: label
 load_col: 
     inter: '*'
 
-highest_val:
-    index: 2292530
-
 fill_nan: True
 normalize_all: True
-min_item_inter_num: 0
-min_user_inter_num: 0
-
-unused_col: 
-  inter: [index]
-
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
-eval_setting: RO_RS
-group_by_user: False
+train_batch_size: 4096
+eval_batch_size: 4096
+eval_args:
+  mode: labeled
+  group_by: ~
 valid_metric: AUC
 metrics: ['AUC', 'LogLoss']
+
+# model
+embedding_size: 10
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -135,23 +136,23 @@ Other parameters (including model parameters) are default value.
 
 #### Time and memory cost on Avazu dataset:
 
-| Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -------------------------: | ---------------------------: | ---------------: |
-| LR        | 9.30                      | 0.76                        | 1.42            |
-| DIN       | -                         | -                           | -               |
-| DSSM      | -                         | -                           | -               |
-| FM        | 25.68                     | 0.94                        | 2.60            |
-| DeepFM    | 28.41                     | 1.19                        | 2.66            |
-| Wide&Deep | 27.58                     | 0.97                        | 2.66            |
-| NFM       | 30.46                     | 1.06                        | 2.66            |
-| AFM       | 31.03                     | 1.06                        | 2.69            |
-| AutoInt   | 38.11                     | 1.41                        | 2.84            |
-| DCN       | 30.78                     | 0.96                        | 2.64            |
-| FNN(DNN)  | 23.53                     | 0.84                        | 2.60            |
-| PNN       | 25.86                     | 0.90                        | 2.68            |
-| FFM       | -                         | -                           | Out of Memory               |
-| FwFM      | 336.75                    | 7.49                        | 2.63            |
-| xDeepFM   | 54.88                     | 1.45                        | 2.89            |
+| Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB)      |
+| --------- | ------------------------: | --------------------------: | -------------------: |
+| LR        |                     4.01  |                       0.37  |                0.36  |
+| DIN       |                         - |                           - |                    - |
+| DSSM      |                         - |                           - |                    - |
+| FM        |                    13.14  |                       0.40  |                1.35  |
+| DeepFM    |                    14.69  |                       0.48  |                1.38  |
+| Wide&Deep |                    14.20  |                       0.41  |                1.36  |
+| NFM       |                    17.40  |                       0.48  |                1.36  |
+| AFM       |                    18.25  |                       0.55  |                1.89  |
+| AutoInt   |                    21.42  |                       0.68  |                1.67  |
+| DCN       |                    18.95  |                       0.44  |                1.37  |
+| FNN(DNN)  |                    12.13  |                       0.40  |                1.31  |
+| PNN       |                    14.19  |                       0.41  |                1.45  |
+| FFM       |                         - |                           - |   CUDA out of memory |
+| FwFM      |                   292.43  |                       3.83  |                1.74  |
+| xDeepFM   |                    35.60  |                       0.93  |                2.20  |
 
 Note: Avazu dataset is not suitable for DIN model and DSSM model.
 #### Config file of Avazu dataset:
@@ -160,28 +161,37 @@ Note: Avazu dataset is not suitable for DIN model and DSSM model.
 # dataset config
 field_separator: "\t"
 seq_separator: " "
-USER_ID_FIELD: ~
-ITEM_ID_FIELD: ~
 LABEL_FIELD: label
-fill_nan: True
-normalize_all: True
 
-load_col:
+load_col: 
     inter: '*'
-    
-lowest_val:
-  timestamp: 14102931
-unused_col: 
-  inter: [timestamp]
+
+fill_nan: True
+USER_ID_FIELD: ~
+ITEM_ID_FIELD: ~
+normalize_all: True
+val_interval: 
+  timestamp: "[14102931, inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
-eval_setting: RO_RS
+train_batch_size: 4096
+eval_batch_size: 4096
+eval_args:
+  group_by: ~
+  split: {'RS':[0.8, 0.1, 0.1]}
+  mode: labeled
+  order: RO
 group_by_user: False
 valid_metric: AUC
 metrics: ['AUC', 'LogLoss']
+
+# model
+embedding_size: 10    
+attention_size: 30
+dropout_prob: 0.1
+learning_rate: 5e-5
+reg_weight: 5
 ```
 
 Other parameters (including model parameters) are default value. 
diff --git a/asset/time_test_result/General_recommendation.md b/asset/time_test_result/General_recommendation.md
index 851df2a2a..e3c7a7740 100644
--- a/asset/time_test_result/General_recommendation.md
+++ b/asset/time_test_result/General_recommendation.md
@@ -2,21 +2,21 @@
 
 ### Datasets information:
 
-| Dataset | #User   | #Item  | #Interaction | Sparsity |
-| ------- | -------: | ------: | ------------: | --------: |
-| ml-1m   | 6,041   | 3,707  | 1,000,209    | 0.9553   |
-| Netflix | 80,476  | 16,821 | 1,977,844    | 0.9985   |
-| Yelp    | 102,046 | 98,408 | 2,903,648    | 0.9997   |
+| Dataset | #User   | #Item   | #Interaction | Sparsity |
+| ------- | ------: | ------: | -----------: | -------: |
+| ml-1m   |  6,040  |  3,629  |   836,478    |  0.9618  |
+| Netflix | 40,227  |  8,727  |  1,752,648   |  0.9950  |
+| Yelp    | 45,478  | 30,709  |  1,777,765   |  0.9987  |
 
 ### Device information
 
 ```
 OS:                   Linux
-Python Version:       3.8.3
-PyTorch Version:      1.7.0
+Python Version:       3.8.10
+PyTorch Version:      1.8.1
 cudatoolkit Version:  10.1
-GPU:                  TITAN RTX（24GB）
-Machine Specs:        32 CPU machine, 64GB RAM
+GPU:                  TITAN V（12GB）
+Machine Specs:        14 CPU machine, 256GB RAM
 ```
 
 ### 1) ml-1m dataset:
@@ -25,19 +25,19 @@ Machine Specs:        32 CPU machine, 64GB RAM
 
 | Method     | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
 | ---------- | ------------------------: | --------------------------: | --------------: |
-| Popularity |                      2.11 |                        8.08 |            0.82 |
-| ItemKNN    |                      2.00 |                       11.76 |            0.82 |
-| BPRMF      |                      1.93 |                        7.43 |            0.91 |
-| NeuMF      |                      4.94 |                       13.12 |            0.94 |
-| DMF        |                      4.47 |                       12.63 |            1.52 |
-| NAIS       |                     59.27 |                       24.41 |           21.83 |
-| NGCF       |                     12.09 |                        7.12 |            1.20 |
-| GCMC       |                      9.04 |                       54.15 |            1.32 |
-| LightGCN   |                      7.83 |                        7.47 |            1.15 |
-| DGCF       |                    181.66 |                        8.06 |            6.59 |
-| ConvNCF    |                      8.46 |                       19.60 |            1.31 |
-| FISM       |                     19.30 |                       10.92 |            6.94 |
-| SpectralCF |                     13.87 |                        6.97 |            1.19 |
+| Popularity |                     0.62  |                       0.41  |           0.00  |
+| ItemKNN    |                     0.65  |                       4.87  |           0.00  |
+| BPRMF      |                     0.89  |                       0.71  |           0.03  |
+| NeuMF      |                     3.63  |                       0.83  |           0.33  |
+| DMF        |                     3.70  |                       1.34  |           0.87  |
+| NAIS       |                    44.94  |                      13.73  |           8.12  |
+| NGCF       |                     6.19  |                       0.40  |           0.19  |
+| GCMC       |                     4.46  |                       1.74  |           0.26  |
+| LightGCN   |                     3.76  |                       0.76  |           0.16  |
+| DGCF       |                    63.83  |                       0.57  |           4.15  |
+| ConvNCF    |                     8.43  |                      10.04  |           8.58  |
+| FISM       |                    17.54  |                       3.46  |           3.35  |
+| SpectralCF |                     8.02  |                       0.43  |           0.18  |
 
 #### Config file of ml-1m dataset:
 
@@ -48,20 +48,23 @@ seq_separator: " "
 USER_ID_FIELD: user_id
 ITEM_ID_FIELD: item_id
 RATING_FIELD: rating
-TIME_FIELD: timestamp
-LABEL_FIELD: label
 NEG_PREFIX: neg_
+LABEL_FIELD: label
 load_col:
-  inter: [user_id, item_id, rating, timestamp]
-min_user_inter_num: 0
-min_item_inter_num: 0
-
+    inter: [user_id, item_id, rating]
+val_interval:
+    rating: "[3,inf)"    
+unused_col: 
+    inter: [rating]
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -70,21 +73,21 @@ Other parameters (including model parameters) are default value.
 
 #### Time and memory cost on Netflix dataset:
 
-| Method     | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| ---------- | ----------------: | -----------------: | -----------: |
-| Popularity | 3.98              | 58.86             | 0.86     |
-| ItemKNN    | 5.42              | 69.64             | 0.86      |
-| BPRMF      | 4.42              | 52.81             | 1.08    |
-| NeuMF      | 11.33             | 238.92            | 1.26     |
-| DMF        | 20.62             | 68.89             | 7.12     |
-| NAIS       | -                 | -                 | Out of Memory       |
-| NGCF       | 52.50             | 51.60             | 2.00     |
-| GCMC       | 93.15             |                     1810.43 | 3.17     |
-| LightGCN   | 30.21             | 47.12             | 1.58     |
-| DGCF       |                    750.74 |                       47.23 |           12.52 |
-| ConvNCF    | 17.02             | 402.65            | 1.44     |
-| FISM       | 86.52             | 83.26             | 20.54   |
-| SpectralCF | 59.92             | 46.94             | 1.88     |
+| Method     | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB)      |
+| ---------- | ------------------------: | --------------------------: | -------------------: |
+| Popularity |                     1.55  |                       6.62  |                0.00  |
+| ItemKNN    |                     2.48  |                      25.71  |                0.00  |
+| BPRMF      |                     1.92  |                       5.82  |                0.09  |
+| NeuMF      |                     7.54  |                      12.61  |                0.40  |
+| DMF        |                    10.66  |                       8.14  |                3.54  |
+| NAIS       |                         - |                           - |   CUDA out of memory |
+| NGCF       |                    18.26  |                       5.70  |                0.58  |
+| GCMC       |                    22.07  |                      86.32  |                1.17  |
+| LightGCN   |                    10.85  |                       6.31  |                0.41  |
+| DGCF       |                   269.08  |                       5.39  |                8.80  |
+| ConvNCF    |                    15.66  |                     168.54  |                8.29  |
+| FISM       |                    57.58  |                      23.10  |                8.51  |
+| SpectralCF |                    20.67  |                       5.52  |                0.51  |
 
 #### Config file of Netflix dataset:
 
@@ -100,19 +103,22 @@ LABEL_FIELD: label
 NEG_PREFIX: neg_
 load_col:
   inter: [user_id, item_id, rating, timestamp]
-min_user_inter_num: 3
-min_item_inter_num: 0
-lowest_val:
-  timestamp: 1133366400
-  rating: 3
-unused_col: 
-  inter: [timestamp, rating]
+
+user_inter_num_interval: "[10,inf)"
+item_inter_num_interval: "[10,inf)"
+val_interval:
+  rating: "[3,inf)"
+  timestamp: "[1133366400, inf)"
+
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64 
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -121,21 +127,21 @@ Other parameters (including model parameters) are default value.
 
 #### Time and memory cost on Yelp dataset:
 
-| Method     | Training Time (sec/epoch) | Evaluate Time (sec/epoch) | GPU Memory (GB) |
-| ---------- | -------------------------: | -------------------------: | ---------------: |
-| Popularity | 5.69                      | 134.23                    | 0.89            |
-| ItemKNN    | 8.44                      | 194.24                    | 0.90            |
-| BPRMF      | 6.31                      | 120.03                    | 1.29            |
-| NeuMF      | 17.38                     | 2069.53                   | 1.67            |
-| DMF        | 43.96                     | 173.13                    | 9.22            |
-| NAIS       | -                         | -                         | Out of Memory               |
-| NGCF       | 122.90                    | 129.59                    | 3.28            |
-| GCMC       | 299.36                    | 9833.24                   | 5.96            |
-| LightGCN   | 67.91                     | 116.16                    | 2.02            |
-| DGCF       | 1542.00                   | 119.00                    | 17.17           |
-| ConvNCF    | 87.56                     | 11155.31                  | 1.62            |
-| FISM       | -                         | -                         | Out of Memory     |
-| SpectralCF | 138.99                    | 133.37                    | 3.10            |
+| Method     | Training Time (sec/epoch) | Evaluate Time (sec/epoch) | GPU Memory (GB)      |
+| ---------- | ------------------------: | ------------------------: | -------------------: |
+| Popularity |                     1.71  |                     6.45  |                0.02  |
+| ItemKNN    |                     5.67  |                    37.37  |                0.02  |
+| BPRMF      |                     2.86  |                     5.96  |                0.13  |
+| NeuMF      |                     7.75  |                    32.75  |                1.27  |
+| DMF        |                    12.82  |                     9.27  |                2.90  |
+| NAIS       |                         - |                         - |   CUDA out of memory |
+| NGCF       |                    23.17  |                     5.62  |                0.79  |
+| GCMC       |                    32.20  |                   110.34  |                1.65  |
+| LightGCN   |                    13.06  |                     5.85  |                0.47  |
+| DGCF       |                   270.31  |                     5.92  |                8.62  |
+| ConvNCF    |                         - |                         - |   CUDA out of memory |
+| FISM       |                         - |                         - |   CUDA out of memory |
+| SpectralCF |                    24.44  |                     5.73  |                0.62  |
 
 #### Config file of Yelp dataset:
 
@@ -151,18 +157,21 @@ LABEL_FIELD: label
 NEG_PREFIX: neg_
 load_col:
   inter: [user_id, business_id, stars]
-min_user_inter_num: 10
-min_item_inter_num: 4
-lowest_val:
-  stars: 3
-unused_col: 
-  inter: [stars]
+
+user_inter_num_interval: "[15,inf)"
+item_inter_num_interval: "[15,inf)"
+val_interval:
+  stars: "[3,inf)"
+
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
diff --git a/asset/time_test_result/Knowledge-based_recommendation.md b/asset/time_test_result/Knowledge-based_recommendation.md
index 53b6dca69..3f123b4b4 100644
--- a/asset/time_test_result/Knowledge-based_recommendation.md
+++ b/asset/time_test_result/Knowledge-based_recommendation.md
@@ -2,21 +2,21 @@
 
 ### Datasets information:
 
-| Dataset | #User  | #Item   | #Interaction | Sparsity | #Entity   | #Relation | #Triple   |
-| ------- | ------: | -------: | ------------: | --------: | ---------: | ---------: | ---------: |
-| ml-1m   | 6,040  | 3,629   | 836,478      | 0.9618   | 79,388    | 51        | 385,923   |
-| ml-10m  | 69,864 | 10,599  | 8,242,124    | 0.9889   | 181,941   | 51        | 1,051,385 |
-| LFM-1b | 64,536 | 156,343 | 6,544,312    | 0.9994   | 1,751,586 | 10        | 3,054,516 |
+| Dataset    | #User   | #Item   | #Interaction | Sparsity | #Entity  | #Relation | #Triple    |
+| ---------- | ------: | ------: | -----------: | -------: | -------: | --------: | ---------: |
+| ml-1m      |  6,040  |  3,629  |     836,478  |  0.9618  |  79,388  |       51  |   385,923  |
+| ml-10m     | 69,864  | 10,599  |   8,242,124  |  0.9889  | 181,941  |       51  | 1,051,385  |
+| LFM-1b2013 | 28,150  | 64,583  |   1,907,900  |  0.9990  | 181,112  |        7  |   281,900  |
 
 ### Device information
 
 ```
 OS:                   Linux
-Python Version:       3.8.3
-PyTorch Version:      1.7.0
+Python Version:       3.8.10
+PyTorch Version:      1.8.1
 cudatoolkit Version:  10.1
-GPU:                  TITAN RTX（24GB）
-Machine Specs:        32 CPU machine, 64GB RAM
+GPU:                  TITAN V（12GB）
+Machine Specs:        14 CPU machine, 256GB RAM
 ```
 
 ### 1) ml-1m dataset:
@@ -24,15 +24,15 @@ Machine Specs:        32 CPU machine, 64GB RAM
 #### Time and memory cost on ml-1m dataset:
 
 | Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -------------------------: | ---------------------------: | ---------------: |
-| CKE       | 3.76                      | 8.73                        | 1.16            |
-| KTUP      | 3.82                      | 17.68                       | 1.04            |
-| RippleNet | 9.39                      | 13.13                       | 4.57            |
-| KGAT      | 9.59                      | 8.63                        | 3.52            |
-| KGNN-LS   | 4.78                      | 15.09                       | 1.04            |
-| KGCN      | 2.25                      | 13.71                       | 1.04            |
-| MKR       | 6.25                      | 14.89                       | 1.29            |
-| CFKG      | 1.49                      | 9.76                        | 0.97            |
+| --------- | ------------------------: | --------------------------: | --------------: |
+| CKE       |                     4.88  |                       0.44  |           0.38  |
+| KTUP      |                     3.76  |                       1.70  |           0.47  |
+| RippleNet |                    35.85  |                       0.84  |           7.26  |
+| KGAT      |                     6.68  |                       0.37  |           2.10  |
+| KGNN-LS   |                     8.20  |                       1.14  |           0.57  |
+| KGCN      |                     3.56  |                       1.14  |           0.56  |
+| MKR       |                     4.36  |                       5.57  |           3.68  |
+| CFKG      |                     1.60  |                       0.57  |           0.27  |
 
 #### Config file of ml-1m dataset:
 
@@ -53,16 +53,17 @@ load_col:
     inter: [user_id, item_id, rating]
     kg: [head_id, relation_id, tail_id]
     link: [item_id, entity_id]
-lowest_val:
-    rating: 3
-unused_col:
-    inter: [rating]
+val_interval:
+    rating: "[3,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -71,16 +72,16 @@ Other parameters (including model parameters) are default value.
 
 #### Time and memory cost on ml-10m dataset:
 
-| Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -------------------------: | ---------------------------: | ---------------: |
-| CKE       | 8.65                      | 85.53                       | 1.46            |
-| KTUP      | 40.71                     | 507.56                      | 1.43            |
-| RippleNet | 32.01                     | 152.40                      | 4.71            |
-| KGAT      | 298.22                    | 80.94                       | 22.44           |
-| KGNN-LS   | 15.47                     | 241.57                      | 1.42            |
-| KGCN      | 7.73                      | 244.93                      | 1.42            |
-| MKR       | 61.05                     | 383.29                      | 1.80            |
-| CFKG      | 5.99                      | 140.74                      | 1.35            |
+| Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB)    |
+| --------- | ------------------------: | --------------------------: | -----------------: |
+| CKE       |                    43.41  |                      10.72  |              0.70  |
+| KTUP      |                    33.82  |                      38.87  |              0.66  |
+| RippleNet |                   360.16  |                      23.35  |              7.38  |
+| KGAT      |                         - |                           - | CUDA out of memory |
+| KGNN-LS   |                    84.51  |                      47.31  |              0.73  |
+| KGCN      |                    20.13  |                      53.33  |              0.74  |
+| MKR       |                    31.74  |                     207.12  |              3.85  |
+| CFKG      |                    16.33  |                      16.88  |              0.46  |
 
 #### Config file of ml-10m dataset:
 
@@ -101,16 +102,17 @@ load_col:
     inter: [user_id, item_id, rating]
     kg: [head_id, relation_id, tail_id]
     link: [item_id, entity_id]
-lowest_val:
-    rating: 3
-unused_col:
-    inter: [rating]
+val_interval:
+    rating: "[3,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
@@ -120,15 +122,15 @@ Other parameters (including model parameters) are default value.
 #### Time and memory cost on LFM-1b dataset:
 
 | Method    | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| --------- | -------------------------: | ---------------------------: | ---------------: |
-| CKE       | 62.99                     | 82.93                       | 4.45            |
-| KTUP      | 91.79                     | 3218.69                     | 4.36            |
-| RippleNet | 126.26                    | 188.38                      | 6.49            |
-| KGAT      | 626.07                    | 75.70                       | 23.28           |
-| KGNN-LS   | 62.55                     | 1709.10                     | 4.73            |
-| KGCN      | 52.54                     | 1763.03                     | 4.71            |
-| MKR       | 290.01                    | 2341.91                     | 6.96            |
-| CFKG      | 53.35                     | 553.58                      | 4.22            |
+| --------- | ------------------------: | --------------------------: | --------------: |
+| CKE       |                     8.73  |                      41.84  |           0.69  |
+| KTUP      |                     4.56  |                      87.67  |           0.48  |
+| RippleNet |                    82.53  |                      69.37  |           7.32  |
+| KGAT      |                    15.69  |                      40.75  |           4.19  |
+| KGNN-LS   |                    15.65  |                     436.84  |           0.61  |
+| KGCN      |                     8.04  |                     443.80  |           0.60  |
+| MKR       |                     9.06  |                     456.11  |           2.87  |
+| CFKG      |                     3.81  |                      50.48  |           0.45  |
 
 #### Config file of LFM-1b  dataset:
 
@@ -137,7 +139,7 @@ Other parameters (including model parameters) are default value.
 field_separator: "\t"
 seq_separator: " "
 USER_ID_FIELD: user_id
-ITEM_ID_FIELD: tracks_id
+ITEM_ID_FIELD: item_id
 RATING_FIELD: rating
 HEAD_ENTITY_ID_FIELD: head_id
 TAIL_ENTITY_ID_FIELD: tail_id
@@ -146,24 +148,22 @@ ENTITY_ID_FIELD: entity_id
 NEG_PREFIX: neg_
 LABEL_FIELD: label
 load_col:
-    inter: [user_id, tracks_id, timestamp]
+    inter: [user_id, item_id, rating]
     kg: [head_id, relation_id, tail_id]
-    link: [tracks_id, entity_id]
-lowest_val:
-    timestamp: 1356969600
-  
-highest_val:
-    timestamp: 1362067200
-unused_col: 
-    inter: [timestamp]
-min_user_inter_num: 2
-min_item_inter_num: 15
+    link: [item_id, entity_id]
+val_interval:
+  rating: "[10,inf)"
+user_inter_num_interval: "[10,inf)"
+item_inter_num_interval: "[10,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 102400
 valid_metric: MRR@10
+
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
diff --git a/asset/time_test_result/Sequential_recommendation.md b/asset/time_test_result/Sequential_recommendation.md
index 5fa984797..289a5e13c 100644
--- a/asset/time_test_result/Sequential_recommendation.md
+++ b/asset/time_test_result/Sequential_recommendation.md
@@ -2,46 +2,46 @@
 
 ### Datasets information:
 
-| Dataset    | #User   | #Item  | #Interaction | Sparsity |
-| ---------- | -------: | ------: | ------------: | --------: |
-| ml-1m      | 6,041   | 3,707  | 1,000,209    | 0.9553   |
-| DIGINETICA | 59,425  | 42,116 | 547,416      | 0.9998   |
-| Yelp       | 102,046 | 98,408 | 2,903,648    | 0.9997   |
+| Dataset    | #User   | #Item   | #Interaction | Sparsity |
+| ---------- | ------: | ------: | -----------: | -------: |
+| ml-1m      |  6,040  |  3,629  |     836,478  |  0.9618  |
+| DIGINETICA | 72,014  | 29,454  |     580,490  |  0.9997  |
+| Yelp       | 45,478  | 30,709  |   1,777,765  |  0.9987  |
 
 ### Device information
 
 ```
 OS:                   Linux
-Python Version:       3.8.3
-PyTorch Version:      1.7.0
+Python Version:       3.8.10
+PyTorch Version:      1.8.1
 cudatoolkit Version:  10.1
-GPU:                  TITAN RTX（24GB）
-Machine Specs:        32 CPU machine, 64GB RAM
+GPU:                  TITAN V（12GB）
+Machine Specs:        14 CPU machine, 256GB RAM
 ```
 
 ### 1) ml-1m dataset:
 
 #### Time and memory cost on ml-1m dataset:
 
-| Method           | Training Time (sec/epoch) | Evaluate Time (sec/epoch) | GPU Memory (GB) |
-| ---------------- | -----------------: | -----------------: | -----------: |
-| Improved GRU-Rec | 7.78              | 0.11              | 1.27     |
-| SASRec           | 17.78             | 0.12              | 1.84     |
-| NARM             | 8.29              | 0.11              | 1.29     |
-| FPMC             | 7.51              | 0.11              | 1.18     |
-| STAMP            | 7.32              | 0.11              | 1.20     |
-| Caser            | 44.85             | 0.12              | 1.14     |
-| NextItNet        |                  16433.27 |                     96.31 |            1.86 |
-| TransRec         | 10.08             | 0.16              | 8.18     |
-| S3Rec            | - | - | -       |
-| GRU4RecF         | 10.20             | 0.15              | 1.80     |
-| SASRecF          | 18.84             | 0.17              | 1.78    |
-| BERT4Rec         | 36.09             | 0.34              | 1.97    |
-| FDSA             | 31.86             | 0.19              | 2.32     |
-| SRGNN            | 327.38            | 2.19              | 1.21     |
-| GCSAN            | 335.27            | 0.02             | 1.58     |
-| KSR              | - | - | - |
-| GRU4RecKG        | - | - | - |
+| Method           | Training Time (sec/epoch) | Evaluate Time (sec/epoch)   | GPU Memory (GB)          |
+| ---------------- | ------------------------: | --------------------------: | -----------------------: |
+| Improved GRU-Rec |                     6.15  |                       0.06  |                    1.46  |
+| SASRec           |                    24.86  |                       0.09  |                    4.11  |
+| NARM             |                     7.34  |                       0.07  |                    1.51  |
+| FPMC             |                     6.07  |                       0.05  |                    0.30  |
+| STAMP            |                     3.10  |                       0.10  |                    0.65  |
+| Caser            |                   549.40  |                       0.21  |                    1.08  |
+| NextItNet        |                   203.85  |                       0.71  |                    3.68  |
+| TransRec         |                     5.81  |                       0.12  |                    7.21  |
+| S3Rec            |                         - |                           - |       CUDA out of memory |
+| GRU4RecF         |                    13.54  |                       0.09  |                    2.18  |
+| SASRecF          |                    28.16  |                       0.11  |                    5.08  |
+| BERT4Rec         |                    56.57  |                       0.32  |                    6.20  |
+| FDSA             |                    50.18  |                       0.14  |                    8.12  |
+| SRGNN            |                   631.08  |                       4.58  |                    1.12  |
+| GCSAN            |                   671.66  |                       4.99  |                    2.96  |
+| KSR              |                    61.18  |                       0.21  |                    6.94  |
+| GRU4RecKG        |                    11.36  |                       0.07  |                    2.22  |
 
 #### Config file of ml-1m dataset:
 
@@ -51,63 +51,72 @@ field_separator: "\t"
 seq_separator: " "
 USER_ID_FIELD: user_id
 ITEM_ID_FIELD: item_id
+RATING_FIELD: rating
 TIME_FIELD: timestamp
 NEG_PREFIX: neg_
 ITEM_LIST_LENGTH_FIELD: item_length
 LIST_SUFFIX: _list
-MAX_ITEM_LIST_LENGTH: 20
+MAX_ITEM_LIST_LENGTH: 50
 POSITION_FIELD: position_id
 load_col:
-  inter: [user_id, item_id, timestamp]
-min_user_inter_num: 0
-min_item_inter_num: 0
+  inter: [user_id, item_id, rating, timestamp]
+val_interval:
+  rating: "[3,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
+train_batch_size: 4096
 eval_batch_size: 2048
-valid_metric: MRR@10
-eval_setting: TO_LS,full
-training_neg_sample_num: 0
+valid_metric: recall@10
+eval_args:
+  split: {'LS': 'valid_and_test'}
+  mode: full
+  order: TO
+neg_sampling: ~
+
+# model
+embedding_size: 64 
 ```
 
 Other parameters (including model parameters) are default value. 
 
 **NOTE :** 
 
-1) For FPMC and TransRec model,  `training_neg_sample_num`  should be  `1` . 
+1) For FPMC and TransRec model,  `neg_sampling`  should be  `{'uniform': 1}` .
 
-2) For  SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
+2) For SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
 
 ```
 load_col:
-  inter: [user_id, item_id, timestamp]
+  inter: [user_id, item_id, rating, timestamp]
   item: [item_id, genre]
 ```
 
+3) For KSR and GRU4RecKG, you should prepare pretrained knowledge graph embedding.
+
 ### 2）DIGINETICA dataset:
 
 #### Time and memory cost on DIGINETICA dataset:
 
-| Method           | Training Time (sec/epoch) | Evaluate Time (sec/epoch) | GPU Memory (GB) |
-| ---------------- | -----------------: | -----------------: | -----------: |
-| Improved GRU-Rec | 4.10              | 1.05              | 4.02     |
-| SASRec           | 8.36              | 1.21              | 4.43     |
-| NARM             | 4.30              | 1.08              | 4.09     |
-| FPMC             | 2.98              | 1.08              | 4.08     |
-| STAMP            | 4.27              | 1.04              | 3.88     |
-| Caser            | 17.15             | 1.18              | 3.94    |
-| NextItNet        | 6150.49 | 947.66 | 4.54 |
-| TransRec         | -                 | -                 | Out of Memory           |
-| S3Rec            | - | - | - |
-| GRU4RecF         | 4.79              | 1.17              | 4.83     |
-| SASRecF          | 8.66              | 1.29              | 5.11     |
-| BERT4Rec         | 16.80             | 3.54              | 7.97    |
-| FDSA             | 13.44             | 1.47              | 5.66     |
-| SRGNN            | 88.59             | 15.37             | 4.01     |
-| GCSAN            | 96.69             | 17.11             | 4.25     |
-| KSR              | - | - | - |
-| GRU4RecKG        | - | - | - |
+| Method           | Training Time (sec/epoch) | Evaluate Time (sec/epoch)   | GPU Memory (GB)          |
+| ---------------- | ------------------------: | --------------------------: | -----------------------: |
+| Improved GRU-Rec |                     2.22  |                       0.74  |                    2.70  |
+| SASRec           |                     6.88  |                       0.88  |                    3.53  |
+| NARM             |                     2.42  |                       0.74  |                    2.37  |
+| FPMC             |                     2.44  |                       0.72  |                    2.31  |
+| STAMP            |                     2.01  |                       0.71  |                    2.44  |
+| Caser            |                    17.51  |                       0.86  |                    2.49  |
+| NextItNet        |                    34.00  |                       2.98  |                    3.71  |
+| TransRec         |                         - |                           - |       CUDA out of memory |
+| S3Rec            |                   160.15  |                           - |                    6.20  |
+| GRU4RecF         |                     3.00  |                       0.84  |                    3.02  |
+| SASRecF          |                     6.67  |                       0.93  |                    3.61  |
+| BERT4Rec         |                    12.97  |                       3.43  |                   10.26  |
+| FDSA             |                    11.17  |                       1.10  |                    4.71  |
+| SRGNN            |                    66.67  |                      14.81  |                    2.66  |
+| GCSAN            |                    69.03  |                      14.29  |                    3.13  |
+| KSR              |                         - |                           - |                        - |
+| GRU4RecKG        |                         - |                           - |                        - |
 
 #### Config file of DIGINETICA dataset:
 
@@ -125,25 +134,31 @@ MAX_ITEM_LIST_LENGTH: 20
 POSITION_FIELD: position_id
 load_col:
   inter: [session_id, item_id, timestamp]
-min_user_inter_num: 6
-min_item_inter_num: 1
+user_inter_num_interval: "[5,inf)"
+item_inter_num_interval: "[5,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
+train_batch_size: 4096
 eval_batch_size: 2048
 valid_metric: MRR@10
-eval_setting: TO_LS,full
-training_neg_sample_num: 0
+eval_args:
+  split: {'LS':"valid_and_test"}
+  mode: full
+  order: TO
+neg_sampling: ~
+
+# model
+embedding_size: 64 
 ```
 
 Other parameters (including model parameters) are default value. 
 
 **NOTE :** 
 
-1) For FPMC and TransRec model,  `training_neg_sample_num`  should be  `1` . 
+1) For FPMC and TransRec model,  `neg_sampling`  should be  `{'uniform': 1}` .
 
-2) For  SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
+2) For SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
 
 ```
 load_col:
@@ -151,29 +166,31 @@ load_col:
    item: [item_id, item_category]
 ```
 
+3) For KSR and GRU4RecKG, you should prepare pretrained knowledge graph embedding.
+
 ### 3）Yelp dataset:
 
 #### Time and memory cost on Yelp dataset:
 
-| Method           | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB) |
-| ---------------- | -----------------: | -----------------: | -----------: |
-| Improved GRU-Rec | 44.31             | 2.74              | 7.92        |
-| SASRec           | 75.51             | 3.11              | 8.32        |
-| NARM             | 45.65             | 2.76              | 7.98        |
-| FPMC             | 21.05             | 3.05              | 8.22        |
-| STAMP            | 42.08             | 2.72              | 7.77        |
-| Caser            | 147.15            | 2.89              | 7.87        |
-| NextItNet        |                  45019.38 |                     1670.76 |            8.44 |
-| TransRec         | -                 | -                 | Out of Memory           |
-| S3Rec            | -                 | -                 | -           |
-| GRU4RecF         | -                 | -                 | Out of Memory           |
-| SASRecF          | -                 | -                 | Out of Memory           |
-| BERT4Rec         | 193.74            | 8.43              | 16.57       |
-| FDSA             | -                 | -                 | Out of Memory           |
-| SRGNN            | 825.11            | 33.20             | 7.90        |
-| GCSAN            | 837.23            | 33.00             | 8.14        |
-| KSR              | - | - | - |
-| GRU4RecKG        | - | - | - |
+| Method           | Training Time (sec/epoch) | Evaluation Time (sec/epoch) | GPU Memory (GB)          |
+| ---------------- | ------------------------: | --------------------------: | -----------------------: |
+| Improved GRU-Rec |                    16.52  |                       0.66  |                    3.34  |
+| SASRec           |                    54.92  |                       0.90  |                    5.82  |
+| NARM             |                    19.35  |                       0.79  |                    3.26  |
+| FPMC             |                    11.44  |                       0.58  |                    0.76  |
+| STAMP            |                     9.97  |                       0.59  |                    2.76  |
+| Caser            |                  1105.96  |                       2.02  |                    3.21  |
+| NextItNet        |                   413.43  |                       5.57  |                    5.73  |
+| TransRec         |                         - |                           - |       CUDA out of memory |
+| S3Rec            |                         - |                           - |       CUDA out of memory |
+| GRU4RecF         |                     62,41 |                        1.32 |                     7.36 |
+| SASRecF          |                    86.20  |                        1.42 |                     6.12 |
+| BERT4Rec         |                         - |                           - |       CUDA out of memory |
+| FDSA             |                   133.52  |                       1.87  |                    9.19  |
+| SRGNN            |                  1165.06  |                      30.35  |                    3.41  |
+| GCSAN            |                  1112.46  |                      29.84  |                    4.67  |
+| KSR              |                         - |                           - |                        - |
+| GRU4RecKG        |                         - |                           - |                        - |
 
 #### Config file of Yelp dataset:
 
@@ -188,44 +205,42 @@ TIME_FIELD: date
 NEG_PREFIX: neg_
 ITEM_LIST_LENGTH_FIELD: item_length
 LIST_SUFFIX: _list
-MAX_ITEM_LIST_LENGTH: 20
+MAX_ITEM_LIST_LENGTH: 50
 POSITION_FIELD: position_id
 load_col:
   inter: [user_id, business_id, stars, date]
-min_user_inter_num: 10
-min_item_inter_num: 4
-lowest_val:
-  stars: 3
-unused_col: 
-  inter: [stars]
+
+user_inter_num_interval: "[15,inf)"
+item_inter_num_interval: "[15,inf)"
+val_interval:
+  stars: "[3,inf)"
 
 # training and evaluation
 epochs: 500
-train_batch_size: 2048
-eval_batch_size: 2048
+train_batch_size: 4096
+eval_batch_size: 512
 valid_metric: MRR@10
-eval_setting: TO_LS,full
-training_neg_sample_num: 0
+eval_args:
+  split: {'LS':"valid_and_test"}
+  order: TO
+neg_sampling: ~
 
+# model
+embedding_size: 64
 ```
 
 Other parameters (including model parameters) are default value. 
 
 **NOTE :** 
 
-1) For FPMC and TransRec model,  `training_neg_sample_num`  should be  `1` . 
+1) For FPMC and TransRec model,  `neg_sampling`  should be  `{'uniform': 1}` .
 
-2) For  SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
+2) For SASRecF, GRU4RecF and FDSA,   `load_col` should as below:
 
 ```
 load_col:
-  inter: [session_id, item_id, timestamp]
-  item: [item_id, item_category]
+  inter: [user_id, business_id, stars, date]
+  item: [business_id, categories]
 ```
 
-
-
-
-
-
-
+3) For KSR and GRU4RecKG, you should prepare pretrained knowledge graph embedding.
\ No newline at end of file
diff --git a/run_test.sh b/run_test.sh
index 6d70c5171..e035d878e 100644
--- a/run_test.sh
+++ b/run_test.sh
@@ -7,7 +7,7 @@ echo "metrics tests finished"
 python -m pytest -v tests/config/test_config.py
 python -m pytest -v tests/config/test_overall.py
 export PYTHONPATH=.
-python tests/config/test_command_line.py --use_gpu=False --valid_metric=Recall@10 --split_ratio=[0.7,0.2,0.1] --metrics=['Recall@10'] --epochs=200 --eval_setting='LO_RS' --learning_rate=0.3
+python tests/config/test_command_line.py --use_gpu=False --valid_metric=Recall@10  --metrics=['Recall@10'] --epochs=200  --learning_rate=0.3
 echo "config tests finished"
 
 python -m pytest -v tests/evaluation_setting
diff --git a/tests/config/run.sh b/tests/config/run.sh
index 455c2a2b1..49323c8dc 100644
--- a/tests/config/run.sh
+++ b/tests/config/run.sh
@@ -1,8 +1,8 @@
-#!/bin/bash
-
-
-python -m unittest
-
-python test_command_line.py --use_gpu=False --valid_metric=Recall@10 --split_ratio=[0.7,0.2,0.1] \
---metrics=['Recall@10'] \
+#!/bin/bash
+
+
+python -m unittest
+
+python test_command_line.py --use_gpu=False --valid_metric=Recall@10 --split_ratio=[0.7,0.2,0.1] \
+--metrics='["Recall"]' --topk=[10] \
 --epochs=200 --eval_setting='LO_RS' --learning_rate=0.3
\ No newline at end of file
diff --git a/tests/config/test_command_line.py b/tests/config/test_command_line.py
index 627ba95f1..c4ea6ac01 100644
--- a/tests/config/test_command_line.py
+++ b/tests/config/test_command_line.py
@@ -2,6 +2,11 @@
 # @Author : Shanlei Mu
 # @Email  : slmu@ruc.edu.cn
 
+# UPDATE:
+# @Time   : 2021/7/1
+# @Author : Xingyu Pan
+# @Email  : xy_pan@foxmail.com
+
 
 from recbole.config import Config
 
@@ -22,12 +27,10 @@
     # command line
     assert config['use_gpu'] == False
     assert config['valid_metric'] == 'Recall@10'
-    assert config['split_ratio'] == [0.7, 0.2, 0.1]
     # assert config['metrics'] == ['Recall@10']     # bug
 
     # priority
     assert config['epochs'] == 200
-    assert config['eval_setting'] == 'LO_RS'
     assert config['learning_rate'] == 0.3
 
     print('------------------------------------------------------------')
diff --git a/tests/config/test_config.py b/tests/config/test_config.py
index 681eb1355..c698227d2 100644
--- a/tests/config/test_config.py
+++ b/tests/config/test_config.py
@@ -2,6 +2,10 @@
 # @Author : Shanlei Mu
 # @Email  : slmu@ruc.edu.cn
 
+# UPDATE:
+# @Time   : 2021/7/1
+# @Author : Xingyu Pan
+# @Email  : xy_pan@foxmail.com
 
 import os
 import unittest
@@ -38,16 +42,12 @@ def test_default_settings(self):
         self.assertIsInstance(config['train_batch_size'], int)
         self.assertIsInstance(config['learner'], str)
         self.assertIsInstance(config['learning_rate'], float)
-        self.assertIsInstance(config['training_neg_sample_num'], int)
+        self.assertIsInstance(config['neg_sampling'], dict)
         self.assertIsInstance(config['eval_step'], int)
         self.assertIsInstance(config['stopping_step'], int)
         self.assertIsInstance(config['checkpoint_dir'], str)
 
-        self.assertIsInstance(config['eval_setting'], str)
-        self.assertIsInstance(config['group_by_user'], bool)
-        self.assertIsInstance(config['split_ratio'], list)
-        self.assertIsInstance(config['leave_one_num'], int)
-        self.assertIsInstance(config['real_time_process'], bool)
+        self.assertIsInstance(config['eval_args'], dict)
         self.assertIsInstance(config['metrics'], list)
         self.assertIsInstance(config['topk'], list)
         self.assertIsInstance(config['valid_metric'], str)
@@ -56,26 +56,35 @@ def test_default_settings(self):
     def test_default_context_settings(self):
         config = Config(model='FM', dataset='ml-100k')
 
-        self.assertEqual(config['eval_setting'], 'RO_RS')
-        self.assertEqual(config['group_by_user'], False)
+        self.assertEqual(config['eval_args']['split'], {'RS': [0.8,0.1,0.1]})
+        self.assertEqual(config['eval_args']['order'], 'RO')
+        self.assertEqual(config['eval_args']['mode'],'labeled')
+        self.assertEqual(config['eval_args']['group_by'], None)
+
         self.assertEqual(config['metrics'], ['AUC', 'LogLoss'])
         self.assertEqual(config['valid_metric'], 'AUC')
-        self.assertEqual(config['training_neg_sample_num'], 0)
+        self.assertEqual(config['neg_sampling'], None)
 
     def test_default_sequential_settings(self):
         para_dict = {
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         config = Config(model='SASRec', dataset='ml-100k', config_dict=para_dict)
-        self.assertEqual(config['eval_setting'], 'TO_LS,full')
-
+        self.assertEqual(config['eval_args']['split'], {'LS': 'valid_and_test'})
+        self.assertEqual(config['eval_args']['order'], 'TO')
+        self.assertEqual(config['eval_args']['mode'],'full')
+        self.assertEqual(config['eval_args']['group_by'], 'user')
+        
     def test_config_file_list(self):
         config = Config(model='BPR', dataset='ml-100k', config_file_list=config_file_list)
 
         self.assertEqual(config['model'], 'BPR')
         self.assertEqual(config['learning_rate'], 0.1)
         self.assertEqual(config['topk'], [5, 20])
-        self.assertEqual(config['eval_setting'], 'TO_LS,full')
+        self.assertEqual(config['eval_args']['split'], {'LS': 'valid_and_test'})
+        self.assertEqual(config['eval_args']['order'], 'TO')
+        self.assertEqual(config['eval_args']['mode'],'full')
+        self.assertEqual(config['eval_args']['group_by'], 'user')
 
     def test_config_dict(self):
         config = Config(model='BPR', dataset='ml-100k', config_dict=parameters_dict)
@@ -83,7 +92,10 @@ def test_config_dict(self):
         self.assertEqual(config['model'], 'BPR')
         self.assertEqual(config['learning_rate'], 0.2)
         self.assertEqual(config['topk'], [50, 100])
-        self.assertEqual(config['eval_setting'], 'RO_RS,full')
+        self.assertEqual(config['eval_args']['split'], {'RS': [0.8, 0.1, 0.1]})
+        self.assertEqual(config['eval_args']['order'], 'RO')
+        self.assertEqual(config['eval_args']['mode'],'full')
+        self.assertEqual(config['eval_args']['group_by'], 'user')
 
     # todo: add command line test examples
     def test_priority(self):
@@ -92,7 +104,10 @@ def test_priority(self):
 
         self.assertEqual(config['learning_rate'], 0.2)  # default, file, dict
         self.assertEqual(config['topk'], [50, 100])     # default, file, dict
-        self.assertEqual(config['eval_setting'], 'TO_LS,full')  # default, file
+        self.assertEqual(config['eval_args']['split'], {'LS': 'valid_and_test'})
+        self.assertEqual(config['eval_args']['order'], 'TO')
+        self.assertEqual(config['eval_args']['mode'],'full')
+        self.assertEqual(config['eval_args']['group_by'], 'user')
         self.assertEqual(config['epochs'], 100)                 # default, dict
 
 
diff --git a/tests/config/test_config_example.yaml b/tests/config/test_config_example.yaml
index 741d51ad7..09a0ec111 100644
--- a/tests/config/test_config_example.yaml
+++ b/tests/config/test_config_example.yaml
@@ -1,4 +1,7 @@
 model: FM
 learning_rate: 0.1
 topk: [5, 20]
-eval_setting: 'TO_LS,full'
\ No newline at end of file
+eval_args: 
+  split: {'LS': 'valid_and_test'}
+  mode: full
+  order: TO
\ No newline at end of file
diff --git a/tests/config/test_overall.py b/tests/config/test_overall.py
index 78b820cca..7838ab52a 100644
--- a/tests/config/test_overall.py
+++ b/tests/config/test_overall.py
@@ -4,9 +4,10 @@
 # @email   :   tsotfsk@outlook.com
 
 # UPDATE:
-# @Time   : 2020/11/17
+# @Time   : 2021/7/1
 # @Author : Xingyu Pan
-# @Email  : panxy@ruc.edu.cn
+# @Email  : xy_pan@foxmail.com
+
 import os
 import sys
 import unittest
@@ -22,7 +23,7 @@
 def run_parms(parm_dict, extra_dict=None):
     config_dict = {
         'epochs': 1,
-        'state': 'CRITICAL'
+        'state': 'INFO'
     }
     for name, parms in parm_dict.items():
         for parm in parms:
@@ -43,14 +44,14 @@ def setUp(self):
         warnings.simplefilter('ignore', ResourceWarning)
 
     def test_gpu_id(self):
-        self.assertTrue(run_parms({'gpu_id':['0', '-1', '1']}))
+        self.assertTrue(run_parms({'gpu_id': ['0', '-1', '1']}))
 
     def test_use_gpu(self):
         self.assertTrue(run_parms({'use_gpu': [True, False]}))
 
     def test_reproducibility(self):
         self.assertTrue(run_parms({'reproducibility': [True, False]}))
-        
+
     def test_seed(self):
         self.assertTrue(run_parms({'seed': [2021, 1024]}))
 
@@ -69,19 +70,18 @@ def test_learner(self):
     def test_learning_rate(self):
         self.assertTrue(run_parms({'learning_rate': [0, 0.001, 1e-5]}))
 
-    def test_training_neg_sample_num(self):
-        self.assertTrue(run_parms({'training_neg_sample_num': [  #0,
-         1, 2]}))
+    def test_training_neg_sampling(self):
+        self.assertTrue(run_parms({'neg_sampling': [{'uniform': 1}, {'uniform': 2}, {'uniform': 3}]}))
 
     def test_eval_step(self):
         settings = {
-            'epochs':5
+            'epochs': 5
         }
         self.assertTrue(run_parms({'eval_step': [1, 2]}))
 
     def test_stopping_step(self):
         settings = {
-            'epochs':100
+            'epochs': 100
         }
         self.assertTrue(run_parms({'stopping_step': [0, 1, 2]}))
 
@@ -91,49 +91,35 @@ def test_checkpoint_dir(self):
     def test_eval_batch_size(self):
         self.assertTrue(run_parms({'eval_batch_size': [1, 100]}))
 
-    def test_real_time_process(self):
-        self.assertTrue(run_parms({'real_time_process':[False, True]}))
-
     def test_topk(self):
         settings = {
             'metrics': ["Recall", "MRR", "NDCG", "Hit", "Precision"],
             'valid_metric': 'Recall@1'
         }
-        self.assertTrue(run_parms({'topk':[1, [1, 3]]}, extra_dict=settings))
+        self.assertTrue(run_parms({'topk': [1, [1, 3]]}, extra_dict=settings))
 
     def test_loss(self):
         settings = {
-            'metrics':["MAE", "RMSE", "LOGLOSS", "AUC"],
+            'metrics': ["MAE", "RMSE", "LOGLOSS", "AUC"],
             'valid_metric': 'auc',
-            'eval_setting': 'RO_RS, uni100'
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'RO', 'mode': 'uni100'}
         }
-        self.assertTrue(run_parms({'topk':{None, 1}}, extra_dict=settings))
+        self.assertTrue(run_parms({'topk': {1, }}, extra_dict=settings))
 
     def test_metric(self):
         settings = {
-            'topk':3,
+            'topk': 3,
             'valid_metric': 'Recall@3'
         }
-        self.assertTrue(run_parms({'metrics':["Recall", ["Recall", "MRR", "NDCG", "Hit", "Precision"]]}, extra_dict=settings))
+        self.assertTrue(
+            run_parms({'metrics': ["Recall", ["Recall", "MRR", "NDCG", "Hit", "Precision"]]}, extra_dict=settings)
+        )
 
     def test_split_ratio(self):
-        settings = {
-            'leave_one_num':None
-        }
+        self.assertTrue(run_parms({'eval_args': [{'split': {'RS': [0.8, 0.1, 0.1]}}, {'split': {'RS': [16, 2, 2]}}]}))
 
-        self.assertTrue(run_parms({'split_ratio':[  # [0.8, 0.2], 
-        [0.8, 0.1, 0.1],  [16, 2, 2]]}))
-
-    def test_leave_one_num(self):
-        settings = {
-            'split_ratio':None
-        }
-
-        self.assertTrue(run_parms({'leave_one_num':[1, 2, 3]}))
-        
     def test_group_by_user(self):
-        self.assertTrue(run_parms({'group_by_user':[True, False]}))
-
+        self.assertTrue(run_parms({'eval_args': [{'group_by': 'user'}, {'group_by': 'None'}]}))
 
 
 if __name__ == '__main__':
diff --git a/tests/data/kg_remap_id/kg_remap_id.inter b/tests/data/kg_remap_id/kg_remap_id.inter
new file mode 100644
index 000000000..f8ab8a690
--- /dev/null
+++ b/tests/data/kg_remap_id/kg_remap_id.inter
@@ -0,0 +1,5 @@
+user_id:token	item_id:token
+ua	ia
+ub	ib
+uc	ic
+ud	id
\ No newline at end of file
diff --git a/tests/data/kg_remap_id/kg_remap_id.kg b/tests/data/kg_remap_id/kg_remap_id.kg
new file mode 100644
index 000000000..95f6d4189
--- /dev/null
+++ b/tests/data/kg_remap_id/kg_remap_id.kg
@@ -0,0 +1,5 @@
+head_id:token	tail_id:token	relation_id:token
+eb	ea	ra
+ec	eb	rb
+ed	ec	rc
+ee	ed	rd
\ No newline at end of file
diff --git a/tests/data/kg_remap_id/kg_remap_id.link b/tests/data/kg_remap_id/kg_remap_id.link
new file mode 100644
index 000000000..3328eccb5
--- /dev/null
+++ b/tests/data/kg_remap_id/kg_remap_id.link
@@ -0,0 +1,5 @@
+item_id:token	entity_id:token
+ib	eb
+ic	ec
+id	ed
+ie	ee
\ No newline at end of file
diff --git a/tests/data/seq_benchmark/seq_benchmark.test.inter b/tests/data/seq_benchmark/seq_benchmark.test.inter
new file mode 100644
index 000000000..e58c2927d
--- /dev/null
+++ b/tests/data/seq_benchmark/seq_benchmark.test.inter
@@ -0,0 +1,5 @@
+user_id:token	item_id:token	timestamp:float	item_id_list:token_seq	timestamp_list:float_seq
+1	7	7	1 2 3 4 5 6	1 2 3 4 5 6
+1	8	8	1 2 3 4 5 6 7	1 2 3 4 5 6 7
+2	8	8	4 5 6 7	4 5 6 7
+3	6	6	4 5	4 5
diff --git a/tests/data/seq_benchmark/seq_benchmark.train.inter b/tests/data/seq_benchmark/seq_benchmark.train.inter
new file mode 100644
index 000000000..24b14ddd8
--- /dev/null
+++ b/tests/data/seq_benchmark/seq_benchmark.train.inter
@@ -0,0 +1,8 @@
+user_id:token	item_id:token	timestamp:float	item_id_list:token_seq	timestamp_list:float_seq
+1	2	2	1	1
+1	3	3	1 2	1 2
+1	4	4	1 2 3	1 2 3
+4	4	4	3	3
+2	5	5	4	4
+2	6	6	4 5	4 5
+3	5	5	4	4
diff --git a/tests/data/seq_benchmark/seq_benchmark.valid.inter b/tests/data/seq_benchmark/seq_benchmark.valid.inter
new file mode 100644
index 000000000..ce15c506c
--- /dev/null
+++ b/tests/data/seq_benchmark/seq_benchmark.valid.inter
@@ -0,0 +1,4 @@
+user_id:token	item_id:token	timestamp:float	item_id_list:token_seq	timestamp_list:float_seq
+1	5	5	1 2 3 4	1 2 3 4
+1	6	6	1 2 3 4 5	1 2 3 4 5
+2	7	7	4 5 6	4 5 6
diff --git a/tests/data/test_dataloader.py b/tests/data/test_dataloader.py
index e79e86030..5659dad8b 100644
--- a/tests/data/test_dataloader.py
+++ b/tests/data/test_dataloader.py
@@ -4,9 +4,9 @@
 # @Email  : chenyushuo@ruc.edu.cn
 
 # UPDATE
-# @Time    :   2020/1/5
-# @Author  :   Yushuo Chen
-# @email   :   chenyushuo@ruc.edu.cn
+# @Time    :   2020/1/5, 2021/7/1, 2021/7/19
+# @Author  :   Yushuo Chen, Xingyu Pan, Zhichao Feng
+# @email   :   chenyushuo@ruc.edu.cn, xy_pan@foxmail.com, fzcbupt@gmail.com
 
 import logging
 import os
@@ -37,23 +37,26 @@ def test_general_dataloader(self):
             'dataset': 'general_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS',
-            'training_neg_sample_num': 0,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'labeled'},
+            'neg_sampling': None,
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
         train_data, valid_data, test_data = new_dataloader(config_dict=config_dict)
 
-        def check_dataloader(data, item_list, batch_size):
+        def check_dataloader(data, item_list, batch_size, train=False):
             data.shuffle = False
             pr = 0
             for batch_data in data:
                 batch_item_list = item_list[pr: pr + batch_size]
-                assert (batch_data['item_id'].numpy() == batch_item_list).all()
+                if train:
+                    user_df = batch_data
+                else:
+                    user_df = batch_data[0]
+                assert (user_df['item_id'].numpy() == batch_item_list).all()
                 pr += batch_size
 
-        check_dataloader(train_data, list(range(1, 41)), train_batch_size)
+        check_dataloader(train_data, list(range(1, 41)), train_batch_size, True)
         check_dataloader(valid_data, list(range(41, 46)), eval_batch_size)
         check_dataloader(test_data, list(range(46, 51)), eval_batch_size)
 
@@ -65,9 +68,8 @@ def test_general_neg_sample_dataloader_in_pair_wise(self):
             'dataset': 'general_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS,full',
-            'training_neg_sample_num': 1,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'neg_sampling': {'uniform': 1},
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'full'},
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
@@ -93,9 +95,8 @@ def test_general_neg_sample_dataloader_in_point_wise(self):
             'dataset': 'general_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS,full',
-            'training_neg_sample_num': 1,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'neg_sampling': {'uniform': 1},
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'full'},
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
@@ -121,9 +122,8 @@ def test_general_full_dataloader(self):
             'dataset': 'general_full_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS,full',
-            'training_neg_sample_num': 1,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'neg_sampling': {'uniform': 1},
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'full'},
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
@@ -132,59 +132,43 @@ def test_general_full_dataloader(self):
         def check_result(data, result):
             assert len(data) == len(result)
             for i, batch_data in enumerate(data):
-                user_df, history_index, swap_row, swap_col_after, swap_col_before = batch_data
+                user_df, history_index, positive_u, positive_i = batch_data
                 history_row, history_col = history_index
                 assert len(user_df) == result[i]['len_user_df']
                 assert (user_df['user_id'].numpy() == result[i]['user_df_user_id']).all()
-                assert (user_df.pos_len_list == result[i]['pos_len_list']).all()
-                assert (user_df.user_len_list == result[i]['user_len_list']).all()
                 assert len(history_row) == len(history_col) == result[i]['history_len']
                 assert (history_row.numpy() == result[i]['history_row']).all()
                 assert (history_col.numpy() == result[i]['history_col']).all()
-                assert len(swap_row) == len(swap_col_after) == len(swap_col_before) == result[i]['swap_len']
-                assert (swap_row.numpy() == result[i]['swap_row']).all()
-                assert (swap_col_after.numpy() == result[i]['swap_col_after']).all()
-                assert (swap_col_before.numpy() == result[i]['swap_col_before']).all()
+                assert (positive_u.numpy() == result[i]['positive_u']).all()
+                assert (positive_i.numpy() == result[i]['positive_i']).all()
 
         valid_result = [
             {
                 'len_user_df': 1,
                 'user_df_user_id': [1],
-                'pos_len_list': [5],
-                'user_len_list': [101],
                 'history_len': 40,
                 'history_row': 0,
                 'history_col': list(range(1, 41)),
-                'swap_len': 10,
-                'swap_row': 0,
-                'swap_col_after': [0, 1, 2, 3, 4, 41, 42, 43, 44, 45],
-                'swap_col_before': [45, 44, 43, 42, 41, 4, 3, 2, 1, 0],
+                'positive_u': [0, 0, 0, 0, 0],
+                'positive_i': [41, 42, 43, 44, 45]
             },
             {
                 'len_user_df': 1,
                 'user_df_user_id': [2],
-                'pos_len_list': [5],
-                'user_len_list': [101],
                 'history_len': 37,
                 'history_row': 0,
                 'history_col': list(range(1, 38)),
-                'swap_len': 10,
-                'swap_row': 0,
-                'swap_col_after': [0, 1, 2, 3, 4, 38, 39, 40, 41, 42],
-                'swap_col_before': [42, 41, 40, 39, 38, 4, 3, 2, 1, 0],
+                'positive_u': [0, 0, 0, 0, 0],
+                'positive_i': [38, 39, 40, 41, 42]
             },
             {
                 'len_user_df': 1,
                 'user_df_user_id': [3],
-                'pos_len_list': [1],
-                'user_len_list': [101],
                 'history_len': 0,
                 'history_row': [],
                 'history_col': [],
-                'swap_len': 2,
-                'swap_row': 0,
-                'swap_col_after': [0, 1],
-                'swap_col_before': [1, 0],
+                'positive_u': [0],
+                'positive_i': [1]
             },
         ]
         check_result(valid_data, valid_result)
@@ -193,41 +177,29 @@ def check_result(data, result):
             {
                 'len_user_df': 1,
                 'user_df_user_id': [1],
-                'pos_len_list': [5],
-                'user_len_list': [101],
                 'history_len': 45,
                 'history_row': 0,
                 'history_col': list(range(1, 46)),
-                'swap_len': 10,
-                'swap_row': 0,
-                'swap_col_after': [0, 1, 2, 3, 4, 46, 47, 48, 49, 50],
-                'swap_col_before': [50, 49, 48, 47, 46, 4, 3, 2, 1, 0],
+                'positive_u': [0, 0, 0, 0, 0],
+                'positive_i': [46, 47, 48, 49, 50]
             },
             {
                 'len_user_df': 1,
                 'user_df_user_id': [2],
-                'pos_len_list': [5],
-                'user_len_list': [101],
                 'history_len': 37,
                 'history_row': 0,
                 'history_col': list(range(1, 36)) + [41, 42],
-                'swap_len': 10,
-                'swap_row': 0,
-                'swap_col_after': [0, 1, 2, 3, 4, 36, 37, 38, 39, 40],
-                'swap_col_before': [40, 39, 38, 37, 36, 4, 3, 2, 1, 0],
+                'positive_u': [0, 0, 0, 0, 0],
+                'positive_i': [36, 37, 38, 39, 40]
             },
             {
                 'len_user_df': 1,
                 'user_df_user_id': [3],
-                'pos_len_list': [1],
-                'user_len_list': [101],
                 'history_len': 0,
                 'history_row': [],
                 'history_col': [],
-                'swap_len': 2,
-                'swap_row': 0,
-                'swap_col_after': [0, 1],
-                'swap_col_before': [1, 0],
+                'positive_u': [0],
+                'positive_i': [1]
             },
         ]
         check_result(test_data, test_result)
@@ -240,9 +212,8 @@ def test_general_uni100_dataloader_with_batch_size_in_101(self):
             'dataset': 'general_uni100_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS,uni100',
-            'training_neg_sample_num': 1,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'neg_sampling': {'uniform': 1},
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'uni100'},
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
@@ -252,30 +223,35 @@ def check_result(data, result):
             assert data.batch_size == 202
             assert len(data) == len(result)
             for i, batch_data in enumerate(data):
-                assert result[i]['item_id_check'](batch_data['item_id'])
-                assert batch_data.pos_len_list == result[i]['pos_len_list']
-                assert batch_data.user_len_list == result[i]['user_len_list']
+                user_df, row_idx, positive_u, positive_i = batch_data
+                assert result[i]['item_id_check'](user_df['item_id'])
+                assert (row_idx.numpy() == result[i]['row_idx']).all()
+                assert (positive_u.numpy() == result[i]['positive_u']).all()
+                assert (positive_i.numpy() == result[i]['positive_i']).all()
 
         valid_result = [
             {
                 'item_id_check': lambda data: data[0] == 9
                                               and (8 < data[1:]).all()
                                               and (data[1:] <= 100).all(),
-                'pos_len_list': [1],
-                'user_len_list': [101],
+                'row_idx': [0] * 101,
+                'positive_u': [0],
+                'positive_i': [9],
             },
             {
                 'item_id_check': lambda data: data[0] == 1
                                               and (data[1:] != 1).all(),
-                'pos_len_list': [1],
-                'user_len_list': [101],
+                'row_idx': [0] * 101,
+                'positive_u': [0],
+                'positive_i': [1],
             },
             {
                 'item_id_check': lambda data: (data[0: 2].numpy() == [17, 18]).all()
                                               and (16 < data[2:]).all()
                                               and (data[2:] <= 100).all(),
-                'pos_len_list': [2],
-                'user_len_list': [202],
+                'row_idx': [0] * 202,
+                'positive_u': [0, 0],
+                'positive_i': [17, 18],
             },
         ]
         check_result(valid_data, valid_result)
@@ -285,21 +261,24 @@ def check_result(data, result):
                 'item_id_check': lambda data: data[0] == 10
                                               and (9 < data[1:]).all()
                                               and (data[1:] <= 100).all(),
-                'pos_len_list': [1],
-                'user_len_list': [101],
+                'row_idx': [0] * 101,
+                'positive_u': [0],
+                'positive_i': [10],
             },
             {
                 'item_id_check': lambda data: data[0] == 1
                                               and (data[1:] != 1).all(),
-                'pos_len_list': [1],
-                'user_len_list': [101],
+                'row_idx': [0] * 101,
+                'positive_u': [0],
+                'positive_i': [1],
             },
             {
                 'item_id_check': lambda data: (data[0: 2].numpy() == [19, 20]).all()
                                               and (18 < data[2:]).all()
                                               and (data[2:] <= 100).all(),
-                'pos_len_list': [2],
-                'user_len_list': [202],
+                'row_idx': [0] * 202,
+                'positive_u': [0, 0],
+                'positive_i': [19, 20],
             },
         ]
         check_result(test_data, test_result)
@@ -312,9 +291,8 @@ def test_general_uni100_dataloader_with_batch_size_in_303(self):
             'dataset': 'general_uni100_dataloader',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS,uni100',
-            'training_neg_sample_num': 1,
-            'split_ratio': [0.8, 0.1, 0.1],
+            'neg_sampling': {'uniform': 1},
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'uni100'},
             'train_batch_size': train_batch_size,
             'eval_batch_size': eval_batch_size,
         }
@@ -324,9 +302,11 @@ def check_result(data, result):
             assert data.batch_size == 303
             assert len(data) == len(result)
             for i, batch_data in enumerate(data):
-                assert result[i]['item_id_check'](batch_data['item_id'])
-                assert batch_data.pos_len_list == result[i]['pos_len_list']
-                assert batch_data.user_len_list == result[i]['user_len_list']
+                user_df, row_idx, positive_u, positive_i = batch_data
+                assert result[i]['item_id_check'](user_df['item_id'])
+                assert (row_idx.numpy() == result[i]['row_idx']).all()
+                assert (positive_u.numpy() == result[i]['positive_u']).all()
+                assert (positive_i.numpy() == result[i]['positive_i']).all()
 
         valid_result = [
             {
@@ -335,15 +315,17 @@ def check_result(data, result):
                                               and (data[1: 101] <= 100).all()
                                               and data[101] == 1
                                               and (data[102:202] != 1).all(),
-                'pos_len_list': [1, 1],
-                'user_len_list': [101, 101],
+                'row_idx': [0] * 101 + [1] * 101,
+                'positive_u': [0, 1],
+                'positive_i': [9, 1],
             },
             {
                 'item_id_check': lambda data: (data[0: 2].numpy() == [17, 18]).all()
                                               and (16 < data[2:]).all()
                                               and (data[2:] <= 100).all(),
-                'pos_len_list': [2],
-                'user_len_list': [202],
+                'row_idx': [0] * 202,
+                'positive_u': [0, 0],
+                'positive_i': [17, 18],
             },
         ]
         check_result(valid_data, valid_result)
@@ -355,15 +337,17 @@ def check_result(data, result):
                                               and (data[1:101] <= 100).all()
                                               and data[101] == 1
                                               and (data[102:202] != 1).all(),
-                'pos_len_list': [1, 1],
-                'user_len_list': [101, 101],
+                'row_idx': [0] * 101 + [1] * 101,
+                'positive_u': [0, 1],
+                'positive_i': [10, 1],
             },
             {
                 'item_id_check': lambda data: (data[0: 2].numpy() == [19, 20]).all()
                                               and (18 < data[2:]).all()
                                               and (data[2:] <= 100).all(),
-                'pos_len_list': [2],
-                'user_len_list': [202],
+                'row_idx': [0] * 202,
+                'positive_u': [0, 0],
+                'positive_i': [19, 20],
             },
         ]
         check_result(test_data, test_result)
diff --git a/tests/data/test_dataset.py b/tests/data/test_dataset.py
index 3550f00d6..54484d8e5 100644
--- a/tests/data/test_dataset.py
+++ b/tests/data/test_dataset.py
@@ -4,16 +4,16 @@
 # @Email  : chenyushuo@ruc.edu.cn
 
 # UPDATE
-# @Time    :   2020/1/3
-# @Author  :   Yushuo Chen
-# @email   :   chenyushuo@ruc.edu.cn
+# @Time    :   2020/1/3, 2021/7/1, 2021/7/11
+# @Author  :   Yushuo Chen, Xingyu Pan, Yupeng Hou
+# @email   :   chenyushuo@ruc.edu.cn, xy_pan@foxmail.com, houyupeng@ruc.edu.cn
 
 import logging
 import os
 
 import pytest
 
-from recbole.config import Config, EvalSetting
+from recbole.config import Config
 from recbole.data import create_dataset
 from recbole.utils import init_seed
 
@@ -29,11 +29,7 @@ def new_dataset(config_dict=None, config_file_list=None):
 
 def split_dataset(config_dict=None, config_file_list=None):
     dataset = new_dataset(config_dict=config_dict, config_file_list=config_file_list)
-    config = dataset.config
-    es_str = [_.strip() for _ in config['eval_setting'].split(',')]
-    es = EvalSetting(config)
-    es.set_ordering_and_splitting(es_str[0])
-    return dataset.build(es)
+    return dataset.build()
 
 
 class TestDataset:
@@ -77,8 +73,8 @@ def test_filter_by_field_value_with_lowest_val(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'lowest_val': {
-                'timestamp': 4,
+            'val_interval': {
+                'timestamp': "[4,inf)",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -90,8 +86,8 @@ def test_filter_by_field_value_with_highest_val(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'highest_val': {
-                'timestamp': 4,
+            'val_interval': {
+                'timestamp': "(-inf,4]",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -103,8 +99,8 @@ def test_filter_by_field_value_with_equal_val(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'equal_val': {
-                'rating': 0,
+            'val_interval': {
+                'rating': "[0,0]",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -116,8 +112,8 @@ def test_filter_by_field_value_with_not_equal_val(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'not_equal_val': {
-                'rating': 4,
+            'val_interval': {
+                'rating': "(-inf,4);(4,inf)",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -129,11 +125,8 @@ def test_filter_by_field_value_in_same_field(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'lowest_val': {
-                'timestamp': 3,
-            },
-            'highest_val': {
-                'timestamp': 8,
+            'val_interval': {
+                'timestamp': "[3,8]",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -145,14 +138,9 @@ def test_filter_by_field_value_in_different_field(self):
             'dataset': 'filter_by_field_value',
             'data_path': current_path,
             'load_col': None,
-            'lowest_val': {
-                'timestamp': 3,
-            },
-            'highest_val': {
-                'timestamp': 8,
-            },
-            'not_equal_val': {
-                'rating': 4,
+            'val_interval': {
+                'timestamp': "[3,8]",
+                'rating': "(-inf,4);(4,inf)",
             }
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -186,7 +174,7 @@ def test_filter_by_inter_num_in_min_user_inter_num(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'min_user_inter_num': 2,
+            'user_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 6
@@ -198,7 +186,7 @@ def test_filter_by_inter_num_in_min_item_inter_num(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'min_item_inter_num': 2,
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 7
@@ -210,7 +198,7 @@ def test_filter_by_inter_num_in_max_user_inter_num(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'max_user_inter_num': 2,
+            'user_inter_num_interval': "(-inf,2]",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 6
@@ -222,7 +210,7 @@ def test_filter_by_inter_num_in_max_item_inter_num(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'max_item_inter_num': 2,
+            'item_inter_num_interval': "(-inf,2]",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 5
@@ -234,8 +222,8 @@ def test_filter_by_inter_num_in_min_inter_num(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'min_user_inter_num': 2,
-            'min_item_inter_num': 2,
+            'user_inter_num_interval': "[2,inf)",
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 5
@@ -247,9 +235,8 @@ def test_filter_by_inter_num_in_complex_way(self):
             'dataset': 'filter_by_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'max_user_inter_num': 3,
-            'min_user_inter_num': 2,
-            'min_item_inter_num': 2,
+            'user_inter_num_interval': "[2,3]",
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert dataset.user_num == 3
@@ -262,8 +249,8 @@ def test_rm_dup_by_first_and_filter_value(self):
             'data_path': current_path,
             'load_col': None,
             'rm_dup_inter': 'first',
-            'highest_val': {
-                'rating': 4,
+            'val_interval': {
+                'rating': "(-inf,4]",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -276,8 +263,8 @@ def test_rm_dup_by_last_and_filter_value(self):
             'data_path': current_path,
             'load_col': None,
             'rm_dup_inter': 'last',
-            'highest_val': {
-                'rating': 4,
+            'val_interval': {
+                'rating': "(-inf,4]",
             },
         }
         dataset = new_dataset(config_dict=config_dict)
@@ -290,8 +277,8 @@ def test_rm_dup_and_filter_by_inter_num(self):
             'data_path': current_path,
             'load_col': None,
             'rm_dup_inter': 'first',
-            'min_user_inter_num': 2,
-            'min_item_inter_num': 2,
+            'user_inter_num_interval': "[2,inf)",
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert len(dataset.inter_feat) == 4
@@ -304,11 +291,9 @@ def test_filter_value_and_filter_inter_by_ui(self):
             'dataset': 'filter_value_and_filter_inter_by_ui',
             'data_path': current_path,
             'load_col': None,
-            'highest_val': {
-                'age': 2,
-            },
-            'not_equal_val': {
-                'price': 2,
+            'val_interval': {
+                'age': "(-inf,2]",
+                'price': "(-inf,2);(2,inf)",
             },
             'filter_inter_by_user_or_item': True,
         }
@@ -323,13 +308,13 @@ def test_filter_value_and_inter_num(self):
             'dataset': 'filter_value_and_inter_num',
             'data_path': current_path,
             'load_col': None,
-            'highest_val': {
-                'rating': 0,
-                'age': 0,
-                'price': 0,
+            'val_interval': {
+                'rating': "(-inf,0]",
+                'age': "(-inf,0]",
+                'price': "(-inf,0]",
             },
-            'min_user_inter_num': 2,
-            'min_item_inter_num': 2,
+            'user_inter_num_interval': "[2,inf)",
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert len(dataset.inter_feat) == 4
@@ -343,8 +328,8 @@ def test_filter_inter_by_ui_and_inter_num(self):
             'data_path': current_path,
             'load_col': None,
             'filter_inter_by_user_or_item': True,
-            'min_user_inter_num': 2,
-            'min_item_inter_num': 2,
+            'user_inter_num_interval': "[2,inf)",
+            'item_inter_num_interval': "[2,inf)",
         }
         dataset = new_dataset(config_dict=config_dict)
         assert len(dataset.inter_feat) == 4
@@ -357,7 +342,6 @@ def test_remap_id(self):
             'dataset': 'remap_id',
             'data_path': current_path,
             'load_col': None,
-            'fields_in_same_space': None,
         }
         dataset = new_dataset(config_dict=config_dict)
         user_list = dataset.token2id('user_id', ['ua', 'ub', 'uc', 'ud'])
@@ -373,16 +357,14 @@ def test_remap_id(self):
         assert (dataset.inter_feat['user_list'][2] == [3, 4, 1]).all()
         assert (dataset.inter_feat['user_list'][3] == [5]).all()
 
-    def test_remap_id_with_fields_in_same_space(self):
+    def test_remap_id_with_alias(self):
         config_dict = {
             'model': 'BPR',
             'dataset': 'remap_id',
             'data_path': current_path,
             'load_col': None,
-            'fields_in_same_space': [
-                ['user_id', 'add_user', 'user_list'],
-                ['item_id', 'add_item'],
-            ],
+            'alias_of_user_id': ['add_user', 'user_list'],
+            'alias_of_item_id': ['add_item'],
         }
         dataset = new_dataset(config_dict=config_dict)
         user_list = dataset.token2id('user_id', ['ua', 'ub', 'uc', 'ud', 'ue', 'uf'])
@@ -473,8 +455,7 @@ def test_TO_RS_811(self):
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS',
-            'split_ratio': [0.8, 0.1, 0.1],
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 17)) + [1] + [1] + [1] + [1, 2, 3] +
@@ -490,8 +471,7 @@ def test_TO_RS_820(self):
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS',
-            'split_ratio': [0.8, 0.2, 0.0],
+            'eval_args': {'split': {'RS': [0.8, 0.2, 0.0]}, 'order': 'TO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 17)) + [1] + [1] + [1, 2] + [1, 2, 3, 4] +
@@ -506,8 +486,7 @@ def test_TO_RS_802(self):
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_RS',
-            'split_ratio': [0.8, 0.0, 0.2],
+            'eval_args': {'split': {'RS': [0.8, 0.0, 0.2]}, 'order': 'TO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 17)) + [1] + [1] + [1, 2] + [1, 2, 3, 4] +
@@ -516,14 +495,13 @@ def test_TO_RS_802(self):
         assert (test_dataset.inter_feat['item_id'].numpy() == list(range(17, 21)) + [] + [2] + [3] + [5] +
                 [9] + [9, 10] + [10, 11]).all()
 
-    def test_TO_LS(self):
+    def test_TO_LS_valid_and_test(self):
         config_dict = {
             'model': 'BPR',
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'TO_LS',
-            'leave_one_num': 2,
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'TO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 19)) + [1] + [1] + [1] + [1, 2, 3] +
@@ -533,14 +511,43 @@ def test_TO_LS(self):
         assert (test_dataset.inter_feat['item_id'].numpy() == list(range(20, 21)) + [] + [2] + [3] + [5] +
                 [9] + [10] + [11]).all()
 
+    def test_TO_LS_valid_only(self):
+        config_dict = {
+            'model': 'BPR',
+            'dataset': 'build_dataset',
+            'data_path': current_path,
+            'load_col': None,
+            'eval_args': {'split': {'LS': 'valid_only'}, 'order': 'TO', 'mode': 'labeled'}
+        }
+        train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
+        assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 20)) + [1] + [1] + [1, 2] + [1, 2, 3, 4] +
+                list(range(1, 9)) + list(range(1, 10)) + list(range(1, 11))).all()
+        assert (valid_dataset.inter_feat['item_id'].numpy() == list(range(20, 21)) + [] + [2] + [3] + [5] +
+                [9] + [10] + [11]).all()
+        assert len(test_dataset.inter_feat) == 0
+
+    def test_TO_LS_test_only(self):
+        config_dict = {
+            'model': 'BPR',
+            'dataset': 'build_dataset',
+            'data_path': current_path,
+            'load_col': None,
+            'eval_args': {'split': {'LS': 'test_only'}, 'order': 'TO', 'mode': 'labeled'}
+        }
+        train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
+        assert (train_dataset.inter_feat['item_id'].numpy() == list(range(1, 20)) + [1] + [1] + [1, 2] + [1, 2, 3, 4] +
+                list(range(1, 9)) + list(range(1, 10)) + list(range(1, 11))).all()
+        assert len(valid_dataset.inter_feat) == 0
+        assert (test_dataset.inter_feat['item_id'].numpy() == list(range(20, 21)) + [] + [2] + [3] + [5] +
+                [9] + [10] + [11]).all()
+
     def test_RO_RS_811(self):
         config_dict = {
             'model': 'BPR',
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'RO_RS',
-            'split_ratio': [0.8, 0.1, 0.1],
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'RO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert len(train_dataset.inter_feat) == 16 + 1 + 1 + 1 + 3 + 7 + 8 + 9
@@ -553,8 +560,7 @@ def test_RO_RS_820(self):
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'RO_RS',
-            'split_ratio': [0.8, 0.2, 0.0],
+            'eval_args': {'split': {'RS': [0.8, 0.2, 0.0]}, 'order': 'RO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert len(train_dataset.inter_feat) == 16 + 1 + 1 + 2 + 4 + 8 + 8 + 9
@@ -567,8 +573,7 @@ def test_RO_RS_802(self):
             'dataset': 'build_dataset',
             'data_path': current_path,
             'load_col': None,
-            'eval_setting': 'RO_RS',
-            'split_ratio': [0.8, 0.0, 0.2],
+            'eval_args': {'split': {'RS': [0.8, 0.0, 0.2]}, 'order': 'RO', 'mode': 'labeled'}
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
         assert len(train_dataset.inter_feat) == 16 + 1 + 1 + 2 + 4 + 8 + 8 + 9
@@ -583,24 +588,38 @@ def test_seq_leave_one_out(self):
             'dataset': 'seq_dataset',
             'data_path': current_path,
             'load_col': None,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
-        assert (train_dataset.uid_list == [1, 1, 1, 1, 1, 2, 2, 3, 4]).all()
-        assert (train_dataset.item_list_index == [slice(0, 1), slice(0, 2), slice(0, 3), slice(0, 4), slice(0, 5),
-                                                  slice(8, 9), slice(8, 10), slice(13, 14), slice(16, 17)]).all()
-        assert (train_dataset.target_index == [1, 2, 3, 4, 5, 9, 10, 14, 17]).all()
-        assert (train_dataset.item_list_length == [1, 2, 3, 4, 5, 1, 2, 1, 1]).all()
-
-        assert (valid_dataset.uid_list == [1, 2]).all()
-        assert (valid_dataset.item_list_index == [slice(0, 6), slice(8, 11)]).all()
-        assert (valid_dataset.target_index == [6, 11]).all()
-        assert (valid_dataset.item_list_length == [6, 3]).all()
-
-        assert (test_dataset.uid_list == [1, 2, 3]).all()
-        assert (test_dataset.item_list_index == [slice(0, 7), slice(8, 12), slice(13, 15)]).all()
-        assert (test_dataset.target_index == [7, 12, 15]).all()
-        assert (test_dataset.item_list_length == [7, 4, 2]).all()
+        assert (train_dataset.inter_feat[train_dataset.uid_field].numpy() == [1, 1, 1, 1, 1, 4, 2, 2, 3]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_id_list_field][:, :5].numpy() == [
+            [1, 0, 0, 0, 0],
+            [1, 2, 0, 0, 0],
+            [1, 2, 3, 0, 0],
+            [1, 2, 3, 4, 0],
+            [1, 2, 3, 4, 5],
+            [3, 0, 0, 0, 0],
+            [4, 0, 0, 0, 0],
+            [4, 5, 0, 0, 0],
+            [4, 0, 0, 0, 0]]).all()
+        assert (train_dataset.inter_feat[train_dataset.iid_field].numpy() == [2, 3, 4, 5, 6, 4, 5, 6, 5]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_list_length_field].numpy() == [1, 2, 3, 4, 5, 1, 1, 2,
+                                                                                           1]).all()
+
+        assert (valid_dataset.inter_feat[valid_dataset.uid_field].numpy() == [1, 2]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_id_list_field][:, :6].numpy() == [
+            [1, 2, 3, 4, 5, 6],
+            [4, 5, 6, 0, 0, 0]]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.iid_field].numpy() == [7, 7]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_list_length_field].numpy() == [6, 3]).all()
+
+        assert (test_dataset.inter_feat[test_dataset.uid_field].numpy() == [1, 2, 3]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_id_list_field][:, :7].numpy() == [
+            [1, 2, 3, 4, 5, 6, 7],
+            [4, 5, 6, 7, 0, 0, 0],
+            [4, 5, 0, 0, 0, 0, 0]]).all()
+        assert (test_dataset.inter_feat[test_dataset.iid_field].numpy() == [8, 8, 6]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_list_length_field].numpy() == [7, 4, 2]).all()
 
         assert (train_dataset.inter_matrix().toarray() == [
             [0., 0., 0., 0., 0., 0., 0., 0., 0.],
@@ -611,19 +630,121 @@ def test_seq_leave_one_out(self):
         ]).all()
         assert (valid_dataset.inter_matrix().toarray() == [
             [0., 0., 0., 0., 0., 0., 0., 0., 0.],
-            [0., 1., 1., 1., 1., 1., 1., 1., 0.],
-            [0., 0., 0., 0., 1., 1., 1., 1., 0.],
-            [0., 0., 0., 0., 1., 1., 0., 0., 0.],
-            [0., 0., 0., 1., 1., 0., 0., 0., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 1., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 1., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 0., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 0., 0.]
         ]).all()
         assert (test_dataset.inter_matrix().toarray() == [
             [0., 0., 0., 0., 0., 0., 0., 0., 0.],
-            [0., 1., 1., 1., 1., 1., 1., 1., 1.],
-            [0., 0., 0., 0., 1., 1., 1., 1., 1.],
-            [0., 0., 0., 0., 1., 1., 1., 0., 0.],
-            [0., 0., 0., 1., 1., 0., 0., 0., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 0., 1.],
+            [0., 0., 0., 0., 0., 0., 0., 0., 1.],
+            [0., 0., 0., 0., 0., 0., 1., 0., 0.],
+            [0., 0., 0., 0., 0., 0., 0., 0., 0.]
         ]).all()
 
+    def test_seq_split_by_ratio(self):
+        config_dict = {
+            'model': 'GRU4Rec',
+            'dataset': 'seq_dataset',
+            'data_path': current_path,
+            'load_col': None,
+            'neg_sampling': None,
+            'eval_args': {
+                'split': {'RS': [0.3, 0.3, 0.4]},
+                'order': 'TO'
+            }
+        }
+        train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
+        assert (train_dataset.inter_feat[train_dataset.uid_field].numpy() == [1, 1, 1, 4, 2, 2, 3]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_id_list_field][:, :3].numpy() == [
+            [1, 0, 0],
+            [1, 2, 0],
+            [1, 2, 3],
+            [3, 0, 0],
+            [4, 0, 0],
+            [4, 5, 0],
+            [4, 0, 0]]).all()
+        assert (train_dataset.inter_feat[train_dataset.iid_field].numpy() == [2, 3, 4, 4, 5, 6, 5]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_list_length_field].numpy() == [1, 2, 3, 1, 1, 2, 1]).all()
+
+        assert (valid_dataset.inter_feat[valid_dataset.uid_field].numpy() == [1, 1, 2]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_id_list_field][:, :5].numpy() == [
+            [1, 2, 3, 4, 0],
+            [1, 2, 3, 4, 5],
+            [4, 5, 6, 0, 0]]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.iid_field].numpy() == [5, 6, 7]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_list_length_field].numpy() == [4, 5, 3]).all()
+
+        assert (test_dataset.inter_feat[test_dataset.uid_field].numpy() == [1, 1, 2, 3]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_id_list_field][:, :7].numpy() == [
+            [1, 2, 3, 4, 5, 6, 0],
+            [1, 2, 3, 4, 5, 6, 7],
+            [4, 5, 6, 7, 0, 0, 0],
+            [4, 5, 0, 0, 0, 0, 0]]).all()
+        assert (test_dataset.inter_feat[test_dataset.iid_field].numpy() == [7, 8, 8, 6]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_list_length_field].numpy() == [6, 7, 4, 2]).all()
+
+    def test_seq_benchmark(self):
+        config_dict = {
+            'model': 'GRU4Rec',
+            'dataset': 'seq_benchmark',
+            'data_path': current_path,
+            'load_col': None,
+            'neg_sampling': None,
+            'benchmark_filename': ['train', 'valid', 'test'],
+            'alias_of_item_id': ['item_id_list']
+        }
+        train_dataset, valid_dataset, test_dataset = split_dataset(config_dict=config_dict)
+        assert (train_dataset.inter_feat[train_dataset.uid_field].numpy() == [1, 1, 1, 2, 3, 3, 4]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_id_list_field][:, :3].numpy() == [
+            [8, 0, 0],
+            [8, 1, 0],
+            [8, 1, 2],
+            [2, 0, 0],
+            [3, 0, 0],
+            [3, 4, 0],
+            [3, 0, 0]]).all()
+        assert (train_dataset.inter_feat[train_dataset.iid_field].numpy() == [1, 2, 3, 3, 4, 5, 4]).all()
+        assert (train_dataset.inter_feat[train_dataset.item_list_length_field].numpy() == [1, 2, 3, 1, 1, 2, 1]).all()
+
+        assert (valid_dataset.inter_feat[valid_dataset.uid_field].numpy() == [1, 1, 3]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_id_list_field][:, :5].numpy() == [
+            [8, 1, 2, 3, 0],
+            [8, 1, 2, 3, 4],
+            [3, 4, 5, 0, 0]]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.iid_field].numpy() == [4, 5, 6]).all()
+        assert (valid_dataset.inter_feat[valid_dataset.item_list_length_field].numpy() == [4, 5, 3]).all()
+
+        assert (test_dataset.inter_feat[test_dataset.uid_field].numpy() == [1, 1, 3, 4]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_id_list_field][:, :7].numpy() == [
+            [8, 1, 2, 3, 4, 5, 0],
+            [8, 1, 2, 3, 4, 5, 6],
+            [3, 4, 5, 6, 0, 0, 0],
+            [3, 4, 0, 0, 0, 0, 0]]).all()
+        assert (test_dataset.inter_feat[test_dataset.iid_field].numpy() == [6, 7, 7, 5]).all()
+        assert (test_dataset.inter_feat[test_dataset.item_list_length_field].numpy() == [6, 7, 4, 2]).all()
+
+
+class TestKGDataset:
+    def test_kg_remap_id(self):
+        config_dict = {
+            'model': 'KGAT',
+            'dataset': 'kg_remap_id',
+            'data_path': current_path,
+            'load_col': None,
+        }
+        dataset = new_dataset(config_dict=config_dict)
+        print(dataset.field2id_token['entity_id'])
+        item_list = dataset.token2id('item_id', ['ia', 'ib', 'ic', 'id'])
+        entity_list = dataset.token2id('entity_id', ['eb', 'ec', 'ed', 'ee', 'ea'])
+        assert (item_list == [1, 2, 3, 4]).all()
+        assert (entity_list == [2, 3, 4, 5, 6]).all()
+        assert (dataset.inter_feat['user_id'] == [1, 2, 3, 4]).all()
+        assert (dataset.inter_feat['item_id'] == [1, 2, 3, 4]).all()
+        assert (dataset.kg_feat['head_id'] == [2, 3, 4, 5]).all()
+        assert (dataset.kg_feat['tail_id'] == [6, 2, 3, 4]).all()
+
 
 if __name__ == "__main__":
     pytest.main()
diff --git a/tests/evaluation_setting/test_evaluation_setting.py b/tests/evaluation_setting/test_evaluation_setting.py
index 059f6f010..19d240d14 100644
--- a/tests/evaluation_setting/test_evaluation_setting.py
+++ b/tests/evaluation_setting/test_evaluation_setting.py
@@ -4,9 +4,9 @@
 # @Email  : slmu@ruc.edu.cn
 
 # UPDATE:
-# @Time   : 2020/11/17
+# @Time   : 2021/7/1
 # @Author : Xingyu Pan
-# @Email  : panxy@ruc.edu.cn
+# @Email  : xy_pan@foxmail.com
 import os
 import unittest
 
@@ -20,250 +20,83 @@ class TestGeneralRecommender(unittest.TestCase):
 
     def test_rols_full(self):
         config_dict = {
-            'eval_setting': 'RO_LS,full',
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'RO', 'mode': 'full'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        '''
-        config_dict = {
-            'eval_setting': 'RO_LS,full',
-            'model': 'NeuMF',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        config_dict = {
-            'eval_setting': 'RO_LS,full',
-            'model': 'FISM',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        config_dict = {
-            'eval_setting': 'RO_LS,full',
-            'model': 'LightGCN',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        '''
 
     def test_tols_full(self):
         config_dict = {
-            'eval_setting': 'TO_LS,full',
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'TO', 'mode': 'full'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        '''
-        config_dict = {
-            'eval_setting': 'TO_LS,full',
-            'model': 'NeuMF',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        config_dict = {
-            'eval_setting': 'TO_LS,full',
-            'model': 'FISM',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        config_dict = {
-            'eval_setting': 'TO_LS,full',
-            'model': 'LightGCN',
-        }
-        objective_function(config_dict=config_dict,
-                           config_file_list=config_file_list, saved=False)
-        '''
 
     def test_tors_full(self):
         config_dict = {
-            'eval_setting': 'TO_RS,full',
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'RO', 'mode': 'full'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,full',
-        #     'model': 'NeuMF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,full',
-        #     'model': 'FISM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,full',
-        #     'model': 'LightGCN',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
     def test_rors_uni100(self):
         config_dict = {
-            'eval_setting': 'RO_RS,uni100',
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'RO', 'mode': 'uni100'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_RS,uni100',
-        #     'model': 'NeuMF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_RS,uni100',
-        #     'model': 'FISM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_RS,uni100',
-        #     'model': 'LightGCN',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
     def test_tols_uni100(self):
         config_dict = {
             'eval_setting': 'TO_LS,uni100',
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'TO', 'mode': 'full'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'NeuMF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'FISM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'LightGCN',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
     def test_rols_uni100(self):
         config_dict = {
-            'eval_setting': 'RO_LS,uni100',
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'RO', 'mode': 'uni100'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_LS,uni100',
-        #     'model': 'NeuMF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_LS,uni100',
-        #     'model': 'FISM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'RO_LS,uni100',
-        #     'model': 'LightGCN',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
     def test_tors_uni100(self):
         config_dict = {
-            'eval_setting': 'TO_RS,uni100',
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'uni100'},
             'model': 'BPR',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,uni100',
-        #     'model': 'NeuMF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,uni100',
-        #     'model': 'FISM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS,uni100',
-        #     'model': 'LightGCN',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
 
 class TestContextRecommender(unittest.TestCase):
 
     def test_tors(self):
         config_dict = {
-            'eval_setting': 'TO_RS',
+            'eval_args': {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'TO', 'mode': 'labeled'},
             'threshold': {'rating': 4},
             'model': 'FM',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS',
-        #     'model': 'DeepFM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS',
-        #     'model': 'DSSM',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_RS',
-        #     'model': 'AutoInt',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
 
 class TestSequentialRecommender(unittest.TestCase):
 
     def test_tols_uni100(self):
         config_dict = {
-            'eval_setting': 'TO_LS,uni100',
+            'eval_args': {'split': {'LS': 'valid_and_test'}, 'order': 'TO', 'mode': 'uni100'},
             'model': 'FPMC',
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'SASRec',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'GRU4RecF',
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
-        # config_dict = {
-        #     'eval_setting': 'TO_LS,uni100',
-        #     'model': 'Caser',
-        #     'MAX_ITEM_LIST_LENGTH': 10,
-        #     'reproducibility': False,
-        # }
-        # objective_function(config_dict=config_dict,
-        #                    config_file_list=config_file_list, saved=False)
 
 
 if __name__ == '__main__':
diff --git a/tests/metrics/test_loss_metrics.py b/tests/metrics/test_loss_metrics.py
index c5a609473..c6b99fadf 100644
--- a/tests/metrics/test_loss_metrics.py
+++ b/tests/metrics/test_loss_metrics.py
@@ -10,7 +10,14 @@
 
 sys.path.append(os.getcwd())
 import numpy as np
-from recbole.evaluator.metrics import metrics_dict
+from recbole.config import Config
+from recbole.evaluator.register import metrics_dict
+
+parameters_dict = {
+    'metric_decimal_place': 4,
+}
+
+config = Config('BPR', 'ml-1m', config_dict=parameters_dict)
 
 
 class TestCases(object):
@@ -22,9 +29,10 @@ class TestCases(object):
 
 
 def get_result(name, case=0):
-    func = metrics_dict[name]
-    return func(getattr(TestCases, f'trues_{case}'),
-                getattr(TestCases, f'preds_{case}'))
+    Metric = metrics_dict[name](config)
+    return Metric.metric_info(
+        getattr(TestCases, f'preds_{case}'),
+        getattr(TestCases, f'trues_{case}'))
 
 
 class TestLossMetrics(unittest.TestCase):
@@ -36,9 +44,9 @@ def test_auc(self):
     def test_rmse(self):
         name = 'rmse'
         self.assertEqual(get_result(name, case=0),
-                         np.sqrt((0.9**2 + 0.9**2 + 0.8**2 + 0.7**2) / 4))
+                         np.sqrt((0.9 ** 2 + 0.9 ** 2 + 0.8 ** 2 + 0.7 ** 2) / 4))
         self.assertEqual(get_result(name, case=1),
-                         np.sqrt((0.7**2 + 0.5**2 + 0.4**2 + 0.2**2) / 4))
+                         np.sqrt((0.7 ** 2 + 0.5 ** 2 + 0.4 ** 2 + 0.2 ** 2) / 4))
 
     def test_logloss(self):
         name = 'logloss'
diff --git a/tests/metrics/test_rank_metrics.py b/tests/metrics/test_rank_metrics.py
index c60a2c485..74851a64d 100644
--- a/tests/metrics/test_rank_metrics.py
+++ b/tests/metrics/test_rank_metrics.py
@@ -3,6 +3,10 @@
 # @Author  :   Zhichao Feng
 # @email   :   fzcbupt@gmail.com
 
+# UPDATE:
+# @Time   : 2021/7/1
+# @Author : Xingyu Pan
+# @Email  : xy_pan@foxmail.com
 
 import os
 import sys
@@ -10,17 +14,17 @@
 
 sys.path.append(os.getcwd())
 import numpy as np
-import torch
 from recbole.config import Config
-from recbole.data.interaction import Interaction
-from recbole.evaluator.metrics import metrics_dict
-from recbole.evaluator.evaluators import RankEvaluator
+from recbole.evaluator import metrics_dict, Collector
 
 parameters_dict = {
     'model': 'BPR',
-    'eval_setting': 'RO_RS,uni100',
+    'eval_args': {'split':{'RS':[0.8,0.1,0.1]}, 'order': 'RO', 'mode': 'uni100'},
+    'metric_decimal_place': 4,
 }
 
+config = Config('BPR', 'ml-1m', config_dict=parameters_dict)
+
 
 class MetricsTestCases(object):
     user_len_list0 = np.array([2, 3, 5])
@@ -32,25 +36,12 @@ class MetricsTestCases(object):
     pos_rank_sum1 = np.array([3, 0, 6])
 
 
-class CollectTestCases(object):
-    interaction0 = Interaction({}, [0, 2, 3, 4], [2, 3, 4, 5])
-    scores_tensor0 = torch.Tensor([0.1, 0.2,
-                                   0.1, 0.1, 0.2,
-                                   0.2, 0.2, 0.2, 0.2,
-                                   0.3, 0.2, 0.1, 0.4, 0.3])
-
-
 def get_metric_result(name, case=0):
-    func = metrics_dict[name]
-    return func(getattr(MetricsTestCases, f'user_len_list{case}'),
-                getattr(MetricsTestCases, f'pos_len_list{case}'),
-                getattr(MetricsTestCases, f'pos_rank_sum{case}'))
-
-
-def get_collect_result(evaluator, case=0):
-    func = evaluator.collect
-    return func(getattr(CollectTestCases, f'interaction{case}'),
-                getattr(CollectTestCases, f'scores_tensor{case}'))
+    Metric = metrics_dict[name](config)
+    return Metric.metric_info(
+                getattr(MetricsTestCases, f'pos_rank_sum{case}'),
+                getattr(MetricsTestCases, f'user_len_list{case}'),
+                getattr(MetricsTestCases, f'pos_len_list{case}'))
 
 
 class TestRankMetrics(unittest.TestCase):
@@ -62,13 +53,6 @@ def test_gauc(self):
                          / (1 + 2 + 3))
         self.assertEqual(get_metric_result(name, case=1), (3 - 0 - 3 / 1) / (3 - 1))
 
-    def test_collect(self):
-        config = Config('BPR', 'ml-100k', config_dict=parameters_dict)
-        metrics = ['GAUC']
-        rank_evaluator = RankEvaluator(config, metrics)
-        self.assertEqual(get_collect_result(rank_evaluator, case=0).squeeze().cpu().numpy().tolist(),
-                         np.array([0, (2 + 3) / 2 * 2, (1 + 2 + 3 + 4) / 4 * 3, 1 + (2 + 3) / 2 + 4 + 5]).tolist())
-
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/metrics/test_topk_metrics.py b/tests/metrics/test_topk_metrics.py
index 03880c613..b58fb628c 100644
--- a/tests/metrics/test_topk_metrics.py
+++ b/tests/metrics/test_topk_metrics.py
@@ -3,6 +3,10 @@
 # @Author  :   Kaiyuan Li
 # @email   :   tsotfsk@outlook.com
 
+# UPDATE
+# @Time    :    2021/7/2, 2021/7/5
+# @Author  :    Zihan Lin, Zhichao Feng
+# @email   :    zhlin@ruc.edu.cn, fzcbupt@gmail.com
 
 import os
 import sys
@@ -10,8 +14,15 @@
 
 sys.path.append(os.getcwd())
 import numpy as np
-from recbole.evaluator.metrics import metrics_dict
+from recbole.config import Config
+from recbole.evaluator.register import metrics_dict
 
+parameters_dict = {
+    'topk': [10],
+    'metric_decimal_place': 4,
+}
+
+config = Config('BPR', 'ml-1m', config_dict=parameters_dict)
 pos_idx = np.array([
     [0, 0, 0],
     [1, 1, 1],
@@ -20,23 +31,37 @@
 ])
 pos_len = np.array([1, 3, 4, 2])
 
+item_matrix = np.array([
+    [5, 7, 3],
+    [4, 5, 2],
+    [2, 3, 5],
+    [1, 4, 6],
+    [5, 3, 7]
+])
+
+num_items = 8
 
-def get_result(name):
-    func = metrics_dict[name]
-    return func(pos_idx, pos_len)
+item_count = {1: 0,
+              2: 1,
+              3: 2,
+              4: 3,
+              5: 4,
+              6: 5}
 
 
 class TestTopKMetrics(unittest.TestCase):
     def test_hit(self):
         name = 'hit'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx).tolist(),
             np.array([[0, 0, 0], [1, 1, 1], [1, 1, 1], [0, 0, 1]]).tolist())
 
     def test_ndcg(self):
         name = 'ndcg'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx, pos_len).tolist(),
             np.array([[0, 0, 0], [1, 1, 1],
                       [
                           1,
@@ -51,33 +76,76 @@ def test_ndcg(self):
 
     def test_mrr(self):
         name = 'mrr'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx).tolist(),
             np.array([[0, 0, 0], [1, 1, 1], [1, 1, 1], [0, 0,
                                                         1 / 3]]).tolist())
 
     def test_map(self):
         name = 'map'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx, pos_len).tolist(),
             np.array([[0, 0, 0], [1, 1, 1],
                       [1, (1 / 2), (1 / 3) * ((1 / 1) + (2 / 3))],
                       [0, 0, (1 / 3) * (1 / 2)]]).tolist())
 
     def test_recall(self):
         name = 'recall'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx, pos_len).tolist(),
             np.array([[0, 0, 0], [1 / 3, 2 / 3, 3 / 3], [1 / 4, 1 / 4, 2 / 4],
                       [0, 0, 1 / 2]]).tolist())
 
     def test_precision(self):
         name = 'precision'
+        Metric = metrics_dict[name](config)
         self.assertEqual(
-            get_result(name).tolist(),
+            Metric.metric_info(pos_idx).tolist(),
             np.array([[0, 0, 0], [1 / 1, 2 / 2, 3 / 3], [1 / 1, 1 / 2, 2 / 3],
                       [0, 0, 1 / 3]]).tolist())
 
+    def test_itemcoverage(self):
+        name = 'itemcoverage'
+        Metric = metrics_dict[name](config)
+        self.assertEqual(
+            Metric.get_coverage(item_matrix, num_items),
+            7 / 8)
+
+    def test_averagepopularity(self):
+        name = 'averagepopularity'
+        Metric = metrics_dict[name](config)
+        self.assertEqual(
+            Metric.metric_info(Metric.get_pop(item_matrix, item_count)).tolist(),
+            np.array([[4/1, 4/2, 6/3], [3/1, 7/2, 8/3], [1/1, 3/2, 7/3], [0/1, 3/2, 8/3],
+                      [4/1, 6/2, 6/3]]).tolist())
+
+    def test_giniindex(self):
+        name = 'giniindex'
+        Metric = metrics_dict[name](config)
+        self.assertEqual(
+            Metric.get_gini(item_matrix, num_items),
+            ((-7) * 0 + (-5) * 1 + (-3) * 1 + (-1) * 2 + 1 * 2 + 3 * 2 + 5 * 3 + 7 * 4)
+            / (8 * (3 * 5)))
+
+    def test_shannonentropy(self):
+        name = 'shannonentropy'
+        Metric = metrics_dict[name](config)
+        self.assertEqual(
+            Metric.get_entropy(item_matrix),
+            -np.mean([1/15*np.log(1/15), 2/15*np.log(2/15), 3/15*np.log(3/15), 2/15*np.log(2/15),
+                     4/15*np.log(4/15), 1/15*np.log(1/15), 2/15*np.log(2/15)]))
+
+    def test_tailpercentage(self):
+        name = 'tailpercentage'
+        Metric = metrics_dict[name](config)
+        self.assertEqual(
+            Metric.metric_info(Metric.get_tail(item_matrix, item_count)).tolist(),
+            np.array([[0 / 1, 0 / 2, 0 / 3], [0 / 1, 0 / 2, 0 / 3], [0 / 1, 0 / 2, 0 / 3], [1 / 1, 1 / 2, 1 / 3],
+                      [0 / 1, 0 / 2, 0 / 3]]).tolist())
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/model/test_model.yaml b/tests/model/test_model.yaml
index 4604e8a65..6860c88fe 100644
--- a/tests/model/test_model.yaml
+++ b/tests/model/test_model.yaml
@@ -38,18 +38,11 @@ load_col:
 
 unload_col: ~
 
-# Filtering
-max_user_inter_num: ~
-min_user_inter_num: ~
-max_item_inter_num: ~
-min_item_inter_num: ~
-lowest_val: ~
-highest_val: ~
-equal_val: ~
-not_equal_val: ~
-
 # Preprocessing
-fields_in_same_space: ~
+alias_of_user_id: ~
+alias_of_item_id: ~
+alias_of_entity_id: ~
+alias_of_relation_id: ~
 preload_weight: ~
 normalize_field: ~
 normalize_all: True
diff --git a/tests/model/test_model_auto.py b/tests/model/test_model_auto.py
index 3c2a5c610..17360cd6f 100644
--- a/tests/model/test_model_auto.py
+++ b/tests/model/test_model_auto.py
@@ -149,38 +149,38 @@ def test_ease(self):
     def test_MultiDAE(self):
         config_dict = {
             'model': 'MultiDAE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_MultiVAE(self):
         config_dict = {
             'model': 'MultiVAE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_enmf(self):
         config_dict = {
             'model': 'ENMF',
-            'training_neg_sample_num': 0,
+            'neg_sampling': None,
         }
         quick_test(config_dict)
- 
+
     def test_MacridVAE(self):
         config_dict = {
             'model': 'MacridVAE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_CDAE(self):
         config_dict = {
             'model': 'CDAE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
-        
+
     def test_NNCF(self):
         config_dict = {
             'model': 'NNCF',
@@ -190,7 +190,7 @@ def test_NNCF(self):
     def test_RecVAE(self):
         config_dict = {
             'model': 'RecVAE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -378,7 +378,7 @@ def test_fpmc(self):
     def test_gru4rec(self):
         config_dict = {
             'model': 'GRU4Rec',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -392,7 +392,7 @@ def test_gru4rec_with_BPR_loss(self):
     def test_narm(self):
         config_dict = {
             'model': 'NARM',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -406,7 +406,7 @@ def test_narm_with_BPR_loss(self):
     def test_stamp(self):
         config_dict = {
             'model': 'STAMP',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -422,7 +422,7 @@ def test_caser(self):
             'model': 'Caser',
             'MAX_ITEM_LIST_LENGTH': 10,
             'reproducibility': False,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -439,7 +439,7 @@ def test_nextitnet(self):
         config_dict = {
             'model': 'NextItNet',
             'reproducibility': False,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -460,7 +460,7 @@ def test_transrec(self):
     def test_sasrec(self):
         config_dict = {
             'model': 'SASRec',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -484,7 +484,7 @@ def test_srgnn(self):
         config_dict = {
             'model': 'SRGNN',
             'MAX_ITEM_LIST_LENGTH': 3,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -500,7 +500,7 @@ def test_gcsan(self):
         config_dict = {
             'model': 'GCSAN',
             'MAX_ITEM_LIST_LENGTH': 3,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -516,7 +516,7 @@ def test_gcsan_with_BPR_loss_and_tanh(self):
     def test_gru4recf(self):
         config_dict = {
             'model': 'GRU4RecF',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -524,7 +524,7 @@ def test_gru4recf_with_max_pooling(self):
         config_dict = {
             'model': 'GRU4RecF',
             'pooling_mode': 'max',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -532,14 +532,14 @@ def test_gru4recf_with_sum_pooling(self):
         config_dict = {
             'model': 'GRU4RecF',
             'pooling_mode': 'sum',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_sasrecf(self):
         config_dict = {
             'model': 'SASRecF',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -547,7 +547,7 @@ def test_sasrecf_with_max_pooling(self):
         config_dict = {
             'model': 'SASRecF',
             'pooling_mode': 'max',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -555,14 +555,14 @@ def test_sasrecf_with_sum_pooling(self):
         config_dict = {
             'model': 'SASRecF',
             'pooling_mode': 'sum',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_hrm(self):
         config_dict = {
             'model': 'HRM',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -576,7 +576,7 @@ def test_hrm_with_BPR_loss(self):
     def test_npe(self):
         config_dict = {
             'model': 'NPE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -590,7 +590,7 @@ def test_npe_with_BPR_loss(self):
     def test_shan(self):
         config_dict = {
             'model': 'SHAN',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -611,14 +611,14 @@ def test_hgn_with_CE_loss(self):
         config_dict = {
             'model': 'HGN',
             'loss_type': 'CE',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_fossil(self):
         config_dict = {
             'model': 'FOSSIL',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -631,7 +631,7 @@ def test_repeat_net(self):
     def test_fdsa(self):
         config_dict = {
             'model': 'FDSA',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -639,7 +639,7 @@ def test_fdsa_with_max_pooling(self):
         config_dict = {
             'model': 'FDSA',
             'pooling_mode': 'max',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -647,14 +647,14 @@ def test_fdsa_with_sum_pooling(self):
         config_dict = {
             'model': 'FDSA',
             'pooling_mode': 'sum',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
     def test_bert4rec(self):
         config_dict = {
             'model': 'BERT4Rec',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         objective_function(config_dict=config_dict,
                            config_file_list=config_file_list, saved=False)
@@ -808,6 +808,5 @@ def test_kgnnls_with_concat(self):
         quick_test(config_dict)
 
 
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/model/test_model_manual.py b/tests/model/test_model_manual.py
index 581ff060e..607983a1a 100644
--- a/tests/model/test_model_manual.py
+++ b/tests/model/test_model_manual.py
@@ -30,7 +30,7 @@ def test_s3rec(self):
             'model': 'S3Rec',
             'train_stage': 'pretrain',
             'save_step': 1,
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)
 
@@ -38,7 +38,7 @@ def test_s3rec(self):
             'model': 'S3Rec',
             'train_stage': 'finetune',
             'pre_model_path': './saved/S3Rec-test-1.pth',
-            'training_neg_sample_num': 0
+            'neg_sampling': None
         }
         quick_test(config_dict)