Python module

本文详细介绍了在PyTorch中如何通过.module属性访问DataParallel包装的模型,以及.children和.modules方法遍历和操作模型的子模块。文章还提供了不同方式注册hook函数的示例,展示了对模型结构的不同层次遍历方法。
摘要由CSDN通过智能技术生成

在PyTorch中,.module属性通常用于访问DataParallel包装的模型的原始模型。当你使用DataParallel包装模型时,原始模型会被包装在module属性下。这是为了处理多GPU训练时的并行计算。

如果你没有使用DataParallel包装模型,你应该可以直接通过模型对象访问模块,而不需要使用.module属性。只有在使用DataParallel包装模型时,原始模型会被放在.module下。

所以,如果你在模型上使用了DataParallel,那么你应该使用.module来访问原始模型的属性和方法。如果没有使用DataParallel,你可以直接通过模型对象访问属性和方法,而不需要.module

1、module:

_modules 可以直接获取特定名称的子模块对象,但无法直接获取名称以及遍历所有子模块,所以需要递归是一个字典,所以其好处就是可以直接用键值索引,坏处是无法直接迭代需要用items(),其中键是子模块的名称,值是对应的子模块对象。
_moudules.items()是迭代字典的基本用法,返回可迭代对象,基操如下:

for key, value in my_dict.items():
    print(key, value)

如果是:

for key in my_dict:
    print(key)

则迭代一个字典的键。

所以看下面这段代码:

for name, module in model._modules.items():
	if hasattr(module, "_modules"):
		.....

name: layer1 (key)
module: Sequential() (value)

2、children

children() 方法返回一个迭代器,用于遍历模型的直接子模块。它只返回子模块的对象,不包含子模块的名称
model.named_children() 返回一个迭代器,该迭代器依次生成由子模块名称和子模块对象组成的元组
每个元组的结构是 (name, child),其中 name 是子模块的名称,child 是子模块对象本身

for name, child in model.named_children():

这和上面的效果是一样的。
而且:model._modules[name]child是一样的

3、modules

def modules(self) -> Iterator[‘Module’]:
Returns an iterator over all modules in the network.

modules(): 返回一个迭代器,提供模型及其所有子模块(包括子模块的子模块,这样就不用递归了
named_modules(): 返回一个迭代器,提供模型及其所有子模块的名称和对象
官方实例:

>>> l = nn.Linear(2, 2)
>>> net = nn.Sequential(l, l)
>>> for idx, m in enumerate(net.modules()):
...     print(idx, '->', m)

0 -> Sequential(
 (0): Linear(in_features=2, out_features=2, bias=True)
 (1): Linear(in_features=2, out_features=2, bias=True)
)
1 -> Linear(in_features=2, out_features=2, bias=True)

几个点:
1、当调用net.modules()时,它会返回模型中的所有模块,包括子模块
2、net.modules()返回的是模型及其子模块的生成器,而不是按照层级结构的生成器。由于这两个nn.Linear层是同一个对象,所以它们在模型中共享同一个索引编号。

4、practice

懂了上面之后我们可以写一个hook函数
Version1:用直接子模块迭代器

def add_IF_hook(model):
	for name, child in model.named_children():
			if isinstance(child, ScaledNeuron):
			child.register_forward_hook(save_spikes_number)
		else:
			add_IF_hook(child) # 需要递归children对应的是直接子模块

Version2:用属性_modules,items()转成迭代器

def add_IF_hook(model):
	for name, module in model._modules.items():
		if isinstance(module, ScaledNeuron):
			model._modules[name],register_forward_hook(save_spikes_number)
			#或者 module.register_forward_hook(save_spikes_number)
		else:
			add_IF_hook(module) #需要递归	

上面两个输出的形式是这样的:pipeline是先从layer1—sequential下去,然后到sequential里面找到ScaledNeuron:layer1.2

===> name: 2 child: ScaledNeuron(
(neuron): IFNode(
v_threshold=1.0, v_reset=None, detach_reset=False
(surrogate_function): Sigmoid(alpha=1.0, spiking=True)
)
)

Version3:用全部子模块,最简形式

def add_IF_hook(model):
    for name, module in model.named_modules():
        if isinstance(module, ScaledNeuron):
            print(f"===> name: {name}  child: {module}")
            module.register_forward_hook(save_spikes_number)

最后输出的形式是这样的:

===> name: layer1.2 child: ScaledNeuron(
(neuron): IFNode(
v_threshold=1.0, v_reset=None, detach_reset=False
(surrogate_function): Sigmoid(alpha=1.0, spiking=True)
)
)
===> name: layer1.6 child: ScaledNeuron(
(neuron): IFNode(
v_threshold=1.0, v_reset=None, detach_reset=False
(surrogate_function): Sigmoid(alpha=1.0, spiking=True)
)
)

5、

spikes = {'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}

# 使用enumerate(spikes.keys())遍历字典的键
for i, key in enumerate(spikes.keys()):
    print(f"Index: {i}, Key: {key}")

# 使用spikes.items()遍历字典的键和值
for key, value in spikes.items():
    print(f"Key: {key}, Value: {value}")

在这里插入图片描述

6、

.module 属性来访问原始的模型
如果没有parallel你访问module就会
'SNNVGG' object has no attribute 'module'
没有parallel直接访问即可啊

snn_model = torch.nn.DataParallel(snn_model).cuda()
layers_fin_fout = snn_model.module.calculate_fin_fout()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值