当前位置: 首页 > news >正文

mlp文件夹继续阅读

纵览结构,mlp文件夹就是定义了mlp类,所有的函数都在mlp这个class下。

关于plot:画神经网络结构图

def plot(self, beta=3, scale=1., metric='w'):# metric = 'w', 'act' or 'fa'if metric == 'fa':self.attribute()depth = self.depthy0 = 0.5fig, ax = plt.subplots(figsize=(3*scale,3*y0*depth*scale))shp = self.widthmin_spacing = 1/max(self.width)for j in range(len(shp)):N = shp[j]for i in range(N):plt.scatter(1 / (2 * N) + i / N, j * y0, s=min_spacing ** 2 * 5000 * scale ** 2, color='black')plt.ylim(-0.1*y0,y0*depth+0.1*y0)plt.xlim(-0.02,1.02)linears = self.linearsfor ii in range(len(linears)):linear = linears[ii]p = linear.weightp_shp = p.shapeif metric == 'w':passelif metric == 'act':p = self.wa_forward[ii]elif metric == 'fa':p = self.wa_backward[ii]else:raise Exception('metric = \'{}\' not recognized. Choices are \'w\', \'act\', \'fa\'.'.format(metric))for i in range(p_shp[0]):for j in range(p_shp[1]):plt.plot([1/(2*p_shp[0])+i/p_shp[0], 1/(2*p_shp[1])+j/p_shp[1]], [y0*(ii+1),y0*ii], lw=0.5*scale, alpha=np.tanh(beta*np.abs(p[i,j].cpu().detach().numpy())), color="blue" if p[i,j]>0 else "red")ax.axis('off')

这段代码是一个Python函数,用于绘制一个神经网络的结构图。以下是代码的主要功能和它所绘制的内容的详细解释:

  1. 参数说明

    • beta:用于控制连接线的透明度,基于权重的大小。
    • scale:用于调整图形的大小。
    • metric:用于指定绘制时使用的度量标准,可以是权重(‘w’)、激活(‘act’)或反馈调整(‘fa’)。
  2. 绘图步骤

    • 首先,根据网络深度和给定的比例尺设置图形的大小。
    • y0 是一个垂直间距因子,用于控制层与层之间的距离。
    • 绘制神经网络中的每个神经元,它们被表示为黑色的小点。点的位置取决于它们在各自层中的位置,点的尺寸与层的宽度成反比。
  3. 神经元布局

    • 通过两层循环,在每个层的指定位置上放置神经元。
    • min_spacing 用于确保即使在非常宽的层中,神经元也不会太小。
  4. 绘制连接线

    • linears 是一个包含神经网络层权重的列表。
    • 对于每一层,根据metric参数选择要使用的权重(原始权重、激活后的权重或反馈调整后的权重)。
    • 连接线表示层与层之间的连接,线的颜色取决于权重的符号(正为蓝色,负为红色),线宽和透明度则取决于权重的大小和beta参数。
  5. 坐标轴设置

    • 设置y轴的范围以适应所有层。
    • 设置x轴的范围,确保所有神经元都在视图内。
    • 最后,关闭坐标轴的显示,以便只显示神经网络的结构图。

总结:这个函数绘制了一个神经网络的结构,其中包括层的神经元和它们之间的连接。通过调整metric参数,可以查看不同视角下的网络结构,例如原始权重、激活后的权重或反馈调整后的权重。通过这种方式,可以直观地了解神经网络的结构和权重分布。

第一步:画散点scatter,使用x 与y坐标

第二部:用线连接,权重大小决定透明度,越重要透明度低。                plt.plot([

1/(2*p_shp[0])+i/p_shp[0],1/(2*p_shp[1])+j/p_shp[1]],【x0,x1】

[y0*(ii+1),y0*ii],【y0,y1】,这里x01,y01都是单个数字

lw=0.5*scale,

  • lw 是线宽的缩写,表示连接线的宽度。
  • 这里的线宽是0.5乘以缩放因子scale,以便在调整图形大小时保持线宽的比例。

alpha=np.tanh(beta*np.abs(p[i,j].cpu().detach().numpy())),【透明度】

  • lpha 表示连接线的透明度。
  • 透明度由权重p[i,j]的绝对值决定,经过beta缩放后,再通过双曲正切函数np.tanh进行变换。这样,权重较大的连接线会更明显,而权重较小的连接线则更透明。

color="blue" if p[i,j]>0 else "red")权重正,蓝色;否则红色。

init__里的linear

linears = []self.width = widthself.depth = depth = len(width) - 1for i in range(depth):linears.append(nn.Linear(width[i], width[i+1]))self.linears = nn.ModuleList(linears)

linears是一层又一层的(depth层)nn.linear 组成的列表,将linears列表转换为nn.ModuleList

  1. linears = []

    • 这行代码初始化了一个名为linears的空列表,用于存储即将创建的线性层。
  2. self.width = width

    • 这里,width是一个列表,表示每一层的神经元数量。self.width将这个列表存储为模型的属性。
  3. self.depth = depth = len(width) - 1

    • depth变量计算网络的总层数,它是width列表长度的减一。这样做是因为列表中的元素数量代表层数,而层数比元素数量少一个(因为每一层都连接到下一层)。
    • self.depth将层数存储为模型的属性。
  4. for i in range(depth)

    • 这是一个循环,它遍历每一层,从0开始到depth - 1结束。
  5. linears.append(nn.Linear(width[i], width[i+1]))

    • 在循环内部,这行代码为每一层创建一个线性层(全连接层),并将其添加到linears列表中。
    • nn.Linear(width[i], width[i+1])是PyTorch框架中用于创建线性层的函数,其中width[i]是当前层的输入特征数(即当前层的神经元数量),width[i+1]是下一层的输出特征数(即下一层的神经元数量)。
  6. self.linears = nn.ModuleList(linears)

    • 最后,self.linearslinears列表转换为nn.ModuleList,这是PyTorch中的一个类,它能够将模块列表作为模型的一部分进行管理。
    • 通过这种方式,所有创建的线性层都会被PyTorch识别,并在模型的参数优化和移动到GPU等操作中一起处理。

总结:这段代码创建了一个由多个线性层组成的神经网络模型,每一层的神经元数量由width列表指定。通过这种方式,可以定义一个具有特定结构和深度的全连接神经网络。

方便之后前向传播像函数一样作用在输入上——

x = self.linears[i](x)
  1. self.linears 是一个 nn.ModuleList,它是一个可以包含多个模块(例如,神经网络层)的列表。当你通过索引i访问self.linears[i]时,你实际上是在获取列表中的第i个模块。

  2. 在PyTorch中,每个模块(例如nn.Linear)都是一个可调用的对象。这意味着你可以像调用函数一样调用这个模块。当你调用self.linears[i](x)时,你实际上是在调用第i个线性层,并将输入数据x传递给它。

  3. 当一个线性层被调用时,它会执行矩阵乘法(加上偏置项,如果有的话),这就是全连接层的典型操作。输入x会通过这个线性层,并产生输出,这个输出可以被用作下一层的输入。

所以,整个表达式x = self.linears[i](x)的含义是:

  • 获取索引为i的线性层。
  • 将当前的数据x传递给这个线性层。
  • 执行线性层的操作(即全连接层的计算)。
  • 将计算结果赋值给变量x,这样x就成为了下一层的输入。

这样的链式调用在神经网络的前向传播过程中非常常见,允许你按顺序通过网络的每一层

装饰器,w属性

@property是把函数转成属性

@自定义函数 才是自定义装饰函数、

    @propertydef w(self):return [self.linears[l].weight for l in range(self.depth)]

 

在Python中,@property装饰器用于将一个方法转换为属性访问。这里,@property被用来定义一个属性的getter方法,允许用户以访问属性的方式访问方法返回的值,而不是显式地调用一个方法。

@property装饰器用于定义一个名为w的属性,它允许用户以self.w的形式访问网络中每一层线性变换的权重。

以下是为什么使用@property装饰器的原因:

  1. 简化访问:使用@property,你可以像访问一个普通属性一样访问self.w,而不是调用一个方法(如self.get_weights())。这使得代码更加简洁,易于理解。

  2. 封装:通过使用@property,你可以隐藏内部的实现细节。例如,如果你想在未来改变权重存储或计算的方式,你可以只修改w属性的getter方法,而不需要修改使用这些权重的代码。

  3. 控制访问:如果你需要对属性的访问进行更多的控制(例如,添加验证逻辑或者延迟计算),你可以通过@property来实现。虽然在这个例子中,w属性只是简单地返回一个列表,但你可以添加额外的逻辑来控制权重值的访问。

  4. 只读属性:在这个例子中,@property没有对应的setter方法(如@w.setter),这意味着self.w是一个只读属性。这可以防止权重被外部代码意外修改。

reg正则化

  def reg(self, reg_metric, lamb_l1, lamb_entropy):if reg_metric == 'w':acts_scale = self.wif reg_metric == 'act':acts_scale = self.wa_forwardif reg_metric == 'fa':acts_scale = self.wa_backwardif reg_metric == 'a':acts_scale = self.acts_scaleif len(acts_scale[0].shape) == 2:reg_ = 0.for i in range(len(acts_scale)):vec = acts_scale[i]vec = torch.abs(vec)l1 = torch.sum(vec)p_row = vec / (torch.sum(vec, dim=1, keepdim=True) + 1)p_col = vec / (torch.sum(vec, dim=0, keepdim=True) + 1)entropy_row = - torch.mean(torch.sum(p_row * torch.log2(p_row + 1e-4), dim=1))entropy_col = - torch.mean(torch.sum(p_col * torch.log2(p_col + 1e-4), dim=0))reg_ += lamb_l1 * l1 + lamb_entropy * (entropy_row + entropy_col)elif len(acts_scale[0].shape) == 1:reg_ = 0.for i in range(len(acts_scale)):vec = acts_scale[i]vec = torch.abs(vec)l1 = torch.sum(vec)p = vec / (torch.sum(vec) + 1)entropy = - torch.sum(p * torch.log2(p + 1e-4))reg_ += lamb_l1 * l1 + lamb_entropy * entropyreturn reg_
def reg(self, reg_metric, lamb_l1, lamb_entropy):
  • 定义一个名为 reg 的方法,它接受三个参数:reg_metric(用于选择正则化类型),lamb_l1(L1正则化的系数),和 lamb_entropy(熵正则化的系数)。

python

复制

    if reg_metric == 'w':acts_scale = self.w
  • 如果 reg_metric 是 ‘w’,则将 self.w 赋值给 acts_scale,这意味着正则化将基于权重。

python

复制

    if reg_metric == 'act':acts_scale = self.wa_forward
  • 如果 reg_metric 是 ‘act’,则将 self.wa_forward 赋值给 acts_scale,这意味着正则化将基于前向激活。

python

复制

    if reg_metric == 'fa':acts_scale = self.wa_backward
  • 如果 reg_metric 是 ‘fa’,则将 self.wa_backward 赋值给 acts_scale,这意味着正则化将基于反向激活。

python

复制

    if reg_metric == 'a':acts_scale = self.acts_scale
  • 如果 reg_metric 是 ‘a’,则将 self.acts_scale 赋值给 acts_scale,这意味着正则化将基于激活尺度。

python

复制

    if len(acts_scale[0].shape) == 2:reg_ = 0.
  • 检查 acts_scale 的第一个元素是否是二维的(即矩阵)。如果是,初始化正则化损失 reg_ 为 0。

python

复制

        for i in range(len(acts_scale)):vec = acts_scale[i]vec = torch.abs(vec)
  • 遍历 acts_scale 中的每个元素,并计算其绝对值。

python

复制

            l1 = torch.sum(vec)
  • 计算当前元素的L1范数(所有元素的绝对值之和)。

python

复制

            p_row = vec / (torch.sum(vec, dim=1, keepdim=True) + 1)p_col = vec / (torch.sum(vec, dim=0, keepdim=True) + 1)
  • 计算每行的归一化概率 p_row 和每列的归一化概率 p_col,这里加1是为了避免除以0。

python

复制

            entropy_row = - torch.mean(torch.sum(p_row * torch.log2(p_row + 1e-4), dim=1))entropy_col = - torch.mean(torch.sum(p_col * torch.log2(p_col + 1e-4), dim=0))
  • 计算每行的熵 entropy_row 和每列的熵 entropy_col,这里加 1e-4 是为了数值稳定性,避免对0取对数。

python

复制

            reg_ += lamb_l1 * l1 + lamb_entropy * (entropy_row + entropy_col)
  • 将当前层的L1正则化和熵正则化加到总正则化损失 reg_ 上。

python

复制

    elif len(acts_scale[0].shape) == 1:
  • 如果 acts_scale 的第一个元素是一维的(即向量),则进行以下操作。

python

复制

        reg_ = 0.
  • 初始化正则化损失 reg_ 为 0。

python

复制

        for i in range(len(acts_scale)):vec = acts_scale[i]vec = torch.abs(vec)
  • 遍历 acts_scale 中的每个元素,并计算其绝对值。

python

复制

            l1 = torch.sum(vec)
  • 计算当前元素的L1范数。

python

复制

            p = vec / (torch.sum(vec) + 1)
  • 计算归一化概率 p

python

复制

            entropy = - torch.sum(p * torch.log2(p + 1e-4))
  • 计算熵 entropy

python

复制

            reg_ += lamb_l1 * l1 + lamb_entropy * entropy
  • 将当前层的L1正则化和熵正则化加到总正则化损失 reg_ 上。

python

复制

    return reg_
  • 返回计算得到的总正则化损失 reg_

 

closure闭包

def closure():global train_loss, reg_optimizer.zero_grad()pred = self.forward(dataset['train_input'][train_id].to(self.device))train_loss = loss_fn(pred, dataset['train_label'][train_id].to(self.device))if self.save_act:if reg_metric == 'fa':self.attribute()reg_ = self.get_reg(reg_metric, lamb_l1, lamb_entropy)else:reg_ = torch.tensor(0.)objective = train_loss + lamb * reg_objective.backward()return objective
def closure():global train_loss, reg_
  • 定义一个名为 closure 的函数。这个函数将被用作优化器中的闭包,用于计算损失并执行反向传播。
  • 使用 global 关键字声明 train_loss 和 reg_ 是全局变量,这样在函数内部对这些变量的修改会影响到外部作用域。

python

复制

    optimizer.zero_grad()
  • 清除优化器中所有参数的梯度。这是在每次迭代开始时必须执行的步骤,以确保不会累加之前的梯度。

python

复制

    pred = self.forward(dataset['train_input'][train_id].to(self.device))
  • 调用 self.forward 方法来获取模型的预测结果。这里的 dataset['train_input'][train_id] 是当前批次的数据,.to(self.device) 确保数据在正确的设备上(CPU或GPU)。

python

复制

    train_loss = loss_fn(pred, dataset['train_label'][train_id].to(self.device))
  • 使用提供的损失函数 loss_fn 计算预测结果 pred 和真实标签 dataset['train_label'][train_id] 之间的损失,并将结果赋值给全局变量 train_loss

python

复制

    if self.save_act:
  • 检查 self.save_act 是否为真。如果为真,则执行以下代码块。

python

复制

        if reg_metric == 'fa':self.attribute()
  • 如果 reg_metric 等于 'fa',则调用 self.attribute() 方法。这个方法可能是用来计算或者保存某些属性,但具体实现未在代码中给出。

python

复制

        reg_ = self.get_reg(reg_metric, lamb_l1, lamb_entropy)
  • 调用 self.get_reg 方法来计算正则化项 reg_。这个方法接受正则化类型 reg_metric、L1正则化系数 lamb_l1 和熵正则化系数 lamb_entropy 作为参数。

python

复制

    else:reg_ = torch.tensor(0.)
  • 如果 self.save_act 为假,则将正则化项 reg_ 设置为 0,即不应用正则化。

python

复制

    objective = train_loss + lamb * reg_
  • 计算最终的目标函数,它是训练损失 train_loss 和正则化项 lamb * reg_ 的和。

python

复制

    objective.backward()
  • 对目标函数执行反向传播,计算模型参数的梯度。

python

复制

    return objective
  • 返回计算得到的最终目标函数值。这个值可能用于调试或其他目的,但通常不是必须的,因为闭包的主要目的是执行反向传播。

 fit()

def fit(self, dataset, opt="LBFGS", steps=100, log=1, lamb=0., lamb_l1=1., lamb_entropy=2., loss_fn=None, lr=1., batch=-1,metrics=None, in_vars=None, out_vars=None, beta=3, device='cpu', reg_metric='w', display_metrics=None):if lamb > 0. and not self.save_act:print('setting lamb=0. If you want to set lamb > 0, set =True')old_save_act = self.save_actif lamb == 0.:self.save_act = Falsepbar = tqdm(range(steps), desc='description', ncols=100)if loss_fn == None:loss_fn = loss_fn_eval = lambda x, y: torch.mean((x - y) ** 2)else:loss_fn = loss_fn_eval = loss_fnif opt == "Adam":optimizer = torch.optim.Adam(self.parameters(), lr=lr)elif opt == "LBFGS":optimizer = LBFGS(self.parameters(), lr=lr, history_size=10, line_search_fn="strong_wolfe", tolerance_grad=1e-32, tolerance_change=1e-32, tolerance_ys=1e-32)results = {}results['train_loss'] = []results['test_loss'] = []results['reg'] = []if metrics != None:for i in range(len(metrics)):results[metrics[i].__name__] = []if batch == -1 or batch > dataset['train_input'].shape[0]:batch_size = dataset['train_input'].shape[0]batch_size_test = dataset['test_input'].shape[0]else:batch_size = batchbatch_size_test = batchglobal train_loss, reg_def closure():global train_loss, reg_optimizer.zero_grad()pred = self.forward(dataset['train_input'][train_id].to(self.device))train_loss = loss_fn(pred, dataset['train_label'][train_id].to(self.device))if self.save_act:if reg_metric == 'fa':self.attribute()reg_ = self.get_reg(reg_metric, lamb_l1, lamb_entropy)else:reg_ = torch.tensor(0.)objective = train_loss + lamb * reg_objective.backward()return objectivefor _ in pbar:if _ == steps-1 and old_save_act:self.save_act = Truetrain_id = np.random.choice(dataset['train_input'].shape[0], batch_size, replace=False)test_id = np.random.choice(dataset['test_input'].shape[0], batch_size_test, replace=False)if opt == "LBFGS":optimizer.step(closure)if opt == "Adam":pred = self.forward(dataset['train_input'][train_id].to(self.device))train_loss = loss_fn(pred, dataset['train_label'][train_id].to(self.device))if self.save_act:reg_ = self.get_reg(reg_metric, lamb_l1, lamb_entropy)else:reg_ = torch.tensor(0.)loss = train_loss + lamb * reg_optimizer.zero_grad()loss.backward()optimizer.step()test_loss = loss_fn_eval(self.forward(dataset['test_input'][test_id].to(self.device)), dataset['test_label'][test_id].to(self.device))if metrics != None:for i in range(len(metrics)):results[metrics[i].__name__].append(metrics[i]().item())results['train_loss'].append(torch.sqrt(train_loss).cpu().detach().numpy())results['test_loss'].append(torch.sqrt(test_loss).cpu().detach().numpy())results['reg'].append(reg_.cpu().detach().numpy())if _ % log == 0:if display_metrics == None:pbar.set_description("| train_loss: %.2e | test_loss: %.2e | reg: %.2e | " % (torch.sqrt(train_loss).cpu().detach().numpy(), torch.sqrt(test_loss).cpu().detach().numpy(), reg_.cpu().detach().numpy()))else:string = ''data = ()for metric in display_metrics:string += f' {metric}: %.2e |'try:results[metric]except:raise Exception(f'{metric} not recognized')data += (results[metric][-1],)pbar.set_description(string % data)return results@propertydef connection_cost(self):with torch.no_grad():cc = 0.for linear in self.linears:t = torch.abs(linear.weight)def get_coordinate(n):return torch.linspace(0,1,steps=n+1, device=self.device)[:n] + 1/(2*n)in_dim = t.shape[0]x_in = get_coordinate(in_dim)out_dim = t.shape[1]x_out = get_coordinate(out_dim)dist = torch.abs(x_in[:,None] - x_out[None,:])cc += torch.sum(dist * t)return ccdef swap(self, l, i1, i2):def swap_row(data, i1, i2):data[i1], data[i2] = data[i2].clone(), data[i1].clone()def swap_col(data, i1, i2):data[:,i1], data[:,i2] = data[:,i2].clone(), data[:,i1].clone()swap_row(self.linears[l-1].weight.data, i1, i2)swap_row(self.linears[l-1].bias.data, i1, i2)swap_col(self.linears[l].weight.data, i1, i2)def auto_swap_l(self, l):num = self.width[l]for i in range(num):ccs = []for j in range(num):self.swap(l,i,j)self.get_act()self.attribute()cc = self.connection_cost.detach().clone()ccs.append(cc)self.swap(l,i,j)j = torch.argmin(torch.tensor(ccs))self.swap(l,i,j)def auto_swap(self):depth = self.depthfor l in range(1, depth):self.auto_swap_l(l)def tree(self, x=None, in_var=None, style='tree', sym_th=1e-3, sep_th=1e-1, skip_sep_test=False, verbose=False):if x == None:x = self.cache_dataplot_tree(self, x, in_var=in_var, style=style, sym_th=sym_th, sep_th=sep_th, skip_sep_test=skip_sep_test, verbose=verbose)
def fit(self, dataset, opt="LBFGS", steps=100, log=1, lamb=0., lamb_l1=1., lamb_entropy=2., loss_fn=None, lr=1., batch=-1,metrics=None, in_vars=None, out_vars=None, beta=3, device='cpu', reg_metric='w', display_metrics=None):
  • 定义了一个名为 fit 的方法,它是用来训练神经网络的。它接受多个参数,包括数据集、优化器选项、训练步骤数、日志频率、正则化参数、损失函数、学习率等。

python

复制

if lamb > 0. and not self.save_act:print('setting lamb=0. If you want to set lamb > 0, set =True')
  • 检查正则化参数 lamb 是否大于 0 且 self.save_act 是否为 False。如果是,则打印一条消息,并建议设置 self.save_act 为 True。

python

复制

old_save_act = self.save_act
if lamb == 0.:self.save_act = False
  • 保存原始的 self.save_act 值,并根据 lamb 的值设置 self.save_act

python

复制

pbar = tqdm(range(steps), desc='description', ncols=100)
  • 创建一个进度条,用于显示训练进度。

python

复制

if loss_fn == None:loss_fn = loss_fn_eval = lambda x, y: torch.mean((x - y) ** 2)
else:loss_fn = loss_fn_eval = loss_fn
  • 如果没有提供损失函数,则使用均方误差作为默认损失函数。否则,使用提供的损失函数。

python

复制

if opt == "Adam":optimizer = torch.optim.Adam(self.parameters(), lr=lr)
elif opt == "LBFGS":optimizer = LBFGS(self.parameters(), lr=lr, history_size=10, line_search_fn="strong_wolfe", tolerance_grad=1e-32, tolerance_change=1e-32, tolerance_ys=1e-32)
  • 根据优化器选项 opt 创建一个优化器对象。

python

复制

results = {}
results['train_loss'] = []
results['test_loss'] = []
results['reg'] = []
if metrics != None:for i in range(len(metrics)):results[metrics[i].__name__] = []
  • 初始化一个字典 results 用于存储训练过程中的结果,包括训练损失、测试损失和正则化项。如果提供了 metrics,则为每个度量初始化一个空列表。

python

复制

if batch == -1 or batch > dataset['train_input'].shape[0]:batch_size = dataset['train_input'].shape[0]batch_size_test = dataset['test_input'].shape[0]
else:batch_size = batchbatch_size_test = batch
  • 确定批处理大小,如果 batch 参数小于等于 -1 或大于训练集大小,则使用整个数据集。

python

复制

global train_loss, reg_
  • 声明 train_loss 和 reg_ 为全局变量。

python

复制

def closure():# ...
  • 定义一个闭包函数 closure,用于优化器的内部使用。

python

复制

for _ in pbar:# ...
  • 使用进度条进行迭代训练过程。

python

复制

if _ == steps-1 and old_save_act:self.save_act = True
  • 在最后一次迭代时,如果原始的 self.save_act 为 True,则将其重新设置为 True。

python

复制

train_id = np.random.choice(dataset['train_input'].shape[0], batch_size, replace=False)
test_id = np.random.choice(dataset['test_input'].shape[0], batch_size_test, replace=False)
  • 随机选择训练和测试数据的批次。

python

复制

if opt == "LBFGS":optimizer.step(closure)
  • 如果使用的是 LBFGS 优化器,则调用闭包函数进行优化步骤。

python

复制

# ... (省略了 Adam 优化器的代码)

python

复制

test_loss = loss_fn_eval(self.forward(dataset['test_input'][test_id].to(self.device)), dataset['test_label'][test_id].to(self.device))
  • 计算测试集上的损失。

python

复制

if metrics != None:for i in range(len(metrics)):results[metrics[i].__name__].append(metrics[i]().item())
  • 如果提供了度量函数,则计算并存储这些度量的结果。
  • ……、

【】

@propertydef connection_cost(self):with torch.no_grad():cc = 0.for linear in self.linears:t = torch.abs(linear.weight)def get_coordinate(n):return torch.linspace(0,1,steps=n+1, device=self.device)[:n] + 1/(2*n)in_dim = t.shape[0]x_in = get_coordinate(in_dim)out_dim = t.shape[1]x_out = get_coordinate(out_dim)dist = torch.abs(x_in[:,None] - x_out[None,:])cc += torch.sum(dist * t)return ccdef swap(self, l, i1, i2):def swap_row(data, i1, i2):data[i1], data[i2] = data[i2].clone(), data[i1].clone()def swap_col(data, i1, i2):data[:,i1], data[:,i2] = data[:,i2].clone(), data[:,i1].clone()swap_row(self.linears[l-1].weight.data, i1, i2)swap_row(self.linears[l-1].bias.data, i1, i2)swap_col(self.linears[l].weight.data, i1, i2)def auto_swap_l(self, l):num = self.width[l]for i in range(num):ccs = []for j in range(num):self.swap(l,i,j)self.get_act()self.attribute()cc = self.connection_cost.detach().clone()ccs.append(cc)self.swap(l,i,j)j = torch.argmin(torch.tensor(ccs))self.swap(l,i,j)def auto_swap(self):depth = self.depthfor l in range(1, depth):self.auto_swap_l(l)def tree(self, x=None, in_var=None, style='tree', sym_th=1e-3, sep_th=1e-1, skip_sep_test=False, verbose=False):if x == None:x = self.cache_dataplot_tree(self, x, in_var=in_var, style=style, sym_th=sym_th, sep_th=sep_th, skip_sep_test=skip_sep_test, verbose=verbose)逐行解释
@property
def connection_cost(self):
  • 定义一个名为 connection_cost 的属性方法,它将计算并返回网络中所有线性层权重的“连接成本”。

python

复制

with torch.no_grad():cc = 0.for linear in self.linears:t = torch.abs(linear.weight)def get_coordinate(n):return torch.linspace(0,1,steps=n+1, device=self.device)[:n] + 1/(2*n)in_dim = t.shape[0]x_in = get_coordinate(in_dim)out_dim = t.shape[1]x_out = get_coordinate(out_dim)dist = torch.abs(x_in[:,None] - x_out[None,:])cc += torch.sum(dist * t)return cc
  • 在不计算梯度的情况下,初始化 cc 为 0,遍历网络中的每个线性层。
  • 对于每个线性层,计算其权重的绝对值 t
  • 定义一个内部函数 get_coordinate 来获取每个维度上的坐标。
  • 计算 in_dim 和 out_dim 的坐标 x_in 和 x_out
  • 计算输入和输出坐标之间的距离 dist
  • 将距离与权重相乘并累加到 cc 中。
  • 返回累加的连接成本 cc

python

复制

def swap(self, l, i1, i2):
  • 定义一个名为 swap 的方法,它将交换第 l 层线性层的第 i1 和第 i2 行(权重)以及对应的偏置。

python

复制

def swap_row(data, i1, i2):data[i1], data[i2] = data[i2].clone(), data[i1].clone()def swap_col(data, i1, i2):data[:,i1], data[:,i2] = data[:,i2].clone(), data[:,i1].clone()swap_row(self.linears[l-1].weight.data, i1, i2)
swap_row(self.linears[l-1].bias.data, i1, i2)
swap_col(self.linears[l].weight.data, i1, i2)
  • 定义两个内部函数 swap_row 和 swap_col 用于交换行和列。
  • 使用这些函数交换指定层线性层权重和偏置的行和列。

python

复制

def auto_swap_l(self, l):
  • 定义一个名为 auto_swap_l 的方法,它将自动交换第 l 层的行,以最小化连接成本。

python

复制

num = self.width[l]
for i in range(num):ccs = []for j in range(num):self.swap(l,i,j)self.get_act()self.attribute()cc = self.connection_cost.detach().clone()ccs.append(cc)self.swap(l,i,j)j = torch.argmin(torch.tensor(ccs))self.swap(l,i,j)
  • 获取第 l 层的宽度 num
  • 遍历所有行 i,对于每一行,尝试与所有其他行 j 交换。
  • 在每次交换后,计算连接成本 cc 并存储在 ccs 列表中。
  • 恢复交换前的状态。
  • 选择连接成本最小的交换,并执行最终的交换。

python

复制

def auto_swap(self):
  • 定义一个名为 auto_swap 的方法,它将遍历所有层并调用 auto_swap_l 来最小化整个网络的连接成本。

python

复制

depth = self.depth
for l in range(1, depth):self.auto_swap_l(l)
  • 获取网络的深度 depth
  • 遍历所有层(除了输入层),并对每一层调用 auto_swap_l

python

复制

def tree(self, x=None, in_var=None, style='tree', sym_th=1e-3, sep_th=1e-1, skip_sep_test=False, verbose=False):
  • 定义一个名为 tree 的方法,它可能用于绘制或分析网络的树状结构。

python

复制

if x == None:x = self.cache_data
plot_tree(self, x, in_var=in_var, style=style, sym_th=sym_th, sep_th=sep_th, skip_sep_test=skip_sep_test, verbose=verbose)
  • 如果没有提供输入数据 x,则使用缓存的 self.cache_data
  • 调用 plot_tree 函数来绘制或分析网络,这个函数可能是在其他地方定义的。


http://www.mrgr.cn/news/63818.html

相关文章:

  • C语言中插入排序
  • 分享一些在部署k8s集群时遇到的问题
  • Linux(Cent OS)环境离线安装mkfontscale mkfontdir命令 解决java项目在linux系统下无法获取中文字体问题
  • 图神经网络(GNN):处理图结构数据的 AI 新宠
  • 程序中怎样用最简单方法实现写excel文档
  • 【安全性分析】正式安全分析与非正式安全分析
  • ST IoT Wireless 物联网与无线技术 研讨会
  • 现代生产系统DORA的应用与集成
  • 理解typeScript中的高级类型
  • 如何在Linux下部署自己的ZFile开源网盘
  • 使用MongoDB Atlas构建无服务器数据库
  • CentOS下载ISO镜像的方法
  • CF983(div2)(未补)
  • Ubuntu软件包管理机制
  • PyTorch实践-CNN-鸢尾花分类
  • 资深项目经理推荐的这五款国产项目管理软件值得收藏使用
  • Kotlin一之内置类型
  • 【数据结构】构造函数和析构函数
  • Linux 进程间通信——管道
  • 问答系统评估标准
  • 安装scrcpy-client模块av模块异常,环境问题解决方案
  • leetcode hot100【LeetCode 279. 完全平方数】java实现
  • Pandas JSON学习
  • 遥感辐射传输方程中的格林函数
  • PyTorch实践-CNN-手写数字识别
  • [Web安全 网络安全]-学习视频分享汇总(持续更新中)