In [1485]:
import numpy as np
import pandas as pd
import pickle
import csv
import os
import torch
from torch_geometric.data import Data
from torch_geometric.data import InMemoryDataset
from torch_geometric.nn import GraphConv, TopKPooling, GatedGraphConv, SAGEConv, SGConv
from torch_geometric.nn import global_mean_pool as gap, global_max_pool as gmp
from torch_geometric.nn import SAGEConv, to_hetero
from torch_geometric.nn import GATConv, Linear, to_hetero
import torch.nn.functional as F
from tqdm import tqdm
import networkx as nx
seed = 0
np.random.seed(seed)
torch.manual_seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
In [ ]:
!pip install tensorboard
In [ ]:
%load_ext tensorboard
In [ ]:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

Samples "from a simulation"¶

In [1486]:
G = nx.balanced_tree(2, 5)
edge_nodes = [x for (x,d) in nx.degree(G) if d==1]
print("Total number of nodes: ",len(G.nodes))
print(" - Edge nodes: %i %0.3f%%"%(len(edge_nodes),len(edge_nodes)/len(G.nodes)))
pos=nx.spring_layout(G,seed=seed)
labels=nx.draw_networkx_labels(G,pos)    
nx.draw(G,pos)
nx.draw_networkx_nodes(G,pos,nodelist=edge_nodes,node_color="r")
nx.draw_networkx_nodes(G,pos,nodelist=[0],node_size=500,node_color="g")
Total number of nodes:  63
 - Edge nodes: 32 0.508%
Out[1486]:
<matplotlib.collections.PathCollection at 0x7fcb9123d3a0>
In [1487]:
#Node Features
levels = nx.single_source_shortest_path_length(G,source=0) #get tier-level based on Cloud-node length
nLevel = max(levels.values())+1

centrality = nx.eigenvector_centrality(G)

features = []
for n in G.nodes():
    hwr = (nLevel-levels[n])*10
    watts = (0.2 if n%2==0 else 2.4)
    features.append([n,centrality[n],levels[n],hwr,watts,int(n in edge_nodes)])

features = np.array(features)

num_features = features.shape[1]
print(num_features)
print(features[:3])
print(features[-3:])
6
[[ 0.          0.23190717  0.         60.          0.2         0.        ]
 [ 1.          0.29549267  1.         50.          2.4         0.        ]
 [ 2.          0.29549267  1.         50.          0.2         0.        ]]
[[6.00000000e+01 4.10005359e-02 5.00000000e+00 1.00000000e+01
  2.00000000e-01 1.00000000e+00]
 [6.10000000e+01 4.10005359e-02 5.00000000e+00 1.00000000e+01
  2.40000000e+00 1.00000000e+00]
 [6.20000000e+01 4.10005359e-02 5.00000000e+00 1.00000000e+01
  2.00000000e-01 1.00000000e+00]]
In [1488]:
#Test. Sample 1
alloc = 0 #the service is in node 0
neighs = [n for n in G.neighbors(alloc)]
edge_index = [[*[alloc]*len(neighs),*neighs],[*neighs,*[alloc]*len(neighs)]]  #Doubt: bidirectional?
print(edge_index)

print(np.array(features[[alloc,*neighs]]).astype(float))
node_feats = torch.LongTensor(features[[alloc,*neighs]])

node_feats = torch.tensor(node_feats, dtype=torch.float)
y = np.zeros(len(node_feats))
best_choice = np.argmax(neighs) #Get the node with less watts.
y[best_choice] = 1 
y = torch.FloatTensor(y)
print(y)
edge_index = torch.tensor(edge_index)
data = Data(x=node_feats, edge_index=edge_index,y=y) #Torch data

print(data) # Works :)
[[0, 0, 1, 2], [1, 2, 0, 0]]
[[ 0.          0.23190717  0.         60.          0.2         0.        ]
 [ 1.          0.29549267  1.         50.          2.4         0.        ]
 [ 2.          0.29549267  1.         50.          0.2         0.        ]]
tensor([0., 1., 0.])
Data(x=[3, 6], edge_index=[2, 4], y=[3])
/tmp/ipykernel_781697/1953125285.py:10: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  node_feats = torch.tensor(node_feats, dtype=torch.float)
In [1489]:
#Test.sample 2 
alloc = 2 #the service is in node 0
neighs = [n for n in G.neighbors(alloc)]


edge_index_old = [[*[alloc]*len(neighs),*neighs],[*neighs,*[alloc]*len(neighs)]]  #Doubt: bidirectional?

#Note: I normalize the edge_index with respect to the nodes in this case
#Note: bidirecctional?
edge_index = [  [*np.zeros(len(neighs),dtype=int),*np.arange(1,len(neighs)+1)],
                [*np.arange(1,len(neighs)+1),*np.zeros(len(neighs),dtype=int)] ]

node_feats = features[[alloc,*neighs]]
node_feats = torch.tensor(node_feats, dtype=torch.float)

y = np.zeros(len(node_feats))
best_choice = np.argmax(neighs) #Get the node with less watts.
y[best_choice] = 1 
y = torch.FloatTensor(y)

edge_index = torch.tensor(edge_index, dtype=torch.long)

print(node_feats)
print(edge_index)
data = Data(x=node_feats, edge_index=edge_index,y=y) #Torch data

print(data) # Data.X HAS DIFFERENT SIZE

#Note: Data.Node_feature DO has the same shape for all cases.... I think so.
tensor([[ 2.0000,  0.2955,  1.0000, 50.0000,  0.2000,  0.0000],
        [ 0.0000,  0.2319,  0.0000, 60.0000,  0.2000,  0.0000],
        [ 5.0000,  0.2606,  2.0000, 40.0000,  2.4000,  0.0000],
        [ 6.0000,  0.2606,  2.0000, 40.0000,  0.2000,  0.0000]])
tensor([[0, 0, 0, 1, 2, 3],
        [1, 2, 3, 0, 0, 0]])
Data(x=[4, 6], edge_index=[2, 6], y=[4])
In [1490]:
#Can feed this Data a simple Network? errors?
conv1 = GATConv(num_features, 1)
x = conv1(data.x, data.edge_index)
print(x)
tensor([[-4.5470],
        [ 0.3566],
        [-2.9737],
        [-4.7560]], grad_fn=<AsStridedBackward0>)
In [1491]:
## FINAL TEST for previous dataset generation

#alloc = 0 #the service is in cloud
alloc = 48 #the service is in edge node
#alloc = 2 #service at intermediate node
alloc = 0 #service at intermediate node


neighs = np.array([n for n in G.neighbors(alloc)])
max_degree_graph = 3

diff = max_degree_graph - len(neighs)
print(diff)

node_feats = np.array(features[[alloc,*neighs]]).astype(float)
print(node_feats)
print(len(node_feats))

diff_row = (np.ones(num_features*diff)*-1).reshape(diff,num_features)
print(diff_row)
node_feats = np.vstack((node_feats, diff_row))
node_feats = torch.tensor(node_feats, dtype=torch.float)
print(node_feats)


#edge_index = [[*[alloc]*len(neighs),*neighs,*[-1]*diff*2],[*neighs,*[alloc]*len(neighs),*[-1]*diff*2]]  #Doubt: bidirectional?
edge_index = [  [*np.zeros(len(neighs),dtype=int),*np.arange(1,len(neighs)+1),*[-1]*diff*2],
                [*np.arange(1,len(neighs)+1),*np.zeros(len(neighs),dtype=int),*[-1]*diff*2 ]]
print(edge_index)
edge_index = torch.tensor(edge_index, dtype=torch.long)

y = np.zeros(len(node_feats))
best_choice = np.argmax(neighs) #Get the node with less watts.
y[best_choice] = 1 # where the service "migrates" #It will depends of our goal
y = torch.tensor(y, dtype=torch.int64)
print(y.dtype)
print(y)  
if alloc==2 or alloc==14:
    assert(y[2]==1)
if alloc==48:
    assert(y[0]==1)
if alloc==0:
    assert(y[1]==1)
1
[[ 0.          0.23190717  0.         60.          0.2         0.        ]
 [ 1.          0.29549267  1.         50.          2.4         0.        ]
 [ 2.          0.29549267  1.         50.          0.2         0.        ]]
3
[[-1. -1. -1. -1. -1. -1.]]
tensor([[ 0.0000,  0.2319,  0.0000, 60.0000,  0.2000,  0.0000],
        [ 1.0000,  0.2955,  1.0000, 50.0000,  2.4000,  0.0000],
        [ 2.0000,  0.2955,  1.0000, 50.0000,  0.2000,  0.0000],
        [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000]])
[[0, 0, 1, 2, -1, -1], [1, 2, 0, 0, -1, -1]]
torch.int64
tensor([0, 1, 0, 0])
In [1492]:
print(data.num_node_features)
print(data.x)
print(data.y)
6
tensor([[ 2.0000,  0.2955,  1.0000, 50.0000,  0.2000,  0.0000],
        [ 0.0000,  0.2319,  0.0000, 60.0000,  0.2000,  0.0000],
        [ 5.0000,  0.2606,  2.0000, 40.0000,  2.4000,  0.0000],
        [ 6.0000,  0.2606,  2.0000, 40.0000,  0.2000,  0.0000]])
tensor([0., 0., 1., 0.])

Generating random samples¶

In [1493]:
!rm -R processed
!rm -R raw
In [1494]:
np.random.seed(0)
class SimpleMigrationDataset(InMemoryDataset):
    def __init__(self, root, n_samples, max_degree_graph, transform=None, pre_transform=None):
        self.n_samples = n_samples
        self.max_degree_graph = max_degree_graph
        super(SimpleMigrationDataset, self).__init__(root, transform, pre_transform)
        self.data, self.slices = torch.load(self.processed_paths[0])

    @property
    def raw_file_names(self):
        return []
    @property
    def processed_file_names(self):
        return ['simple_migrations.dataset']

    def download(self):
        pass
    
    def process(self):
        #In this point, we could load them from the traces...
        data_list = []
        for x in range(self.n_samples):
#            print("ID:",x)
            alloc = np.random.choice(G.nodes,1)[0]
#            print("\t alloc:",alloc)
            
            neighs = np.array([n for n in G.neighbors(alloc)])
            diff = max_degree_graph - len(neighs)

            
            node_feats = np.array(features[[alloc,*neighs]]).astype(float)
            diff_row = (np.ones(num_features*diff)*-1).reshape(diff,num_features)
            node_feats = np.vstack((node_feats, diff_row))
            
            node_feats = torch.tensor(node_feats, dtype=torch.float)
#            print(node_feats)

#           edge_index = [[*[alloc]*len(neighs),*neighs,*[-1]*diff],[*neighs,*[alloc]*len(neighs),*[-2]*diff]]  #Doubt: bidirectional?
            edge_index = [  [*np.zeros(len(neighs),dtype=int),*np.arange(1,len(neighs)+1),*[-1]*diff*2],
                [*np.arange(1,len(neighs)+1),*np.zeros(len(neighs),dtype=int),*[-1]*diff*2 ]]
            edge_index = torch.tensor(edge_index, dtype=torch.long)

#            print(edge_index)
            y = np.zeros(len(node_feats))
            best_choice = np.argmax(neighs) #Get the node with less watts.
            y[best_choice] = 1
#            print(y)
            y = torch.tensor(y, dtype=torch.int64)
            data = Data(x=node_feats, edge_index=edge_index, y=y)
#            print(data)
            data_list.append(data)
        

        data, slices = self.collate(data_list)
        torch.save((data, slices), self.processed_paths[0])
In [1495]:
dataset = SimpleMigrationDataset('',n_samples=1000,max_degree_graph=3)
Processing...
Done!
In [1496]:
!ls processed/
pre_filter.pt  pre_transform.pt  simple_migrations.dataset
In [1497]:
len(dataset)
Out[1497]:
1000
In [1498]:
dataset.num_classes, dataset.num_features
Out[1498]:
(2, 6)
In [1499]:
dataset = dataset.shuffle()
one_tenth_length = int(len(dataset) * 0.1)
train_dataset = dataset[:one_tenth_length * 8]
val_dataset = dataset[one_tenth_length*8:one_tenth_length * 9]
test_dataset = dataset[one_tenth_length*9:]
len(train_dataset), len(val_dataset), len(test_dataset)
Out[1499]:
(800, 100, 100)
In [1500]:
from torch_geometric.loader import DataLoader
batch_size= 40
train_loader = DataLoader(train_dataset, batch_size=batch_size)
val_loader = DataLoader(val_dataset, batch_size=batch_size)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
len(train_loader), len(val_loader), len(test_loader)
Out[1500]:
(20, 3, 3)
In [1501]:
from torch_geometric.nn import GCNConv
class Net2(torch.nn.Module):
    def __init__(self,hidden_channels):
        super(Net2, self).__init__()
        self.conv1 = GCNConv(dataset.num_node_features, hidden_channels)
        self.conv2 = GCNConv(hidden_channels, dataset.num_classes)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index)
        return F.log_softmax(x, dim=1) 
In [1791]:
from torch_geometric.nn import global_mean_pool
class MLP(torch.nn.Module):
    def __init__(self, hidden_channels):
        super().__init__()
        self.conv1 = GCNConv(dataset.num_node_features, hidden_channels)
        self.conv2 = GCNConv(hidden_channels, hidden_channels)
        self.conv3 = GCNConv(hidden_channels, hidden_channels)
        self.lin = Linear(hidden_channels, dataset.num_classes)

        
    def forward(self, x,edge_index,batch=None):
         # 1. Obtain node embeddings 
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = self.conv2(x, edge_index)
        x = F.relu(x)
        x = self.conv3(x, edge_index)

        # 2. Readout layer
#         print(x.shape)
#         print(batch.shape)
#         x = global_mean_pool(x, batch)  # [batch_size, hidden_channels]

        # 3. Apply a final classifier
        x = F.dropout(x, p=0.05, training=self.training)
        x = self.lin(x)
        return x
MLP(
  (conv1): GCNConv(6, 16)
  (conv2): GCNConv(16, 16)
  (conv3): GCNConv(16, 16)
  (lin): Linear(16, 2, bias=True)
)
In [1864]:
np.random.seed(seed)
torch.manual_seed(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

from torch_geometric.nn import global_mean_pool
class MLP2(torch.nn.Module):
    def __init__(self, hidden_channels):
        super().__init__()
        self.conv1 = GCNConv(dataset.num_node_features, hidden_channels)
        self.conv2 = GCNConv(hidden_channels, hidden_channels)
#         self.conv3 = GCNConv(hidden_channels, hidden_channels)
        self.lin3 = Linear(hidden_channels, dataset.num_classes)

        
    def forward(self, x,edge_index,batch=None):
         # 1. Obtain node embeddings 
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = self.conv2(x, edge_index)

        x = F.dropout(x, p=0.6, training=self.training)
        x = self.lin3(x)
        return x
In [1834]:
## TEST A: 
# Epoch: 399, Loss: 0.28797, Train Auc: 0.82875, Val Auc: 0.81833, Test Auc: 0.79333
model = MLP(hidden_channels=8)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
loss_op = torch.nn.CrossEntropyLoss() 
In [1835]:
## TEST B: 
# Epoch: 399, Loss: 0.38136, Train Auc: 0.73521, Val Auc: 0.69833, Test Auc: 0.77000
model = MLP(hidden_channels=16)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
loss_op = torch.nn.CrossEntropyLoss() 
In [1865]:
## TEST C: 
# Epoch: 399, Loss: 0.38086, Train Auc: 0.76417, Val Auc: 0.74000, Test Auc: 0.77833
model = MLP2(hidden_channels=16)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
loss_op = torch.nn.CrossEntropyLoss() 
In [1866]:
model.train()
Out[1866]:
MLP2(
  (conv1): GCNConv(6, 16)
  (conv2): GCNConv(16, 16)
  (lin3): Linear(16, 2, bias=True)
)
In [1867]:
def train(writer,epoch):
    model.train()
    total_loss = 0
#     first_time = False
    
    for data in train_loader:
#         print(data)
        data = data.to(device)
    
#         if not first_time:
#             writer.add_graph(model, input_to_model=data, verbose=False)
#             first_time = True
        
        optimizer.zero_grad()
        output = model(data.x, data.edge_index,data.batch) #.max(dim=1)
        loss = loss_op(output, data.y)
        loss.backward()
        total_loss += data.num_graphs * loss.item()
        optimizer.step()
        
        epoch_loss = total_loss / len(train_loader.dataset)
        writer.add_scalar('Loss/train', epoch_loss, global_step = epoch)
    return epoch_loss
In [1868]:
from sklearn.metrics import roc_auc_score
def evaluate(loader):
    model.eval()

    predictions = []
    labels = []

    with torch.no_grad():
        for data in loader:
#           print(data)
            data = data.to(device)
            _, pred = model(data.x,data.edge_index).max(dim=1)
#             print(pred)
            label = data.y.detach().cpu().numpy()
#           print(label)
            predictions.append(pred)
            labels.append(label)

    predictions = np.hstack(predictions)
    labels = np.hstack(labels)

    return roc_auc_score(labels, predictions)
In [1869]:
from torch.utils.tensorboard import SummaryWriter
logging_dir = "/home/isaac/projects/tmp"
In [1870]:
writer = SummaryWriter(logging_dir)
model_plotted = False

old_loss = 0 
for epoch in range(1, 400):
                
    loss = train(writer,epoch)
        
    train_acc = evaluate(train_loader)
    test_acc = evaluate(test_loader)
    val_acc = evaluate(val_loader)    

    writer.add_scalar('Accuracy/train', train_acc, epoch)
    writer.add_scalar('Accuracy/test', test_acc, epoch)
    writer.add_scalar('Accuracy/val', val_acc, epoch)
    
    
    if abs(loss-old_loss)>0.01 or epoch%25==0:
        print('Epoch: {:03d}, Loss: {:.5f}, Train Auc: {:.5f}, Val Auc: {:.5f}, Test Auc: {:.5f}'.format(epoch, loss, train_acc, val_acc, test_acc))
    old_loss = loss
    
print('Epoch: {:03d}, Loss: {:.5f}, Train Auc: {:.5f}, Val Auc: {:.5f}, Test Auc: {:.5f}'.format(epoch, loss, train_acc, val_acc, test_acc))

writer.close()
print("Done")
Epoch: 001, Loss: 1.76032, Train Auc: 0.50000, Val Auc: 0.50000, Test Auc: 0.50000
Epoch: 002, Loss: 1.21946, Train Auc: 0.50000, Val Auc: 0.50000, Test Auc: 0.50000
Epoch: 003, Loss: 0.87318, Train Auc: 0.50458, Val Auc: 0.50000, Test Auc: 0.50000
Epoch: 004, Loss: 0.68167, Train Auc: 0.53396, Val Auc: 0.51500, Test Auc: 0.53833
Epoch: 005, Loss: 0.61816, Train Auc: 0.52667, Val Auc: 0.51333, Test Auc: 0.52667
Epoch: 006, Loss: 0.56680, Train Auc: 0.53396, Val Auc: 0.51500, Test Auc: 0.53833
Epoch: 007, Loss: 0.54776, Train Auc: 0.51417, Val Auc: 0.50333, Test Auc: 0.52000
Epoch: 008, Loss: 0.52857, Train Auc: 0.50000, Val Auc: 0.50000, Test Auc: 0.50000
Epoch: 009, Loss: 0.51235, Train Auc: 0.51500, Val Auc: 0.50333, Test Auc: 0.51000
Epoch: 012, Loss: 0.48631, Train Auc: 0.50500, Val Auc: 0.50333, Test Auc: 0.50333
Epoch: 025, Loss: 0.45785, Train Auc: 0.51542, Val Auc: 0.51000, Test Auc: 0.51667
Epoch: 050, Loss: 0.44605, Train Auc: 0.55167, Val Auc: 0.54000, Test Auc: 0.53667
Epoch: 075, Loss: 0.44216, Train Auc: 0.57604, Val Auc: 0.56000, Test Auc: 0.56167
Epoch: 100, Loss: 0.43716, Train Auc: 0.60604, Val Auc: 0.58500, Test Auc: 0.58667
Epoch: 125, Loss: 0.43545, Train Auc: 0.61438, Val Auc: 0.60167, Test Auc: 0.60833
Epoch: 150, Loss: 0.43007, Train Auc: 0.57604, Val Auc: 0.56000, Test Auc: 0.56167
Epoch: 175, Loss: 0.41738, Train Auc: 0.58667, Val Auc: 0.57000, Test Auc: 0.56167
Epoch: 191, Loss: 0.42013, Train Auc: 0.71167, Val Auc: 0.68000, Test Auc: 0.74167
Epoch: 200, Loss: 0.40683, Train Auc: 0.61667, Val Auc: 0.60500, Test Auc: 0.61667
Epoch: 220, Loss: 0.41178, Train Auc: 0.71375, Val Auc: 0.68500, Test Auc: 0.73833
Epoch: 225, Loss: 0.40056, Train Auc: 0.59917, Val Auc: 0.58500, Test Auc: 0.57167
Epoch: 249, Loss: 0.40389, Train Auc: 0.68021, Val Auc: 0.65167, Test Auc: 0.71000
Epoch: 250, Loss: 0.39633, Train Auc: 0.64542, Val Auc: 0.62000, Test Auc: 0.66500
Epoch: 261, Loss: 0.38923, Train Auc: 0.73167, Val Auc: 0.72333, Test Auc: 0.74667
Epoch: 275, Loss: 0.38502, Train Auc: 0.60292, Val Auc: 0.59833, Test Auc: 0.57667
Epoch: 300, Loss: 0.39234, Train Auc: 0.73667, Val Auc: 0.71000, Test Auc: 0.76000
Epoch: 325, Loss: 0.38419, Train Auc: 0.68000, Val Auc: 0.68833, Test Auc: 0.67500
Epoch: 328, Loss: 0.39304, Train Auc: 0.76750, Val Auc: 0.75000, Test Auc: 0.77500
Epoch: 331, Loss: 0.39055, Train Auc: 0.73438, Val Auc: 0.72000, Test Auc: 0.74500
Epoch: 336, Loss: 0.38527, Train Auc: 0.76750, Val Auc: 0.75000, Test Auc: 0.77500
Epoch: 350, Loss: 0.37780, Train Auc: 0.68937, Val Auc: 0.69167, Test Auc: 0.67333
Epoch: 371, Loss: 0.38140, Train Auc: 0.57271, Val Auc: 0.55667, Test Auc: 0.55500
Epoch: 375, Loss: 0.37546, Train Auc: 0.73938, Val Auc: 0.74167, Test Auc: 0.73500
Epoch: 397, Loss: 0.37659, Train Auc: 0.77437, Val Auc: 0.77167, Test Auc: 0.78833
Epoch: 399, Loss: 0.38086, Train Auc: 0.76417, Val Auc: 0.74000, Test Auc: 0.77833
Done
In [1573]:
## TESTING THE TRAINING MODEL
# A simple sample 
alloc = 31 #the service goes to node 0
alloc = 14#the service goes to  node 2
alloc = 0 #the service goes to  node 1
alloc = 0 
print(alloc)
neighs = np.array([n for n in G.neighbors(alloc)])
diff = max_degree_graph - len(neighs)

node_feats = np.array(features[[alloc,*neighs]]).astype(float)
diff_row = (np.ones(num_features*diff)*-1).reshape(diff,num_features)
node_feats = np.vstack((node_feats, diff_row))
print(node_feats)
node_feats = torch.tensor(node_feats, dtype=torch.float)
edge_index = [  [*np.zeros(len(neighs),dtype=int),*np.arange(1,len(neighs)+1),*[-1]*diff*2],
    [*np.arange(1,len(neighs)+1),*np.zeros(len(neighs),dtype=int),*[-1]*diff*2 ]]
edge_index = torch.tensor(edge_index, dtype=torch.long)

y = np.zeros(len(node_feats))
best_choice = np.argmax(neighs) #Get the node with less watts.
y[best_choice] = 1
y = torch.tensor(y, dtype=torch.int64)
data = Data(x=node_feats, edge_index=edge_index, y=y)
print(data)
_ , pred = model(data.x, data.edge_index).max(dim=1)
print(pred)
0
[[ 0.          0.23190717  0.         60.          0.2         0.        ]
 [ 1.          0.29549267  1.         50.          2.4         0.        ]
 [ 2.          0.29549267  1.         50.          0.2         0.        ]
 [-1.         -1.         -1.         -1.         -1.         -1.        ]]
Data(x=[4, 6], edge_index=[2, 6], y=[4])
tensor([0, 1, 0, 0])
In [1576]:
!lsof -i:8008
COMMAND       PID  USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
tensorboa 2833806 isaac    8u  IPv4 145673214      0t0  TCP localhost:8008 (LISTEN)
In [1577]:
!kill -9 2833806
In [1578]:
%tensorboard --logdir {logging_dir} --port=8008