syeedalireza's picture
Upload folder using huggingface_hub
f43cdb8 verified
"""
ResNet-style 1D CNN for radio modulation classification.
Input: (batch, 2, seq_len) — I/Q channels.
Output: (batch, num_classes) logits.
"""
import torch
import torch.nn as nn
from typing import Optional
class ResidualBlock1d(nn.Module):
def __init__(self, in_ch: int, out_ch: int, kernel_size: int = 3):
super().__init__()
self.conv1 = nn.Conv1d(in_ch, out_ch, kernel_size, padding=kernel_size // 2)
self.bn1 = nn.BatchNorm1d(out_ch)
self.conv2 = nn.Conv1d(out_ch, out_ch, kernel_size, padding=kernel_size // 2)
self.bn2 = nn.BatchNorm1d(out_ch)
self.downsample = nn.Conv1d(in_ch, out_ch, 1) if in_ch != out_ch else nn.Identity()
def forward(self, x: torch.Tensor) -> torch.Tensor:
out = torch.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.downsample(x)
return torch.relu(out)
class ModulationClassifier(nn.Module):
def __init__(
self,
num_classes: int = 10,
seq_len: int = 128,
base_channels: int = 32,
num_blocks: int = 3,
):
super().__init__()
self.num_classes = num_classes
self.seq_len = seq_len
self.stem = nn.Sequential(
nn.Conv1d(2, base_channels, 7, padding=3),
nn.BatchNorm1d(base_channels),
nn.ReLU(inplace=True),
nn.MaxPool1d(2),
)
channels = [base_channels * (2 ** i) for i in range(num_blocks)]
layers = []
in_ch = base_channels
for ch in channels:
layers.append(ResidualBlock1d(in_ch, ch))
in_ch = ch
self.blocks = nn.Sequential(*layers)
# Global pool then classifier
self.pool = nn.AdaptiveAvgPool1d(1)
self.fc = nn.Linear(channels[-1], num_classes)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# x: (B, 2, L)
x = self.stem(x)
x = self.blocks(x)
x = self.pool(x)
x = x.flatten(1)
return self.fc(x)