๐Ÿ˜ŠAI๋ฅผ ์ด์šฉํ•ด์„œ ์–ด๋‘์šด ์ด๋ฏธ์ง€๋ฅผ ๋ฐ๊ฒŒ ๋งŒ๋“ค์–ด๋ณด์ž

,

์œก์•„ ํœด์ง ์ค‘์ธ๋ฐ ์‹ฌ์‹ฌํ•˜๊ตฐ์š”..

AI๋ฅผ ์ด์šฉํ•ด์„œ ์–ด๋‘์šด ์ด๋ฏธ์ง€๋ฅผ ๋ฐ๊ฒŒ ๋งŒ๋“œ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด๊ณ  ์‹ถ์–ด์กŒ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜ ์ด๋ฏธ์ง€๋Š” ์ €์กฐ๋„ ๋ฐ์ดํ„ฐ์…‹ ์ด๋ฏธ์ง€์ธ๋ฐ ์žฌ๋ฏธ์žˆ์–ด ๋ณด์ด๋Š”๊ตฐ์š”.

์กฐ๊ธˆ์”ฉ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ๊ฒฐ๊ณผ๋“ค์„ ์—…๋ฐ์ดํŠธ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

13๊ฐœ์˜ ์ข‹์•„์š”

๊ฐ€์žฅ ๋งŒ๋งŒํ•ด ๋ณด์ด๋Š” ๋…ผ๋ฌธ์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

https://arxiv.org/pdf/2103.00860

์š” ๋…€์„์„ ์ •๋…ํ•ด ๋ณด๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๊ตฌํ˜„์„ ํ•ด๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค.

  1. pytorch๋ฅผ ์ด์šฉํ•ด์„œ ๋ชจ๋ธ์„ ๋งŒ๋“ฌ
  2. C++์—์„œ ๋Œ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ inference ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ
  3. C#์œผ๋กœ ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ๋žฉํ•‘ (๋งˆ์ƒฌ๋ง๋ฐฉ๋ฒ•๊ณผ C++/CLI ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ž˜ํ•‘์„ ์ง„ํ–‰ํ•ด์„œ ์žฅ๋‹จ์  ์ •๋ฆฌ)
  4. C# WPF์— ์„œ๋น„์Šค๋กœ ๋ฐ€์–ด ๋„ฃ์–ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ์ž…๋ ฅ ์ด๋ฏธ์ง€์™€ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋น„๊ต

๊ทผ๋ฐ.. ๋ฒ„๋ฆ‡์ด ์ฐธ ๋ฌด์„œ์šด๊ฒŒ ๋ถ„๋ช… ํœด๊ฐ€ ์ค‘์ธ๋ฐ ๋ˆˆ์ด ๋กœ๋ด‡์ฒ˜๋Ÿผ ์ƒˆ๋ฒฝ์ด ๋˜๋ฉด ์—ด๋ฆฌ๋Š”๊ตฐ์š”..

14๊ฐœ์˜ ์ข‹์•„์š”

๋„ˆ๋Š” ๋„๋Œ€์ฒด ์–ด๋–ป๊ฒŒ ๋™์ž‘ ํ•˜๋Š” ๊ฑฐ๋‹ˆ?

Zero-DCE๋ชจ๋ธ์€ ์ฝ์–ด ๋ณด๋‹ˆ.. ์ž…๋ ฅ RGB ์ž…๋ ฅ์„ ๋ฐ›์œผ๋ฉด ๊ทธ ์ž…๋ ฅ์œผ๋กœ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ํ†ต๊ณผํ•ด ์ถ”์ •ํ•œ ๊ณก์„  ์ปค๋ธŒ์šฉ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์˜ ์ž…๋ ฅ์œผ๋กœ ๋„ฃ์—ˆ๋˜ x์™€ ํ•จ๊ป˜ ๊ณฑํ•˜๊ฑฐ๋‚˜ ๋”ํ•ด์„œ ์ตœ์ ์˜ ๋ฐ๊ธฐ ๊ณก์„ ์„ ๊ฐ€์ง„ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“œ๋Š”๊ฒƒ์ด ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.

๋…ผ๋ฌธ ์ €์ž๋Š” 8๋ฒˆ ๋ฐ˜๋ณตํ•ด์„œ ๊ณฑํ•ด์„œ ์ตœ์ ์˜ ๋ฐ๊ธฐ๋ฅผ ๊ฐ€์ง„ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค์–ด๋ƒˆ์Šต๋‹ˆ๋‹ค.

์•„.. ๊ทธ๋ฆฌ๊ณ  ์Œ.. ๋…ผ๋ฌธ์ €์ž์˜ ์›๋ฌธ repository๋„ ์ฐธ๊ณ ํ–ˆ๋Š”๋ฐ ์ € ์ปค๋ธŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ž…๋ ฅ์ด๋ฏธ์ง€๊ฐ€ 500x500์ด๋ผ๋ฉด ๊ทธ ๊ฐฏ์ˆ˜๋งŒํผ ๋”ฐ๋กœ ์ถ”์ •ํ•ฉ๋‹ˆ๋‹ค. ์ดํ•ด๊ฐ€ ์•ˆ๋˜์„œ ํ•œ์ฐธ์„ ๋ดค๋Š”๋ฐโ€ฆ ํ”ฝ์…€๋งˆ๋‹ค ํŒŒ๋ผ๋ฏธํ„ฐ weight๊ฐ€ ๋…๋ฆฝ์ด๋‹ˆ ์–ด๋‘์šด ๊ณณ์€ ๋ฐ๊ฒŒ ๋ฐ์€ ๊ณณ์€ ๋” ์ž‘์€ ๊ฐ€์ค‘์น˜๋ฅผ ์ค˜์„œ ๋ฒˆ์ง€์ง€ ์•Š๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ๋А๋‚Œ์ ์ธ ๋А๋‚Œ์ด ๋“œ๋Š”๊ตฐ์š”. ๋งŒ์•ฝ ์ € ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•˜๋‚˜์˜€๋‹ค๋ฉด ๋‹น์—ฐํ•˜๊ฒ ์ง€๋งŒ ๋ฐ์€๊ณณ๊ณผ ์–ด๋‘์šด ๊ณณ์„ ๋”ฐ๋กœ ์ปจํŠธ๋กค ํ•  ์ˆ˜ ์—†๊ฒ ์ง€์š” ใ… 

์œ„์— ์„ค๋ช…ํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ๋ชจ๋“  ํ”ฝ์…€์ด ๋‹ค๋ฅธ ๊ฐ€์ค‘์น˜๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋”ฅ๋Ÿฌ๋‹์ด ์กฐ์ •ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’๋“ค์„ R,G,B ์ฑ„๋„๋กœ ๋ถ„๋ฆฌํ•ด์„œ ์‹œ๊ฐํ™”ํ•˜์—ฌ heatmap์œผ๋กœ ํ‘œํ˜„ํ–ˆ์„ ๋•Œ ์–ด๋‘์šด ๊ณณ์€ ๋งŽ์€ ๊ฐ€์ค‘์น˜, ๋ฐ์€ ๊ณณ์€ ์ ์€ ๊ฐ€์ค‘์น˜๋ฅผ ๊ณฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์˜ ๊ตฌ์กฐ์  ๊ด€์ ์œผ๋กœ ๊ด€์ฐฐํ•ด๋ณด์ž

์ด๊ฑด ๋ญ.. ์ „ํ˜€ ๋ณต์žกํ•˜์ง€ ์•Š์€ ์—ฌ๋Ÿฌ ์ปจ๋ณผ๋ฃจ์…˜์„ ์ ์ธตํ•˜์—ฌ ๋งŒ๋“  ๋‹จ์ˆœํ•œ ๋ชจ๋ธ์ด๊ตฐ์š”.

๋‹ค๋งŒ ์•„๋ฌด๋ฆฌ ๋‹จ์ˆœํ•˜๋”๋ผ๋„ stride๋‚˜ max pooling์„ ์ด์šฉํ•œ ํ”ผ์ณ๋งต ์ถ•์†Œ๊ฐ€ ์—†์–ด์„œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ„ฐ์ ธ๋ฒ„๋ฆด ๊ฒƒ ๊ฐ™์€๋ฐ.. ์ฝ์–ด๋ณด๋‹ˆ ์ € ์ปจ๋ณผ๋ฃจ์…˜์€ ๋‹จ์ˆœ ์ปจ๋ณผ๋ฃจ์…˜์ด ์•„๋‹ˆ๋ผ google์ด mobilenet์ด๋ž‘ xception๋ชจ๋ธ์—์„œ ์‚ฌ์šฉํ•œ separable convolution์„ ์ด์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

separable convolution์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ ์œผ๋ฉด ๋„ˆ๋ฌด ๊ธธ์–ด์งˆ ๊ฒƒ ๊ฐ™์•„์„œ ์•„๋ž˜ ๋งํฌ๋กœ ๋Œ€์ฒดํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ์šด์˜ํ•˜์‹œ๋Š” ๋ถ„๋“ค์ด ๊ธ€์„ ์ •๋ง ์ž˜ ์“ฐ์‹œ๋Š”๊ตฐ์š” โ€ฆ.

๊ทธ ์™ธ์— ํŠน๋ณ„ํ•œ ๊ธฐ์ˆ ์ ์ธ ๋ถ€๋ถ„์€ ์—†๊ณ  ์—ฐ์‚ฐ๋Ÿ‰์„ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ ์ปค๋ธŒ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”์ • ์‹œ์— ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ scale๊ฐ’ ๋งŒํผ์„ ์ค„์ด๋Š” ์ž‘์—…์„ ํ•˜๋Š”๊ตฐ์š”.

์ฝ”๋“œ๋ฅผ ๋œฏ์–ด๋ณด๋‹ˆ.. ๊ฐ€๋กœ ์„ธ๋กœ ๊ธธ์ด๋ฅผ 4๋ฐฐ๋ฅผ ์ค„์ž…๋‹ˆ๋‹ค. ๋ฉด์ ์œผ๋กœ ๋”ฐ์ง€๋ฉด 16๋ถ„์˜ 1๋กœ ์ค„์–ด ๋“ค์—ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๊ฒ ๊ตฐ์š”.

์ฝ”๋”ฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐ”๋ผ๋ณด๋Š” ๋™์ž‘ ์›๋ฆฌ

์ €๋Š” ๋”ฅ๋Ÿฌ๋‹์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ์ด์ง€ ๋Œ€ํ•™์›์„ ๋‹ค๋‹ˆ๊ฑฐ๋‚˜ ์—ฐ๊ตฌ์›์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜ํ•™์„ ์ •๋ง ๋ชปํ•ฉ๋‹ˆ๋‹ค -_-

์˜คํžˆ๋ ค C# ์ฝ”๋”ฉ์ด ์ข‹์€๋ฐ ๊ทธ๋Ÿผ ์ € ๋ชจ๋ธ์„ ๋„๋Œ€์ฒด ์–ด๋–ป๊ฒŒ ์ดํ•ดํ•ด์•ผ ๋  ๊ฐ€ ์ƒ๊ฐํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๋”ฑ ๋งž๋Š” ์ •ํ™•ํ•œ ์„ค๋ช…์€ ์•„๋‹ˆ์ง€๋งŒ ์•„๋ž˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ์ง๊ด€์ ์ธ ๋А๋‚Œ์ด ๊ทธ๋ ค์ง€๋Š”๊ตฐ์š”..

Slog ํƒœํด๊ณผ ์˜๊ฒฌ๊ณต์œ โ€ฆ ๋Œ“๊ธ€์€ ์–ธ์ œ๋‚˜ ํ™˜์˜์ž…๋‹ˆ๋‹ค.

9๊ฐœ์˜ ์ข‹์•„์š”

๊ตฌํ˜„ํ•œ ์ €์กฐ๋„ ๊ฐœ์„  ๋ชจ๋ธ Python์ฝ”๋“œ

๋…ผ๋ฌธ์— ๋‚˜์˜จ๋Œ€๋กœ ๊ตฌํ˜„ํ•˜์˜€๊ณ  ํ•™์Šต์„ ๊ฑธ์–ด๋†“์•˜์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ๊ฐ€ ์ž˜ ๋‚˜์™”์œผ๋ฉด ์ข‹๊ฒ ๊ตฐ์š”..
์ด์ „ ํฌ์ŠคํŠธ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ด ๋ชจ๋ธ์„ ํ•™์Šต์‹œ์ผœ์„œ ๋ฐฐํฌ๋Š” ONNX๋กœ ์ง„ํ–‰์„ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ ONNX๋ชจ๋ธ์„ C++ ONNX๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋กœ๋“œํ•ด์„œ ๋Œ์•„๊ฐ€๋„๋ก ๋งŒ๋“ค ๊ฒƒ์ด๊ณ .
๊ทธ ์ดํ›„์— C# ๋ž˜ํ•‘ ๊ณผ์ •์„ ๊ฑฐ์ณ UI์— ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œ์‹œํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.
๋ฌผ๋ก  ๋ˆ„๊ฒŸ์— ๋ฐฐํฌ๋˜์–ด์žˆ๋Š” ์œ ๋ช…ํ•œ ONNX C#๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด์„œ ์ถ”๋ก ํ•˜๋Š”๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์•„ ๊ทธ๋ฆฌ๊ณ  ์ œ๊ฐ€ ์‚ฌ์šฉํ•œ ์ €์กฐ๋„ ๊ฐœ์„  ๋ฐ์ดํ„ฐ์…‹์€ ์•„๋ž˜ ๋งํฌ์—์„œ ๋ฐ›์œผ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Separable Convolution Block

import torch
class DepthwiseSeparableConv(torch.nn.Module):
    def __init__(self, in_ch, out_ch):
        super(DepthwiseSeparableConv, self).__init__()
        self.depth_conv = torch.nn.Conv2d(in_ch, in_ch, kernel_size=3, padding=1, groups=in_ch)
        self.point_conv = torch.nn.Conv2d(in_ch, out_ch, kernel_size=1)

    def forward(self, x):
        return self.point_conv(self.depth_conv(x))

ZeroDCE Model

import torch
import torch.nn as nn
import torch.nn.functional as F



from model.block import DepthwiseSeparableConv


class ZeroDCEPP(nn.Module):
    def __init__(self, scale_factor=4, num_features=32):
        super(ZeroDCEPP, self).__init__()

        self.relu = nn.ReLU(inplace=True)
        self.scale_factor = scale_factor
        self.upsample = nn.UpsamplingBilinear2d(scale_factor=self.scale_factor)

        self.e_conv1 = DepthwiseSeparableConv(3, num_features) 
        self.e_conv2 = DepthwiseSeparableConv(num_features, num_features) 
        self.e_conv3 = DepthwiseSeparableConv(num_features, num_features) 
        self.e_conv4 = DepthwiseSeparableConv(num_features, num_features) 
        self.e_conv5 = DepthwiseSeparableConv(num_features * 2, num_features) # x3 + x4
        self.e_conv6 = DepthwiseSeparableConv(num_features * 2, num_features) # x2 + x5
        self.e_conv7 = DepthwiseSeparableConv(num_features * 2, 3)            # x1 + x6

    def apply_curve(self, x, x_r):
        for _ in range(8):
            x = x + x_r * (torch.pow(x, 2) - x)
        return x

    def forward(self, x):
        # ๋‹ค์šด ์Šค์ผ€์ผ
        if self.scale_factor == 1:
            x_down = x
        else:
            x_down = F.interpolate(x, scale_factor=1/self.scale_factor, mode='bilinear', align_corners=False)


        # ํŠน์ง• ์ถ”์ถœ ๋ ˆ์ด์–ด ์‹œ์ž‘ 
        layer1 = self.relu(self.e_conv1(x_down))
        layer2 = self.relu(self.e_conv2(layer1))
        layer3 = self.relu(self.e_conv3(layer2))
        layer4 = self.relu(self.e_conv4(layer3))
        
        # Feature Concat
        layer5 = self.relu(self.e_conv5(torch.cat([layer3, layer4], 1)))
        layer6 = self.relu(self.e_conv6(torch.cat([layer2, layer5], 1)))
        layer7 = self.e_conv7(torch.cat([layer1, layer6], 1))
        

        x_r = torch.tanh(layer7)

        # ์›๋ณธ ์‚ฌ์ด์ฆˆ๋กœ ๋‹ค์‹œ upsampling
        if self.scale_factor != 1:
            x_r = self.upsample(x_r)
        
        # ์›๋ณธ ์ด๋ฏธ์ง€์— ๋ผ์ดํŠธ๋งต์„ ๊ณฑํ•จ.
        enhance_image = self.apply_curve(x, x_r)
        
        return enhance_image, x_r

ONNX Model ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ๋ชจ๋ธ ์ฝ”๋“œ

import torch


class OnnxModel(torch.nn.Module):
    def __init__(self, backbone:torch.nn.Module):
        super(OnnxModel, self).__init__()

        self.backbone = backbone


    def forward(self, x):
    
        ## ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ๋‚ด๋ณด๋‚ด๊ธฐ ํ• ๋•Œ curve parameter๋Š” inference์‹œ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—. 
        ## OnnxModel์šฉ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ curve๋ฅผ ์ œ์™ธํ•œ ๊ฒฐ๊ณผ๋งŒ ๋ฆฌํ„ดํ•˜๋„๋ก ์ˆ˜์ • 
        
        x, curve = self.backbone(x)

        return x

Training Code

import torch
import torch.onnx
import numpy as np
import cv2
import os

from model.zerodcepp import ZeroDCEPP
from loss.zerodce_loss import ZeroDCETotalLoss
from dataset.lle_dataset import get_lle_loader
from model.onnx_model import OnnxModel

# GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ๋””๋ฐ”์ด์Šค: {device}")

# Hyper Parameter
epochs = 50
learning_rate = 0.0001
weight_decay = 0.0001
batch_size = 8
scale_factor = 4
num_features = 32
image_width = 1024
image_height = 1024
image_channel = 3

dataset_path = "C://github//dataset//lol_dataset//our485//all"
weight_path = "C://github//Dot4Seminar//working//python//results//weights.pth"
onnx_model_path = "C://github//Dot4Seminar//working//python//results//model.onnx"


dummy_input = torch.randn(size=(1, image_channel, image_height, image_width)).to(device)

model = ZeroDCEPP(scale_factor=scale_factor, num_features=num_features)
model = model.to(device)
if os.path.exists(weight_path):
    state_dict = torch.load(weight_path, map_location=device)
    model.load_state_dict(state_dict)


dataloader = get_lle_loader(dataset_path, batch_size, resize_shape=(image_height, image_width))
total_batches = len(dataloader)


loss = ZeroDCETotalLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=weight_decay)

temp_loss = 1000000
for epoch in range(epochs):
    avg_loss = 0

    model.train()
    for i, x_image in enumerate(dataloader):

        gpu_x_image = x_image.to(device)
        enhanced_img, curve_params = model(gpu_x_image)
        current_loss = loss(gpu_x_image, enhanced_img, curve_params)

        optimizer.zero_grad()
        current_loss.backward()
        optimizer.step()

        avg_loss += current_loss.item() / total_batches

    tensor_input_check = gpu_x_image[0]
    tensor_output_check = enhanced_img[0]
    # 1. CPU ์ด๋™ ๋ฐ Numpy ๋ณ€ํ™˜
    input = tensor_input_check.detach().cpu().numpy()
    input = np.transpose(input, (1, 2, 0))
    input = (input * 255).astype(np.uint8)
    input = cv2.cvtColor(input, cv2.COLOR_RGB2BGR)

    # 1. CPU ์ด๋™ ๋ฐ Numpy ๋ณ€ํ™˜
    output = tensor_output_check.detach().cpu().numpy()
    output = np.transpose(output, (1, 2, 0))
    output = (output * 255).astype(np.uint8)
    output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)


    # 5. ์‹œ๊ฐํ™”
    cv2.imshow("original", input)
    cv2.imshow("output", output)
    cv2.waitKey(1) # 1ms ๋Œ€๊ธฐ (ํ•™์Šต ๋ฃจํ”„ ๋ฉˆ์ถค ๋ฐฉ์ง€)

    if temp_loss > avg_loss:
        temp_loss = avg_loss
        
        model.eval()
    
        onnx_model = OnnxModel(backbone=model)

        torch.save(model.state_dict(), weight_path)
        torch.onnx.export(
            onnx_model,                      # ์‹คํ–‰ํ•  ๋ชจ๋ธ
            dummy_input,                # ๋ชจ๋ธ ์ž…๋ ฅ ์˜ˆ์‹œ
            onnx_model_path,            # ์ €์žฅ ํŒŒ์ผ๋ช…
            export_params=True,         # ๋ชจ๋ธ ํŒŒ์ผ ์•ˆ์— ํ•™์Šต๋œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ €์žฅ
            opset_version=11,           # Bilinear ์—ฐ์‚ฐ์„ ์•ˆ์ •์ ์œผ๋กœ ์ง€์›ํ•˜๋Š” ๋ฒ„์ „
            do_constant_folding=True,   # ์ƒ์ˆ˜ ํด๋”ฉ ์ตœ์ ํ™” (์†๋„ ํ–ฅ์ƒ)
            input_names=['input'],      # ์ž…๋ ฅ ๋…ธ๋“œ ์ด๋ฆ„ (C++์—์„œ ํ˜ธ์ถœ ์‹œ ์‚ฌ์šฉ)
            output_names=['output'],    # ์ถœ๋ ฅ ๋…ธ๋“œ ์ด๋ฆ„
        )
        
    print('current avg loss = ', avg_loss)

7๊ฐœ์˜ ์ข‹์•„์š”

์†”์งํžˆ ์•Œ์•„๋“ฃ์ง€ ๋ชปํ•˜์ง€๋งŒ ๋Œ€๋‹จํ•˜์‹œ๋„ค์š” ์ œ๊ฐ€ ๋ชฉํ‘œ๊ฐ€ AI ๋Š” ๋ชจ๋ฅด์ง€๋งŒ @gellston ๋‹˜๊ฐ™์ด
์ผ์ฐจ๋กœ ํ•™์Šต์„ ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋Š”๊ฒƒ๋ฐ ๋Œ€๋‹จํ•˜์„ธ์š”

2๊ฐœ์˜ ์ข‹์•„์š”

์Œโ€ฆ ๋”ฅ๋Ÿฌ๋‹ ๋„ˆ๋ฌด ์–ด๋ ค์šด๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ์ถ”๋ก 

์ง€๋‚œ ํฌ์ŠคํŠธ์—์„œ ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ถ”๋ก ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
์ถ”๋ก ์‹œ์—๋Š” ONNX๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  pytorch ๋ชจ๋ธ์˜ ์ €์žฅ๋œ weights๋ฅผ ๋กœ๋“œํ•˜์—ฌ ์ถ”๋ก  ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์ฝ”๋“œ ๋™์ž‘์€ ์ €์กฐ๋„ ์ด๋ฏธ์ง€๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ ์ˆœํšŒํ•˜๋ฉฐ ์ถ”๋ก ์„ ์ง„ํ–‰ํ•˜๋ฉฐ opencv๋ฅผ ์ด์šฉํ•ด์„œ ์‹œ๊ฐํ™” ๋ฐ ์ •์ƒ ๋™์ž‘ํ•˜๋Š”์ง€ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜์—ฌ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋ธ ์ถ”๋ก  ์ฝ”๋“œ

import torch
import numpy as np
import cv2
import os


from model.zerodcepp import ZeroDCEPP


# GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ๋””๋ฐ”์ด์Šค: {device}")



# Hyper Parameter
scale_factor = 4
num_features = 32
image_width = 1024
image_height = 1024
image_channel = 3

dataset_path = "C://github//dataset//lol_dataset//our485//low"
weight_path = "C://github//Dot4Seminar//working//python//results//weights.pth"
output_dir = "C://github//Dot4Seminar//working//python//results//output_images"


dummy_input = torch.randn(size=(1, image_channel, image_height, image_width)).to(device)

model = ZeroDCEPP(scale_factor=scale_factor, num_features=num_features)
model = model.to(device)
if os.path.exists(weight_path):
    state_dict = torch.load(weight_path, map_location=device)
    model.load_state_dict(state_dict)

model.eval()

os.makedirs(output_dir, exist_ok=True)

file_list = os.listdir(dataset_path)
image_extensions = ('.jpg', '.jpeg', '.png', '.bmp')


for file_name in file_list:
    if not file_name.lower().endswith(image_extensions):
        continue

    full_path = os.path.join(dataset_path, file_name)
    input = cv2.imread(full_path)
    
    if input is None:
        continue

    h, w, _ = input.shape

    input_img = cv2.cvtColor(input, cv2.COLOR_BGR2RGB)
    input_img = cv2.resize(input_img, (image_width, image_height))
    input_img = input_img.astype(np.float32) / 255.0
    input_img = np.transpose(input_img, (2, 0, 1))
    
    input_tensor = torch.from_numpy(input_img).unsqueeze(0).to(device)

    with torch.no_grad():
        enhanced_tensor, _ = model(input_tensor)


    output = enhanced_tensor.squeeze(0).cpu().numpy()
    output = np.transpose(output, (1, 2, 0))
    output = (output * 255.0).clip(0, 255).astype(np.uint8)
    
    output = cv2.cvtColor(output, cv2.COLOR_RGB2BGR)
    output = cv2.resize(output, (w, h))


    save_path = os.path.join(output_dir, file_name)
    cv2.imwrite(save_path, output)


    cv2.imshow('input', input)
    cv2.imshow('output', output)
    

    cv2.waitKey(1)

์‹œ์—ฐ ๋™์˜์ƒ

์ €์กฐ๋„๊ฐœ์„ ๋ชจ๋ธ ํ…Œ์ŠคํŠธ
click image to open video

๊ฒฐ๊ณผ ์ด๋ฏธ์ง€

:blob: #1 ์›๋ณธ

:blob: #1 ๊ฒฐ๊ณผ

:blob: #2 ์›๋ณธ

:blob: #2 ๊ฒฐ๊ณผ

:blob: #3 ์›๋ณธ

:blob: #3 ๊ฒฐ๊ณผ

์ผ๋ถ€ ์ €์กฐ๋„๊ฐ€ ์•„๋‹Œ ๋ฐ์€ ์ด๋ฏธ์ง€์—์„œ๋Š” ์™œ ์˜ค๋™์ž‘์„ ํ• ๊ฐ€?

์™œ๋ƒ๋ฉด ZeroDCE์˜ ํ•™์Šต ๋กœ์Šค๋Š” ์–ด๋‘์šด ์ด๋ฏธ์ง€๋ฅผ ๋ฐ๊ฒŒ ๋งŒ๋“ค๋„๋ก weights ๋“ค์„ ์กฐ์ •ํ•˜์ง€๋งŒ (curve parameters) ๋ฐ˜๋Œ€๋กœ ๊ณผํ•˜๊ฒŒ ๋ฐ์€ ํ”ฝ์…€ ๋ถ€๋ถ„์„ ์กฐ์ •ํ•˜์—ฌ ๋‚ฎ์ถ”๋Š” ์„ค๊ณ„๋Š” ๋“ค์–ด๊ฐ€ ์žˆ์ง€ ์•Š์•„์„œ ๊ทธ๋Ÿฐ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋งŒ์•ฝ์— ์ด ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ํ‰๊ท  ๋ฐ๊ธฐ๊ฐ€ ์–ด๋А ๊ฐ’ ์ด์ƒ์ผ๋•Œ์—๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก (๊ตณ์ด ์ €์กฐ๋„ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๊ธฐ๋–„๋ฌธ์—?) ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ํ•™์Šต์ค‘์— ์„ค์ •ํ•˜๋Š” ํ•˜์ดํผํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์กฐ์ •ํ•˜์—ฌ ํƒ€๊ฒŸ ๋ฐ๊ธฐ๋ฅผ ๋„ˆ๋ฌด ๋ฐ์ง€ ์•Š๋„๋ก ์กฐ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ฒ ๋„ค์š” (ํ•ด๋ดค๋Š”๋ฐ ์ž˜์•ˆ๋ฉ๋‹ˆ๋‹ค..)

7๊ฐœ์˜ ์ข‹์•„์š”

์šฐ์˜คโ€ฆ.. CCTV ์Šคํฌ๋ฆฐ์ƒท ์ด ์–ด๋‘์šธ๋•Œ ์‚ฌ์šฉ ํ•˜๋ฉดโ€ฆ ๋Œ€๋ฐ• ๋‚˜๋Š”๊ฑฐ ์•„๋‹˜๊นŒ ?

์Œ ๋Œ€๊ธฐ์—…๋งŒ ์“ฐ๋ ค๋‚˜

๋Šฅ๋ ฅ์ž ํšฝ์•„๋„คโ€ฆ .. ๋…ผ๋ฌธ์„ ๊ฐœ๋ฐœ๋กœโ€ฆ

2๊ฐœ์˜ ์ข‹์•„์š”

์ƒ๊ฐ๋ณด๋‹ค ์ฝ”๋“œ๊ฐ€ ๊ฐ„๋‹จํ•ด์„œ onnx ๋ณ€ํ™˜๋งŒ ๋˜๋ฉด ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”

1๊ฐœ์˜ ์ข‹์•„์š”

ํ‰๊ท  ๋ฐ๊ธฐ๊ฐ€ ์ผ์ • ์ด์ƒ์ผ ๋•Œ,

์ด๋ฏธ์ง€ ๋ฐ˜์ „ โ†’ ๋กœ์ง ์ ์šฉ โ†’ ๊ฒฐ๊ณผ๋ฌผ ๋ฐ˜์ „

์œผ๋กœ ํ•œ ๋ฒˆ ํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์œผ๋ฆฌ๋ผ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

4๊ฐœ์˜ ์ข‹์•„์š”

์š”์ฆ˜ CCTV์— ๋”ฅ๋Ÿฌ๋‹ ์“ด๋‹ค๊ณ  ๋“ค์—ˆ๋Š”๋ฐ ๋” ์ข‹์€๊ฒŒ ๋“ค์–ด๊ฐ€ ์žˆ์ง€ ์•Š์„๊ฐ€์š”?ใ…  ์ž˜๋ชจ๋ฅด๊ฒ ๊ตฐ์š” ๊ฑฐ๊ธฐ ์—…๊ณ„๋Š” ใ… ใ… 

๋„ค ๋งž์Šต๋‹ˆ๋‹ค ๋…ผ๋ฌธ ์ €์ž๋ถ„์ด ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๊ณ„๋ฅผ ํ•˜์…จ๋”๋ผ๊ตฌ์š”
์˜ค๋ž˜๋œ ๋…ผ๋ฌธ์ด์ง€๋งŒ ์ € ์ €๋„ ๋…ผ๋ฌธ์—์„œ ํ•ญ์ƒ reference๋กœ ๋‚˜์˜ค๋Š” ๋…ผ๋ฌธ๊ฐ™๋”๊ตฐ์š”.
onnx๋ชจ๋ธ์€ ๋ˆ„๊ฒŸ์œผ๋กœ ๊ฐ์‹ธ์„œ ๋งŒ๋“ค๋•Œ ๊ฐ™์ด readme๋ฅผ ์ž‘์„ฑํ•ด์„œ ๊ฐ™์ด ๊ณต์œ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค (๊ณต๋ถ€์šฉ)

์•„ ์ข‹์€ ์•„์ด๋””์–ด ๊ฐ™์Šต๋‹ˆ๋‹ค.
C++ ๋ž˜ํ•‘์„ ํ• ๊ฑด๋ฐ ๊ทธ๋•Œ worst์ผ€์ด์Šค ์ด๋ฏธ์ง€๋“ค์„ ๋ชจ์•„์„œ ๋˜๋Š”์ง€ ์‹คํ—˜ํ•ด๋ด์•ผ๊ฒ ๊ตฐ์š”.


๋Œ€์ถฉ ์ด๋Ÿฐ ๋А๋‚Œ์ด๊ตฐ์š”?
๋‹ค๋งŒ ๋”ฅ๋Ÿฌ๋‹์ด ์ € ๋ฐ˜์ „๋œ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์„๋•Œ ์–ด๋–ป๊ฒŒ ํ•ด์„ํ• ์ง€ (์˜ค๋™์ž‘) ํ•ด๋ด์•ผ ๋  ๊ฒƒ ๊ฐ™๋„ค์š”
์•„๋งˆ ์ž˜ ๋˜๋ฆฌ๋ผ ๋ณด๋Š”๋ฐโ€ฆ ๋งŒ์•ฝ์— ๋ฐ˜์ „์ด ์•ˆ๋œ๋‹ค๋ฉด ํ•™์Šตํ•  ๋•Œ augmentation์œผ๋กœ ํ”ฝ์…€ ๊ฐ’ ๋ฐ˜์ „์„ ๋„ฃ๊ณ  ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ๊ฐ€์ง€๊ณ  ์•„์ด๋””์–ด๋ฅผ ์ ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜๊ฒฌ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

3๊ฐœ์˜ ์ข‹์•„์š”

์•„๊นŒ ์˜๊ฒฌ ์ฃผ์‹  ๊ฑฐ ๋Œ“๊ธ€๋กœ ๋‹ต๋ณ€ ๋“œ๋ฆฌ๋‹ค๊ฐ€ ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ € ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฌ๋‹ค๊ฐ€?
๋ฌธ๋“ ๋“œ๋Š” ์ƒ๊ฐ์ด ์ด๋ฏธ ๋กœ์Šค ํ•จ์ˆ˜์—์„œ๋Š” ์ธ์ ‘ ํ”ฝ์…€์˜ ๋ฐ๊ธฐ์ฐจ๊ฐ€(๊ตญ์†Œ์ ์ธ ๋ฐ๊ธฐ์ฐจ) ๊ณผํ•˜์ง€ ์•Š๋„๋ก ์ œ์•ฝ์„ ์ฃผ๊ณ ์žˆ๋Š”๋ฐ์š”.
๊ฑฐ๊ธฐ์— ๋”ํ•ด์„œ ํ‰๊ท  ๋ฐ๊ธฐ๊ฐ€ ๋‚ด๊ฐ€ ์„ค์ •ํ•œ ๋ฐ๊ธฐ๋กœ ๋”ฐ๋ผ๊ฐ€๋„๋ก ์„ค๊ณ„๊ฐ€ ๋˜์–ด์žˆ๋Š”๋ฐ.
์‹คํ—˜์—์„œ ์ž…๋ ฅ์œผ๋กœ ๋„ฃ์€ ์ •์ƒ์ ์ธ ์ด๋ฏธ์ง€๋Š” ์‚ฌ๋žŒ์˜ ๋ˆˆ์œผ๋กœ ๋ณด์•˜์„๋•Œ ์ „์ฒด์ ์ธ ๊ธ€๋กœ๋ฒŒํ•œ ๋ฐ๊ธฐ๊ฐ€
์˜ฌ๋ผ๊ฐ€ ์žˆ๋Š” ์ƒํƒœ์ธ๋ฐ ๋ชจ๋ธ์˜ ํ”ผ์ณ๋ฅผ ๋ฝ‘๋Š” ์ปจ๋ณผ๋ฃจ์…˜ ๋ ˆ์ด์–ด๋“ค์˜ ์ปค๋„์‚ฌ์ด์ฆˆ๋Š” 3x3์œผ๋กœ ์ž‘๊ธฐ ๋•Œ๋ฌธ์— ์ „์ฒด ์”ฌ ํ•ด์„ ๋Šฅ๋ ฅ์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ๋„ ์–ด๋А๋ถ€๋ถ„ ์ž‘์šฉํ–ˆ์„ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐ์ด ๋“œ๋Š”๊ตฐ์š” ใ… 
๋ชจ๋ธ์ด ๋„ˆ๋ฌด ์ข๊ฒŒ ๋ณด๋Š”๊ฒŒ ์•„๋‹Œ๊ฐ€ ์ƒ๊ฐ์ด ์Œ..
๊ทธ๋ž˜์„œ ๋ง์”€ํ•˜์‹  ๋ฐ˜์ „ ์‹คํ—˜์— ๋”ํ•ด์„œ ํ”ผ์ณ๋ ˆ์ด์–ด์— ์ปค๋„ ์‚ฌ์ด์ฆˆ๋ฅผ ๋Š˜๋ ค์„œ ํ…Œ์ŠคํŠธํ•ด๋ณด๋Š” ๊ฒƒ๋„ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

1๊ฐœ์˜ ์ข‹์•„์š”

์–ด์ œ๋ฐค์— ์ž‘์—…ํ•œ ๊ฒƒโ€ฆ

  • ์ปค์Šคํ…€ ๋ฉ”๋ชจ๋ฆฌํ’€
  • ์ปค์Šคํ…€ ์ด๋ฏธ์ง€ ๊ฐ์ฒด

์™œ ๋งŒ๋“ค์—ˆ๋Š”๊ฐ€?

์ €์กฐ๋„ ๋ชจ๋ธ์„ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ
์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋ชจ๋ธ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ(์ €์กฐ๋„ ๊ฐœ์„ ๋œ ์ด๋ฏธ์ง€)๋ฐ›์„ ํ…๋ฐ ๊ทธ๋Ÿผ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋Š˜์–ด๋‚ ํ…Œ๊ณ 
๋ฌดํ•œ์ • ๊ฐ€์ง€๊ณ  ์žˆ์„ ์ˆ˜ ์—†์œผ๋‹ˆ ๋‹ค์‹œ ํ•ด์ œ๋ฅผ ํ•  ๊ฑด๋ฐ.. ์Œ..
C#์ฝ”๋“œ๋กœ ๋ณด๋ฉด ๋นˆ๋ฒˆํ•œ ์ƒ์„ฑ๊ณผ dispose๊ฐ€ ์žˆ์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถœ๋ ์ถœ๋  ๊ฑฐ๋ฆด ๊ฒƒ ๊ฐ™๋”๊ตฐ์š” ์†๋„์—๋„ ์•ˆ์ข‹๊ตฌ์š”.
์•„๋ฌด๋ฆฌ ์žฌ๋ฏธ๋กœ ๋งŒ๋“ ๋‹ค์ง€๋งŒ.. ์ฉ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์–ด์„œ ๋ฐค์ค‘์— ๋จธ๋ฆฌ๋ฅผ ๊ตด๋ ค์„œ ๋ฉ”๋ชจ๋ฆฌ ํ’€๋„ ๋งŒ๋“ค์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.
์ด ๋ฉ”๋ชจ๋ฆฌํ’€์„ ๋ชจ๋ธ ๋‚ด๋ถ€์—์„œ ์“ฐ๊ฑฐ๋‚˜ ์ด๋ฏธ์ง€๋ฅผ ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ๋ถˆ๋Ÿฌ์™€์„œ ์ƒ์„ฑํ•  ๋•Œ์—๋„ ์“ฐ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋”๊ตฐ์š”.
๊ทธ๋ฆฌ๊ณ  ๋˜ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ.. C++์—์„œ ์ด ๋ฉ”๋ชจ๋ฆฌํ’€์„ ๋””์ž์ธํ•ด๋ณด๋ฉด ๋ณดํ†ต ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋Ÿญ์„ pool ํด๋ž˜์Šค๋กœ ๋ฐ˜ํ™˜์„ ํ• ๋•Œ poolํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํšŒ์ˆ˜๋ฅผ ํ•ด์ค˜์•ผํ•˜๋Š”๋ฐ (์˜ˆ: free) ๊ทธ๊ฒƒ์กฐ์ฐจ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์“ฐ๊ณ ๋ฒ„๋ฆฌ๋ฉด pool๋กœ ์ž๋™์œผ๋กœ ํšŒ์ˆ˜๋˜๋„๋ก ๋””์ž์ธํ•ด๋ณด๊ณ ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์น˜.. GC์ฒ˜๋Ÿผ..
๊ทธ๋ฆฌ๊ณ  ์ด๋ฒˆ์— ๋งŒ๋“œ๋Š” C++ poolํด๋ž˜์Šค๋‚˜ imageํด๋ž˜์Šค์˜ ๋ชจ์–‘์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ผํ•ด์„œ C#์œผ๋กœ๋„ ๋ž˜ํ•‘์„ ์ง„ํ–‰ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

๋ฐค์ค‘์— ๋งŒ๋“  ๋ฉ”๋ชจ๋ฆฌํ’€ ํด๋ž˜์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํŠน๋ณ„ํ•œ ์„ค๊ณ„๋ฅผ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋งŒ์˜ ์ปค์Šคํ…€ ๋ฉ”๋ชจ๋ฆฌํ’€์˜ ๊ธฐ๋Šฅ

  • ๋ฉ”๋ชจ๋ฆฌํ’€์— ํŠน์ • ์‚ฌ์ด์ฆˆ ๋งŒํผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์š”์ฒญํ•˜๋ฉด ๋ฏธ๋ฆฌ ์ƒ์„ฑ๋œ ๋˜‘๊ฐ™์€ ํฌ๊ธฐ์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋Ÿญ์„ ์ฐพ์•„ ๋ฉ”๋ชจ๋ฆฌ ํ† ํฐ์„ ๋ฆฌํ„ด
  • ๋งŒ์•ฝ ๋ฉ”๋ชจ๋ฆฌํ’€์— ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋Ÿญ์ด ์ƒ์„ฑ๋˜์–ด ์žˆ์ง€ ์•Š๋Š”๋‹ค๋ฉด ์‹ ๊ทœ๋กœ ์ƒ์„ฑ
  • ๋ฉ”๋ชจ๋ฆฌํ’€์— bin ์‚ฌ์ด์ฆˆ๋ฅผ ์‚ฌ์ „์— ์„ค์ •ํ•˜๊ณ  ๊ทธ bin์‚ฌ์ด์ฆˆ๋ณด๋‹ค ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์€ ์‚ฌ์ด์ฆˆ๋ฅผ ์š”์ฒญํ•˜๋ฉด ํ•ด๋‹น ๋นˆ์— ํ• ๋‹น ๋˜์–ด ์žˆ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋Ÿญ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ† ํฐ์„ ๋ฆฌํ„ด
  • 3๋ฒˆ์งธ ์‚ฌํ•ญ์˜ ๋™์ž‘์— ์˜ํ•ด์„œ ๋งŒ์•ฝ ์‚ฌ์ „์— ์„ค์ •ํ•œ bin์‚ฌ์ด์ฆˆ์™€ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ์‚ฌ์ด์ฆˆ์˜ ๋น„๊ฐ€ ๋ฉ”๋ชจ๋ฆฌํ’€์— ์„ค์ •ํ•˜๋Š” efficient_rate ๋ณด๋‹ค ์ž‘๋‹ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ์‚ฌ์ด์ฆˆ๋ฅผ bin์œผ๋กœ ์‹ ๊ทœ ๋“ฑ๋ก
    (โ€ป์ค‘์š” : ๋‚ด๋ถ€๋‹จํŽธํ™”๋ฅผ ์–ด๋А์ •๋„ ๋ฐฉ์ง€)
  • ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ฉ”๋ชจ๋ฆฌํ’€ ๋‚ด๋ถ€์—์„œ ์‚ฌ์ „์— ์„ค์ •ํ•œ ๋‹จ์œ„ ์‚ฌ์ด์ฆˆ๋กœ
    align (โ€ป ์ค‘์š”: ์™ธ๋ถ€๋‹จํŽธํ™”๋ฅผ ์–ด๋А์ •๋„ ๋ฐฉ์ง€)
  • freeํ•จ์ˆ˜๋ฅผ ์“ฐ์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์š”์ฒญํ•œ ํ›„์— ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐฉ์น˜ํ•˜์—ฌ ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์ปค์Šคํ…€ ๋ฉ”๋ชจ๋ฆฌํ’€๋กœ ํšŒ์ˆ˜๋จ. (C# ๋ž˜ํ•‘์—์„œ๋„ ๋˜‘๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋„๋ก ๋งŒ๋“ค๊ฒƒ)

C++ ์ฝ”๋“œ


#include <lle/memoryPool.h>
#include <lle/image.h>


int main()
{

    //๋ฉ”๋ชจ๋ฆฌํ’€ ํด๋ž˜์Šค
    auto pool = lleapi::v1::memoryPool::create();
    while (true) {
        {
            //๋ฉ”๋ชจ๋ฆฌ๋ธ”๋Ÿญ ํ† ํฐ
            auto block = pool->acquire(3145728);
            {
                auto block = pool->acquire(3145728);
                {
                    auto block = pool->acquire(3145728);
                    {
                        auto block = pool->acquire(3145728);
                    }
                }
            }
        }
        //๋ฉ”๋ชจ๋ฆฌํ’€์„ ํ†ตํ•ด ์ƒ์„ฑํ•œ ์ด๋ฏธ์ง€
        auto image = lleapi::v1::image::create(1024, 1024, 3, pool);
    }
    
}

์œ„ ์ฝ”๋“œ๋Š” ์ค‘๊ด„ํ˜ธ ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ ์ƒ์„ฑ๋œ ๋ฉ”๋ชจ๋ฆฌ block์ด ์Šค์ฝ”ํ”„๋ฅผ ๋ฒ—์–ด๋‚˜ ํ•ด์ œ ๋˜๊ธฐ ์ „ pool์— ๋ฐ˜ํ™˜์„ ์ง์ ‘์ ์œผ๋กœ ํ•˜์ง€ ์•Š๋”๋ผ๋„ pool๋กœ ์ž๋™ ํšŒ์ˆ˜๋˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ• ๋•Œ ํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ๋„ ๋งŒ์•ฝ ์ด๋ฏธ์ง€์˜ ์ƒ์„ฑ์ž์— pool์„ ์ธ์ž๋กœ ์ฃผ๋ฉด ๋ฉ”๋ชจ๋ฆฌํ’€์— ์š”์ฒญํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ด๋ฏธ์ง€๊ฐ€ ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ

์‹œ๋ชฌ์Šค ์นจ๋Œ€์ฒ˜๋Ÿผ ์ถœ๋ ๊ฑฐ๋ฆฌ์ง€ ์•Š๊ณ  ์žฌํ• ๋‹น๊ณผ ํ•ด์ œ๊ฐ€ ์—†๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†๋„๋Š” ์ธก์ •ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์•„๋งˆ๋„ ๋นˆ๋ฒˆํ•œ ํ• ๋‹น์ด ์—†์œผ๋‹ˆ ๋น ๋ฅด์ง€ ์•Š์„๊นŒ..์‹ถ์Šต๋‹ˆ๋‹คโ€ฆ ๋นจ๋ฆฌ C#์œผ๋กœ ๋˜‘๊ฐ™์€ ๋ชจ์–‘์œผ๋กœ ๋ž˜ํ•‘ํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ์‹ถ๊ตฐ์š” ใ… 

์†Œ์Šค์ฝ”๋“œ

์—ฌ๊ธฐ Git์— ์ €์กฐ๋„ ๋ชจ๋ธ์„ ๋Œ๋ฆด C++ API์™€ C# API๋ฅผ ๋งŒ๋“ค๊ณ  ๋ˆ„๊ฒŸ์œผ๋กœ ๋ฐฐํฌํ•  ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ฒŸ์œผ๋กœ ๋ฐฐํฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๊ฐ€ ๋˜๋ฉด ๊ทธ ๋‹ค์Œ์—๋Š” WPF UI์— ์˜ฌ๋ ค์„œ ๋ทฐ์–ด๋„ ๋งŒ๋“ค์–ด๋ณผ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ํ›„! ์–ด์ œ๋ฐค์— ์ž‘์—…ํ•œ ์ € ๋ฉ”๋ชจ๋ฆฌํ’€๊ณผ ์ด๋ฏธ์ง€๋„ ์˜ฌ๋ผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

CCTV๋Š” ์ ์™ธ์„  ๋ผ์ดํŠธ๊ฐ€ ๋‹ฌ๋ ค ์žˆ์–ด, ๊ตณ์ด ์–ด๋‘ก๊ฒŒ ์ฐ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์•ˆ๊ฐœ ๋‚€ ๋‚  ์‚ฌ๋ฌผ์„ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋น„์Šทํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ ์šฉ๋œ (๋™์˜์ƒ) ๊ฐ์‹œ ์‹œ์Šคํ…œ์ด ์ด๋ฏธ ์šด์šฉ์ค‘์— ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ํ™”์ฒ˜๋Ÿผ ๋ง‰ ์„ ๋ช…ํ•˜๊ฒŒ ๊ฑธ๋Ÿฌ๋‚ด์ง€๋Š” ๋ชป ํ•ด๋„, ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

ONNX C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•ด์„œ ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ๋Œ๋ ค๋ณด์ž.

์–ด์ œ ์ž‘์—…ํ•œ ๋ฉ”๋ชจ๋ฆฌํ’€๊ณผ ์ด๋ฏธ์ง€ ํด๋ž˜์Šค์— ์ˆ˜์ •์„ ๋”ํ•ด์„œ lle๋ผ๋Š” ์ €์กฐ๋„ ๊ฐœ์„  ๋ชจ๋ธ์„ ๋Œ๋ ค์ค„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
lle์™€ imageํด๋ž˜์Šค ๋ชจ๋‘ memoryPool ์ธ์ž๋กœ ๋ฐ›์•„์„œ ์ƒ์„ฑํ•˜๋ฉด ๊ทธ ํ•ด๋‹น ํด๋ž˜์Šค๋“ค์ด ๋ถ€๊ฐ€์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ์‹œ๋„ํ• ๋•Œ ๋ฉ”๋ชจ๋ฆฌํ’€์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
(์˜ˆ: ์ด๋ฏธ์ง€๋ฅผ ๋ฆฌ์‚ฌ์ด์ฆˆํ•œ ๊ฒฐ๊ณผ, ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์˜ ์˜ˆ์ธก ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€, ํŒŒ์ผ์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ ๋“ฑ๋“ฑ)

์ฝ”๋“œ

#include <lle/memoryPool.h>
#include <lle/image.h>
#include <lle/lle.h>

#include <iostream>


int main()
{

    try {
        auto pool = lleapi::v1::memoryPool::create();

        auto lle = lleapi::v1::lle::create(pool);
        lle->setup("C://github//LLE//python//results//model.onnx", lleapi::v1::device::cpu);

        auto input = lleapi::v1::image::imread("C://github//dataset//lol_dataset//our485//low//low_15.png", lleapi::v1::colorType::color, pool);
        auto output1 = lle->predict(input);
        lleapi::v1::image::imwrite("C://github//LLE//LLE//x64//Debug//result1.jpg", output1);

        auto output2 = lle->predict("C://github//dataset//lol_dataset//our485//low//low_15.png");
        lleapi::v1::image::imwrite("C://github//LLE//LLE//x64//Debug//result2.jpg", output1);

    }
    catch (std::exception ex) {

        std::cout << ex.what() << std::endl;
    }
}

๊ฒฐ๊ณผ

์•„๋ž˜์˜ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋Š” ๋ชจ๋‘ ์œ„ C++ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ์ถ”๋ก ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜์—ฌ ๊ฐ€์ ธ์˜จ ์ด๋ฏธ์ง€์ž…๋‹ˆ๋‹ค. python์—์„œ ์ถ”๋ก ํ•œ ๊ฒฐ๊ณผ์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์Œ์„ ์œก์•ˆ์œผ๋กœ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

input.jpg

result1.jpg

์†Œ์Šค์ฝ”๋“œ

๊ณ ๋ฏผ๊ฑฐ๋ฆฌ

์Œโ€ฆ ONNX ๋ชจ๋ธ์„ ๋ˆ„๊ฒŸ์œผ๋กœ ๊ฐ™์ด ๋ง์•„๋‹ค๊ฐ€ ๋ฐฐํฌํ• ๋•Œ์— ๋นŒ๋“œ ์•„์›ƒํ’‹๊ฒฝ๋กœ ์ชฝ์œผ๋กœ ๋˜์ง€๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•˜๊ธดํ•œ๋ฐ์š”.
๋ญ”๊ฐ€ ์‚ฌ์šฉ์ž๊ฐ€ ์ € ๋ชจ๋ธ๊ฒฝ๋กœ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•œ๋‹ค๋Š”๊ฒŒ ์ข€ ์•„์ด๋Ÿฌ๋‹ˆํ•˜๊ตฐ์š”.
๊ทธ๋ ‡๊ฒŒ๋œ๋‹ค๋ฉด ์ € ๋ชจ๋ธ inference๋ฅผ ๋„์™€์ฃผ๋Š” ํด๋ž˜์Šค๋Š” ์ €์กฐ๋„ ํŠนํ™” ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ๋ชจ๋ธ์„ ๋Œ๋ ค์ฃผ๋Š” ๋…€์„์ด ๋ ํ…๋ฐ์š”.. (๊ธฐ์ˆ ์ ์œผ๋กœ ์ „ํ˜€ ๋‹ค๋ฅธ ๋ชจ๋ธ์„ ๋„ฃ์–ด๋„ ๋Œ์•„๊ฐˆ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค..)
์ฐพ์•„๋ณด๋‹ˆ window resource๋กœ ๋ฐ”์ด๋Ÿฌ๋‹ˆ๋ฅผ ์ €์žฅํ•ด๋†“๊ณ  winapi๋กœ ๊ฐ€์ ธ๋‹ค๊ฐ€ ๋กœ๋“œํ•˜๋Š”๋ฐฉ๋ฒ•๋„์žˆ๊ฒ ์ง€๋งŒโ€ฆ

-_- LoadLibrary๋นผ๊ณ ๋Š” ์ •๋ง๋กœ.. winapi๋ฅผ ์‹ซ์–ดํ•ฉ๋‹ˆ๋‹ค. ใ… ใ…  ๋ฌด์Šจ ๋А๋‚Œ์ด ๋ญ”์ง€ ์•„์‹ค ๊ฒ๋‹ˆ๋‹ค. ๋Œ€๋ฌธ์ž ํ•จ์ˆ˜๋“ค ใ… 

๊ทธ๋ž˜์„œ ์ €๋Ÿฐ ๋ฆฌ์†Œ์ŠคํŒŒ์ผ์„ C++ dll ๋‚ด๋ถ€๋กœ ๋“ค์—ฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„๊ฐ€์š”?
์‚ฌ์šฉํ•ด ๋ณด์ง„ ์•Š์•˜์ง€๋งŒ ํŠน๋ณ„ํ•œ ํˆด๋“ค์„ ์ด์šฉํ•ด์„œ ๋ฐ”์ดํŠธ๋ฅผ ํ—ค๋”๋กœ ๋ฐ”๊ฟ”์„œ ๊ฐ™์ด ์ปดํŒŒ์ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋˜๋ฐ
์ตœ์‹  ๋ฐฉ๋ฒ•์ด ๊ถ๊ธˆํ•˜๊ตฐ์š” ๋ฌธ๋“..

๋‹ค์Œ์— ํ•  ๊ฒƒ

์ด์ œ C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ C#์œผ๋กœ ๋ž˜ํ•‘์„ ์ง„ํ–‰ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์• ์ฐฉ์ด ๊ฐ€๋Š” C++/CLI์–ธ์–ด๋ฅผ ํ†ตํ•ด์„œ ๋ž˜ํ•‘์„ ์ง„ํ–‰ํ•ด ๋ณผํ…๋ฐ ๊ณต๋ถ€๊ฒธ ๋งˆ์ƒฌ๋ง์œผ๋กœ๋„ ์ง„ํ–‰์„ ํ•ด๋ด์„œ ์žฅ๋‹จ์ ์„ ์ •๋ฆฌํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๋“ฏ ์‹ถ์Šต๋‹ˆ๋‹ค.

4๊ฐœ์˜ ์ข‹์•„์š”

ํ›Œ๋ฅญํ•œ ์ปจํŠธ๋ฆฌ๋ทฐ์…˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

C/C++ ์ฝ”๋“œ ์ž‘์„ฑ์— ์ต์ˆ™ํ•˜์‹œ๋‹ˆ ๊ฒ€ํ† ํ•ด๋ณผ ์ˆ˜ ์žˆ์„๋งŒํ•œ ๋‹ค์Œ Step์œผ๋กœ, C#์˜ ๊ฒฝ์šฐ JIT์— ์˜์กดํ•˜์ง€ ์•Š๋Š” Naive AOT ๋นŒ๋“œ, ๊ทธ๋ฆฌ๊ณ  ๋‹ท๋„ท์˜ ๋™์  ๋ฉ”๋ชจ๋ฆฌ ์ธํ”„๋ผ์— ์˜์กดํ•˜์ง€ ์•Š๋Š” unsafe ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ฒ€ํ† ํ•ด๋ณด์‹œ๋Š” ๊ฒƒ๋„ ๊ดœ์ฐฎ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. :smiley:

C/C++ DLL ๋‚ด๋ถ€๋กœ ๋ชจ๋ธ์„ ์ ์žฌํ•  ์ˆ˜ ์žˆ๋Š” โ€œํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ง€ํ–ฅโ€์ด๋ฉด์„œ โ€œํšจ์œจ์ โ€์ธ ๋ฐฉ๋ฒ•์€ AI์˜ ๋„์›€์„ ๋ฐ›์•„ ์ฐพ์•„๋ณธ ๋‚ด์šฉ์„ ๊ณต์œ ๋“œ๋ ค๋ด…๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์‹œ๋ฉด ์–ด๋–จ๊นŒ ์‹ถ์Šต๋‹ˆ๋‹ค.


๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์ฒ˜๋Ÿผ ๊ฑฐ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ DLL(Windows)์ด๋‚˜ ELF(Linux) ๊ฐ™์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋‚ด๋ถ€์— ์ง์ ‘ ํฌํ•จ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณดํ†ต โ€œResource Embeddingโ€ ๋˜๋Š” โ€œBinary Blobsโ€ ์ฒ˜๋ฆฌ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ด๊ณ  ์‹ค๋ฌด์—์„œ ์“ฐ์ด๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์ •๋ฆฌํ•ด ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


1. ๋ง์ปค(Linker)๋ฅผ ์ด์šฉํ•œ ๋ฐฉ์‹ (๊ฐ€์žฅ ๋ฒ”์šฉ์ )

ํŒŒ์ผ์˜ ์ข…๋ฅ˜์™€ ์ƒ๊ด€์—†์ด ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ ๊ทธ ์ž์ฒด๋ฅผ ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ(.o ๋˜๋Š” .obj)๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฉ”์ธ ํ”„๋กœ๊ทธ๋žจ๊ณผ ํ•ฉ์น˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

  • GNU objcopy (Linux/ELF ์ค‘์‹ฌ):

    ํŠน์ • ํŒŒ์ผ์„ ์„น์…˜์œผ๋กœ ํฌํ•จ๋œ ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    Bash

    objcopy -I binary -O elf64-x86-64 -B i386 model.onnx model_data.o
    
    

    ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด model_data.o ์•ˆ์— _binary_model_onnx_start, _binary_model_onnx_end ๊ฐ™์€ ์‹ฌ๋ณผ์ด ์ƒ์„ฑ๋˜์–ด ์†Œ์Šค ์ฝ”๋“œ์—์„œ ์™ธ๋ถ€ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • MSVC (Windows/DLL ์ค‘์‹ฌ):

    Visual Studio์—์„œ๋Š” ๋ฆฌ์†Œ์Šค ํŒŒ์ผ(.rc)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

    ์ฝ”๋“œ ์Šค๋‹ˆํŽซ

    // model.rc
    IDR_MODEL_DATA RCDATA "model.onnx"
    
    

    ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์ค‘์— FindResource, LoadResource, LockResource API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ํฌ์ธํ„ฐ๋ฅผ ์–ป์–ด์˜ต๋‹ˆ๋‹ค.

2. ์–ด์…ˆ๋ธ”๋ฆฌ(Assembly) incbin ์‚ฌ์šฉ

์–ด์…ˆ๋ธ”๋ฆฌ์–ด์˜ incbin ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํŒŒ์ผ ํƒ€์ž„์— ํŒŒ์ผ์„ ์ง์ ‘ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ ์„น์…˜์— ๋ฐ•์•„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ์Šค๋‹ˆํŽซ

; model.asm (NASM ์˜ˆ์‹œ)
section .rodata
global model_start
model_start:
    incbin "model.onnx"
model_end:

์ด ๋ฐฉ์‹์€ ์ œ์–ด๊ถŒ์ด ๋งค์šฐ ๋†’๊ณ , ๊ฑฐ์˜ ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์–ด์…ˆ๋ธ”๋Ÿฌ๋งŒ ์žˆ๋‹ค๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

3. ์–ธ์–ด๋ณ„ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ํ™œ์šฉ

์ตœ์‹  ์–ธ์–ด๋“ค์€ ์ด๋ฅผ ์–ธ์–ด ์ฐจ์›์—์„œ ์ง€์›ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

  • Rust: include_bytes! ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํŒŒ์ผ ์‹œ์ ์— ํŒŒ์ผ ๋‚ด์šฉ์„ &[u8] ๋ฐฐ์—ด๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    Rust

    const MODEL_DATA: &[u8] = include_bytes!("model.onnx");
    
    
  • C++23: #embed ์ง€์‹œ์–ด๊ฐ€ ๋„์ž…๋  ์˜ˆ์ •(๋˜๋Š” ์ผ๋ถ€ ์ปดํŒŒ์ผ๋Ÿฌ ์ง€์›)์ž…๋‹ˆ๋‹ค. ์ด์ „์—๋Š” xxd -i ๊ฐ™์€ ๋„๊ตฌ๋กœ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ C ์–ธ์–ด ๋ฐฐ์—ด(unsigned char model[] = {0x12, ...})๋กœ ๋ณ€ํ™˜ํ•ด ํฌํ•จํ•˜๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค.


:warning: ์ฃผ์˜ํ•  ์ : ํŒŒ์ผ์ด โ€œ๋งค์šฐ ํดโ€ ๊ฒฝ์šฐ์˜ ๋ฌธ์ œ

๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์ด ์ˆ˜ GB ๋‹จ์œ„๋กœ ์ปค์ง€๋ฉด ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ง์ ‘ ๋„ฃ๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์— ๋ด‰์ฐฉํ•ฉ๋‹ˆ๋‹ค.

  1. ์ปดํŒŒ์ผ ์†๋„ ์ €ํ•˜: ์ˆ˜ GB์˜ ๋ฐฐ์—ด์„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋А๋ผ ๋นŒ๋“œ ์‹œ๊ฐ„์ด ์—„์ฒญ๋‚˜๊ฒŒ ๋Š˜์–ด๋‚ฉ๋‹ˆ๋‹ค.

  2. ๋ฉ”๋ชจ๋ฆฌ ๋งตํ•‘ ํšจ์œจ: ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์ „์ฒด ๋ฐ์ดํ„ฐ๊ฐ€ ํ”„๋กœ์„ธ์Šค ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  3. ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๊ธฐ ์ œํ•œ: Windows PE ํฌ๋งท ๋“ฑ ์ผ๋ถ€ ๋ฐ”์ด๋„ˆ๋ฆฌ ํฌ๋งท์€ ์„น์…˜ ํฌ๊ธฐ์— ์ œํ•œ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

:light_bulb: ๋Œ€์•ˆ: Memory-Mapped Files (mmap)

์‹ค์ œ๋กœ ๋งŽ์€ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(TensorFlow, PyTorch, ONNX Runtime)๋Š” ๋ชจ๋ธ์„ ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋ฐ•๊ธฐ๋ณด๋‹ค๋Š” ๋ณ„๋„ ํŒŒ์ผ๋กœ ๋‘๊ณ  Memory Mapping (mmap) ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ์žฅ์ : ํŒŒ์ผ์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ง์ ‘ ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ , ํ•„์š”ํ•  ๋•Œ OS๊ฐ€ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ํŽ˜์ด์ง•ํ•ด์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ๋ฒ•: ๋ฐ”์ด๋„ˆ๋ฆฌ ์•ˆ์—๋Š” ๋ชจ๋ธ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋งŒ ์ €์žฅํ•˜๊ณ , ์‹คํ–‰ ์‹œ mmap์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ํฌ์ธํ„ฐ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


์ถ”์ฒœํ•˜๋Š” ๋ฐฉ์‹:

  • ๋ชจ๋ธ ํฌ๊ธฐ๊ฐ€ ์ˆ˜์‹ญ MB ์ดํ•˜๋ผ๋ฉด: **objcopy**๋‚˜ Resource ํŒŒ์ผ ๋ฐฉ์‹์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐํฌ๊ฐ€ ํŒŒ์ผ ํ•˜๋‚˜๋กœ ๋๋‚˜์„œ ๋งค์šฐ ๊ฐ„ํŽธํ•ฉ๋‹ˆ๋‹ค.

  • ๋ชจ๋ธ ํฌ๊ธฐ๊ฐ€ ์ˆ˜๋ฐฑ MB ~ GB ๋‹จ์œ„๋ผ๋ฉด: ๋ฐ”์ด๋„ˆ๋ฆฌ์— ๋„ฃ์ง€ ๋ง๊ณ  **์™ธ๋ถ€ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•œ ๋’ค mmap**์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์„ฑ๋Šฅ๊ณผ ๊ด€๋ฆฌ ๋ฉด์—์„œ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

3๊ฐœ์˜ ์ข‹์•„์š”

์ฐธ๊ณ ๋กœ Native AOT ๋นŒ๋“œ์˜ ๊ฒฝ์šฐ ๋‹จ์ˆœํžˆ JIT ์ปดํŒŒ์ผ๋งŒ ํ”ผํ•œ๋‹ค๋Š” ๊ฐœ๋…์„ ๋„˜์–ด์„ญ๋‹ˆ๋‹ค. Windows, Linux, macOS๋ฅผ ๋Œ€์ƒ์œผ๋กœ amd64, arm64 (+ s390x ๋“ฑ ํŠน์ • ๋ฆฌ๋ˆ…์Šค ๋ฐฐํฌํŒ์ด ์ง€์›ํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜ ํฌํ•จ) ๋Œ€์ƒ์œผ๋กœ ๋‹ท๋„ท ๋Ÿฐํƒ€์ž„์„ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š” ๋‹จ์ผ ์‹คํ–‰ ํŒŒ์ผ์€ ๋ฌผ๋ก , ๋™์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (dll, so, dylib)์™€ ์ •์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (lib, a) ํŒŒ์ผ ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

ํŒŒ์ผ์„ ํ—ค๋”ํŒŒ์ผ ํ–‰๋ ฌ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋„ฃ๊ฑฐ๋‚˜ window resource๋กœ ๋ฐ€์–ด๋„ฃ์–ด์„œ ๊ฐ€์ ธ์˜ค๋Š”๊ฑด ์•Œ๊ณ ์žˆ์—ˆ๋Š”๋ฐ
๊ทธ ์™ธ์— ๋งŽ์€ ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ๊ตฐ์—ฌ (asm๊ณผ AOT?๊ฐ€ ๊ฐ€๋Šฅํ•œ์ค„ ์ฒ˜์Œ์•Œ์•˜์Šต๋‹ˆ๋‹ค.)
์—ด์‹ฌํžˆ ๊ณต๋ถ€ํ•ด์„œ ๋ฐ˜์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.


๋‹คํ–‰ํžˆ ์ด๋ฒˆ์— ๋งŒ๋“  ๋ชจ๋ธ์€ ์ž‘์•„์„œ ํ—ค๋”๋“  resource๊ฑด ๋ฌด๋ฆฌ๊ฐ€ ์—†์–ด๋ณด์ด๋Š”๋ฐ AOT?๋ฅผ ์•Œ์•„๋ด์•ผ๊ฒ ๊ตฐ์š”
๋‹ค์‹œ ํ•œ๋ฒˆ ๋‹ต๋ณ€ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.!

1๊ฐœ์˜ ์ข‹์•„์š”