Я новичок в Pytorch и преподаю сам, и я хочу создать ANN, которые принимают ориентированный граф. Я также хочу передать предопределенные веса и смещения для каждого соединения, но хочу игнорировать это на данный момент.
Моя мотивация для этих условий заключается в том, что я пытаюсь реализовать NEAT Алгоритм, который в основном использует алгоритм Geneti c для развития сети.
Например, пусть graph = dict{'1':[[], [4, 7]], '2':[[], [6]], '3':[[], [6]], '4':[[1, 7], []], '5':[[7], []], '6':[[2, 3], [7]], '7':[[1, 6], [4, 5]]}
представляет ориентированный граф.
Мой код того, о чем я думаю:
class Net(torch.nn.Module):
def __init__(self, graph):
super(Net, self).__init__()
self.graph = graph
self.walk_graph()
def walk_graph(self):
graph_remaining = copy.deepcopy(self.graph)
done = False # Has every node/connection been processed?
while not done:
processed = [] # list of tuples, of a node and the nodes it outputs to
for node_id in graph_remaining.keys():
if len(graph_remaining[node_id][0]) == 0: # if current node has no incoming connections
try:
# if current node has been processed, but waited for others to finish
if callable(getattr(self, 'layer{}'.format(node_id))):
D_in = len(eval('self.layer{}'.format(node_id)).in_features)
D_out = len(eval('self.layer{}'.format(node_id)).out_features)
setattr(self, 'layer{}'.format(node_id), torch.nn.Linear(D_in, D_out))
cat_list = [] # list of input tensors
for i in self.graph[node_id][0]: # search the entire graph for inputs
cat_list.append(globals()['out_{}'.format(i)]) # add incoming tensor to list
# create concatenated tensor for incoming tensors
# I'm not confident about this
globals()['in_{}'.format(node_id)] = torch.cat(cat_list, len(cat_list))
except AttributeError: # if the current node hasn't been waiting
try:
setattr(self, 'layer{}'.format(node_id), torch.nn.Linear(len(self.graph[node_id][0]), len(self.graph[node_id][1])))
except ZeroDivisionError: # Input/Output nodes have zero inputs/outputs in the graph
setattr(self, 'layer{}'.format(node_id), torch.nn.Linear(1, 1))
globals()['out_{}'.format(node_id)] = getattr(self, 'layer' + node_id)(globals()['in_{}'.format(node_id)])
processed.append((node_id, graph_remaining[node_id][1]))
for node_id, out_list in processed:
for out_id in out_list:
try:
graph_remaining[str(out_id)][0].remove(int(node_id))
except ValueError:
pass
try:
del graph_remaining[node_id]
except KeyError:
pass
done = True
for node_id in self.graph.keys():
if len(graph_remaining[node_id][0]) != 0 or len(graph_remaining[node_id][1]) != 0:
done = False
return None
Я немного не в своей зоне комфорта по этому поводу, но если у вас есть идея получше или вы можете указать как это смертельно испорчено, у меня все уши. Я знаю, что мне не хватает функции пересылки, и мог бы воспользоваться некоторыми советами о том, как реструктурировать.