2022년 10월 8일 토요일

2022 Naver AI Rush

예선

1. 한 사람당 카드 30장이 주어지는데, 카드 종류는 R,G,B로 총 3종류이다.
    각 사람의 점수는 갖고있는 카드의 가장 적은 종류의 카드의 갯수가 점수가 된다.
    (R=15, G=5, B=10 을 갖고 있다면 G=5개가 가장 적기때문에 5점)
    각 사람이 다음 사람들과 교환할 수 있는 몇가지 규칙이 있는데 이것들을 구현하여
    사람들  점수의 합을 구하는 문제이다.
   

2. 문장과 단어가 있는데 문장에 단어를 끼워넣어야 하는데 규칙이 있다.
    이 규칙을 잘 구현하면 되는 문제인데 풀다가 조금 말려서 3번을 먼저 풀고 다시 2번을 풀었다.

3. 배열 100만개와 규칙 4가지가 주어지는데 이 규칙대로 값을 구하는 문제이다. 중간값, 구간합 개념정도만 알면 쉽게 풀 수 있다.

4. 5x5배열이 있고 각  grid마다 방향이 정해져있다. (상하좌우, 2종류의 대각선이였던것 같다.)
   5개의 돌을 놓을 수 있는데 단, 5개의 돌은 각 열과 행에 1개씩 어긋나게 배치해야한다.
   만약 서로 다른 두 돌들이 연속적인 대각선으로 연결이 되어있다면 적절하지 않은것이다.
   모든 경우의 수를 구하는 문제였다.
   

1라운드

- Data imbalance 문제를 해결할 때 under-sampling 방식만 적용한게 컸던것 같다. (참가자분들은 over-sampling방식을 사용) 데이터가 부족해지기 때문에 일반화 측면에서 성능이 낮아지는듯

- Focal loss는 잘 적용한것 같다

- Face detection 전처리를 적용하지 않고 해볼걸 그랬다

- Augmentation을 color, flip 정도로만 적용했는데 다른 augmentation도 적용을 했어야했다.

- 모델 변천사: resnet18 → efficientnet → resnext

- 개인적으로 대회 참여할 시간이 많이 없어서 시도를 많이 못했 (직장인의 한계)

2022년 9월 22일 목요일

활기찬 하루의 시작, 정원삼 6년근 고려홍삼정 365 스틱으로!

안녕하세요, 건강과 활력을 사랑하는 여러분! 오늘은 일상에 에너지를 더해줄 특별한 제품을 소개해드리려고 합니다.

바로 정원삼 6년근 고려홍삼정 365 스틱 + 쇼핑백, 300g입니다.

https://link.coupang.com/a/bS8PWZ
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

6년근 고려홍삼의 진한 에너지

정원삼의 홍삼정 365 스틱은 엄선된 6년근 고려홍삼만을 사용하여 만들어졌습니다. 오랜 시간 정성껏 키워낸 홍삼의 깊은 풍미와 농축된 유효성분을 그대로 담아냈습니다.

  • 진한 풍미: 홍삼의 깊고 진한 맛을 간편하게 즐길 수 있습니다.
  • 풍부한 사포닌: 홍삼의 핵심 성분인 사포닌이 풍부하게 함유되어 있습니다.


언제 어디서나 간편하게, 스틱 포장

바쁜 현대인을 위해 스틱형 포장으로 제작되어 휴대가 간편합니다. 출근길, 운동 전후, 피로를 느낄 때 언제든지 한 스틱으로 활력을 충전하세요.



고급스러운 쇼핑백 포함, 선물용으로도 최고!

함께 제공되는 고급스러운 쇼핑백으로 소중한 분들께 감사의 마음을 전해보세요. 부모님, 친구, 동료 누구에게나 건강을 선물할 수 있습니다.

정원삼을 선택해야 하는 이유

  • 신뢰할 수 있는 품질: 엄격한 품질 관리로 안전하고 믿을 수 있는 제품만을 제공합니다.
  • 합리적인 가격: 고품질의 홍삼을 합리적인 가격에 만나보세요.
  • 고객 만족도 1위: 많은 고객들이 만족한 베스트셀러 제품입니다.

지금 바로 경험해보세요!

일상의 활력을 찾고 싶으신가요? 그렇다면 정원삼 6년근 고려홍삼정 365 스틱이 그 해답입니다. 건강한 에너지로 가득한 하루를 시작해보세요.


https://link.coupang.com/a/bS8PWZ

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

2022년 2월 27일 일요일

if constexpr 구문

 if constexpr 구문은 템플릿 함수가 컴파일 시에 동일한 함수 내에서 여러 범위를 평가할 수 있게 합니다.

1
2
3
4
5
6
7
8
struct Bear
{
    auto roar() const { std::cout << "Roar!\n"; }
};
struct Duck
{
    auto quack() const { std::cout << "Quack!\n"; }
};
cs

위와 같은 Bear와 Duck 클래스가 있을 때 의성어를 내는 메소드를 만든다고 가정해봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Animal 
{
    virtual ~Animal() {}
    virtual void speak() const {}
};
struct Bear : public Animal
{
    void roar() const { std::cout << "Roar!\n"; }
    void speak() const override { roar(); }
};
struct Duck: public Animal
{
    void quack() const { std::cout << "Quack!\n"; }
    void speak() const override  { quack(); }
};
cs

OOP관점에서 생각하자면 위와 같이 Animal이라는 클래스를 만들어 Bear와 Duck를 상속시켜주고 speak()과 같은 메소드에서 roar(), quack() 메소드를 각각 호출해주는 방법을 생각해볼 수 있습니다.


if constexpr 구문을 사용하면 상속을 사용하지 않고 컴파일 타임에 두 객체의 종류에 맞게 메소드를 호출할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Bear
{
    void roar() const { std::cout << "Roar!\n"; }
};
struct Duck
{
    void quack() const { std::cout << "Quack!\n"; }
};
 
template <typename Animal>
void speak(const Animal &a)
{
    if constexpr (std::is_same_v<Animal, Bear>)
    {
        a.roar();
    }
    else if constexpr (std::is_same_v<Animal, Duck>)
    {
        a.quack();
    }
}
cs

compile time에 연산이 수행되는 if constexpr 구문을 사용하는게 훨씬 효율적이라고 합니다.

Reference: 고성능을 위한 언어 C++

2022년 2월 18일 금요일

② Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference




이어서 QAT에 대해 더 알아보도록 하겠습니다.
먼저 QAT를 Batch normalizationSkip connection에 어떻게 적용하는지 보도록 하겠습니다.



[Quantization aware training: Batch normalization folding] 

Conv2d+Batch normalization+Activation 형태의 block을 사용하는 모델들이 대중화되었습니다. 이렇게 Batch normalization을 적용할 때 더 빠른 inference를 위해 weights들을 결합(fusing)하는 최적화를 하게 됩니다.
(해당 내용들은 https://lyzqm.blogspot.com/2021/12/foldingfusing-batch-normalization.html 에 정리해놨으니 참고바랍니다.)

QAT를 적용할 때는 fusing된 weights들에 fake quantization을 적용하고 마찬가지로 activation output에대해서도 적용합니다.




[Quantization aware training: Skip connection] 

   

Resnet에서 사용하는 Skip connection도 QAT를 적용할 때도 기존 방식과 유사합니다.
convolution을 거친 output에 fake quantization을 적용하는것 이외에는 다른것이 없습니다.




[Quantization aware training: Experiments]

Mobilenet의 결과입니다. 
QAT를 적용하여 quantization된 8bit 모델이 퀄컴사의 스냅드래곤에서 
모두 같은 성능대비 빠른 inference가 가능한것을 확인할 수 있습니다.




이러한 성능은 Object detection에서도 비슷하게 나타납니다. 
위의 실험은 MobilenetSSD로 COCO data를 학습시키고 벤치마킹한 결과입니다.
mAP지표는 큰 차이는 없지만 속도 측면에서 향상된 모습을 볼 수 있습니다.



[Conclusion] 
지금까지 QAT에 대해 알아봤습니다. 
quantization효과를 학습하는 과정에서 미리 그 효과를 반영하여 학습 후에 quantization을 진행하여도 성능하락이 없도록 만드는 깔끔하고 간단한 방법인것 같습니다.
NVIDIA, Qualcomm, Google과 같은 기업에서 제공해주는 딥러닝 학습 프레임워크에 모두 QAT를 사용할 수 있는 API가 있을 정도로 많이 사용되는 방법이니 직접 코드를 찾아보셔도 좋을것 같습니다.




2022년 2월 1일 화요일

① Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference


구글이 CVPR2018에서 발표한 논문으로 현재 대부분의 model optimization framework(AIMET, TFMOT, TensorRT)들에서 
제공하는 Quantization aware training기법을 제시한 논문입니다. 
대체로 큰 모델의 경우 post training quantization을 한 후에도 정확도는 크게 떨어지지 않지만 
가벼운 모델(mobilenet, efficientnet...)은 정확도가 많이 떨어질 수 있는데 QAT로 이러한 문제를 해결할 수 있습니다.

hardware에 좀 더 친화적인(friendly)방식으로 deploy하고자 하는 hardware에 맞추기 때문에 
post training quantization적용 후 정확도에 대한 괴리감이 많이 없어지게 됩니다.

해당 논문에서는 이론적인 내용뿐만 아니라 Tensorflow에도 바로 적용할 수 있는 API를 제공해주고 있습니다.
기본적인 개념과 이 논문에서 contribution한 내용들에대해 자세히 알아보도록 하겠습니다.



[Quantization error]
보통 32bit의 모델을 8bit로 quantization을 하곤하는데 정보손실로 인해 quantization error가 발생합니다.
위의 그림이 quantization과 dequantization으로 인한 quantization error를 잘 말해주고 있습니다.
위의 과정을 c++로 구현을 했으니 참고바랍니다. (https://github.com/lyzqm123/quantization/blob/master/algorithm/main.cpp)




[Limitations of post training quantization]
post training quantization은 말 그대로 학습후에 모델을 quantization하는것을 의미합니다.
해당논문에서는 두 가지 이유로 accuracy drop이 발생한다고 제시하고 있습니다.

1. 첫 번째는 output channel에서 발생하는 서로 다른 범위가 매우 차이나는 것입니다. 
예를 들어 weight tensor가 각각 [-2.3, 2.1], [-0.7, 0.5], [-4.7, 3.8]의 범위를 갖고 있다고 했을 때
해당 weight는 각 채널 범위에서 가장 큰 범위인 [-4.7, 3.8]을 기준으로 quantization이 될것입니다.

여기서 눈여겨볼것은 두 번째 채널은 [-0.7, 0.5]의 범위로 상당히 작은 범위이기 때문에 
quantization이 될 때 quantization error가 크게 발생하게 됩니다.
[이 문제를 보완한 per-channel quantization이라는 기법도 있으니 관심있으시면 참고바랍니다.]

2. 두 번째는 weight의 가장자리 값(outlier weight values)으로 인해 quantization시 정확도가 떨어진다고 말하고있습니다.

위의 그래프는 weight tensor의 분포를 나타낸 예시인데 노란색으로 표시된 부분처럼 
값이 큰 tensor들이 비중을 많이 차지하고 있지 않지만 quantization 범위를 크게 만들어 정확도를 떨어뜨리는 효과를 만들어냅니다.



[Quantization aware training: training process]

Quantization aware training방식은 integer-only hardware의 연산과 quantized된 모델의 형태를 학습과정에서부터 
반영한다고 생각하면 이해하기가 쉽습니다.
integer hardware의 환경과 quantization을 simulation했기 때문에 quantization simulation이라고도 부릅니다. 
또한 quantization의 효과를 간접적으로 반영하기 때문에 fake quantization이라고도 불립니다.
QAT에서는 위의 그림(b)처럼 학습하는 과정에서 weights와 activation output에 대해서 fake quantization node(wt quant, act quant)를 
추가해 quantization효과를 줍니다.

quantization 효과란 32bit의 실수가 8bit의 정수가 되고 다시 32bit 실수로 변환되는 
과정에서 발생하는 clamping, rounding효과를 의미합니다.
위의 수식에서 언급하는 값들의 정의는 다음과 같습니다.
$r:$변환하고자 하는 실수
$a, b:$ quantization하고자 하는 실수 범위
$s:$ quantization scale

Example)
$r=1.0,  a=-3.2,  b=1.3,  n=2^{8}(8bit)$
$s(a,b,n)=\frac{1.3-(-3.2)}{2^{8}-1}=0.0176$
$q(r;a,b,n)=\left \lfloor (1.0-(-3.2))/0.0176 \right \rceil *0.0176+(-3.2)=1.0064$

위의 수식에대한 예시를 들어보면, quantization error가 0.0064만큼 발생하는것을 볼 수 있습니다.
즉, QAT는 quantization error가 반영된 값을 학습하는데 의의가 있습니다.

weight quantization과 activation output quantization에서 서로 다른 방법으로 $a, b$를 계산합니다.
  •  weight quantization: $a=min(w), b=max(w)$, int 8bit quantization 기준으로  뺄셈 최적화를 위해 [-127, 127]로 범위를 정함
  • activation quantization: 범위를 어느정도 smooth하게 하기 위해 EMA로 $a, b$를 학습중에 계산함 (범위가 급격하게 바뀔 때 초반 학습 단계에서 activation quantization이 불가능해짐)



[Quantization aware training: inference process]
기존의 fake quantization node (wt quant, act quant)를 제거하고 quantization range 정보를 모델에 quantization할 때 반영합니다.
그렇게 만들어진 quantization 모델을 inference합니다. 이 과정은 target hardware(DSP / EdgeTPU)의 실제 연산과정과 유사합니다.



다음장에서 설명 이어나가겠습니다.


(Reference)


2022년 1월 7일 금요일

Folding(Fusing) Batch normalization

1. Batch normalization


$\gamma,\beta$는 학습중에 지속적으로 업데이트되는 trainable한 변수입니다.
$\mu,\sigma$은 mini batch에서 계산되는 평균값과 표준편차값입니다.
$\mu_{avg}, \sigma_{avg}$은 inference과정에서 사용하기위해 moving average로 축적하는 값입니다.






2. Folding(Fusing) batch normalization

<inception block>

일반적으로 위와 같이 convolution layer와 batch normalization, 그리고 activation function을 연달아 사용하는 
block형태로 일반화되어 사용하는데 Folding(Fusing) batch normalization은 convolution layer와 batch normalization layer가 
결합되어 최적화를 한 layer를 말합니다.


$1.$   $y_{conv}=Wx+b$
-  convolution layer는 위의 식으로 표현됩니다.

$2.$   $\hat{x}=\frac{x-\mu}{\sqrt{\sigma^{2}+\epsilon}}$
$3.$   $y=\gamma\hat{x}+\beta$
-  batch normalization layer는 위의 식으로 표현됩니다.

$4.$   $y=\frac{\gamma(x-\mu)}{\sqrt{\sigma^{2}+\epsilon}}+\beta$                     $\because(2.\cup3.)$
$5.$   $y=\frac{\gamma(Wx+b-\mu)}{\sqrt{\sigma^{2}+\epsilon}}+\beta$                     $\because(1.\cup4.)$
-  batch normalization layer의 input이 convolution layer의 output이 되기 때문에 두 과정을 결합할 수 있습니다.
 
$6.$   $y=\frac{\gamma W}{\sqrt{\sigma^{2}+\epsilon}}x+\gamma\frac{b-\mu}{\sqrt{\sigma^{2}+\epsilon}}+\beta$     $\approx$    $y_{inference}=\frac{\gamma W}{\sqrt{\sigma_{avg}^{2}+\epsilon}}x_{inference}+\gamma\frac{b-\mu_{avg}}{\sqrt{\sigma_{avg}^{2}+\epsilon}}+\beta$      $\approx$    $y_{inference}=\dot{W}x_{inference}$ $+\dot{b}$
-  결국 최종형태의 식은 $y=\dot{W}x$ $+\dot{b}$형태가 되는데 inference과정에서의 $\dot{W}, \dot{b}$값은 모두 상수이기 때문에
   시간복잡도 $O(1)$로 굉장히 빨리 계산할 수 있게됩니다.





3. Tensorflow code
tensorflow2.7버젼 기준으로 batch normalization은 위의 API로 정의 되어있습니다.
앞서 설명한 fusing관련된 argument가 없어보이지만 실제로는 내부적으로 wrapping 돼 있어 
fused = False # or True
와 같이 argument를 추가적으로 명시해줄 수 있습니다.


fused의 코드들을 쭉 따라가다보면  아래와 같은 코드를 볼 수 있게되는데 (https://github.com/tensorflow/tensorflow/blob/v2.7.0/tensorflow/python/ops/nn_impl.py#L1586-L1691)
@tf_export("nn.batch_normalization")
@dispatch.add_dispatch_support
def batch_normalization(x,
                        mean,
                        variance,
                        offset,
                        scale,
                        variance_epsilon,
                        name=None):
  ...
  ...
  y, running_mean, running_var, _, _, _ = gen_nn_ops.fused_batch_norm_v3(
      x,
      scale,
      offset,
      mean,
      variance,
      epsilon=epsilon,
      exponential_avg_factor=exponential_avg_factor,
      data_format=data_format,
      is_training=is_training,
      name=name)
  return y, running_mean, running_var
더이상 fused_batch_norm_v3를 실행하는 gen_nn_ops라는 라이브러리를 따라갈 수 없게됩니다.
그 이유는 bazel빌드를 통해서 만들어지는 파일이기 때문입니다.

실제 코드는 C++로 구현이 되어있으며 gen_nn_ops는 단순히 python으로 wrapping되어있는것 뿐인것이죠.


fused_batch_norm API의 자세한 C++코드를 보고 싶으다면 아래의 링크에서 확인할 수 있습니다.





[Reference]

2022년 1월 3일 월요일

OpenCL - WSL2에 OpenCL 설치하기

OpenCL

OpenCL(Open Computing Language)은 병렬 처리를 위한 표준 API(Application Programming Interface)입니다.
CPU, GPU, FPGA 등 다양한 병렬 처리 장치에서 작업을 병렬화하여 처리할 수 있도록 지원합니다.

OpenCL은 C99 언어를 기반으로 하며, 프로그래머가 병렬 처리를 위한 코드를 작성하면 OpenCL 런타임이 자동으로 해당 코드를 여러 개의 작은 작업으로 분할하여 병렬 처리 장치에 할당합니다.

OpenCL은 다음과 같은 기능을 제공합니다.

  • 하드웨어 추상화
  • 자동 병렬화
  • 동적 디바이스 및 커널 선택
  • 메모리 관리 및 전송
  • 프로그램 빌드 및 컴파일


회사에서는 주로 ubuntu를 사용하다 보니 제 PC는 WSL2로 ubuntu 환경을 구축 해놓았습니다.
WSL2 환경에 OpenCL을 설치하는 방법을 알아보도록 하겠습니다.


WSL2에서 OpenCL 설치하기

먼저 제 PC환경은 아래와 같습니다.

  • OS: Windows 11
  • WSL2: Ubuntu 20.04
  • CPU: Intel i7
  • GPU: Intel(R) Iris(R) XE Graphics


1. OpenCL package 다운로드

$ mkdir neo
$ cd neo
$ wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.12149.1/intel-igc-core_1.0.12149.1_amd64.deb
$ wget https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.12149.1/intel-igc-opencl_1.0.12149.1_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/22.39.24347/intel-level-zero-gpu-dbgsym_1.3.24347_amd64.ddeb
$ wget https://github.com/intel/compute-runtime/releases/download/22.39.24347/intel-level-zero-gpu_1.3.24347_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/22.39.24347/intel-opencl-icd-dbgsym_22.39.24347_amd64.ddeb
$ wget https://github.com/intel/compute-runtime/releases/download/22.39.24347/intel-opencl-icd_22.39.24347_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/22.39.24347/libigdgmm12_22.2.0_amd64.deb
cs


2. OpenCL package 설치

$ sudo apt install ./*.deb
$ sudo apt install -y clinfo
cs


3. OpenCL 패키지 설치 확인

/usr/bin/clinfo -l

Platform #0: Intel(R) OpenCL HD Graphics
 `-- Device #0: Intel(R) Graphics [0x9a49]
cs

 

4. NEO 드라이버, OpenCL 라이브러리 설치

$ sudo add-apt-repository ppa:intel-opencl/intel-opencl
$ sudo apt-get update
$ sudo apt install intel-opencl-icd
 
$ sudo apt-get update
$ sudo apt-get install ocl-icd-opencl-dev
cs


5. OpenCL 라이브러리 확인

$ ls /usr/lib/x86_64-linux-gnu | grep CL
libOpenCL.so
libOpenCL.so.1
libOpenCL.so.1.0.0
cs


Reference: