摘要
前面五节学习了信息如何从外界进入数字大脑加工处理,并输出决策信号。单个神经元、单层神经元、多层神经元的不同组合,功能分工也不同,本节学习如何通过模块化的方式实现对不同基本功能分工的规范化管理和协调。
从信息流转到模块化设计
前面我们学习了预备知识,理解了信息在数字大脑中流转的基本原理和规则:
1. 信息的存在方式:电信号编码和传递的规则(张量的存储和操作)
2. 信息的读取:眼耳机制(pandas工具)
3. 信息的道路调整:突触影响力计算和可塑性实现(自动微分、反向传播、梯度下降算法)
4. 信息的转换输出:不确定性推理(概率估计)
然后,我们学习线性神经网络,理解数字大脑中最基础最简单的线性推理单元。多个只有线性计算规则的神经元组成的单层,可以对输入信号做出预测信号输出(线性回归)或类别信号输出(softmax回归)。
最后,我们学习多层感知机,理解数字大脑中拥有更强表达能力和推理能力的基本网络——MLP。在每个单层线性神经元后增加激活通道(激活线性信号,可选Dropout机制避免神经元共适应),从而增强表达能力;并且单层可增加至多层,这样每层负责不同级别的特征提取,使得推理有序分工、高效明确。
此外,为保证多层的神经元信号数值稳定与泛化稳定,可选参数初始化、BatchNorm、Weight Decay、Adam定制步长、Clipping、Dropout、训练样本量增加、环境和分布偏移的适应系统、根据环境调整的学习范式。
如果说每个神经元是基础信号处理,每个单层相当于大脑皮层的一个个功能柱(如方向柱、频率柱、颜色柱),那么多个单层就有可能组成一个功能模块,专门负责某种子任务的决策,比如视觉皮层V1区、海马体环路等;而多个模块组合成复杂网络,可以完成更复杂的任务。
类似于生物细胞的分裂和分化,我们需要将不同层的转换函数、不同模块按功能分工做一定的抽象,就像生物体中的细胞、组织、器官被抽象出来一样,各自有基本的功能分工,有序规范地运行。
1. 层和块:大脑的功能柱和功能区及复用模板
现实任务是多种多样的,构建的网络也千种万种,这意味着功能模块(器官组织)的基本结构和功能常常需要复用。
为方便复用,PyTorch的nn模块中给出了Module模板,包含了:
• 登记所有参数的参数管理本:net.parameters()、net.named_parameters()
• 自动微分后台:计算和保存梯度
• 模型设备切换功能:net.to(device)
• 模型保存和加载接口:net.state_dict()
• 可放置多个子模块的字典:self._modules属性
通过class 功能模块名(nn.Module)即可继承模板,通过super().__init__()激活模板上述预装功能。我们只需在其中定义好各层神经元的信号处理函数、以及信号传递过程(前向传播)即可。
我们也可以通过Module模板构造MySequential:将按顺序输入的函数记录在Module父类内置属性_modules字典中(自带激活登记参数、转移模型、初始化、保存等操作),再遍历前向传播,实现顺序串接层/模块。
2. 参数管理:突触数量与大小的调控
PyTorch中的参数管理函数可分为以下几类:
模型对象(nn.Module实例):通过索引或层属性名可定位对应层
所有参数的集合:通过参数名(键)从字典中访问对应参数值(值)
• state_dict():参数字典(用于保存/加载)
• named_parameters():(参数名, 参数对象) 迭代器
• parameters():参数对象迭代器
单个层的参数类:
• .weight:权重参数(nn.Parameter)
• .bias:偏置参数(nn.Parameter,可选)
参数类中参数的数值与梯度(通过索引访问data张量中的切片):
• .data:直接访问或修改数值(不记录计算图)
• .grad:访问反向传播后的梯度
| |
|---|
| |
| |
| |
| |
| |
| state_dict()['2.bias'].data |
| |
| nn.init.xavier_uniform_() |
| net[0].apply(init_xavier) |
| net[0].weight.data[:] += 1 |
参数共享:
shared = nn.Linear(8, 8)
net = nn.Sequential(
nn.Linear(4, 8), nn.ReLU(),
shared, nn.ReLU(),
shared, nn.ReLU(),
nn.Linear(8, 1)
)
net(X)
print(net[2].weight.data[0] == net[4].weight.data[0]) # True
当参数绑定时,梯度会发生什么情况?答案是:由于模型参数包含梯度,因此在反向传播期间第二个隐藏层和第三个隐藏层的梯度会加在一起。参数共享方便我们用更少的参数学到更本质更通用的规则。
注意:由于前向传播函数为y = xW^T,所以W的形状为(out_feature, in_feature)。
3. 延后初始化:经验驱动的突触生成
前面设计网络结构时,如果没有输入数据的形状信息,无法指定输入维度,也不能确定有多少个参数。在传入输入数据第一次经过模型前向传播后,会自动计算各层维度和参数数量,并默认真正使用初始化。
比如nn.LazyLinear(256)未指定维度,此时访问weight的值会出错,直到传入数据第一次经过模型前向传播才会真正初始化参数的形状和大小。若自定义初始化,需在第一次传播后使用;或者继承LazyLinear,重写_reset_parameters。
4. 读写文件:突触的保存与加载
定期保存训练的模型参数,方便下次直接读取,也可以避免因突然断电导致需要重新训练。
5. GPU:神经元集群的并行加速计算
核心要点:
• 我们可以指定用于存储和计算的设备,例如CPU或GPU。默认情况下,数据在主内存中创建,然后使用CPU进行计算
• 深度学习框架要求计算的所有输入数据都在同一设备上,无论是CPU还是GPU
• 不经意地移动数据可能会显著降低性能。一个典型的错误是:计算GPU上每个小批量的损失,并在命令行中将其报告给用户时,将触发全局解释器锁,从而使所有GPU阻塞
• 要使用GPU,必须确保安装了一个NVIDIA GPU,并下载了NVIDIA驱动和CUDA
| |
|---|
| |
| device=torch.device('cuda') |
| torch.cuda.device_count() |
| |
| |
重要区别:CPU内存(RAM)vs GPU显存(VRAM),两者是物理隔离的独立存储空间。打印GPU张量、调用.numpy()时,框架会自动将数据从GPU显存复制到CPU内存,由于总线带宽有限,传输开销和时间比较大。大计算量用GPU快,小计算量用CPU快,因为有数据传输的开销。
留言
模块化的管理方式,使得数字大脑功能分工更规范、任务完成更高效!
关注小鱼,一起游历AI世界