전 포스팅 데이터 전처리 에서 데이터 전처리 과정에 대해서 다뤄봤습니다.
이번 포스팅에서는 데이터 전처리에서 처리한 SoundDS 클래스를 어떻게 사용하는지 살펴봅시다.
Data Loader 를 사용한 데이터 Batch 사용하기
custom Dataset을 사용하여 Feature와 Label을 모은 데이터를 8:2로 나눕니다.
다음 이미지를 참조하여 주세요!
from torch.utils.data import random_split
myds = SoundDS(df, data_path)
# Random split of 80:20 between training and validation
num_items = len(myds)
num_train = round(num_items * 0.8)
num_val = num_items - num_train
train_ds, val_ds = random_split(myds, [num_train, num_val])
# Create training and validation data loaders
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=16, shuffle=True)
val_dl = torch.utils.data.DataLoader(val_ds, batch_size=16, shuffle=False)
Training data에서 random하게 하나의 batch를 뽑아서 위와 같이 transform을 진행합니다.
몇 가지 프로세스를 같이 살펴봅시다.
1. audio file 은 numpy array로 들어가고, shape은 (num_channels, num_samples)가 됩니다.
만약 16000의 sample rate, 4초로 설정했다고 하면, 16000 * 4 = 64000개의 샘플이 나옵니다. 1 channel이라면,
(1, 64000)의 shape을 가지게 됩니다.
2. channel 과 sample rate이 다를 경우를 대비해서 transform이 진행됩니다.
3. 4초보다 적거나 많을 때에 대비해서 4초로 맞춰줍니다.
4. Time Shift function을 통해서 왼쪽이나 오른쪽으로 옮길수 있습니다. shape는 변하지 않습니다.
5. audio를 mel spectrogram으로 변환합니다. shape는 (num_channels, Mel freq_bands, time_steps) = (1, 64, 344)가 됩니다.
모델 만들기
pytorch를 이용해서 모델을 만듭니다.
모든 디테일을 다 언급하기는 힘들겠지만,
self.conv1 = nn.Conv2d(2, 8, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2))
에서 앞에 2가 input이기 때문에, channel 수에 맞춰 줘야 됩니다.
또한, batch마다의 inference를 진행하기 때문에, 다음과 같은 특징들이 있습니다.
1. 한 batch마다의 shape은 다음과 같습니다. (batch_size, num_channels, Mel freq_bands, time_steps) 지금의 경우에는
(16, 2, 64, 344) 입니다.
2. CNN layer를 4개 지나는 동안 stride가 2이기 때문에, 반씩 줄어들게 되고, output channel은 64가 됩니다.
결국 마지막 shape은 (16, 64, 4, 22) 가 됩니다.
3. (16, 64)의 shape가 linear layer에 들어가게 됩니다.
4. 마지막 prediction을 위해서 class 10개로 들어가게 됩니다. 이는 조정이 가능한 것으로 보입니다.
CNN에 관한 얘기는 많이 하지 않겠지만, 워낙 얘기할 내용이 많아서..
여기서 사용된 모델이 꼭 최선의 모델이 아니라는 점만 얘기하고 싶네요!
import torch.nn.functional as F
from torch.nn import init
# ----------------------------
# Audio Classification Model
# ----------------------------
class AudioClassifier (nn.Module):
# ----------------------------
# Build the model architecture
# ----------------------------
def __init__(self):
super().__init__()
conv_layers = []
# First Convolution Block with Relu and Batch Norm. Use Kaiming Initialization
self.conv1 = nn.Conv2d(2, 8, kernel_size=(5, 5), stride=(2, 2), padding=(2, 2))
self.relu1 = nn.ReLU()
self.bn1 = nn.BatchNorm2d(8)
init.kaiming_normal_(self.conv1.weight, a=0.1)
self.conv1.bias.data.zero_()
conv_layers += [self.conv1, self.relu1, self.bn1]
# Second Convolution Block
self.conv2 = nn.Conv2d(8, 16, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
self.relu2 = nn.ReLU()
self.bn2 = nn.BatchNorm2d(16)
init.kaiming_normal_(self.conv2.weight, a=0.1)
self.conv2.bias.data.zero_()
conv_layers += [self.conv2, self.relu2, self.bn2]
# Second Convolution Block
self.conv3 = nn.Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
self.relu3 = nn.ReLU()
self.bn3 = nn.BatchNorm2d(32)
init.kaiming_normal_(self.conv3.weight, a=0.1)
self.conv3.bias.data.zero_()
conv_layers += [self.conv3, self.relu3, self.bn3]
# Second Convolution Block
self.conv4 = nn.Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
self.relu4 = nn.ReLU()
self.bn4 = nn.BatchNorm2d(64)
init.kaiming_normal_(self.conv4.weight, a=0.1)
self.conv4.bias.data.zero_()
conv_layers += [self.conv4, self.relu4, self.bn4]
# Linear Classifier
self.ap = nn.AdaptiveAvgPool2d(output_size=1)
self.lin = nn.Linear(in_features=64, out_features=10)
# Wrap the Convolutional Blocks
self.conv = nn.Sequential(*conv_layers)
# ----------------------------
# Forward pass computations
# ----------------------------
def forward(self, x):
# Run the convolutional blocks
x = self.conv(x)
# Adaptive pool and flatten for input to linear layer
x = self.ap(x)
x = x.view(x.shape[0], -1)
# Linear layer
x = self.lin(x)
# Final output
return x
# Create the model and put it on the GPU if available
myModel = AudioClassifier()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
myModel = myModel.to(device)
# Check that it is on Cuda
next(myModel.parameters()).device
학습하기
학습에서는, optimzer, loss, scheduler 등을 정해주면 됩니다.
epoch 숫자는 더 높게 할 수 있습니다.
# ----------------------------
# Training Loop
# ----------------------------
def training(model, train_dl, num_epochs):
# Loss Function, Optimizer and Scheduler
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.001,
steps_per_epoch=int(len(train_dl)),
epochs=num_epochs,
anneal_strategy='linear')
# Repeat for each epoch
for epoch in range(num_epochs):
running_loss = 0.0
correct_prediction = 0
total_prediction = 0
# Repeat for each batch in the training set
for i, data in enumerate(train_dl):
# Get the input features and target labels, and put them on the GPU
inputs, labels = data[0].to(device), data[1].to(device)
# Normalize the inputs
inputs_m, inputs_s = inputs.mean(), inputs.std()
inputs = (inputs - inputs_m) / inputs_s
# Zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
# Keep stats for Loss and Accuracy
running_loss += loss.item()
# Get the predicted class with the highest score
_, prediction = torch.max(outputs,1)
# Count of predictions that matched the target label
correct_prediction += (prediction == labels).sum().item()
total_prediction += prediction.shape[0]
#if i % 10 == 0: # print every 10 mini-batches
# print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 10))
# Print stats at the end of the epoch
num_batches = len(train_dl)
avg_loss = running_loss / num_batches
acc = correct_prediction/total_prediction
print(f'Epoch: {epoch}, Loss: {avg_loss:.2f}, Accuracy: {acc:.2f}')
print('Finished Training')
num_epochs=2 # Just for demo, adjust this higher.
training(myModel, train_dl, num_epochs)
인퍼런스 하기
인퍼런스는 val_dl이라는 우리가 만들었던 DataLoader에서 가져왔습니다.
wav 파일을 바로 사용한 것이 아니라 DataLoader를 사용하였기 때문에,
실제 wav 나 mp4 파일을 사용하는 것이 아닌, DataLoader에 패키징 되어 있는 파일들을 사용한다는 점
유의해 주시면 좋을것 같습니다.
이를 실제 wav 파일이나 mp4 파일에 사용하려면, DataLoader가 아닌 다른 포맷으로 사용해야 될 것으로 생각됩니다.
# ----------------------------
# Inference
# ----------------------------
def inference (model, val_dl):
correct_prediction = 0
total_prediction = 0
# Disable gradient updates
with torch.no_grad():
for data in val_dl:
# Get the input features and target labels, and put them on the GPU
inputs, labels = data[0].to(device), data[1].to(device)
# Normalize the inputs
inputs_m, inputs_s = inputs.mean(), inputs.std()
inputs = (inputs - inputs_m) / inputs_s
# Get predictions
outputs = model(inputs)
# Get the predicted class with the highest score
_, prediction = torch.max(outputs,1)
# Count of predictions that matched the target label
correct_prediction += (prediction == labels).sum().item()
total_prediction += prediction.shape[0]
acc = correct_prediction/total_prediction
print(f'Accuracy: {acc:.2f}, Total items: {total_prediction}')
# Run inference on trained model with the validation set
inference(myModel, val_dl)
'Deep Learning' 카테고리의 다른 글
Pytorch를 이용한 Quantization (0) | 2023.01.25 |
---|---|
Pytorch에서 Batch Size 1로 했을 때 accuracy가 떨어지는 문제 해결 (model.eval()) (0) | 2022.09.23 |
오디오 딥러닝을 해봅시다! (Sound Classification) - 1. 데이터 전처리 (0) | 2022.09.06 |
torchviz로 모델 시각화 하기 (0) | 2022.07.27 |
Coursera Deep Learning Specialization 후기 (0) | 2022.02.08 |