Загрузка одного графа в объект геометрических данных pytorch для классификации узлов

У меня есть один граф, определяемый 4 матрицами: x (характеристики узлов), y (метки узлов), edge_index (список ребер) и edge_attr (особенности ребер). Я хочу создать набор данных в Pytorch Geometric с этим единственным графом и выполнить классификацию на уровне узлов. Кажется, что просто обернуть эти 4 матрицы в объект data по какой-то причине не удается.

Я создал набор данных, содержащий атрибуты:

Data(edge_attr=[3339730, 1], edge_index=[2, 3339730], x=[6911, 50000], y=[6911, 1])

представляющий граф. Если я попытаюсь разрезать этот график, например:

train_dataset, test_dataset = dataset[:5000], dataset[5000:]

Я получаю сообщение об ошибке:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-feb278180c99> in <module>
      3 # train_dataset, test_dataset = torch.utils.data.random_split(dataset, [train_size, test_size])
      4 
----> 5 train_dataset, test_dataset = dataset[:5000], dataset[5000:]
      6 
      7 # Create dataloader for training and test dataset.

~/anaconda3/envs/py38/lib/python3.8/site-packages/torch_geometric/data/data.py in __getitem__(self, key)
     92     def __getitem__(self, key):
     93         r"""Gets the data of the attribute :obj:`key`."""
---> 94         return getattr(self, key, None)
     95 
     96     def __setitem__(self, key, value):

TypeError: getattr(): attribute name must be string

Что я делаю не так при построении данных?


person Qubix    schedule 11.01.2021    source источник


Ответы (2)


Для классификации узлов:

Создайте собственный набор данных.

class CustomDataset(InMemoryDataset):
    def __init__(self, root, transform=None, pre_transform=None):
        super(CustomDataset, self).__init__(root, transform, pre_transform)
        self.data, self.slices = torch.load(self.processed_paths[0])
        
    @property
    def raw_file_names(self):
        return ['edge_list.csv', 'x.pt', 'y.pt', 'edge_attributes.csv']

    @property
    def processed_file_names(self):
        return ['graph.pt']

    def process(self):
        data_list = []
        edge_list = pd.read_csv(self.raw_paths[0], dtype=int)
        target_nodes = edge_list.iloc[:,0].values
        source_nodes = edge_list.iloc[:,1].values
        edge_index = torch.tensor([source_nodes, target_nodes], dtype=torch.int64)

        x = torch.load(self.raw_paths[1], map_location=torch.device('cpu'))
        y = torch.load(self.raw_paths[2], map_location=torch.device('cpu'))

        # make masks
        n = x.shape[0]
        randomassort = list(range(n))
        random.shuffle(randomassort)
        max_train = floor(len(randomassort) * .1)
        train_mask_idx = torch.tensor(randomassort[:max_train])
        test_mask_idx = torch.tensor(randomassort[max_train:])
        train_mask = torch.zeros(n); test_mask = torch.zeros(n)
        train_mask.scatter_(0, train_mask_idx, 1)
        test_mask.scatter_(0, test_mask_idx, 1)
        train_mask = train_mask.type(torch.bool)
        test_mask = test_mask.type(torch.bool)

        edge_attributes = pd.read_csv(self.raw_paths[3])

        data = Data(edge_index=edge_index, x=x, y=y, train_mask=train_mask, test_mask=test_mask)

        print(data.__dict__)
        data, slices = self.collate([data])
        torch.save((data, slices), self.processed_paths[0])

Затем в цикле поезда используйте маски при обновлении модели.

def train():
    ...
    model.train()
    optimizer.zero_grad()
    F.nll_loss(model()[data.train_mask], data.y[data.train_mask]).backward()
    optimizer.step()
person jchaykow    schedule 11.01.2021
comment
Что такое ch в train_mask.scatter_ (0, ch, 1); test_mask.scatter_ (0, канал, 1)? - person Qubix; 17.01.2021
comment
@Qubix whoops Я думаю, что переименовал некоторые переменные, когда переместил код. Только что отредактировал. Это должны быть idx поезда и тестовые маски. - person jchaykow; 18.01.2021

Вы не можете разрезать person Ivan    schedule 11.01.2021

comment
Привет, спасибо за ответ. Я разместил этот вопрос по всему Интернету, так как он довольно срочен :( и пока получил 1 единственный ответ. Ваш. Я смотрю на эту функцию, но не знаю, как я могу включить ее в свой объект данных. Можно ли опубликовать простой пример, показывающий, как это делается, если вам дан только один график в виде одного объекта данных: Data (edge_attr = [3339730, 1], edge_index = [2, 3339730], x = [6911, 50000], y = [6911, 1]) - person Qubix; 11.01.2021
comment
Вы хотите использовать train_test_split_edges только в том случае, если вы хотите выполнить тестовое разбиение на ребрах, а не на узлах. Чтобы обучить и протестировать разбиение на узлах, вы хотите использовать маски - person jchaykow; 11.01.2021
comment
@jchaykow любая идея, как это делается, не могли бы вы опубликовать минимальный рабочий пример с небольшим графиком? - person Qubix; 11.01.2021