From 84a7df628216909bde8f7d77c4f63babb1090de1 Mon Sep 17 00:00:00 2001 From: Gordon119 Date: Tue, 16 Jul 2024 22:29:04 +0800 Subject: [PATCH 1/2] update document --- docs/data_preparation.rst | 10 + docs/examples/plot_dataset_tutorial.py | 10 +- docs/examples/plot_linear_feature_gen.py | 33 +++ .../plot_linear_gridsearch_tutorial.py | 83 ++---- docs/examples/plot_linear_tree_tutorial.py | 24 +- docs/examples/plot_multi_label.py | 236 ++++++++++++++++++ docs/index.rst | 3 +- docs/papers.rst | 4 + docs/{linear.rst => search_retrain.rst} | 6 +- docs/tree.rst | 9 + docs/tutorial.rst | 7 +- ...arameter_Selection_for_Neural_Networks.rst | 20 +- docs/tutorials/images/multilabel.png | Bin 0 -> 115634 bytes 13 files changed, 359 insertions(+), 86 deletions(-) create mode 100644 docs/data_preparation.rst create mode 100644 docs/examples/plot_linear_feature_gen.py create mode 100644 docs/examples/plot_multi_label.py create mode 100644 docs/papers.rst rename docs/{linear.rst => search_retrain.rst} (51%) create mode 100644 docs/tree.rst create mode 100644 docs/tutorials/images/multilabel.png diff --git a/docs/data_preparation.rst b/docs/data_preparation.rst new file mode 100644 index 000000000..2b3c723aa --- /dev/null +++ b/docs/data_preparation.rst @@ -0,0 +1,10 @@ +Data Preparation +================ + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + + ../auto_examples/plot_dataset_tutorial + ../auto_examples/plot_linear_feature_gen diff --git a/docs/examples/plot_dataset_tutorial.py b/docs/examples/plot_dataset_tutorial.py index 8a7c2dfa6..b2700eb6b 100644 --- a/docs/examples/plot_dataset_tutorial.py +++ b/docs/examples/plot_dataset_tutorial.py @@ -1,8 +1,8 @@ """ -An Example of Using Data Stored in Different Forms +Using Data not in Default Forms =================================================== -Different data sets are stored in various structures and formats. +Different datasets are stored in various structures and formats. To apply LibMultiLabel with any of them, one must convert the data to a form accepted by the library first. In this tutorial, we demonstrate an example of converting a hugging face data set. Before we start, note that LibMultiLabel format consists of IDs (optional), labels, and raw texts. @@ -21,8 +21,8 @@ from datasets import load_dataset ###################################################################### -# We choose a multi-label set ``emoji`` from ``tweet_eval`` in this example. -# The data set can be loaded by the following code. +# We choose a multi-label dataset ``emoji`` from ``tweet_eval`` in this example. +# The dataset can be loaded by the following code. hf_datasets = dict() hf_datasets["train"] = load_dataset("tweet_eval", "emoji", split="train") @@ -60,7 +60,7 @@ datasets = preprocessor.fit_transform(datasets) ############################################################################### -# Also, if you want to use a NN model, +# In this case, if you want to use a deep learning model, # use ``load_datasets`` from ``libmultilabel.nn.data_utils`` and change the data to the dataframes we created. # Here is the modification of our `Bert model quickstart `_. diff --git a/docs/examples/plot_linear_feature_gen.py b/docs/examples/plot_linear_feature_gen.py new file mode 100644 index 000000000..0750e6216 --- /dev/null +++ b/docs/examples/plot_linear_feature_gen.py @@ -0,0 +1,33 @@ +""" +Tweaking Feature Generation for Linear Methods +============================================================= + +In both `API <../auto_examples/plot_linear_quickstart.html>`_ and `CLI <../cli/linear.html>`_ usage of linear methods, LibMultiLabel handles the feature generation step by default. +Unless necessary, you do not need to generate features in different ways as described in this tutorial. + +This tutorial demonstrates how to customize the way to generate features for linear methods through an API example. +Here we use the `rcv1 `_ dataset as an example. +""" + +from sklearn.preprocessing import MultiLabelBinarizer +from libmultilabel import linear + +datasets = linear.load_dataset("txt", "data/rcv1/train.txt", "data/rcv1/test.txt") +tfidf_params = { + "max_features": 20000, + "min_df": 3, + "ngram_range": (1, 3) +} +preprocessor = linear.Preprocessor(tfidf_params=tfidf_params) +preprocessor.fit(datasets) +datasets = preprocessor.transform(datasets) + +############################################ +# The argument ``tfidf_params`` of the ``Preprocessor`` can specify how to generate the TF-IDF features. +# In this example, we adjust the ``max_features``, ``min_df``, and ``ngram_range`` of the preprocessor. +# For explanation of these three and other options, refer to the `sklearn page `_. +# Users can also try other methods to generalize features, like word embedding. +# +# Finally, we use the generated numerical features to train and evaluate the model. +# The rest of the steps is the same in the quickstarts. +# Please refer to them for details. \ No newline at end of file diff --git a/docs/examples/plot_linear_gridsearch_tutorial.py b/docs/examples/plot_linear_gridsearch_tutorial.py index 75a2e7691..b7e38413b 100644 --- a/docs/examples/plot_linear_gridsearch_tutorial.py +++ b/docs/examples/plot_linear_gridsearch_tutorial.py @@ -1,12 +1,10 @@ """ -Feature Generation and Parameter Selection for Linear Methods +Hyperparameter Search for Linear Methods ============================================================= +This guide helps users to tune the hyperparameters of the feature generation step and the linear model. -This tutorial demonstrates feature generation and parameter selection for linear methods. - -Here we show an example of training a linear text classifier with the rcv1 dataset. -If you haven't downloaded it yet, see `Data Preparation <../cli/linear.html#step-1-data-preparation>`_. -Then you can read and preprocess the data as follows +Here we show an example of tuning a linear text classifier with the `rcv1 dataset `_. +Starting with loading and preprocessing of the data without using ``Preprocessor``: """ from sklearn.preprocessing import MultiLabelBinarizer @@ -17,33 +15,9 @@ y = binarizer.fit_transform(datasets["train"]["y"]).astype("d") ###################################################################### -# We format labels into a 0/1 sparse matrix with ``MultiLabelBinarizer``. -# -# Feature Generation -# ------------------ -# Before training a linear classifier, we must convert each text to a vector of numerical features. -# To use the default setting (TF-IDF features), check -# `Linear Model for MultiLabel Classification <../auto_examples/plot_linear_quickstart.html#linear-model-for-multi-label-classification>`_ -# for easily conducting training and testing. -# -# If you want to tweak the generation of TF-IDF features, consider - -from sklearn.feature_extraction.text import TfidfVectorizer - -vectorizer = TfidfVectorizer(max_features=20000, min_df=3) -x = vectorizer.fit_transform(datasets["train"]["x"]) -model = linear.train_1vsrest(y, x, "-s 2 -m 4") - -####################################################################### -# We use the generated numerical features ``x`` as the input of -# the linear method ``linear.train_1vsrest``. +# we format labels into a 0/1 sparse matrix with ``MultiLabelBinarizer``. # -# An Alternative Way for Using a Linear Method -# -------------------------------------------- -# Besides the default way shown in `Feature Generation <#feature-generation>`_, -# we can construct a sklearn estimator for training and prediction. -# This way is used namely for parameter selection described later, -# as the estimator makes LibMultiLabel methods in a sklearn Pipeline for a grid search. +# Next, we construct a ``Pipeline`` object that will be used for hyperparameter search later. from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.pipeline import Pipeline @@ -56,33 +30,30 @@ ) ###################################################################### -# For the estimator ``MultiLabelEstimator``, arguments ``options`` is a LIBLINEAR option +# The vectorizor ``TfidfVectorizer`` is used in ``Pipeline`` to generate TF-IDF features from raw texts. +# As for the estimator ``MultiLabelEstimator``, argument ``options`` is a LIBLINEAR option # (see *train Usage* in `liblinear `__ README), and -# ``linear_technique`` is one of linear techniques: ``1vsrest``, ``thresholding``, ``cost_sensitive``, +# ``linear_technique`` is one of the linear techniques, including ``1vsrest``, ``thresholding``, ``cost_sensitive``, # ``cost_sensitive_micro``, and ``binary_and_mulitclass``. -# In ``pipeline``, we specify settings used by the estimator. +# +# We can specify the aliases of the components used by the pipeline. # For example, ``tfidf`` is the alias of ``TfidfVectorizer`` and ``clf`` is the alias of the estimator. # -# We can then use the following code for training. -pipeline.fit(datasets["train"]["x"], y) - -###################################################################### -# Grid Search over Feature Generations and LIBLINEAR Options -# ----------------------------------------------------------- -# To search for the best setting, we can employ ``GridSearchCV``. +# To search for the best setting, we employ ``GridSearchCV``. # The usage is similar to sklearn's except that the parameter ``scoring`` is not available. Please specify # ``scoring_metric`` in ``linear.MultiLabelEstimator`` instead. -liblinear_options = ["-s 2 -c 0.5", "-s 2 -c 1", "-s 2 -c 2"] + +liblinear_options = ["-s 2 -c 0.5", "-s 2 -c 1", "-s 2 -c 2", "-s 1 -c 0.5", "-s 1 -c 1", "-s 1 -c 2"] parameters = {"clf__options": liblinear_options, "tfidf__max_features": [10000, 20000, 40000], "tfidf__min_df": [3, 5]} clf = linear.GridSearchCV(pipeline, parameters, cv=5, n_jobs=4, verbose=1) clf = clf.fit(datasets["train"]["x"], y) ###################################################################### -# Here we check the combinations of six feature generations and three regularization parameters +# Here we check the combinations of six feature generation options and six liblinear options # in the linear classifier. The key in ``parameters`` should follow the sklearn's coding rule # starting with the estimator's alias and two underscores (i.e., ``clf__``). # We specify ``n_jobs=4`` to run four tasks in parallel. -# After finishing gridsearch, we can get the best parameters by the following code: +# After finishing the grid search, we can get the best parameters by the following code: for param_name in sorted(parameters.keys()): print(f"{param_name}: {clf.best_params_[param_name]}") @@ -90,19 +61,19 @@ ###################################################################### # The best parameters are:: # -# clf__options: '-s 2 -c 0.5 -m 1' -# tfidf__max_features: 20000 -# tfidf__min_df: 3 +# clf__options: -s 2 -c 0.5 -m 1 +# tfidf__max_features: 10000 +# tfidf__min_df: 5 # -# For testing, we also need to read in data first and format test labels into a 0/1 sparse matrix. - -y = binarizer.transform(datasets["test"]["y"]).astype("d").toarray() - -###################################################################### -# Applying the ``predict`` function of ``GridSearchCV`` object to use the -# estimator trained under the best hyper-parameters for prediction. +# Note that in the above code, the ``refit`` argument of ``GridSearchCV`` is enabled by default, meaning that the best configuration will be trained on the whole dataset after hyperparameter search. +# We refer to this as the retrain strategy. +# After fitting ``GridSearchCV``, the retrained model is stored in ``clf``. +# +# We can apply the ``predict`` function of ``GridSearchCV`` object to use the estimator trained under the best hyperparameters for prediction. # Then use ``linear.compute_metrics`` to calculate the test performance. +# For testing, we also need to read in data first and format test labels into a 0/1 sparse matrix. +y = binarizer.transform(datasets["test"]["y"]).astype("d").toarray() preds = clf.predict(datasets["test"]["x"]) metrics = linear.compute_metrics( preds, @@ -114,4 +85,4 @@ ###################################################################### # The result of the best parameters will look similar to:: # -# {'Macro-F1': 0.4965720851051106, 'Micro-F1': 0.8004678830627301, 'P@1': 0.9587412721675744, 'P@3': 0.8021469454453142, 'P@5': 0.5605401496291271} +# {'Macro-F1': 0.5296621774388927, 'Micro-F1': 0.8021279986938116, 'P@1': 0.9561621216872636, 'P@3': 0.7983185389507189, 'P@5': 0.5570921518306848} diff --git a/docs/examples/plot_linear_tree_tutorial.py b/docs/examples/plot_linear_tree_tutorial.py index ffa779c44..d9cb41f1c 100644 --- a/docs/examples/plot_linear_tree_tutorial.py +++ b/docs/examples/plot_linear_tree_tutorial.py @@ -1,14 +1,25 @@ """ -Handling Data with Many Labels -============================== +Handling Data with Many Labels using Linear Methods. +==================================================== For the case that the amount of labels is very large, the training time of the standard ``train_1vsrest`` method may be unpleasantly long. The ``train_tree`` method in LibMultiLabel can vastly improve the training time on such data sets. -To illustrate this speedup, we will use the `EUR-Lex dataset `_, -which contains 3,956 labels. -In this example, the data is downloaded under the directory ``data/eur-lex``. +To illustrate this speedup, we will use the `EUR-Lex dataset `_, which contains 3,956 labels. +The data in the following example is downloaded under the directory ``data/eur-lex`` + +Users can use the following command to easily apply the ``train_tree`` method. + +.. code-block:: bash + + $ python3 main.py --training_file data/eur-lex/train.txt + --test_file data/eur-lex/test.txt + --linear + --linear_technique tree + +Besides CLI usage, users can also use API to apply ``train_tree`` method. +Below is an example. """ import math @@ -88,6 +99,3 @@ def metrics_in_batches(model): print("Score of 1vsrest:", metrics_in_batches(ovr_model)) print("Score of tree:", metrics_in_batches(tree_model)) -###################################################################### -# -# .. bibliography:: diff --git a/docs/examples/plot_multi_label.py b/docs/examples/plot_multi_label.py new file mode 100644 index 000000000..e8aef667a --- /dev/null +++ b/docs/examples/plot_multi_label.py @@ -0,0 +1,236 @@ +""" +A Guide for Multi-Label Classification +====================================== + +This tutorial serves as a high-level guide for multi-label classification. +Users can follow the steps in this guide to select suitable training methods and evaluation metrics for their applications, gaining a better understanding of multi-label classification. +Below is a flow chart summarizing this tutorial. +We will explain each stage in the graph. + +.. image:: ../tutorials/images/multilabel.png + :width: 100% + :align: center + +Depending on the number of labels in the application, multi-label classification requires different methods to achieve good efficiency and performance. To simulate different numbers of labels for users' possible applications, this guide utilizes two datasets: one with a smaller label space, `rcv1 `_ (101 labels), and the other with a larger label space, `EUR-Lex-57K `_ (4,271 labels). + +Details of the training methods and the evaluation metrics mentioned in this guide can be found in the `implementation document `_. + +Step 1. Linear Methods or Neural Networks +----------------------------------------- +LibMultiLabel offers both deep learning and linear methods. +Linear methods usually serve as strong baselines with better efficiency in training the models, while deep learning methods achieve state-of-the-art results with less efficiency. +For more details, refer to the paper :cite:p:`YCL22a`. + +To showcase the difference, we provide an example using the rcv1 dataset to compare the two methods. +The following code uses the one-vs-rest linear method on rcv1. +This method, also known as binary relevance, trains a binary classification model for each label on data with and without that label. +Detailed explanation of the following code can be found in the `linear quickstart <../auto_examples/plot_linear_quickstart.html>`_. +""" +import libmultilabel.linear as linear +import time + +datasets_rcv1 = linear.load_dataset("txt", "data/rcv1/train.txt", "data/rcv1/test.txt") +preprocessor_rcv1 = linear.Preprocessor() +preprocessor_rcv1.fit(datasets_rcv1) +datasets_rcv1 = preprocessor_rcv1.transform(datasets_rcv1) + +start = time.time() +model = linear.train_1vsrest(datasets_rcv1["train"]["y"], datasets_rcv1["train"]["x"], "") +end = time.time() + +preds = linear.predict_values(model, datasets_rcv1["test"]["x"]) +target = datasets_rcv1["test"]["y"].toarray() +metrics = linear.compute_metrics(preds, target, monitor_metrics=["Macro-F1"]) +print({"Macro-F1":metrics["Macro-F1"], "Training_time":end - start}) + +#################################################### +# As the label space of rcv1 is small, we consider an accuracy-based metric Macro-F1; see Step 3 for more details. +# +# The performance and training time are as follows:: +# +# {'Macro-F1': 0.5171960144875225, 'Training_time': 4.327306747436523} +# +# For deep learning, we train a BERT model for this dataset. +# We exclude the code here for simplicity. +# Please refer to the `BERT quickstart <../auto_examples/plot_bert_quickstart.html>`_ for details. +# Following the quickstart, the resulting performance and training time are as follows:: +# +# {'Macro-F1': 0.564618763137536, 'Training_time': 5412.955321788788} +# +# The table below illustrates the performance and efficiency trade-off between these methods. +# Users can use this information to decide which method to employ depending on their specific application needs. +# +# .. list-table:: +# :widths: 50 50 50 +# :header-rows: 1 +# +# * - Methods +# - Macro-F1 +# - Training time (sec) +# +# * - Linear method (one-vs-rest) +# - 0.5171960144875225 +# - 4.327306747436523 +# +# * - Deep learning method (BERT) +# - 0.564618763137536 +# - 5412.955321788788 +# +# Step 2. Training: +# ----------------- +# If number of labels is small +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Due to the nature of multi-label problems, there are often many more instances without a particular label than with it. +# As we mentioned, the one-vs-rest method trains a binary classifier for each label. +# When using this method, each binary problem becomes imbalanced, and the model will rarely predict some labels. +# This imbalance leads to unsatisfactory results when accuracy-based metrics like Macro-F1 are used (refer to Step 3 for the reason why Macro-F1 is often used when the number of labels is small). +# Some techniques can solve this problem, including thresholding and cost-sensitive methods. +# Because this is a high-level guide, we leave the details of data imbalance and the solutions in the `implementation document `_. +# Below is an example of thresholding and cost-sensitive methods on rcv1 dataset. + +model_threshold = linear.train_thresholding(datasets_rcv1["train"]["y"], datasets_rcv1["train"]["x"], "") + +model_cost_sensitive = linear.train_cost_sensitive(datasets_rcv1["train"]["y"], datasets_rcv1["train"]["x"], "") + +preds_threshold = linear.predict_values(model_threshold, datasets_rcv1["test"]["x"]) +preds_cost_sensitive = linear.predict_values(model_cost_sensitive, datasets_rcv1["test"]["x"]) + +metrics_threshold = linear.compute_metrics(preds_threshold, target, monitor_metrics=["Macro-F1"]) +metrics_cost_sensitive = linear.compute_metrics(preds_cost_sensitive, target, monitor_metrics=["Macro-F1"]) + +print({"Macro-F1":metrics_threshold["Macro-F1"]}) +print({"Macro-F1":metrics_cost_sensitive["Macro-F1"]}) + +############################################ +# The performance of thresholding:: +# +# {'Macro-F1': 0.5643407144065415} +# +# The performance of cost-sensitive:: +# +# {'Macro-F1': 0.5704056980791481} +# +# Compare with the naive one-vs-rest method in Step 1: +# +# .. list-table:: +# :widths: 50 50 +# :header-rows: 1 +# +# * - Methods +# - Macro-F1 +# +# * - One-vs-rest +# - 0.5171960144875225 +# +# * - Thresholding +# - 0.5643407144065415 +# +# * - Cost-sensitive +# - 0.5704056980791481 +# +# From the comparison, one can see that these techniques improves the naive method. +# +# As for the situation for deep learning, we are still investigating the problem and working on the solution. +# +# If number of labels is large +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# When the label space is large, the imbalance problem is less of a concern because we only consider top predictions (refer to Step 3 for explanation). +# The challenge, however, shifts to efficiency in training the model. +# Training models directly in this case may result in high runtime and space consumption. +# A solution to reduce these costs is to utilize tree-based models. +# Here we provide an example comparing a linear one-vs-rest model and a tree model on the EUR-Lex-57k dataset, which has a larger label space. +# We start by training a tree model following another detailed `tutorial <../auto_examples/plot_linear_tree_tutorial.html>`__. + +datasets_eurlex = linear.load_dataset("txt", "data/eurlex57k/train.txt", "data/eurlex57k/test.txt") +preprocessor_eurlex = linear.Preprocessor() +datasets_eurlex = preprocessor_eurlex.fit_transform(datasets_eurlex) + +start = time.time() +tree_model = linear.train_tree(datasets_eurlex["train"]["y"], datasets_eurlex["train"]["x"]) +end = time.time() + +tree_preds = linear.predict_values(tree_model, datasets_eurlex["test"]["x"]) +target = datasets_eurlex["test"]["y"].toarray() +tree_score = linear.compute_metrics(tree_preds, target, ["P@5"]) +print({"P@5":tree_score["P@5"], "Training_time":end - start}) + +######################################################################## +# Different from Step 1, the label space of EUR-Lex-57k is large, so we use a ranking-based metric precision@5 here. +# Refer to Step 3 for more details. +# +# In this case, the performance and training time of the tree model is:: +# +# {'P@5': 0.679, 'Training_time': 262.8317949771881} +# +# If we follow the training procedure from Step 1 and train a one-vs-rest model, the performance and training time on this larger dataset will be as follows:: +# +# {"P@5": 0.6866666666666666, "Training_time": 1403.1347591876984} +# +# It is clear that the tree model significantly improves efficiency. +# As for deep learning, a similar improvement in efficiency can be observed. +# Details for the tree-based deep learning model can be found in this `tutorial <../tutorials/AttentionXML.html>`__. +# +# Step 3. Evaluation: Pick Suitable Metrics +# ----------------------------------------- +# As for the evaluation of the model, the choice of the evaluation metric also depends on the application and the number of labels. +# +# Consider problems with a small label space. +# In such cases, the goal is often to accurately predict every label relevant to an instance, making accuracy-based metrics appropriate choices. +# Accuracy-based metrics include Macro and Micro-F1. +# +# In problems where there are thousands or even millions of labels, it is extremely difficult to exactly identify the label set of an instance from the vast label space. +# Furthermore, the goal of such applications is often to ensure that the top predictions are relevant to the user. +# In these cases, instead of metrics that consider the whole label set, like Macro-F1 and Micro-F1, ranking-based metrics such as precision at K (P@K) and normalized discounted cumulative gain at K (NDCG@K) will be more suitable. +# +# For linear models, the evaluation metrics can be easily specified with the argument ``monitor_metrics`` in the ``compute_metrics`` function. +# +# In Step 2, we mentioned that a ranking-based metric (precision@5) is used because the label space of the dataset (EUR-Lex-57k) is large. +# If we instead use Macro-F1 in Step 2, by the following code: + +tree_score = linear.compute_metrics(tree_preds, target, ["Macro-F1"]) +print({"Macro-F1":tree_score["Macro-F1"]}) + +################################################# +# the result will look like:: +# +# {'Macro-F1': 0.06455166396222473} +# +# The Macro-F1 score for this dataset with more labels is close to zero, making this result not very informative. +# +# For deep learning usage, please refer to the two quickstarts (`BERT quickstart <../auto_examples/plot_bert_quickstart.html>`_, `CNN quickstart <../auto_examples/plot_KimCNN_quickstart.html>`_) for more details. +# +# Step 4. Hyperparameter Search +# ----------------------------- +# Models with suboptimal hyperparameters may lead to poor performance :cite:p:`JJL21a`. +# Users can incorporate hyperparameter tuning into the training process. +# Because this functionality is more complex and cannot be adequately demonstrated within a code snippet, please refer to these two tutorials for more details about hyperparameter tuning (`linear <../auto_examples/plot_gridsearch_tutorial.html>`_ +# and `deep learning <../tutorials/Parameter_Selection_for_Neural_Networks.html>`_). +# Another thing to consider is that hyperparameter search can be time-consuming, especially in the case of deep learning. +# Users need to conduct this step with consideration of the available resources and time. +# +# Step 5. Retraining +# ------------------ +# The common practice in machine learning for hyperparameter search involves splitting the available data into training and validation sets. +# To use as much information as possible, for linear methods, after determining the best hyperparameters, all available data are generally trained under these optimal hyperparameters to obtain the final model. +# We refer to this as the "retrain" strategy. +# +# For linear methods, the `tutorial <../auto_examples/plot_gridsearch_tutorial.html>`__ for hyperparameter search already handles retraining by default. +# As for deep learning, since this additional step is not common in practice, we include it in the last section of this `tutorial <../tutorials/Parameter_Selection_for_Neural_Networks.html>`__. +# +# Step 6. Prediction +# ------------------ +# In Step 1 and 2, we simply use the decision values from the model to compute the metrics. +# To get predicted labels of each test instance, users can use the following code (using the linear one-vs-rest model in Step 1): + +pred_labels, pred_scores = linear.get_positive_labels(preds, preprocessor_rcv1.label_mapping) +prediction = [] +for label, score in zip(pred_labels, pred_scores): + prediction.append([f"{i}:{s:.4}" for i, s in zip(label, score)]) +print(prediction[0]) + +############################################################# +# The prediction for the first test instance will look like:: +# +# ['GCAT:1.345', 'GSPO:1.519'] +# +# As for deep learning, please refer to the two quickstarts (`BERT quickstart <../auto_examples/plot_bert_quickstart.html>`_, `CNN quickstart <../auto_examples/plot_KimCNN_quickstart.html>`_) for more details. \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 7fb4aec9a..4d8b612aa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,8 @@ For practical use, please see the `Tutorials `_. For Implementati cli_index library_index tutorial - LibMultiLabel Implementation Doc + Implementation Document + papers .. diff --git a/docs/papers.rst b/docs/papers.rst new file mode 100644 index 000000000..931ba6ef4 --- /dev/null +++ b/docs/papers.rst @@ -0,0 +1,4 @@ +Cited Papers +============ + + .. bibliography:: diff --git a/docs/linear.rst b/docs/search_retrain.rst similarity index 51% rename from docs/linear.rst rename to docs/search_retrain.rst index 743f94ef0..26acfccb6 100644 --- a/docs/linear.rst +++ b/docs/search_retrain.rst @@ -1,5 +1,5 @@ -Linear -====== +Hyperparameter Search +===================== .. toctree:: :maxdepth: 1 @@ -7,4 +7,4 @@ Linear ../auto_examples/plot_linear_gridsearch_tutorial - ../auto_examples/plot_linear_tree_tutorial + tutorials/Parameter_Selection_for_Neural_Networks diff --git a/docs/tree.rst b/docs/tree.rst new file mode 100644 index 000000000..54e354f44 --- /dev/null +++ b/docs/tree.rst @@ -0,0 +1,9 @@ +If The Number of Labels is Large +================================ + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + ../auto_examples/plot_linear_tree_tutorial + tutorials/AttentionXML diff --git a/docs/tutorial.rst b/docs/tutorial.rst index e0bf3f416..0391b70ed 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -5,6 +5,7 @@ Tutorials :maxdepth: 2 :titlesonly: - ../auto_examples/plot_dataset_tutorial.rst - neural_networks - linear + ../auto_examples/plot_multi_label + data_preparation + tree + search_retrain diff --git a/docs/tutorials/Parameter_Selection_for_Neural_Networks.rst b/docs/tutorials/Parameter_Selection_for_Neural_Networks.rst index d19832f34..e76351e9e 100644 --- a/docs/tutorials/Parameter_Selection_for_Neural_Networks.rst +++ b/docs/tutorials/Parameter_Selection_for_Neural_Networks.rst @@ -1,7 +1,7 @@ -Parameter Selection for Neural Networks +Hyperparameter Search for Neural Networks ========================================== -The performance of a model depends on the choice of hyper-parameters. +The performance of a model depends on the choice of hyperparameters. The following example demonstrates how the BiGRU model performs differently on the EUR-Lex data set with two parameter sets. Datasets can be downloaded from the `LIBSVM datasets `_. @@ -79,8 +79,8 @@ The process finds the best parameter set of ``learning_rate=0.0003``, ``embed_dr After the search process, the program applies the best parameters to obtain the final model by adding the validation set for training. The average P@1 score is 81.99% on the test set, better -than the result without a hyper-parameter search. Note that after obtaining the best -hyper-parameters, we combine training and validation sets to train a final model for testing. +than the result without a hyperparameter search. Note that after obtaining the best +hyperparameters, we combine training and validation sets to train a final model for testing. For more details about 're-training', please refer to the `Re-train or not`_ section. Early Stopping of the Parameter Search @@ -145,7 +145,7 @@ Re-train or not In the `Grid Search over Parameters`_ section, we split the available data into training and validation sets for hyperparameter search. For methods like SVM, they usually train the -final model with the best hyper-parameters by combining the training and validation sets. +final model with the best hyperparameters by combining the training and validation sets. This approach maximizes the utilization of information for model learning, and we refer to it as the "re-train" strategy. @@ -153,13 +153,13 @@ it as the "re-train" strategy. .. set means that the optimization process, which previously relied on the validation set for .. termination, no longer works. While there's no definitively proven best termination criterion .. , a typical approach is to determine the optimal epoch during -.. hyper-parameter search based on the number of training steps that led to the best +.. hyperparameter search based on the number of training steps that led to the best .. validation performance. This optimal epoch serves as a stopping criterion .. when training the model with all available data. This strategy has been shown .. to provide stable improvements while mitigating the risk of overfitting. Since re-training is usually beneficial, we have incorporated the strategy into ``search_params.py``. -When hyper-parameter search is done, the re-training process will be automatically +When hyperparameter search is done, the re-training process will be automatically executed by default, like the case in section `Grid Search over Parameters`_. Though not recommended, you can use the argument ``--no_retrain`` to disable the @@ -185,20 +185,20 @@ the advantages of the re-training. - P@1 - P@5 - * - wo/ re-training after hyper-parameter search + * - wo/ re-training after hyperparameter search - 22.95 - 56.37 - 80.08 - 56.24 - * - w/ re-training after hyper-parameter search + * - w/ re-training after hyperparameter search - 24.43 - 57.99 - 81.99 - 57.57 In a different scenario, if you want to skip the parameter search but still wish -to re-train the model with your chosen hyper-parameters, we will provide an example +to re-train the model with your chosen hyperparameters, we will provide an example of how to do this. Let's train a BiGRU model using the configuration file used in the `Direct Trying Some Parameters`_ diff --git a/docs/tutorials/images/multilabel.png b/docs/tutorials/images/multilabel.png new file mode 100644 index 0000000000000000000000000000000000000000..e5f98c11338dbe35f5b96b9de31746dce00f19af GIT binary patch literal 115634 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 Date: Fri, 19 Jul 2024 21:56:36 +0800 Subject: [PATCH 2/2] update --- docs/examples/plot_dataset_tutorial.py | 2 +- .../plot_linear_gridsearch_tutorial.py | 2 +- docs/examples/plot_linear_tree_tutorial.py | 2 +- docs/examples/plot_multi_label.py | 23 +++++++++---------- docs/neural_networks.rst | 9 -------- docs/tutorial.rst | 2 +- docs/tutorials/AttentionXML.rst | 6 ++--- 7 files changed, 18 insertions(+), 28 deletions(-) delete mode 100644 docs/neural_networks.rst diff --git a/docs/examples/plot_dataset_tutorial.py b/docs/examples/plot_dataset_tutorial.py index b2700eb6b..cf986e575 100644 --- a/docs/examples/plot_dataset_tutorial.py +++ b/docs/examples/plot_dataset_tutorial.py @@ -62,7 +62,7 @@ ############################################################################### # In this case, if you want to use a deep learning model, # use ``load_datasets`` from ``libmultilabel.nn.data_utils`` and change the data to the dataframes we created. -# Here is the modification of our `Bert model quickstart `_. +# Here is the modification of our `Bert model quickstart <../auto_examples/plot_bert_quickstart.html>`_. from libmultilabel.nn.data_utils import load_datasets diff --git a/docs/examples/plot_linear_gridsearch_tutorial.py b/docs/examples/plot_linear_gridsearch_tutorial.py index b7e38413b..d1a239e7f 100644 --- a/docs/examples/plot_linear_gridsearch_tutorial.py +++ b/docs/examples/plot_linear_gridsearch_tutorial.py @@ -34,7 +34,7 @@ # As for the estimator ``MultiLabelEstimator``, argument ``options`` is a LIBLINEAR option # (see *train Usage* in `liblinear `__ README), and # ``linear_technique`` is one of the linear techniques, including ``1vsrest``, ``thresholding``, ``cost_sensitive``, -# ``cost_sensitive_micro``, and ``binary_and_mulitclass``. +# ``cost_sensitive_micro``, and ``binary_and_multiclass``. # # We can specify the aliases of the components used by the pipeline. # For example, ``tfidf`` is the alias of ``TfidfVectorizer`` and ``clf`` is the alias of the estimator. diff --git a/docs/examples/plot_linear_tree_tutorial.py b/docs/examples/plot_linear_tree_tutorial.py index d9cb41f1c..846ae88ae 100644 --- a/docs/examples/plot_linear_tree_tutorial.py +++ b/docs/examples/plot_linear_tree_tutorial.py @@ -1,5 +1,5 @@ """ -Handling Data with Many Labels using Linear Methods. +Handling Data with Many Labels Using Linear Methods ==================================================== For the case that the amount of labels is very large, diff --git a/docs/examples/plot_multi_label.py b/docs/examples/plot_multi_label.py index e8aef667a..d8c28a081 100644 --- a/docs/examples/plot_multi_label.py +++ b/docs/examples/plot_multi_label.py @@ -69,12 +69,12 @@ # - Training time (sec) # # * - Linear method (one-vs-rest) -# - 0.5171960144875225 -# - 4.327306747436523 +# - 0.52 +# - 4.33 # # * - Deep learning method (BERT) -# - 0.564618763137536 -# - 5412.955321788788 +# - 0.56 +# - 5412.96 # # Step 2. Training: # ----------------- @@ -120,13 +120,13 @@ # - Macro-F1 # # * - One-vs-rest -# - 0.5171960144875225 +# - 0.52 # # * - Thresholding -# - 0.5643407144065415 +# - 0.56 # # * - Cost-sensitive -# - 0.5704056980791481 +# - 0.57 # # From the comparison, one can see that these techniques improves the naive method. # @@ -139,7 +139,7 @@ # Training models directly in this case may result in high runtime and space consumption. # A solution to reduce these costs is to utilize tree-based models. # Here we provide an example comparing a linear one-vs-rest model and a tree model on the EUR-Lex-57k dataset, which has a larger label space. -# We start by training a tree model following another detailed `tutorial <../auto_examples/plot_linear_tree_tutorial.html>`__. +# We start by training a tree model following the `linear tree tutorial <../auto_examples/plot_linear_tree_tutorial.html>`__. datasets_eurlex = linear.load_dataset("txt", "data/eurlex57k/train.txt", "data/eurlex57k/test.txt") preprocessor_eurlex = linear.Preprocessor() @@ -168,7 +168,7 @@ # # It is clear that the tree model significantly improves efficiency. # As for deep learning, a similar improvement in efficiency can be observed. -# Details for the tree-based deep learning model can be found in this `tutorial <../tutorials/AttentionXML.html>`__. +# Details for the tree-based deep learning model can be found in the `deep learning tree tutorial <../tutorials/AttentionXML.html>`__. # # Step 3. Evaluation: Pick Suitable Metrics # ----------------------------------------- @@ -203,8 +203,7 @@ # ----------------------------- # Models with suboptimal hyperparameters may lead to poor performance :cite:p:`JJL21a`. # Users can incorporate hyperparameter tuning into the training process. -# Because this functionality is more complex and cannot be adequately demonstrated within a code snippet, please refer to these two tutorials for more details about hyperparameter tuning (`linear <../auto_examples/plot_gridsearch_tutorial.html>`_ -# and `deep learning <../tutorials/Parameter_Selection_for_Neural_Networks.html>`_). +# Because this functionality is more complex and cannot be adequately demonstrated within a code snippet, please refer to these two tutorials for more details about hyperparameter tuning (`linear <../auto_examples/plot_linear_gridsearch_tutorial.html>`_ and `deep learning <../tutorials/Parameter_Selection_for_Neural_Networks.html>`_). # Another thing to consider is that hyperparameter search can be time-consuming, especially in the case of deep learning. # Users need to conduct this step with consideration of the available resources and time. # @@ -214,7 +213,7 @@ # To use as much information as possible, for linear methods, after determining the best hyperparameters, all available data are generally trained under these optimal hyperparameters to obtain the final model. # We refer to this as the "retrain" strategy. # -# For linear methods, the `tutorial <../auto_examples/plot_gridsearch_tutorial.html>`__ for hyperparameter search already handles retraining by default. +# For linear methods, the `tutorial <../auto_examples/plot_linear_gridsearch_tutorial.html>`_ for hyperparameter search already handles retraining by default. # As for deep learning, since this additional step is not common in practice, we include it in the last section of this `tutorial <../tutorials/Parameter_Selection_for_Neural_Networks.html>`__. # # Step 6. Prediction diff --git a/docs/neural_networks.rst b/docs/neural_networks.rst deleted file mode 100644 index 7e68cd382..000000000 --- a/docs/neural_networks.rst +++ /dev/null @@ -1,9 +0,0 @@ -Neural Networks -=============== - -.. toctree:: - :maxdepth: 1 - :titlesonly: - - tutorials/Parameter_Selection_for_Neural_Networks - tutorials/AttentionXML diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 0391b70ed..6d18243c8 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -2,7 +2,7 @@ Tutorials ========= .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :titlesonly: ../auto_examples/plot_multi_label diff --git a/docs/tutorials/AttentionXML.rst b/docs/tutorials/AttentionXML.rst index e050399b2..daa4e42be 100644 --- a/docs/tutorials/AttentionXML.rst +++ b/docs/tutorials/AttentionXML.rst @@ -1,5 +1,5 @@ -Handling Data with Many Labels with AttentionXML -================================================ +Handling Data with Many Labels Using Neural Networks +==================================================== As time and space complexities grow linearly as the label size increases, it is inefficient to train models in its original label space. We consider adopting AttentionXML :cite:p:`RY19a` to address the issue by training models with a reduced space of labels. @@ -38,7 +38,7 @@ There are 2 extra hyperparameters for AttentionXML that users need to know: Performance ----------- -We compared the performance between BiLSTM and AttentionXML as they have similar architectures. The datasest, +We compared the performance between BiLSTM and AttentionXML as they have similar architectures. The dataset, Wiki10-31K, has 30,938 classes, which makes it hard for models to train in a one-vs-all manner. Both models were trained on an A100 Nvidia GPU. Their test results are shown below. Notice the difference