🎯 Goal
- Dataset을 spiking Dataset으로 변환
- 시각화 방법
- random spike trains 생성 방법
Intro
우리의 감각은 각각의 신호(빛, 냄새, 압력 등등)을 Spike로 변환 될 때 느낀다.
SNN을 구축하기 위해선 입력에서도 Spike 데이터를 입력하는 것이 맞으며 이때 데이터를 인코딩하는 데에는 3가지의 요소에서 비롯된다.

Spike (a) - (b)
생물학적 뉴런들은 spike를 통해 정보를 처리하고 소통한다. 대략 100mV의 전압 변화를 통해 1, 0으로 데이터를 단순화 한다. → 데이터의 단순화를 통해 하드웨어에서 효율적으로 처리 가능해진다.
Sparsity (c)
신경형 하드웨어 뉴런은 대부분이 비활성 즉 0인 상태로 유지하고 특정한 상황에서만 1로 활성화 되는 희소성(Sparsity)가 있다.
space complexity : 모든 벡터, 행렬이 0인 형태는 흔하기에 해당 데이터를 재사용 할 수 있으며 또한 대부분의 요소가 0이면 1인 위치만 저장해도 됨으로 메모리 절약이 크다.
time complexity : 0과 곱해지면 항상 0이니 이러한 과정의 계산 과정은 생략이 가능해진다. → 연산량이 줄어들어 계산 시간이 줄고 소비 전력도 줄어든다.
Static-suppression (d) - (e)
spike neuron의 출력은 0,1 이진의 값으로 표현될 수 있다. 즉 하드웨어의 구현이 단순해 짐으로써 하드웨어 구현이 단순해 진다.
Setup
MNIST dataset을 로드하고 환경 세팅하는 과정
$ pip install snntorch
Import package, 환경 설정
import snntorch as snn
import torch
# Training Parameters
batch_size=128
data_path='/tmp/data/mnist'
num_classes = 10 # MNIST has 10 output classes
# Torch Variables
dtype = torch.float
MNIST dataset 다운로드
from torchvision import datasets, transforms
# Define a transform
transform = transforms.Compose([
transforms.Resize((28,28)),
transforms.Grayscale(),
transforms.ToTensor(),
transforms.Normalize((0,), (1,))])
mnist_train = datasets.MNIST(data_path, train=True, download=True, transform=transform)
from snntorch import utils
subset = 10
mnist_train = utils.data_subset(mnist_train, subset)
>>> print(f"The size of mnist_train is {len(mnist_train)}")
The size of mnist_train is 6000
Dataloader
Dataloader은 데이터를 네트워크로 전달하기 위한 인터페이스로 batch_size 크기로 분할 된 데이터를 반환한다.
from torch.utils.data import DataLoader
train_loader = DataLoader(mnist_train, batch_size=batch_size, shuffle=True)
Spike encoding
SNN은 시간에 따라 변하는 데이터를 활용한다. 그런데 MNIST는 시간에 따라 변하는 데이터 셋이 아니다. 따라서 MNIST를 SNN에서 사용하는 방법은 두 가지가 존재한다.
동일 샘플 전달

동일한 이미지를 SNN에 전달한다. 정지된 이미지의 동영상의 형태로 인코딩 한다고 보면 된다. 다만 이를 이용할 경우 SNN의 시간적 요소를 활용하지 못한다는 단점이 존재한다.
시간에 따른 spike squence 변환

입력을 spike 열로 변환 후 시간에 따라 변화하는 Spike squence로 변환된다.
Spike Encoding function
SNNTorch에서 사용 가능한 Spike encoding은 세 가지가 존재한다.
- Rate coding - spiking frequency
- Latency coding - spike timing
- Delta modulation - temporal change of input features to generate spikes
Rate coding
특정 시간 동안 spike가 발생될 확률을 입력하고 베르누이 시행으로 이진 스파이크 시퀀스를 생성합니다.
$$ P(R_{ij}=1)=X_{ij}=1-P(R_{ij}=0) $$
$X_{ij}$은 Spike가 주어진 time step에서 일어날 확률로 사용된다.
$R_{ij}$은
# Temporal Dynamics
num_steps = 10
# create vector filled with 0.5
raw_vector = torch.ones(num_steps) * 0.5
# pass each sample through a Bernoulli trial
rate_coded_vector = torch.bernoulli(raw_vector)
print(f"Converted vector: {rate_coded_vector}")
큰 수의 법칙에 의거해 num_steps가 증가할 수록 원래 raw값에 가까워 진다.
Latency coding
Latency Coding은 이벤트가 발생한 시간(Timing)에 정보를 담는 방식입니다. 예를 들어 자극의 세기가 강할수록 스파이크가 발생하는 시간이 빠르고, 약할수록 늦게 발화하는 원리입니다. Rate Coding이 긴 시간 동안 몇 번 발생했는지를 본다면, Latency Coding은 언제 발생했는지 단일 스파이크 타이밍만으로 정보를 처리하여 훨씬 빠르고 에너지 효율적입니다.
Delta modulation
Delta Modulation은 입력값의 시간적 변화량(Temporal Change) 만을 스파이크로 인코딩합니다. 이전 상태와 현재 상태의 차이(Delta)가 임계값을 넘을 때만 스파이크를 발생시킵니다. 정적인 정보보다는 동적인 시각 정보를 처리하는 DVS(Dynamic Vision Sensor) 카메라 데이터에서 유용하게 쓰입니다.