神经细胞自动机不会“训练”

问题描述 投票:0回答:1

我正在尝试使用 pytorch 实现 2D 神经细胞自动机(NCA)。

主要问题:权重在学习迭代之间不会改变,因此模型不会“进步”并保持在初始化状态。

主脚本似乎工作正常(虽然不完全确定它有多正确),但我就是无法使训练工作。

一些技术细节:我的目标是创建一个 NCA,它可以学习仅使用有关单元及其 4 个邻居的信息重新创建某些图像(numpy 数组)的“规则”。因此模型无法一次性获取所有网格的信息。由于某些原因,我想在没有卷积的情况下完成它。

想法是拥有一个网络,对网格上的每个单元格执行更新,并且(在更新所有单元格之后)基于原始数组和生成的(更新的)数组之间的某些差异度量来改进自身。

代码:

import numpy as np
import torch
from torch import nn
import torch.optim as optim


class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(5, 32),
            nn.ReLU(),
            nn.Linear(32, 2)
        )

    def forward(self, x):
        x = self.flatten(x)
        x = self.linear_relu_stack(x)
        return x

# cellular automaton update function
def update_grid(grid, model):
    dsize = grid.shape[0]
    domain_next = grid.copy()
    for i in range(1, dsize - 1):
        for j in range(1, dsize - 1):
            inp = [grid[i][j], grid[i + 1][j], grid[i - 1][j],
                   grid[i][j + 1], grid[i][j - 1]]

            out = model(torch.tensor([inp], dtype=torch.float32))
            domain_next[i][j] = torch.argmax(out).item()

    return domain_next

if __name__ == '__main__':
    dsize = 8
    np.random.seed(42)
    domain = np.random.randint(2, size=(dsize, dsize))
    init_domain = domain.copy()

    #torch.manual_seed(43)
    model = NeuralNetwork()
    optimizer = optim.SGD(model.parameters(), lr=0.01)

    # training loop
    num_train_iter = 100
    for _ in range(num_train_iter):
        optimizer.zero_grad()

        # create domain based on rules from NN
        domain_next = update_grid(domain, model)

        domain_tensor = torch.tensor(domain, dtype=torch.float32, requires_grad=True)
        domain_next_tensor = torch.tensor(domain_next, dtype=torch.float32, requires_grad=True)

        # measure of how close generated image is to the original
        similarity = torch.mean(torch.abs(domain_next_tensor - domain_tensor))

        # to make it possible to minize, loss is in some sense...
        # an inverse of similarity
        loss = 1 - similarity 
        loss = torch.mean(torch.abs(domain_next_tensor - domain_tensor))

        loss.backward()
        optimizer.step()

        if (_ + 1) % 10 == 0:
            print(f'Iteration {_ + 1}, Loss: {loss.item()}')

    # evaluation phase
    model.eval()
    num_iterations = 10
    for _ in range(num_iterations):
        domain = update_grid(domain, model)

输出:

Iteration 10, Loss: 0.1666666716337204
Iteration 20, Loss: 0.1666666716337204
Iteration 30, Loss: 0.1666666716337204
Iteration 40, Loss: 0.1666666716337204
Iteration 50, Loss: 0.1666666716337204
Iteration 60, Loss: 0.1666666716337204
Iteration 70, Loss: 0.1666666716337204
Iteration 80, Loss: 0.1666666716337204
Iteration 90, Loss: 0.1666666716337204
Iteration 100, Loss: 0.1666666716337204

我尝试过的:改变学习率、迭代次数等参数;改变损失函数、优化器;改变拓扑;重组代码和许多其他我没有理由的小事情。

machine-learning pytorch neural-network cellular-automata
1个回答
0
投票

看起来您的代码更新了

update_grid
函数中的域网格,这没关系。但是,此更新不是 PyTorch 用于反向传播梯度的计算图的一部分。 Soooo,即使你调用
loss.backward()
,它对模型参数没有任何影响。

© www.soinside.com 2019 - 2024. All rights reserved.