├── autogl ├── data │ ├── graph │ │ ├── utils │ │ │ ├── __init__.py │ │ │ └── conversion.py │ │ ├── _general_static_graph │ │ │ ├── utils │ │ │ │ ├── __init__.py │ │ │ │ └── conversion │ │ │ │ │ └── __init__.py │ │ │ ├── __init__.py │ │ │ ├── _general_static_graph.py │ │ │ └── _canonical_edge_type.py │ │ └── __init__.py │ ├── _dataset │ │ ├── __init__.py │ │ └── _in_memory_static_graph_set.py │ ├── makedirs.py │ ├── __init__.py │ ├── download.py │ └── extract.py ├── module │ ├── hpo │ │ ├── autone_file │ │ │ └── __init__.py │ │ ├── suggestion │ │ │ ├── algorithm │ │ │ │ ├── __init__.py │ │ │ │ ├── tpe.py │ │ │ │ ├── cmaes.py │ │ │ │ ├── mocmaes.py │ │ │ │ ├── chocolate_bayes.py │ │ │ │ ├── simulate_anneal.py │ │ │ │ ├── chocolate_grid_search.py │ │ │ │ ├── chocolate_random_search.py │ │ │ │ ├── quasi_random_search.py │ │ │ │ ├── hyperopt_random_search.py │ │ │ │ ├── skopt_bayesian_optimization.py │ │ │ │ ├── abstract_algorithm.py │ │ │ │ └── util.py │ │ │ ├── migrations │ │ │ │ └── __init__.py │ │ │ ├── early_stop_algorithm │ │ │ │ ├── __init__.py │ │ │ │ ├── no_early_stop.py │ │ │ │ ├── early_stop_first_trial.py │ │ │ │ ├── abstract_early_stop.py │ │ │ │ ├── abstract_early_stop_test.py │ │ │ │ ├── early_stop_descending.py │ │ │ │ ├── no_early_stop_test.py │ │ │ │ ├── early_stop_descending_test.py │ │ │ │ └── early_stop_first_trial_test.py │ │ │ └── __init__.py │ │ ├── bayes_advisorchoco.py │ │ ├── grid_advisorchoco.py │ │ ├── rand_advisorchoco.py │ │ ├── tpe_advisorhpo.py │ │ ├── mocmaes_advisorchoco.py │ │ ├── cmaes_advisorchoco.py │ │ ├── grid_advisor.py │ │ ├── bayes_advisor.py │ │ ├── rand_advisor.py │ │ ├── anneal_advisorhpo.py │ │ ├── quasi_advisorchoco.py │ │ └── __init__.py │ ├── model │ │ ├── dgl │ │ │ ├── hetero │ │ │ │ ├── __init__.py │ │ │ │ └── base.py │ │ │ ├── __init__.py │ │ │ └── _model_registry.py │ │ ├── pyg │ │ │ ├── robust │ │ │ │ ├── __init__.py │ │ │ │ └── nn │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── inits.py │ │ │ ├── __init__.py │ │ │ └── _model_registry.py │ │ ├── _utils │ │ │ ├── __init__.py │ │ │ └── activation.py │ │ ├── encoders │ │ │ ├── _pyg │ │ │ │ └── __init__.py │ │ │ ├── _dgl │ │ │ │ └── __init__.py │ │ │ ├── __init__.py │ │ │ └── encoder_registry.py │ │ ├── decoders │ │ │ ├── _pyg │ │ │ │ └── __init__.py │ │ │ ├── _dgl │ │ │ │ └── __init__.py │ │ │ ├── __init__.py │ │ │ ├── decoder_registry.py │ │ │ └── base_decoder.py │ │ └── __init__.py │ ├── train │ │ ├── sampling │ │ │ ├── __init__.py │ │ │ └── sampler │ │ │ │ └── __init__.py │ │ ├── ssl │ │ │ ├── __init__.py │ │ │ ├── losses.py │ │ │ └── utils.py │ │ ├── node_classification_trainer │ │ │ └── __init__.py │ │ └── __init__.py │ ├── nas │ │ ├── space │ │ │ ├── autoattend_space │ │ │ │ ├── __init__.py │ │ │ │ ├── ops2.py │ │ │ │ └── ops1.py │ │ │ ├── gasso_space │ │ │ │ ├── utils │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── helpers.py │ │ │ │ │ └── jit.py │ │ │ │ ├── __init__.py │ │ │ │ └── inits.py │ │ │ ├── operation.py │ │ │ └── __init__.py │ │ ├── __init__.py │ │ ├── backend.py │ │ ├── algorithm │ │ │ ├── base.py │ │ │ └── __init__.py │ │ └── estimator │ │ │ ├── __init__.py │ │ │ └── base.py │ ├── preprocessing │ │ ├── __init__.py │ │ ├── feature_engineering │ │ │ ├── _selectors │ │ │ │ └── __init__.py │ │ │ ├── _feature_engineer.py │ │ │ ├── _graph │ │ │ │ └── __init__.py │ │ │ ├── _generators │ │ │ │ ├── __init__.py │ │ │ │ └── _page_rank.py │ │ │ └── __init__.py │ │ ├── structure_engineering │ │ │ ├── __init__.py │ │ │ └── _structure_engineer.py │ │ ├── _data_preprocessor │ │ │ └── __init__.py │ │ └── _data_preprocessor_registry.py │ ├── feature │ │ ├── _selectors │ │ │ └── __init__.py │ │ ├── _base_feature_engineer │ │ │ ├── __init__.py │ │ │ ├── _base_feature_engineer_pyg.py │ │ │ └── _base_feature_engineer_dgl.py │ │ ├── _graph │ │ │ └── __init__.py │ │ ├── _generators │ │ │ ├── __init__.py │ │ │ └── _page_rank.py │ │ ├── _feature_engineer_registry.py │ │ └── __init__.py │ ├── __init__.py │ ├── _feature │ │ ├── selectors │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ └── se_filter_constant.py │ │ ├── generators │ │ │ ├── base.py │ │ │ ├── __init__.py │ │ │ └── page_rank.py │ │ ├── graph │ │ │ ├── base.py │ │ │ ├── netlsd.py │ │ │ └── __init__.py │ │ └── utils.py │ └── ensemble │ │ ├── base.py │ │ └── __init__.py ├── backend │ └── __init__.py ├── datasets │ ├── utils │ │ ├── _split_edges │ │ │ ├── __init__.py │ │ │ └── split_edges.py │ │ ├── __init__.py │ │ └── conversion │ │ │ ├── __init__.py │ │ │ ├── _to_pyg_dataset.py │ │ │ └── _to_dgl_dataset.py │ ├── _heterogeneous_datasets │ │ └── __init__.py │ ├── _dataset_registry.py │ └── _data_source.py ├── solver │ ├── classifier │ │ ├── hetero │ │ │ └── __init__.py │ │ ├── ssl │ │ │ ├── __init__.py │ │ │ └── utils.py │ │ ├── __init__.py │ │ └── base.py │ └── __init__.py ├── utils │ ├── __init__.py │ ├── log.py │ └── device.py └── __init__.py ├── video └── showcase.mp4 ├── docs ├── docfile │ ├── documentation │ │ ├── data.rst │ │ ├── dataset │ │ │ ├── dgl.rst │ │ │ └── pyg.rst │ │ ├── solver.rst │ │ ├── hpo.rst │ │ ├── train.rst │ │ ├── ensemble.rst │ │ ├── model.rst │ │ ├── feature.rst │ │ ├── nas.rst │ │ ├── model │ │ │ ├── pyg.rst │ │ │ └── dgl.rst │ │ └── dataset.rst │ ├── tutorial_cn │ │ ├── t_backend.rst │ │ ├── t_ensemble.rst │ │ └── t_quickstart.rst │ └── tutorial │ │ └── t_backend.rst ├── requirements.txt ├── make.bat └── Makefile ├── .readthedocs.yml ├── test ├── dataset │ └── utils.py ├── backend.py ├── solver │ ├── graph_classification.py │ └── node_classification.py ├── trainer │ └── pyg │ │ ├── link_prediction.py │ │ ├── graph_classification.py │ │ └── node_classification.py ├── performance │ ├── link_prediction │ │ ├── pyg │ │ │ └── helper.py │ │ └── dgl │ │ │ └── helper.py │ ├── performance_check.sh │ ├── node_classification │ │ ├── dgl │ │ │ └── helper.py │ │ └── pyg │ │ │ ├── helper.py │ │ │ └── solver.py │ ├── graph_classification │ │ ├── pyg │ │ │ └── helper.py │ │ └── dgl │ │ │ └── helper.py │ └── heterogeneous │ │ └── dgl │ │ ├── solver.py │ │ └── helper.py └── preprocessing │ ├── structure.py │ └── utils.py ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── examples ├── hetero_node_classification.py ├── gasso_test.py ├── quickstart.py ├── graphnas.py ├── autoattend.py └── node_classification_ogb.py ├── configs ├── nodeclf_nas_gasso.yml ├── nodeclf_nas_macro_benchmark2.yml ├── nodeclf_nas_macro_benchmark.yml ├── nodeclf_nas_autoattend_benchmark.yml ├── graphclf_topk_benchmark.yml ├── nodeclf_nas_grna.yml ├── nodeclf_gcn_benchmark_small.yml ├── nodeclf_gcn_benchmark_ogb.yml ├── lp_gcn_benchmark.yml ├── lp_gat_benchmark.yml ├── nodeclf_gcn_benchmark_large.yml ├── nodeclf_gat_benchmark_small.yml ├── nodeclf_gat_benchmark_large.yml ├── nodeclf_sage_benchmark_small.yml ├── lp_sage_benchmark.yml ├── graphclf_gin_benchmark.yml ├── nodeclf_ladies_reproduction.yml ├── nodeclf_sage_benchmark_large.yml ├── graphclf_gin_diffpool_benchmark.yaml ├── nodeclf_full.yml ├── graphclf_full.yml └── pyg │ └── lp_benchmark.yml └── setup.py /autogl/data/graph/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/hpo/autone_file/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/model/dgl/hetero/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/model/pyg/robust/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/train/sampling/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/train/sampling/sampler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/nas/space/autoattend_space/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/nas/space/gasso_space/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/data/graph/_general_static_graph/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogl/module/model/_utils/__init__.py: -------------------------------------------------------------------------------- 1 | from . import activation 2 | -------------------------------------------------------------------------------- /autogl/backend/__init__.py: -------------------------------------------------------------------------------- 1 | from ._dependent_backend import DependentBackend 2 | -------------------------------------------------------------------------------- /autogl/datasets/utils/_split_edges/__init__.py: -------------------------------------------------------------------------------- 1 | from .split_edges import split_edges 2 | -------------------------------------------------------------------------------- /video/showcase.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/THUMNLab/AutoGL/HEAD/video/showcase.mp4 -------------------------------------------------------------------------------- /autogl/data/graph/utils/conversion.py: -------------------------------------------------------------------------------- 1 | from .._general_static_graph.utils.conversion import * 2 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/__init__.py: -------------------------------------------------------------------------------- 1 | """ preprocessing """ 2 | from ._data_preprocessor import * -------------------------------------------------------------------------------- /autogl/solver/classifier/hetero/__init__.py: -------------------------------------------------------------------------------- 1 | from .node_classifier import AutoHeteroNodeClassifier -------------------------------------------------------------------------------- /autogl/module/feature/_selectors/__init__.py: -------------------------------------------------------------------------------- 1 | from ._basic import FilterConstant 2 | from ._gbdt import GBDTFeatureSelector 3 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/__init__.py: -------------------------------------------------------------------------------- 1 | # Files in this folder are reproduced from https://github.com/tobegit3hub/advisor with some changes. 2 | -------------------------------------------------------------------------------- /autogl/data/_dataset/__init__.py: -------------------------------------------------------------------------------- 1 | from ._dataset import Dataset, InMemoryDataset 2 | from ._in_memory_static_graph_set import InMemoryStaticGraphSet 3 | -------------------------------------------------------------------------------- /autogl/module/model/pyg/robust/nn/__init__.py: -------------------------------------------------------------------------------- 1 | from .gcn_conv import GCNConv 2 | 3 | __all__ = [ 4 | 'GCNConv' 5 | ] 6 | 7 | classes = __all__ 8 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/_selectors/__init__.py: -------------------------------------------------------------------------------- 1 | from ._basic import FilterConstant 2 | from ._gbdt import GBDTFeatureSelector 3 | -------------------------------------------------------------------------------- /docs/docfile/documentation/data.rst: -------------------------------------------------------------------------------- 1 | .. _data documentation: 2 | 3 | autogl.data 4 | =========== 5 | 6 | .. automodule:: autogl.data 7 | :members: -------------------------------------------------------------------------------- /autogl/data/graph/__init__.py: -------------------------------------------------------------------------------- 1 | from ._general_static_graph import ( 2 | GeneralStaticGraph, GeneralStaticGraphGenerator 3 | ) 4 | from . import utils 5 | -------------------------------------------------------------------------------- /docs/docfile/documentation/dataset/dgl.rst: -------------------------------------------------------------------------------- 1 | Deep Graph Library Dataset 2 | ========================== 3 | 4 | .. automodule:: autogl.datasets 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/docfile/documentation/dataset/pyg.rst: -------------------------------------------------------------------------------- 1 | PyTorch Geometric Dataset 2 | ========================== 3 | 4 | .. automodule:: autogl.datasets 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/docfile/documentation/solver.rst: -------------------------------------------------------------------------------- 1 | .. _solver documentation: 2 | 3 | autogl.solver 4 | ============= 5 | 6 | .. automodule:: autogl.solver 7 | :members: -------------------------------------------------------------------------------- /docs/docfile/documentation/hpo.rst: -------------------------------------------------------------------------------- 1 | .. _hpo documentation: 2 | 3 | autogl.module.hpo 4 | ----------------- 5 | 6 | .. automodule:: autogl.module.hpo 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/docfile/documentation/train.rst: -------------------------------------------------------------------------------- 1 | .. _train documentation: 2 | 3 | autogl.module.train 4 | ------------------- 5 | 6 | .. automodule:: autogl.module.train 7 | :members: 8 | -------------------------------------------------------------------------------- /autogl/data/graph/_general_static_graph/__init__.py: -------------------------------------------------------------------------------- 1 | from ._general_static_graph import GeneralStaticGraph 2 | from ._general_static_graph_generator import GeneralStaticGraphGenerator 3 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/_feature_engineer.py: -------------------------------------------------------------------------------- 1 | from .. import _data_preprocessor 2 | 3 | 4 | class FeatureEngineer(_data_preprocessor.DataPreprocessor): 5 | ... 6 | -------------------------------------------------------------------------------- /autogl/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Some utils used by AutoGL 3 | """ 4 | 5 | from .log import get_logger 6 | from .device import get_device 7 | 8 | __all__ = ["get_logger", "get_device"] 9 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/structure_engineering/__init__.py: -------------------------------------------------------------------------------- 1 | from ._gcn_jaccard import GCNJaccard 2 | from ._gcn_svd import GCNSVD 3 | from ._structure_engineer import StructureEngineer 4 | 5 | -------------------------------------------------------------------------------- /docs/docfile/documentation/ensemble.rst: -------------------------------------------------------------------------------- 1 | .. _ensemble documentation: 2 | 3 | autogl.module.ensemble 4 | ---------------------- 5 | 6 | .. automodule:: autogl.module.ensemble 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/docfile/documentation/model.rst: -------------------------------------------------------------------------------- 1 | .. _model documentation: 2 | 3 | autogl.module.model 4 | ------------------- 5 | 6 | .. toctree:: 7 | 8 | model/dgl.rst 9 | model/pyg.rst 10 | -------------------------------------------------------------------------------- /autogl/module/nas/__init__.py: -------------------------------------------------------------------------------- 1 | from . import algorithm, estimator, space 2 | 3 | from .algorithm import NAS_ALGO_DICT 4 | from .estimator import NAS_ESTIMATOR_DICT 5 | from .space import NAS_SPACE_DICT 6 | -------------------------------------------------------------------------------- /autogl/module/__init__.py: -------------------------------------------------------------------------------- 1 | from . import feature, model, train, hpo, nas, ensemble 2 | 3 | from .ensemble import * 4 | from .feature import * 5 | from .hpo import * 6 | from .model import * 7 | from .train import * 8 | -------------------------------------------------------------------------------- /autogl/module/model/encoders/_pyg/__init__.py: -------------------------------------------------------------------------------- 1 | from ._gat import GATEncoderMaintainer 2 | from ._gcn import GCNEncoderMaintainer 3 | from ._gin import GINEncoderMaintainer 4 | from ._sage import SAGEEncoderMaintainer 5 | -------------------------------------------------------------------------------- /autogl/module/_feature/selectors/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseSelector 2 | from .se_filter_constant import SeFilterConstant 3 | from .se_gbdt import SeGBDT 4 | 5 | __all__ = ["BaseSelector", "SeFilterConstant", "SeGBDT"] 6 | -------------------------------------------------------------------------------- /autogl/module/model/decoders/_pyg/__init__.py: -------------------------------------------------------------------------------- 1 | from ._pyg_decoders import ( 2 | LogSoftmaxDecoderMaintainer, 3 | SumPoolMLPDecoderMaintainer, 4 | DiffPoolDecoderMaintainer, 5 | DotProductLinkPredictionDecoderMaintainer 6 | ) 7 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | bayesian-optimization 2 | chocolate 3 | dill 4 | hyperopt 5 | lightgbm 6 | networkx 7 | numpy 8 | netlsd 9 | ogb 10 | psutil 11 | pyyaml 12 | requests 13 | scikit-learn 14 | scipy 15 | tabulate 16 | tqdm 17 | nni -------------------------------------------------------------------------------- /autogl/datasets/_heterogeneous_datasets/__init__.py: -------------------------------------------------------------------------------- 1 | from autogl import backend as _backend 2 | 3 | if _backend.DependentBackend.is_dgl(): 4 | from ._dgl_heterogeneous_datasets import ( 5 | ACMHANDataset, ACMHGTDataset 6 | ) 7 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/_data_preprocessor/__init__.py: -------------------------------------------------------------------------------- 1 | import autogl 2 | 3 | if autogl.backend.DependentBackend.is_dgl(): 4 | from ._data_preprocessor_dgl import DataPreprocessor 5 | else: 6 | from ._data_preprocessor import DataPreprocessor 7 | -------------------------------------------------------------------------------- /autogl/solver/classifier/ssl/__init__.py: -------------------------------------------------------------------------------- 1 | from ....backend import DependentBackend 2 | 3 | __all__ = [] 4 | 5 | if DependentBackend.is_pyg(): 6 | from .ssl_graph_classifier import SSLGraphClassifier 7 | __all__.extend(["SSLGraphClassifier"]) 8 | -------------------------------------------------------------------------------- /autogl/module/model/encoders/_dgl/__init__.py: -------------------------------------------------------------------------------- 1 | from ._gat import GATEncoderMaintainer 2 | from ._gcn import GCNEncoderMaintainer 3 | from ._gin import GINEncoderMaintainer 4 | from ._sage import SAGEEncoderMaintainer 5 | from ._topk import AutoTopKMaintainer 6 | -------------------------------------------------------------------------------- /autogl/module/nas/space/gasso_space/utils/helpers.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def expand_left(src: torch.Tensor, dim: int, dims: int) -> torch.Tensor: 5 | for _ in range(dims + dim if dim < 0 else dim): 6 | src = src.unsqueeze(0) 7 | return src 8 | -------------------------------------------------------------------------------- /autogl/module/model/decoders/_dgl/__init__.py: -------------------------------------------------------------------------------- 1 | from ._dgl_decoders import ( 2 | LogSoftmaxDecoderMaintainer, 3 | JKSumPoolDecoderMaintainer, 4 | SumPoolMLPDecoderMaintainer, 5 | TopKDecoderMaintainer, 6 | DotProductLinkPredictionDecoderMaintainer 7 | ) 8 | -------------------------------------------------------------------------------- /docs/docfile/documentation/feature.rst: -------------------------------------------------------------------------------- 1 | .. _feature documentation: 2 | 3 | autogl.module.feature 4 | ===================== 5 | 6 | We support feature engineering for both PyTorch Geometric and Deep Deep Graph Library backend. 7 | 8 | .. automodule:: autogl.module.feature 9 | :members: 10 | -------------------------------------------------------------------------------- /autogl/data/makedirs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import errno 4 | 5 | 6 | def makedirs(path): 7 | try: 8 | os.makedirs(osp.expanduser(osp.normpath(path))) 9 | except OSError as e: 10 | if e.errno != errno.EEXIST and osp.isdir(path): 11 | raise e 12 | -------------------------------------------------------------------------------- /autogl/datasets/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from ._split_edges import split_edges 2 | from ._general import ( 3 | index_to_mask, 4 | random_splits_mask, 5 | random_splits_mask_class, 6 | graph_cross_validation, 7 | graph_random_splits, 8 | graph_get_split, 9 | set_fold, 10 | ) 11 | -------------------------------------------------------------------------------- /autogl/__init__.py: -------------------------------------------------------------------------------- 1 | from . import ( 2 | backend, 3 | data, 4 | datasets, 5 | module, 6 | solver, 7 | utils, 8 | ) 9 | 10 | from .module import ( 11 | ensemble, 12 | feature, 13 | hpo, 14 | model, 15 | nas, 16 | train, 17 | ) 18 | 19 | __version__ = "0.3.1" 20 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/no_early_stop.py: -------------------------------------------------------------------------------- 1 | from suggestion.early_stop_algorithm.abstract_early_stop import ( 2 | AbstractEarlyStopAlgorithm, 3 | ) 4 | 5 | 6 | class NoEarlyStopAlgorithm(AbstractEarlyStopAlgorithm): 7 | def get_early_stop_trials(self, trials): 8 | return [] 9 | -------------------------------------------------------------------------------- /docs/docfile/documentation/nas.rst: -------------------------------------------------------------------------------- 1 | .. _neural architecture search: 2 | 3 | autogl.module.nas 4 | ----------------- 5 | 6 | .. automodule:: autogl.module.nas.algorithm 7 | :members: 8 | 9 | .. automodule:: autogl.module.nas.space 10 | :members: 11 | 12 | .. automodule:: autogl.module.nas.estimator 13 | :members: 14 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/early_stop_first_trial.py: -------------------------------------------------------------------------------- 1 | from suggestion.early_stop_algorithm.abstract_early_stop import ( 2 | AbstractEarlyStopAlgorithm, 3 | ) 4 | 5 | 6 | class EarlyStopFirstTrialAlgorithm(AbstractEarlyStopAlgorithm): 7 | def get_early_stop_trials(self, trials): 8 | return [trials[0]] 9 | -------------------------------------------------------------------------------- /autogl/module/feature/_base_feature_engineer/__init__.py: -------------------------------------------------------------------------------- 1 | import autogl 2 | 3 | if autogl.backend.DependentBackend.is_dgl(): 4 | from ._base_feature_engineer_dgl import BaseFeatureEngineer 5 | else: 6 | from ._base_feature_engineer_pyg import BaseFeatureEngineer 7 | 8 | 9 | class BaseFeature(BaseFeatureEngineer): 10 | ... 11 | -------------------------------------------------------------------------------- /autogl/datasets/utils/conversion/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | import dgl 3 | except ModuleNotFoundError: 4 | dgl = None 5 | else: 6 | from ._to_dgl_dataset import to_dgl_dataset 7 | try: 8 | import torch_geometric 9 | except ModuleNotFoundError: 10 | torch_geometric = None 11 | else: 12 | from ._to_pyg_dataset import to_pyg_dataset 13 | -------------------------------------------------------------------------------- /docs/docfile/documentation/model/pyg.rst: -------------------------------------------------------------------------------- 1 | PyTorch Geometric Backend 2 | ========================= 3 | 4 | Models 5 | ~~~~~~ 6 | 7 | .. automodule:: autogl.module.model.pyg 8 | :members: 9 | 10 | Encoders 11 | ~~~~~~~~ 12 | 13 | .. automodule:: autogl.module.model.encoders 14 | :members: 15 | 16 | Decoders 17 | ~~~~~~~~ 18 | 19 | .. automodule:: autogl.module.model.decoders 20 | :members: 21 | 22 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/tpe.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_hyperopt_algorithm import BaseHyperoptAlgorithm 2 | 3 | 4 | class TpeAlgorithm(BaseHyperoptAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with TPE algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(TpeAlgorithm, self).__init__("tpe") 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/cmaes.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class CmaesAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with CMAES algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(CmaesAlgorithm, self).__init__("CMAES") 12 | -------------------------------------------------------------------------------- /autogl/utils/log.py: -------------------------------------------------------------------------------- 1 | """ 2 | Log utils. Used to manage the output format of AutoGL 3 | """ 4 | 5 | import logging 6 | 7 | 8 | def get_logger(name): 9 | """ 10 | Get the logger of given name 11 | 12 | Parameters 13 | ---------- 14 | name: str 15 | The name of logger 16 | 17 | Returns 18 | ------- 19 | logger: Logger 20 | The logger generated 21 | """ 22 | return logging.getLogger(name) 23 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/mocmaes.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class MocmaesAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with MOCMAES algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(MocmaesAlgorithm, self).__init__("MOCMAES") 12 | -------------------------------------------------------------------------------- /docs/docfile/documentation/dataset.rst: -------------------------------------------------------------------------------- 1 | .. _dataset documentation: 2 | 3 | autogl.datasets 4 | =============== 5 | 6 | We integrate the datasets from `PyTorch Geometric `_, `DGL `_ and `OGB `_. We also list some datasets from `CogDL` for simplicity. 7 | 8 | .. toctree:: 9 | 10 | dataset/dgl.rst 11 | dataset/pyg.rst 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/chocolate_bayes.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class ChocolateBayesAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with bayes algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(ChocolateBayesAlgorithm, self).__init__("Bayes") 12 | -------------------------------------------------------------------------------- /autogl/data/__init__.py: -------------------------------------------------------------------------------- 1 | from .data import Data 2 | from ._dataset import Dataset, InMemoryDataset, InMemoryStaticGraphSet 3 | from .download import download_url 4 | from .extract import extract_tar, extract_zip, extract_bz2, extract_gz 5 | 6 | __all__ = [ 7 | "Data", 8 | "Dataset", 9 | "InMemoryDataset", 10 | "InMemoryStaticGraphSet", 11 | "download_url", 12 | "extract_tar", 13 | "extract_zip", 14 | "extract_bz2", 15 | "extract_gz", 16 | ] 17 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/simulate_anneal.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_hyperopt_algorithm import BaseHyperoptAlgorithm 2 | 3 | 4 | class SimulateAnnealAlgorithm(BaseHyperoptAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with simulate anneal algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(SimulateAnnealAlgorithm, self).__init__("anneal") 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/chocolate_grid_search.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class ChocolateGridSearchAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with grid search algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(ChocolateGridSearchAlgorithm, self).__init__("Grid") 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/chocolate_random_search.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class ChocolateRandomSearchAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with random search algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(ChocolateRandomSearchAlgorithm, self).__init__("Random") 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/quasi_random_search.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_chocolate_algorithm import BaseChocolateAlgorithm 2 | 3 | 4 | class QuasiRandomSearchAlgorithm(BaseChocolateAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with quasi random search algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(QuasiRandomSearchAlgorithm, self).__init__("QuasiRandom") 12 | -------------------------------------------------------------------------------- /autogl/data/graph/_general_static_graph/_general_static_graph.py: -------------------------------------------------------------------------------- 1 | from . import _abstract_views 2 | 3 | 4 | class GeneralStaticGraph: 5 | @property 6 | def nodes(self) -> _abstract_views.HeterogeneousNodeView: 7 | raise NotImplementedError 8 | 9 | @property 10 | def edges(self) -> _abstract_views.HeterogeneousEdgesView: 11 | raise NotImplementedError 12 | 13 | @property 14 | def data(self) -> _abstract_views.GraphDataView: 15 | raise NotImplementedError 16 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/hyperopt_random_search.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_hyperopt_algorithm import BaseHyperoptAlgorithm 2 | 3 | 4 | class HyperoptRandomSearchAlgorithm(BaseHyperoptAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with random search algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(HyperoptRandomSearchAlgorithm, self).__init__("random_search") 12 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/skopt_bayesian_optimization.py: -------------------------------------------------------------------------------- 1 | from ...suggestion.algorithm.base_skopt_algorithm import BaseSkoptAlgorithm 2 | 3 | 4 | class SkoptBayesianOptimization(BaseSkoptAlgorithm): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | Get the new suggested trials with bayesian optimization algorithm. 8 | """ 9 | 10 | def __init__(self): 11 | super(SkoptBayesianOptimization, self).__init__("bayesian_optimization") 12 | -------------------------------------------------------------------------------- /autogl/module/_feature/selectors/base.py: -------------------------------------------------------------------------------- 1 | from ..base import BaseFeature 2 | import numpy as np 3 | 4 | 5 | class BaseSelector(BaseFeature): 6 | def __init__(self, data_t="np", multigraph=False, **kwargs): 7 | super(BaseSelector, self).__init__( 8 | data_t=data_t, multigraph=multigraph, **kwargs 9 | ) 10 | self._sel = None 11 | 12 | def _transform(self, data): 13 | if self._sel is not None: 14 | data.x = data.x[:, self._sel] 15 | return data 16 | -------------------------------------------------------------------------------- /autogl/module/feature/_graph/__init__.py: -------------------------------------------------------------------------------- 1 | from ._netlsd import NetLSD 2 | from ._networkx import ( 3 | NXLargeCliqueSize, 4 | NXDegreeAssortativityCoefficient, 5 | NXDegreePearsonCorrelationCoefficient, 6 | NXHasBridges, 7 | NXGraphCliqueNumber, 8 | NXGraphNumberOfCliques, 9 | NXTransitivity, 10 | NXAverageClustering, 11 | NXIsConnected, 12 | NXNumberConnectedComponents, 13 | NXIsDistanceRegular, 14 | NXLocalEfficiency, 15 | NXGlobalEfficiency, 16 | NXIsEulerian, 17 | ) 18 | -------------------------------------------------------------------------------- /docs/docfile/documentation/model/dgl.rst: -------------------------------------------------------------------------------- 1 | Deep Graph Library Backend 2 | ========================== 3 | 4 | Models 5 | ~~~~~~ 6 | 7 | .. automodule:: autogl.module.model.dgl 8 | :members: 9 | 10 | Encoders 11 | ~~~~~~~~ 12 | 13 | .. autoclass:: autogl.module.model.encoders.GCNEncoderMaintainer 14 | :members: from_hyper_parameter, initialize, get_output_dimensions, hyper_parameter_space, hyper_parameters 15 | 16 | Decoders 17 | ~~~~~~~~ 18 | 19 | .. automodule:: autogl.module.model.decoders 20 | :members: 21 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/abstract_early_stop.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | class AbstractEarlyStopAlgorithm(object): 5 | 6 | __metaclass__ = abc.ABCMeta 7 | 8 | @abc.abstractmethod 9 | def get_early_stop_trials(self, trials): 10 | """ 11 | Pass the trials and return the list of trials to early stop. 12 | 13 | Args: 14 | trials: The all trials of this study. 15 | Returns: 16 | The array of trial objects. 17 | """ 18 | raise NotImplementedError 19 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/_graph/__init__.py: -------------------------------------------------------------------------------- 1 | from ._netlsd import NetLSD 2 | from ._networkx import ( 3 | NXLargeCliqueSize, 4 | NXDegreeAssortativityCoefficient, 5 | NXDegreePearsonCorrelationCoefficient, 6 | NXHasBridges, 7 | NXGraphCliqueNumber, 8 | NXGraphNumberOfCliques, 9 | NXTransitivity, 10 | NXAverageClustering, 11 | NXIsConnected, 12 | NXNumberConnectedComponents, 13 | NXIsDistanceRegular, 14 | NXLocalEfficiency, 15 | NXGlobalEfficiency, 16 | NXIsEulerian, 17 | ) 18 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: docs/conf.py 11 | 12 | formats: 13 | - pdf 14 | 15 | # Optionally set the version of Python and requirements required to build your docs 16 | python: 17 | version: 3.6 18 | install: 19 | - requirements: docs/requirements.txt 20 | - method: pip 21 | path: . -------------------------------------------------------------------------------- /autogl/module/_feature/selectors/se_filter_constant.py: -------------------------------------------------------------------------------- 1 | from .base import BaseSelector 2 | import numpy as np 3 | from .. import register_feature 4 | 5 | 6 | @register_feature("SeFilterConstant") 7 | class SeFilterConstant(BaseSelector): 8 | r"""drop constant features""" 9 | 10 | def _fit(self, data): 11 | d1, d2 = data.x.shape 12 | xx = data.x 13 | # if d2>=d1: 14 | # if np.allclose(xx[:,:d1],np.eye(d1)): 15 | # return np.empty((d1,0)) 16 | self._sel = np.where(np.all(xx == xx[0, :], axis=0) == False)[0] 17 | -------------------------------------------------------------------------------- /autogl/solver/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Auto solver for various graph tasks 3 | """ 4 | 5 | from autogl.backend import DependentBackend 6 | from .classifier import AutoGraphClassifier, AutoNodeClassifier, AutoLinkPredictor 7 | 8 | if DependentBackend.is_dgl(): 9 | from .classifier import AutoHeteroNodeClassifier 10 | 11 | from .utils import LeaderBoard 12 | 13 | __all__ = [ 14 | "AutoNodeClassifier", 15 | "AutoGraphClassifier", 16 | "AutoLinkPredictor", 17 | "LeaderBoard", 18 | ] 19 | 20 | if DependentBackend.is_dgl(): 21 | __all__.append("AutoHeteroNodeClassifier") -------------------------------------------------------------------------------- /autogl/module/train/ssl/__init__.py: -------------------------------------------------------------------------------- 1 | from ....backend import DependentBackend 2 | 3 | if DependentBackend.is_pyg(): 4 | from .graphcl import GraphCLSemisupervisedTrainer, GraphCLUnsupervisedTrainer, BaseContrastiveTrainer 5 | from .utils import get_view_by_name 6 | __all__ = [ 7 | "GraphCLSemisupervisedTrainer", 8 | "GraphCLUnsupervisedTrainer", 9 | "BaseContrastiveTrainer", 10 | "get_view_by_name" 11 | ] 12 | else: 13 | from .graphcl import BaseContrastiveTrainer 14 | __all__ = [ 15 | "BaseContrastiveTrainer" 16 | ] 17 | -------------------------------------------------------------------------------- /autogl/module/hpo/bayes_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | # from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.chocolate_bayes import ChocolateBayesAlgorithm 6 | 7 | # @register_hpo("randadvisor") 8 | 9 | 10 | class BayesAdvisorChoco(AdvisorBaseHPOptimizer): 11 | def __init__(self, args): 12 | super().__init__(args) 13 | self.method = ChocolateBayesAlgorithm() 14 | 15 | @classmethod 16 | def build_hpo_from_args(cls, args): 17 | """Build a new hpo instance.""" 18 | return cls(args) 19 | -------------------------------------------------------------------------------- /autogl/module/hpo/grid_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | # from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.chocolate_grid_search import ChocolateGridSearchAlgorithm 6 | 7 | # @register_hpo("randadvisor") 8 | 9 | 10 | class GridAdvisorChoco(AdvisorBaseHPOptimizer): 11 | def __init__(self, args): 12 | super().__init__(args) 13 | self.method = ChocolateGridSearchAlgorithm() 14 | 15 | @classmethod 16 | def build_hpo_from_args(cls, args): 17 | """Build a new hpo instance.""" 18 | return cls(args) 19 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/abstract_early_stop_test.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from suggestion.early_stop_algorithm.abstract_early_stop import ( 4 | AbstractEarlyStopAlgorithm, 5 | ) 6 | 7 | 8 | class RandomSearchAlgorithmTest(TestCase): 9 | def setUp(self): 10 | pass 11 | 12 | def tearDown(self): 13 | pass 14 | 15 | def test_init(self): 16 | pass 17 | 18 | # abstractEarlyStopAlgorithm = AbstractEarlyStopAlgorithm() 19 | # self.assertEqual(abstractEarlyStopAlgorithm.__class__, AbstractEarlyStopAlgorithm) 20 | -------------------------------------------------------------------------------- /autogl/module/_feature/generators/base.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from .. import register_feature 3 | from ..base import BaseFeature 4 | 5 | 6 | class BaseGenerator(BaseFeature): 7 | def __init__(self, data_t="np", multigraph=True, **kwargs): 8 | super(BaseGenerator, self).__init__( 9 | data_t=data_t, multigraph=multigraph, **kwargs 10 | ) 11 | 12 | 13 | @register_feature("onehot") 14 | class GeOnehot(BaseGenerator): 15 | def _transform(self, data): 16 | fe = np.eye(data.x.shape[0]) 17 | data.x = np.concatenate([data.x, fe], axis=1) 18 | return data 19 | -------------------------------------------------------------------------------- /autogl/module/hpo/rand_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.chocolate_random_search import ChocolateRandomSearchAlgorithm 6 | 7 | # @register_hpo("randomchoco") 8 | 9 | 10 | class RandAdvisorChoco(AdvisorBaseHPOptimizer): 11 | def __init__(self, args): 12 | super().__init__(args) 13 | self.method = ChocolateRandomSearchAlgorithm() 14 | 15 | @classmethod 16 | def build_hpo_from_args(cls, args): 17 | """Build a new hpo instance.""" 18 | return cls(args) 19 | -------------------------------------------------------------------------------- /test/dataset/utils.py: -------------------------------------------------------------------------------- 1 | # test the utils function 2 | 3 | from autogl.datasets import utils, build_dataset_from_name 4 | 5 | def test_graph_cross_validation(): 6 | dataset = build_dataset_from_name('imdb-b') 7 | # first level, 10 folds 8 | utils.graph_cross_validation(dataset, 10) 9 | 10 | # set to fold id 11 | utils.set_fold(dataset, 1) 12 | 13 | # get train split 14 | train_dataset = utils.graph_get_split(dataset, "train", False) 15 | 16 | # further split train to train / val 17 | utils.graph_random_splits(train_dataset, 0.8, 0.2) 18 | 19 | test_graph_cross_validation() 20 | 21 | -------------------------------------------------------------------------------- /autogl/module/feature/_generators/__init__.py: -------------------------------------------------------------------------------- 1 | from ._basic import OneHotFeatureGenerator 2 | from ._eigen import EigenFeatureGenerator 3 | from ._graphlet import GraphletGenerator 4 | from ._page_rank import PageRankFeatureGenerator 5 | from ._pyg import ( 6 | LocalDegreeProfileGenerator, 7 | NormalizeFeatures, 8 | OneHotDegreeGenerator 9 | ) 10 | 11 | __all__ = [ 12 | "OneHotFeatureGenerator", 13 | "EigenFeatureGenerator", 14 | "GraphletGenerator", 15 | "PageRankFeatureGenerator", 16 | "LocalDegreeProfileGenerator", 17 | "NormalizeFeatures", 18 | "OneHotDegreeGenerator" 19 | ] 20 | -------------------------------------------------------------------------------- /autogl/module/train/node_classification_trainer/__init__.py: -------------------------------------------------------------------------------- 1 | from ....backend import DependentBackend 2 | 3 | if DependentBackend.is_pyg(): 4 | from .node_classification_sampled_trainer import ( 5 | NodeClassificationGraphSAINTTrainer, 6 | NodeClassificationLayerDependentImportanceSamplingTrainer, 7 | NodeClassificationNeighborSamplingTrainer 8 | ) 9 | __all__ = [ 10 | "NodeClassificationGraphSAINTTrainer", 11 | "NodeClassificationLayerDependentImportanceSamplingTrainer", 12 | "NodeClassificationNeighborSamplingTrainer" 13 | ] 14 | else: 15 | __all__ = [] 16 | -------------------------------------------------------------------------------- /autogl/module/ensemble/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | ensemble module 3 | """ 4 | 5 | 6 | class BaseEnsembler: 7 | def __init__(self, *args, **kwargs): 8 | super().__init__() 9 | 10 | def fit(self, predictions, label, identifiers, feval, *args, **kwargs): 11 | pass 12 | 13 | def ensemble(self, predictions, identifiers, *args, **kwargs): 14 | pass 15 | 16 | @classmethod 17 | def build_ensembler_from_args(cls, args): 18 | """Build a new ensembler instance.""" 19 | raise NotImplementedError( 20 | "Ensembler must implement the build_ensembler_from_args method" 21 | ) 22 | -------------------------------------------------------------------------------- /autogl/module/nas/space/gasso_space/__init__.py: -------------------------------------------------------------------------------- 1 | from .message_passing import MessagePassing 2 | from .gcn_conv import GCNConv 3 | from .cheb_conv import ChebConv 4 | from .sage_conv import SAGEConv 5 | from .gat_conv import GATConv 6 | from .gin_conv import GINConv, GINEConv 7 | from .arma_conv import ARMAConv 8 | from .edge_conv import EdgeConv, DynamicEdgeConv 9 | 10 | __all__ = [ 11 | 'MessagePassing', 12 | 'GCNConv', 13 | 'ChebConv', 14 | 'SAGEConv', 15 | 'GATConv', 16 | 'GINConv', 17 | 'GINEConv', 18 | 'ARMAConv', 19 | 'EdgeConv', 20 | 'DynamicEdgeConv', 21 | ] 22 | 23 | classes = __all__ 24 | -------------------------------------------------------------------------------- /autogl/module/_feature/generators/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseGenerator 2 | from .graphlet import GeGraphlet 3 | from .eigen import GeEigen 4 | from .page_rank import GePageRank 5 | from .pyg import ( 6 | register_pyg, 7 | PYGGenerator, 8 | pygfunc, 9 | PYGLocalDegreeProfile, 10 | PYGNormalizeFeatures, 11 | PYGOneHotDegree, 12 | ) 13 | 14 | __all__ = [ 15 | "BaseGenerator", 16 | "GeGraphlet", 17 | "GeEigen", 18 | "GePageRank", 19 | "register_pyg", 20 | "pygfunc", 21 | "PYGGenerator", 22 | "PYGLocalDegreeProfile", 23 | "PYGNormalizeFeatures", 24 | "PYGOneHotDegree", 25 | ] 26 | -------------------------------------------------------------------------------- /autogl/module/_feature/graph/base.py: -------------------------------------------------------------------------------- 1 | from ..base import BaseFeature 2 | import numpy as np 3 | import torch 4 | from .. import register_feature 5 | 6 | 7 | @register_feature("graph") 8 | class BaseGraph(BaseFeature): 9 | def __init__(self, data_t="np", multigraph=True, **kwargs): 10 | super(BaseGraph, self).__init__( 11 | data_t=data_t, multigraph=multigraph, subgraph=True, **kwargs 12 | ) 13 | 14 | def _preprocess(self, data): 15 | if not hasattr(data, "gf") or data["gf"] is None: 16 | data.gf = torch.FloatTensor([[]]) 17 | 18 | def _postprocess(self, data): 19 | pass 20 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/_generators/__init__.py: -------------------------------------------------------------------------------- 1 | from ._basic import OneHotFeatureGenerator 2 | from ._eigen import EigenFeatureGenerator 3 | from ._graphlet import GraphletGenerator 4 | from ._page_rank import PageRankFeatureGenerator 5 | from ._pyg import ( 6 | LocalDegreeProfileGenerator, 7 | NormalizeFeatures, 8 | OneHotDegreeGenerator 9 | ) 10 | 11 | __all__ = [ 12 | "OneHotFeatureGenerator", 13 | "EigenFeatureGenerator", 14 | "GraphletGenerator", 15 | "PageRankFeatureGenerator", 16 | "LocalDegreeProfileGenerator", 17 | "NormalizeFeatures", 18 | "OneHotDegreeGenerator" 19 | ] 20 | -------------------------------------------------------------------------------- /autogl/module/model/_utils/activation.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional 2 | import typing as _typing 3 | 4 | 5 | def activation_func( 6 | tensor: torch.Tensor, function_name: _typing.Optional[str] 7 | ) -> torch.Tensor: 8 | if not isinstance(function_name, str): 9 | return tensor 10 | elif function_name == 'linear': 11 | return tensor 12 | elif function_name == 'tanh': 13 | return torch.tanh(tensor) 14 | elif hasattr(torch.nn.functional, function_name): 15 | return getattr(torch.nn.functional, function_name)(tensor) 16 | else: 17 | raise TypeError(f"PyTorch does not support activation function {function_name}") 18 | -------------------------------------------------------------------------------- /autogl/data/graph/_general_static_graph/utils/conversion/__init__.py: -------------------------------------------------------------------------------- 1 | from ._general import StaticGraphToGeneralData, static_graph_to_general_data 2 | from ._nx import ( 3 | HomogeneousStaticGraphToNetworkX 4 | ) 5 | 6 | try: 7 | import dgl 8 | except ModuleNotFoundError: 9 | dgl = None 10 | else: 11 | from ._dgl import ( 12 | DGLGraphToGeneralStaticGraph, dgl_graph_to_general_static_graph, 13 | GeneralStaticGraphToDGLGraph, general_static_graph_to_dgl_graph, 14 | ) 15 | try: 16 | import torch_geometric 17 | except ModuleNotFoundError: 18 | torch_geometric = None 19 | else: 20 | from ._pyg import StaticGraphToPyGData, static_graph_to_pyg_data 21 | -------------------------------------------------------------------------------- /autogl/module/train/ssl/losses.py: -------------------------------------------------------------------------------- 1 | # NTXent_loss from 2 | import torch 3 | import torch.nn as nn 4 | 5 | def NTXent_loss(zs, tau=0.5, norm=True): 6 | batch_size, _ = zs[0].size() 7 | sim_matrix = torch.einsum('ik,jk->ij', zs[0], zs[1]) 8 | if norm: 9 | z1_abs = zs[0].norm(dim=1) 10 | z2_abs = zs[1].norm(dim=1) 11 | sim_matrix = sim_matrix / torch.einsum('i,j->ij', z1_abs, z2_abs) 12 | sim_matrix = torch.exp(sim_matrix/tau) 13 | pos_sim = sim_matrix[range(batch_size), range(batch_size)] 14 | loss = pos_sim / (sim_matrix.sum(dim=1) - pos_sim) 15 | loss = - torch.log(loss).mean() 16 | 17 | return loss 18 | -------------------------------------------------------------------------------- /test/backend.py: -------------------------------------------------------------------------------- 1 | import os 2 | import autogl 3 | 4 | def test_backend(): 5 | environ = os.environ.get("AUTOGL_BACKEND", None) 6 | backend_name = autogl.backend.DependentBackend.get_backend_name() 7 | if environ in ['pyg', 'dgl']: 8 | assert backend_name == environ 9 | else: 10 | try: 11 | import dgl 12 | assert backend_name == 'dgl' 13 | return 14 | except ImportError: 15 | pass 16 | 17 | try: 18 | import torch_geometric 19 | assert backend_name == 'pyg' 20 | return 21 | except ImportError: 22 | pass 23 | 24 | if __name__ == '__main__': 25 | test_backend() 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: general502570 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /autogl/module/nas/backend.py: -------------------------------------------------------------------------------- 1 | # tackle different backend 2 | from autogl.backend import DependentBackend 3 | _isdgl=DependentBackend.is_dgl() 4 | 5 | def is_dgl(): 6 | return _isdgl 7 | 8 | if is_dgl(): 9 | def bk_mask(data,mask): 10 | return data.ndata[f'{mask}_mask'] 11 | def bk_label(data): 12 | return data.ndata['label'] 13 | def bk_feat(data): 14 | return data.ndata['feat'] 15 | def bk_gconv(op,data,feat): 16 | return op(data,feat) 17 | else: 18 | def bk_mask(data,mask): 19 | return data[f'{mask}_mask'] 20 | def bk_label(data): 21 | return data.y 22 | def bk_feat(data): 23 | return data.x 24 | def bk_gconv(op,data,feat): 25 | return op(feat,data.edge_index) 26 | -------------------------------------------------------------------------------- /autogl/module/hpo/tpe_advisorhpo.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.tpe import TpeAlgorithm 6 | 7 | 8 | @register_hpo("tpe") 9 | class TpeAdvisorHPO(AdvisorBaseHPOptimizer): 10 | """ 11 | TPE algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = TpeAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/module/hpo/mocmaes_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.mocmaes import MocmaesAlgorithm 6 | 7 | 8 | @register_hpo("mocmaes") 9 | class MocmaesAdvisorChoco(AdvisorBaseHPOptimizer): 10 | """ 11 | MOCMAES algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, args): 17 | super().__init__(args) 18 | self.method = MocmaesAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/module/hpo/cmaes_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.cmaes import CmaesAlgorithm 6 | 7 | 8 | @register_hpo("cmaes") 9 | class CmaesAdvisorChoco(AdvisorBaseHPOptimizer): 10 | """ 11 | CMAES algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = CmaesAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/module/nas/space/gasso_space/utils/jit.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path as osp 3 | from getpass import getuser 4 | from tempfile import NamedTemporaryFile as TempFile, gettempdir 5 | from importlib.util import module_from_spec, spec_from_file_location 6 | 7 | from torch_geometric.data.makedirs import makedirs 8 | 9 | 10 | def class_from_module_repr(cls_name, module_repr): 11 | path = osp.join(gettempdir(), f'{getuser()}_pyg_jit') 12 | makedirs(path) 13 | with TempFile(mode='w+', suffix='.py', delete=False, dir=path) as f: 14 | f.write(module_repr) 15 | spec = spec_from_file_location(cls_name, f.name) 16 | mod = module_from_spec(spec) 17 | sys.modules[cls_name] = mod 18 | spec.loader.exec_module(mod) 19 | return getattr(mod, cls_name) 20 | -------------------------------------------------------------------------------- /test/solver/graph_classification.py: -------------------------------------------------------------------------------- 1 | from autogl.datasets import build_dataset_from_name 2 | from autogl.solver import AutoGraphClassifier 3 | from autogl.datasets import utils 4 | from autogl.backend import DependentBackend 5 | 6 | mutag = build_dataset_from_name("mutag") 7 | utils.graph_random_splits(mutag, 0.8, 0.1) 8 | 9 | solver = AutoGraphClassifier( 10 | graph_models=("gin",), 11 | hpo_module=None, 12 | device="auto" 13 | ) 14 | 15 | solver.fit(mutag, evaluation_method=["acc"]) 16 | result = solver.predict(mutag) 17 | if DependentBackend.is_dgl(): 18 | print("Acc:", sum([d[1].item() == r for d, r in zip(mutag.test_split, result)]) / len(result)) 19 | else: 20 | print("Acc:", sum([d.y.item() == r for d, r in zip(mutag.test_split, result)]) / len(result)) 21 | -------------------------------------------------------------------------------- /autogl/module/hpo/grid_advisor.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.grid_search import GridSearchAlgorithm 6 | 7 | 8 | @register_hpo("grid") 9 | class GridAdvisor(AdvisorBaseHPOptimizer): 10 | """ 11 | Grid search algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = GridSearchAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/module/hpo/bayes_advisor.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.bayesian_optimization import BayesianOptimization 6 | 7 | 8 | @register_hpo("bayes") 9 | class BayesAdvisor(AdvisorBaseHPOptimizer): 10 | """ 11 | Bayes algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = BayesianOptimization() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/module/hpo/rand_advisor.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.random_search import RandomSearchAlgorithm 6 | 7 | 8 | @register_hpo("random") 9 | class RandAdvisor(AdvisorBaseHPOptimizer): 10 | """ 11 | Random search algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = RandomSearchAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /test/trainer/pyg/link_prediction.py: -------------------------------------------------------------------------------- 1 | from autogl.module.train import LinkPredictionTrainer 2 | from autogl.datasets import build_dataset_from_name 3 | from torch_geometric.utils import train_test_split_edges 4 | 5 | def test_lp_trainer(): 6 | 7 | dataset = build_dataset_from_name("cora") 8 | data = dataset[0] 9 | data = train_test_split_edges(data, 0.1, 0.1) 10 | dataset = [data] 11 | 12 | lp_trainer = LinkPredictionTrainer(model='gcn', init=False) 13 | 14 | lp_trainer.num_features = data.x.size(1) 15 | lp_trainer.initialize() 16 | print(lp_trainer.encoder.encoder) 17 | print(lp_trainer.decoder.decoder) 18 | 19 | lp_trainer.train(dataset, True) 20 | result = lp_trainer.evaluate(dataset, "test", "auc") 21 | print(result) 22 | 23 | test_lp_trainer() 24 | -------------------------------------------------------------------------------- /docs/docfile/tutorial_cn/t_backend.rst: -------------------------------------------------------------------------------- 1 | .. _backend_cn: 2 | 3 | Backend Support 4 | =============== 5 | 6 | 目前,AutoGL支持使用PyTorch-Geometric或Deep Graph Library作为后端,以便熟悉两者之一的用户均可受益于自动图学习。 7 | 8 | 为指定特定的后端,用户可以使用环境变量``AUTOGL_BACKEND``进行声明,例如: 9 | 10 | .. code-block:: python 11 | 12 | AUTOGL_BACKEND=pyg python xxx.py 13 | 14 | 或 15 | 16 | .. code-block:: python 17 | 18 | import os 19 | os.environ["AUTOGL_BACKEND"] = "pyg" 20 | import autogl 21 | 22 | ... 23 | 24 | 25 | 如果环境变量``AUTOGL_BACKEND``未声明,AutoGL会根据用户的Python运行环境中所安装的图学习库自动选择。 26 | 如果PyTorch-Geometric和Deep Graph Library均已安装,则Deep Graph Library将被作为默认的后端。 27 | 28 | 可以以编程方式获得当前使用的后端: 29 | 30 | .. code-block:: python 31 | 32 | from autogl.backend import DependentBackend 33 | print(DependentBackend.get_backend_name()) 34 | -------------------------------------------------------------------------------- /examples/hetero_node_classification.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ["AUTOGL_BACKEND"] = 'dgl' 3 | 4 | from autogl.datasets import build_dataset_from_name 5 | from autogl.solver import AutoHeteroNodeClassifier 6 | import argparse 7 | 8 | if __name__ == '__main__': 9 | 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument("--model", type=str, default = "han", choices=["han", "hgt"]) 12 | parser.add_argument("--max_evals", type=int, default=10) 13 | 14 | args = parser.parse_args() 15 | 16 | dataset = build_dataset_from_name(f"hetero-acm-{args.model}") 17 | solver = AutoHeteroNodeClassifier( 18 | graph_models=(args.model, ), 19 | max_evals=10 20 | ) 21 | solver.fit(dataset) 22 | acc = solver.evaluate(metric='acc') 23 | 24 | print("acc: ", acc) 25 | -------------------------------------------------------------------------------- /autogl/module/hpo/anneal_advisorhpo.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.simulate_anneal import SimulateAnnealAlgorithm 6 | 7 | 8 | @register_hpo("anneal") 9 | class AnnealAdvisorHPO(AdvisorBaseHPOptimizer): 10 | """ 11 | Simulate anneal algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = SimulateAnnealAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /test/performance/link_prediction/pyg/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gat', decoder='lpdecoder'): 2 | if model == 'gat': 3 | model_hp = { 4 | "num_layers": 2, 5 | "hidden": [16, 16], 6 | "dropout": 0.0, 7 | "act": "relu", 8 | "num_hidden_heads": 8, 9 | "num_output_heads": 8 10 | } 11 | elif model == 'gcn': 12 | model_hp = { 13 | "hidden": [128, 64], 14 | "dropout": 0.0, 15 | "act": "relu" 16 | } 17 | elif model == 'sage': 18 | model_hp = { 19 | "num_layers": 3, 20 | "hidden": [128,64], 21 | "dropout": 0.0, 22 | "act": "relu", 23 | "agg": "mean" 24 | } 25 | 26 | return model_hp, {} 27 | -------------------------------------------------------------------------------- /autogl/module/hpo/quasi_advisorchoco.py: -------------------------------------------------------------------------------- 1 | import hyperopt 2 | 3 | from . import register_hpo 4 | from .advisorbase import AdvisorBaseHPOptimizer 5 | from .suggestion.algorithm.quasi_random_search import QuasiRandomSearchAlgorithm 6 | 7 | 8 | @register_hpo("quasi") 9 | class QuasiAdvisorChoco(AdvisorBaseHPOptimizer): 10 | """ 11 | Quasi random search algorithm in `advisor` package 12 | See https://github.com/tobegit3hub/advisor for the package 13 | See .advisorbase.AdvisorBaseHPOptimizer for more information 14 | """ 15 | 16 | def __init__(self, *args, **kwargs): 17 | super().__init__(*args, **kwargs) 18 | self.method = QuasiRandomSearchAlgorithm() 19 | 20 | @classmethod 21 | def build_hpo_from_args(cls, args): 22 | """Build a new hpo instance.""" 23 | return cls(args) 24 | -------------------------------------------------------------------------------- /autogl/solver/classifier/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Auto classifier for classification problems. 3 | """ 4 | 5 | from .base import BaseClassifier 6 | from .graph_classifier import AutoGraphClassifier 7 | from .node_classifier import AutoNodeClassifier 8 | from .link_predictor import AutoLinkPredictor 9 | from autogl.backend import DependentBackend 10 | if DependentBackend.is_dgl(): 11 | from .hetero import AutoHeteroNodeClassifier 12 | if DependentBackend.is_pyg(): 13 | from .ssl import SSLGraphClassifier 14 | 15 | __all__ = [ 16 | "BaseClassifier", 17 | "AutoGraphClassifier", 18 | "AutoNodeClassifier", 19 | "AutoLinkPredictor", 20 | ] 21 | 22 | if DependentBackend.is_dgl(): 23 | __all__.extend(['AutoHeteroNodeClassifier']) 24 | 25 | if DependentBackend.is_pyg(): 26 | __all__.extend(['SSLGraphClassifier']) 27 | -------------------------------------------------------------------------------- /test/trainer/pyg/graph_classification.py: -------------------------------------------------------------------------------- 1 | from autogl.module.train import GraphClassificationFullTrainer 2 | from autogl.datasets import build_dataset_from_name, utils 3 | 4 | def test_graph_trainer(): 5 | 6 | dataset = build_dataset_from_name("mutag") 7 | utils.graph_random_splits(dataset, 0.8, 0.1) 8 | 9 | lp_trainer = GraphClassificationFullTrainer(model='gin', init=False) 10 | 11 | lp_trainer.num_features = dataset[0].x.size(1) 12 | lp_trainer.num_classes = max([d.y for d in dataset]).item() + 1 13 | lp_trainer.num_graph_features = 0 14 | lp_trainer.initialize() 15 | 16 | print(lp_trainer.encoder.encoder) 17 | print(lp_trainer.decoder.decoder) 18 | 19 | lp_trainer.train(dataset, True) 20 | result = lp_trainer.evaluate(dataset, "test", "acc") 21 | print("Acc:", result) 22 | 23 | test_graph_trainer() 24 | -------------------------------------------------------------------------------- /test/preprocessing/structure.py: -------------------------------------------------------------------------------- 1 | envs='dgl pyg'.split() 2 | forbids=dict(zip(envs,"torch_geometric dgl".split())) 3 | 4 | from utils import * 5 | def func(dev,env): 6 | import os 7 | import sys 8 | sys.modules[forbids[env]]=None 9 | os.environ['AUTOGL_BACKEND']=env 10 | from autogl.backend import DependentBackend 11 | print('using backend :',DependentBackend.get_backend_name()) 12 | from autogl.datasets import build_dataset_from_name 13 | data = build_dataset_from_name('cora') 14 | from autogl.module.preprocessing.structure_engineering import GCNJaccard,GCNSVD 15 | 16 | fes=[GCNJaccard,GCNSVD] 17 | for fe in fes: 18 | print(f'Doing {fe}') 19 | fe = fe() 20 | data=fe.fit_transform(data,inplace=False) 21 | 22 | return 'Test OK' 23 | 24 | results=mp_exec([0,1],envs,func) 25 | print(results) 26 | 27 | 28 | -------------------------------------------------------------------------------- /autogl/module/model/pyg/__init__.py: -------------------------------------------------------------------------------- 1 | from ._model_registry import MODEL_DICT, ModelUniversalRegistry, register_model 2 | from .base import BaseAutoModel 3 | from .topkpool import AutoTopkpool 4 | 5 | # from .graph_sage import AutoSAGE 6 | from .graphsage import AutoSAGE 7 | from .graph_saint import GraphSAINTAggregationModel 8 | from .gcn import AutoGCN 9 | from .gat import AutoGAT 10 | from .gin import AutoGIN 11 | 12 | from .robust.gnnguard import AutoGNNGuard, AutoGNNGuard_attack, GCN4GNNGuard, GCN4GNNGuard_attack 13 | 14 | __all__ = [ 15 | "ModelUniversalRegistry", 16 | "register_model", 17 | "BaseAutoModel", 18 | "AutoTopkpool", 19 | "AutoSAGE", 20 | "GraphSAINTAggregationModel", 21 | "AutoGCN", 22 | "AutoGAT", 23 | "AutoGIN", 24 | "AutoGNNGuard", 25 | "AutoGNNGuard_attack", 26 | "GCN4GNNGuard", 27 | "GCN4GNNGuard_attack", 28 | ] 29 | -------------------------------------------------------------------------------- /configs/nodeclf_nas_gasso.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | name: null 7 | nas: 8 | space: 9 | name: gassospace 10 | hidden_dim: 64 11 | layer_number: 2 12 | algorithm: 13 | name: gasso 14 | num_epochs: 250 15 | estimator: 16 | name: oneshot 17 | models: [] 18 | trainer: 19 | hp_space: 20 | - maxValue: 300 21 | minValue: 100 22 | parameterName: max_epoch 23 | scalingType: LINEAR 24 | type: INTEGER 25 | - maxValue: 30 26 | minValue: 10 27 | parameterName: early_stopping_round 28 | scalingType: LINEAR 29 | type: INTEGER 30 | - maxValue: 0.05 31 | minValue: 0.01 32 | parameterName: lr 33 | scalingType: LOG 34 | type: DOUBLE 35 | - maxValue: 0.0005 36 | minValue: 5.0e-05 37 | parameterName: weight_decay 38 | scalingType: LOG 39 | type: DOUBLE 40 | -------------------------------------------------------------------------------- /autogl/module/model/dgl/__init__.py: -------------------------------------------------------------------------------- 1 | from ._model_registry import MODEL_DICT, ModelUniversalRegistry, register_model 2 | from .base import BaseAutoModel 3 | from .topkpool import AutoTopkpool 4 | 5 | 6 | # from .graph_saint import GraphSAINTAggregationModel 7 | from .gcn import GCN, AutoGCN 8 | from .graphsage import GraphSAGE, AutoSAGE 9 | from .gat import GAT,AutoGAT 10 | from .gin import AutoGIN 11 | from .hetero.hgt import AutoHGT 12 | from .hetero.han import AutoHAN 13 | from .hetero.HeteroRGCN import AutoHeteroRGCN 14 | 15 | __all__ = [ 16 | "ModelUniversalRegistry", 17 | "register_model", 18 | "BaseAutoModel", 19 | "AutoTopkpool", 20 | # "GraphSAINTAggregationModel", 21 | "GCN", 22 | "AutoGCN", 23 | "GraphSAGE", 24 | "AutoSAGE", 25 | "GAT", 26 | "AutoGAT", 27 | "AutoGIN", 28 | "AutoHGT", 29 | "AutoHAN", 30 | "AutoHeteroRGCN", 31 | ] 32 | -------------------------------------------------------------------------------- /autogl/module/nas/space/operation.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch import nn 3 | import torch.nn.functional as F 4 | def act_map(act): 5 | if act == "linear": 6 | return lambda x: x 7 | elif act == "elu": 8 | return F.elu 9 | elif act == "sigmoid": 10 | return torch.sigmoid 11 | elif act == "tanh": 12 | return torch.tanh 13 | elif act == "relu": 14 | return torch.nn.functional.relu 15 | elif act == "relu6": 16 | return torch.nn.functional.relu6 17 | elif act == "softplus": 18 | return torch.nn.functional.softplus 19 | elif act == "leaky_relu": 20 | return torch.nn.functional.leaky_relu 21 | else: 22 | raise Exception("wrong activate function") 23 | 24 | from ..backend import * 25 | if is_dgl(): 26 | from .operation_dgl import gnn_map,GeoLayer 27 | else: 28 | from .operation_pyg import gnn_map,GeoLayer -------------------------------------------------------------------------------- /examples/gasso_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ["AUTOGL_BACKEND"] = "pyg" 3 | import sys 4 | sys.path.append('../') 5 | from autogl.datasets import build_dataset_from_name 6 | from autogl.solver import AutoNodeClassifier 7 | from autogl.module.train import Acc 8 | from autogl.solver.utils import set_seed 9 | import argparse 10 | 11 | if __name__ == '__main__': 12 | set_seed(202106) 13 | parser = argparse.ArgumentParser() 14 | parser.add_argument('--config', type=str, default='../configs/nodeclf_nas_gasso.yml') 15 | parser.add_argument('--dataset', choices=['cora', 'citeseer', 'pubmed'], default='citeseer', type=str) 16 | 17 | args = parser.parse_args() 18 | 19 | dataset = build_dataset_from_name(args.dataset) 20 | solver = AutoNodeClassifier.from_config(args.config) 21 | solver.fit(dataset) 22 | solver.get_leaderboard().show() 23 | print('acc on dataset', solver.evaluate()) 24 | -------------------------------------------------------------------------------- /test/trainer/pyg/node_classification.py: -------------------------------------------------------------------------------- 1 | from autogl.module.train import NodeClassificationFullTrainer 2 | from autogl.datasets import build_dataset_from_name 3 | 4 | def test_node_trainer(): 5 | 6 | dataset = build_dataset_from_name("cora") 7 | 8 | node_trainer = NodeClassificationFullTrainer( 9 | model='gcn', 10 | init=False, 11 | lr=1e-2, 12 | weight_decay=5e-4, 13 | max_epoch=200, 14 | early_stopping_round=200, 15 | ) 16 | 17 | node_trainer.num_features = dataset[0].x.size(1) 18 | node_trainer.num_classes = dataset[0].y.max().item() + 1 19 | node_trainer.initialize() 20 | 21 | print(node_trainer.encoder.encoder) 22 | print(node_trainer.decoder.decoder) 23 | 24 | node_trainer.train(dataset, True) 25 | result = node_trainer.evaluate(dataset, "test", "acc") 26 | print("Acc:", result) 27 | 28 | test_node_trainer() 29 | -------------------------------------------------------------------------------- /examples/quickstart.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | import autogl 3 | from autogl.datasets import build_dataset_from_name 4 | cora_dataset = build_dataset_from_name('cora') 5 | 6 | import torch 7 | device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') 8 | from autogl.solver import AutoNodeClassifier 9 | solver = AutoNodeClassifier( 10 | feature_module='deepgl', 11 | graph_models=['gcn', 'gat'], 12 | hpo_module='anneal', 13 | ensemble_module='voting', 14 | device=device 15 | ) 16 | 17 | solver.fit(cora_dataset, time_limit=30) 18 | solver.get_leaderboard().show() 19 | 20 | from autogl.module.train import Acc 21 | from autogl.solver.utils import get_graph_labels, get_graph_masks 22 | 23 | predicted = solver.predict_proba() 24 | label = get_graph_labels(cora_dataset[0])[get_graph_masks(cora_dataset[0], 'test')].cpu().numpy() 25 | print('Test accuracy: ', Acc.evaluate(predicted, label)) 26 | -------------------------------------------------------------------------------- /configs/nodeclf_nas_macro_benchmark2.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | nas: 9 | space: 10 | name: singlepath 11 | hidden_dim: 64 12 | layer_number: 2 13 | algorithm: 14 | name: enas 15 | num_epochs: 200 16 | estimator: 17 | name: oneshot 18 | models: [] 19 | trainer: 20 | hp_space: 21 | - maxValue: 300 22 | minValue: 100 23 | parameterName: max_epoch 24 | scalingType: LINEAR 25 | type: INTEGER 26 | - maxValue: 30 27 | minValue: 10 28 | parameterName: early_stopping_round 29 | scalingType: LINEAR 30 | type: INTEGER 31 | - maxValue: 0.05 32 | minValue: 0.01 33 | parameterName: lr 34 | scalingType: LOG 35 | type: DOUBLE 36 | - maxValue: 0.0005 37 | minValue: 5.0e-05 38 | parameterName: weight_decay 39 | scalingType: LOG 40 | type: DOUBLE 41 | -------------------------------------------------------------------------------- /configs/nodeclf_nas_macro_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | nas: 9 | space: 10 | name: graphnas 11 | hidden_dim: 64 12 | layer_number: 2 13 | algorithm: 14 | name: rl 15 | num_epochs: 200 16 | estimator: 17 | name: scratch_hardware 18 | models: [] 19 | trainer: 20 | hp_space: 21 | - maxValue: 300 22 | minValue: 100 23 | parameterName: max_epoch 24 | scalingType: LINEAR 25 | type: INTEGER 26 | - maxValue: 30 27 | minValue: 10 28 | parameterName: early_stopping_round 29 | scalingType: LINEAR 30 | type: INTEGER 31 | - maxValue: 0.05 32 | minValue: 0.01 33 | parameterName: lr 34 | scalingType: LOG 35 | type: DOUBLE 36 | - maxValue: 0.0005 37 | minValue: 5.0e-05 38 | parameterName: weight_decay 39 | scalingType: LOG 40 | type: DOUBLE 41 | -------------------------------------------------------------------------------- /autogl/utils/device.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from typing import Union 3 | 4 | 5 | def get_device(device: Union[str, torch.device]): 6 | """ 7 | Get device of passed argument. Will return a torch.device based on passed arguments. 8 | Can parse auto, cpu, gpu, cpu:x, gpu:x, etc. If auto is given, will automatically find 9 | available devices. 10 | 11 | 12 | Parameters 13 | ---------- 14 | device: ``str`` or ``torch.device`` 15 | The device to parse. If ``auto`` if given, will determine automatically. 16 | 17 | Returns 18 | ------- 19 | device: ``torch.device`` 20 | The parsed device. 21 | """ 22 | assert isinstance( 23 | device, (str, torch.device) 24 | ), "Only support device of str or torch.device, get {} instead".format(device) 25 | if device == "auto": 26 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 27 | return torch.device(device) 28 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | pyg: 18 | @AUTOGL_BACKEND=pyg $(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 19 | 20 | dgl: 21 | @AUTOGL_BACKEND=dgl $(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | 23 | html: Makefile pyg dgl 24 | 25 | # Catch-all target: route all unknown targets to Sphinx using the new 26 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 27 | %: Makefile 28 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 29 | -------------------------------------------------------------------------------- /autogl/module/_feature/graph/netlsd.py: -------------------------------------------------------------------------------- 1 | import netlsd 2 | from .base import BaseGraph 3 | import numpy as np 4 | import torch 5 | from .. import register_feature 6 | 7 | 8 | @register_feature("netlsd") 9 | class SgNetLSD(BaseGraph): 10 | r""" 11 | Notes 12 | ----- 13 | a graph feature generation method. This is a simple wrapper of NetLSD [#]_. 14 | References 15 | ---------- 16 | .. [#] A. Tsitsulin, D. Mottin, P. Karras, A. Bronstein, and E. Müller, “NetLSD: Hearing the shape of a graph,” 17 | Proc. ACM SIGKDD Int. Conf. Knowl. Discov. Data Min., pp. 2347–2356, 2018. 18 | """ 19 | 20 | def __init__(self, *args, **kwargs): 21 | super(SgNetLSD, self).__init__(data_t="nx") 22 | self._args = args 23 | self._kwargs = kwargs 24 | 25 | def _transform(self, data): 26 | dsc = torch.FloatTensor([netlsd.heat(data.G, *self._args, **self._kwargs)]) 27 | data.gf = torch.cat([data.gf, dsc], dim=1) 28 | return data 29 | -------------------------------------------------------------------------------- /examples/graphnas.py: -------------------------------------------------------------------------------- 1 | from autogl.datasets import build_dataset_from_name 2 | from autogl.solver import AutoNodeClassifier 3 | from autogl.solver.utils import set_seed 4 | import argparse 5 | from autogl.backend import DependentBackend 6 | 7 | if __name__ == '__main__': 8 | set_seed(202106) 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument('--config', type=str, default='../configs/nodeclf_nas_macro_benchmark2.yml') 11 | parser.add_argument('--dataset', choices=['cora', 'citeseer', 'pubmed'], default='cora', type=str) 12 | 13 | args = parser.parse_args() 14 | 15 | dataset = build_dataset_from_name(args.dataset) 16 | if DependentBackend.is_pyg(): 17 | label = dataset[0].y 18 | else: 19 | label = dataset[0].ndata['label'] 20 | solver = AutoNodeClassifier.from_config(args.config) 21 | solver.fit(dataset) 22 | solver.get_leaderboard().show() 23 | acc = solver.evaluate(metric="acc") 24 | print('acc on dataset', acc) 25 | -------------------------------------------------------------------------------- /autogl/module/model/encoders/__init__.py: -------------------------------------------------------------------------------- 1 | from .base_encoder import BaseEncoderMaintainer, AutoHomogeneousEncoderMaintainer 2 | from .encoder_registry import EncoderUniversalRegistry 3 | from autogl.backend import DependentBackend 4 | 5 | if DependentBackend.is_pyg(): 6 | from ._pyg import ( 7 | GCNEncoderMaintainer, 8 | GATEncoderMaintainer, 9 | GINEncoderMaintainer, 10 | SAGEEncoderMaintainer 11 | ) 12 | else: 13 | from ._dgl import ( 14 | GCNEncoderMaintainer, 15 | GATEncoderMaintainer, 16 | GINEncoderMaintainer, 17 | SAGEEncoderMaintainer, 18 | AutoTopKMaintainer 19 | ) 20 | 21 | __all__ = [ 22 | "BaseEncoderMaintainer", 23 | "EncoderUniversalRegistry", 24 | "AutoHomogeneousEncoderMaintainer", 25 | "GCNEncoderMaintainer", 26 | "GATEncoderMaintainer", 27 | "GINEncoderMaintainer", 28 | "SAGEEncoderMaintainer", 29 | ] 30 | 31 | if DependentBackend.is_dgl(): 32 | __all__.append("AutoTopKMaintainer") 33 | -------------------------------------------------------------------------------- /configs/nodeclf_nas_autoattend_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | nas: 9 | space: 10 | name: autoattend 11 | hidden_dim: 64 12 | layer_number: 2 13 | dropout: 0.7 14 | algorithm: 15 | name: spos 16 | n_warmup: 2000 #2000 17 | population_size: 500 18 | cycles: 50 #5 19 | sample_size: 100 20 | estimator: 21 | name: oneshot 22 | models: [] 23 | trainer: 24 | hp_space: 25 | - maxValue: 300 26 | minValue: 100 27 | parameterName: max_epoch 28 | scalingType: LINEAR 29 | type: INTEGER 30 | - maxValue: 30 31 | minValue: 10 32 | parameterName: early_stopping_round 33 | scalingType: LINEAR 34 | type: INTEGER 35 | - maxValue: 0.05 36 | minValue: 0.01 37 | parameterName: lr 38 | scalingType: LOG 39 | type: DOUBLE 40 | - maxValue: 0.0005 41 | minValue: 5.0e-05 42 | parameterName: weight_decay 43 | scalingType: LOG 44 | type: DOUBLE 45 | -------------------------------------------------------------------------------- /docs/docfile/tutorial/t_backend.rst: -------------------------------------------------------------------------------- 1 | .. _backend: 2 | 3 | Backend Support 4 | =============== 5 | 6 | Currently, AutoGL support both pytorch geometric backend and deep graph library backend to 7 | enable users from both end benifiting the automation of graph learning. 8 | 9 | To specify one specific backend, you can declare the backend using environment variables 10 | ``AUTOGL_BACKEND``. For example: 11 | 12 | .. code-block:: python 13 | 14 | AUTOGL_BACKEND=pyg python xxx.py 15 | 16 | or 17 | 18 | .. code-block:: python 19 | 20 | import os 21 | os.environ["AUTOGL_BACKEND"] = "pyg" 22 | import autogl 23 | 24 | ... 25 | 26 | 27 | If no backend is specified, AutoGL will use the backend in your environment. If you have both 28 | Deep Graph Library and PyTorch Geometric installed, the default backend will be Deep Graph Library. 29 | 30 | You can also get current backend in the code by: 31 | 32 | .. code-block :: python 33 | 34 | from autogl.backend import DependentBackend 35 | print(DependentBackend.get_backend_name()) 36 | -------------------------------------------------------------------------------- /autogl/module/_feature/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | 4 | 5 | def data_is_tensor(data): 6 | return isinstance(data.x, torch.Tensor) 7 | 8 | 9 | def data_is_numpy(data): 10 | return isinstance(data.x, np.ndarray) 11 | 12 | 13 | def data_tensor2np(data): 14 | if data_is_tensor(data): 15 | data.x = data.x.numpy() 16 | data.y = data.y.numpy() 17 | data.edge_index = data.edge_index.numpy() 18 | return data 19 | 20 | 21 | def data_np2tensor(data): 22 | if not data_is_tensor(data): 23 | if data_is_numpy(data): 24 | data.x = torch.FloatTensor(data.x) 25 | data.y = torch.tensor(data.y) 26 | data.edge_index = torch.tensor(data.edge_index, dtype=torch.long) 27 | return data 28 | 29 | 30 | # from .base import BaseFeatureAtom 31 | # class DataTensor2Np(BaseFeatureAtom): 32 | # def __call__(self,data): 33 | # return data_tensor2np(data) 34 | # class DataNp2Tensor(BaseFeatureAtom): 35 | # def __call__(self,data): 36 | # return data_np2tensor(data) 37 | -------------------------------------------------------------------------------- /autogl/module/model/dgl/_model_registry.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from .base import BaseAutoModel 3 | 4 | MODEL_DICT: _typing.Dict[str, _typing.Type[BaseAutoModel]] = {} 5 | 6 | 7 | def register_model(name): 8 | def register_model_cls(cls): 9 | if name in MODEL_DICT: 10 | raise ValueError("Cannot register duplicate trainer ({})".format(name)) 11 | if not issubclass(cls, BaseAutoModel): 12 | raise ValueError( 13 | "Trainer ({}: {}) must extend BaseModel".format(name, cls.__name__) 14 | ) 15 | MODEL_DICT[name] = cls 16 | return cls 17 | 18 | return register_model_cls 19 | 20 | 21 | class ModelUniversalRegistry: 22 | @classmethod 23 | def get_model(cls, name: str) -> _typing.Type[BaseAutoModel]: 24 | if type(name) != str: 25 | raise TypeError(f"Expect model type str, but get {type(name)}.") 26 | if name not in MODEL_DICT: 27 | raise KeyError(f"Do not support {name} model in pyg backend") 28 | return MODEL_DICT.get(name) 29 | -------------------------------------------------------------------------------- /autogl/module/model/pyg/_model_registry.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from .base import BaseAutoModel 3 | 4 | MODEL_DICT: _typing.Dict[str, _typing.Type[BaseAutoModel]] = {} 5 | 6 | 7 | def register_model(name): 8 | def register_model_cls(cls): 9 | if name in MODEL_DICT: 10 | raise ValueError("Cannot register duplicate trainer ({})".format(name)) 11 | if not issubclass(cls, BaseAutoModel): 12 | raise ValueError( 13 | "Trainer ({}: {}) must extend BaseModel".format(name, cls.__name__) 14 | ) 15 | MODEL_DICT[name] = cls 16 | return cls 17 | 18 | return register_model_cls 19 | 20 | 21 | class ModelUniversalRegistry: 22 | @classmethod 23 | def get_model(cls, name: str) -> _typing.Type[BaseAutoModel]: 24 | if type(name) != str: 25 | raise TypeError(f"Expect model type str, but get {type(name)}.") 26 | if name not in MODEL_DICT: 27 | raise KeyError(f"Do not support {name} model in pyg backend") 28 | return MODEL_DICT.get(name) 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: general502570 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment (please complete the following information):** 27 | - OS: [e.g. Windows 10] 28 | - python version: [The output of cmd `python -V`] 29 | - autogl version: [The output of cmd `python -c 'import autogl; print(autogl.__version__)'`] 30 | - pip list: [the output of cmd `pip list`] 31 | 32 | **Additional Info (Optional)** 33 | Add any other context about the problem here. Such as the possible reason you think, or how to solve this bug if you are interested. 34 | -------------------------------------------------------------------------------- /autogl/module/_feature/generators/page_rank.py: -------------------------------------------------------------------------------- 1 | from scipy.sparse import csr_matrix 2 | import scipy.sparse as ssp 3 | import networkx as nx 4 | import numpy as np 5 | 6 | # @register_feature('pagerank') 7 | from .base import BaseGenerator 8 | from .. import register_feature 9 | 10 | 11 | @register_feature("pagerank") 12 | class GePageRank(BaseGenerator): 13 | r"""concat pagerank features""" 14 | 15 | def _transform(self, data): 16 | graph = nx.DiGraph() 17 | w = data.edge_weight 18 | eg = [(u, v, w[i]) for i, (u, v) in enumerate(data.edge_index.T)] 19 | graph.add_weighted_edges_from(eg) 20 | pagerank = nx.pagerank(graph) 21 | pr = np.zeros((data.x.shape[0], 1)) 22 | for i, v in pagerank.items(): 23 | pr[i] = v 24 | data.x = np.concatenate([data.x, pr], axis=1) 25 | return data 26 | 27 | def _preprocess(self, data): 28 | if not hasattr(data, "edge_weight"): 29 | data.edge_weight = np.ones(data.edge_index.shape[1]) 30 | 31 | def _postprocess(self, data): 32 | del data.edge_weight 33 | -------------------------------------------------------------------------------- /autogl/data/_dataset/_in_memory_static_graph_set.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from ._dataset import InMemoryDataset 3 | from ..graph import GeneralStaticGraph 4 | 5 | 6 | class InMemoryStaticGraphSet(InMemoryDataset[GeneralStaticGraph]): 7 | def __init__( 8 | self, graphs: _typing.Iterable[GeneralStaticGraph], 9 | train_index: _typing.Optional[_typing.Iterable[int]] = ..., 10 | val_index: _typing.Optional[_typing.Iterable[int]] = ..., 11 | test_index: _typing.Optional[_typing.Iterable[int]] = ... 12 | ): 13 | super(InMemoryStaticGraphSet, self).__init__( 14 | graphs, train_index, val_index, test_index 15 | ) 16 | 17 | def __iter__(self) -> _typing.Iterator[GeneralStaticGraph]: 18 | return super(InMemoryStaticGraphSet, self).__iter__() 19 | 20 | def __getitem__(self, index: int) -> GeneralStaticGraph: 21 | return super(InMemoryStaticGraphSet, self).__getitem__(index) 22 | 23 | def __setitem__(self, index: int, data: GeneralStaticGraph): 24 | super(InMemoryStaticGraphSet, self).__setitem__(index, data) 25 | -------------------------------------------------------------------------------- /autogl/data/download.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os.path as osp 4 | from six.moves import urllib 5 | 6 | from .makedirs import makedirs 7 | 8 | 9 | def download_url(url, folder, name=None, log=True): 10 | r"""Downloads the content of an URL to a specific folder. 11 | 12 | Args: 13 | url (string): The url. 14 | folder (string): The folder. 15 | log (bool, optional): If :obj:`False`, will not print anything to the 16 | console. (default: :obj:`True`) 17 | """ 18 | 19 | data = urllib.request.urlopen(url) 20 | if name is None: 21 | filename = url.rpartition("/")[2] 22 | else: 23 | filename = name 24 | path = osp.join(folder, filename) 25 | 26 | if osp.exists(path): # pragma: no cover 27 | if log: 28 | print("Using exist file", filename) 29 | return path 30 | 31 | if log: 32 | print("Downloading", url) 33 | 34 | makedirs(folder) 35 | data = urllib.request.urlopen(url) 36 | 37 | with open(path, "wb") as f: 38 | f.write(data.read()) 39 | 40 | return path 41 | -------------------------------------------------------------------------------- /autogl/module/model/decoders/__init__.py: -------------------------------------------------------------------------------- 1 | from .base_decoder import BaseDecoderMaintainer 2 | from .decoder_registry import DecoderUniversalRegistry 3 | from autogl.backend import DependentBackend 4 | 5 | if DependentBackend.is_pyg(): 6 | from ._pyg import ( 7 | LogSoftmaxDecoderMaintainer, 8 | SumPoolMLPDecoderMaintainer, 9 | DiffPoolDecoderMaintainer, 10 | DotProductLinkPredictionDecoderMaintainer 11 | ) 12 | else: 13 | from ._dgl import ( 14 | LogSoftmaxDecoderMaintainer, 15 | JKSumPoolDecoderMaintainer, 16 | TopKDecoderMaintainer, 17 | DotProductLinkPredictionDecoderMaintainer 18 | ) 19 | 20 | __all__ = [ 21 | "BaseDecoderMaintainer", 22 | "DecoderUniversalRegistry", 23 | "LogSoftmaxDecoderMaintainer", 24 | "DotProductLinkPredictionDecoderMaintainer" 25 | ] 26 | 27 | if DependentBackend.is_pyg(): 28 | __all__.extend([ 29 | "DiffPoolDecoderMaintainer", 30 | "SumPoolMLPDecoderMaintainer" 31 | ]) 32 | else: 33 | __all__.extend([ 34 | "JKSumPoolDecoderMaintainer", 35 | "TopKDecoderMaintainer" 36 | ]) 37 | -------------------------------------------------------------------------------- /test/solver/node_classification.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ["AUTOGL_BACKEND"] = "dgl" 3 | 4 | from autogl.datasets import build_dataset_from_name 5 | from autogl.solver import AutoNodeClassifier 6 | from autogl.module.train import NodeClassificationFullTrainer 7 | from autogl.backend import DependentBackend 8 | 9 | key = "y" if DependentBackend.is_pyg() else "label" 10 | 11 | cora = build_dataset_from_name("cora") 12 | # print(cora.__class__) 13 | 14 | solver = AutoNodeClassifier( 15 | graph_models=("gcn",), 16 | default_trainer=NodeClassificationFullTrainer( 17 | decoder=None, 18 | init=False, 19 | max_epoch=200, 20 | early_stopping_round=201, 21 | lr=0.01, 22 | weight_decay=0.0, 23 | ), 24 | hpo_module=None, 25 | device="auto" 26 | ) 27 | 28 | solver.fit(cora, evaluation_method=["acc"]) 29 | result = solver.predict(cora) 30 | if DependentBackend.is_pyg(): 31 | print((result == cora[0].y[cora[0].test_mask].cpu().numpy()).astype('float').mean()) 32 | else: 33 | print((result == cora[0].ndata['label'][cora[0].ndata['test_mask']].cpu().numpy()).astype('float').mean()) 34 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/structure_engineering/_structure_engineer.py: -------------------------------------------------------------------------------- 1 | from .. import _data_preprocessor 2 | class StructureEngineer(_data_preprocessor.DataPreprocessor): 3 | ... 4 | 5 | import torch 6 | from ....utils import get_logger 7 | LOGGER = get_logger("Structure") 8 | 9 | def get_feature(data): 10 | """return features : numpy.ndarray 11 | """ 12 | for fk in 'x feat'.split(): 13 | if fk in data.nodes.data: 14 | features=data.nodes.data[fk].numpy() 15 | return features 16 | 17 | def get_edges(data): 18 | return data.edges.connections 19 | 20 | def set_edges(data,adj): 21 | data.data["edge_index"]=adj 22 | 23 | def to_adjacency_matrix(adj): 24 | """ 25 | adj : torch.Tensor [2,E] 26 | return Tensor [N,N] 27 | """ 28 | num_nodes=adj.max().item()+1 29 | mat = torch.zeros((num_nodes,num_nodes), dtype=bool) 30 | mat[tuple(adj)]=1 31 | return mat 32 | 33 | def to_adjacency_list(adj): 34 | """ 35 | adj : Tensor [N,N] 36 | return Tensor [2,E] 37 | """ 38 | adj = torch.stack(adj.nonzero(as_tuple=True)).long() # edge list 39 | return adj 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/performance/link_prediction/dgl/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gin', decoder=None, decoupled=True): 2 | if model == 'gat': 3 | if decoupled: 4 | model_hp = { 5 | "num_layers": 3, 6 | "hidden": [8, 8], 7 | "num_hidden_heads": 8, 8 | "num_output_heads": 8, 9 | "dropout": 0.0, 10 | "act": "relu" 11 | } 12 | else: 13 | model_hp = { 14 | "num_layers": 3, 15 | "hidden": [8, 8], 16 | "heads": 8, 17 | "dropout": 0.0, 18 | "act": "relu" 19 | } 20 | elif model == 'gcn': 21 | model_hp = { 22 | "num_layers": 3, 23 | "hidden": [16, 16], 24 | "dropout": 0., 25 | "act": "relu", 26 | } 27 | elif model == 'sage': 28 | model_hp = { 29 | 'num_layers': 3, 30 | 'hidden': [16, 16], 31 | 'dropout': 0.0, 32 | 'act': 'relu', 33 | 'agg': 'mean' 34 | } 35 | 36 | return model_hp, {} 37 | -------------------------------------------------------------------------------- /autogl/module/feature/_generators/_page_rank.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import networkx as nx 3 | import torch 4 | import autogl 5 | from ._basic import BaseFeatureGenerator 6 | from .._feature_engineer_registry import FeatureEngineerUniversalRegistry 7 | 8 | 9 | @FeatureEngineerUniversalRegistry.register_feature_engineer("PageRank".lower()) 10 | class PageRankFeatureGenerator(BaseFeatureGenerator): 11 | def _extract_nodes_feature(self, data: autogl.data.Data) -> torch.Tensor: 12 | edge_weight = getattr(data, "edge_weight").tolist() 13 | g = nx.DiGraph() 14 | g.add_weighted_edges_from( 15 | [ 16 | (u, v, edge_weight[i]) 17 | for i, (u, v) in enumerate(data.edge_index.t().tolist()) 18 | ] 19 | ) 20 | page_rank = nx.pagerank(g) 21 | num_nodes: int = ( 22 | data.x.size(0) 23 | if data.x is not None and isinstance(data.x, torch.Tensor) 24 | else (data.edge_index.max().item() + 1) 25 | ) 26 | pr = np.zeros(num_nodes) 27 | for i, v in page_rank.items(): 28 | pr[i] = v 29 | return torch.from_numpy(pr) 30 | -------------------------------------------------------------------------------- /autogl/module/model/decoders/decoder_registry.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from autogl.utils import universal_registry 3 | from . import base_decoder 4 | 5 | 6 | class DecoderUniversalRegistry(universal_registry.UniversalRegistryBase): 7 | @classmethod 8 | def register_decoder(cls, name: str) -> _typing.Callable[ 9 | [_typing.Type[base_decoder.BaseDecoderMaintainer]], 10 | _typing.Type[base_decoder.BaseDecoderMaintainer] 11 | ]: 12 | def register_decoder( 13 | _decoder: _typing.Type[base_decoder.BaseDecoderMaintainer] 14 | ) -> _typing.Type[base_decoder.BaseDecoderMaintainer]: 15 | if not issubclass(_decoder, base_decoder.BaseDecoderMaintainer): 16 | raise TypeError 17 | else: 18 | cls[name] = _decoder 19 | return _decoder 20 | 21 | return register_decoder 22 | 23 | @classmethod 24 | def get_decoder(cls, name: str) -> _typing.Type[base_decoder.BaseDecoderMaintainer]: 25 | if name not in cls: 26 | raise ValueError(f"Decoder with name \"{name}\" not exist") 27 | else: 28 | return cls[name] 29 | -------------------------------------------------------------------------------- /autogl/module/model/encoders/encoder_registry.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from autogl.utils import universal_registry 3 | from . import base_encoder 4 | 5 | 6 | class EncoderUniversalRegistry(universal_registry.UniversalRegistryBase): 7 | @classmethod 8 | def register_encoder(cls, name: str) -> _typing.Callable[ 9 | [_typing.Type[base_encoder.BaseEncoderMaintainer]], 10 | _typing.Type[base_encoder.BaseEncoderMaintainer] 11 | ]: 12 | def register_encoder( 13 | _encoder: _typing.Type[base_encoder.BaseEncoderMaintainer] 14 | ) -> _typing.Type[base_encoder.BaseEncoderMaintainer]: 15 | if not issubclass(_encoder, base_encoder.BaseEncoderMaintainer): 16 | raise TypeError 17 | else: 18 | cls[name] = _encoder 19 | return _encoder 20 | 21 | return register_encoder 22 | 23 | @classmethod 24 | def get_encoder(cls, name: str) -> _typing.Type[base_encoder.BaseEncoderMaintainer]: 25 | if name not in cls: 26 | raise ValueError(f"Encoder with name \"{name}\" not exist") 27 | else: 28 | return cls[name] 29 | -------------------------------------------------------------------------------- /test/performance/performance_check.sh: -------------------------------------------------------------------------------- 1 | # graph clf - dgl 2 | for name in "base" "model" "trainer" "trainer_dataset" "solver" 3 | do 4 | python graph_classification/dgl/$name.py --repeat 10 --dataset MUTAG > graph_classification/dgl/$name.log 2>&1 5 | done 6 | 7 | # graph clf - pyg 8 | for name in "base" "model" "trainer" "trainer_dataset" "solver" 9 | do 10 | for dataset in "MUTAG" "COLLAB" 11 | do 12 | for model in "gin" "topkpool" 13 | do 14 | python graph_classification/pyg/$name.py --repeat 10 --dataset $dataset --model $model > graph_classification/pyg/$name-$dataset-$model.log 2>&1 15 | done 16 | done 17 | done 18 | 19 | # node clf 20 | for backend in "pyg" "dgl" 21 | do 22 | for name in "base" "model" "trainer" "trainer_dataset" "solver" 23 | do 24 | for dataset in "Cora" "CiteSeer" "PubMed" 25 | do 26 | for model in "gcn" "gat" "sage" "gin" 27 | do 28 | python node_classification/$backend/$name.py --repeat 10 --dataset $dataset --model $model > node_classification/$backend/$name-$dataset-$model.log 2>&1 29 | done 30 | done 31 | done 32 | done 33 | -------------------------------------------------------------------------------- /test/preprocessing/utils.py: -------------------------------------------------------------------------------- 1 | import torch.multiprocessing as mp 2 | from queue import Queue 3 | import time 4 | import random 5 | 6 | def dummy_func(dev,cfg): 7 | time.sleep(random.random()*2) 8 | def dummy_config(): 9 | return list(range(20)) 10 | 11 | def mp_exec(resources,configs,func): 12 | ''' 13 | @ resources : list of gpu devices 14 | @ configs : list of params 15 | @ func : f(dev,cfg) 16 | ''' 17 | q=Queue() 18 | ret=Queue() 19 | for res in resources: 20 | q.put(res) 21 | pool=mp.Pool() 22 | def put_back_dev(dev,cfg): 23 | def callback(*args): 24 | print(f"Device {dev} Finish cfg {cfg} ") 25 | q.put(dev) 26 | ret.put([cfg,args]) 27 | print(*args) 28 | return callback 29 | 30 | for idx,cfg in enumerate(configs): 31 | dev = q.get() 32 | print(f"Start config {cfg} on device {dev}") 33 | pool.apply_async(func,args=[dev,cfg],callback=put_back_dev(dev,cfg),error_callback=put_back_dev(dev,cfg)) 34 | 35 | pool.close() 36 | pool.join() 37 | 38 | lret=[] 39 | while not ret.empty(): 40 | lret.append(ret.get()) 41 | return lret -------------------------------------------------------------------------------- /autogl/module/nas/space/autoattend_space/ops2.py: -------------------------------------------------------------------------------- 1 | from .operations import * 2 | OPS = { 3 | 'ZERO': lambda indim, outdim, head, dropout, concat=False: Zero(indim, outdim), 4 | 'CONST': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='const', dropout=dropout), 5 | 'GCN': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='gcn', dropout=dropout), 6 | 'GAT': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='gat', dropout=dropout), 7 | 'SYM': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='gat_sym', dropout=dropout), 8 | 'COS': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='cos', dropout=dropout), 9 | 'LIN': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='linear', dropout=dropout), 10 | 'GENE': lambda indim, outdim, head, dropout, concat=False: GeoLayer(indim, outdim, head, concat, att_type='generalized_linear', dropout=dropout) 11 | } 12 | 13 | PRIMITIVES = list(OPS.keys()) 14 | -------------------------------------------------------------------------------- /configs/graphclf_topk_benchmark.yml: -------------------------------------------------------------------------------- 1 | hpo: 2 | max_evals: 10 3 | name: tpe 4 | models: 5 | - hp_space: 6 | - maxValue: 0.9 7 | minValue: 0.1 8 | parameterName: ratio 9 | scalingType: LINEAR 10 | type: DOUBLE 11 | - maxValue: 0.9 12 | minValue: 0.1 13 | parameterName: dropout 14 | scalingType: LINEAR 15 | type: DOUBLE 16 | - feasiblePoints: 17 | - leaky_relu 18 | - relu 19 | - elu 20 | - tanh 21 | parameterName: act 22 | type: CATEGORICAL 23 | name: topkpool-model 24 | trainer: 25 | hp_space: 26 | - maxValue: 300 27 | minValue: 10 28 | parameterName: max_epoch 29 | scalingType: LINEAR 30 | type: INTEGER 31 | - maxValue: 30 32 | minValue: 10 33 | parameterName: early_stopping_round 34 | scalingType: LINEAR 35 | type: INTEGER 36 | - maxValue: 0.1 37 | minValue: 0.0001 38 | parameterName: lr 39 | scalingType: LOG 40 | type: DOUBLE 41 | - maxValue: 0.005 42 | minValue: 5.0e-05 43 | parameterName: weight_decay 44 | scalingType: LOG 45 | type: DOUBLE 46 | - maxValue: 128 47 | minValue: 48 48 | parameterName: batch_size 49 | scalingType: LINEAR 50 | type: INTEGER 51 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/_generators/_page_rank.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import networkx as nx 3 | import torch 4 | import autogl 5 | from ._basic import BaseFeatureGenerator 6 | from ..._data_preprocessor_registry import DataPreprocessorUniversalRegistry 7 | 8 | 9 | @DataPreprocessorUniversalRegistry.register_data_preprocessor("PageRank".lower()) 10 | class PageRankFeatureGenerator(BaseFeatureGenerator): 11 | def _extract_nodes_feature(self, data: autogl.data.Data) -> torch.Tensor: 12 | edge_weight = getattr(data, "edge_weight").tolist() 13 | g = nx.DiGraph() 14 | g.add_weighted_edges_from( 15 | [ 16 | (u, v, edge_weight[i]) 17 | for i, (u, v) in enumerate(data.edge_index.t().tolist()) 18 | ] 19 | ) 20 | page_rank = nx.pagerank(g) 21 | num_nodes: int = ( 22 | data.x.size(0) 23 | if data.x is not None and isinstance(data.x, torch.Tensor) 24 | else (data.edge_index.max().item() + 1) 25 | ) 26 | pr = np.zeros(num_nodes) 27 | for i, v in page_rank.items(): 28 | pr[i] = v 29 | return torch.from_numpy(pr).unsqueeze(-1) 30 | -------------------------------------------------------------------------------- /examples/autoattend.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ['AUTOGL_BACKEND']='pyg' 3 | from autogl.datasets import build_dataset_from_name 4 | from autogl.solver import AutoNodeClassifier 5 | from autogl.solver.utils import set_seed 6 | import argparse 7 | from autogl.backend import DependentBackend 8 | 9 | if __name__ == '__main__': 10 | set_seed(202106) 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument('--config', type=str, default='../configs/nodeclf_nas_autoattend_benchmark.yml') 13 | parser.add_argument('--dataset', choices=['cora', 'citeseer', 'pubmed'], default='cora', type=str) 14 | 15 | args = parser.parse_args() 16 | 17 | dataset = build_dataset_from_name(args.dataset) 18 | if DependentBackend.is_pyg(): 19 | label = dataset[0].y[dataset[0].test_mask].cpu().numpy() 20 | else: 21 | label = dataset[0].ndata['label'][dataset[0].ndata['test_mask']] 22 | # label = dataset[0].nodes.data["y" if DependentBackend.is_pyg() else "label"][dataset[0].nodes.data["test_mask"]].cpu().numpy() 23 | solver = AutoNodeClassifier.from_config(args.config) 24 | solver.fit(dataset) 25 | solver.get_leaderboard().show() 26 | acc = solver.evaluate(metric="acc") 27 | print('acc on dataset', acc) 28 | -------------------------------------------------------------------------------- /test/performance/node_classification/dgl/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gin', decoder=None): 2 | if model == 'gin': 3 | model_hp = { 4 | "num_layers": 5, 5 | "hidden": [64], 6 | "act": "relu", 7 | "eps": "False", 8 | "mlp_layers": 2, 9 | "neighbor_pooling_type": "sum" 10 | } 11 | elif model == 'gat': 12 | model_hp = { 13 | # hp from model 14 | "num_layers": 2, 15 | "hidden": [8], 16 | "heads": 8, 17 | "dropout": 0.6, 18 | "act": "relu", 19 | } 20 | elif model == 'gcn': 21 | model_hp = { 22 | "num_layers": 2, 23 | "hidden": [16], 24 | "dropout": 0.5, 25 | "act": "relu" 26 | } 27 | elif model == 'sage': 28 | model_hp = { 29 | "num_layers": 2, 30 | "hidden": [64], 31 | "dropout": 0.5, 32 | "act": "relu", 33 | "agg": "gcn", 34 | } 35 | elif model == 'topk': 36 | model_hp = { 37 | "num_layers": 5, 38 | "hidden": [64, 64, 64, 64] 39 | } 40 | 41 | return model_hp, {} 42 | -------------------------------------------------------------------------------- /configs/nodeclf_nas_grna.yml: -------------------------------------------------------------------------------- 1 | nas: 2 | space: 3 | name: grnaspace 4 | hidden_dim: 64 5 | layer_number: 2 6 | dropout: 0.6 7 | ops: ["gcn", "gat_2","sage", "gin"] 8 | rob_ops: ["identity", "jaccard", "gnnguard"] 9 | act_ops: ['relu','elu','leaky_relu','tanh'] 10 | algorithm: 11 | name: grna 12 | n_warmup: 1000 # 1000 13 | cycles: 5000 14 | population_size: 50 15 | sample_size: 20 16 | mutation_prob: 0.05 17 | estimator: 18 | name: grna 19 | lambda_: 0.05 20 | adv_sample_num: 10 21 | ptbr: 0.05 22 | ensemble: 23 | name: null 24 | feature: 25 | - name: NormalizeFeatures 26 | hpo: 27 | name: null 28 | models: [] 29 | trainer: 30 | hp_space: 31 | - maxValue: 300 # 300 32 | minValue: 100 # 100 33 | parameterName: max_epoch 34 | scalingType: LINEAR 35 | type: INTEGER 36 | - maxValue: 30 37 | minValue: 10 38 | parameterName: early_stopping_round 39 | scalingType: LINEAR 40 | type: INTEGER 41 | - maxValue: 0.05 42 | minValue: 0.005 43 | parameterName: lr 44 | scalingType: LOG 45 | type: DOUBLE 46 | - maxValue: 0.0005 47 | minValue: 1.0e-05 48 | parameterName: weight_decay 49 | scalingType: LOG 50 | type: DOUBLE 51 | -------------------------------------------------------------------------------- /autogl/module/_feature/graph/__init__.py: -------------------------------------------------------------------------------- 1 | from .netlsd import SgNetLSD 2 | from .base import BaseGraph 3 | from .nx import ( 4 | register_nx, 5 | NxGraph, 6 | nxfunc, 7 | NxLargeCliqueSize, 8 | NxAverageClusteringApproximate, 9 | NxDegreeAssortativityCoefficient, 10 | NxDegreePearsonCorrelationCoefficient, 11 | NxHasBridge, 12 | NxGraphCliqueNumber, 13 | NxGraphNumberOfCliques, 14 | NxTransitivity, 15 | NxAverageClustering, 16 | NxIsConnected, 17 | NxNumberConnectedComponents, 18 | NxIsDistanceRegular, 19 | NxLocalEfficiency, 20 | NxGlobalEfficiency, 21 | NxIsEulerian, 22 | ) 23 | 24 | __all__ = [ 25 | "SgNetLSD", 26 | "BaseGraph", 27 | "register_nx", 28 | "NxGraph", 29 | "nxfunc", 30 | "NxLargeCliqueSize", 31 | "NxAverageClusteringApproximate", 32 | "NxDegreeAssortativityCoefficient", 33 | "NxDegreePearsonCorrelationCoefficient", 34 | "NxHasBridge", 35 | "NxGraphCliqueNumber", 36 | "NxGraphNumberOfCliques", 37 | "NxTransitivity", 38 | "NxAverageClustering", 39 | "NxIsConnected", 40 | "NxNumberConnectedComponents", 41 | "NxIsDistanceRegular", 42 | "NxLocalEfficiency", 43 | "NxGlobalEfficiency", 44 | "NxIsEulerian", 45 | ] 46 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/_data_preprocessor_registry.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from autogl.utils import universal_registry 3 | from . import _data_preprocessor 4 | 5 | 6 | class DataPreprocessorUniversalRegistry(universal_registry.UniversalRegistryBase): 7 | @classmethod 8 | def register_data_preprocessor(cls, name: str) -> typing.Callable[ 9 | [typing.Type[_data_preprocessor.DataPreprocessor]], 10 | typing.Type[_data_preprocessor.DataPreprocessor] 11 | ]: 12 | def register_data_preprocessor( 13 | data_preprocessor: typing.Type[_data_preprocessor.DataPreprocessor] 14 | ) -> typing.Type[_data_preprocessor.DataPreprocessor]: 15 | if not issubclass(data_preprocessor, _data_preprocessor.DataPreprocessor): 16 | raise TypeError 17 | else: 18 | cls[name] = data_preprocessor 19 | return data_preprocessor 20 | 21 | return register_data_preprocessor 22 | 23 | @classmethod 24 | def get_data_preprocessor(cls, name: str) -> typing.Type[_data_preprocessor.DataPreprocessor]: 25 | if name not in cls: 26 | raise ValueError(f"Data Preprocessor with name \"{name}\" not exist") 27 | else: 28 | return cls[name] 29 | -------------------------------------------------------------------------------- /autogl/module/ensemble/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseEnsembler 2 | 3 | ENSEMBLE_DICT = {} 4 | 5 | 6 | def register_ensembler(name): 7 | def register_ensembler_cls(cls): 8 | if name in ENSEMBLE_DICT: 9 | raise ValueError("Cannot register duplicate ensembler ({})".format(name)) 10 | if not issubclass(cls, BaseEnsembler): 11 | raise ValueError( 12 | "Model ({}: {}) must extend BaseEnsembler".format(name, cls.__name__) 13 | ) 14 | ENSEMBLE_DICT[name] = cls 15 | return cls 16 | 17 | return register_ensembler_cls 18 | 19 | 20 | from .voting import Voting 21 | from .stacking import Stacking 22 | 23 | 24 | def build_ensembler_from_name(name: str) -> BaseEnsembler: 25 | """ 26 | Parameters 27 | ---------- 28 | name: ``str`` 29 | the name of ensemble module. 30 | 31 | Returns 32 | ------- 33 | BaseEnsembler: 34 | the ensembler built using default parameters 35 | 36 | Raises 37 | ------ 38 | AssertionError 39 | If an invalid name is passed in 40 | """ 41 | assert name in ENSEMBLE_DICT, "ensemble module do not have name " + name 42 | return ENSEMBLE_DICT[name]() 43 | 44 | 45 | __all__ = ["BaseEnsembler", "Voting", "Stacking", "build_ensembler_from_name"] 46 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/early_stop_descending.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from suggestion.models import Study 4 | from suggestion.models import TrialMetric 5 | from suggestion.early_stop_algorithm.abstract_early_stop import ( 6 | AbstractEarlyStopAlgorithm, 7 | ) 8 | 9 | 10 | class EarlyStopDescendingAlgorithm(AbstractEarlyStopAlgorithm): 11 | def get_early_stop_trials(self, trials): 12 | result = [] 13 | 14 | for trial in trials: 15 | study = Study.objects.get(name=trial.study_name) 16 | study_configuration_json = json.loads(study.study_configuration) 17 | study_goal = study_configuration_json["goal"] 18 | 19 | metrics = TrialMetric.objects.filter(trial_id=trial.id).order_by( 20 | "-training_step" 21 | ) 22 | metrics = [metric for metric in metrics] 23 | 24 | if len(metrics) >= 2: 25 | if study_goal == "MAXIMIZE": 26 | if metrics[0].objective_value < metrics[1].objective_value: 27 | result.append(trial) 28 | elif study_goal == "MINIMIZE": 29 | if metrics[0].objective_value > metrics[1].objective_value: 30 | result.append(trial) 31 | 32 | return result 33 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/abstract_algorithm.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | class AbstractSuggestionAlgorithm(object): 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | """ 8 | 9 | __metaclass__ = abc.ABCMeta 10 | 11 | @abc.abstractmethod 12 | def get_new_suggestions(self, study_name, trials=[], number=1): 13 | """ 14 | The study's study_configuration is like this. 15 | { 16 | "goal": "MAXIMIZE", 17 | "maxTrials": 5, 18 | "maxParallelTrials": 1, 19 | "params": [ 20 | { 21 | "parameterName": "hidden1", 22 | "type": "INTEGER", 23 | "minValue": 40, 24 | "maxValue": 400, 25 | "scalingType": "LINEAR" 26 | } 27 | ] 28 | } 29 | 30 | The trial's parameter_values_json should be like this. 31 | { 32 | "hidden1": 40 33 | } 34 | 35 | Args: 36 | study_name: The study name. 37 | trials: The all trials of this study. 38 | number: The number of trial to return. 39 | Returns: 40 | The array of trial objects. 41 | """ 42 | raise NotImplementedError 43 | -------------------------------------------------------------------------------- /configs/nodeclf_gcn_benchmark_small.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: '2' 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 1 17 | maxValue: 18 | - 64 19 | minValue: 20 | - 16 21 | numericalType: INTEGER 22 | parameterName: hidden 23 | scalingType: LOG 24 | type: NUMERICAL_LIST 25 | - maxValue: 0.8 26 | minValue: 0.2 27 | parameterName: dropout 28 | scalingType: LINEAR 29 | type: DOUBLE 30 | - feasiblePoints: 31 | - leaky_relu 32 | - relu 33 | - elu 34 | - tanh 35 | parameterName: act 36 | type: CATEGORICAL 37 | name: gcn-model 38 | trainer: 39 | hp_space: 40 | - maxValue: 300 41 | minValue: 100 42 | parameterName: max_epoch 43 | scalingType: LINEAR 44 | type: INTEGER 45 | - maxValue: 30 46 | minValue: 10 47 | parameterName: early_stopping_round 48 | scalingType: LINEAR 49 | type: INTEGER 50 | - maxValue: 0.05 51 | minValue: 0.005 52 | parameterName: lr 53 | scalingType: LOG 54 | type: DOUBLE 55 | - maxValue: 0.001 56 | minValue: 0.0001 57 | parameterName: weight_decay 58 | scalingType: LOG 59 | type: DOUBLE 60 | -------------------------------------------------------------------------------- /configs/nodeclf_gcn_benchmark_ogb.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 256 19 | - 256 20 | minValue: 21 | - 256 22 | - 256 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.505 28 | minValue: 0.495 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 33 | - leaky_relu 34 | - relu 35 | parameterName: act 36 | type: CATEGORICAL 37 | name: gcn-model 38 | trainer: 39 | hp_space: 40 | - maxValue: 500 41 | minValue: 500 42 | parameterName: max_epoch 43 | scalingType: LINEAR 44 | type: INTEGER 45 | - maxValue: 500 46 | minValue: 500 47 | parameterName: early_stopping_round 48 | scalingType: LINEAR 49 | type: INTEGER 50 | - maxValue: 0.0105 51 | minValue: 0.0095 52 | parameterName: lr 53 | scalingType: LOG 54 | type: DOUBLE 55 | - maxValue: 0.0000001 56 | minValue: 0.00000001 57 | parameterName: weight_decay 58 | scalingType: LOG 59 | type: DOUBLE 60 | -------------------------------------------------------------------------------- /configs/lp_gcn_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 256 19 | - 256 20 | minValue: 21 | - 64 22 | - 64 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.2 28 | minValue: 0.0 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 33 | - leaky_relu 34 | - relu 35 | - elu 36 | - tanh 37 | parameterName: act 38 | type: CATEGORICAL 39 | name: gcn-model 40 | trainer: 41 | hp_space: 42 | - maxValue: 150 43 | minValue: 50 44 | parameterName: max_epoch 45 | scalingType: LINEAR 46 | type: INTEGER 47 | - maxValue: 40 48 | minValue: 25 49 | parameterName: early_stopping_round 50 | scalingType: LINEAR 51 | type: INTEGER 52 | - maxValue: 0.05 53 | minValue: 0.005 54 | parameterName: lr 55 | scalingType: LOG 56 | type: DOUBLE 57 | - maxValue: 1.0E-7 58 | minValue: 1.0E-10 59 | parameterName: weight_decay 60 | scalingType: LOG 61 | type: DOUBLE 62 | -------------------------------------------------------------------------------- /configs/lp_gat_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - name: gat-model 10 | hp_space: 11 | - feasiblePoints: 2,3 12 | parameterName: num_layers 13 | type: DISCRETE 14 | - cutFunc: lambda x:x[0] - 1 15 | cutPara: 16 | - num_layers 17 | length: 2 18 | maxValue: 19 | - 256 20 | - 256 21 | minValue: 22 | - 64 23 | - 64 24 | numericalType: INTEGER 25 | parameterName: hidden 26 | scalingType: LOG 27 | type: NUMERICAL_LIST 28 | - maxValue: 0.2 29 | minValue: 0.0 30 | parameterName: dropout 31 | scalingType: LINEAR 32 | type: DOUBLE 33 | - feasiblePoints: 34 | - leaky_relu 35 | - relu 36 | - elu 37 | - tanh 38 | parameterName: act 39 | type: CATEGORICAL 40 | trainer: 41 | hp_space: 42 | - maxValue: 150 43 | minValue: 50 44 | parameterName: max_epoch 45 | scalingType: LINEAR 46 | type: INTEGER 47 | - maxValue: 40 48 | minValue: 25 49 | parameterName: early_stopping_round 50 | scalingType: LINEAR 51 | type: INTEGER 52 | - maxValue: 0.05 53 | minValue: 0.005 54 | parameterName: lr 55 | scalingType: LOG 56 | type: DOUBLE 57 | - maxValue: 1.0E-7 58 | minValue: 1.0E-10 59 | parameterName: weight_decay 60 | scalingType: LOG 61 | type: DOUBLE 62 | -------------------------------------------------------------------------------- /configs/nodeclf_gcn_benchmark_large.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 128 19 | - 128 20 | minValue: 21 | - 32 22 | - 32 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.8 28 | minValue: 0.2 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 33 | - leaky_relu 34 | - relu 35 | - elu 36 | - tanh 37 | parameterName: act 38 | type: CATEGORICAL 39 | name: gcn 40 | trainer: 41 | hp_space: 42 | - maxValue: 300 43 | minValue: 100 44 | parameterName: max_epoch 45 | scalingType: LINEAR 46 | type: INTEGER 47 | - maxValue: 30 48 | minValue: 10 49 | parameterName: early_stopping_round 50 | scalingType: LINEAR 51 | type: INTEGER 52 | - maxValue: 0.05 53 | minValue: 0.01 54 | parameterName: lr 55 | scalingType: LOG 56 | type: DOUBLE 57 | - maxValue: 0.0005 58 | minValue: 5.0e-05 59 | parameterName: weight_decay 60 | scalingType: LOG 61 | type: DOUBLE 62 | -------------------------------------------------------------------------------- /configs/nodeclf_gat_benchmark_small.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: '2' 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - feasiblePoints: 6,8,10,12 14 | parameterName: heads 15 | type: DISCRETE 16 | - cutFunc: lambda x:x[0] - 1 17 | cutPara: 18 | - num_layers 19 | length: 1 20 | maxValue: 21 | - 16 22 | minValue: 23 | - 4 24 | numericalType: INTEGER 25 | parameterName: hidden 26 | scalingType: LOG 27 | type: NUMERICAL_LIST 28 | - maxValue: 0.8 29 | minValue: 0.2 30 | parameterName: dropout 31 | scalingType: LINEAR 32 | type: DOUBLE 33 | - feasiblePoints: 34 | - leaky_relu 35 | - relu 36 | - elu 37 | - tanh 38 | parameterName: act 39 | type: CATEGORICAL 40 | name: gat-model 41 | trainer: 42 | hp_space: 43 | - maxValue: 300 44 | minValue: 100 45 | parameterName: max_epoch 46 | scalingType: LINEAR 47 | type: INTEGER 48 | - maxValue: 30 49 | minValue: 10 50 | parameterName: early_stopping_round 51 | scalingType: LINEAR 52 | type: INTEGER 53 | - maxValue: 0.05 54 | minValue: 0.01 55 | parameterName: lr 56 | scalingType: LOG 57 | type: DOUBLE 58 | - maxValue: 0.001 59 | minValue: 0.0001 60 | parameterName: weight_decay 61 | scalingType: LOG 62 | type: DOUBLE 63 | -------------------------------------------------------------------------------- /test/performance/node_classification/pyg/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gin', decoder=None, decoupled=False): 2 | if model == 'gin': 3 | model_hp = { 4 | # hp from model 5 | "num_layers": 2, 6 | "hidden": [64], 7 | "dropout": 0.5, 8 | "act": "relu", 9 | "eps": "False", 10 | "mlp_layers": 2 11 | } 12 | 13 | if model == 'gat': 14 | if decoupled: 15 | model_hp = { 16 | "num_layers": 2, 17 | "hidden": [8], 18 | "num_hidden_heads": 8, 19 | "num_output_heads": 1, 20 | "dropout": 0.6, 21 | "act": "elu" 22 | } 23 | else: 24 | model_hp = { 25 | "num_layers": 2, 26 | "hidden": [8], 27 | "heads": 8, 28 | "dropout": 0.6, 29 | "act": "elu" 30 | } 31 | elif model == 'gcn': 32 | model_hp = { 33 | "num_layers": 2, 34 | "hidden": [16], 35 | "dropout": 0.5, 36 | "act": "relu" 37 | } 38 | elif model == 'sage': 39 | model_hp = { 40 | "num_layers": 2, 41 | "hidden": [64], 42 | "dropout": 0.5, 43 | "act": "relu", 44 | "agg": "mean", 45 | } 46 | else: 47 | model_hp = {} 48 | 49 | return model_hp, {} 50 | -------------------------------------------------------------------------------- /configs/nodeclf_gat_benchmark_large.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 32 19 | - 32 20 | minValue: 21 | - 8 22 | - 8 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.5 28 | minValue: 0.2 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 8,10,12 33 | parameterName: heads 34 | type: DISCRETE 35 | - feasiblePoints: 36 | - leaky_relu 37 | - relu 38 | - elu 39 | - tanh 40 | parameterName: act 41 | type: CATEGORICAL 42 | name: gat-model 43 | trainer: 44 | hp_space: 45 | - maxValue: 400 46 | minValue: 250 47 | parameterName: max_epoch 48 | scalingType: LINEAR 49 | type: INTEGER 50 | - maxValue: 40 51 | minValue: 25 52 | parameterName: early_stopping_round 53 | scalingType: LINEAR 54 | type: INTEGER 55 | - maxValue: 0.05 56 | minValue: 0.01 57 | parameterName: lr 58 | scalingType: LOG 59 | type: DOUBLE 60 | - maxValue: 0.0005 61 | minValue: 0.0001 62 | parameterName: weight_decay 63 | scalingType: LOG 64 | type: DOUBLE 65 | -------------------------------------------------------------------------------- /autogl/module/nas/algorithm/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base class for algorithm 3 | """ 4 | from ...model import BaseAutoModel 5 | import torch 6 | from abc import abstractmethod 7 | from ....utils import get_device 8 | 9 | 10 | class BaseNAS: 11 | """ 12 | Base NAS algorithm class 13 | 14 | Parameters 15 | ---------- 16 | device: str or torch.device 17 | The device of the whole process 18 | """ 19 | 20 | def __init__(self, device="auto") -> None: 21 | self.device = get_device(device) 22 | 23 | def to(self, device): 24 | """ 25 | Change the device of the whole NAS search process 26 | 27 | Parameters 28 | ---------- 29 | device: str or torch.device 30 | """ 31 | self.device = get_device(device) 32 | 33 | @abstractmethod 34 | def search(self, space, dataset, estimator) -> BaseAutoModel: 35 | """ 36 | The search process of NAS. 37 | 38 | Parameters 39 | ---------- 40 | space : autogl.module.nas.space.BaseSpace 41 | The search space. Constructed following nni. 42 | dataset : autogl.datasets 43 | Dataset to perform search on. 44 | estimator : autogl.module.nas.estimator.BaseEstimator 45 | The estimator to compute loss & metrics. 46 | 47 | Returns 48 | ------- 49 | model: autogl.module.model.BaseModel 50 | The searched model. 51 | """ 52 | raise NotImplementedError() 53 | -------------------------------------------------------------------------------- /autogl/module/model/dgl/hetero/base.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from ..base import BaseAutoModel 3 | 4 | class BaseHeteroModelMaintainer(BaseAutoModel): 5 | def __init__(self, num_features, num_classes, device, dataset=None, **kwargs): 6 | super().__init__(num_features, num_classes, device, **kwargs) 7 | self._registered_parameters = {} 8 | if dataset is not None: 9 | self.from_dataset(dataset) 10 | 11 | def from_dataset(self, dataset): 12 | raise NotImplementedError 13 | 14 | # consider moving this to inner classes 15 | def register_parameter(self, key: str, value): 16 | self._registered_parameters[key] = value 17 | setattr(self, key, value) 18 | 19 | def destroy_parameter(self, key): 20 | if key in self._registered_parameters: 21 | return self._registered_parameters.pop(key) 22 | return None 23 | 24 | def from_hyper_parameter(self, hp, **kwargs): 25 | kw = deepcopy(self._kwargs) 26 | kw.update(kwargs) 27 | ret_self = self.__class__( 28 | self.input_dimension, 29 | self.output_dimension, 30 | self.device, 31 | **kw 32 | ) 33 | hp_now = dict(self.hyper_parameters) 34 | hp_now.update(hp) 35 | ret_self.hyper_parameters = hp_now 36 | for key, value in self._registered_parameters.items(): 37 | ret_self.register_parameter(key, value) 38 | ret_self.initialize() 39 | return ret_self 40 | -------------------------------------------------------------------------------- /configs/nodeclf_sage_benchmark_small.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 16 19 | - 64 20 | minValue: 21 | - 16 22 | - 64 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.8 28 | minValue: 0.2 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 33 | - mean 34 | - add 35 | - max 36 | parameterName: agg 37 | type: CATEGORICAL 38 | - feasiblePoints: 39 | - leaky_relu 40 | - relu 41 | - elu 42 | - tanh 43 | parameterName: act 44 | type: CATEGORICAL 45 | name: gcn 46 | trainer: 47 | hp_space: 48 | - maxValue: 300 49 | minValue: 100 50 | parameterName: max_epoch 51 | scalingType: LINEAR 52 | type: INTEGER 53 | - maxValue: 30 54 | minValue: 10 55 | parameterName: early_stopping_round 56 | scalingType: LINEAR 57 | type: INTEGER 58 | - maxValue: 0.05 59 | minValue: 0.01 60 | parameterName: lr 61 | scalingType: LOG 62 | type: DOUBLE 63 | - maxValue: 0.001 64 | minValue: 0.0001 65 | parameterName: weight_decay 66 | scalingType: LOG 67 | type: DOUBLE 68 | -------------------------------------------------------------------------------- /autogl/module/model/pyg/robust/nn/inits.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import torch 4 | 5 | 6 | def uniform(size, tensor): 7 | if tensor is not None: 8 | bound = 1.0 / math.sqrt(size) 9 | tensor.data.uniform_(-bound, bound) 10 | 11 | 12 | def kaiming_uniform(tensor, fan, a): 13 | if tensor is not None: 14 | bound = math.sqrt(6 / ((1 + a**2) * fan)) 15 | tensor.data.uniform_(-bound, bound) 16 | 17 | 18 | def glorot(tensor): 19 | if tensor is not None: 20 | stdv = math.sqrt(6.0 / (tensor.size(-2) + tensor.size(-1))) 21 | tensor.data.uniform_(-stdv, stdv) 22 | 23 | 24 | def glorot_orthogonal(tensor, scale): 25 | if tensor is not None: 26 | torch.nn.init.orthogonal_(tensor.data) 27 | scale /= ((tensor.size(-2) + tensor.size(-1)) * tensor.var()) 28 | tensor.data *= scale.sqrt() 29 | 30 | 31 | def zeros(tensor): 32 | if tensor is not None: 33 | tensor.data.fill_(0) 34 | 35 | 36 | def ones(tensor): 37 | if tensor is not None: 38 | tensor.data.fill_(1) 39 | 40 | 41 | def normal(tensor, mean, std): 42 | if tensor is not None: 43 | tensor.data.normal_(mean, std) 44 | 45 | 46 | def reset(nn): 47 | def _reset(item): 48 | if hasattr(item, 'reset_parameters'): 49 | item.reset_parameters() 50 | 51 | if nn is not None: 52 | if hasattr(nn, 'children') and len(list(nn.children())) > 0: 53 | for item in nn.children(): 54 | _reset(item) 55 | else: 56 | _reset(nn) 57 | -------------------------------------------------------------------------------- /autogl/datasets/_dataset_registry.py: -------------------------------------------------------------------------------- 1 | import os 2 | import typing as _typing 3 | from autogl.utils import universal_registry 4 | from autogl.data import Dataset 5 | 6 | 7 | class DatasetUniversalRegistry(universal_registry.UniversalRegistryBase): 8 | @classmethod 9 | def register_dataset(cls, dataset_name: str) -> _typing.Callable[ 10 | [_typing.Type[Dataset]], _typing.Type[Dataset] 11 | ]: 12 | def register_dataset_cls(dataset: _typing.Type[Dataset]): 13 | # print(dataset_name) 14 | if (not callable(dataset)) and (not issubclass(dataset, Dataset)): 15 | raise TypeError 16 | else: 17 | cls[dataset_name] = dataset 18 | return dataset 19 | 20 | return register_dataset_cls 21 | 22 | @classmethod 23 | def get_dataset(cls, dataset_name: str) -> _typing.Type[Dataset]: 24 | # print(dataset_name) 25 | return cls[dataset_name] 26 | 27 | 28 | def build_dataset_from_name(dataset_name: str, path: str = "~/.cache-autogl/", *args, **kwargs): 29 | """ 30 | 31 | Parameters 32 | ---------- 33 | dataset_name: `str` 34 | name of dataset 35 | path: `str` 36 | local cache directory for datasets, default to "~/.cache-autogl/" 37 | 38 | Returns 39 | ------- 40 | instance of dataset 41 | """ 42 | path = os.path.expanduser(os.path.join(path, "data", dataset_name)) 43 | _dataset = DatasetUniversalRegistry.get_dataset(dataset_name) 44 | return _dataset(path, *args, **kwargs) 45 | -------------------------------------------------------------------------------- /autogl/module/nas/space/gasso_space/inits.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import torch 4 | 5 | 6 | def uniform(size, tensor): 7 | if tensor is not None: 8 | bound = 1.0 / math.sqrt(size) 9 | tensor.data.uniform_(-bound, bound) 10 | 11 | 12 | def kaiming_uniform(tensor, fan, a): 13 | if tensor is not None: 14 | bound = math.sqrt(6 / ((1 + a**2) * fan)) 15 | tensor.data.uniform_(-bound, bound) 16 | 17 | 18 | def glorot(tensor): 19 | if tensor is not None: 20 | stdv = math.sqrt(6.0 / (tensor.size(-2) + tensor.size(-1))) 21 | tensor.data.uniform_(-stdv, stdv) 22 | 23 | 24 | def glorot_orthogonal(tensor, scale): 25 | if tensor is not None: 26 | torch.nn.init.orthogonal_(tensor.data) 27 | scale /= ((tensor.size(-2) + tensor.size(-1)) * tensor.var()) 28 | tensor.data *= scale.sqrt() 29 | 30 | 31 | def zeros(tensor): 32 | if tensor is not None: 33 | tensor.data.fill_(0) 34 | 35 | 36 | def ones(tensor): 37 | if tensor is not None: 38 | tensor.data.fill_(1) 39 | 40 | 41 | def normal(tensor, mean, std): 42 | if tensor is not None: 43 | tensor.data.normal_(mean, std) 44 | 45 | 46 | def reset(nn): 47 | def _reset(item): 48 | if hasattr(item, 'reset_parameters'): 49 | item.reset_parameters() 50 | 51 | if nn is not None: 52 | if hasattr(nn, 'children') and len(list(nn.children())) > 0: 53 | for item in nn.children(): 54 | _reset(item) 55 | else: 56 | _reset(nn) 57 | -------------------------------------------------------------------------------- /configs/lp_sage_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - name: sage 10 | hp_space: 11 | - parameterName: num_layers 12 | type: DISCRETE 13 | feasiblePoints: 2,3 14 | 15 | - parameterName: hidden 16 | type: NUMERICAL_LIST 17 | scalingType: LOG 18 | numericalType: INTEGER 19 | cutFunc: lambda x:x[0] - 1 20 | cutPara: 21 | - num_layers 22 | length: 2 23 | maxValue: 24 | - 256 25 | - 256 26 | minValue: 27 | - 64 28 | - 64 29 | 30 | - parameterName: dropout 31 | type: DOUBLE 32 | scalingType: LINEAR 33 | maxValue: 0.2 34 | minValue: 0.0 35 | 36 | - parameterName: act 37 | type: CATEGORICAL 38 | feasiblePoints: 39 | - leaky_relu 40 | - relu 41 | - elu 42 | - tanh 43 | 44 | - parameterName: agg 45 | type: CATEGORICAL 46 | feasiblePoints: ["mean", "add", "max"] 47 | 48 | trainer: 49 | hp_space: 50 | - maxValue: 150 51 | minValue: 50 52 | parameterName: max_epoch 53 | scalingType: LINEAR 54 | type: INTEGER 55 | - maxValue: 40 56 | minValue: 25 57 | parameterName: early_stopping_round 58 | scalingType: LINEAR 59 | type: INTEGER 60 | - maxValue: 0.05 61 | minValue: 0.005 62 | parameterName: lr 63 | scalingType: LOG 64 | type: DOUBLE 65 | - maxValue: 1.0E-7 66 | minValue: 1.0E-10 67 | parameterName: weight_decay 68 | scalingType: LOG 69 | type: DOUBLE 70 | -------------------------------------------------------------------------------- /autogl/module/train/ssl/utils.py: -------------------------------------------------------------------------------- 1 | from .views_fn import ( 2 | DropNode, 3 | PermuteEdge, 4 | MaskNode, 5 | SubGraph, 6 | RandomView 7 | ) 8 | 9 | def get_view_by_name(view, aug_ratio): 10 | if view is None: 11 | return lambda x: x 12 | elif view == "dropN": 13 | return DropNode(aug_ratio=aug_ratio) 14 | elif view == "permE": 15 | return PermuteEdge(aug_ratio=aug_ratio) 16 | elif view == "subgraph": 17 | return SubGraph(aug_ratio=aug_ratio) 18 | elif view == "maskN": 19 | return MaskNode(aug_ratio=aug_ratio) 20 | elif view == "random2": 21 | canditates = [DropNode(aug_ratio=aug_ratio), 22 | SubGraph(aug_ratio=aug_ratio)] 23 | return RandomView(candidates=canditates) 24 | elif view == "random3": 25 | canditates = [DropNode(aug_ratio=aug_ratio), 26 | SubGraph(aug_ratio=aug_ratio), 27 | PermuteEdge(aug_ratio=aug_ratio)] 28 | return RandomView(candidates=canditates) 29 | elif view == "random4": 30 | canditates = [DropNode(aug_ratio=aug_ratio), 31 | SubGraph(aug_ratio=aug_ratio), 32 | PermuteEdge(aug_ratio=aug_ratio), 33 | MaskNode(aug_ratio=aug_ratio)] 34 | return RandomView(candidates=canditates) 35 | else: 36 | raise NotImplementedError(f'{view} is not supported yet. Support: ["dropN", "permE", "subgraph", \ 37 | "maskN", "random2", "random3", "random4", None]') 38 | -------------------------------------------------------------------------------- /examples/node_classification_ogb.py: -------------------------------------------------------------------------------- 1 | import os 2 | os.environ["AUTOGL_BACKEND"] = "pyg" 3 | import autogl 4 | from autogl.datasets import build_dataset_from_name 5 | ogbn_dataset = build_dataset_from_name('ogbn-arXiv') 6 | import torch 7 | # temporal fix to add masks, only for one graph, not recommended 8 | split_index = ogbn_dataset.get_idx_split() 9 | num_nodes = ogbn_dataset[0].num_nodes 10 | ogbn_dataset.data.train_mask = torch.zeros(num_nodes, dtype=torch.bool) 11 | ogbn_dataset.data.train_mask[split_index['train']] = True 12 | ogbn_dataset.data.val_mask = torch.zeros(num_nodes, dtype=torch.bool) 13 | ogbn_dataset.data.val_mask[split_index['valid']] = True 14 | ogbn_dataset.data.test_mask = torch.zeros(num_nodes, dtype=torch.bool) 15 | ogbn_dataset.data.test_mask[split_index['test']] = True 16 | ogbn_dataset.data.y = ogbn_dataset.data.y.squeeze(-1) 17 | 18 | device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') 19 | from autogl.solver import AutoNodeClassifier 20 | solver = AutoNodeClassifier( 21 | feature_module='deepgl', 22 | graph_models=['gcn', 'gat'], 23 | hpo_module='anneal', 24 | ensemble_module='voting', 25 | device=device 26 | ) 27 | 28 | solver.fit(ogbn_dataset, time_limit=30) 29 | solver.get_leaderboard().show() 30 | 31 | from autogl.module.train import Acc 32 | from autogl.solver.utils import get_graph_labels, get_graph_masks 33 | 34 | predicted = solver.predict_proba() 35 | label = get_graph_labels(ogbn_dataset[0])[get_graph_masks(ogbn_dataset[0], 'test')].cpu().numpy() 36 | print('Test accuracy: ', Acc.evaluate(predicted, label)) 37 | -------------------------------------------------------------------------------- /autogl/module/nas/estimator/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import BaseEstimator 2 | 3 | NAS_ESTIMATOR_DICT = {} 4 | 5 | 6 | def register_nas_estimator(name): 7 | def register_nas_estimator_cls(cls): 8 | if name in NAS_ESTIMATOR_DICT: 9 | raise ValueError( 10 | "Cannot register duplicate NAS estimator ({})".format(name) 11 | ) 12 | if not issubclass(cls, BaseEstimator): 13 | raise ValueError( 14 | "Model ({}: {}) must extend NAS estimator".format(name, cls.__name__) 15 | ) 16 | NAS_ESTIMATOR_DICT[name] = cls 17 | return cls 18 | 19 | return register_nas_estimator_cls 20 | 21 | 22 | from .one_shot import OneShotEstimator, OneShotEstimator_HardwareAware 23 | from .grna_estimator import GRNAEstimator 24 | from .train_scratch import TrainEstimator, TrainEstimator_HardwareAware 25 | 26 | def build_nas_estimator_from_name(name: str) -> BaseEstimator: 27 | """ 28 | Parameters 29 | ---------- 30 | name: ``str`` 31 | the name of nas estimator. 32 | 33 | Returns 34 | ------- 35 | BaseEstimator: 36 | the NAS estimator built using default parameters 37 | 38 | Raises 39 | ------ 40 | AssertionError 41 | If an invalid name is passed in 42 | """ 43 | assert name in NAS_ESTIMATOR_DICT, "HPO module do not have name " + name 44 | return NAS_ESTIMATOR_DICT[name]() 45 | 46 | 47 | __all__ = ["BaseEstimator", "OneShotEstimator", "TrainEstimator", "OneShotEstimator_HardwareAware", "TrainEstimator_HardwareAware", "GRNAEstimator"] 48 | -------------------------------------------------------------------------------- /test/performance/graph_classification/pyg/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gin', decoder=None): 2 | if model == 'gin': 3 | model_hp = { 4 | # hp from model 5 | "num_layers": 5, 6 | "hidden": [64,64,64,64], 7 | "dropout": 0.5, 8 | "act": "relu", 9 | "eps": "False", 10 | "mlp_layers": 2 11 | } 12 | 13 | if model == 'gat': 14 | model_hp = { 15 | "num_layers": 2, 16 | "hidden": [8], 17 | "num_hidden_heads": 8, 18 | "num_output_heads": 8, 19 | "dropout": 0.6, 20 | "act": "elu" 21 | } 22 | elif model == 'gcn': 23 | model_hp = { 24 | "num_layers": 2, 25 | "hidden": [16], 26 | "dropout": 0.5, 27 | "act": "relu" 28 | } 29 | elif model == 'sage': 30 | model_hp = { 31 | "num_layers": 2, 32 | "hidden": [64], 33 | "dropout": 0.5, 34 | "act": "relu", 35 | "agg": "mean", 36 | } 37 | else: 38 | model_hp = {} 39 | 40 | if decoder is None or decoder == "addpoolmlp": 41 | decoder_hp = { 42 | "hidden": 64, 43 | "act": "relu", 44 | "dropout": 0.5 45 | } 46 | elif decoder == "diffpool": 47 | decoder_hp = { 48 | "ratio": 0.8, 49 | "dropout": 0.5, 50 | "act": "relu" 51 | } 52 | else: 53 | decoder_hp = {} 54 | 55 | return model_hp, decoder_hp 56 | -------------------------------------------------------------------------------- /autogl/datasets/utils/conversion/_to_pyg_dataset.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | import torch 3 | import torch_geometric 4 | from autogl.data import Dataset, InMemoryDataset 5 | from autogl.data.graph import GeneralStaticGraph 6 | from autogl.data.graph.utils import conversion 7 | 8 | 9 | def to_pyg_dataset( 10 | dataset: _typing.Union[Dataset, _typing.Iterable[GeneralStaticGraph]] 11 | ) -> Dataset[torch_geometric.data.Data]: 12 | transformed_datalist: _typing.MutableSequence[torch_geometric.data.Data] = [] 13 | for item in dataset: 14 | if isinstance(item, torch_geometric.data.Data): 15 | transformed_datalist.append(item) 16 | elif isinstance(item, GeneralStaticGraph): 17 | transformed_datalist.append(conversion.static_graph_to_pyg_data(item)) 18 | elif ( 19 | isinstance(item, _typing.Mapping) and 20 | all([ 21 | (isinstance(k, str) and isinstance(v, torch.Tensor)) 22 | for k, v in item.items() 23 | ]) 24 | ): 25 | transformed_datalist.append(torch_geometric.data.Data(**item)) 26 | else: 27 | raise NotImplementedError( 28 | f"Unsupported data item {type(item)}<{item}> to convert as " 29 | f"{torch_geometric.data.Data}" 30 | ) 31 | return ( 32 | InMemoryDataset(transformed_datalist, dataset.train_index, dataset.val_index, dataset.test_index, dataset.schema) 33 | if isinstance(dataset, InMemoryDataset) 34 | else InMemoryDataset(transformed_datalist) 35 | ) 36 | -------------------------------------------------------------------------------- /autogl/datasets/utils/_split_edges/split_edges.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from autogl.data import InMemoryDataset, Dataset 3 | import autogl 4 | 5 | if autogl.backend.DependentBackend.is_dgl(): 6 | from ._dgl_compatible import split_edges_for_data 7 | elif autogl.backend.DependentBackend.is_pyg(): 8 | from ._pyg_compatible import split_edges_for_data 9 | else: 10 | raise NotImplementedError 11 | 12 | 13 | def split_edges( 14 | dataset: _typing.Iterable, train_ratio: float, val_ratio: _typing.Optional[float] = ... 15 | ) -> Dataset: 16 | if isinstance(val_ratio, float) and not 0 < train_ratio + val_ratio < 1: 17 | raise ValueError 18 | elif not 0 < train_ratio < 1: 19 | raise ValueError 20 | if ( 21 | autogl.backend.DependentBackend.is_pyg() and 22 | not (isinstance(val_ratio, float) and 0 < val_ratio < 1) 23 | ): 24 | raise ValueError( 25 | "For PyG as backend, val_ratio MUST be specific float between 0 and 1, " 26 | "i.e. 0 < val_ratio < 1" 27 | ) 28 | return ( 29 | InMemoryDataset( 30 | [split_edges_for_data(item, train_ratio, val_ratio) for item in dataset], 31 | dataset.train_index, dataset.val_index, dataset.test_index, dataset.schema 32 | ) 33 | if isinstance(dataset, Dataset) 34 | else 35 | InMemoryDataset( 36 | [split_edges_for_data(item, train_ratio, val_ratio) for item in dataset] 37 | ) if len(dataset) > 1 else 38 | InMemoryDataset([split_edges_for_data(dataset[0], train_ratio, val_ratio)]) 39 | ) 40 | -------------------------------------------------------------------------------- /autogl/module/feature/_base_feature_engineer/_base_feature_engineer_pyg.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import torch 3 | import typing as _typing 4 | from autogl.data.graph import GeneralStaticGraph 5 | from . import _base_feature_engineer 6 | 7 | 8 | class BaseFeatureEngineer( 9 | _base_feature_engineer.BaseFeatureEngineer 10 | ): 11 | @classmethod 12 | def __preprocess( 13 | cls, data: _typing.Union[GeneralStaticGraph, _typing.Any] 14 | ) -> _typing.Union[GeneralStaticGraph, _typing.Any]: 15 | return data # todo: Support torch_geometric.HeteroData in future 16 | 17 | @classmethod 18 | def __postprocess( 19 | cls, data: _typing.Union[GeneralStaticGraph, _typing.Any] 20 | ) -> _typing.Union[GeneralStaticGraph, _typing.Any]: 21 | return data # todo: Support torch_geometric.HeteroData in future 22 | 23 | def fit(self, dataset): 24 | dataset = copy.deepcopy(dataset) 25 | with torch.no_grad(): 26 | for i, data in enumerate(dataset): 27 | dataset[i] = self.__postprocess( 28 | self._postprocess(self._fit(self._preprocess(self.__preprocess(data)))) 29 | ) 30 | return dataset 31 | 32 | def transform(self, dataset, inplace: bool = True): 33 | if not inplace: 34 | dataset = copy.deepcopy(dataset) 35 | with torch.no_grad(): 36 | for i, data in enumerate(dataset): 37 | dataset[i] = self.__postprocess( 38 | self._postprocess(self._transform(self._preprocess(self.__preprocess(data)))) 39 | ) 40 | return dataset 41 | -------------------------------------------------------------------------------- /configs/graphclf_gin_benchmark.yml: -------------------------------------------------------------------------------- 1 | hpo: 2 | max_evals: 10 3 | name: tpe 4 | models: 5 | - hp_space: 6 | - parameterName: num_layers 7 | type: DISCRETE 8 | feasiblePoints: '3,4,5' 9 | 10 | - parameterName: hidden 11 | type: NUMERICAL_LIST 12 | numericalType: INTEGER 13 | length: 5 14 | minValue: [8, 8, 8, 8, 8] 15 | maxValue: [64, 64, 64, 64, 64] 16 | scalingType: LOG 17 | cutPara: ["num_layers"] 18 | cutFunc: "lambda x: x[0] - 1" 19 | 20 | - parameterName: dropout 21 | type: DOUBLE 22 | maxValue: 0.9 23 | minValue: 0.1 24 | scalingType: LINEAR 25 | 26 | - parameterName: act 27 | type: CATEGORICAL 28 | feasiblePoints: 29 | - leaky_relu 30 | - relu 31 | - elu 32 | - tanh 33 | 34 | - parameterName: eps 35 | type: CATEGORICAL 36 | feasiblePoints: 37 | - True 38 | - False 39 | 40 | - parameterName: mlp_layers 41 | type: DISCRETE 42 | feasiblePoints: '2,3,4' 43 | name: gin-model 44 | trainer: 45 | hp_space: 46 | - maxValue: 300 47 | minValue: 10 48 | parameterName: max_epoch 49 | scalingType: LINEAR 50 | type: INTEGER 51 | - maxValue: 30 52 | minValue: 10 53 | parameterName: early_stopping_round 54 | scalingType: LINEAR 55 | type: INTEGER 56 | - maxValue: 0.1 57 | minValue: 0.0001 58 | parameterName: lr 59 | scalingType: LOG 60 | type: DOUBLE 61 | - maxValue: 0.005 62 | minValue: 5.0e-05 63 | parameterName: weight_decay 64 | scalingType: LOG 65 | type: DOUBLE 66 | - maxValue: 128 67 | minValue: 48 68 | parameterName: batch_size 69 | scalingType: LINEAR 70 | type: INTEGER 71 | -------------------------------------------------------------------------------- /autogl/module/nas/algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | NAS algorithms 3 | """ 4 | 5 | import importlib 6 | import os 7 | from .base import BaseNAS 8 | 9 | NAS_ALGO_DICT = {} 10 | 11 | 12 | def register_nas_algo(name): 13 | def register_nas_algo_cls(cls): 14 | if name in NAS_ALGO_DICT: 15 | raise ValueError( 16 | "Cannot register duplicate NAS algorithm ({})".format(name) 17 | ) 18 | if not issubclass(cls, BaseNAS): 19 | raise ValueError( 20 | "Model ({}: {}) must extend NAS algorithm".format(name, cls.__name__) 21 | ) 22 | NAS_ALGO_DICT[name] = cls 23 | return cls 24 | 25 | return register_nas_algo_cls 26 | 27 | 28 | from .darts import Darts 29 | from .enas import Enas 30 | from .random_search import RandomSearch 31 | from .rl import RL, GraphNasRL 32 | from ..backend import * 33 | if not is_dgl(): 34 | from .gasso import Gasso 35 | from .grna import GRNA 36 | from .spos import Spos 37 | 38 | def build_nas_algo_from_name(name: str) -> BaseNAS: 39 | """ 40 | Parameters 41 | ---------- 42 | name: ``str`` 43 | the name of nas algorithm. 44 | 45 | Returns 46 | ------- 47 | BaseNAS: 48 | the NAS algorithm built using default parameters 49 | 50 | Raises 51 | ------ 52 | AssertionError 53 | If an invalid name is passed in 54 | """ 55 | assert name in NAS_ALGO_DICT, "HPO module do not have name " + name 56 | return NAS_ALGO_DICT[name]() 57 | 58 | 59 | __all__ = ["BaseNAS", "Darts", "Enas", "RandomSearch", "RL", "GraphNasRL","Spos"] 60 | if not is_dgl(): 61 | __all__.append("Gasso") 62 | __all__.append("GRNA") 63 | -------------------------------------------------------------------------------- /configs/nodeclf_ladies_reproduction.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 20 7 | name: random 8 | models: 9 | - hp_space: 10 | - value: 5 11 | parameterName: num_layers 12 | type: FIXED 13 | - parameterName: hidden 14 | type: FIXED 15 | value: [256, 256, 256, 256] 16 | - value: [0.2, 0.2, 0.2, 0.2, 0.6] 17 | parameterName: dropout 18 | type: FIXED 19 | - value: elu 20 | parameterName: act 21 | type: FIXED 22 | - parameterName: add_self_loops 23 | type: FIXED 24 | value: 0 25 | - parameterName: normalize 26 | type: FIXED 27 | value: 0 28 | name: gcn-model 29 | trainer: 30 | name: NodeClassificationLayerDependentImportanceSamplingTrainer 31 | hp_space: 32 | - parameterName: sampled_node_sizes 33 | type: FIXED 34 | value: [512, 512, 512, 512, 512] 35 | - maxValue: 128 36 | minValue: 64 37 | parameterName: max_epoch 38 | scalingType: LINEAR 39 | type: INTEGER 40 | - maxValue: 12 41 | minValue: 6 42 | parameterName: early_stopping_round 43 | scalingType: LOG 44 | type: INTEGER 45 | - parameterName: training_batch_size 46 | type: FIXED 47 | value: 512 48 | - parameterName: predicting_batch_size 49 | type: FIXED 50 | value: 1024 51 | - parameterName: training_sampler_num_workers 52 | type: FIXED 53 | value: 0 54 | - parameterName: predicting_sampler_num_workers 55 | type: FIXED 56 | value: 0 57 | - maxValue: 0.001 58 | minValue: 0.0005 59 | parameterName: lr 60 | scalingType: LOG 61 | type: DOUBLE 62 | - maxValue: 0 63 | minValue: 0 64 | parameterName: weight_decay 65 | scalingType: LINEAR 66 | type: DOUBLE 67 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/no_early_stop_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django.test import TestCase 4 | 5 | from suggestion.models import Study 6 | from suggestion.models import Trial 7 | from suggestion.models import TrialMetric 8 | from suggestion.early_stop_algorithm.no_early_stop import NoEarlyStopAlgorithm 9 | 10 | 11 | class NoEarlyStopAlgorithmTest(TestCase): 12 | def setUp(self): 13 | study_configuration_json = { 14 | "goal": "MAXIMIZE", 15 | "maxTrials": 5, 16 | "maxParallelTrials": 1, 17 | "params": [ 18 | { 19 | "parameterName": "hidden1", 20 | "type": "INTEGER", 21 | "minValue": 40, 22 | "maxValue": 400, 23 | "scalingType": "LINEAR", 24 | } 25 | ], 26 | } 27 | study_configuration = json.dumps(study_configuration_json) 28 | self.study = Study.create("RandomSearchStudy", study_configuration) 29 | trial1 = Trial.create(self.study.id, "RandomSearchTrial1") 30 | trial2 = Trial.create(self.study.id, "RandomSearchTrial2") 31 | self.trials = [trial1, trial2] 32 | TrialMetric.create(trial1.id, 10, 0.5) 33 | TrialMetric.create(trial1.id, 20, 0.6) 34 | TrialMetric.create(trial2.id, 10, 0.6) 35 | TrialMetric.create(trial2.id, 20, 0.5) 36 | 37 | def tearDown(self): 38 | pass 39 | 40 | # Test NoEarlyStopAlgorithm 41 | def test_get_early_stop_trials1(self): 42 | algorithm = NoEarlyStopAlgorithm() 43 | early_stop_trials = algorithm.get_early_stop_trials(self.trials) 44 | self.assertEqual(len(early_stop_trials), 0) 45 | -------------------------------------------------------------------------------- /test/performance/graph_classification/dgl/helper.py: -------------------------------------------------------------------------------- 1 | def get_encoder_decoder_hp(model='gin', decoder=None): 2 | if model == 'gin': 3 | model_hp = { 4 | "num_layers": 5, 5 | "hidden": [64,64,64,64], 6 | "dropout": 0.5, 7 | "act": "relu", 8 | "eps": "False", 9 | "mlp_layers": 2, 10 | "neighbor_pooling_type": "sum", 11 | } 12 | elif model == 'gat': 13 | model_hp = { 14 | # hp from model 15 | "num_layers": 2, 16 | "hidden": [8], 17 | "heads": 8, 18 | "dropout": 0.6, 19 | "act": "elu", 20 | } 21 | elif model == 'gcn': 22 | model_hp = { 23 | "num_layers": 2, 24 | "hidden": [16], 25 | "dropout": 0.5, 26 | "act": "relu" 27 | } 28 | elif model == 'sage': 29 | model_hp = { 30 | "num_layers": 2, 31 | "hidden": [64], 32 | "dropout": 0.5, 33 | "act": "relu", 34 | "agg": "mean", 35 | } 36 | elif model == 'topk': 37 | model_hp = { 38 | "num_layers": 5, 39 | "hidden": [64, 64, 64, 64] 40 | } 41 | 42 | if decoder is None: 43 | decoder_hp = { 44 | "hidden": 64, 45 | "dropout": 0.5, 46 | "act": "relu", 47 | "graph_pooling_type": "sum" 48 | } 49 | elif decoder == "JKSumPoolMLP": 50 | decoder_hp = { 51 | "dropout": 0.5, 52 | "graph_pooling_type": "sum" 53 | } 54 | elif decoder == "topk": 55 | decoder_hp = { 56 | "dropout": 0.5 57 | } 58 | 59 | return model_hp, decoder_hp 60 | -------------------------------------------------------------------------------- /autogl/data/extract.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os.path as osp 4 | import tarfile 5 | import zipfile 6 | import bz2 7 | import gzip 8 | 9 | 10 | def maybe_log(path, log=True): 11 | if log: 12 | print("Extracting", path) 13 | 14 | 15 | def extract_tar(path, folder, mode="r:gz", log=True): 16 | r"""Extracts a tar archive to a specific folder. 17 | 18 | Args: 19 | path (string): The path to the tar archive. 20 | folder (string): The folder. 21 | mode (string, optional): The compression mode. (default: :obj:`"r:gz"`) 22 | log (bool, optional): If :obj:`False`, will not print anything to the 23 | console. (default: :obj:`True`) 24 | """ 25 | maybe_log(path, log) 26 | with tarfile.open(path, mode) as f: 27 | f.extractall(folder) 28 | 29 | 30 | def extract_zip(path, folder, log=True): 31 | r"""Extracts a zip archive to a specific folder. 32 | 33 | Args: 34 | path (string): The path to the tar archive. 35 | folder (string): The folder. 36 | log (bool, optional): If :obj:`False`, will not print anything to the 37 | console. (default: :obj:`True`) 38 | """ 39 | maybe_log(path, log) 40 | with zipfile.ZipFile(path, "r") as f: 41 | f.extractall(folder) 42 | 43 | 44 | def extract_bz2(path, folder, log=True): 45 | maybe_log(path, log) 46 | with bz2.open(path, "r") as r: 47 | with open(osp.join(folder, ".".join(path.split(".")[:-1])), "wb") as w: 48 | w.write(r.read()) 49 | 50 | 51 | def extract_gz(path, folder, log=True): 52 | maybe_log(path, log) 53 | with gzip.open(path, "r") as r: 54 | with open(osp.join(folder, ".".join(path.split(".")[:-1])), "wb") as w: 55 | w.write(r.read()) 56 | -------------------------------------------------------------------------------- /autogl/module/preprocessing/feature_engineering/__init__.py: -------------------------------------------------------------------------------- 1 | from ._generators import ( 2 | OneHotFeatureGenerator, 3 | EigenFeatureGenerator, 4 | GraphletGenerator, 5 | PageRankFeatureGenerator, 6 | LocalDegreeProfileGenerator, 7 | NormalizeFeatures, 8 | OneHotDegreeGenerator 9 | ) 10 | from ._graph import ( 11 | NetLSD, 12 | NXLargeCliqueSize, 13 | NXDegreeAssortativityCoefficient, 14 | NXDegreePearsonCorrelationCoefficient, 15 | NXHasBridges, 16 | NXGraphCliqueNumber, 17 | NXGraphNumberOfCliques, 18 | NXTransitivity, 19 | NXAverageClustering, 20 | NXIsConnected, 21 | NXNumberConnectedComponents, 22 | NXIsDistanceRegular, 23 | NXLocalEfficiency, 24 | NXGlobalEfficiency, 25 | NXIsEulerian, 26 | ) 27 | from ._selectors import ( 28 | FilterConstant, GBDTFeatureSelector 29 | ) 30 | from ._auto_feature_engineer import ( 31 | IdentityFeature, AutoFeatureEngineer 32 | ) 33 | 34 | __all__ = [ 35 | "OneHotFeatureGenerator", 36 | "EigenFeatureGenerator", 37 | "GraphletGenerator", 38 | "PageRankFeatureGenerator", 39 | "LocalDegreeProfileGenerator", 40 | "NormalizeFeatures", 41 | "OneHotDegreeGenerator", 42 | "NetLSD", 43 | "NXLargeCliqueSize", 44 | "NXDegreeAssortativityCoefficient", 45 | "NXDegreePearsonCorrelationCoefficient", 46 | "NXHasBridges", 47 | "NXGraphCliqueNumber", 48 | "NXGraphNumberOfCliques", 49 | "NXTransitivity", 50 | "NXAverageClustering", 51 | "NXIsConnected", 52 | "NXNumberConnectedComponents", 53 | "NXIsDistanceRegular", 54 | "NXLocalEfficiency", 55 | "NXGlobalEfficiency", 56 | "NXIsEulerian", 57 | "FilterConstant", 58 | "GBDTFeatureSelector", 59 | "IdentityFeature", 60 | "AutoFeatureEngineer" 61 | ] 62 | -------------------------------------------------------------------------------- /configs/nodeclf_sage_benchmark_large.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: null 3 | feature: 4 | - name: PYGNormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - hp_space: 10 | - feasiblePoints: 2,3 11 | parameterName: num_layers 12 | type: DISCRETE 13 | - cutFunc: lambda x:x[0] - 1 14 | cutPara: 15 | - num_layers 16 | length: 2 17 | maxValue: 18 | - 32 19 | - 128 20 | minValue: 21 | - 32 22 | - 128 23 | numericalType: INTEGER 24 | parameterName: hidden 25 | scalingType: LOG 26 | type: NUMERICAL_LIST 27 | - maxValue: 0.8 28 | minValue: 0.2 29 | parameterName: dropout 30 | scalingType: LINEAR 31 | type: DOUBLE 32 | - feasiblePoints: 33 | - mean 34 | parameterName: agg 35 | type: CATEGORICAL 36 | - feasiblePoints: 37 | - leaky_relu 38 | - relu 39 | - elu 40 | - tanh 41 | parameterName: act 42 | type: CATEGORICAL 43 | name: sage 44 | trainer: 45 | name: NodeClassificationNeighborSampling 46 | hp_space: 47 | - parameterName: sampling_sizes 48 | type: NUMERICAL_LIST 49 | numericalType: INTEGER 50 | length: 3 51 | cutFunc: lambda x:x[0] 52 | cutPara: 53 | - num_layers 54 | minValue: 3 55 | maxValue: 8 56 | scalingType: LOG 57 | - maxValue: 300 58 | minValue: 100 59 | parameterName: max_epoch 60 | scalingType: LINEAR 61 | type: INTEGER 62 | - maxValue: 30 63 | minValue: 10 64 | parameterName: early_stopping_round 65 | scalingType: LINEAR 66 | type: INTEGER 67 | - maxValue: 0.05 68 | minValue: 0.01 69 | parameterName: lr 70 | scalingType: LOG 71 | type: DOUBLE 72 | - maxValue: 0.0005 73 | minValue: 0.0001 74 | parameterName: weight_decay 75 | scalingType: LOG 76 | type: DOUBLE 77 | -------------------------------------------------------------------------------- /autogl/module/nas/estimator/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base estimator of NAS 3 | """ 4 | 5 | from abc import abstractmethod 6 | from ..space import BaseSpace 7 | from typing import Tuple 8 | from ...train.evaluation import Evaluation, Acc 9 | import torch.nn.functional as F 10 | import torch 11 | 12 | 13 | class BaseEstimator: 14 | """ 15 | The estimator of NAS model. 16 | 17 | Parameters 18 | ---------- 19 | loss_f: callable 20 | Default loss function for evaluation 21 | 22 | evaluation: list of autogl.module.train.evaluation.Evaluation 23 | Default evaluation metric 24 | """ 25 | 26 | def __init__(self, loss_f: str = "nll_loss", evaluation=[Acc()]): 27 | self.loss_f = loss_f 28 | self.evaluation = evaluation 29 | 30 | def setLossFunction(self, loss_f: str): 31 | self.loss_f = loss_f 32 | 33 | def setEvaluation(self, evaluation): 34 | self.evaluation = evaluation 35 | 36 | @abstractmethod 37 | def infer( 38 | self, model: BaseSpace, dataset, mask="train" 39 | ) -> Tuple[torch.Tensor, torch.Tensor]: 40 | """ 41 | Calculate the loss and metrics of given model on given dataset using 42 | specified masks. 43 | 44 | Parameters 45 | ---------- 46 | model: autogl.module.nas.space.BaseSpace 47 | The model in space. 48 | 49 | dataset: autogl.dataset 50 | The dataset to perform infer 51 | 52 | mask: str 53 | The mask to evalute on dataset 54 | 55 | Return 56 | ------ 57 | metrics: list of float 58 | the metrics on given datasets. 59 | loss: torch.Tensor 60 | the loss on given datasets. Note that loss should be differentiable. 61 | """ 62 | raise NotImplementedError() 63 | -------------------------------------------------------------------------------- /configs/graphclf_gin_diffpool_benchmark.yaml: -------------------------------------------------------------------------------- 1 | hpo: 2 | max_evals: 10 3 | name: tpe 4 | models: 5 | - encoder: 6 | name: gin 7 | hp_space: 8 | - parameterName: num_layers 9 | type: DISCRETE 10 | feasiblePoints: '3,4,5' 11 | 12 | - parameterName: hidden 13 | type: NUMERICAL_LIST 14 | numericalType: INTEGER 15 | length: 5 16 | minValue: [8, 8, 8, 8, 8] 17 | maxValue: [64, 64, 64, 64, 64] 18 | scalingType: LOG 19 | cutPara: ["num_layers"] 20 | cutFunc: "lambda x: x[0] - 1" 21 | 22 | - parameterName: dropout 23 | type: DOUBLE 24 | maxValue: 0.9 25 | minValue: 0.1 26 | scalingType: LINEAR 27 | 28 | - parameterName: act 29 | type: CATEGORICAL 30 | feasiblePoints: 31 | - leaky_relu 32 | - relu 33 | - elu 34 | - tanh 35 | 36 | - parameterName: eps 37 | type: CATEGORICAL 38 | feasiblePoints: 39 | - "true" 40 | - "false" 41 | 42 | - parameterName: mlp_layers 43 | type: DISCRETE 44 | feasiblePoints: '2,3,4' 45 | 46 | decoder: 47 | name: topk 48 | trainer: 49 | hp_space: 50 | - maxValue: 300 51 | minValue: 10 52 | parameterName: max_epoch 53 | scalingType: LINEAR 54 | type: INTEGER 55 | - maxValue: 30 56 | minValue: 10 57 | parameterName: early_stopping_round 58 | scalingType: LINEAR 59 | type: INTEGER 60 | - maxValue: 0.1 61 | minValue: 0.0001 62 | parameterName: lr 63 | scalingType: LOG 64 | type: DOUBLE 65 | - maxValue: 0.005 66 | minValue: 5.0e-05 67 | parameterName: weight_decay 68 | scalingType: LOG 69 | type: DOUBLE 70 | - maxValue: 128 71 | minValue: 48 72 | parameterName: batch_size 73 | scalingType: LINEAR 74 | type: INTEGER 75 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/early_stop_descending_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django.test import TestCase 4 | 5 | from suggestion.models import Study 6 | from suggestion.models import Trial 7 | from suggestion.models import TrialMetric 8 | from suggestion.early_stop_algorithm.early_stop_descending import ( 9 | EarlyStopDescendingAlgorithm, 10 | ) 11 | 12 | 13 | class EarlyStopDescendingAlgorithmTest(TestCase): 14 | def setUp(self): 15 | study_configuration_json = { 16 | "goal": "MAXIMIZE", 17 | "maxTrials": 5, 18 | "maxParallelTrials": 1, 19 | "params": [ 20 | { 21 | "parameterName": "hidden1", 22 | "type": "INTEGER", 23 | "minValue": 40, 24 | "maxValue": 400, 25 | "scalingType": "LINEAR", 26 | } 27 | ], 28 | } 29 | study_configuration = json.dumps(study_configuration_json) 30 | self.study = Study.create("RandomSearchStudy", study_configuration) 31 | trial1 = Trial.create(self.study.id, "RandomSearchTrial1") 32 | trial2 = Trial.create(self.study.id, "RandomSearchTrial2") 33 | self.trials = [trial1, trial2] 34 | TrialMetric.create(trial1.id, 10, 0.5) 35 | TrialMetric.create(trial1.id, 20, 0.6) 36 | TrialMetric.create(trial2.id, 10, 0.6) 37 | TrialMetric.create(trial2.id, 20, 0.5) 38 | 39 | def tearDown(self): 40 | pass 41 | 42 | # Test EarlyStopDescendingAlgorithm 43 | def test_get_early_stop_trials1(self): 44 | algorithm = EarlyStopDescendingAlgorithm() 45 | early_stop_trials = algorithm.get_early_stop_trials(self.trials) 46 | self.assertEqual(len(early_stop_trials), 1) 47 | self.assertEqual(early_stop_trials[0].name, "RandomSearchTrial2") 48 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/early_stop_algorithm/early_stop_first_trial_test.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from django.test import TestCase 4 | 5 | from suggestion.models import Study 6 | from suggestion.models import Trial 7 | from suggestion.models import TrialMetric 8 | from suggestion.early_stop_algorithm.early_stop_first_trial import ( 9 | EarlyStopFirstTrialAlgorithm, 10 | ) 11 | 12 | 13 | class EarlyStopFirstTrialAlgorithmTest(TestCase): 14 | def setUp(self): 15 | study_configuration_json = { 16 | "goal": "MAXIMIZE", 17 | "maxTrials": 5, 18 | "maxParallelTrials": 1, 19 | "params": [ 20 | { 21 | "parameterName": "hidden1", 22 | "type": "INTEGER", 23 | "minValue": 40, 24 | "maxValue": 400, 25 | "scalingType": "LINEAR", 26 | } 27 | ], 28 | } 29 | study_configuration = json.dumps(study_configuration_json) 30 | self.study = Study.create("RandomSearchStudy", study_configuration) 31 | trial1 = Trial.create(self.study.id, "RandomSearchTrial1") 32 | trial2 = Trial.create(self.study.id, "RandomSearchTrial2") 33 | self.trials = [trial1, trial2] 34 | TrialMetric.create(trial1.id, 10, 0.5) 35 | TrialMetric.create(trial1.id, 20, 0.6) 36 | TrialMetric.create(trial2.id, 10, 0.6) 37 | TrialMetric.create(trial2.id, 20, 0.5) 38 | 39 | def tearDown(self): 40 | pass 41 | 42 | # Test EarlyStopFirstTrialAlgorithm 43 | def test_get_early_stop_trials1(self): 44 | algorithm = EarlyStopFirstTrialAlgorithm() 45 | early_stop_trials = algorithm.get_early_stop_trials(self.trials) 46 | self.assertEqual(len(early_stop_trials), 1) 47 | self.assertEqual(early_stop_trials[0].name, "RandomSearchTrial1") 48 | -------------------------------------------------------------------------------- /autogl/module/nas/space/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import os 3 | from .base import BaseSpace 4 | 5 | NAS_SPACE_DICT = {} 6 | 7 | 8 | def register_nas_space(name): 9 | def register_nas_space_cls(cls): 10 | if name in NAS_SPACE_DICT: 11 | raise ValueError("Cannot register duplicate NAS space ({})".format(name)) 12 | if not issubclass(cls, BaseSpace): 13 | raise ValueError( 14 | "Model ({}: {}) must extend NAS space".format(name, cls.__name__) 15 | ) 16 | NAS_SPACE_DICT[name] = cls 17 | return cls 18 | 19 | return register_nas_space_cls 20 | 21 | 22 | from .graph_nas_macro import GraphNasMacroNodeClassificationSpace 23 | from .graph_nas import GraphNasNodeClassificationSpace 24 | from .single_path import SinglePathNodeClassificationSpace 25 | from ..backend import * 26 | if not is_dgl(): 27 | from .gasso import GassoSpace 28 | from .autoattend import AutoAttendNodeClassificationSpace 29 | from .grna import GRNASpace 30 | 31 | def build_nas_space_from_name(name: str) -> BaseSpace: 32 | """ 33 | Parameters 34 | ---------- 35 | name: ``str`` 36 | the name of nas space. 37 | 38 | Returns 39 | ------- 40 | BaseSpace: 41 | the NAS space built using default parameters 42 | 43 | Raises 44 | ------ 45 | AssertionError 46 | If an invalid name is passed in 47 | """ 48 | assert name in NAS_SPACE_DICT, "HPO module do not have name " + name 49 | return NAS_SPACE_DICT[name]() 50 | 51 | 52 | __all__ = [ 53 | "BaseSpace", 54 | "GraphNasMacroNodeClassificationSpace", 55 | "GraphNasNodeClassificationSpace", 56 | "SinglePathNodeClassificationSpace", 57 | ] 58 | 59 | if not is_dgl(): 60 | __all__.append("GassoSpace") 61 | __all__.append("GRNASpace") 62 | __all__.append("AutoAttendNodeClassificationSpace") 63 | 64 | -------------------------------------------------------------------------------- /autogl/module/feature/_feature_engineer_registry.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | from autogl.utils import universal_registry 3 | from ._base_feature_engineer import BaseFeatureEngineer 4 | 5 | 6 | class _FeatureEngineerUniversalRegistryMetaclass(type): 7 | def __new__( 8 | mcs, name: str, bases: _typing.Tuple[type, ...], 9 | namespace: _typing.Dict[str, _typing.Any] 10 | ): 11 | return super(_FeatureEngineerUniversalRegistryMetaclass, mcs).__new__( 12 | mcs, name, bases, namespace 13 | ) 14 | 15 | def __init__( 16 | cls, name: str, bases: _typing.Tuple[type, ...], 17 | namespace: _typing.Dict[str, _typing.Any] 18 | ): 19 | super(_FeatureEngineerUniversalRegistryMetaclass, cls).__init__( 20 | name, bases, namespace 21 | ) 22 | cls._feature_engineer_universal_registry: _typing.MutableMapping[ 23 | str, _typing.Type[BaseFeatureEngineer] 24 | ] = {} 25 | 26 | 27 | class FeatureEngineerUniversalRegistry(universal_registry.UniversalRegistryBase): 28 | @classmethod 29 | def register_feature_engineer(cls, name: str) -> _typing.Callable[ 30 | [_typing.Type[BaseFeatureEngineer]], _typing.Type[BaseFeatureEngineer] 31 | ]: 32 | def register_fe(fe: _typing.Type[BaseFeatureEngineer]) -> _typing.Type[BaseFeatureEngineer]: 33 | if not issubclass(fe, BaseFeatureEngineer): 34 | raise TypeError 35 | else: 36 | cls[name] = fe 37 | return fe 38 | 39 | return register_fe 40 | 41 | @classmethod 42 | def get_feature_engineer(cls, name: str) -> _typing.Type[BaseFeatureEngineer]: 43 | if name not in cls: 44 | raise ValueError(f"cannot find feature engineer {name}") 45 | else: 46 | return cls[name] 47 | 48 | 49 | FEATURE_DICT = FeatureEngineerUniversalRegistry 50 | -------------------------------------------------------------------------------- /docs/docfile/tutorial_cn/t_ensemble.rst: -------------------------------------------------------------------------------- 1 | .. _ensemble_cn: 2 | 3 | Ensemble 4 | ======== 5 | 6 | 我们现在支持 voting 和 stacking 方法 7 | 8 | Voting 9 | ------ 10 | 11 | Voter本质上构建了base learner预测的加权和。给定一个评估指标,Voter以某种方式确定base learner的权重,使得验证集指标分数最大化。 12 | 13 | 我们采用Rich Caruana的权重确定方法。该方法首先通过贪婪搜索找到权重相等的(可能是冗余的)base learner集合,然后通过集合中出现的次数指定Voter中的权重。 14 | 15 | 您可以通过重写 ``_specificy_weights`` 方法来定制自己的权重确定方法。 16 | 17 | .. code-block :: python 18 | 19 | # 例子: 对所有base learner 使用同样的权重 20 | class EqualWeightVoting(Voting): 21 | def _specify_weights(self, predictions, label, feval): 22 | return np.ones(self.n_models)/self.n_models 23 | # 对所有base learner 赋予相同的权重 24 | 25 | Stacking 26 | -------- 27 | 28 | Stacker将Base Learner的预测作为输入来训练元模型,以找到这些base learner的最佳组合。 29 | 30 | 目前我们支持广义线性模型(GLM)和梯度推进模型(GBM)作为元模型。 31 | 32 | 创建一个新的ensemble 33 | ---------------------- 34 | 35 | 您可以通过继承base ensember,重载``fit``和``ensemble``方法来创建自己的ensember。 36 | 37 | .. code-block :: python 38 | 39 | # 例子 : 使用当前可用的最佳模型 40 | from autogl.module.ensemble.base import BaseEnsembler 41 | import numpy as np 42 | class BestModel(BaseEnsembler): 43 | def fit(self, predictions, label, identifiers, feval): 44 | if not isinstance(feval, list): 45 | feval = [feval] 46 | scores = np.array([feval[0].evaluate(pred, label) for pred in predictions]) * (1 if feval[0].is_higher_better else -1) 47 | self.scores = dict(zip(identifiers, scores)) # record validation score of base learners 48 | ensemble_pred = predictions[np.argmax(scores)] 49 | return [fx.evaluate(ensemble_pred, label) for fx in feval] 50 | 51 | def ensemble(self, predictions, identifiers): 52 | best_idx = np.argmax([self.scores[model_name] for model_name in identifiers]) # choose the currently best model in the identifiers 53 | return predictions[best_idx] 54 | 55 | -------------------------------------------------------------------------------- /autogl/module/hpo/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import os 3 | from .base import BaseHPOptimizer 4 | from .auto_module import AutoModule 5 | 6 | HPO_DICT = {} 7 | 8 | 9 | def register_hpo(name): 10 | def register_hpo_cls(cls): 11 | if name in HPO_DICT: 12 | raise ValueError("Cannot register duplicate HP Optimizer ({})".format(name)) 13 | if not issubclass(cls, BaseHPOptimizer): 14 | raise ValueError( 15 | "Model ({}: {}) must extend HPOptimizer".format(name, cls.__name__) 16 | ) 17 | HPO_DICT[name] = cls 18 | return cls 19 | 20 | return register_hpo_cls 21 | 22 | 23 | from .anneal_advisorhpo import AnnealAdvisorHPO 24 | from .autone import AutoNE 25 | from .bayes_advisor import BayesAdvisor 26 | from .cmaes_advisorchoco import CmaesAdvisorChoco 27 | from .grid_advisor import GridAdvisor 28 | from .mocmaes_advisorchoco import MocmaesAdvisorChoco 29 | from .quasi_advisorchoco import QuasiAdvisorChoco 30 | from .rand_advisor import RandAdvisor 31 | from .tpe_advisorhpo import TpeAdvisorHPO 32 | 33 | 34 | def build_hpo_from_name(name: str) -> BaseHPOptimizer: 35 | """ 36 | Parameters 37 | ---------- 38 | name: ``str`` 39 | the name of hpo module. 40 | 41 | Returns 42 | ------- 43 | BaseHPOptimizer: 44 | the HPO built using default parameters 45 | 46 | Raises 47 | ------ 48 | AssertionError 49 | If an invalid name is passed in 50 | """ 51 | assert name in HPO_DICT, "HPO module do not have name " + name 52 | return HPO_DICT[name]() 53 | 54 | 55 | __all__ = [ 56 | "AutoModule", 57 | "BaseHPOptimizer", 58 | "AnnealAdvisorHPO", 59 | "AutoNE", 60 | "BayesAdvisor", 61 | "CmaesAdvisorChoco", 62 | "GridAdvisor", 63 | "MocmaesAdvisorChoco", 64 | "QuasiAdvisorChoco", 65 | "RandAdvisor", 66 | "TpeAdvisorHPO", 67 | "build_hpo_from_name", 68 | ] 69 | -------------------------------------------------------------------------------- /autogl/module/model/__init__.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import sys 3 | from ...backend import DependentBackend 4 | from . import _utils 5 | 6 | from .decoders import ( 7 | BaseDecoderMaintainer, 8 | DecoderUniversalRegistry, 9 | LogSoftmaxDecoderMaintainer, 10 | DotProductLinkPredictionDecoderMaintainer 11 | ) 12 | 13 | from .encoders import ( 14 | BaseEncoderMaintainer, 15 | AutoHomogeneousEncoderMaintainer, 16 | EncoderUniversalRegistry, 17 | GCNEncoderMaintainer, 18 | GATEncoderMaintainer, 19 | GINEncoderMaintainer, 20 | SAGEEncoderMaintainer 21 | ) 22 | 23 | if DependentBackend.is_dgl(): 24 | from .decoders import ( 25 | TopKDecoderMaintainer, 26 | JKSumPoolDecoderMaintainer 27 | ) 28 | else: 29 | from .decoders import ( 30 | DiffPoolDecoderMaintainer, 31 | SumPoolMLPDecoderMaintainer 32 | ) 33 | 34 | # load corresponding backend model of subclass 35 | def _load_subclass_backend(backend): 36 | sub_module = importlib.import_module(f'.{backend.get_backend_name()}', __name__) 37 | this = sys.modules[__name__] 38 | for api, obj in sub_module.__dict__.items(): 39 | setattr(this, api, obj) 40 | 41 | _load_subclass_backend(DependentBackend) 42 | 43 | __all__.extend([ 44 | "BaseDecoderMaintainer", 45 | "DecoderUniversalRegistry", 46 | "LogSoftmaxDecoderMaintainer", 47 | "DotProductLinkPredictionDecoderMaintainer", 48 | "BaseEncoderMaintainer", 49 | "AutoHomogeneousEncoderMaintainer", 50 | "EncoderUniversalRegistry", 51 | "GCNEncoderMaintainer", 52 | "GATEncoderMaintainer", 53 | "GINEncoderMaintainer", 54 | "SAGEEncoderMaintainer" 55 | ]) 56 | 57 | if DependentBackend.is_dgl(): 58 | __all__.extend([ 59 | "TopKDecoderMaintainer", 60 | "JKSumPoolDecoderMaintainer", 61 | 62 | ]) 63 | else: 64 | __all__.extend([ 65 | "DiffPoolDecoderMaintainer", 66 | "SumPoolMLPDecoderMaintainer" 67 | ]) 68 | -------------------------------------------------------------------------------- /autogl/module/nas/space/autoattend_space/ops1.py: -------------------------------------------------------------------------------- 1 | from .operations import * 2 | 3 | OPS = { 4 | 'ZERO': lambda indim, outdim, dropout, concat=False: Zero(indim, outdim), 5 | 'IDEN': lambda indim, outdim, dropout, concat=False: Identity(), 6 | 'GCN': lambda indim, outdim, dropout, concat=False: GCNConv(indim, outdim, add_self_loops=False), 7 | 'SAGE-MEAN': lambda indim, outdim, dropout, concat=False: SAGEConv(indim, outdim), 8 | 'GAT16': lambda indim, outdim, dropout, concat=False: GATConv(indim, outdim, dropout=dropout, heads=16, concat=False, add_self_loops=False) if not concat else GATConv(indim, outdim // 16, dropout=dropout, heads=16, concat=True, add_self_loops=False), 9 | 'GAT2': lambda indim, outdim, dropout, concat=False: GATConv(indim, outdim, dropout=dropout, heads=2, concat=False, add_self_loops=False) if not concat else GATConv(indim, outdim // 2, dropout=dropout, heads=2, concat=True, add_self_loops=False), 10 | 'GAT4': lambda indim, outdim, dropout, concat=False: GATConv(indim, outdim, dropout=dropout, heads=4, concat=False, add_self_loops=False) if not concat else GATConv(indim, outdim // 4, dropout=dropout, heads=4, concat=True, add_self_loops=False), 11 | 'GAT8': lambda indim, outdim, dropout, concat=False: GATConv(indim, outdim, dropout=dropout, heads=8, concat=False, add_self_loops=False) if not concat else GATConv(indim, outdim // 8, dropout=dropout, heads=8, concat=True, add_self_loops=False), 12 | 'GAT1': lambda indim, outdim, dropout, concat=False: GATConv(indim, outdim, dropout=dropout, heads=1, concat=False, add_self_loops=False), 13 | 'LIN': lambda indim, outdim, dropout, concat=False: Linear(indim, outdim), 14 | 'ARMA': lambda indim, outdim, dropout, concat=False: ARMAConv(indim, outdim), 15 | 'CHEB': lambda indim, outdim, dropout, concat=False: ChebConv(indim, outdim, 2), 16 | 'SGC': lambda indim, outdim, dropout, concat=False: SGConv(indim, outdim, add_self_loops=False) 17 | } 18 | 19 | PRIMITIVES = list(OPS.keys()) 20 | -------------------------------------------------------------------------------- /autogl/solver/classifier/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base solver for classification problems 3 | """ 4 | 5 | from typing import Any 6 | from ..base import BaseSolver 7 | from ...module.ensemble import ENSEMBLE_DICT 8 | from ...module import BaseEnsembler 9 | 10 | 11 | class BaseClassifier(BaseSolver): 12 | """ 13 | Base solver for classification problems 14 | """ 15 | 16 | def predict_proba(self, *args, **kwargs) -> Any: 17 | """ 18 | Predict the node probability. 19 | 20 | Returns 21 | ------- 22 | result: Any 23 | The predicted probability 24 | """ 25 | raise NotImplementedError() 26 | 27 | def set_ensemble_module(self, ensemble_module, *args, **kwargs) -> "BaseClassifier": 28 | """ 29 | Set the ensemble module used in current solver. 30 | 31 | Parameters 32 | ---------- 33 | ensemble_module: autogl.module.ensemble.BaseEnsembler or str or None 34 | The (name of) ensemble module used to ensemble the multi-models found. 35 | Disable ensemble by setting it to ``None``. 36 | 37 | Returns 38 | ------- 39 | self: autogl.solver.BaseSolver 40 | A reference of current solver. 41 | """ 42 | # load ensemble module 43 | if ensemble_module is None: 44 | self.ensemble_module = None 45 | elif isinstance(ensemble_module, BaseEnsembler): 46 | self.ensemble_module = ensemble_module 47 | elif isinstance(ensemble_module, str): 48 | if ensemble_module in ENSEMBLE_DICT: 49 | self.ensemble_module = ENSEMBLE_DICT[ensemble_module](*args, **kwargs) 50 | else: 51 | raise KeyError("cannot find ensemble module %s." % (ensemble_module)) 52 | else: 53 | ValueError( 54 | "need ensemble module to be str or a BaseEnsembler instance, get", 55 | type(ensemble_module), 56 | "instead.", 57 | ) 58 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | import torch 3 | except ModuleNotFoundError: 4 | raise ModuleNotFoundError( 5 | "PyTorch not installed. " 6 | "Please appropriately install PyTorch, " 7 | "see https://pytorch.org/ for installation." 8 | ) 9 | 10 | from setuptools import setup, find_packages 11 | 12 | with open("README.md", 'r') as fh: 13 | long_description = fh.read() 14 | 15 | ''' https://packaging.python.org/guides/distributing-packages-using-setuptools/ ''' 16 | ''' https://setuptools.readthedocs.io/en/latest/ ''' 17 | setup( 18 | name='autogl', 19 | version='0.4.1', 20 | author='THUMNLab/aglteam', 21 | maintainer='THUMNLab/aglteam', 22 | author_email='autogl@tsinghua.edu.cn', 23 | description='AutoML tools for graph-structure dataset', 24 | long_description=long_description, 25 | long_description_content_type='text/markdown', 26 | include_package_data=True, 27 | packages=find_packages(), 28 | # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires 29 | python_requires='~=3.6', 30 | # https://pypi.org/classifiers/ 31 | classifiers=[ 32 | "Development Status :: 4 - Beta", 33 | "License :: OSI Approved :: Apache Software License", 34 | "Programming Language :: Python :: 3 :: Only", 35 | "Programming Language :: Python :: 3.6" 36 | ], 37 | # https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html 38 | # note that setup_requires and tests_require are deprecated 39 | install_requires=[ 40 | 'bayesian-optimization', 41 | 'chocolate', 42 | 'dill', 43 | 'deeprobust', 44 | 'hyperopt', 45 | 'lightgbm', 46 | 'networkx <= 3.1', 47 | 'numpy', 48 | 'numba', 49 | 'netlsd', 50 | 'ogb', 51 | 'psutil', 52 | 'pyyaml', 53 | 'requests', 54 | 'scikit-learn', 55 | 'scipy', 56 | 'tabulate', 57 | 'tqdm', 58 | 'nni==2.8' 59 | ] 60 | ) -------------------------------------------------------------------------------- /autogl/module/feature/__init__.py: -------------------------------------------------------------------------------- 1 | from ._base_feature_engineer import ( 2 | BaseFeatureEngineer, BaseFeature 3 | ) 4 | from ._feature_engineer_registry import ( 5 | FeatureEngineerUniversalRegistry, FEATURE_DICT 6 | ) 7 | from ._generators import ( 8 | OneHotFeatureGenerator, 9 | EigenFeatureGenerator, 10 | GraphletGenerator, 11 | PageRankFeatureGenerator, 12 | LocalDegreeProfileGenerator, 13 | NormalizeFeatures, 14 | OneHotDegreeGenerator 15 | ) 16 | from ._graph import ( 17 | NetLSD, 18 | NXLargeCliqueSize, 19 | NXDegreeAssortativityCoefficient, 20 | NXDegreePearsonCorrelationCoefficient, 21 | NXHasBridges, 22 | NXGraphCliqueNumber, 23 | NXGraphNumberOfCliques, 24 | NXTransitivity, 25 | NXAverageClustering, 26 | NXIsConnected, 27 | NXNumberConnectedComponents, 28 | NXIsDistanceRegular, 29 | NXLocalEfficiency, 30 | NXGlobalEfficiency, 31 | NXIsEulerian, 32 | ) 33 | from ._selectors import ( 34 | FilterConstant, GBDTFeatureSelector 35 | ) 36 | from ._auto_feature import ( 37 | IdentityFeature, OnlyConstFeature, AutoFeatureEngineer 38 | ) 39 | 40 | __all__ = [ 41 | "BaseFeatureEngineer", 42 | "BaseFeature", 43 | "FeatureEngineerUniversalRegistry", 44 | "OneHotFeatureGenerator", 45 | "EigenFeatureGenerator", 46 | "GraphletGenerator", 47 | "PageRankFeatureGenerator", 48 | "LocalDegreeProfileGenerator", 49 | "NormalizeFeatures", 50 | "OneHotDegreeGenerator", 51 | "NetLSD", 52 | "NXLargeCliqueSize", 53 | "NXDegreeAssortativityCoefficient", 54 | "NXDegreePearsonCorrelationCoefficient", 55 | "NXHasBridges", 56 | "NXGraphCliqueNumber", 57 | "NXGraphNumberOfCliques", 58 | "NXTransitivity", 59 | "NXAverageClustering", 60 | "NXIsConnected", 61 | "NXNumberConnectedComponents", 62 | "NXIsDistanceRegular", 63 | "NXLocalEfficiency", 64 | "NXGlobalEfficiency", 65 | "NXIsEulerian", 66 | "FilterConstant", 67 | "GBDTFeatureSelector", 68 | "IdentityFeature", 69 | "OnlyConstFeature", 70 | "AutoFeatureEngineer" 71 | ] -------------------------------------------------------------------------------- /autogl/solver/classifier/ssl/utils.py: -------------------------------------------------------------------------------- 1 | from ....module.model import EncoderUniversalRegistry, DecoderUniversalRegistry, ModelUniversalRegistry 2 | 3 | def _parse_hp_space(spaces): 4 | if spaces is None: 5 | return None 6 | for space in spaces: 7 | if "cutFunc" in space and isinstance(space["cutFunc"], str): 8 | space["cutFunc"] = eval(space["cutFunc"]) 9 | return spaces 10 | 11 | def _parse_model_hp(model): 12 | assert isinstance(model, dict) 13 | if "encoder" in model and "decoder" in model: 14 | if "prediction_head" in model: 15 | return { 16 | "encoder": _parse_hp_space(model["encoder"].pop("hp_space", None)), 17 | "decoder": _parse_hp_space(model["decoder"].pop("hp_space", None)), 18 | "prediction_head": _parse_hp_space(model["prediction_head"].pop("hp_space", None)) 19 | } 20 | else: 21 | return { 22 | "encoder": _parse_hp_space(model["encoder"].pop("hp_space", None)), 23 | "decoder": _parse_hp_space(model["decoder"].pop("hp_space", None)), 24 | } 25 | elif "encoder" in model: 26 | return { 27 | "encoder": _parse_hp_space(model["encoder"].pop("hp_space", None)), 28 | "decoder": None, 29 | } 30 | else: 31 | return _parse_hp_space(model.pop("hp_space", None)) 32 | 33 | def _initialize_single_model(model): 34 | encoder, decoder = None, None 35 | if "encoder" in model: 36 | # initialize encoder 37 | name = model["encoder"].pop("name") 38 | encoder = EncoderUniversalRegistry.get_encoder(name)(**model["encoder"]) 39 | if "decoder" in model: 40 | # initialize decoder 41 | name = model["decoder"].pop("name") 42 | decoder = DecoderUniversalRegistry.get_decoder(name)(**model["decoder"]) 43 | return (encoder, decoder) 44 | 45 | if "name" in model: 46 | # whole model 47 | name = model.pop("name") 48 | encoder = ModelUniversalRegistry.get_model(name)(**model) 49 | return encoder 50 | -------------------------------------------------------------------------------- /autogl/module/model/decoders/base_decoder.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import typing as _typing 3 | from ...hpo import AutoModule 4 | from ..encoders import base_encoder 5 | 6 | 7 | class BaseDecoderMaintainer(AutoModule): 8 | def _initialize( 9 | self, encoder: base_encoder.AutoHomogeneousEncoderMaintainer, *args, **kwargs 10 | ) -> _typing.Optional[bool]: 11 | """ Abstract initialization method to override """ 12 | raise NotImplementedError 13 | 14 | def from_hyper_parameter_and_encoder( 15 | self, hp: _typing.Mapping[str, _typing.Any], 16 | encoder: base_encoder.BaseEncoderMaintainer 17 | ) -> 'BaseDecoderMaintainer': 18 | duplicate = self.__class__( 19 | self.output_dimension, self.device 20 | ) 21 | new_hp = dict(self.hyper_parameters) 22 | new_hp.update(hp) 23 | duplicate.hyper_parameters = new_hp 24 | duplicate.initialize(encoder) 25 | return duplicate 26 | 27 | def __init__( 28 | self, output_dimension: _typing.Optional[int] = ..., 29 | device: _typing.Union[torch.device, str, int, None] = ..., 30 | *args, **kwargs 31 | ): 32 | super(BaseDecoderMaintainer, self).__init__( 33 | device, *args, **kwargs 34 | ) 35 | self.output_dimension = output_dimension 36 | self._decoder: _typing.Optional[torch.nn.Module] = None 37 | 38 | @property 39 | def output_dimension(self): 40 | return self.__output_dimension 41 | 42 | @output_dimension.setter 43 | def output_dimension(self, output_dimension): 44 | self.__output_dimension = output_dimension 45 | 46 | @property 47 | def decoder(self) -> _typing.Optional[torch.nn.Module]: 48 | return self._decoder 49 | 50 | def to_device(self, device: _typing.Union[torch.device, str, int, None]): 51 | self.device = device 52 | if ( 53 | self._decoder not in (Ellipsis, None) and 54 | isinstance(self._decoder, torch.nn.Module) 55 | ): 56 | self._decoder.to(self.device) 57 | -------------------------------------------------------------------------------- /configs/nodeclf_full.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: voting 3 | size: 2 4 | feature: 5 | - name: PYGNormalizeFeatures 6 | hpo: 7 | max_evals: 50 8 | name: tpe 9 | models: 10 | - hp_space: 11 | - feasiblePoints: '2' 12 | parameterName: num_layers 13 | type: DISCRETE 14 | - feasiblePoints: 6,8,10,12 15 | parameterName: heads 16 | type: DISCRETE 17 | - cutFunc: lambda x:x[0] - 1 18 | cutPara: 19 | - num_layers 20 | length: 1 21 | maxValue: 22 | - 16 23 | minValue: 24 | - 4 25 | numericalType: INTEGER 26 | parameterName: hidden 27 | scalingType: LOG 28 | type: NUMERICAL_LIST 29 | - maxValue: 0.8 30 | minValue: 0.2 31 | parameterName: dropout 32 | scalingType: LINEAR 33 | type: DOUBLE 34 | - feasiblePoints: 35 | - leaky_relu 36 | - relu 37 | - elu 38 | - tanh 39 | parameterName: act 40 | type: CATEGORICAL 41 | name: gat 42 | - hp_space: 43 | - feasiblePoints: '2' 44 | parameterName: num_layers 45 | type: DISCRETE 46 | - cutFunc: lambda x:x[0] - 1 47 | cutPara: 48 | - num_layers 49 | length: 1 50 | maxValue: 51 | - 64 52 | minValue: 53 | - 16 54 | numericalType: INTEGER 55 | parameterName: hidden 56 | scalingType: LOG 57 | type: NUMERICAL_LIST 58 | - maxValue: 0.8 59 | minValue: 0.2 60 | parameterName: dropout 61 | scalingType: LINEAR 62 | type: DOUBLE 63 | - feasiblePoints: 64 | - leaky_relu 65 | - relu 66 | - elu 67 | - tanh 68 | parameterName: act 69 | type: CATEGORICAL 70 | name: gcn 71 | trainer: 72 | hp_space: 73 | - maxValue: 300 74 | minValue: 100 75 | parameterName: max_epoch 76 | scalingType: LINEAR 77 | type: INTEGER 78 | - maxValue: 30 79 | minValue: 10 80 | parameterName: early_stopping_round 81 | scalingType: LINEAR 82 | type: INTEGER 83 | - maxValue: 0.05 84 | minValue: 0.01 85 | parameterName: lr 86 | scalingType: LOG 87 | type: DOUBLE 88 | - maxValue: 0.001 89 | minValue: 0.0001 90 | parameterName: weight_decay 91 | scalingType: LOG 92 | type: DOUBLE 93 | 94 | -------------------------------------------------------------------------------- /configs/graphclf_full.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: voting 3 | size: 2 4 | hpo: 5 | max_evals: 10 6 | name: anneal 7 | models: 8 | - hp_space: 9 | - parameterName: num_layers 10 | type: DISCRETE 11 | feasiblePoints: '3,4,5' 12 | 13 | - parameterName: hidden 14 | type: NUMERICAL_LIST 15 | numericalType: INTEGER 16 | length: 5 17 | minValue: [8, 8, 8, 8, 8] 18 | maxValue: [64, 64, 64, 64, 64] 19 | scalingType: LOG 20 | cutPara: ["num_layers"] 21 | cutFunc: "lambda x: x[0] - 1" 22 | 23 | - parameterName: dropout 24 | type: DOUBLE 25 | maxValue: 0.9 26 | minValue: 0.1 27 | scalingType: LINEAR 28 | 29 | - parameterName: act 30 | type: CATEGORICAL 31 | feasiblePoints: 32 | - leaky_relu 33 | - relu 34 | - elu 35 | - tanh 36 | 37 | - parameterName: eps 38 | type: CATEGORICAL 39 | feasiblePoints: 40 | - True 41 | - False 42 | 43 | - parameterName: mlp_layers 44 | type: DISCRETE 45 | feasiblePoints: '2,3,4' 46 | name: gin-model 47 | - hp_space: 48 | - maxValue: 0.9 49 | minValue: 0.1 50 | parameterName: ratio 51 | scalingType: LINEAR 52 | type: DOUBLE 53 | - maxValue: 0.9 54 | minValue: 0.1 55 | parameterName: dropout 56 | scalingType: LINEAR 57 | type: DOUBLE 58 | - feasiblePoints: 59 | - leaky_relu 60 | - relu 61 | - elu 62 | - tanh 63 | parameterName: act 64 | type: CATEGORICAL 65 | name: topkpool-model 66 | trainer: 67 | hp_space: 68 | - maxValue: 300 69 | minValue: 10 70 | parameterName: max_epoch 71 | scalingType: LINEAR 72 | type: INTEGER 73 | - maxValue: 30 74 | minValue: 10 75 | parameterName: early_stopping_round 76 | scalingType: LINEAR 77 | type: INTEGER 78 | - maxValue: 0.1 79 | minValue: 0.0001 80 | parameterName: lr 81 | scalingType: LOG 82 | type: DOUBLE 83 | - maxValue: 0.005 84 | minValue: 5.0e-05 85 | parameterName: weight_decay 86 | scalingType: LOG 87 | type: DOUBLE 88 | - maxValue: 128 89 | minValue: 48 90 | parameterName: batch_size 91 | scalingType: LINEAR 92 | type: INTEGER 93 | -------------------------------------------------------------------------------- /autogl/module/hpo/suggestion/algorithm/util.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | class AlgorithmUtil: 5 | """ 6 | The implementation is based on https://github.com/tobegit3hub/advisor 7 | """ 8 | 9 | @staticmethod 10 | def get_random_value(min_value, max_value): 11 | """ 12 | Get the random value from given min and max values. 13 | 14 | Args: 15 | min_value: The min value. 16 | max_value: The max value. 17 | 18 | Return: 19 | The random value between min and max values. 20 | """ 21 | return random.uniform(min_value, max_value) 22 | 23 | @staticmethod 24 | def get_random_int_value(min_value, max_value): 25 | """ 26 | Get the random int value from given min and max values. 27 | 28 | Args: 29 | min_value: The min value. 30 | max_value: The max value. 31 | 32 | Return: 33 | The random int value between min and max values. 34 | """ 35 | return int(random.uniform(min_value, max_value)) 36 | 37 | @staticmethod 38 | def get_closest_value_in_list(input_list, objective_value): 39 | """ 40 | Return the closet value for the objective value in the list. 41 | 42 | Args: 43 | input_list: Example: [-1.5, 1.5, 2.5, 4.5] 44 | objective_value: Example: 1.1 45 | 46 | Return: 47 | Example: 1.5 48 | """ 49 | closest_value = input_list[0] 50 | cloeset_value_abs = abs(closest_value - objective_value) 51 | 52 | for current_value in input_list: 53 | current_value_abs = abs(current_value - objective_value) 54 | if current_value_abs < cloeset_value_abs: 55 | closest_value = current_value 56 | cloeset_value_abs = current_value_abs 57 | 58 | return closest_value 59 | 60 | @staticmethod 61 | def get_random_item_from_list(input_list): 62 | """ 63 | Get the random item from given list. 64 | 65 | Args: 66 | input_list: The list. 67 | 68 | Return: 69 | The random item. 70 | """ 71 | return random.choice(input_list) 72 | -------------------------------------------------------------------------------- /test/performance/heterogeneous/dgl/solver.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from autogl.datasets import build_dataset_from_name 3 | from autogl.solver import AutoHeteroNodeClassifier 4 | from helper import get_encoder_decoder_hp 5 | from tqdm import tqdm 6 | 7 | def fixed(**kwargs): 8 | return [{ 9 | 'parameterName': k, 10 | "type": "FIXED", 11 | "value": v 12 | } for k, v in kwargs.items()] 13 | 14 | if __name__ == '__main__': 15 | import argparse 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument("--model", type=str, choices=["han", "hgt", "HeteroRGCN"], default="hgt") 18 | parser.add_argument("--epoch", type=int, default=200) 19 | parser.add_argument("--lr", type=float, default=1e-3) 20 | parser.add_argument("--weight_decay", type=float, default=1e-2) 21 | parser.add_argument("--device", type=str, default="cuda") 22 | parser.add_argument("--repeat", type=int, default=10) 23 | 24 | args = parser.parse_args() 25 | 26 | dataset = { 27 | "han": "hetero-acm-han", 28 | "hgt": "hetero-acm-hgt", 29 | "HeteroRGCN": "hetero-acm-hgt" 30 | } 31 | 32 | dataset = build_dataset_from_name(dataset[args.model]) 33 | 34 | model_hp, _ = get_encoder_decoder_hp(args.model) 35 | 36 | accs = [] 37 | process = tqdm(total=args.repeat) 38 | for rep in range(args.repeat): 39 | solver = AutoHeteroNodeClassifier( 40 | graph_models=[args.model], 41 | hpo_module="random", 42 | ensemble_module=None, 43 | max_evals=1, 44 | device=args.device, 45 | trainer_hp_space=fixed( 46 | max_epoch=args.epoch, 47 | early_stopping_round=args.epoch + 1, 48 | lr=args.lr, 49 | weight_decay=args.weight_decay 50 | ), 51 | model_hp_spaces=[fixed(**model_hp)] 52 | ) 53 | solver.fit(dataset) 54 | acc = solver.evaluate() 55 | accs.append(acc) 56 | process.update(1) 57 | process.set_postfix(mean=np.mean(accs), std=np.std(accs)) 58 | process.close() 59 | print("mean: {:.4f} ~ std: {:.4f}".format(np.mean(accs), np.std(accs))) 60 | -------------------------------------------------------------------------------- /configs/pyg/lp_benchmark.yml: -------------------------------------------------------------------------------- 1 | ensemble: 2 | name: voting 3 | feature: 4 | - name: NormalizeFeatures 5 | hpo: 6 | max_evals: 10 7 | name: random 8 | models: 9 | - encoder: 10 | hp_space: 11 | - feasiblePoints: 2,3 12 | parameterName: num_layers 13 | type: DISCRETE 14 | - cutFunc: lambda x:x[0] - 1 15 | cutPara: 16 | - num_layers 17 | length: 2 18 | maxValue: 19 | - 256 20 | - 256 21 | minValue: 22 | - 64 23 | - 64 24 | numericalType: INTEGER 25 | parameterName: hidden 26 | scalingType: LOG 27 | type: NUMERICAL_LIST 28 | - maxValue: 0.2 29 | minValue: 0.0 30 | parameterName: dropout 31 | scalingType: LINEAR 32 | type: DOUBLE 33 | - feasiblePoints: 34 | - leaky_relu 35 | - relu 36 | - elu 37 | - tanh 38 | parameterName: act 39 | type: CATEGORICAL 40 | name: gcn 41 | - encoder: 42 | name: gat 43 | hp_space: 44 | - feasiblePoints: 2,3 45 | parameterName: num_layers 46 | type: DISCRETE 47 | - cutFunc: lambda x:x[0] - 1 48 | cutPara: 49 | - num_layers 50 | length: 2 51 | maxValue: 52 | - 256 53 | - 256 54 | minValue: 55 | - 64 56 | - 64 57 | numericalType: INTEGER 58 | parameterName: hidden 59 | scalingType: LOG 60 | type: NUMERICAL_LIST 61 | - maxValue: 0.2 62 | minValue: 0.0 63 | parameterName: dropout 64 | scalingType: LINEAR 65 | type: DOUBLE 66 | - feasiblePoints: 67 | - leaky_relu 68 | - relu 69 | - elu 70 | - tanh 71 | parameterName: act 72 | type: CATEGORICAL 73 | trainer: 74 | hp_space: 75 | - maxValue: 150 76 | minValue: 50 77 | parameterName: max_epoch 78 | scalingType: LINEAR 79 | type: INTEGER 80 | - maxValue: 40 81 | minValue: 25 82 | parameterName: early_stopping_round 83 | scalingType: LINEAR 84 | type: INTEGER 85 | - maxValue: 0.05 86 | minValue: 0.005 87 | parameterName: lr 88 | scalingType: LOG 89 | type: DOUBLE 90 | - maxValue: 1.0E-7 91 | minValue: 1.0E-10 92 | parameterName: weight_decay 93 | scalingType: LOG 94 | type: DOUBLE 95 | -------------------------------------------------------------------------------- /autogl/datasets/_data_source.py: -------------------------------------------------------------------------------- 1 | import os 2 | import typing as _typing 3 | 4 | 5 | class OnlineDataSource: 6 | @property 7 | def _raw_directory(self) -> str: 8 | return os.path.join(self.__path, "raw") 9 | 10 | @property 11 | def _processed_directory(self) -> str: 12 | return os.path.join(self.__path, "processed") 13 | 14 | @property 15 | def _raw_filenames(self) -> _typing.Iterable[str]: 16 | raise NotImplementedError 17 | 18 | @property 19 | def _processed_filenames(self) -> _typing.Iterable[str]: 20 | raise NotImplementedError 21 | 22 | @property 23 | def _raw_file_paths(self) -> _typing.Iterable[str]: 24 | return [ 25 | os.path.join(self._raw_directory, raw_filename) 26 | for raw_filename in self._raw_filenames 27 | ] 28 | 29 | @property 30 | def _processed_file_paths(self) -> _typing.Iterable[str]: 31 | return [ 32 | os.path.join(self._processed_directory, processed_filename) 33 | for processed_filename in self._processed_filenames 34 | ] 35 | 36 | @classmethod 37 | def __files_exist(cls, files: _typing.Iterable[str]) -> bool: 38 | return all([os.path.exists(file) for file in files]) 39 | 40 | @classmethod 41 | def __make_directory(cls, path): 42 | os.makedirs(os.path.expanduser(os.path.normpath(path)), exist_ok=True) 43 | 44 | def _fetch(self): 45 | raise NotImplementedError 46 | 47 | def __fetch(self): 48 | if not self.__files_exist(self._raw_file_paths): 49 | self.__make_directory(self._raw_directory) 50 | self._fetch() 51 | 52 | def _process(self): 53 | raise NotImplementedError 54 | 55 | def __preprocess(self): 56 | if not self.__files_exist(self._processed_file_paths): 57 | self.__make_directory(self._processed_directory) 58 | self._process() 59 | 60 | def __getitem__(self, index: int) -> _typing.Any: 61 | raise NotImplementedError 62 | 63 | def __len__(self) -> int: 64 | raise NotImplementedError 65 | 66 | def __init__(self, path: str): 67 | self.__path: str = os.path.expanduser(os.path.normpath(path)) 68 | self.__fetch() 69 | self.__preprocess() 70 | -------------------------------------------------------------------------------- /test/performance/heterogeneous/dgl/helper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pickle 3 | 4 | class EarlyStopping(object): 5 | def __init__(self, patience=10): 6 | self.patience = patience 7 | self.counter = 0 8 | self.best_acc = None 9 | self.best_loss = None 10 | self.early_stop = False 11 | self.model = None 12 | 13 | def step(self, loss, acc, model): 14 | if self.best_loss is None: 15 | self.best_acc = acc 16 | self.best_loss = loss 17 | self.save_checkpoint(model) 18 | elif (loss > self.best_loss) and (acc < self.best_acc): 19 | self.counter += 1 20 | print(f'EarlyStopping counter: {self.counter} out of {self.patience}') 21 | if self.counter >= self.patience: 22 | self.early_stop = True 23 | else: 24 | if (loss <= self.best_loss) and (acc >= self.best_acc): 25 | self.save_checkpoint(model) 26 | self.best_loss = np.min((loss, self.best_loss)) 27 | self.best_acc = np.max((acc, self.best_acc)) 28 | self.counter = 0 29 | return self.early_stop 30 | 31 | def save_checkpoint(self, model): 32 | """Saves model when validation loss decreases.""" 33 | self.model = pickle.dumps(model.state_dict()) 34 | 35 | def load_checkpoint(self, model): 36 | """Load the latest checkpoint.""" 37 | model.load_state_dict(pickle.loads(self.model)) 38 | 39 | def get_encoder_decoder_hp(model='han'): 40 | if model == "han": 41 | return { 42 | "num_layers": 2, 43 | "hidden": [256], ## 44 | "heads": [8], ## 45 | "dropout": 0.2, 46 | "act": "gelu", 47 | }, None 48 | if model == "hgt": 49 | return { 50 | "num_layers": 2, 51 | "hidden": [256,256,256], 52 | "heads": 4, 53 | "dropout": 0.2, 54 | "act": "gelu", 55 | "use_norm": True, 56 | }, None 57 | if model == "HeteroRGCN": 58 | return { 59 | "num_layers": 2, 60 | "hidden": [256], 61 | "heads": 4, 62 | "dropout": 0.2, 63 | "act": "leaky_relu", 64 | }, None 65 | return {}, None -------------------------------------------------------------------------------- /autogl/data/graph/_general_static_graph/_canonical_edge_type.py: -------------------------------------------------------------------------------- 1 | import typing as _typing 2 | 3 | 4 | class CanonicalEdgeType(_typing.Sequence[str]): 5 | def __init__(self, source_node_type: str, relation_type: str, target_node_type: str): 6 | if not isinstance(source_node_type, str): 7 | raise TypeError 8 | elif ' ' in source_node_type: 9 | raise ValueError 10 | if not isinstance(relation_type, str): 11 | raise TypeError 12 | elif ' ' in relation_type: 13 | raise ValueError 14 | if not isinstance(target_node_type, str): 15 | raise TypeError 16 | elif ' ' in target_node_type: 17 | raise ValueError 18 | self.__source_node_type: str = source_node_type 19 | self.__relation_type: str = relation_type 20 | self.__destination_node_type: str = target_node_type 21 | 22 | @property 23 | def source_node_type(self) -> str: 24 | return self.__source_node_type 25 | 26 | @property 27 | def relation_type(self) -> str: 28 | return self.__relation_type 29 | 30 | @property 31 | def target_node_type(self) -> str: 32 | return self.__destination_node_type 33 | 34 | def __eq__(self, other): 35 | if not (isinstance(other, CanonicalEdgeType) or isinstance(other, _typing.Sequence)): 36 | return False 37 | elif isinstance(other, _typing.Sequence): 38 | if not (len(other) == 3 and all([(isinstance(t, str) and ' ' not in t) for t in other])): 39 | raise TypeError 40 | return ( 41 | other[0] == self.source_node_type and 42 | other[1] == self.relation_type and 43 | other[2] == self.target_node_type 44 | ) 45 | elif isinstance(other, CanonicalEdgeType): 46 | return ( 47 | other.source_node_type == self.source_node_type and 48 | other.relation_type == self.relation_type and 49 | other.target_node_type == self.target_node_type 50 | ) 51 | 52 | def __getitem__(self, index: int): 53 | return (self.source_node_type, self.relation_type, self.target_node_type)[index] 54 | 55 | def __len__(self) -> int: 56 | return 3 57 | -------------------------------------------------------------------------------- /autogl/module/feature/_base_feature_engineer/_base_feature_engineer_dgl.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import torch 3 | import typing as _typing 4 | import dgl 5 | from autogl.data.graph import GeneralStaticGraph 6 | import autogl.data.graph.utils.conversion 7 | from . import _base_feature_engineer 8 | 9 | 10 | class BaseFeatureEngineer( 11 | _base_feature_engineer.BaseFeatureEngineer 12 | ): 13 | @classmethod 14 | def __preprocess( 15 | cls, data: _typing.Union[dgl.DGLGraph, GeneralStaticGraph, _typing.Any] 16 | ) -> _typing.Union[GeneralStaticGraph, _typing.Any]: 17 | if isinstance(data, dgl.DGLGraph): 18 | graph = autogl.data.graph.utils.conversion.dgl_graph_to_general_static_graph(data) 19 | setattr(graph, '_ORIGINAL_TYPE_BEFORE_FE', 'DGLGraph') 20 | return graph 21 | else: 22 | return data 23 | 24 | @classmethod 25 | def __postprocess( 26 | cls, data: _typing.Union[GeneralStaticGraph, _typing.Any] 27 | ) -> _typing.Union[dgl.DGLGraph, GeneralStaticGraph, _typing.Any]: 28 | if ( 29 | isinstance(data, GeneralStaticGraph) and 30 | hasattr(data, '_ORIGINAL_TYPE_BEFORE_FE') and 31 | isinstance(getattr(data, '_ORIGINAL_TYPE_BEFORE_FE'), str) and 32 | getattr(data, '_ORIGINAL_TYPE_BEFORE_FE') == 'DGLGraph' 33 | ): 34 | return autogl.data.graph.utils.conversion.general_static_graph_to_dgl_graph(data) 35 | else: 36 | return data 37 | 38 | def fit(self, dataset): 39 | dataset = copy.deepcopy(dataset) 40 | with torch.no_grad(): 41 | for i, data in enumerate(dataset): 42 | dataset[i] = self.__postprocess( 43 | self._postprocess(self._fit(self._preprocess(self.__preprocess(data)))) 44 | ) 45 | return dataset 46 | 47 | def transform(self, dataset, inplace: bool = True): 48 | if not inplace: 49 | dataset = copy.deepcopy(dataset) 50 | with torch.no_grad(): 51 | for i, data in enumerate(dataset): 52 | dataset[i] = self.__postprocess( 53 | self._postprocess(self._transform(self._preprocess(self.__preprocess(data)))) 54 | ) 55 | return dataset 56 | -------------------------------------------------------------------------------- /autogl/module/train/__init__.py: -------------------------------------------------------------------------------- 1 | from ...backend import DependentBackend 2 | 3 | TRAINER_DICT = {} 4 | from .base import ( 5 | BaseTrainer, 6 | Evaluation, 7 | BaseNodeClassificationTrainer, 8 | BaseGraphClassificationTrainer, 9 | BaseLinkPredictionTrainer, 10 | BaseNodeClassificationHetTrainer 11 | ) 12 | 13 | 14 | def register_trainer(name): 15 | def register_trainer_cls(cls): 16 | if name in TRAINER_DICT: 17 | raise ValueError("Cannot register duplicate trainer ({})".format(name)) 18 | if not issubclass(cls, BaseTrainer): 19 | raise ValueError( 20 | "Trainer ({}: {}) must extend BaseTrainer".format(name, cls.__name__) 21 | ) 22 | TRAINER_DICT[name] = cls 23 | return cls 24 | 25 | return register_trainer_cls 26 | 27 | 28 | from .graph_classification_full import GraphClassificationFullTrainer 29 | from .node_classification_full import NodeClassificationFullTrainer 30 | from .link_prediction_full import LinkPredictionTrainer 31 | from .node_classification_het import NodeClassificationHetTrainer 32 | if DependentBackend.is_pyg(): 33 | from .node_classification_trainer import ( 34 | NodeClassificationGraphSAINTTrainer, 35 | NodeClassificationLayerDependentImportanceSamplingTrainer, 36 | NodeClassificationNeighborSamplingTrainer 37 | ) 38 | from .ssl import GraphCLSemisupervisedTrainer, GraphCLUnsupervisedTrainer 39 | from .evaluation import get_feval, Acc, Auc, Logloss, Mrr, MicroF1 40 | 41 | __all__ = [ 42 | "BaseTrainer", 43 | "Evaluation", 44 | "BaseGraphClassificationTrainer", 45 | "BaseNodeClassificationTrainer", 46 | "BaseNodeClassificationHetTrainer", 47 | "BaseLinkPredictionTrainer", 48 | "GraphClassificationFullTrainer", 49 | "NodeClassificationFullTrainer", 50 | "NodeClassificationHetTrainer", 51 | "LinkPredictionTrainer", 52 | "Acc", 53 | "Auc", 54 | "Logloss", 55 | "Mrr", 56 | "MicroF1", 57 | "get_feval", 58 | ] 59 | 60 | if DependentBackend.is_pyg(): 61 | __all__.extend([ 62 | "NodeClassificationGraphSAINTTrainer", 63 | "NodeClassificationLayerDependentImportanceSamplingTrainer", 64 | "NodeClassificationNeighborSamplingTrainer", 65 | "GraphCLSemisupervisedTrainer", 66 | "GraphCLUnsupervisedTrainer" 67 | ]) -------------------------------------------------------------------------------- /autogl/datasets/utils/conversion/_to_dgl_dataset.py: -------------------------------------------------------------------------------- 1 | import dgl 2 | import torch 3 | import typing as _typing 4 | from autogl.data import Dataset, InMemoryDataset 5 | from autogl.data.graph import GeneralStaticGraph 6 | from autogl.data.graph.utils import conversion 7 | 8 | 9 | def to_dgl_dataset( 10 | dataset: _typing.Union[Dataset, _typing.Iterable[GeneralStaticGraph]] 11 | ) -> Dataset[_typing.Union[dgl.DGLGraph, _typing.Tuple[dgl.DGLGraph, torch.Tensor]]]: 12 | def _transform( 13 | general_static_graph: GeneralStaticGraph 14 | ) -> _typing.Union[dgl.DGLGraph, _typing.Tuple[dgl.DGLGraph, torch.Tensor]]: 15 | if not isinstance(general_static_graph, GeneralStaticGraph): 16 | raise TypeError 17 | if 'label' in general_static_graph.data: 18 | label: _typing.Optional[torch.Tensor] = general_static_graph.data['label'] 19 | elif 'y' in general_static_graph.data: 20 | label: _typing.Optional[torch.Tensor] = general_static_graph.data['y'] 21 | else: 22 | label: _typing.Optional[torch.Tensor] = None 23 | if label is not None and isinstance(label, torch.Tensor) and torch.is_tensor(label): 24 | return conversion.general_static_graph_to_dgl_graph(general_static_graph), label 25 | else: 26 | return conversion.general_static_graph_to_dgl_graph(general_static_graph) 27 | 28 | transformed_datalist: _typing.MutableSequence[ 29 | _typing.Union[dgl.DGLGraph, _typing.Tuple[dgl.DGLGraph, torch.Tensor]] 30 | ] = [] 31 | for item in dataset: 32 | if isinstance(item, GeneralStaticGraph): 33 | transformed_datalist.append(_transform(item)) 34 | elif isinstance(item, dgl.DGLGraph): 35 | transformed_datalist.append(item) 36 | elif ( 37 | isinstance(item, _typing.Sequence) and len(item) == 2 and 38 | isinstance(item[0], dgl.DGLGraph) and isinstance(item[1], torch.Tensor) 39 | ): 40 | transformed_datalist.append(tuple(item)) 41 | else: 42 | raise ValueError(f"Illegal data item as {item}") 43 | 44 | return ( 45 | InMemoryDataset(transformed_datalist, dataset.train_index, dataset.val_index, dataset.test_index, dataset.schema) 46 | if isinstance(dataset, InMemoryDataset) 47 | else InMemoryDataset(transformed_datalist) 48 | ) 49 | -------------------------------------------------------------------------------- /docs/docfile/tutorial_cn/t_quickstart.rst: -------------------------------------------------------------------------------- 1 | .. _quickstart_cn: 2 | 3 | 快速开始 4 | =========== 5 | 6 | 本教程将帮助您快速了解智图(AutoGL)中重要类的概念和用法。在本教程中,您将在数据集`Cora`_上进行快速的自动图学习。 7 | 8 | .. _Cora: https://graphsandnetworks.com/the-cora-dataset/ 9 | 10 | 智图 11 | --------------- 12 | 13 | 基于自动机器学习(AutoML)的概念,自动图学习的目标是用图数据**自动地**解决任务。与传统的学习框架不同,自动图学习不需要人工参与实验循环。您只需要向智图求解器提供数据集和任务,本框架将自动为您找到合适的方法和超参数。 14 | 15 | 下图描述了智图框架的工作流程。 16 | 17 | 为了达到自动机器学习的目标,我们提出的自动图学习框架组织如下。我们用 ``数据集(dataset)``来维护由用户给出的图形数据集。为了指定目标任务,需要构建一个 ``求解器(solver)``对象。 ``求解器``内部,有五个子模型来帮助完成完成自动图学习任务,即 ``自动特征工程``, ``自动模型``, ``神经架构搜索``, ``超参数优化``和 ``自动集成学习``来根据您的需求自动预处理/增强您的数据,选择和优化深度模型并集成。 18 | 假设你想在数据集 ``Cora``上进行自动图学习。首先,您可以通过 ``dataset``模块得到 ``Cora``数据集: 19 | 20 | .. code-block:: python 21 | 22 | from autogl.datasets import build_dataset_from_name 23 | cora_dataset = build_dataset_from_name('cora') 24 | 25 | 数据集将自动下载给您。请参考:ref:`dataset`或:ref:`dataset documentation`获取更多关于数据集构造、可用数据集、添加本地数据集等详细信息。 26 | 27 | 在导出数据集之后,您可以构建一个 ``节点分类求解器(node classification solver)``来处理自动训练过程: 28 | 29 | .. code-block:: python 30 | 31 | import torch 32 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') 33 | from autogl.solver import AutoNodeClassifier 34 | solver = AutoNodeClassifier( 35 | feature_module='deepgl', 36 | graph_models=['gcn', 'gat'], 37 | hpo_module='anneal', 38 | ensemble_module='voting', 39 | device=device 40 | ) 41 | 42 | 通过这种方式,我们构建了一个 ``节点分类求解器``,它使用 ``deepgl``进行特征工程,并使用 ``anneal``超参数优化器对给定的三个模型“ ``['gcn','gat']``进行优化。派生的模型将使用 ``voting``集成器进行集成。请参考相应的教程或文档,以了解可用子模块的定义和用法。 43 | 44 | Then, you can fit the solver and then check the leaderboard: 45 | 接下来,你可以安装求解器,然后查看排行榜: 46 | 47 | .. code-block:: python 48 | 49 | solver.fit(cora_dataset, time_limit=3600) 50 | solver.get_leaderboard().show() 51 | 52 | ``time_limit``设置为3600,这样整个自动绘图过程不会超过1小时。 ``solver.show()``将显示由 ``solver``维护的模型,以及它们在验证数据集上的性能。 53 | 54 | 然后,你可以使用提供的评估函数进行预测和结果评估: 55 | 56 | .. code-block:: python 57 | 58 | from autogl.module.train import Acc 59 | predicted = solver.predict_proba() 60 | print('Test accuracy: ', Acc.evaluate(predicted, 61 | cora_dataset.data.y[cora_dataset.data.test_mask].cpu().numpy())) 62 | 63 | .. 注意:: 当预测时,你不需要再次传递``cora_dataset``,因为数据集被``求解器``**记住**,预测时如果没有传递数据集将被重用。然而,您也可以在预测时传递一个新的数据集,新的数据集将被使用,而不是被记住的数据集。详情请参考:ref:`solver`或:ref:`solver documentation`。 -------------------------------------------------------------------------------- /test/performance/node_classification/pyg/solver.py: -------------------------------------------------------------------------------- 1 | """ 2 | Performance check of AutoGL trainer + PYG dataset 3 | """ 4 | import os 5 | import numpy as np 6 | from tqdm import tqdm 7 | 8 | os.environ["AUTOGL_BACKEND"] = "pyg" 9 | 10 | from autogl.module.feature import NormalizeFeatures 11 | from autogl.solver import AutoNodeClassifier 12 | from autogl.datasets import utils, build_dataset_from_name 13 | from autogl.solver.utils import set_seed 14 | from helper import get_encoder_decoder_hp 15 | import logging 16 | 17 | logging.basicConfig(level=logging.ERROR) 18 | 19 | def fixed(**kwargs): 20 | return [{ 21 | 'parameterName': k, 22 | "type": "FIXED", 23 | "value": v 24 | } for k, v in kwargs.items()] 25 | 26 | if __name__ == '__main__': 27 | 28 | import argparse 29 | parser = argparse.ArgumentParser('pyg model') 30 | parser.add_argument('--device', type=str, default='cuda') 31 | parser.add_argument('--dataset', type=str, choices=['Cora', 'CiteSeer', 'PubMed'], default='Cora') 32 | parser.add_argument('--repeat', type=int, default=50) 33 | parser.add_argument('--model', type=str, choices=['gat', 'gcn', 'sage', 'gin'], default='gat') 34 | parser.add_argument('--lr', type=float, default=0.01) 35 | parser.add_argument('--weight_decay', type=float, default=0.0) 36 | parser.add_argument('--epoch', type=int, default=200) 37 | 38 | args = parser.parse_args() 39 | 40 | # seed = 100 41 | dataset = build_dataset_from_name(args.dataset.lower()) 42 | label = dataset[0].y 43 | accs = [] 44 | 45 | model_hp, decoder_hp = get_encoder_decoder_hp(args.model, decoupled=True) 46 | 47 | for seed in tqdm(range(args.repeat)): 48 | 49 | solver = AutoNodeClassifier( 50 | feature_module='NormalizeFeatures', 51 | graph_models=(args.model,), 52 | ensemble_module=None, 53 | max_evals=1, 54 | hpo_module='random', 55 | trainer_hp_space=fixed(**{ 56 | "max_epoch": args.epoch, 57 | "early_stopping_round": args.epoch + 1, 58 | "lr": args.lr, 59 | "weight_decay": args.weight_decay, 60 | }), 61 | model_hp_spaces=[{"encoder": fixed(**model_hp), "decoder": fixed(**decoder_hp)}] 62 | ) 63 | 64 | solver.fit(dataset, seed=seed) 65 | acc = solver.evaluate(metric='acc') 66 | accs.append(acc) 67 | print('{:.4f} ~ {:.4f}'.format(np.mean(accs), np.std(accs))) 68 | --------------------------------------------------------------------------------