Package: ugle
UGLE: Unsupervised GNN Learning EnvironmentIntroductionugle is a library build on pytorch to compare implementations of GNNs for unsupervised clustering.
It consists of a wide range of methods, with the original implementations referenced in the source code.
We provide an experiment abstraction to compare different models and visualisation tools to plot results.
Any method can be trained individually via the main script using a specified config and the trainer objects.Optunais used to optimize hyperparameters, however models can be trained by specifying parameters.InstallationTo use this repository, you need to installpytorch_geometricso adjust the variables for the appropriateTORCHversion andCUDAoption. Please refer to thePyTorch Geometricinstallation guide if the following doesn't work for you as pytorch-geometric can be tricky with an M* Series Mac or Windows. Please use a virtual environment manager to install and use a version ofpython>=3.9.12. If you want a different version ofpytorchthen raise a pull request that can pass the version number to setup.py.CUDA=cpu | cu102 | cu113 | cu116pip install --extra-index-url https://data.pyg.org/whl/torch-1.12.0+{CUDA}.html ugleQuick TourHere is an example of how you can use the python APIs from this repo.importugleimportnumpyasnpn_nodes=1000n_features=200n_clusters=3# demo to evaluate a in Memory datasetdataset={'features':np.random.rand(n_nodes,n_features),'adjacency':np.random.rand(n_nodes,n_nodes),'label':np.random.randint(0,n_clusters+1,size=n_nodes)}# load the dmon default hyperparameters and evaluate on in memory datasetcfg=ugle.utils.load_model_config(override_model="dmon_default")Trainer=ugle.trainer.ugleTrainer("dmon",cfg)results=Trainer.eval(dataset)# evalute dmon with hpoTrainer=ugle.trainer.ugleTrainer("dmon")Trainer.cfg.dataset="cora"Trainer.cfg.trainer.n_trials_hyperopt=2# this is how you change the configTrainer.cfg.args.max_epoch=250results=Trainer.eval(dataset)Changing the cfg property in the Trainer object will change the training and optimisation procedure as demonstrated above. Detailed below are all the options that can be changed.ugle/configs/config.yamltrainer:gpu:"0"# GPU index (-1 = CPU)show_config:False# prints the working config to cmd lineresults_path:'./results/'# where to save results todata_path:'./data/'# where to look for datamodels_path:'./models/'# where to save models# if load_exising_test = True then trainer will look in {load_hps_path}{cfg.dataset}_{cfg.model}.pkl"# for previous found hyperparametersload_existing_test:Falseload_hps_path:'./found_hps/'save_hpo_study:False# whether to save the hpo investigationsave_model:False# whether to save the best model# hyperparameter optionstest_metrics:['f1','nmi','modularity','conductance']# metrics to evaluate test datavalid_metrics:['f1','nmi','modularity','conductance']# metrics used for hpo and model selectionvalidate_every_nepochs:5# how many training epochs per validationn_trials_hyperopt:5# how many hpo trialsmax_n_pruned:20# patience for repeated hpo trialstraining_to_testing_split:0.2# percentage of testing data compared to total of training+validationtrain_to_valid_split:0.2# percentage of validation data as proportion of the whole datasetsplit_scheme:'drop_edges'# one of drop_edges, split_edges, all_edges, no_edges (see ugle.datasets.split_adj() for more info)# logging optionscalc_time:True# whether to calculate the time taken for evaluationcalc_memory:False# whether to calculate the memory used by evaluationlog_interval:5# how often to refresh the progress barargs:random_seed:42# the random seed to setmax_epoch:5000# the number of epochs to train for# this is also where the specific model args are loaded intoIf you want to do the same on the command line then you can parse use some of these arguments when runningpython main.py.--model=<NAME-OF-MODEL>--dataset=<NAME-OF-DATASET>--seed=<SEED-ID>--max_epoch=<MAX-EPOCHS-FOR-TRAINING>--gpu=<GPU-INDEX>--load_existing_test# if you specify a model as "dmon_custom" and write some custom args in the appropriate file that you want to test on then use this argument to load theseRunning Experiment on Multiple (seeds/datasets/algorithms)If you want to run a study over multiple seeds/dataset/algorithms then use themodel_evaluations.pyscript alongside theexperimentsconfig files. See theugle/configs/testing/directory for examples on different scripts. If you have thenulloption in bothdatasetsandalgorithmsin your config file then you can run the config over a single dataset and algorithm combination by using the-daargument which puts this combination into thedataset_algo_combinationsoption. This can also be used to define a list of combinations to choose to evaluate.python3 model_evaluations.py -ec=<PATH-TO-EXP-CONFIG> -da=<DATASET>_<MODEL>Existing GNN ImplementationsdaegcdgidmonmvgrlgraceselfgnnsublimebgrlvgaercagcExisting DatasetsacmamacamapbatciteseercoracocsdblpeatuatpubmedtexaswisccornellPhysicsCSPhotoComputershow to add a new model <: MODEL-NAME>To create a model with the name , you need to create minimum two files:create a file for the model:ugle/models/<MODEL-NAME>.pycreate a file to hold the hyperparameters:ugle/configs/models/<MODEL-NAME>/<MODEL-NAME>.yamloptional* create file to hold default hyperparameters :ugle/configs/models/<MODEL-NAME>/<MODEL-NAME>_default.yamloptional* create a new .yaml file to hold other variations:ugle/configs/models/<MODEL_NAME>/<MODEL_NAME>_myparameters.yamlrun an experiments or a single model run using the name reference as :"<MODEL_NAME>_myparameters"Insideugle/models/<MODEL-NAME>.py, define four hooks to process the whole modelfromugle.trainerimportugleTrainer# this is the base class for training any model in this frameworkclass<MODEL-NAME>_trainer(ugleTrainer):defpreprocess_data(self,features,adjacency):# here we process the data into a required format# some models using pytorch_geometric layers, some use custom layers# this allows us to create new representation formats for features/adjacency matrix# additional data structures needed can be returned for access under the tuple: processed_datareturn(features,adj,...)deftraining_preprocessing(self,args,processed_data):(features,adj,...)=processed_data# here the model and optimisers are defined as followsself.model=...Model()self.optimizers=[optimizer]returndeftraining_epoch_iter(self,args,processed_data):# here is the training iterations hook, that defines the forward pass for each model# the only requirement is that a loss is returned.# If the processed data changes and is needed for the next iteration,# then, return the tuple you need in place of processed data# If this is not needed then None must be returned insteadreturnloss,(None/updated_processed_data)deftest(self,processed_data):# the testing loop# the definition of how predictions are returned by this model# 1d numpy array returned of predictions for each nodereturnpreds