unet++ pytorch模型转换为onnx模型并实际测试

5 篇文章 0 订阅
2 篇文章 0 订阅

书接上回,上次在安装好openvino环境之后,以及自己在了解完其相关的处理流程之后,现在将自己的模型转换为onnx格式以便后续转换为openvino的中间件。
直接上代码:

import os
import cv2
import onnxruntime
import torch
from albumentations import Compose
from albumentations.augmentations import transforms
from torch.utils.data import DataLoader

import L1_archs_cut
from dataset import test_Dataset


def pth_2onnx():
    """
    pytorch 模型转换为onnx模型
    :return:
    """
    torch_model = torch.load('./model/model.pth')

    model = L1_archs_cut.NestedUNet(num_classes=1, input_channels=3, deep_supervision=True)
    model.load_state_dict(torch_model)
    batch_size = 1  # 批处理大小
    input_shape = (3, 1920, 1088)  # 输入数据

    # set the model to inference mode
    model.eval()
    print(model)
    x = torch.randn(batch_size, *input_shape)  # 生成张量
    export_onnx_file = "model.onnx"  # 目的ONNX文件名
    torch.onnx.export(model,
                      x,
                      export_onnx_file,
                      # 注意这个地方版本选择为11
                      opset_version=11,
                      do_constant_folding=True,  # 是否执行常量折叠优化
                      input_names=["input"],  # 输入名
                      output_names=["output"],  # 输出名
                      dynamic_axes={"input": {0: "batch_size"},  # 批处理变量
                                    "output": {0: "batch_size"}})


def to_numpy(tensor):
    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()


def image_test():
    """
    实际测试onnx模型效果
    :return:
    """
    onnx_path = './model/model.onnx'
    image_path = './data/ray_test/'

    test_transform = Compose([
        transforms.Normalize(),
    ])

    test_dataset = test_Dataset(
        img_ids='0',
        img_dir=image_path,
        num_classes=1,
        transform=test_transform
    )
    test_loader = DataLoader(
        test_dataset,
        batch_size=1,
        shuffle=False,
        num_workers=1,
        drop_last=False
    )
    # print(test_loader)
    for input, meta in test_loader:
        ort_session = onnxruntime.InferenceSession(onnx_path)
        # print('input', input.shape)
        # print(input.shape)
        ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(input)}
        # print('ort_inputs', len(ort_inputs))
        ort_outs = ort_session.run(None, ort_inputs)
        # print('ort_outs', type(ort_outs))
        img_out = ort_outs[0]
        img_out = torch.from_numpy(img_out)
        # print('1', img_out)
        img_out = torch.sigmoid(img_out).cpu().numpy()

        # print('img_out', img_out.shape)
        img_out = img_out.transpose(0, 1, 3, 2)
        num_classes = 1
        for i in range(len(img_out)):
            cv2.imwrite(os.path.join('./', meta['img_id'][i].split('.')[0] + '.png'),
                        (img_out[i, num_classes - 1] * 255).astype('uint8'))


if __name__ == '__main__':
    # pth_2onnx()
    image_test()

数据加载的模块:

import os

import cv2
import torch.utils.data
class test_Dataset(torch.utils.data.Dataset):
    def __init__(self, img_ids, img_dir, num_classes, transform=None):
        self.img_ids = img_ids
        self.img_dir = img_dir
        self.num_classes = num_classes
        self.transform = transform

    def __len__(self):
        return len(self.img_ids)

    def __getitem__(self, idx):

        img_id = self.img_ids[idx]

        img = cv2.imread(os.path.join(self.img_dir, img_id + '.png'))
        if self.transform is not None:
            augmented = self.transform(image=img)
            img = augmented['image']

        img = img.astype('float32') / 255

        img = img.transpose(2, 1, 0)

        return img, {'img_id': img_id}

以上代码是经过自己的测试转换为onnx格式的unet++模型和pth格式的效果是一样的。

注:
若在转换为中间件的过程中若出现一下错误:

[ ERROR ]  Exception occurred during running replacer "REPLACEMENT_ID" (<class 'extensions.middle.DecomposeBias.DecomposeBias'>): After partial shape inference were found shape collision for node Conv_0 (old shape: [   0   32 1920 1088], new shape: [  -1   32 1920 1088])

可将onnx转化的

  do_constant_folding=True,  # 是否执行常量折叠优化
              input_names=["input"],  # 输入名
              output_names=["output"],  # 输出名
              dynamic_axes={"input": {0: "batch_size"},  # 批处理变量
                            "output": {0: "batch_size"}}

这部分代码删除掉
江湖不是打打杀杀,是人情世故,若你有幸看到这边文章点个关注可否

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个简单的UNet++模型PyTorch代码实现: ```python import torch import torch.nn as nn import torch.nn.functional as F class ConvBlock(nn.Module): def __init__(self, in_channels, out_channels): super(ConvBlock, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm2d(out_channels) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1) self.bn2 = nn.BatchNorm2d(out_channels) def forward(self, x): x = F.relu(self.bn1(self.conv1(x))) x = F.relu(self.bn2(self.conv2(x))) return x class ConvTransBlock(nn.Module): def __init__(self, in_channels, out_channels): super(ConvTransBlock, self).__init__() self.convtrans = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=2, stride=2) def forward(self, x): x = self.convtrans(x) return x class UNetPP(nn.Module): def __init__(self, in_channels, out_channels): super(UNetPP, self).__init__() self.conv1 = ConvBlock(in_channels, 64) self.conv2 = ConvBlock(64, 128) self.conv3 = ConvBlock(128, 256) self.conv4 = ConvBlock(256, 512) self.conv5 = ConvBlock(512, 1024) self.conv6 = ConvBlock(1024, 2048) self.upconv1 = ConvTransBlock(2048, 1024) self.upconv2 = ConvTransBlock(1024, 512) self.upconv3 = ConvTransBlock(512, 256) self.upconv4 = ConvTransBlock(256, 128) self.upconv5 = ConvTransBlock(128, 64) self.conv7 = ConvBlock(3072, 1024) self.conv8 = ConvBlock(1536, 512) self.conv9 = ConvBlock(768, 256) self.conv10 = ConvBlock(384, 128) self.conv11 = ConvBlock(192, 64) self.final_conv = nn.Conv2d(64, out_channels, kernel_size=1) def forward(self, x): x1 = self.conv1(x) x2 = F.max_pool2d(x1, kernel_size=2, stride=2) x2 = self.conv2(x2) x3 = F.max_pool2d(x2, kernel_size=2, stride=2) x3 = self.conv3(x3) x4 = F.max_pool2d(x3, kernel_size=2, stride=2) x4 = self.conv4(x4) x5 = F.max_pool2d(x4, kernel_size=2, stride=2) x5 = self.conv5(x5) x6 = F.max_pool2d(x5, kernel_size=2, stride=2) x6 = self.conv6(x6) x7 = self.upconv1(x6) x7 = torch.cat([x7, x5], dim=1) x7 = self.conv7(x7) x8 = self.upconv2(x7) x8 = torch.cat([x8, x4], dim=1) x8 = self.conv8(x8) x9 = self.upconv3(x8) x9 = torch.cat([x9, x3], dim=1) x9 = self.conv9(x9) x10 = self.upconv4(x9) x10 = torch.cat([x10, x2], dim=1) x10 = self.conv10(x10) x11 = self.upconv5(x10) x11 = torch.cat([x11, x1], dim=1) x11 = self.conv11(x11) output = self.final_conv(x11) return output ``` 这个模型实现了一个6层的UNet++结构,每个卷积块的通道数为64/128/256/512/1024/2048。在这个实现中,每个卷积块的结构都是两个3x3的卷积层,中间使用了BatchNorm层和ReLU激活函数。上采样层使用的是2x2的转置卷积。在UNet++结构中,每个上采样层都会将其对应的下采样层的输出与上采样后的特征图进行级联,然后再进行卷积操作。最终的输出使用了一个1x1的卷积层将特征图转换为目标类别的概率图。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值