Download models/echmo.py from PeCoLab/EchMo-Vis: direct link, hf CLI and curl.
- Browser
- Download file 23.6 kB
-
https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/echmo.py
- Command line
-
hf download hf://PeCoLab/EchMo-Vis/models/echmo.py
-
curl -L -o echmo.py https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/echmo.py
23.6 kB
| """ | |
| EchMo Model Implementation | |
| End-to-End Radar Echo Segmentation Model | |
| """ | |
| import os | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import torch.nn.init as init | |
| import scipy.io as scio | |
| # ==================== Utility Functions ==================== | |
| def complex_std(x, epsilon=1e-5): | |
| mu_R = x.real.mean(dim=3, keepdim=True).detach() | |
| mu_I = x.imag.mean(dim=3, keepdim=True).detach() | |
| x_R = x.real - mu_R | |
| x_I = x.imag - mu_I | |
| sigma_R = torch.sqrt(torch.var(x.real, dim=3, keepdim=True, unbiased=False) + epsilon) | |
| sigma_I = torch.sqrt(torch.var(x.imag, dim=3, keepdim=True, unbiased=False) + epsilon) | |
| x_R /= sigma_R | |
| x_I /= sigma_I | |
| return x_R + 1j * x_I | |
| def complex_double2float(x): | |
| x_r = x.real.float() | |
| x_i = x.imag.float() | |
| return x_r + 1j * x_i | |
| def filter_coef_loader(path, coef_type=None): | |
| coef = scio.loadmat(os.path.join(path, 's_tx.mat'))['s_tx'] | |
| coef = torch.tensor(coef) | |
| if coef_type == 'ori_mf': | |
| coef = complex_double2float(torch.conj(coef)) | |
| zero = torch.complex(torch.zeros([1, 1], dtype=torch.float32), torch.zeros([1, 1], dtype=torch.float32)) | |
| coef = torch.cat((zero, coef), dim=1) | |
| return coef | |
| elif coef_type == 'tay_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_taylor.mat'))['w_taylor'] | |
| elif coef_type == 'che_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_chebyshev.mat'))['w_chebyshev'] | |
| elif coef_type == 'ham_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_hamming.mat'))['w_hamming'] | |
| elif coef_type == 'han_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_hanning.mat'))['w_hanning'] | |
| elif coef_type == 'black_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_blackman.mat'))['w_blackman'] | |
| elif coef_type == 'cos_mf': | |
| win = scio.loadmat(os.path.join(path, 'w_cosine.mat'))['w_cosine'] | |
| else: | |
| win = scio.loadmat(os.path.join(path, 'w_taylor.mat'))['w_taylor'] | |
| win = torch.permute(torch.tensor(win), [1, 0]) | |
| coef = complex_double2float(torch.conj(coef * win)) | |
| zero = torch.complex(torch.zeros([1, 1], dtype=torch.float32), torch.zeros([1, 1], dtype=torch.float32)) | |
| coef = torch.cat((zero, coef), dim=1) | |
| return coef | |
| # ==================== Model Components ==================== | |
| class ComplexBatchNorm2d(nn.Module): | |
| def __init__(self, num_features): | |
| super().__init__() | |
| self.bn_real = nn.BatchNorm2d(num_features) | |
| self.bn_imag = nn.BatchNorm2d(num_features) | |
| def forward(self, x): | |
| return torch.complex(self.bn_real(x.real), self.bn_imag(x.imag)) | |
| class ComplexReLU(nn.Module): | |
| def __init__(self, activation='leaky_relu'): | |
| super(ComplexReLU, self).__init__() | |
| self.activation = activation | |
| def forward(self, input): | |
| if self.activation == 'relu': | |
| return nn.ReLU()(input.real) + 1j * nn.ReLU()(input.imag) | |
| elif self.activation == 'leaky_relu': | |
| return F.leaky_relu(input.real) + 1j * F.leaky_relu(input.imag) | |
| elif self.activation == 'celu': | |
| return F.celu(input.real) + 1j * F.celu(input.imag) | |
| else: | |
| return input | |
| class DoubleConvBlock(nn.Module): | |
| def __init__(self, in_ch, out_ch, k_size, pad, dil): | |
| super().__init__() | |
| self.block = nn.Sequential( | |
| nn.Conv2d(in_ch, out_ch, kernel_size=k_size, padding=pad, dilation=dil), | |
| nn.BatchNorm2d(out_ch), | |
| nn.LeakyReLU(inplace=True), | |
| nn.Conv2d(out_ch, out_ch, kernel_size=k_size, padding=pad, dilation=dil), | |
| nn.BatchNorm2d(out_ch), | |
| nn.LeakyReLU(inplace=True) | |
| ) | |
| def forward(self, x): | |
| return self.block(x) | |
| class Double3DConvBlock(nn.Module): | |
| def __init__(self, in_ch, out_ch, k_size, pad, dil): | |
| super().__init__() | |
| self.block = nn.Sequential( | |
| nn.Conv3d(in_ch, out_ch, kernel_size=k_size, padding=pad, dilation=dil), | |
| nn.BatchNorm3d(out_ch), | |
| nn.LeakyReLU(inplace=True), | |
| nn.Conv3d(out_ch, out_ch, kernel_size=k_size, padding=pad, dilation=dil), | |
| nn.BatchNorm3d(out_ch), | |
| nn.LeakyReLU(inplace=True) | |
| ) | |
| def forward(self, x): | |
| return self.block(x) | |
| class ConvBlock(nn.Module): | |
| def __init__(self, in_ch, out_ch, k_size, pad, dil): | |
| super().__init__() | |
| self.block = nn.Sequential( | |
| nn.Conv2d(in_ch, out_ch, kernel_size=k_size, padding=pad, dilation=dil), | |
| nn.BatchNorm2d(out_ch), | |
| nn.LeakyReLU(inplace=True) | |
| ) | |
| def forward(self, x): | |
| return self.block(x) | |
| class PeakConv2D(nn.Module): | |
| def __init__(self, in_ch, out_ch, bias, refer_band, guard_band_dop, guard_band, signal_type): | |
| super(PeakConv2D, self).__init__() | |
| self.signal_type = signal_type | |
| if self.signal_type in ('range_doppler', 'angle_doppler'): | |
| self.guard_band = (guard_band_dop, guard_band_dop) | |
| self.padding = (self.guard_band[1] + refer_band, | |
| self.guard_band[1] + refer_band, | |
| self.guard_band[0] + refer_band, | |
| self.guard_band[0] + refer_band) | |
| else: | |
| self.guard_band = (guard_band, guard_band) | |
| self.padding = (self.guard_band[1] + refer_band, | |
| self.guard_band[1] + refer_band, | |
| self.guard_band[0] + refer_band, | |
| self.guard_band[0] + refer_band) | |
| self.refer_band = refer_band | |
| self.kernel_size = (self.guard_band[0] + self.guard_band[1] + self.refer_band * 2), 4 | |
| self.stride = self.kernel_size | |
| self.zero_padding = nn.ZeroPad2d(self.padding) | |
| self.bias = bias | |
| self.pc_strd = 1 | |
| self.peak_conv = nn.Conv2d(in_ch, out_ch, | |
| kernel_size=self.kernel_size, | |
| padding=0, | |
| stride=self.stride, | |
| bias=self.bias) | |
| def forward(self, x): | |
| h, w = x.shape[2], x.shape[3] | |
| rb = self.refer_band | |
| gb = self.guard_band | |
| k_pk = self.kernel_size | |
| N = k_pk[0] * k_pk[1] | |
| dtype = x.data.type() | |
| b = x.size(0) | |
| x = self.zero_padding(x) | |
| p_r = self._get_p_r(b, h, w, N, dtype) | |
| x_r = self._sample_x(x, p_r, N) | |
| p_c = self._get_p_c(b, h, w, N, dtype) | |
| x_c = self._sample_x(x, p_c, N) | |
| x_prf = x_c - x_r | |
| x_prf = self._reshape_x_prf(k_pk[0], k_pk[1], x_prf) | |
| out = self.peak_conv(x_prf) | |
| return out | |
| def _get_p_c(self, b, h, w, N, dtype): | |
| p_c_x, p_c_y = torch.meshgrid( | |
| torch.arange(self.padding[2], h * self.pc_strd + self.padding[2], self.pc_strd), | |
| torch.arange(self.padding[0], w * self.pc_strd + self.padding[0], self.pc_strd), indexing='ij') | |
| p_c_x = torch.flatten(p_c_x).view(1, 1, h, w).repeat(1, N, 1, 1) | |
| p_c_y = torch.flatten(p_c_y).view(1, 1, h, w).repeat(1, N, 1, 1) | |
| p_c = torch.cat([p_c_x, p_c_y], 1).type(dtype) | |
| p_c = p_c.repeat(b, 1, 1, 1) | |
| return p_c | |
| def _gen_prf_grid(self, rb, gb, N, dtype): | |
| h_t = -(rb + gb[0]) | |
| h_d = rb + gb[0] | |
| w_l = -(rb + gb[1]) | |
| w_r = rb + gb[1] | |
| w_prf = (rb + gb[1]) * 2 + 1 | |
| h_prf = (rb + gb[0]) * 2 + 1 | |
| prf_x_idx, prf_y_idx = torch.meshgrid( | |
| torch.arange(h_t, h_d + 1), | |
| torch.arange(w_l, w_r + 1), indexing='ij') | |
| prf_xt = prf_x_idx[0:rb] | |
| prf_xr = prf_x_idx[rb:(h_prf - 2 * rb + 1), (w_prf - rb):w_prf] | |
| prf_xd = prf_x_idx[(h_prf - rb):h_prf] | |
| prf_xl = prf_x_idx[rb:(h_prf - 2 * rb + 1), 0:rb] | |
| prf_x = torch.cat([torch.flatten(prf_xt), | |
| torch.flatten(prf_xr), | |
| torch.flatten(prf_xd), | |
| torch.flatten(prf_xl)], 0) | |
| prf_yt = prf_y_idx[0:rb] | |
| prf_yr = prf_y_idx[rb:(h_prf - 2 * rb + 1), (w_prf - rb):w_prf] | |
| prf_yd = prf_y_idx[(h_prf - rb):h_prf] | |
| prf_yl = prf_y_idx[rb:(h_prf - 2 * rb + 1), 0:rb] | |
| prf_y = torch.cat([torch.flatten(prf_yt), | |
| torch.flatten(prf_yr), | |
| torch.flatten(prf_yd), | |
| torch.flatten(prf_yl)], 0) | |
| prf = torch.cat([prf_x, prf_y], 0) | |
| prf = prf.view(1, 2 * N, 1, 1).type(dtype) | |
| return prf | |
| def _get_p_r(self, b, h, w, N, dtype): | |
| rb = self.refer_band | |
| gb = self.guard_band | |
| prf = self._gen_prf_grid(rb, gb, N, dtype) | |
| p_c = self._get_p_c(b, h, w, N, dtype) | |
| p_r = p_c + prf | |
| return p_r | |
| def _sample_x(self, x_pad, p, N): | |
| p = p.contiguous().permute(0, 2, 3, 1).floor() | |
| b, h, w, _ = p.size() | |
| h_pad = x_pad.size(2) | |
| w_pad = x_pad.size(3) | |
| c = x_pad.size(1) | |
| x_pad = x_pad.contiguous().view(b, c, -1) | |
| index = p[..., :N] * w_pad + p[..., N:] | |
| index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1) | |
| index = index.long().to(x_pad.device) | |
| x_r = x_pad.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N) | |
| return x_r | |
| def _reshape_x_prf(k_h, k_w, x_prf): | |
| b, c, h, w, N = x_prf.size() | |
| x_prf = torch.cat([x_prf[..., s:s + k_w].contiguous().view(b, c, h, w * k_w) for s in range(0, N, k_w)], dim=-1) | |
| x_prf = x_prf.contiguous().view(b, c, h * k_h, w * k_w) | |
| return x_prf | |
| class DoublePeakConv2D(nn.Module): | |
| def __init__(self, in_ch, out_ch, bias, rb, gb_dop, gb, sig): | |
| super(DoublePeakConv2D, self).__init__() | |
| self.bias = bias | |
| self.refer_band = rb | |
| self.guard_band_dop = gb_dop | |
| self.guard_band = gb | |
| self.signal_type = sig | |
| self.pk_conv1 = PeakConv2D(in_ch, out_ch, bias=self.bias, | |
| refer_band=self.refer_band, | |
| guard_band_dop=self.guard_band_dop, | |
| guard_band=self.guard_band, | |
| signal_type=self.signal_type) | |
| self.bn1 = nn.BatchNorm2d(out_ch) | |
| self.act1 = nn.LeakyReLU(inplace=True) | |
| self.pk_conv2 = PeakConv2D(out_ch, out_ch, bias=self.bias, | |
| refer_band=self.refer_band, | |
| guard_band_dop=self.guard_band_dop, | |
| guard_band=self.guard_band, | |
| signal_type=self.signal_type) | |
| self.bn2 = nn.BatchNorm2d(out_ch) | |
| self.act2 = nn.LeakyReLU(inplace=True) | |
| def forward(self, x): | |
| x = self.pk_conv1(x) | |
| x = self.bn1(x) | |
| x = self.act1(x) | |
| x = self.pk_conv2(x) | |
| x = self.bn2(x) | |
| x = self.act2(x) | |
| return x | |
| class ASPPBlock(nn.Module): | |
| def __init__(self, in_ch, out_ch, shape): | |
| super().__init__() | |
| self.shape = shape | |
| self.global_avg_pool = nn.AvgPool2d(self.shape) | |
| self.conv1_1x1 = nn.Conv2d(in_ch, out_ch, kernel_size=1, padding=0, dilation=1) | |
| self.single_conv_block1_1x1 = ConvBlock(in_ch, out_ch, k_size=1, pad=0, dil=1) | |
| self.single_conv_block1_3x3 = ConvBlock(in_ch, out_ch, k_size=3, pad=6, dil=6) | |
| self.single_conv_block2_3x3 = ConvBlock(in_ch, out_ch, k_size=3, pad=12, dil=12) | |
| self.single_conv_block3_3x3 = ConvBlock(in_ch, out_ch, k_size=3, pad=18, dil=18) | |
| def forward(self, x): | |
| x1 = F.interpolate(self.global_avg_pool(x), size=self.shape, align_corners=False, mode='bilinear') | |
| x1 = self.conv1_1x1(x1) | |
| x2 = self.single_conv_block1_1x1(x) | |
| x3 = self.single_conv_block1_3x3(x) | |
| x4 = self.single_conv_block2_3x3(x) | |
| x5 = self.single_conv_block3_3x3(x) | |
| x_cat = torch.cat((x2, x3, x4, x5, x1), 1) | |
| return x_cat | |
| class EncodingBranch(nn.Module): | |
| def __init__(self, signal_type, n_frames, in_ch=1): | |
| super().__init__() | |
| self.signal_type = signal_type | |
| self.n_frames = n_frames | |
| self.in_ch = in_ch | |
| self.double_3dconv_block1 = Double3DConvBlock(in_ch=self.in_ch, out_ch=32, | |
| k_size=(1+n_frames//2, 3, 3), | |
| pad=(0, 1, 1), dil=1) | |
| self.doppler_max_pool = nn.MaxPool2d(2, stride=(1, 2)) | |
| self.max_pool = nn.MaxPool2d(2, stride=2) | |
| self.double_pkc_block = DoublePeakConv2D(in_ch=32, out_ch=64, | |
| bias=True, rb=1, gb_dop=1, gb=1, sig=self.signal_type) | |
| self.single_conv_block1_1x1 = ConvBlock(in_ch=64, out_ch=128, k_size=1, pad=0, dil=1) | |
| def forward(self, x): | |
| x1 = self.double_3dconv_block1(x) | |
| x1 = torch.squeeze(x1, 2) | |
| x1_pad = F.pad(x1, (0, 0, 0, 0), "constant", 0) | |
| x1_down = self.max_pool(x1_pad) | |
| x2 = self.double_pkc_block(x1_down) | |
| x2_pad = F.pad(x2, (0, 0, 0, 1), "constant", 0) | |
| x2_down = self.doppler_max_pool(x2_pad) | |
| x3 = self.single_conv_block1_1x1(x2_down) | |
| return x2_down, x3 | |
| class PKCIn4ANY(nn.Module): | |
| def __init__(self, n_classes, n_frames, in_ch, w, h): | |
| super().__init__() | |
| self.n_classes = n_classes | |
| self.n_frames = n_frames | |
| self.in_ch = in_ch | |
| self.rd_shape = (int(w//2), int(h//4)) | |
| self.rd_encoding_branch = EncodingBranch('range_doppler', self.n_frames, self.in_ch) | |
| self.rd_aspp_block = ASPPBlock(in_ch=64, out_ch=128, shape=self.rd_shape) | |
| self.rd_single_conv_block1_1x1 = ConvBlock(in_ch=640, out_ch=128, k_size=1, pad=0, dil=1) | |
| self.rd_upconv1 = nn.ConvTranspose2d(256, 128, (2, 2), stride=(2, 2)) | |
| self.rd_double_conv_block1 = DoubleConvBlock(in_ch=128, out_ch=128, k_size=3, pad=1, dil=1) | |
| self.rd_upconv2 = nn.ConvTranspose2d(128, 128, (1, 2), stride=(1, 2)) | |
| self.rd_double_conv_block2 = DoubleConvBlock(in_ch=128, out_ch=128, k_size=3, pad=1, dil=1) | |
| self.rd_final = nn.Conv2d(in_channels=128, out_channels=n_classes, kernel_size=1) | |
| def forward(self, x_rd): | |
| rd_features, rd_latent = self.rd_encoding_branch(x_rd) | |
| x2_rd = self.rd_aspp_block(rd_features) | |
| x2_rd = self.rd_single_conv_block1_1x1(x2_rd) | |
| x4_rd = torch.cat((x2_rd, rd_latent), 1) | |
| x4_rd = self.rd_upconv1(x4_rd) | |
| x4_rd = self.rd_double_conv_block1(x4_rd) | |
| x4_rd = self.rd_upconv2(x4_rd) | |
| x4_rd = self.rd_double_conv_block2(x4_rd) | |
| x4_rd = self.rd_final(x4_rd) | |
| return x4_rd | |
| def _init_translator_weights(m): | |
| if isinstance(m, nn.Linear): | |
| torch.nn.init.xavier_uniform_(m.weight) | |
| nn.init.constant_(m.bias, 0.) | |
| elif isinstance(m, nn.Conv2d): | |
| torch.nn.init.xavier_uniform_(m.weight) | |
| if m.bias is not None: | |
| nn.init.constant_(m.bias, 0.) | |
| elif isinstance(m, nn.BatchNorm2d): | |
| nn.init.uniform_(m.weight, 0., 1.) | |
| nn.init.constant_(m.bias, 0.) | |
| class Leanable_Match_FilterV5(nn.Module): | |
| def __init__(self, k_size, in_ch, out_ch, lmf_coef, activation='relu', bias=True): | |
| super(Leanable_Match_FilterV5, self).__init__() | |
| self.k_size = k_size | |
| self.stride = 1 | |
| self.in_ch = in_ch | |
| self.out_ch = out_ch | |
| self.activation = activation | |
| self.bias = bias | |
| self.lmf_real = nn.Conv2d(self.in_ch, self.out_ch, | |
| kernel_size=(1, k_size), stride=(1, 1), | |
| bias=self.bias) | |
| self.lmf_imag = nn.Conv2d(self.in_ch, self.out_ch, | |
| kernel_size=(1, k_size), stride=(1, 1), | |
| bias=self.bias) | |
| init.kaiming_uniform_(self.lmf_real.weight) | |
| init.kaiming_uniform_(self.lmf_imag.weight) | |
| if self.bias: | |
| init.zeros_(self.lmf_real.bias) | |
| init.zeros_(self.lmf_imag.bias) | |
| self.cause_padding = torch.nn.ZeroPad2d(padding=(0, self.k_size - 1, 0, 0)) | |
| self.cmplx_relu = ComplexReLU(self.activation) | |
| def forward(self, x): | |
| inputR = self.cause_padding(x.real) | |
| inputI = self.cause_padding(x.imag) | |
| x_RR = self.lmf_real(inputR) | |
| x_II = self.lmf_imag(inputI) | |
| x_RI = self.lmf_imag(inputR) | |
| x_IR = self.lmf_real(inputI) | |
| x = x_RR - x_II + 1j * (x_RI + x_IR) | |
| x = self.cmplx_relu(x) | |
| return x | |
| class LMF_Chain(nn.Module): | |
| def __init__(self, configs): | |
| super(LMF_Chain, self).__init__() | |
| self.lmf_coef = filter_coef_loader(os.path.join(configs.dataset_path, configs.coef_path), configs.lmf_coefs) | |
| self.in_ch = 1 | |
| self.Chain = nn.Sequential() | |
| for l in range(configs.lmf_layers): | |
| self.Chain.add_module('lmfV5-{0}'.format(l), | |
| Leanable_Match_FilterV5(k_size=self.lmf_coef.shape[1], | |
| in_ch=self.in_ch, | |
| out_ch=configs.lmf_channels, | |
| lmf_coef=self.lmf_coef, | |
| activation=configs.activation, | |
| bias=configs.bias)) | |
| self.in_ch = configs.lmf_channels | |
| def forward(self, x): | |
| x = self.Chain(x) | |
| return x | |
| class Multi_Order_LDC(nn.Module): | |
| def __init__(self, in_ch, out_ch, orders, activation='relu', bias=True): | |
| super(Multi_Order_LDC, self).__init__() | |
| self.in_ch = in_ch | |
| self.out_ch = out_ch | |
| self.orders = orders | |
| self.activation = activation | |
| self.bias = bias | |
| self.ldc_list = nn.ModuleList() | |
| self.pad_list = nn.ModuleList() | |
| for n in range(self.orders): | |
| ldc = nn.Conv2d(self.in_ch, self.out_ch, kernel_size=(n+2, 1), bias=self.bias) | |
| pad = torch.nn.ZeroPad2d(padding=(0, 0, n+1, 0)) | |
| self.in_ch = self.out_ch | |
| self.ldc_list.append(ldc) | |
| self.pad_list.append(pad) | |
| self.cmplx_relu = ComplexReLU(self.activation) | |
| self._initialize_MLDC_weights() | |
| def _initialize_MLDC_weights(self): | |
| for n, conv in enumerate(self.ldc_list): | |
| nn.init.kaiming_normal_(conv.weight) | |
| if self.bias: | |
| nn.init.zeros_(conv.bias) | |
| def forward(self, x): | |
| B, P, R = x.shape[0], x.shape[2], x.shape[3] | |
| x = x.unsqueeze(dim=1).broadcast_to(B, self.orders, x.shape[1], P, R) | |
| y_r = torch.zeros(B, self.orders, self.out_ch, P, R).to(x.device) | |
| y_i = torch.zeros(B, self.orders, self.out_ch, P, R).to(x.device) | |
| for n in range(self.orders): | |
| x_n_real = self.ldc_list[n](self.pad_list[n](x[:,n,...].real)) | |
| x_n_imag = self.ldc_list[n](self.pad_list[n](x[:,n,...].imag)) | |
| y_r[:,n,...] = x_n_real | |
| y_i[:,n,...] = x_n_imag | |
| y_r = y_r.view(B, self.orders*self.out_ch, P, R) | |
| y_i = y_i.view(B, self.orders*self.out_ch, P, R) | |
| y = torch.complex(y_r, y_i) | |
| y = self.cmplx_relu(y) | |
| return y | |
| class Group_Purturble_DF(nn.Module): | |
| def __init__(self, in_ch, out_ch, k_size, groups, activation='relu', bias=True): | |
| super(Group_Purturble_DF, self).__init__() | |
| self.k_size = k_size | |
| self.in_ch = in_ch | |
| self.out_ch = out_ch | |
| self.groups = groups | |
| self.activation = activation | |
| self.bias = bias | |
| self.gdf_cos = nn.Conv2d(self.in_ch*self.groups, self.out_ch*self.groups, | |
| kernel_size=(k_size, 1), stride=(k_size, 1), | |
| padding=0, groups=self.groups, bias=self.bias) | |
| self.gdf_sin = nn.Conv2d(self.in_ch*self.groups, self.out_ch*self.groups, | |
| kernel_size=(k_size, 1), stride=(k_size, 1), | |
| padding=0, groups=self.groups, bias=self.bias) | |
| self._initialize_GDF_weights() | |
| self.cmplx_relu = ComplexReLU(self.activation) | |
| def _initialize_GDF_weights(self): | |
| init.kaiming_uniform_(self.gdf_cos.weight) | |
| init.kaiming_uniform_(self.gdf_sin.weight) | |
| if self.bias: | |
| init.zeros_(self.gdf_cos.bias) | |
| init.zeros_(self.gdf_sin.bias) | |
| def forward(self, x): | |
| B, R = x.shape[0], x.shape[3] | |
| x_real, x_imag = x.real.to(x.device), x.imag.to(x.device) | |
| x_rr = self.gdf_cos(x_real) | |
| x_ii = self.gdf_sin(x_imag) | |
| x_ri = self.gdf_sin(x_real) | |
| x_ir = self.gdf_cos(x_imag) | |
| x = x_rr + x_ii - 1j * x_ri + 1j * x_ir | |
| x = self.cmplx_relu(x) | |
| x = x.view(B, self.groups, self.out_ch, 1, R).squeeze(dim=3) | |
| return x | |
| class EchMo(nn.Module): | |
| def __init__(self, configs): | |
| super(EchMo, self).__init__() | |
| self.cfg = configs | |
| self.task_name = configs.task_name | |
| self.n_range = configs.n_range | |
| self.n_pulse = configs.n_pulse | |
| self.n_classes = configs.n_classes | |
| self.n_frames = configs.n_frames | |
| self.scale = configs.scale | |
| self.activation = configs.activation | |
| self.bias = configs.bias | |
| self.lmf_chains = configs.lmf_chains | |
| self.lmf_channels = configs.lmf_channels | |
| self.lmf_layers = configs.lmf_layers | |
| self.lmf_coefs = configs.lmf_coefs | |
| self.ldc_orders = configs.ldc_orders | |
| self.ldc_channels = configs.ldc_channels | |
| self.df_groups = configs.ldc_orders | |
| self.df_channels = configs.df_channels | |
| self.LMFChain = nn.ModuleList([LMF_Chain(configs=self.cfg) for _ in range(self.lmf_chains)]) | |
| self.MLDC = Multi_Order_LDC(in_ch=self.lmf_channels*self.lmf_chains, | |
| out_ch=self.ldc_channels, | |
| orders=self.ldc_orders, | |
| activation=self.activation, | |
| bias=self.bias) | |
| self.GDF = Group_Purturble_DF(in_ch=self.ldc_channels, | |
| out_ch=self.df_channels, | |
| k_size=self.n_pulse, | |
| groups=self.df_groups, | |
| activation=self.activation, | |
| bias=self.bias) | |
| self.RDTranslator = PKCIn4ANY(n_classes=self.n_classes, | |
| n_frames=self.n_frames, | |
| in_ch=self.df_groups, | |
| w=self.df_channels, | |
| h=self.n_range) | |
| self.RDTranslator.apply(_init_translator_weights) | |
| def forward(self, x): | |
| if self.scale == 'instance': | |
| x = complex_double2float(complex_std(x, epsilon=1e-8)) | |
| elif self.scale == 'global': | |
| x = complex_double2float(x) | |
| for i in range(self.lmf_chains): | |
| if i == 0: | |
| x_k = self.LMFChain[i](x) | |
| else: | |
| x_ki = self.LMFChain[i](x) | |
| x_k = torch.concatenate([x_k, x_ki], dim=1) | |
| x_h = self.MLDC(x_k) | |
| x_d = self.GDF(x_h) | |
| gdf_out = x_d | |
| x_d = torch.abs(x_d).unsqueeze(dim=2) | |
| y = self.RDTranslator(x_d) | |
| return y, x_k, x_h, gdf_out | |