网络结构Unet,实现一维信号dense prediction,如EEG情绪识别,受干扰信号修复,不同的任务需要设计不同的损失函数。
本文resnet的实现参考了pytorch官方resnet实现的源码,区别在于二维的size为3x3卷积替换成了一维的长度为5卷积。同时Unet的实现参考Hi_AI的实现。
该网络输入为 channels x length,输出为 1 x length,不过输出的通道数是可以改变的
import torch
import torch.nn as nn
def conv1d_5(inplanes, outplanes, stride=1):
return nn.Conv1d(inplanes, outplanes, kernel_size=5, stride=stride,
padding=2, bias=False)
# 下采样block,下采样过程中使用resnet作为backbone
class Block(nn.Module):
def __init__(self, inplanes, planes, stride=1, downsample=None, bn=False):
super(Block, self).__init__()
self.bn = bn
self.conv1 = conv1d_5(inplanes, planes, stride)
self.bn1 = nn.BatchNorm1d(planes)
self.relu = nn.ReLU(inplace=False)
self.conv2 = conv1d_5(planes, planes)
self.bn2 = nn.BatchNorm1d(planes)
self.downsample = downsample
self.stride = stride
def forward(self, x):
residual = x
out = self.conv1(x)
if self.bn:
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
if self.bn:
out = self.bn2(out)
out = self.relu(out)
if self.downsample is not None:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
# 上采样block
class Decoder_block(nn.Module):
def __init__(self, inplanes, outplanes, kernel_size=5, stride=5):
super(Decoder_block, self).__init__()
self.upsample = nn.ConvTranspose1d(in_channels=inplanes, out_channels=outplanes,
padding=0, kernel_size=kernel_size, stride=stride, bias=False)
self.conv1 = conv1d_5(inplanes, outplanes)
self.relu = nn.ReLU()
self.conv2 = conv1d_5(outplanes, outplanes)
def forward(self, x1, x2):
x1 = self.upsample(x1)
out = torch.cat((x1, x2), dim=1)
out = self.conv1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.relu(out)
return out
class Uresnet(nn.Module):
def __init__(self, inplanes=5, layers=[2,2,2,2]):
super(Uresnet, self).__init__()
self.inplanes = inplanes
self.encoder1 = self._make_encoder(Block, 32, layers[0], 5)
self.encoder2 = self._make_encoder(Block, 64, layers[1], 5)
self.encoder3 = self._make_encoder(Block, 128, layers[2], 5)
self.encoder4 = self._make_encoder(Block, 256, layers[3], 4)
self.decoder3 = Decoder_block(256, 128, stride=4, kernel_size=4)
self.decoder2 = Decoder_block(128, 64)
self.decoder1 = Decoder_block(64, 32)
# 如果要修改输出的通道,在这里修改
self.conv1x1 = nn.ConvTranspose1d(32, 1, kernel_size=5, stride=5, bias=False)
def _make_encoder(self, block, planes, blocks, stride=1):
downsample = None
if self.inplanes != planes or stride != 1:
downsample = nn.Conv1d(self.inplanes, planes, stride=stride, kernel_size=1, bias=False)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample))
self.inplanes = planes
for i in range(1, blocks):
layers.append(block(self.inplanes, planes))
return nn.Sequential(*layers)
def forward(self, x):
down1 = self.encoder1(x)
down2 = self.encoder2(down1)
down3 = self.encoder3(down2)
down4 = self.encoder4(down3)
up3 = self.decoder3(down4, down3)
up2 = self.decoder2(up3, down2)
up1 = self.decoder1(up2, down1)
out = self.conv1x1(up1)
return out