生成器对象列表的计算平均值

Computing mean of list of generator objects

// Initialize 2-D array, each entry is some neural network
phi = [[None] * n for _ in range(m)]
for i in range(m):
    for j in range(n):
        phi[i][j] = NeuralNetwork()

// Let k, i be arbitrary indices
p1 = torch.nn.utils.parameters_to_vector(phi[k][i - 1].parameters())
p2 = torch.nn.utils.parameters_to_vector(mean of phi[:][i-1])

我想基本上计算参数 phi[k][i-1] 和整个列的平均值 phi[:][i-1] 之间的均方误差,即 ((p1 - p2)**2).sum() 我尝试了以下方式:

tmp = [x.parameters() for x in self.phi[:][i - 1]]
mean_params = torch.mean(torch.stack(tmp), dim=0)
p2 = torch.nn.utils.parameters_to_vector(mean_params)

但这行不通,因为 tmp 是生成器对象的列表。更具体地说,我想我的问题是计算生成器对象的平均值。

首先,我们可以定义一个函数来计算模型列表的平均参数。为了避免同时创建每个模型的参数副本,我们可能希望将其计算为 运行 总和。例如

def average_parameters_vector(model_list):
    n = len(model_list)
    avg = 0 
    for model in model_list:
        avg = avg + torch.nn.utils.parameters_to_vector(model.parameters()) / n 
    return avg 

然后您可以创建 p1p2 并计算 mean-squared 错误

p1 = torch.nn.utils.parameters_to_vector(phi[k][i - 1].parameters())
p2 = average_parameters_vector(phi[:][i - 1])

mse = ((p1 - p2)**2).mean()

如果你真的想要一个 one-line 解决方案,它也可能是最快的,你可以通过制作一个包含 phi[:][i - 1] 中模型的所有参数的单个张量来计算它,然后意味着减少它们。但如前所述,这将显着增加内存使用量,尤其是当您的模型通常有数百万个参数时。

# Uses lots of memory but potentially the fastest solution
def average_parameters_vector(model_list):
    return torch.stack([torch.nn.utils.parameters_to_vector(model.parameters()) for model in model_list]).mean(dim=0)

另一方面,如果您非常关心内存使用情况,那么您可以一次计算每个单独参数的平均值。

# more memory efficient than original solution but probably slower
def average_parameters_vector(model_list):
    n = len(model_list)
    num_params = len(list(model_list[0].parameters()))
    averages = [0] * num_params
    for model in model_list:
        for pidx, p in enumerate(model.parameters()):
            averages[pidx] = averages[pidx] + p.data.flatten() / n 
    return torch.cat(averages)