对应内容【https://spikingjelly.readthedocs.io/zh-cn/0.0.0.0.14/activation_based/basic_concept.html#】
- spikingjelly.activation_based 使用取值仅为0或1的张量表示脉冲
- 基于激活值的表示方法
import torch
v = torch.rand([8])
v_th = 0.5
spike = (v >= v_th).to(v)
print('spike =', spike)
# spike = tensor([0., 0., 0., 1., 1., 0., 1., 0.])```
```python
在PyTorch中,`.to()`方法用于改变一个Tensor的数据类型或设备。在这个上下文中,`spike = (v >= v_th).to(v)`这行代码的目的是将比较操作`(v >= v_th)`的结果(一个布尔型Tensor)转换为与`v`相同的数据类型。
具体来说,`(v >= v_th)`会生成一个布尔型Tensor,其中每个元素的值根据`v`中对应元素是否大于或等于`v_th`来确定,结果为`True`或`False`。然后,`.to(v)`调用将这个布尔型Tensor转换为与`v`相同的数据类型。如果`v`是浮点型或整型,布尔型的`True`和`False`会被转换为相应的数值(通常是`1`和`0`)。
这种用法在处理神经网络时非常有用,特别是在需要将布尔型的掩码或条件操作的结果转换为神经网络可以处理的数值型数据时。
简而言之,`.to()`在这里用于确保结果Tensor与`v`有相同的数据类型,以便后续操作可以无缝进行。
import torch
from spikingjelly.activation_based import neuron
net_s = neuron.IFNode(step_mode='s')
T = 4
N = 1
C = 3
H = 8
W = 8
x_seq = torch.rand([T, N, C, H, W])
y_seq = []
print("###########################################################################")
for t in range(T):
print("----------")
x = x_seq[t] # x.shape = [1, 3, 8, 8]
print("x的shape=",x.shape)
print("x=",x)
y = net_s(x) # y.shape = [N, C, H, W]
print("y的shape=",y.shape)
print("y=",y)
y_seq.append(y.unsqueeze(0))
print("y_seq=",y_seq)
print("最后的y_seq=",y_seq)
y_seq = torch.cat(y_seq)
print(y_seq.shape)
print("最后的y_seq CAT之后的=",y_seq)
# y_seq.shape = [T, N, C, H, W]
import torch
from spikingjelly.activation_based import neuron
net_s = neuron.IFNode(step_mode='s')
x = torch.rand([4])
print(net_s)
print(f'the initial v={net_s.v}')
y = net_s(x)
print(f'x={x}')
print(f'y={y}')
print(f'v={net_s.v}')
# outputs are:
'''
IFNode(
v_threshold=1.0, v_reset=0.0, detach_reset=False
(surrogate_function): Sigmoid(alpha=4.0, spiking=True)
)
the initial v=0.0
x=tensor([0.5543, 0.0350, 0.2171, 0.6740])
y=tensor([0., 0., 0., 0.])
v=tensor([0.5543, 0.0350, 0.2171, 0.6740])
'''
初始if的v=0
x通过if之后
y是激活之后的脉冲可能是0或者1
if神经元的电压会保持
import torch
from spikingjelly.activation_based import neuron
net_s = neuron.IFNode(step_mode='s')
x = torch.rand([4])
print(f'check point 0: v={net_s.v}')
y = net_s(x)
print(f'check point 1: v={net_s.v}')
net_s.reset()
print(f'check point 2: v={net_s.v}')
x = torch.rand([8])
y = net_s(x)
print(f'check point 3: v={net_s.v}')
# outputs are:
'''
check point 0: v=0.0
check point 1: v=tensor([0.9775, 0.6598, 0.7577, 0.2952])
check point 2: v=0.0
check point 3: v=tensor([0.8728, 0.9031, 0.2278, 0.5089, 0.1059, 0.0479, 0.5008, 0.8530])
'''
import torch
import torch.nn as nn
from spikingjelly.activation_based import neuron, functional, layer
T = 4
N = 2
C = 8
x_seq = torch.rand([T, N, C]) * 64.
net = nn.Sequential(
layer.Linear(C, 4),
neuron.IFNode(),
layer.Linear(4, 2),
neuron.IFNode()
)
functional.set_step_mode(net, step_mode='m')
with torch.no_grad():
y_seq_layer_by_layer = x_seq
for i in range(net.__len__()):
y_seq_layer_by_layer = net[i](y_seq_layer_by_layer)
print(f'y_seq_layer_by_layer=\n{y_seq_layer_by_layer}')
import torch
import torch.nn as nn
from spikingjelly.activation_based import neuron, functional, layer
T = 4
N = 2
C = 3
H = 8
W = 8
x_seq = torch.rand([T, N, C, H, W]) * 64.
net = nn.Sequential(
layer.Conv2d(3, 8, kernel_size=3, padding=1, stride=1, bias=False),
neuron.IFNode(),
layer.MaxPool2d(2, 2),
neuron.IFNode(),
layer.Flatten(start_dim=1),
layer.Linear(8 * H // 2 * W // 2, 10),
neuron.IFNode(),
)
print(f'net={net}')
with torch.no_grad():
y_seq_step_by_step = []
for t in range(T):
x = x_seq[t]
y = net(x)
y_seq_step_by_step.append(y.unsqueeze(0))
y_seq_step_by_step = torch.cat(y_seq_step_by_step, 0)
# we can also use `y_seq_step_by_step = functional.multi_step_forward(x_seq, net)` to get the same results
print(f'y_seq_step_by_step=\n{y_seq_step_by_step}')
functional.reset_net(net)
functional.set_step_mode(net, step_mode='m')
y_seq_layer_by_layer = net(x_seq)
max_error = (y_seq_layer_by_layer - y_seq_step_by_step).abs().max()
print(f'max_error={max_error}')
尽管两者区别仅在于计算顺序,但计算速度和内存消耗上会略有区别。
在使用梯度替代法训练时,通常推荐使用逐层传播。在正确构建网络的情况下,逐层传播的并行度更大,速度更快
训练的时候用layer by layer 一层一层训练
在内存受限时使用逐步传播,例如ANN2SNN任务中需要用到非常大的 T。因为在逐层传播模式下,对无状态的层而言,真正的 batch size 是 TN 而不是 N (参见下一个教程),当 T 太大时内存消耗极大
snn推理的时候,一次的缓存有限,要一步一步来