如何构建指定连接占比的半全连接神经网络?适配GPU与正交初始化
构建稀疏连接的全连接网络(半全连接网络)
你可以通过生成带稀疏掩码的权重矩阵来实现半全连接网络,这种方法既能满足指定连接占比的需求,又能利用PyTorch的GPU加速能力,避免低效的循环操作。同时也能轻松支持正交初始化,以下是具体实现方案:
核心思路
- 为每层权重矩阵生成随机稀疏掩码:掩码中仅保留指定比例的位置为1(代表存在连接),其余为0(无连接)。
- 先对全权重矩阵做正交初始化,再与掩码相乘得到稀疏权重,确保保留的连接权重符合正交性要求。
- 前向传播直接使用稀疏权重做矩阵乘法,PyTorch会自动处理并行计算并利用GPU加速。
代码实现
1. 稀疏权重生成与正交初始化工具函数
import torch import torch.nn.init as init def create_sparse_orthogonal_weights(in_features, out_features, connection_percent): # 计算每个输入神经元需要连接的输出神经元数量 num_connections = int(out_features * connection_percent) # 初始化全权重矩阵并执行正交初始化 weights = torch.empty(in_features, out_features) init.orthogonal_(weights) # 生成稀疏掩码:每个输入神经元随机选择指定数量的输出神经元建立连接 mask = torch.zeros_like(weights) for i in range(in_features): # 随机挑选不重复的输出神经元索引 indices = torch.randperm(out_features)[:num_connections] mask[i, indices] = 1. # 应用掩码得到最终的稀疏权重 sparse_weights = weights * mask return sparse_weights
2. 构建10层稀疏连接网络
# 输入张量(可直接移至GPU) input_tensor = torch.rand(1, 10).cuda() if torch.cuda.is_available() else torch.rand(1, 10) # 定义网络结构参数 layer_sizes = [10] + [32] * 10 # 输入层10个神经元,后续10层各32个神经元 connection_percent = 0.1 # 每个神经元仅连接下一层10%的神经元 # 生成各层稀疏权重 layers_weights = [] for i in range(len(layer_sizes)-1): in_size = layer_sizes[i] out_size = layer_sizes[i+1] w = create_sparse_orthogonal_weights(in_size, out_size, connection_percent) if torch.cuda.is_available(): w = w.cuda() layers_weights.append(w) # 前向传播计算 x = input_tensor for w in layers_weights: x = torch.sin(torch.mm(x, w)) print(x.shape) # 输出:torch.Size([1, 32])
优化说明
- GPU加速:将张量和权重移至GPU后,PyTorch的矩阵乘法会自动调用CUDA并行计算,效率远高于循环实现。
- 固定连接结构:如果需要训练过程中保持连接结构不变,只需在网络初始化时生成一次掩码即可;若需动态调整连接,可在每次前向传播时重新生成掩码(不推荐,会增加计算开销)。
- 内存优化(可选):如果网络规模极大,可使用PyTorch的
torch.sparse.Tensor存储稀疏权重,进一步降低内存占用:
def create_sparse_tensor_weights(in_features, out_features, connection_percent): num_connections = int(out_features * connection_percent) total_nonzeros = in_features * num_connections # 生成非零元素的行列索引 rows = torch.repeat_interleave(torch.arange(in_features), num_connections) cols = torch.cat([torch.randperm(out_features)[:num_connections] for _ in range(in_features)]) # 生成归一化的权重值(模拟正交初始化效果) weights = torch.empty(total_nonzeros) init.normal_(weights) weights = weights.view(in_features, num_connections) weights = torch.nn.functional.normalize(weights, p=2, dim=1) weights = weights.flatten() # 创建稀疏张量 sparse_weights = torch.sparse_coo_tensor( torch.stack([rows, cols]), weights, size=(in_features, out_features), device='cuda' if torch.cuda.is_available() else 'cpu' ) return sparse_weights
使用时前向传播改为torch.sparse.mm(x, sparse_weights)即可。
内容的提问来源于stack exchange,提问作者Penguin
相关产品推荐
相关产品推荐

