fangwei123456 / spikingjelly

SpikingJelly is an open-source deep learning framework for Spiking Neural Network (SNN) based on PyTorch.
https://spikingjelly.readthedocs.io
Other
1.35k stars 239 forks source link

关于cifar10_r11_enabling_spikebased_backpropagation.py #136

Closed EmmmaEric closed 2 years ago

EmmmaEric commented 2 years ago

您好, 我能请问一下您在这个example中的spikingjelly/spikingjelly/clock_driven/examples/cifar10_r11_enabling_spikebased_backpropagation.py 运行环境设定嘛?(library version啥的)然后运行这个代码是直接python cifar10_r11_enabling_spikebased_backpropagation.py 后面加dataset的path嘛?

谢谢您的帮助

fangwei123456 commented 2 years ago
python -m spikingjelly.clock_driven.examples.cifar10_r11_enabling_spikebased_backpropagation -h
usage: cifar10_r11_enabling_spikebased_backpropagation.py [-h] [-j N] [-b N] [-T TIMESTEPS] [--lr LR] [--pretrained] [--gpu GPU] DIR

spikingjelly CIFAR10 Training

positional arguments:
  DIR                   path to dataset

optional arguments:
  -h, --help            show this help message and exit
  -j N, --workers N     number of data loading workers (default: 4)
  -b N, --batch-size N
  -T TIMESTEPS, --timesteps TIMESTEPS
                        Simulation timesteps
  --lr LR, --learning-rate LR
                        initial learning rate
  --pretrained          use pre-trained parameters.
  --gpu GPU             GPU id to use.
fangwei123456 commented 2 years ago

python -m spikingjelly.clock_driven.examples.cifar10_r11_enabling_spikebased_backpropagation后面跟运行参数就行

Yanqi-Chen commented 2 years ago

我的环境是PyTorch 1.6.0, torchvision 0.7.0, CUDA 10.1 把这一行 https://github.com/fangwei123456/spikingjelly/blob/6648e0cc3dddded57f4b875ea25bedc1b6f04814/spikingjelly/clock_driven/examples/cifar10_r11_enabling_spikebased_backpropagation.py#L236 改成

    learning_rate = args.lr

然后执行

python -m spikingjelly.clock_driven.examples.cifar10_r11_enabling_spikebased_backpropagation <数据集路径> --gpu <GPUID>

这样应该可以跑,这个bug我修复一下

EmmmaEric commented 2 years ago

谢谢您的答复

我再请问一下(如下是源代码的network) class CNNModel(nn.Module): def init(self): super(CNNModel, self).init() self.cnn11 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False) self.cnn12 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False) self.avgpool1 = nn.AvgPool2d(kernel_size=2)

    self.cnn21 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1, bias=False)
    self.cnn22 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1, bias=False)
    self.avgpool2 = nn.AvgPool2d(kernel_size=2)

    self.cnn31 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False)
    self.cnn32 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False)
    self.cnn33 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False)
    self.avgpool3 = nn.AvgPool2d(kernel_size=2)

    self.fc0 = nn.Linear(256 * 4 * 4, 1024, bias=False)
    self.fc1 = nn.Linear(1024, 10, bias=False)

...... ......

fully-connected Layer

        membrane_f0 = membrane_f0 + self.fc0(out)
        membrane_f0, out = LIF_sNeuron(membrane_f0, self.fc0.threshold, l, i)
        out = torch.mul(out, mask_f0)
        LF_f0_output, Total_f0_output, out = LF_Unit(l, LF_f0_output, Total_f0_output, out, outf0_temp, i)

        membrane_f1 = membrane_f1 + self.fc1(out)
        membrane_f1 = l * membrane_f1.detach() + membrane_f1 - membrane_f1.detach()

他计算的最后的menbrane_f1 是一个accumulated的值,每一次loop 增加self.fc1(out)

而在您的代码: for t in range(T - 1):

Poisson encoding

            rand_num = torch.rand_like(img).cuda()
            poisson_input = (torch.abs(img) > rand_num).float()
            poisson_input = torch.mul(poisson_input, torch.sign(img))

            net(poisson_input)

        output = net(poisson_input)

您在中间有call net(poisson_input),然后最后output= net(poisson_input). 我没有很理解这里是如何实现output是之前(T-1)次值得累加?我的理解您output仅仅是得到的最后一次的men potential != ∑nL−1i=1(wijxi(T)) . 您方便能分享一下您这一步的理解嘛?

再次谢谢您

Yanqi-Chen commented 2 years ago

这里涉及到具体实现比较复杂。首先,这份代码实际上是完全重写(但是数学上等价,可以给定输入和权重求梯度验证)了原始代码的前向和反向部分。

简单来说,这里最后一层的LIF神经元设定了一个参数fire=False https://github.com/fangwei123456/spikingjelly/blob/6648e0cc3dddded57f4b875ea25bedc1b6f04814/spikingjelly/clock_driven/examples/cifar10_r11_enabling_spikebased_backpropagation.py#L105 加上这个参数后,神经元永远不会发放脉冲,并且只输出当前时刻的电压 https://github.com/fangwei123456/spikingjelly/blob/6648e0cc3dddded57f4b875ea25bedc1b6f04814/spikingjelly/clock_driven/examples/cifar10_r11_enabling_spikebased_backpropagation.py#L117-L122 所以最后输出的就是累计的电压

Yanqi-Chen commented 2 years ago

@EmmmaEric 如果还有任何问题可以重新打开issue