傻大方


首页 > 潮·科技 > >

用PyTorch实现图像聚类( 二 )



按关键词阅读:

因为这是一个PyTorch模块(nn.Module) , 通过EncoderVGG实例实现小批量图像数据的前向传播需要一个forward方法:
def forward(self, x):'''将图像输入encoderArgs:x (Tensor): 图片tensorReturns:x_code (Tensor): 编码 tensorpool_indices (list): 池索引张量'''pool_indices = []x_current = xfor module_encode in self.encoder:output = module_encode(x_current)# 如果模块是池 , 有两个输出 , 第二个是池索引if isinstance(output, tuple) and len(output) == 2:x_current = output[0]pool_indices.append(output[1])else:x_current = outputreturn x_current, pool_indices该方法按顺序执行编码器中的每个层 , 并在创建池索引时收集它们 。 在执行编码器模块之后 , 代码与池索引的有序集合一起返回 。
接下来是解码器 。
它是VGG-16网络的“转置”版本 。 我使用引号是因为解码器层看起来很像反向的编码器 , 但严格地说 , 它不是反转或转置 。
译码器模块的初始化:
class DecoderVGG(nn.Module):'''译码器的代码基于vgg16体系结构与batch normalization 。Args:encoder: ' EncoderVGG '的编码器实例 , 它将被转换成一个解码器'''channels_in = EncoderVGG.channels_codechannels_out = 3def __init__(self, encoder):super(DecoderVGG, self).__init__()self.decoder = self._invert_(encoder)def _invert_(self, encoder):'''将编码器反转 , 以将译码器创建为编码器的镜像译码器由两种主要类型组成:二维转置卷积和二维解池 , 2D卷积之后是批处理归一化和激活 。译码器是反向的 , 编码器中的卷积变成了转置卷积加上归一化和激活 , 编码器中的maxpooling变成了unpooling 。Args:encoder (ModuleList): 编码器Returns:decoder (ModuleList): 通过编码器的“反转”获得的译码器'''modules_transpose = []for module in reversed(encoder):if isinstance(module, nn.Conv2d):kwargs = {'in_channels' : module.out_channels, 'out_channels' : module.in_channels,'kernel_size' : module.kernel_size, 'stride' : module.stride,'padding' : module.padding}module_transpose = nn.ConvTranspose2d(**kwargs)module_norm = nn.BatchNorm2d(module.in_channels)module_act = nn.ReLU(inplace=True)modules_transpose += [module_transpose, module_norm, module_act]elif isinstance(module, nn.MaxPool2d):kwargs = {'kernel_size' : module.kernel_size, 'stride' : module.stride,'padding' : module.padding}module_transpose = nn.MaxUnpool2d(**kwargs)modules_transpose += [module_transpose]# 放弃最后的归一化和激活函数modules_transpose = modules_transpose[:-2]return nn.ModuleList(modules_transpose)_invert_方法反向遍历编码器的各个层 。
编码器中的卷积(图像中为绿色)替换为解码器中相应的转置卷积(图像中为浅绿色) 。 这个nn.ConvTranspose2d是PyTorch中的模块 , 它对数据进行上采样 , 而不是像众所周知的卷积操作那样进行下采样 。 如需进一步解释 , 请参阅此处:
编码器中的最大池(紫色)替换为相应的解池层(浅紫色) , 或nn.MaxUnpool2d , 参考PyTorch库模块 。
解码器forward为:
def forward(self, x, pool_indices):'''执行解码器Args:x (Tensor): 从编码器得到的编码张量pool_indices (list): 池索引Returns:x (Tensor): 解码后的图像张量'''x_current = xk_pool = 0reversed_pool_indices = list(reversed(pool_indices))for module_decode in self.decoder:# 如果模块正在解池 , 收集适当的池索引if isinstance(module_decode, nn.MaxUnpool2d):x_current = module_decode(x_current, indices=reversed_pool_indices[k_pool])k_pool += 1else:x_current = module_decode(x_current)return x_current编码以及编码器创建的池索引列表是输入 。 每当执行一个解池层时 , 反向地 , 每次取一个池索引 。 这样 , 关于编码器如何执行最大池的信息被转移到解码器 。
因此 , 在镜像编码器层的转置层之后 , forward的输出张量形状是与输入到编码器的图像张量形状相同 。
完整的自编码器模块实现为编码器和解码器实例的组合:
class AutoEncoderVGG(nn.Module):'''基于vgg16的batch normalization的自编码器 。 该类由编码器和解码器组成 。Args:pretrained_params (bool, optional): 是否应该用先训练好的VGG参数填充网络 。默认值为True 。'''channels_in = EncoderVGG.channels_inchannels_code = EncoderVGG.channels_codechannels_out = DecoderVGG.channels_outdef __init__(self, pretrained_params=True):super(AutoEncoderVGG, self).__init__()self.encoder = EncoderVGG(pretrained_params=pretrained_params)self.decoder = DecoderVGG(self.encoder.encoder)def forward(self, x):'''自编码器前向传播Args:x (Tensor): 图像张量Returns:x_prime (Tensor): 编码和解码后的图像张量'''code, pool_indices = self.encoder(x)x_prime = self.decoder(code, pool_indices)return x_primeAE的一组参数可以产生与相应输入非常相似的输出 , 这是一组很好的参数 。 我使用AE输入和输出之间每个像素的均方误差来作为一个目标函数量化它 , 也就是PyTorch库的nn.MSELoss 。


稿源:(未知)

【傻大方】网址:http://www.shadafang.com/c/111T31F92020.html

标题:用PyTorch实现图像聚类( 二 )


上一篇:“智造珠海·进而有为”,华为携手珠海打造全场景智慧城市

下一篇:M1芯片打赢五万元的iMac Pro?首批用户表示性能给力