<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://thplus.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://thplus.github.io/" rel="alternate" type="text/html" /><updated>2025-12-15T14:37:20+00:00</updated><id>https://thplus.github.io/feed.xml</id><title type="html">Brix</title><subtitle>Brix Development Diary</subtitle><author><name>Buyoung Kim</name></author><entry><title type="html">OnTheTop Service</title><link href="https://thplus.github.io/project/ktb/onthetop/" rel="alternate" type="text/html" title="OnTheTop Service" /><published>2025-07-07T00:00:00+00:00</published><updated>2025-07-07T00:00:00+00:00</updated><id>https://thplus.github.io/project/ktb/onthetop</id><content type="html" xml:base="https://thplus.github.io/project/ktb/onthetop/"><![CDATA[<h1 id="프로젝트-소개">프로젝트 소개</h1>
<p><strong>OnTheTop</strong><br /></p>

<ul>
  <li>데스크 테리어에 관심있는 사람들을 위해 생성형 AI 기반으로 퍼스널 데스크 특가 정보를 제공
    <ul>
      <li>사용자의 데스크 셋업 이미지를 분석해 어울리는 아이템 이미지를 생성하고 클릭하면 바로 구매할 수 있는 쇼핑 링크를 제공</li>
    </ul>
  </li>
</ul>

<h2 id="주요기능">주요기능</h2>
<ul>
  <li>사용자가 업로드한 책상 이미지를 AI가 분석하여 데스크 환경을 인식하고 어울리는 데스크 아이템을 추천</li>
  <li>추천된 아이템을 Diffusion 모델을 기반으로 추천 데스크 셋업 이미지 생성</li>
  <li>생성된 이미지를 기반으로 추천된 아이템을 구매할 수 있는 쇼핑 링크 제공</li>
  <li>다양한 Style LoRA를 적용하여 MSPainting Style, Oil Painting Style, Cartoon Style 등 이미지 스타일 변경 기능 제공</li>
</ul>

<h1 id="ai-server-architecture">AI Server Architecture</h1>
<p><img src="/assets/images/OTT_AI_Architect_v1.drawio.png" alt="alt text" /></p>

<h2 id="folder">Folder</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OTT_AI_Server
├── app
│   ├── core
│   │   ├── config.py
│   │   └── logging_config.py
│   ├── main.py
│   ├── routers
│   │   ├── __init__.py
│   │   ├── healthcheck.py
│   │   └── info.py
│   ├── services
│   │   ├── __init__.py
│   │   ├── backend_notify.py
│   │   ├── desk_classify.py
│   │   ├── gpt_api.py
│   │   ├── groundig_dino.py
│   │   ├── masking.py
│   │   ├── naverapi.py
│   │   ├── sam.py
│   │   └── sdxl_inpainting.py
│   ├── shutdown.py
│   ├── startup.py
│   └── utils
│       ├── clear_cache.py
│       ├── delete_image.py
│       ├── load_image.py
│       ├── mapping.py
│       ├── queue_manager.py
│       ├── s3.py
│       └── upscaling.py
├── README.md
├── requirements.txt
└── scripts
    ├── ai-server.service
    ├── start-ai.sh
    └── stop-ai.sh
</code></pre></div></div>

<h1 id="base-model">Base Model</h1>

<ul>
  <li>Base Model로 Stable Diffusion XL 선정</li>
  <li>다른 AI 모델들에 비해 적은 VRAM을 차지하며 생성 속도 또한 빠르기 때문에 가성비가 좋다.</li>
  <li>LoRA를 이용한 Fine Tuning이 가능하여 원하는 이미지 생성이 가능하다.</li>
  <li>다른 AI 모델과의 비교는 <a href="https://github.com/100-hours-a-week/16-Hot6-wiki/wiki/AI_모델-성능-지표">Github Wiki</a> 참조</li>
</ul>

<h2 id="stable-diffusion-xl">Stable Diffusion XL</h2>

<p><a href="https://arxiv.org/abs/2307.01952"><em>SDXL:</em> Improving Latent Diffusion Models for High-Resolution Image Synthesis</a>에 따르면 SDXL은 이전 Stable Diffusion 모델에 비해 세 배 더 큰 규모의 UNet 백본을 포함하며 2개의 텍스트 인코더를 사용해 더 나은 성능을 보여준다. 또한 후작업(refinement)모델이 도압되어 prompt 일관성과 고화질 유지를 모두 달성할 수 있다고 한다.<br />
<br />
<img src="/assets/images/sdxl_architect.png" alt="alt text" /><br />
<br />
SDXL의 아키텍처를 보면 Base 부분은 UNet 기반의 확산 모델로 Prompt와 Noise를 입력받아 Unrefiend Latent를 생성한다. Unrefined Latent는 아직 세부 디테일이 부족한 상태로 Refiner Model를 통해 세부 묘사 및 시각적 품질을 개선하는 방식으로 작동된다. 마지막으로 VAE-Decoder를 통해 latent 공간을 실제 이미지 공간으로 복원하게 되며 여기서 128x128 latent를 1024x1024 해상도로 업스케일 된다.<br /></p>

<h2 id="unet">UNet</h2>

<p>UNet이라는 이름이 붙여진 이유는 구조가 ‘U’자 형태를 띄기 때문이다. 기본적으로는 오토인코더와 같은 인코더-디코더 기반 모델에 속한다.<br />
<br />
<img src="/assets/images/unet_architect.png" alt="alt text" /><br />
<br />
UNet은 크게 Contracting Path(축소 경로)와 Expansive path(확장 경로)로 이루어진다. Contracting path는 일반적인 CNN과 유사하며 이미지의 정보 추출의 목적이다. Expanding path는 Up-convolution을 사용해 해상도를 증가시키며 정확학 경계 정보 유지와 세밀한 Feature 복원이 주 목적이다.<br />
<br />
Stable Diffusion XL의 UNet Block의 구조는 아래와 같다.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conv_in
 
down_blocks:
    DownBlock2D:
        (ResnetBlock2D) x 2
        Downsample2D
    CrossAttnDownBlock2D:
        (ResnetBlock2D
        Transformer2DModel (BasicTransformerBlock x 2) ) x 2
        Downsample2D
    CrossAttnDownBlock2D:
        (ResnetBlock2D
        Transformer2DModel (BasicTransformerBlock x 10) ) x 2
 
mid_blocks:
        ResnetBlock2D
        Transformer2DModel
        ResnetBlock2D
 
up_blocks:
    CrossAttnUpBlock2D:
        (ResnetBlock2D
        Transformer2DModel (BasicTransformerBlock x 10) ) x 3
        Upsample2D
    CrossAttnUpBlock2D:
        (ResnetBlock2D
        Transformer2DModel (BasicTransformerBlock x 2) ) x 3
        Upsample2D
    UpBlock2D:
       (ResnetBlock2D) x 3
 
out
</code></pre></div></div>

<p>Stable Diffusion의 UNet 구조의 특징은 Self-Attention과 Cross-Attention의 개념이 사용된다.<br />
두 개념은 일반적으로 Transformer 기반에서 사용되는 개념으로 Self-Attention은 자기 자신과의 관계에 주목하며, Cross-Attention은 두 입력 간의 관계에 주목하게 된다. Stable Diffusion에서는 Self-Attention은 이미지 latent 내부의 위치 간 관계를 파악해 자연스러운 구조, 질감을 형성하며 Cross-Attention은 텍스트 임베딩과의 관계를 통해 텍스트 조건에 맞는 이미지를 생성하게 된다.<br /></p>

\[Attention(Q, K, V) = softmax \left ( \frac {QK^T}{\sqrt{d_k}} \right )\]

<h2 id="lora">LoRA</h2>
<p>일반적으로 사전학습 된 LLM은 Full-Fine tuning 방식은 모든 파라미터 업데이트로 인해 계산 비용, GPU 메모리, 저장 공간 부담이 크다. GPT-3가 175B 이므로 Full-Fine tuning을 한다면 약 1750억개의 파라미터를 저장해야한다.<br />
<br />
LoRA는 기존 모델의 가중치를 학습 중 직접 수정하지 않고 보정행렬을 삽입하여 fine tuning하는 방법이다.<br />
사전학습된 모델 가중치 $W$는 동결하고 작은 저차원 행렬 $A (r \times k)$와 $B (d \times r)$를 추가학습하여
\(\Delta W = BA, W' = W + \Delta W\)
형태로 표현할 수 있다.<br /></p>

<p>Stable Diffusion에서는 UNet내부 Attention에 적용되며 선형 projection 레이어에만 적용된다.<br />
\(W_qx \Rightarrow \left ( W_q + \frac{\alpha}{\gamma}B_q A_q \right )x\)
위의 수식과 같은 방식으로 $Q$, $K$, $V$, $O$(Out projection)에 $\Delta W$가 붙게 된다.<br />
기존의 Weight의 구조가 $Q = x \cdot W_q$라면
<code class="language-plaintext highlighter-rouge">.load_lora_weight()</code> 메서드 적용후에는 $Q = x \cdot W_q + (x \cdot A_q)B_q$의 구조가 된다.</p>

<h3 id="lora-학습">LoRA 학습</h3>
<ul>
  <li>LoRA의 경우 <a href="https://github.com/bmaltais/kohya_ss">kohya_ss</a>를 사용하여 Custom 학습 하였다.</li>
  <li>학습 이미지의 경우 GPT-4o 이미지 생성 기능을 이용해 깔끔한 Desksetup 기반 이미지 121장(1024x1024)을 추출하여 학습에 사용하였다.</li>
  <li>이미지 예시
<img src="/assets/images/lora_train_ex1.png" alt="alt text" />
<img src="/assets/images/lora_train_ex2.png" alt="alt text" />
<img src="/assets/images/lora_train_ex3.png" alt="alt text" /></li>
</ul>

<h1 id="desk-classify">Desk Classify</h1>
<ul>
  <li>Desk Classify 목적 설명</li>
  <li>CNN 학습 및 경량화 과정</li>
  <li>Desk Classify가 가져온 이점</li>
</ul>

<h1 id="grounding-dino">Grounding DINO</h1>
<ul>
  <li>Grounding DINO 목적 설명 YOLO와의 비교</li>
  <li>Grounding DINO의 Output 값 등 설명</li>
</ul>

<h1 id="sam21">SAM2.1</h1>
<ul>
  <li>SAM2 논문 소개하며 SAM2 기능 설명</li>
  <li>Segmentation 설명 및 단점 등 설명</li>
  <li>Mask Image 처리 과정 설명 등</li>
</ul>

<h1 id="major-update">Major Update</h1>
<ul>
  <li>주요 업데이트 설명 및 트러블 슈팅 과정을 설명</li>
</ul>

<h2 id="test-version">Test Version</h2>
<ul>
  <li>CNN 도입 과정 설명</li>
</ul>

<h2 id="v1">V1</h2>
<ul>
  <li>LoRA학습 및 img2txt -&gt; txt2img pipeline 설명</li>
</ul>

<h2 id="v2">V2</h2>
<ul>
  <li>Inpainting 도입과정 설명 및 Grounding DINO, SAM2.1을 이용한 Auto Masking Process 설명</li>
  <li>Style LoRA 적용</li>
</ul>

<h2 id="v3">V3</h2>
<ul>
  <li>Redis를 응용한 Multi-GPU</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Project" /><category term="KTB" /><category term="python" /><category term="fastapi" /><category term="cnn" /><category term="computer_vision" /><summary type="html"><![CDATA[프로젝트 소개 OnTheTop]]></summary></entry><entry><title type="html">Feature Map 기반 CNN 모델 최적화</title><link href="https://thplus.github.io/project/ktb/cnn_project/" rel="alternate" type="text/html" title="Feature Map 기반 CNN 모델 최적화" /><published>2025-03-29T00:00:00+00:00</published><updated>2025-03-29T00:00:00+00:00</updated><id>https://thplus.github.io/project/ktb/cnn_project</id><content type="html" xml:base="https://thplus.github.io/project/ktb/cnn_project/"><![CDATA[<h1 id="1-서론">1. 서론</h1>
<p>  최근 다양한 CNN(Convolutional Neural Network) 기반의 이미지 분류 모델들이 제안되며 이미지 인식 분야에서 뛰어난 성능을 보이고 있다. 하지만 이러한 모델들은 구조의 복잡성이나 파라미터 수에 따라 연산 비용과 메모리 사용량에 큰 차이를 보이며, 특히 데이터셋의 특성에 따라 성능 및 효율성이 달라질 수 있다.<br />
  실제 응용 환경에서는 모델의 경량화 또한 중요한 과제로 떠오르고 있다. 모바일 기기, 임베디드 시스템, 자동화 기계 등에서는 모델의 정확도뿐만 아니라 처리 속도와 자원 효율성이 중요한 요소로 작용하기 때문이다.<br />
  따라서 본 프로젝트에서는 ‘Rice Image Dataset’을 활용하여 여러 CNN 기반 모델들이 해당 데이터셋에서 어떤 성능을 보이는지 비교하고 모델별 특징 및 효율성을 분석하고자 한다. 특히, 이미지 분류 과정에서 생성되는 Feature map을 시각화함으로써 각 모델이 어떤 방식으로 이미지를 인식하고 구분하는지 직관적으로 이해하고자 하였다.<br />
  이를 통해 더 이상 특징을 제대로 추출하지 못 하는 Layer를 일부 제거하거나 Filter의 수를 줄임 성능저하 없이 예측 효율성을 개선할 수 있는 가능성도 살펴보고자한다. 이러한 분석을 통해 단순 정확도 비교를 넘어서 실제 응용에 적합한 효율적인 모델을 선정하기 위한 방법을 살펴보고자 한다.<br /></p>

<h2 id="1-모델-경량화">(1) 모델 경량화</h2>
<p>  모델 경량화가 필요한 이유는 다양하지만 비용적 문제가 크다. 모델이 크고 계산량이 많아질수록 전력 소비량이 늘어나고 열 발생량도 높아진다. 심지어 최근에는 스마트폰, IoT 기기 등에도 탑재하고자 노력 중이다. 따라서 모델이 가볍고 성능은 뒤떨어지지 않는 것이 중요하다.<br />
  모델 경량화의 Solution은 Pruning, Quantization, Knowledg Distillation 등 다양하게 존재한다. 하지만 본 프로젝트에서는 Filter를 통과한 Featrue Map을 시각화하여 불필요한 Filter를 삭제해봄으로써 모델 경량화를 하고자 한다.<br />
  또한 모델을 경량화하다보면 일반화 성능이 좋아지는 부수적인 이득을 볼 수 있다. 따라서 모델을 경량화 해보면서 각 모델의 일반화 성능을 살펴볼 것이다.<br /></p>

<h2 id="2-feature-map">(2) Feature Map</h2>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOmgjJ%2FbtqXrD2js9s%2FGFjoiBuv70Hx53YKb9XOzK%2Fimg.png" alt="alt text" /><br /></p>

<p>  CNN은 Convolution Layer를 통해 이미지의 주요 특징을 추출하며 이때, 각 필터를 통과한 결과가 Feature Map으로 생성된다. 이후 이 Feature Map은 Pooling Layer를 거쳐 중요한 특징을 강조하고 불필요한 정보를 축소하게 된다. 이러한 과정을 반복한 후에는, 최종적으로 Fully Connected Layer에 전달되어 우리가 흔히 알고 있는 인공신경망(ANN) 구조처럼 분류 작업을 수행하게 된다.<br /></p>

<p>  예를 들어 고양이 사진을 CNN구조인 VGG16에 통과시키면 아래와 같은 Feature Map을 얻을 수 있다.<br />
<img src="/assets/images/cnnproject_catfeaturemap.png" alt="alt text" /><br /></p>
<blockquote>
  <table>
    <tbody>
      <tr>
        <td><a href="https://m.blog.naver.com/luvwithcat/222148953574">이미지 출처</a></td>
        <td>LifeofPy, CNN의 정의, 이미지의 feature map 기능과 kernel(filter)의 개념</td>
      </tr>
    </tbody>
  </table>
</blockquote>

<p>   하지만 본 프로젝트에서 사용하는 ‘Rice Image Dataset’의 경우 CNN의 층이 깊어질수록 불필요한 특징이 잡힐 수 있다. 해당 Dataset을 VGG16에 통과시킨 후의 Feature Map의 차이를 보면 아래와 같다.<br />
<img src="/assets/images/cnnproject_vgg16_layer1.png" alt="alt text" /><br />
  위의 Feature Map은 VGG16의 첫 번째 Convolution Layer를 통과한 이미지이다.<br />
<br />
<img src="/assets/images/cnnproject_vgg16_layerfin.png" alt="alt text" /><br />
  해당 Feature Map은 VGG16의 마지막 Convolution Layer를 통과한 이미지이다. 모든 Filter에 대한 Featrue Map을 출력한 것은 아니지만 대부분의 Filter가 특징을 추출하지 못한 채 모두 검정색임을 알 수 있다. 해당 현상은 Fully Connected Layer에서 문제가 발생할 수 있다.<br /></p>

<h2 id="3-feed-forward-관점">(3) Feed Forward 관점</h2>
<p>  Convolution → ReLU → MaxPooling 형태의 CNN 층을 수식으로 표현하면 아래와 같다.<br />
$X \in \mathbb{R}^{C_{in}\times H \times W}$<br />
$W \in \mathbb{R}^{C_{out}\times C_{in} \times K’ \times K}$<br />
$b_i \in \mathbb{R}$<br />
  출력 채널 $i$, 위치 $(m, n)$에서의 convolution 출력은 아래의 식과 같다.<br /></p>

\[Z_i(m, n) = \sum_{c=1}^{C_{\text{in}}} \sum_{u=1}^{K} \sum_{v=1}^{K} W_{i,c,u,v} \cdot X_c(m + u, n + v) + b_i\]

<p><br />
  ReLU는 음수를 0으로 만들고 양수는 그대로 유지하므로 아래의 식과 같다.<br /></p>

\[\text{ReLU}(Z_i(m, n)) = \max(0, Z_i(m, n))\]

<p><br />
   $2 \times 2$ 커널에서의 Max Pooling은 아래의 식과 같다.<br /></p>

\[P_i(p, q) = \max_{\substack{0 \leq m &lt; k \\ 0 \leq n &lt; k}} A_i(s \cdot p + m,\, s \cdot q + n)\]

<p><br />
  Feature Map의 모든 값이 0일 경우, 다음과 같이 출력된다.<br /></p>

\[Z_i(m,n) = 0 \quad \forall i, m, n \\
ReLU(Z_i(m,n)) = \max(0, Z_i(m,n)) = 0 \\
P_i(p, q) = \max(0, 0, 0, 0) = 0\]

<p>  이처럼 Feature Map이 0으로 채워져 있을 경우, ReLU 및 Pooling을 통과한 이후에도 출력값은 여전히 0이다.<br />
  Fully Connected Layer는 $y = Wx + b$로 표현되므로
모든 입력값  $x = 0$ 이라면, 출력 $y$는 오직 bias$(b)$에만 의존하게 된다.이 상황에서는 실제 이미지로부터 추출한 특징이 전혀 반영되지 않으며 모델은 유의미한 학습이 불가능하게 된다.<br />
  결국 이는 모델이 정답을 무작위로 선택하는 것과 유사한 상태로 이어질 수 있다.</p>

<h2 id="4-backpropagation-관점">(4) Backpropagation 관점</h2>
<p>  Backpropagation의 관점에서 보면, Fully Connected Layer(FCL)의 입력값이 모두 $x=0$ 인 경우, Convolution Layer의 필터는 업데이트되지 않게 된다.<br /></p>

<p>  FCL을 $y = \phi(Wx+b)$로 표현할 수 있을 때, $x = 0$이면 $y = \phi(b)$가 된다. 해당 상황에서 FCL의 가중치 $W$에 대한 손실함수의 기울기를 구하면 다음과 같다.<br />
\(\frac{\partial L}{\partial W} = \frac{\partial L}{\partial y} \cdot \phi '(b) \cdot x^{T} = 0\)
<br />
따라서 FCL의 가중치는 학습되지 않으며 오직 bias의 영향만 받게 된다.<br />
  입력 $X$에 대하여 Convolution → ReLU → Pooling 순으로 연산이 이루어진다고 할 때, Convolution Layer의 weight $W_{conv}$에 대한 기울기는 다음과 같이 chain rule로 표현된다.<br />
\(\frac{\partial L}{\partial W_{conv}} = \frac{\partial L}{\partial A} \cdot \frac{\partial A}{\partial Z} \cdot \frac{\partial Z}{\partial W_{conv}}\)
<br />
    앞서 구한 바와 같이 $\frac{\partial L}{\partial W} = 0$이므로 $\frac{\partial Z}{\partial W_{conv}} = 0$ 이다. 이로인해 Convolution Layer의 필터 역시 학습되지 않게 된다. 결국 bias만 업데이트 되며 의미 없는 학습이 반복될 뿐이다.</p>

<p>  이론적으로도 마지막 Feature Map의 모든 값이 0인 경우에는 학습이 이루어지지 않으며 이는 실험적으로도 관찰 가능하다. 본 프로젝트에서는 Feature Map을 grayscale로 출력하였기 때문에 모든 채널(R, G, B)이 동시에 0인지를 정확히 시각적으로 판단하기는 어렵지만, GoogLeNet을 이용해 이를 간접적으로 확인할 수 있었다.<br />
  GoogLeNet의 대표적인 특징은 1×1 Convolution 연산이다. 이 연산은 Feature Map의 공간적 크기를 유지하면서 채널 수를 줄이는 역할을 한다. 즉, RGB 각각의 특성이 하나의 채널로 압축되는 구조로, 학습이 충분히 진행되지 않은 경우 Feature Map 전체가 0으로 수렴할 가능성도 상대적으로 높아진다.<br />
  또한 GoogLeNet은 총 27개의 Layer로 구성된 깊은 구조이기 때문에, 학습이 불안정하거나 정보가 사라질 경우 Feature Map이 0으로 소멸될 위험성도 다른 모델보다 더 클 수 있다.<br /></p>

<p>  아래의 내용은 실제 weight를 초기화 해보면서 학습을 시도한 결과 얻은 GoogLeNet 학습 결과이다. 학습 로그에서 확인할 수 있듯이 학습이 진행되는 동안 ‘val_accuracy’는 0.1956, ‘val_loss’는 1.6096에서 변하지 않고 반복되었다. 이는 Backpropagation이 정상적으로 이루어지지 않고 bias만 업데이트 되는 현상이 발생했을 가능성이 크다.<br />
<img src="/assets/images/cnnproject_learningerror.png" alt="alt text" /><br /></p>

<p><a href="https://colab.research.google.com/drive/1Wt_dMel9Vv8HwzGIlkuvochkIFNWLsv0?usp=sharing">학습 불가 Colab Link</a>, <a href="https://colab.research.google.com/drive/1WgjlYTLEkDyacbimKDHpdKw0LBZn4aTi?usp=sharing">프로젝트 Colab Link</a> 두 링크를 통해 비교해보면 코드는 같은 걸 알 수 있다.<br />
  Cross-Entropy Loss는 아래와 같이 정의된다.<br />
\(L = -\sum _ {i=1} ^{C} y_{i} \cdot \log(\hat{y}_{i})\)
<br />
  모델이 모든 클래스를 동일한 확률로 예측한다면 각 클래스의 예측 확률은 $\hat{y}_{i} = \frac{1}{C}$이다. 그리고 Cross-Entropy는 정답 클래스에만 적용되므로 $L = \log(C)$가 된다. 즉, 무작위 추측 시의 Cross-Entropy Loss는 $\log(C)$가 된다.<br />
  따라서 Class수가 5일 때, 무작위 추측 시 Cross-Entropy Loss는 $\log(5) \approx \ln(5) \approx 1.609$이다. 따라서 ‘val_loss’가 1.609에서 멈춰 있다는건 모델이 학습을 하지 못하고 무작위로 예측하고 있다는 강력한 증거이다.<br /></p>

<h1 id="2-데이터셋-설명">2. 데이터셋 설명</h1>
<p>  본 프로젝트에서 사용한 데이터셋은 Kaggle의 ‘Rice Image Dataset’으로 Murat Koklu에 의해 제공되었다.<br />
  해당 데이터셋은 Arborio, Basmati, Ipsala, Jasmine, Karacadag로 총 5가지 class로 구분되어 있으며 각 데이터는 15,000개로 총 75,000개의 <code class="language-plaintext highlighter-rouge">.jpg</code> 이미지로 구성되어있다.<br />
   각 이미지는 250x250 픽셀 크기를 가지며 검은 배경 위에 단일 쌀알이 위치한 형태로 구성되어 있다. 이미지들은 쌀알 이외의 잡음은 없고 배경과 객체가 명확히 구분되도록 전처리 되어있어 이미지 분류 모델 학습에 적합한 데이터이다.</p>

<h2 id="1-data-load">(1) Data Load</h2>
<ul>
  <li>Kaggle을 이용한 Data Load</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">kaggle</span> <span class="n">datasets</span> <span class="n">download</span> <span class="o">-</span><span class="n">d</span> <span class="n">nuratkokludataset</span><span class="o">/</span><span class="n">rice</span><span class="o">-</span><span class="n">image</span><span class="o">-</span><span class="n">dataset</span>
<span class="err">!</span><span class="n">unzip</span> <span class="n">rice</span><span class="o">-</span><span class="n">image</span><span class="o">-</span><span class="n">dataset</span><span class="p">.</span><span class="nb">zip</span> <span class="o">-</span><span class="n">d</span> <span class="n">rice_dataset</span>
</code></pre></div></div>

<ul>
  <li>Dataset 확인<br />
해당 데이터는 folder로 class화 해놓았기 때문에 folder별로 class index를 붙여주어야 한다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dataset_path</span> <span class="o">=</span> <span class="s">'.../rice_dataset/Rice_Image_Dataset'</span>

<span class="n">class_folders</span> <span class="o">=</span> <span class="p">[</span><span class="n">f</span><span class="p">.</span><span class="n">name</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">os</span><span class="p">.</span><span class="n">scandir</span><span class="p">(</span><span class="n">dataset_path</span><span class="p">)</span> <span class="k">if</span> <span class="n">f</span><span class="p">.</span><span class="n">is_dir</span><span class="p">()]</span>
<span class="n">num_classes</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">class_folders</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="s">"Class Folders:"</span><span class="p">,</span> <span class="n">class_folders</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Number of Classes:"</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Class Folders: ['Ipsala', 'Arborio', 'Karacadag', 'Jasmine', 'Basmati']
Number of Classes: 5
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="p">.</span><span class="n">Path</span><span class="p">(</span><span class="n">dataset_path</span><span class="p">)</span>

<span class="n">arborio</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'Arborio/*.jpg'</span><span class="p">))</span>
<span class="n">basmati</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'Basmati/*.jpg'</span><span class="p">))</span>
<span class="n">ipsala</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'Ipsala/*.jpg'</span><span class="p">))</span>
<span class="n">jasmine</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'Jasmine/*.jpg'</span><span class="p">))</span>
<span class="n">karacadag</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path</span><span class="p">.</span><span class="n">glob</span><span class="p">(</span><span class="s">'Karacadag/*.jpg'</span><span class="p">))</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Arborio: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">arborio</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Basmati: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">basmati</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Ipsala: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">ipsala</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Jasmine: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">jasmine</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">'Karacadag: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">karacadag</span><span class="p">)</span><span class="si">}</span><span class="s">'</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rborio: 15000
Basmati: 15000
Ipsala: 15000
Jasmine: 15000
Karacadag: 15000
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">basmati_img</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">basmati</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">arborio_img</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">arborio</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">ipsala_img</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">ipsala</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">jasmine_img</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">jasmine</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">karacadag_img</span> <span class="o">=</span> <span class="n">img</span><span class="p">.</span><span class="n">imread</span><span class="p">(</span><span class="n">karacadag</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>

<span class="n">fig</span><span class="p">,</span><span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">ncols</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span>
<span class="n">fig</span><span class="p">.</span><span class="n">suptitle</span> <span class="p">(</span><span class="s">'Rice Category'</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">40</span><span class="p">)</span>

<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"arborio"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"basmati"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"ipsala"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"jasmine"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">4</span><span class="p">].</span><span class="n">set_title</span><span class="p">(</span><span class="s">"karacadag"</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">arborio_img</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">basmati_img</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">ipsala_img</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">jasmine_img</span><span class="p">)</span>
<span class="n">ax</span><span class="p">[</span><span class="mi">4</span><span class="p">].</span><span class="n">imshow</span><span class="p">(</span><span class="n">karacadag_img</span><span class="p">)</span>

<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>

<p><img src="/assets/images/rice_category.png" alt="alt text" /></p>

<h1 id="3-모델-구성">3. 모델 구성</h1>
<h2 id="1-cnn">(1) CNN</h2>
<ul>
  <li>
    <p>일반적인 CNN으로 Convolution → ReLu → MaxPooling 으로 3개 층으로 쌓아보았으며 필터의 개수는 32 → 64 → 128 개를 사용하여 Feature Map을 시각화 하였다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">cnn</span><span class="p">(</span><span class="n">input_shape</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
  <span class="n">inputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Flatten</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">outputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
  <span class="k">return</span> <span class="n">model</span>

<span class="n">cnn</span> <span class="o">=</span> <span class="n">cnn</span><span class="p">(</span><span class="n">input_shape</span> <span class="o">=</span> <span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">cnn</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">cnn</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d (Conv2D)</td>
      <td>(None, 224, 224, 32)</td>
      <td>896</td>
    </tr>
    <tr>
      <td>max_pooling2d (MaxPooling2D)</td>
      <td>(None, 112, 112, 32)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_1 (Conv2D)</td>
      <td>(None, 112, 112, 64)</td>
      <td>18,496</td>
    </tr>
    <tr>
      <td>max_pooling2d_1 (MaxPooling2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_2 (Conv2D)</td>
      <td>(None, 56, 56, 128)</td>
      <td>73,856</td>
    </tr>
    <tr>
      <td>max_pooling2d_2 (MaxPooling2D)</td>
      <td>(None, 28, 28, 128)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>flatten (Flatten)</td>
      <td>(None, 100352)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense (Dense)</td>
      <td>(None, 128)</td>
      <td>12,845,184</td>
    </tr>
    <tr>
      <td>dense_1 (Dense)</td>
      <td>(None, 5)</td>
      <td>645</td>
    </tr>
  </tbody>
</table>

<p>Total params: 12,939,077 (49.36 MB)<br />
  Trainable params: 12,939,077 (49.36 MB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_cnn_accuracy.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_cnn_loss.png" alt="alt text" /><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 9.
</code></pre></div></div>
<p>Best score인 9번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9986<br />
  Train Loss: 0.0040<br />
  Validation Accuracy: 0.9963<br />
  Validation Loss:  0.0132<br /></p>

<h3 id="feature-map-시각화">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_cnn_layer1.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_cnn_layer2.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_cnn_layer3.png" alt="alt text" /><br /></p>

<p>  부분적으로 Filter를 거친 후 Feature Map이 검은색인 경우가 많다. 이는 계산에 큰 영향을 미치지 않을 것이라 판단되어 Filter의 개수를 줄여 개선을 경량화를 해보고자 한다.</p>

<h2 id="2-cnn-경량화">(2) CNN 경량화</h2>
<ul>
  <li>
    <p>일반적인 CNN으로 Convolution → ReLu → MaxPooling 으로 2개 층으로 쌓아보았으며 필터의 갯수는 8 → 16 개를 사용하여 이전과 다르게 <code class="language-plaintext highlighter-rouge">strides</code> 추가하여 Feature Map의 크기를 줄여보았다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">cnn_light</span><span class="p">(</span><span class="n">input_shape</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
  <span class="n">inputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Flatten</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">outputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
  <span class="k">return</span> <span class="n">model</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-1">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer_1 (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_3 (Conv2D)</td>
      <td>(None, 112, 112, 8)</td>
      <td>224</td>
    </tr>
    <tr>
      <td>max_pooling2d_3 (MaxPooling2D)</td>
      <td>(None, 56, 56, 8)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_4 (Conv2D)</td>
      <td>(None, 28, 28, 16)</td>
      <td>1,168</td>
    </tr>
    <tr>
      <td>max_pooling2d_4 (MaxPooling2D)</td>
      <td>(None, 14, 14, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>flatten_1 (Flatten)</td>
      <td>(None, 3136)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_2 (Dense)</td>
      <td>(None, 16)</td>
      <td>50,192</td>
    </tr>
    <tr>
      <td>dense_3 (Dense)</td>
      <td>(None, 5)</td>
      <td>85</td>
    </tr>
  </tbody>
</table>

<p>Total params: 51,669 (201.83 KB)<br />
  Trainable params: 51,669 (201.83 KB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation-1">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_cnnlight_accuracy.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_cnn_loss.png" alt="alt text" /><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 19.
</code></pre></div></div>
<p>Best score인 19번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9986<br />
  Train Loss: 0.0044<br />
  Validation Accuracy: 0.9970<br />
  Validation Loss:  0.0108<br /></p>

<h3 id="feature-map-시각화-1">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_cnnlight_layer1.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_cnnlight_layer2.png" alt="alt text" /><br /></p>

<p>해당 모델은 3개의 층으로 쌓은 CNN에 비해 유효한 특징만 추출한 것을 확인할 수 있다.</p>

<h3 id="모델-비교">모델 비교</h3>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Parameter</th>
      <th>Validation Accuracy</th>
      <th>Validation Loss</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>CNN</td>
      <td>12,939,077</td>
      <td>0.9963</td>
      <td>0.0132</td>
    </tr>
    <tr>
      <td>CNN 경량화</td>
      <td><strong>51,669</strong></td>
      <td><strong>0.9970</strong></td>
      <td><strong>0.0108</strong></td>
    </tr>
  </tbody>
</table>

<p>Parameter 수는 각 12,939,077와 51,669로 99.60(%) 경량화하였으며 Accuracy와 Loss를 보았을 때, 성능차이는 거의 없으며 오히려 경량화 모델이 소폭 높은 것을 확인할 수 있다.</p>

<h2 id="3-googlenet">(3) GoogLeNet</h2>
<ul>
  <li>
    <p>GoogLeNet의 구조는 아래 이미지와 같다.<br />
<img src="/assets/images/cnnproject_googlenet_architect.png" alt="alt text" /><br />
GoogLeNet은 총 27개의 Layer로 구성되어 있고 Stem Network는 신경망의 초기 부분으로 일반적인 CNN의 은닉 구조를 가진다. Inception Module은 GoogLeNet의 핵심적인 구조로 Layer를 하나의 Sub-Network구조로 구성하여 연산량을 줄이는 구조이다.<br />
사전 학습된 Weight 없이 직접 해당 구조를 쌓아보았다.<br /></p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">InceptionModule</span><span class="p">(</span><span class="n">layers</span><span class="p">.</span><span class="n">Layer</span><span class="p">):</span>
  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f1</span><span class="p">,</span> <span class="n">f3_reduce</span><span class="p">,</span> <span class="n">f3</span><span class="p">,</span> <span class="n">f5_reduce</span><span class="p">,</span> <span class="n">f5</span><span class="p">,</span> <span class="n">pool_proj</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
      <span class="nb">super</span><span class="p">(</span><span class="n">InceptionModule</span><span class="p">,</span> <span class="bp">self</span><span class="p">).</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
      <span class="c1"># 1x1 conv branch
</span>      <span class="bp">self</span><span class="p">.</span><span class="n">branch1</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">f1</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)</span>
        
      <span class="c1"># 1x1 -&gt; 3x3 branch
</span>      <span class="bp">self</span><span class="p">.</span><span class="n">branch2</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Sequential</span><span class="p">([</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">f3_reduce</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">),</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">f3</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)</span>
      <span class="p">])</span>
        
      <span class="c1"># 1x1 -&gt; 5x5 branch
</span>      <span class="bp">self</span><span class="p">.</span><span class="n">branch3</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Sequential</span><span class="p">([</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">f5_reduce</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">),</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">f5</span><span class="p">,</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)</span>
      <span class="p">])</span>
        
      <span class="c1"># 3x3 max pooling -&gt; 1x1 conv branch
</span>      <span class="bp">self</span><span class="p">.</span><span class="n">branch4</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Sequential</span><span class="p">([</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">),</span>
          <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="n">pool_proj</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)</span>
      <span class="p">])</span>
    
  <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
      <span class="n">branch1</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">branch1</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
      <span class="n">branch2</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">branch2</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
      <span class="n">branch3</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">branch3</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
      <span class="n">branch4</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">branch4</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
      <span class="k">return</span> <span class="n">tf</span><span class="p">.</span><span class="n">concat</span><span class="p">([</span><span class="n">branch1</span><span class="p">,</span> <span class="n">branch2</span><span class="p">,</span> <span class="n">branch3</span><span class="p">,</span> <span class="n">branch4</span><span class="p">],</span> <span class="n">axis</span><span class="o">=-</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>    </div>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">create_googlenet</span><span class="p">(</span><span class="n">input_shape</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
  <span class="n">inputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>
    
  <span class="c1"># Stem network
</span>  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">7</span><span class="p">,</span><span class="mi">7</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">192</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    
  <span class="c1"># Inception modules
</span>  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">32</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">192</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">64</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">192</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">208</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">48</span><span class="p">,</span> <span class="mi">64</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">160</span><span class="p">,</span> <span class="mi">112</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">256</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">112</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">288</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span> <span class="mi">160</span><span class="p">,</span> <span class="mi">320</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span> <span class="mi">160</span><span class="p">,</span> <span class="mi">320</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">384</span><span class="p">,</span> <span class="mi">192</span><span class="p">,</span> <span class="mi">384</span><span class="p">,</span> <span class="mi">48</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">128</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    
  <span class="c1"># 최종 분류기
</span>  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.4</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
  <span class="n">outputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    
  <span class="n">model</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
  <span class="k">return</span> <span class="n">model</span>

<span class="n">googlenet</span> <span class="o">=</span> <span class="n">create_googlenet</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">googlenet</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">googlenet</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-2">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer_86 (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_176 (Conv2D)</td>
      <td>(None, 112, 112, 64)</td>
      <td>9,472</td>
    </tr>
    <tr>
      <td>max_pooling2d_44 (MaxPooling2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_177 (Conv2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>4,160</td>
    </tr>
    <tr>
      <td>conv2d_178 (Conv2D)</td>
      <td>(None, 56, 56, 192)</td>
      <td>110,784</td>
    </tr>
    <tr>
      <td>max_pooling2d_45 (MaxPooling2D)</td>
      <td>(None, 28, 28, 192)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module_27 (InceptionModule)</td>
      <td>(None, 28, 28, 256)</td>
      <td>163,696</td>
    </tr>
    <tr>
      <td>inception_module_28 (InceptionModule)</td>
      <td>(None, 28, 28, 480)</td>
      <td>388,736</td>
    </tr>
    <tr>
      <td>max_pooling2d_48 (MaxPooling2D)</td>
      <td>(None, 14, 14, 480)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module_29 (InceptionModule)</td>
      <td>(None, 14, 14, 512)</td>
      <td>376,176</td>
    </tr>
    <tr>
      <td>inception_module_30 (InceptionModule)</td>
      <td>(None, 14, 14, 512)</td>
      <td>449,160</td>
    </tr>
    <tr>
      <td>inception_module_31 (InceptionModule)</td>
      <td>(None, 14, 14, 512)</td>
      <td>510,104</td>
    </tr>
    <tr>
      <td>inception_module_32 (InceptionModule)</td>
      <td>(None, 14, 14, 528)</td>
      <td>605,376</td>
    </tr>
    <tr>
      <td>inception_module_33 (InceptionModule)</td>
      <td>(None, 14, 14, 832)</td>
      <td>868,352</td>
    </tr>
    <tr>
      <td>max_pooling2d_54 (MaxPooling2D)</td>
      <td>(None, 7, 7, 832)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module_34 (InceptionModule)</td>
      <td>(None, 7, 7, 832)</td>
      <td>1,043,456</td>
    </tr>
    <tr>
      <td>inception_module_35 (InceptionModule)</td>
      <td>(None, 7, 7, 1024)</td>
      <td>1,444,080</td>
    </tr>
    <tr>
      <td>global_average_pooling2d_3 (GlobalAveragePooling2D)</td>
      <td>(None, 1024)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dropout_3 (Dropout)</td>
      <td>(None, 1024)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_7 (Dense)</td>
      <td>(None, 5)</td>
      <td>5,125</td>
    </tr>
  </tbody>
</table>

<p>Total params: 5,978,677 (22.81 MB)<br />
  Trainable params: 5,978,677 (22.81 MB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation-2">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_googlenet_accuracy.png" alt="alt text" /><br /></p>

<p><img src="/assets/images/cnnproject_googlenet_loss.png" alt="alt text" /><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 24.
</code></pre></div></div>
<p>Best score인 24번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9988<br />
  Train Loss: 0.0039<br />
  Validation Accruacy: 0.9975<br />
  Validation Loss: 0.0111<br /></p>

<h3 id="feature-map-시각화-2">Feature Map 시각화</h3>
<p>Feature Map은 Stem Network만 시각화해보았다.</p>

<p><img src="/assets/images/cnnproject_googlenet_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_googlenet_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_googlenet_layer3.png" alt="alt text" /><br /></p>

<h2 id="4-googlenet-경량화">(4) GoogLeNet 경량화</h2>
<ul>
  <li>
    <p>해당 모델은 Stem Network의 Filter의 개수를 줄이고 각 Inception Module의 Filter 개수를 줄여주었다. 또한 2단계의 Inception Module 하나를 삭제하므로써 연산량을 줄였다. Inception Module의 내부 구조는 GoogLeNet의 특징이므로 건드리지 않았다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Inception Module은 GoogLeNet과 같으므로 생략
</span>
<span class="k">def</span> <span class="nf">create_googlenet_light</span><span class="p">(</span><span class="n">input_shape</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
    <span class="n">inputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>

    <span class="c1"># Stem network
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">7</span><span class="p">,</span><span class="mi">7</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="c1"># Inception modules
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">24</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">48</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">16</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">48</span><span class="p">,</span> <span class="mi">48</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">16</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">24</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">96</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">24</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">strides</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">96</span><span class="p">,</span> <span class="mi">64</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">24</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">InceptionModule</span><span class="p">(</span><span class="mi">96</span><span class="p">,</span> <span class="mi">96</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">32</span><span class="p">,</span> <span class="mi">32</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="c1"># 최종 분류기
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.4</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">outputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="n">model</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">model</span>

<span class="n">googlenet_light</span> <span class="o">=</span> <span class="n">create_googlenet_light</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">googlenet_light</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">googlenet_light</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-3">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d (Conv2D)</td>
      <td>(None, 112, 112, 16)</td>
      <td>2,368</td>
    </tr>
    <tr>
      <td>max_pooling2d (MaxPooling2D)</td>
      <td>(None, 56, 56, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_1 (Conv2D)</td>
      <td>(None, 56, 56, 16)</td>
      <td>272</td>
    </tr>
    <tr>
      <td>conv2d_2 (Conv2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>9,280</td>
    </tr>
    <tr>
      <td>max_pooling2d_1 (MaxPooling2D)</td>
      <td>(None, 28, 28, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module (InceptionModule)</td>
      <td>(None, 28, 28, 56)</td>
      <td>7,148</td>
    </tr>
    <tr>
      <td>inception_module_1 (InceptionModule)</td>
      <td>(None, 28, 28, 72)</td>
      <td>11,172</td>
    </tr>
    <tr>
      <td>max_pooling2d_4 (MaxPooling2D)</td>
      <td>(None, 14, 14, 72)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module_2 (InceptionModule)</td>
      <td>(None, 14, 14, 112)</td>
      <td>23,512</td>
    </tr>
    <tr>
      <td>inception_module_3 (InceptionModule)</td>
      <td>(None, 14, 14, 144)</td>
      <td>44,488</td>
    </tr>
    <tr>
      <td>inception_module_4 (InceptionModule)</td>
      <td>(None, 14, 14, 208)</td>
      <td>86,396</td>
    </tr>
    <tr>
      <td>inception_module_5 (InceptionModule)</td>
      <td>(None, 14, 14, 240)</td>
      <td>103,580</td>
    </tr>
    <tr>
      <td>max_pooling2d_9 (MaxPooling2D)</td>
      <td>(None, 7, 7, 240)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>inception_module_6 (InceptionModule)</td>
      <td>(None, 7, 7, 240)</td>
      <td>109,852</td>
    </tr>
    <tr>
      <td>inception_module_7 (InceptionModule)</td>
      <td>(None, 7, 7, 288)</td>
      <td>181,392</td>
    </tr>
    <tr>
      <td>global_average_pooling2d (GlobalAveragePooling2D)</td>
      <td>(None, 288)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dropout (Dropout)</td>
      <td>(None, 288)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense (Dense)</td>
      <td>(None, 5)</td>
      <td>1,445</td>
    </tr>
  </tbody>
</table>

<p>Total params: 580,905 (2.22 MB)<br />
  Trainable params: 580,905 (2.22 MB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation-3">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_googlenetlight_accuracy.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_googlenetlight_loss.png" alt="alt text" /><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 16.
</code></pre></div></div>
<p>Best score인 16번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9983<br />
  Train Loss: 0.0071<br />
  Validation Accuracy: 0.9981<br />
  Validation Loss: 0.0070<br /></p>

<h3 id="feature-map-시각화-3">Feature Map 시각화</h3>
<p>Feature Map은 위와 마찬가지로 Stem Network만 시각화해보았다.</p>

<p><img src="/assets/images/cnnproject_googlenetlight_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_googlenetlight_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_googlenetlight_layer3.png" alt="alt text" /><br /></p>

<h3 id="모델-비교-1">모델 비교</h3>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Parameter</th>
      <th>Validation Accuracy</th>
      <th>Validation Loss</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>GoogLeNet</td>
      <td>5,978,677</td>
      <td>0.9975</td>
      <td>0.0111</td>
    </tr>
    <tr>
      <td>GoogLeNet 경량화</td>
      <td><strong>580,905</strong></td>
      <td><strong>0.9981</strong></td>
      <td><strong>0.0070</strong></td>
    </tr>
  </tbody>
</table>

<p>Parameter 수는 각 5,978,677와 580,905로 90.28(%) 경량화하였으며 Accuracy와 Loss를 보았을 때, 성능차이는 거의 없으며 오히려 경량화 모델이 소폭 높은 것을 확인할 수 있다.</p>

<h2 id="5-vgg16">(5) VGG16</h2>
<ul>
  <li>
    <p>VGG16은 구조가 매우 간단하며 아래와 같은 구조를 가진다.<br />
<img src="/assets/images/cnnproject_vgg16_architect.png" alt="alt text" /><br />
VGG16은 모든 Convolution Layer에 3x3 필터를 적용하는 것이 큰 특징이다. 구조가 간단하고 이해가 쉽고 변형을 시켜가면서 테스트 하기 용이해 자주 사용되는 모델이다. 해당 모델은 Feature Map 크기는 동일하지만 학습해야할 파라미터 수를 줄였다는 특징이 있다.<br />
해당 모델은 ‘<a href="https://www.kaggle.com/code/sharduljoshi29/rice-classification-using-vgg16-99-accuracy">Rice Image Project 예시</a>‘를 참고하여 Imagenet으로 사전학습 된 모델에서 미세조정 하였다. 또한 이미지 증강은 사용하지 않았고 ‘Rice Image Dataset’을 그대로 사용하였다.<br /></p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">input_tensor</span> <span class="o">=</span> <span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,))</span>

<span class="c1"># VGG16 base model
</span><span class="n">base_model</span> <span class="o">=</span> <span class="n">VGG16</span><span class="p">(</span><span class="n">include_top</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
                  <span class="n">weights</span><span class="o">=</span><span class="s">'imagenet'</span><span class="p">,</span>
                  <span class="n">input_tensor</span><span class="o">=</span><span class="n">input_tensor</span><span class="p">)</span>

<span class="c1"># 필요한 레이어만 학습되도록 설정
</span><span class="k">for</span> <span class="n">layer</span> <span class="ow">in</span> <span class="n">base_model</span><span class="p">.</span><span class="n">layers</span><span class="p">[:</span><span class="o">-</span><span class="mi">4</span><span class="p">]:</span>
    <span class="n">layer</span><span class="p">.</span><span class="n">trainable</span> <span class="o">=</span> <span class="bp">False</span>

<span class="c1"># 커스텀 분류기 추가
</span><span class="n">x</span> <span class="o">=</span> <span class="n">base_model</span><span class="p">.</span><span class="n">output</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">Dense</span><span class="p">(</span><span class="mi">512</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">Dropout</span><span class="p">(</span><span class="mf">0.3</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
<span class="n">output_tensor</span> <span class="o">=</span> <span class="n">Dense</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

<span class="n">vgg16</span> <span class="o">=</span> <span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="o">=</span><span class="n">input_tensor</span><span class="p">,</span> <span class="n">outputs</span><span class="o">=</span><span class="n">output_tensor</span><span class="p">)</span>
<span class="n">vgg16</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
              <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
              <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">vgg16</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-4">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer_171 (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block1_conv1 (Conv2D)</td>
      <td>(None, 224, 224, 64)</td>
      <td>1,792</td>
    </tr>
    <tr>
      <td>block1_conv2 (Conv2D)</td>
      <td>(None, 224, 224, 64)</td>
      <td>36,928</td>
    </tr>
    <tr>
      <td>block1_pool (MaxPooling2D)</td>
      <td>(None, 112, 112, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block2_conv1 (Conv2D)</td>
      <td>(None, 112, 112, 128)</td>
      <td>73,856</td>
    </tr>
    <tr>
      <td>block2_conv2 (Conv2D)</td>
      <td>(None, 112, 112, 128)</td>
      <td>147,584</td>
    </tr>
    <tr>
      <td>block2_pool (MaxPooling2D)</td>
      <td>(None, 56, 56, 128)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block3_conv1 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>295,168</td>
    </tr>
    <tr>
      <td>block3_conv2 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>590,080</td>
    </tr>
    <tr>
      <td>block3_conv3 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>590,080</td>
    </tr>
    <tr>
      <td>block3_pool (MaxPooling2D)</td>
      <td>(None, 28, 28, 256)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block4_conv1 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>1,180,160</td>
    </tr>
    <tr>
      <td>block4_conv2 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block4_conv3 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block4_pool (MaxPooling2D)</td>
      <td>(None, 14, 14, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block5_conv1 (Conv2D)</td>
      <td>(None, 14, 14, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block5_conv2 (Conv2D)</td>
      <td>(None, 14, 14, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block5_conv3 (Conv2D)</td>
      <td>(None, 14, 14, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block5_pool (MaxPooling2D)</td>
      <td>(None, 7, 7, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>global_average_pooling2d_7 (GlobalAveragePooling2D)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_14 (Dense)</td>
      <td>(None, 512)</td>
      <td>262,656</td>
    </tr>
    <tr>
      <td>dropout_7 (Dropout)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_15 (Dense)</td>
      <td>(None, 5)</td>
      <td>2,565</td>
    </tr>
  </tbody>
</table>

<p>Total params: 14,979,909 (57.14 MB)<br />
  Trainable params: 7,344,645 (28.02 MB)<br />
  Non-trainable params: 7,635,264 (29.13 MB)<br /></p>

<h3 id="model-evaluation-4">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_vgg16_accuracy.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_loss.png" alt="alt text" /><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 11.
</code></pre></div></div>
<p>Best score인 11번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9994<br />
  Train Loss: 0.0024<br />
  Validation Accuracy: 0.9979<br />
  Validation Loss: 0.0099<br /></p>

<h3 id="feature-map-시각화-4">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_vgg16_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer3.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer4.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer5.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layerfin.png" alt="alt text" /><br /></p>

<h2 id="6-vgg16-경량화">(6) VGG16 경량화</h2>
<ul>
  <li>
    <p>사전학습 되어있는 Filter를 그대로 사용하고 block_5는 특징 추출이 되지 않은 형태로 보이므로 삭제하여 경량화였다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">x</span> <span class="o">=</span> <span class="n">vgg16</span><span class="p">.</span><span class="n">get_layer</span><span class="p">(</span><span class="s">'block4_pool'</span><span class="p">).</span><span class="n">output</span>

<span class="c1"># 분류기 추가
</span><span class="n">x</span> <span class="o">=</span> <span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">Dense</span><span class="p">(</span><span class="mi">512</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">Dropout</span><span class="p">(</span><span class="mf">0.3</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
<span class="n">output_tensor</span> <span class="o">=</span> <span class="n">Dense</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

<span class="c1"># 전체 모델 정의
</span><span class="n">vgg_light</span> <span class="o">=</span> <span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="o">=</span><span class="n">input_tensor</span><span class="p">,</span> <span class="n">outputs</span><span class="o">=</span><span class="n">output_tensor</span><span class="p">)</span>

<span class="c1"># 필요한 레이어만 학습되도록 설정
</span><span class="k">for</span> <span class="n">layer</span> <span class="ow">in</span> <span class="n">vgg16</span><span class="p">.</span><span class="n">layers</span><span class="p">:</span>
    <span class="n">layer</span><span class="p">.</span><span class="n">trainable</span> <span class="o">=</span> <span class="bp">False</span>

<span class="n">vgg_light</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">vgg_light</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-5">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block1_conv1 (Conv2D)</td>
      <td>(None, 224, 224, 64)</td>
      <td>1,792</td>
    </tr>
    <tr>
      <td>block1_conv2 (Conv2D)</td>
      <td>(None, 224, 224, 64)</td>
      <td>36,928</td>
    </tr>
    <tr>
      <td>block1_pool (MaxPooling2D)</td>
      <td>(None, 112, 112, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block2_conv1 (Conv2D)</td>
      <td>(None, 112, 112, 128)</td>
      <td>73,856</td>
    </tr>
    <tr>
      <td>block2_conv2 (Conv2D)</td>
      <td>(None, 112, 112, 128)</td>
      <td>147,584</td>
    </tr>
    <tr>
      <td>block2_pool (MaxPooling2D)</td>
      <td>(None, 56, 56, 128)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block3_conv1 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>295,168</td>
    </tr>
    <tr>
      <td>block3_conv2 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>590,080</td>
    </tr>
    <tr>
      <td>block3_conv3 (Conv2D)</td>
      <td>(None, 56, 56, 256)</td>
      <td>590,080</td>
    </tr>
    <tr>
      <td>block3_pool (MaxPooling2D)</td>
      <td>(None, 28, 28, 256)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>block4_conv1 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>1,180,160</td>
    </tr>
    <tr>
      <td>block4_conv2 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block4_conv3 (Conv2D)</td>
      <td>(None, 28, 28, 512)</td>
      <td>2,359,808</td>
    </tr>
    <tr>
      <td>block4_pool (MaxPooling2D)</td>
      <td>(None, 14, 14, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>global_average_pooling2d_3 (GlobalAveragePooling2D)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_6 (Dense)</td>
      <td>(None, 512)</td>
      <td>262,656</td>
    </tr>
    <tr>
      <td>dropout_3 (Dropout)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_7 (Dense)</td>
      <td>(None, 5)</td>
      <td>2,565</td>
    </tr>
  </tbody>
</table>

<p>Total params: 7,900,485 (30.14 MB)<br />
  Trainable params: 265,221 (1.01 MB)<br />
  Non-trainable params: 7,635,264 (29.13 MB)<br /></p>

<h3 id="model-evaluation-5">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_vgglight_accuracy.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgglight_loss.png" alt="alt text" /><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 28.
</code></pre></div></div>
<p>Best score인 28번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9982<br />
  Train Loss: 0.0061<br />
  Validation Accuracy: 0.9977<br />
  Validation Loss: 0.0077<br /></p>

<h3 id="feature-map-시각화-5">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_vgg16_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer3.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vgg16_layer4.png" alt="alt text" /><br /></p>

<p>사전 학습된 모델 그대로 가져왔으므로 Filter를 통과한 Feature Map은 동일하다.</p>

<h2 id="7-vgg-custom">(7) VGG Custom</h2>
<ul>
  <li>
    <p>VGG16 모델과 경량화 모델은 모두 Imagenet으로 사전학습된 모델이다. 해당 모델은 VGG16의 구조를 따라가되 직접 학습한 모델이며 총 3개의 block으로 이루어져있다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">vgg_custom</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">inputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>

    <span class="c1"># Block 1 - 16 filters
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>

    <span class="c1"># Block 2 - 32 filters
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>

    <span class="c1"># Block 3 - 64 filters
</span>    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>

    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="mi">512</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">outputs</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>

    <span class="n">model</span> <span class="o">=</span> <span class="n">models</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">model</span>
    
<span class="n">vgg_custom</span> <span class="o">=</span> <span class="n">vgg_custom</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">vgg_custom</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">vgg_custom</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="model-summary-6">Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer_1 (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d (Conv2D)</td>
      <td>(None, 224, 224, 16)</td>
      <td>448</td>
    </tr>
    <tr>
      <td>conv2d_1 (Conv2D)</td>
      <td>(None, 224, 224, 16)</td>
      <td>2,320</td>
    </tr>
    <tr>
      <td>max_pooling2d (MaxPooling2D)</td>
      <td>(None, 112, 112, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_2 (Conv2D)</td>
      <td>(None, 112, 112, 32)</td>
      <td>4,640</td>
    </tr>
    <tr>
      <td>conv2d_3 (Conv2D)</td>
      <td>(None, 112, 112, 32)</td>
      <td>9,248</td>
    </tr>
    <tr>
      <td>max_pooling2d_1 (MaxPooling2D)</td>
      <td>(None, 56, 56, 32)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_4 (Conv2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>18,496</td>
    </tr>
    <tr>
      <td>conv2d_5 (Conv2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>36,928</td>
    </tr>
    <tr>
      <td>conv2d_6 (Conv2D)</td>
      <td>(None, 56, 56, 64)</td>
      <td>36,928</td>
    </tr>
    <tr>
      <td>max_pooling2d_2 (MaxPooling2D)</td>
      <td>(None, 28, 28, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>global_average_pooling2d_4 (GlobalAveragePooling2D)</td>
      <td>(None, 64)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_8 (Dense)</td>
      <td>(None, 512)</td>
      <td>33,280</td>
    </tr>
    <tr>
      <td>dropout_4 (Dropout)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_9 (Dense)</td>
      <td>(None, 5)</td>
      <td>2,565</td>
    </tr>
  </tbody>
</table>

<p>Total params: 144,853 (565.83 KB)<br />
  Trainable params: 144,853 (565.83 KB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation-6">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_vggcustom_accuracy.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vggcustom_loss.png" alt="alt text" /><br /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 41.
</code></pre></div></div>
<p>Best score인 41번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9986<br />
  Train Loss: 0.0051<br />
  Validation Accuracy: 0.9988<br />
  Validation Loss: 0.0042<br /></p>

<h3 id="feature-map-시각화-6">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_vggcustom_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vggcustom_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_vggcustom_layer3.png" alt="alt text" /><br /></p>

<p>각 블럭의 1층 Feature Map만 시각화하였다.</p>

<h3 id="모델-비교-2">모델 비교</h3>

<table>
  <thead>
    <tr>
      <th>Model</th>
      <th>Parameter</th>
      <th>Validation Accuracy</th>
      <th>Validation Loss</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>VGG16</td>
      <td>14,979,909</td>
      <td>0.9979</td>
      <td>0.0099</td>
    </tr>
    <tr>
      <td>VGG 경량화</td>
      <td>7,900,485</td>
      <td>0.9977</td>
      <td>0.0077</td>
    </tr>
    <tr>
      <td>VGG Custom</td>
      <td><strong>144,853</strong></td>
      <td><strong>0.9988</strong></td>
      <td><strong>0.0042</strong></td>
    </tr>
  </tbody>
</table>

<p>Parameter 수는 각 VGG16 모델 대비 99.03(%) 경량화하였으며 VGG 경량화 모델 대비 98.16(%)경량화 되었다. Accuracy와 Loss를 보았을 때, 성능차이는 VGG16 Custom 모델이 제일 높은 성능을 보여준다.</p>

<h1 id="4-모델별-일반화-성능비교">4. 모델별 일반화 성능비교</h1>

<p>  각 학습한 모델들을 <code class="language-plaintext highlighter-rouge">.h5</code>형태로 저장하였으며 일반화 성능과 추론 속도를 보기 위해 기존의 데이터를 가공하여 사용해보았다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">raw_test_ds</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">preprocessing</span><span class="p">.</span><span class="n">image_dataset_from_directory</span><span class="p">(</span>
    <span class="n">test_fpath</span><span class="p">,</span>
    <span class="n">image_size</span><span class="o">=</span><span class="n">img_size</span><span class="p">,</span>
    <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span>
    <span class="n">shuffle</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
    <span class="n">label_mode</span><span class="o">=</span><span class="s">'categorical'</span>
<span class="p">)</span>

<span class="n">class_names</span> <span class="o">=</span> <span class="n">raw_test_ds</span><span class="p">.</span><span class="n">class_names</span>

<span class="n">data_augmentation</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Sequential</span><span class="p">([</span>
    <span class="n">layers</span><span class="p">.</span><span class="n">RandomFlip</span><span class="p">(</span><span class="s">"horizontal"</span><span class="p">),</span> <span class="c1"># 수평 뒤집기
</span>    <span class="n">layers</span><span class="p">.</span><span class="n">RandomRotation</span><span class="p">(</span><span class="mf">0.1</span><span class="p">),</span> <span class="c1"># ±10% 회전
</span>    <span class="n">layers</span><span class="p">.</span><span class="n">RandomZoom</span><span class="p">(</span><span class="mf">0.1</span><span class="p">),</span> <span class="c1"># ±10% 확대/축소
</span>    <span class="n">layers</span><span class="p">.</span><span class="n">RandomTranslation</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">),</span> <span class="c1"># ±10% 가로/세로 이동
</span>    <span class="n">layers</span><span class="p">.</span><span class="n">RandomContrast</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="c1"># 명암 변화
</span><span class="p">])</span>

<span class="n">normalization_layer</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Rescaling</span><span class="p">(</span><span class="mf">1.</span><span class="o">/</span><span class="mi">255</span><span class="p">)</span>
<span class="n">test_ds</span> <span class="o">=</span> <span class="n">raw_test_ds</span><span class="p">.</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="p">(</span><span class="n">normalization_layer</span><span class="p">(</span><span class="n">data_augmentation</span><span class="p">(</span><span class="n">x</span><span class="p">)),</span> <span class="n">y</span><span class="p">))</span>

<span class="n">AUTOTUNE</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">AUTOTUNE</span>
<span class="n">test_ds</span> <span class="o">=</span> <span class="n">test_ds</span><span class="p">.</span><span class="n">prefetch</span><span class="p">(</span><span class="n">buffer_size</span><span class="o">=</span><span class="n">AUTOTUNE</span><span class="p">)</span>
</code></pre></div></div>

<p>  추론 속도는 정확한 값으로 측정하기 위해서 FLOPs로 대체하였다. FLOPs란 FLoating point Operations의 약자로 부동소수점 연산을 의미하며 주로 모델의 계산 복잡성을 측정하는데 사용된다. Device Performance는 대개 FLOPS(FLoating point Operations Per Second)로 측정하고 있으며 추론 시간은 Device의 성능이 높을수록 계산해야하는 FLOPs가 낮을수록 추론시간은 짧아진다. CNN 계열 모델의 이론적 추론시간은 아래와 같다.<br />
\(Inference\,Time = \frac{\sum_{l=1}^{L}FLOPs_l}{Device\,Performance\,(FLOPs/sec)}\)
<br />
  일반적으로 Convolution Lyaer의 FLOPs의 계산은 아래와 같이 계산된다.<br /></p>

<p>$C_{in}$: 입력 채널 수<br />
$K$: 커널크기<br />
$H_{out}, W_{out}$: Feature Map의 Height, Width<br />
$C_{out}$: 출력 채널 수<br /></p>

<p>\(FLOPs_{conv} = 2 \times C_{in} \times K^2 \times H_{out} \times W_{out} \times C_{out}\)
<br /></p>

<p>  여기서 Layer를 제거하거나 Filter의 개수를 줄이게 되면 이후 Layer에서의 $C_{in}$값 또한 감소한다. 따라서 연산량이 전반적으로 줄어들게 되며 상당한 계산량 절감 효과를 기대할 수 있다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_flops</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">concrete</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">function</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">model</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
        <span class="n">concrete_func</span> <span class="o">=</span> <span class="n">concrete</span><span class="p">.</span><span class="n">get_concrete_function</span><span class="p">(</span>
            <span class="n">tf</span><span class="p">.</span><span class="n">TensorSpec</span><span class="p">([</span><span class="n">batch_size</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">224</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">tf</span><span class="p">.</span><span class="n">float32</span><span class="p">))</span>

        <span class="n">frozen_func</span> <span class="o">=</span> <span class="n">convert_to_constants</span><span class="p">.</span><span class="n">convert_variables_to_constants_v2</span><span class="p">(</span><span class="n">concrete_func</span><span class="p">)</span>
        <span class="n">graph_def</span> <span class="o">=</span> <span class="n">frozen_func</span><span class="p">.</span><span class="n">graph</span><span class="p">.</span><span class="n">as_graph_def</span><span class="p">()</span>

        <span class="k">with</span> <span class="n">tf</span><span class="p">.</span><span class="n">Graph</span><span class="p">().</span><span class="n">as_default</span><span class="p">()</span> <span class="k">as</span> <span class="n">graph</span><span class="p">:</span>
            <span class="n">tf</span><span class="p">.</span><span class="n">graph_util</span><span class="p">.</span><span class="n">import_graph_def</span><span class="p">(</span><span class="n">graph_def</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
            <span class="n">run_meta</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">compat</span><span class="p">.</span><span class="n">v1</span><span class="p">.</span><span class="n">RunMetadata</span><span class="p">()</span>
            <span class="n">opts</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">compat</span><span class="p">.</span><span class="n">v1</span><span class="p">.</span><span class="n">profiler</span><span class="p">.</span><span class="n">ProfileOptionBuilder</span><span class="p">.</span><span class="n">float_operation</span><span class="p">()</span>
            <span class="n">flops</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">compat</span><span class="p">.</span><span class="n">v1</span><span class="p">.</span><span class="n">profiler</span><span class="p">.</span><span class="n">profile</span><span class="p">(</span><span class="n">graph</span><span class="o">=</span><span class="n">graph</span><span class="p">,</span> <span class="n">run_meta</span><span class="o">=</span><span class="n">run_meta</span><span class="p">,</span> <span class="n">cmd</span><span class="o">=</span><span class="s">'op'</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="n">opts</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">flops</span><span class="p">.</span><span class="n">total_float_ops</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"FLOPs 계산 실패: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">None</span>
</code></pre></div></div>

<h2 id="1-cnn-1">(1) CNN</h2>
<ul>
  <li>
    <p>총 필터 수: 224개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 1,042,859,422 (약 1.04 GFLOPs)<br />
이미지 7,500장 : 약 7.82 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.7092</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_cnn_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.91</td>
          <td>0.55</td>
          <td>0.68</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.68</td>
          <td>0.90</td>
          <td>0.77</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.88</td>
          <td>0.96</td>
          <td>0.92</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.48</td>
          <td>0.60</td>
          <td>0.53</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.76</td>
          <td>0.53</td>
          <td>0.62</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.71</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.74</td>
          <td>0.71</td>
          <td>0.71</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.74</td>
          <td>0.71</td>
          <td>0.71</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="2-cnn-경량화-1">(2) CNN 경량화</h2>
<ul>
  <li>
    <p>총 필터 수: 24개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 7,551,694 (약 7.55 MFLOPs)<br />
이미지 7,500장 : 약 56.64 GFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.7456</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_cnnlight_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.85</td>
          <td>0.60</td>
          <td>0.70</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.67</td>
          <td>0.96</td>
          <td>0.79</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.97</td>
          <td>0.94</td>
          <td>0.95</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.54</td>
          <td>0.77</td>
          <td>0.63</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>1.00</td>
          <td>0.47</td>
          <td>0.64</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.75</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.80</td>
          <td>0.75</td>
          <td>0.74</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.80</td>
          <td>0.75</td>
          <td>0.74</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="3-googlenet-1">(3) GoogLeNet</h2>
<ul>
  <li>
    <p>총 필터 수: 5,808개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 3,179,339,598 (약 3.18 GFLOPs)<br />
이미지 7,500장 : 약 23.85 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.8675</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_googlenet_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.93</td>
          <td>0.69</td>
          <td>0.79</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.92</td>
          <td>0.98</td>
          <td>0.95</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.88</td>
          <td>0.99</td>
          <td>0.93</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.71</td>
          <td>0.91</td>
          <td>0.80</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.99</td>
          <td>0.76</td>
          <td>0.86</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.87</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.89</td>
          <td>0.87</td>
          <td>0.87</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.89</td>
          <td>0.87</td>
          <td>0.87</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="4-googlenet-경량화-1">(4) GoogLeNet 경량화</h2>
<ul>
  <li>
    <p>총 필터 수: 1,456개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 280,058,490 (약 0.28 GFLOPs)<br />
이미지 7,500장 : 약 2.10 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.9319</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_googlenetlight_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.91</td>
          <td>0.87</td>
          <td>0.89</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.97</td>
          <td>0.99</td>
          <td>0.98</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.98</td>
          <td>0.99</td>
          <td>0.98</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.83</td>
          <td>0.98</td>
          <td>0.90</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>1.00</td>
          <td>0.83</td>
          <td>0.91</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.93</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.94</td>
          <td>0.93</td>
          <td>0.93</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.94</td>
          <td>0.93</td>
          <td>0.93</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="5-vgg16-1">(5) VGG16</h2>
<ul>
  <li>
    <p>총 필터 수: 4,320개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 30,713,485,342 (약 30.71 GFLOPs)<br />
이미지 7,500장 : 약 226.30 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.9649</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_vgg16_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>1.00</td>
          <td>0.97</td>
          <td>0.98</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.88</td>
          <td>1.00</td>
          <td>0.94</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.97</td>
          <td>1.00</td>
          <td>0.99</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.99</td>
          <td>0.86</td>
          <td>0.92</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.99</td>
          <td>1.00</td>
          <td>1.00</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.96</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.97</td>
          <td>0.96</td>
          <td>0.96</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.97</td>
          <td>0.96</td>
          <td>0.96</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="6-vgg-경량화">(6) VGG 경량화</h2>
<ul>
  <li>
    <p>총 필터 수: 2,688개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 27,938,627,102 (약 27.94 GFLOPs)<br />
이미지 7,500장 : 약 290.54 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.9227</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_vgglight_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>1.00</td>
          <td>0.89</td>
          <td>0.94</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.78</td>
          <td>1.00</td>
          <td>0.88</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.99</td>
          <td>1.00</td>
          <td>0.99</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.99</td>
          <td>0.72</td>
          <td>0.83</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.93</td>
          <td>1.00</td>
          <td>0.96</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.92</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.94</td>
          <td>0.92</td>
          <td>0.92</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.94</td>
          <td>0.92</td>
          <td>0.92</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="7-vgg-custom-1">(7) VGG Custom</h2>
<ul>
  <li>
    <p>총 필터 수: 288개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 1,203,943,966 (약 1.20 GFLOPs)<br />
이미지 7,500장 : 약 9.02 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.9909</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_vggcustom_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.97</td>
          <td>0.99</td>
          <td>0.98</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>1.00</td>
          <td>1.00</td>
          <td>1.00</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>1.00</td>
          <td>1.00</td>
          <td>1.00</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>1.00</td>
          <td>0.97</td>
          <td>0.98</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.99</td>
          <td>1.00</td>
          <td>0.99</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.99</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.99</td>
          <td>0.99</td>
          <td>0.99</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.99</td>
          <td>0.99</td>
          <td>0.99</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="8-성능비교">(8) 성능비교</h2>

<table>
  <thead>
    <tr>
      <th>모델 이름</th>
      <th>Accuracy</th>
      <th>Macro Precision</th>
      <th>Macro Recall</th>
      <th>Macro F1-score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>CNN</td>
      <td>0.71</td>
      <td>0.74</td>
      <td>0.71</td>
      <td>0.71</td>
    </tr>
    <tr>
      <td>CNN Light</td>
      <td>0.75</td>
      <td>0.80</td>
      <td>0.75</td>
      <td>0.74</td>
    </tr>
    <tr>
      <td>GoogLeNet</td>
      <td>0.87</td>
      <td>0.89</td>
      <td>0.87</td>
      <td>0.87</td>
    </tr>
    <tr>
      <td>GoogLeNet Light</td>
      <td>0.93</td>
      <td>0.94</td>
      <td>0.93</td>
      <td>0.93</td>
    </tr>
    <tr>
      <td>VGG16</td>
      <td>0.96</td>
      <td>0.97</td>
      <td>0.96</td>
      <td>0.96</td>
    </tr>
    <tr>
      <td>VGG Light</td>
      <td>0.92</td>
      <td>0.94</td>
      <td>0.92</td>
      <td>0.92</td>
    </tr>
    <tr>
      <td>VGG Custom</td>
      <td>0.99</td>
      <td>0.99</td>
      <td>0.99</td>
      <td>0.99</td>
    </tr>
  </tbody>
</table>

<p><img src="/assets/images/cnnproject_summary_accuracy.png" alt="alt text" /><br />
Filter의 개수를 줄이거나 Layer를 제거한 모델들의 일반화 성능이 더욱 높게 나왔다.<br /></p>

<p><img src="/assets/images/cnnproject_summary_flops.png" alt="alt text" /><br />
  위 그림은 FLOPs vs Test Accuracy 그래프이다. 해당 그래프는 왼쪽 아래로 갈수록 성능은 낮고 계산량은 많으며 오른쪽 위로 갈수록 성능은 높고 계산량은 적은 모델임을 의미한다.<br />
  ‘Rice Image Dataset’을 기준으로 평가했을 때, VGG Custom 모델이 가장 높은 정확도와 비교적 낮은 FLOPs를 동시에 달성하며 최고의 효율을 보이는 모델로 판단된다. GoogLeNet Light 역시 높은 정확도와 상대적으로 낮은 연산량으로 효율적인 구조임을 확인할 수 있다.
  반면 CNN Light는 FLOPs가 약 0.056TFLOPs 수준으로 가장 낮은 연산량을 보였지만 Test Accuracy가 0.9 미만으로 일반화 성능이 부족하다고 판단되어 실사용에는 적합하지 않은 모델로 분류하였다.<br />
<img src="/assets/images/cnnproject_summary_accpertflops.png" alt="alt text" /><br />
  위 그림은 각 모델의 Accuracy / TFLOPs를 시각화한 그래프이다. 이를 통해 CNN Light의 계산 효율이 매우 높음을 확인할 수 있지만 정확도의 뒷받침이 없을 경우 효율성만으로는 모델 선택이 어렵다는 점을 보여준다.<br />
  하지만 CNN Light는 Validation Accuracy 0.9970, Validation Loss 0.0108로 학습 성능은 매우 우수하게 나타났다. 따라서 ‘Rice Image Dataset’과 같이 이미지 전처리가 잘 되어 있고 과적합에 대한 제약이 비교적 적은 환경에서는 극단적으로 연산량을 줄인 모델도 시도해볼 수 있다고 판단된다.<br />
<img src="/assets/images/cnnproject_summary_filter.png" alt="alt text" /><br />
  위 그림은 Filter 수와 정확도의 관계를 분석한 Filter vs Test Accuracy 그래프이다. 해당 그래프에서는 Filter 수가 많다고 해서 반드시 성능이 좋은 것은 아님을 알 수 있다.<br />
  실제로 VGG Custom, GoogLeNet Light 등은 비교적 적은 수의 필터로도 높은 정확도를 달성하였으며 오히려 필터 수가 적은 모델들이 더 뛰어난 일반화 성능을 보이기도 했다.<br />
  <a href="#4-backpropagation-관점">서론</a>에서 언급한 바와 같이 GoogLeNet처럼 Filter 개수가 지나치게 많은 구조는 학습이 불안정해지거나 정보가 소실되어 학습되지 않는 형상이 발생할 수 있다. 특히 ‘Rice Image Dataset’처럼 비교적 단순한 이미지의 경우 이러한 문제는 더욱 뚜렷하게 나타날 수 있으므로 주의가 필요하다.</p>

<h1 id="5-결론">5. 결론</h1>
<p>  본 프로젝트에서는 모델 구조를 단순히 깊게 설계하거나 필터 수를 늘리는 방식보다는 학습에 실질적으로 기여하지 않는 구조를 제거하는 경량화 전략이 오히려 더 나은 성능을 낼 수 있음을 확인하였다.<br />
  Feature Map을 시각적으로 확인한 결과, 일부 모델에서는 이미지가 비교적 단순하고 전처리가 잘 되어 있음에도 불구하고 의미 있는 특성 추출에 기여하지 않는 필터들이 다수 존재하였다. 따라서 필터 수를 줄이거나 레이어를 삭제하는 방식으로 모델을 경량화한 결과, 실제 테스트 성능에서 오히려 일반화가 더 잘 되는 현상을 확인할 수 있었다.<br />
  실제로 ‘<a href="#4-모델별-일반화-성능비교">4. 모델별 일반화 성능 비교</a>‘에서 확인할 수 있듯이 경량화된 모델들이 오히려 더 우수한 성능을 보이는 경우가 많았으며 이는 필터 수가 많다고 반드시 좋은 모델이 되는 것은 아님을 보여주는 결과였다.
  이를 바탕으로 CNN Light의 압도적으로 낮은 계산량과 VGG Custom의 뛰어난 일반화 성능이라는 각 모델의 장점을 결합한 최종 개선 모델을 설계하였다. 이 모델은 CNN Light처럼 8 → 16 필터 구조를 유지하면서 VGG Custom과 같이 두 번째 풀링 이전에 Convolution 층을 추가하여 표현력을 강화하였고 Global Average Pooling과 Dropout을 적용하여 경량화와 성능 모두를 고려하였다.</p>

<h2 id="1-최종-모델">(1) 최종 모델</h2>
<ul>
  <li>
    <p>CNN Light와 같이 필터의 개수를 8 → 16으로 제한하여 CNN Light의 극단적으로 적은 계산량을 가져가고 VGG Custom과 같이 두 번째 풀링 이전에 Convolution 층을 추가하여 표현력을 확보하였다. 또한 Global Average Pooling과 Dropout을 적용하여 경량화와 성능 모두를 고려한 모델이다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">final_model</span><span class="p">(</span><span class="n">input_shape</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
    <span class="n">inputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Input</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="n">input_shape</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">inputs</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Conv2D</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">3</span><span class="p">),</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s">'same'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">MaxPooling2D</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">),</span> <span class="n">strides</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">2</span><span class="p">))(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">GlobalAveragePooling2D</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Flatten</span><span class="p">()(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="mi">512</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">x</span> <span class="o">=</span> <span class="n">layers</span><span class="p">.</span><span class="n">Dropout</span><span class="p">(</span><span class="mf">0.3</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">outputs</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">layers</span><span class="p">.</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'softmax'</span><span class="p">)(</span><span class="n">x</span><span class="p">)</span>
    <span class="n">model</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">keras</span><span class="p">.</span><span class="n">Model</span><span class="p">(</span><span class="n">inputs</span><span class="p">,</span> <span class="n">outputs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">model</span>

<span class="n">final_model</span> <span class="o">=</span> <span class="n">final_model</span><span class="p">(</span><span class="n">input_shape</span><span class="o">=</span><span class="n">img_size</span> <span class="o">+</span> <span class="p">(</span><span class="mi">3</span><span class="p">,),</span> <span class="n">num_classes</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">final_model</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">optimizer</span><span class="o">=</span><span class="s">'adam'</span><span class="p">,</span>
                  <span class="n">loss</span><span class="o">=</span><span class="s">'categorical_crossentropy'</span><span class="p">,</span>
                  <span class="n">metrics</span><span class="o">=</span><span class="p">[</span><span class="s">'accuracy'</span><span class="p">])</span>
<span class="n">final_model</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="final-model-summary">Final Model Summary</h3>

<table>
  <thead>
    <tr>
      <th>Layer (type)</th>
      <th>Output Shape</th>
      <th>Param #</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>input_layer_10 (InputLayer)</td>
      <td>(None, 224, 224, 3)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_32 (Conv2D)</td>
      <td>(None, 224, 224, 8)</td>
      <td>224</td>
    </tr>
    <tr>
      <td>max_pooling2d_20 (MaxPooling2D)</td>
      <td>(None, 112, 112, 8)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>conv2d_33 (Conv2D)</td>
      <td>(None, 112, 112, 16)</td>
      <td>1,168</td>
    </tr>
    <tr>
      <td>conv2d_34 (Conv2D)</td>
      <td>(None, 112, 112, 16)</td>
      <td>2,320</td>
    </tr>
    <tr>
      <td>conv2d_35 (Conv2D)</td>
      <td>(None, 112, 112, 16)</td>
      <td>2,320</td>
    </tr>
    <tr>
      <td>max_pooling2d_21 (MaxPooling2D)</td>
      <td>(None, 56, 56, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>global_average_pooling2d_6 (GlobalAveragePooling2D)</td>
      <td>(None, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>flatten_10 (Flatten)</td>
      <td>(None, 16)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_20 (Dense)</td>
      <td>(None, 512)</td>
      <td>8,704</td>
    </tr>
    <tr>
      <td>dropout_3 (Dropout)</td>
      <td>(None, 512)</td>
      <td>0</td>
    </tr>
    <tr>
      <td>dense_21 (Dense)</td>
      <td>(None, 5)</td>
      <td>2,565</td>
    </tr>
  </tbody>
</table>

<p>Total params: 17,301 (67.58 KB)<br />
  Trainable params: 17,301 (67.58 KB)<br />
  Non-trainable params: 0 (0.00 B)<br /></p>

<h3 id="model-evaluation-7">Model Evaluation</h3>

<p><img src="/assets/images/cnnproject_final_accuracy.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_final_loss.png" alt="alt text" /><br /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  Restoring model weights from the end of the best epoch: 34.
</code></pre></div></div>
<p>Best score인 34번 째 epoch의 evaluation은 아래와 같다.<br />
  Train Accuracy: 0.9899<br />
  Train Loss: 0.0310<br />
  Validation Accuracy: 0.9897<br />
  Validation Loss: 0.0305<br /></p>

<h3 id="feature-map-시각화-7">Feature Map 시각화</h3>

<p><img src="/assets/images/cnnproject_final_layer1.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_final_layer2.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_final_layer3.png" alt="alt text" /><br />
  <img src="/assets/images/cnnproject_final_layer4.png" alt="alt text" /><br /></p>

<h3 id="final-model-일반화-성능">Final Model 일반화 성능</h3>

<ul>
  <li>
    <p>총 필터 수: 56개</p>
  </li>
  <li>
    <p>이미지 1장 당 FLOPs : 167,860,766 (약 0.17 GFLOPs)<br />
이미지 7,500장 : 약 1.26 TFLOPs</p>
  </li>
  <li>
    <p>Test Accuracy : 0.9533</p>
  </li>
  <li>
    <p>Confusion Matrix<br />
<img src="/assets/images/cnnproject_final_confusionmatrix.png" alt="alt text" /><br /></p>

    <table>
      <thead>
        <tr>
          <th>Class</th>
          <th>Precision</th>
          <th>Recall</th>
          <th>F1-Score</th>
          <th>Support</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>Arborio</strong></td>
          <td>0.91</td>
          <td>0.97</td>
          <td>0.94</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Basmati</strong></td>
          <td>0.98</td>
          <td>0.93</td>
          <td>0.96</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Ipsala</strong></td>
          <td>0.99</td>
          <td>1.00</td>
          <td>0.99</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Jasmine</strong></td>
          <td>0.93</td>
          <td>0.92</td>
          <td>0.92</td>
          <td>1500</td>
        </tr>
        <tr>
          <td><strong>Karacadag</strong></td>
          <td>0.96</td>
          <td>0.95</td>
          <td>0.95</td>
          <td>1500</td>
        </tr>
        <tr>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
          <td> </td>
        </tr>
        <tr>
          <td><strong>Accuracy</strong></td>
          <td> </td>
          <td> </td>
          <td><strong>0.95</strong></td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Macro Avg</strong></td>
          <td>0.95</td>
          <td>0.95</td>
          <td>0.95</td>
          <td>7500</td>
        </tr>
        <tr>
          <td><strong>Weighted Avg</strong></td>
          <td>0.95</td>
          <td>0.95</td>
          <td>0.95</td>
          <td>7500</td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>
    <p>Final Model은 Test Accuracy 0.9533, 필터 수 56개, 최종 연산량 1.26 TFLOPs로 GoogLeNet Light보다 더 높은 정확도를 유지하면서도 계산량은 더욱 낮은 수준을 달성하였다.</p>
  </li>
</ul>

<h2 id="2-최종-성능-비교표">(2) 최종 성능 비교표</h2>

<p><img src="/assets/images/cnnproject_final_summary.png" alt="alt text" /><br />
<img src="/assets/images/cnnproject_final_flops.png" alt="alt text" /><br />
<img src="/assets/images/cnnproject_final_filter.png" alt="alt text" /><br /></p>

<p>  위의 시각화된 성능 비교 그래프에서 확인할 수 있듯이 Final Model은 정확도와 효율성 측명 모두에서 우상단에 위치한다. 이는 단순히 계산량만 줄인 것이 아닌 효과적인 구조 설계를 통해 실질적인 성능 개선까지 달성한 사례라 할 수 있다.<br />
  CNN Light와 같이 극단적으로 연산량을 줄인 모델과 비교해보면 Final Model은 약간의 계산량을 추가함으로써 현실적인 성능 수준을 확보한 균형 잡힌 모델로 평가된다. 이는 경량화 모델 설계시 성능-연산량의 균형이 중요하다는 점을 잘 보여준다.<br /></p>

<h2 id="3-연구-의의와-활용-가능성">(3) 연구 의의와 활용 가능성</h2>
<p>  본 프로젝트는 Feature Map을 기반으로 시각적으로 분석하여 의미없는 필터를 제거하는 방식으로 모델 경량화를 시도하였다. 이는 기존 연구에서 다뤄지지 않았던 접근 방법으로 다양한 CNN 구조를 실험적으로 비교하고 FLOPs 계산량 및 필터 수와의 관계를 장량적으로 분석하였다. 이로써 단순한 구조 최적화만으로도 높은 성능을 유지하면서 연산 효율성을 극대화할 수 있음을 입증하였다.<br />
  최종적으로 제안된 Final Model은 낮은 연산량에도 불구하고 95% 이상의 정확도를 유지하며 성능과 효율의 균형을 모두 고려한 모델 설계가 가능함을 실증적으로 확인하였다. 이는 향후 모바일 디바이스나 엣지 컴퓨팅 환경처럼 제한된 연산 자원 내에서도 실용적인 딥러닝 모델을 구현한느 데에 참고할 수 있는 유의미한 사례가 될 수 있다.<br /></p>

<h1 id="6-reference">6. Reference</h1>
<ol>
  <li>
    <p>Koklu, Murat. “Rice Image Dataset.” Kaggle. Accessed March 26, 2025. https://www.kaggle.com/datasets/muratkokludataset/rice-image-dataset/data.</p>
  </li>
  <li>
    <p>Joshi, Shardul. “Rice Classification Using VGG16 - 99% Accuracy.” Kaggle, September 8, 2022. https://www.kaggle.com/code/sharduljoshi29/rice-classification-using-vgg16-99-accuracy.</p>
  </li>
  <li>
    <p>최진영. “산업인공지능 수업자료”. 아주대학교 산업공학과. 2024.</p>
  </li>
</ol>]]></content><author><name>Buyoung Kim</name></author><category term="Project" /><category term="KTB" /><category term="python" /><category term="langchain" /><category term="fastapi" /><summary type="html"><![CDATA[1. 서론   최근 다양한 CNN(Convolutional Neural Network) 기반의 이미지 분류 모델들이 제안되며 이미지 인식 분야에서 뛰어난 성능을 보이고 있다. 하지만 이러한 모델들은 구조의 복잡성이나 파라미터 수에 따라 연산 비용과 메모리 사용량에 큰 차이를 보이며, 특히 데이터셋의 특성에 따라 성능 및 효율성이 달라질 수 있다.   실제 응용 환경에서는 모델의 경량화 또한 중요한 과제로 떠오르고 있다. 모바일 기기, 임베디드 시스템, 자동화 기계 등에서는 모델의 정확도뿐만 아니라 처리 속도와 자원 효율성이 중요한 요소로 작용하기 때문이다.   따라서 본 프로젝트에서는 ‘Rice Image Dataset’을 활용하여 여러 CNN 기반 모델들이 해당 데이터셋에서 어떤 성능을 보이는지 비교하고 모델별 특징 및 효율성을 분석하고자 한다. 특히, 이미지 분류 과정에서 생성되는 Feature map을 시각화함으로써 각 모델이 어떤 방식으로 이미지를 인식하고 구분하는지 직관적으로 이해하고자 하였다.   이를 통해 더 이상 특징을 제대로 추출하지 못 하는 Layer를 일부 제거하거나 Filter의 수를 줄임 성능저하 없이 예측 효율성을 개선할 수 있는 가능성도 살펴보고자한다. 이러한 분석을 통해 단순 정확도 비교를 넘어서 실제 응용에 적합한 효율적인 모델을 선정하기 위한 방법을 살펴보고자 한다.]]></summary></entry><entry><title type="html">Application Model</title><link href="https://thplus.github.io/today%20i%20learn/7th%20week/application_model/" rel="alternate" type="text/html" title="Application Model" /><published>2025-03-11T00:00:00+00:00</published><updated>2025-03-11T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/7th%20week/application_model</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/7th%20week/application_model/"><![CDATA[<h2 id="한-줄-정리">한 줄 정리</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>한 줄 정리</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="#word-embedding">Word Embedding</a></td>
      <td>단어를 벡터화 한 것으로 비슷한 의미의 단어들을 서로 가까운 벡터 공간에 위치하게 하여 문맥을 파악할 수 있도록 한 것</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#generative-adversarial-netsgans">GANs</a></td>
      <td>두 신경망인 생성자와 판별자를 경쟁적으로 학습시켜 뛰어난 가짜 데이터를 만들기 위한 모델</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#transformer-model">Transformer Model</a></td>
      <td>입력을 병렬로 처리하여 각 단어의 관계를 빠르고 정확하게 처리할 수 있도록 만든 모델</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#self-attention-mechanism">Attention Mechanism</a></td>
      <td>각 입력을 동일하게 처리하지 않고 다른 요소와의 관계 등을 고려하여 가중치를 부여해 중요한 부분에 집종하도록 만든 알고리즘</td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="text-cnn">Text CNN</h2>

<ul>
  <li>
    <p>Text CNN은 text 데이터를 처리하고 분류하기 위해 CNN을 사용하는 모델을 말한다. CNN은 주로 이미지 데이터를 처리하는데 사용되지만 텍스트 데이터 처리에도 성능이 좋다는 것이 Yoon Kim 박사의 논문을 통해 공개 되었다.</p>
  </li>
  <li>
    <p>일반적으로 문장을 Word Embedding 벡터로 변환한 후 CNN 입력으로 사용하게 된다.</p>
  </li>
  <li>
    <p>텍스트 데이터를 임베딩한 후 CNN을 사용해 분류작업을 수행하는 것이 일반적인 진행 순서이다.<br /></p>

    <p><img src="/assets/images/textcnn.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="word-embedding">Word Embedding</h3>

<ul>
  <li>Word Embedding은 단어를 벡터로 표현하는 방법으로 단어를 밀집 표현으로 변환하는 것으로 비슷한 의미의 단어들은 벡터 공간에서 가깝게 위치한다.</li>
</ul>

<h4 id="one-hot-encoding의-문제점">One-Hot Encoding의 문제점</h4>
<ul>
  <li>
    <p>One-Hot Encoding의 경우 Index 값만 1이고 나머지는 0으로 표현된다. 이런 벡터 혹은 행렬의 값 대부분이 0으로 표현되는 방법을 희소 표현(Sparse Representation)이라고 한다.</p>
  </li>
  <li>
    <p>이러한 희소 벡터의 문제점은 단어의 개수가 늘어나면 벡터의 차원이 한 없이 커진다. 예를 들어 10,000개의 단어가 있다면 벡터의 차원이 10,000개여야 한다. 인덱스에 해당되는 부분은 1이고 나머지는 0의 값을 가지는데, 이러한 벡터 표현은 공간적 낭비를 불러 일으킨다.</p>
  </li>
</ul>

<h4 id="dense-representation밀집-표현">Dense Representation(밀집 표현)</h4>
<ul>
  <li>
    <p>희소 표현과 반대되는 표현으로 밀집 표현이 있다. 밀집 표현은 벡터의 차원을 단어 집합의 크기로 상정하지 않고 사용자가 설정한 값으로 모든 단어의 벡터 표현의 차원을 맞춘다. 또한 이 과정에서 더 이상 0과 1만 가진 값이 아니라 실수 값을 가지게 된다.</p>
  </li>
  <li>
    <p>단어의 의미를 내포한 정보를 압축된 형태로 제공하여 다양한 자연어 처리 작업에서 더 효과적으로 사용된다.</p>

    <table>
      <thead>
        <tr>
          <th> </th>
          <th>희소 표현</th>
          <th>밀집 표현</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>벡터 차원</td>
          <td>어휘 전체 크기와 동일한 고차원 벡터</td>
          <td>일반적으로 낮은 차원으로 구성</td>
        </tr>
        <tr>
          <td>값의 분포</td>
          <td>해당 단어에 해당하는 한 위치만 1, 나머지는 0</td>
          <td>모든 차원이 의미 있는 값을 가지며 연속적인 실수 값으로 표현</td>
        </tr>
        <tr>
          <td>의미 반영</td>
          <td>단어 간의 유사성을 반영하지 못한 서로 다른 단어들은 서로 완전히 독립적인 벡터</td>
          <td>단어 간의 의미적, 문법적 유사성을 벡터 공간 내의 거리나 방향으로 반영할 수 있음</td>
        </tr>
        <tr>
          <td>효율성</td>
          <td>대부분의 값이 0이기 때문에 메모리 비효율적일 수 있음</td>
          <td>저차원 벡터 사용으로 메모리와 계산 효율성이 높음</td>
        </tr>
      </tbody>
    </table>

    <p><img src="/assets/images/wordembedding.png" alt="alt text" /><br /></p>
  </li>
</ul>

<h2 id="generative-adversarial-netsgans">Generative Adversarial Nets(GANs)</h2>

<ul>
  <li>
    <p>두 신경망이 경쟁적으로 학습하여 하나는 데이터를 생성하고 다른 하나는 이를 판별하며 서로의 성능을 개선하는 딥러닝 모델</p>
  </li>
  <li>
    <p>2014년 Ian J. Goodfellow 등이 발표한 논문 ‘Generative Adversarial Nets’에서 제안되어 해당 논문에서는 지폐 위조범(Generator)과 경찰(Discriminator)에 비유하였다.</p>
  </li>
  <li>
    <p>사람이 인공지능을 지도학습할 필요가 없이 기계 스스로 학습할 수 있는 길을 열었다는 점에서 뜨거운 반응을 얻었으며 이미지, 음성 신호 및 자연어 등의 다양한 분야에서 데이터를 새로 생성하거나 재구성할 수 있다.</p>

    <p><img src="/assets/images/gans_img.png" alt="alt text" /></p>
  </li>
  <li>
    <p>Generator는 임의의 벡터를 입력 받아 가짜 데이터를 만들어 반별자 네트워크를 속이도록 훈련</p>
  </li>
  <li>
    <p>Discriminator는 실제 학습 데이터와 Generator가 만든 가짜 데이터를 입력으로 받아 훈련 세트에서 온 데이터인지 생성자 네트워크가 만든 데이터인지 판별하는 기준을 설정하면서 생성자의 능력 향상에 적응해간다.</p>
  </li>
</ul>

<h3 id="gans-작동원리">GANs 작동원리</h3>

<ul>
  <li>
    <p>Discriminator 네트워크는 전달된 이미지가 실제 이미지인지 가짜 이미지인지를 판별할 수 있는 일반적인 Convolution Network이다.</p>
  </li>
  <li>
    <p>일반 Convolution 분류기는 이미지를 입력 받아 확률을 예측하기 위해 Maxpooling과 같은 기술을 사용하여 다운 샘플링하는 반면, Generator는 랜덤 노이즈 벡터를 입력 받아 이미지를 만드는 업샘플링을 한다.</p>
  </li>
  <li>
    <p>수학적 표현<br />
  $min_G max_D V(D,G) = \mathbb{E_{x\sim p_{data}(x)}}[logD(x)] + \mathbb{E_{z\sim p _ {z}(z)}}[log(1-D(G(z)))]$ <br /></p>

    <ol>
      <li>
        <p>D가 아주 뛰어날 때, $x$가 실제로 원본에서 온 것이라면 $D(x) = 1$이 될 것이고 $G(z)$에서 온 것이라면 $D(G(z)) = 0$이 될 것이다.</p>
      </li>
      <li>
        <p>만약 $G(z)$가 완벽하게 위조한다면 $D(x) = \frac{1}{2}$이 될 것이다.</p>
      </li>
      <li>
        <p>D의 입장에서 V의 최대값은 0이 되며 G의 입장에서 최소값은 $-\infty$이다. <br />
 \(Max \Rightarrow log(1) + log(1) = 0\)
 \(Min \Rightarrow \lim _{x \rightarrow \infty} log(x) = -\infty\)</p>
      </li>
    </ol>
  </li>
</ul>

<h3 id="gans-활용">GANs 활용</h3>

<ul>
  <li>
    <p>실제 이미지를 학습해 가짜 이미지를 만드는데 활용되며 nvidia는 2017년 유명인 20만 명의 사진을 학습시켜 실존하지 않는 사람들의 사진을 무한대로 만들어낼 수 있는 기술을 선보이기도 하였다.</p>
  </li>
  <li>
    <p>영상 합성에도 사용되며 2017년 8월 미국 워싱턴대학교 연구진은 버락 오바마 전 미국 대통령의 가짜 영상을 만들어 화제가 되기도 하였다.</p>
  </li>
  <li>
    <p>MIT의 한 연구진은 수천 개의 이미지와 시를 쌍으로 학습시켜 AI가 이미지를 보고 시를 만들어내도록 하는 연구를 진행하기도 하였으며 30명의 영문학 전문가를 포함한 500명에게 AI가 만든 시와 인간이 쓴 시를 구별하도록 했는데, 이중 60%만 AI가 쓴 시를 선별해 냈다.</p>
  </li>
  <li>
    <p>위와 같은 예시로 불균형 데이터를 갖는 분류 문제에서 GANs를 이용하여 적은 수의 불균형 데이터를 학습하여 비슷한 유형의 불균형 데이터를 생성한다.</p>
  </li>
</ul>

<h3 id="gans의-단점">GANs의 단점</h3>

<ul>
  <li>
    <p>Model Collapsing : 이 현상은 학습 모델이 실제 데이터의 분포를 정확히 따라가지 못하고 다양성을 잃어버리는 현상</p>
  </li>
  <li>
    <p>Oscillation : G와 D가 수렴하지 않고 진동하는 모양새를 보이는 경우</p>
  </li>
  <li>
    <p>G와 D 사이의 Imbalance : 학습을 진행할 때, 처음에 D가 성능이 너무 좋아져서 오히려 G가 학습이 잘 되지 않는 문제</p>
  </li>
</ul>

<h2 id="transformer-model">Transformer Model</h2>
<ul>
  <li>
    <p>Transformer는 병렬 처리와 Attention 메커니즘을 통해 빠르고 정확한 학습이 가능한 자연어 처리 모델 아키텍처이다.</p>
  </li>
  <li>
    <p>Transformer Model은 Self-attention 메커니즘을 사용해 시퀀스 데이터를 병렬로 처리하고 단어 간의 관계를 빠르고 정확하게 학습할 수 있는 딥러닝 모델이다.</p>
  </li>
  <li>
    <p>Transformer Model은 2017년 구글의 논문 ‘Attention is All You Need’에서 처음 제안되었으며 그 이후 많은 NLP 작업에서 중요한 역할을 하고 있다.</p>

    <p><img src="/assets/images/transformer_model.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="self-attention-mechanism">Self-Attention Mechanism</h3>

<ul>
  <li>
    <p>Self-Attention은 시퀀스의 각 요소가 다른 모든 요소와의 관계를 고려하여 자신을 다시 계산하는 메커니즘이다.</p>
  </li>
  <li>
    <p>각 단어가 문장 내 다른 모든 단어와의 관계(의존성)를 파악하여 중요도에 따라 가중치를 부여하여 문맥 정보와 긴 거리 의존성을 효과적으로 캡처할 수 있다.</p>
  </li>
  <li>
    <p>Self Attention에서는 Query, Key, Value라는 3가지 변수가 존재한다.<br />
  <img src="/assets/images/self_attention_QKV.png" alt="alt text" /><br /></p>

    <p>Self Attention은 Query, Key, Value의 시작 값이 동일하여 ‘Self’가 앞에 붙었으며 중간 학습 weight에 의해 최종적인 Query, Key, Value가 달라지게 된다.</p>
  </li>
  <li>
    <p>Self Attention을 구하는 공식은 아래와 같다.<br />
  \(Attention(Q, K, V) = Softmax \left( \frac{QK^T}{\sqrt{d_k}} V \right)\)</p>

    <p><img src="/assets/images/selfattention_form.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="transformer-model의-구조">Transformer Model의 구조</h3>

<ul>
  <li>
    <p>Transformer Model의 구조는 기본적으로 인코더-디코더 구조를 가지고 있다.</p>

    <p><img src="/assets/images/transformer_ed.png" alt="alt text" /></p>
  </li>
</ul>

<h4 id="encoder-구조">Encoder 구조</h4>

<ul>
  <li>
    <p>트랜스포머에서 인코더는 입력 문장의 정보를 추출해 내부 표현을 생성한다. 인코더는 여러 개의 인코더 레이어로 구성되며 각 레이어는 아래의 순서로 이루어져있다.<br /></p>

    <blockquote class="prompt-info">
      <p><strong>Self-Attention → Add &amp; Norm → Feed Forward → Add &amp; Norm</strong></p>
    </blockquote>
  </li>
</ul>

<h4 id="decoder-구조">Decoder 구조</h4>

<ul>
  <li>
    <p>트랜스포머에서 디코더는 인코딩 된 표현을 받아 출력 시퀀스를 생성하는 역할을 한다. 디코더 또한 여러 개의 디코더 레이어로 구성되며 각 레이어는 아래의 순서로 이루어져있다.<br /></p>

    <blockquote class="prompt-info">
      <p><strong>Masked Self-Attention → Add &amp; Norm → Encoder-Decoder Attention → Add &amp; Norm → Feed Forward → Add &amp; Norm</strong></p>
    </blockquote>
  </li>
</ul>

<h2 id="오늘의-회고">오늘의 회고</h2>
<ul>
  <li>여태 학습하였던 것과 달리 여러 응용 모델을 학습하였다. 응용 모델의 가장 큰 주안점은 Transformer계열 모델이다. nvidia 블로그에 따르면 AI의 발전은 Transformer 이전과 이후로 또 한 번 나뉜다고 한다. Transformer 계열의 BERT계열 모델을 사용해 본 적이 있는데, Transformer의 기본적인 구조를 곱씹어보며 복습해야겠다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="7th Week" /><category term="python" /><category term="TensorFlow" /><category term="Pytorch" /><summary type="html"><![CDATA[한 줄 정리]]></summary></entry><entry><title type="html">Natural Language Processing</title><link href="https://thplus.github.io/today%20i%20learn/7th%20week/nlp/" rel="alternate" type="text/html" title="Natural Language Processing" /><published>2025-03-10T00:00:00+00:00</published><updated>2025-03-10T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/7th%20week/nlp</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/7th%20week/nlp/"><![CDATA[<h2 id="한-줄-정리">한 줄 정리</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>한 줄 정리</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="#natural-language-processing">NLP</a></td>
      <td>자연어 즉, 인간의 언어를 컴퓨터가 이해할 수 있도록 만든 알고리즘 혹은 모델</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#recurrent-neural-network">RNN</a></td>
      <td>뉴런이 정보를 처리한 후 자기 자신에게 되먹임 하는 cycle을 가진 모델로 과거의 정보를 기억하고 최신 데이터를 갱신하는 모델</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#long-short-term-memory">LSTM</a></td>
      <td>RNN의 기울기 소실을 해결하여 과거에서 현재까지 필요한 정보를 기억할 수 있도록 만든 모델로 RNN에 기억 셀과 게이트가 추가된 형태</td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="natural-language-processing">Natural Language Processing</h2>
<ul>
  <li>
    <p>NLP는 인간의 언어 현상을 컴퓨터와 같은 기계를 이용해서 묘사할 수 있도록 연구하고 이를 구현하는 인공지능 분야 중 하나이다. NLP는 언어의 문법적 구조를 분석하고 문장의 의미를 파악하며 맥락을 이해하는 등 다양한 언어적 과제를 처리한다.</p>
  </li>
  <li>
    <p>NLP의 목표는 컴퓨터가 사람의 언어를 이해하고 자연스럽게 소통하여 유용한 정보를 제공하는 것이다.</p>
  </li>
</ul>

<h3 id="nlp의-벡터화">NLP의 벡터화</h3>

<h4 id="bowbag-of-words">BoW(Bag of Words)</h4>
<ul>
  <li>
    <p>문서 내 단어의 등장 빈도수를 벡터로 표현하는 방법이다.</p>
  </li>
  <li>
    <p>BoW 모델에서는 각 문서에 포함된 단어들의 순서나 문법은 무시하고 단어들이 얼마나 등장했는지만 고려한다.<br />
<img src="/assets/images/bow.png" alt="alt text" /></p>
  </li>
  <li>
    <p>해당 단어들의 빈도로 벡터를 구성하여 텍스트를 비교할 수 있다.</p>
  </li>
</ul>

<h4 id="tf-idfterm-frequency-inverse-document-frequency">TF-IDF(Term Frequency-Inverse Document Frequency)</h4>
<ul>
  <li>단어의 빈도(Term Frequency)와 해당 단어가 다른 문서에 등정하는 빈도(Inverse Document Frequency)를 결합해 단어의 중요도를 측정하는 방법이다.</li>
</ul>

<h4 id="multinomial-naive-bayes다항-나이브-베이즈">Multinomial Naive Bayes(다항 나이브 베이즈)</h4>
<ul>
  <li>
    <p>다항 나이브 베이즈는 텍스트 분류와 같이 각 특징의 빈도에 기반해 카테고리를 예측하는 확률적 분류 알고리즘이다.</p>
  </li>
  <li>
    <p>Bayes’s Theorem(베이즈 정리) : 조건부 확률을 계산하는 공식으로 어떤 사건 A가 발생했을 때, 다른 사건 B가 발생할 확률은 아래와 같다.<br /></p>
  </li>
</ul>

\[P(A|B)=\frac{P(B|A)P(A)}{P(B)}\]

<ul>
  <li>
    <p>Bayes’s Theorem의 핵심은 서로 독립이라는 가정이며 한 특성의 값이 다른 특성의 값에 영향을 주지 않는다고 가정하고 확률을 계산한다</p>
  </li>
  <li>
    <p>Navie Bayes는 Bayes’s Theorem을 활용하여 특정 데이터가 특정 클래스에 속할 확률을 계산한다. 즉, 주어진 데이터에 특정 클래스가 나타날 확률을 계산하고 가장 높은 확률을 가진 클래스를 최종 분류 결과로 선택한다.</p>
  </li>
</ul>

<h3 id="nlp의-사용">NLP의 사용</h3>
<ol>
  <li>Library Import</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">nltk</span>  <span class="c1"># 자연어 처리를 위한 NLTK 라이브러리 임포트
</span><span class="kn">import</span> <span class="nn">os</span>  <span class="c1"># 운영체제 관련 기능을 사용하기 위한 os 모듈 임포트
</span><span class="kn">import</span> <span class="nn">shutil</span>  <span class="c1"># 파일 및 디렉터리 관리를 위한 shutil 모듈 임포트
</span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>  <span class="c1"># 수치 계산을 위한 NumPy 라이브러리 임포트
</span><span class="kn">import</span> <span class="nn">torch</span>  <span class="c1"># PyTorch 딥러닝 프레임워크 임포트
</span><span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="n">nn</span>  <span class="c1"># 신경망 모델을 위한 PyTorch의 nn 모듈 임포트
</span><span class="kn">import</span> <span class="nn">torch.optim</span> <span class="k">as</span> <span class="n">optim</span>  <span class="c1"># 최적화 함수(Optimizer)를 위한 PyTorch의 optim 모듈 임포트
</span><span class="kn">from</span> <span class="nn">torch.utils.data</span> <span class="kn">import</span> <span class="n">TensorDataset</span><span class="p">,</span> <span class="n">DataLoader</span>  <span class="c1"># 데이터 관리를 위한 PyTorch 모듈 임포트
</span><span class="kn">from</span> <span class="nn">nltk.corpus</span> <span class="kn">import</span> <span class="n">stopwords</span>  <span class="c1"># NLTK의 불용어(stopwords) 리스트 사용을 위한 임포트
</span><span class="kn">from</span> <span class="nn">nltk.stem</span> <span class="kn">import</span> <span class="n">WordNetLemmatizer</span>  <span class="c1"># 형태소 분석을 위한 WordNetLemmatizer 임포트
</span><span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">fetch_20newsgroups</span>  <span class="c1"># 뉴스 그룹 데이터셋 로드를 위한 임포트
</span><span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>  <span class="c1"># 학습 및 테스트 데이터 분할을 위한 모듈 임포트
</span></code></pre></div></div>

<ol>
  <li>NLTK 데이터 다운로드 및 설정</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 기존 NLTK 데이터 삭제 (손상된 데이터 문제 해결)
</span><span class="n">shutil</span><span class="p">.</span><span class="n">rmtree</span><span class="p">(</span><span class="s">'/root/nltk_data'</span><span class="p">,</span> <span class="n">ignore_errors</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>  <span class="c1"># 손상된 NLTK 데이터를 제거하여 오류 방지
</span>
<span class="c1"># NLTK 데이터 다운로드 및 경로 설정
</span><span class="n">nltk</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">"/root/nltk_data"</span><span class="p">)</span>  <span class="c1"># NLTK 데이터 저장 경로 설정
</span><span class="n">nltk</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="s">'punkt'</span><span class="p">)</span>  <span class="c1"># 단어 토큰화를 위한 Punkt 데이터 다운로드
</span><span class="n">nltk</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="s">'punkt_tab'</span><span class="p">)</span>  <span class="c1"># Punkt 관련 추가 리소스 다운로드
</span><span class="n">nltk</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="s">'stopwords'</span><span class="p">)</span>  <span class="c1"># 불용어(stopwords) 데이터 다운로드
</span><span class="n">nltk</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="s">'wordnet'</span><span class="p">)</span>  <span class="c1"># 형태소 분석을 위한 WordNet 데이터 다운로드
</span><span class="n">nltk</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="s">'omw-1.4'</span><span class="p">)</span>  <span class="c1"># WordNet 관련 추가 리소스 다운로드
</span></code></pre></div></div>

<ol>
  <li>뉴스 그룹 데이터셋 로드 및 텍스트 전처리</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 뉴스 그룹 데이터셋 로드 (스포츠와 우주 관련 카테고리 선택)
</span><span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s">'rec.sport.baseball'</span><span class="p">,</span> <span class="s">'sci.space'</span><span class="p">]</span>  <span class="c1"># 사용할 뉴스 그룹 카테고리 지정
</span><span class="n">newsgroups</span> <span class="o">=</span> <span class="n">fetch_20newsgroups</span><span class="p">(</span><span class="n">subset</span><span class="o">=</span><span class="s">'train'</span><span class="p">,</span> <span class="n">categories</span><span class="o">=</span><span class="n">categories</span><span class="p">)</span>  <span class="c1"># 지정된 카테고리의 뉴스 데이터셋 로드
</span><span class="n">texts</span> <span class="o">=</span> <span class="n">newsgroups</span><span class="p">.</span><span class="n">data</span>  <span class="c1"># 뉴스 데이터의 본문 텍스트 가져오기
</span><span class="n">labels</span> <span class="o">=</span> <span class="n">newsgroups</span><span class="p">.</span><span class="n">target</span>  <span class="c1"># 뉴스 데이터의 레이블 (0: 야구, 1: 우주)
</span>
<span class="c1"># 텍스트 전처리 함수 정의
</span><span class="k">def</span> <span class="nf">preprocess_text</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span>  <span class="c1"># 모든 문자를 소문자로 변환
</span>    <span class="n">tokens</span> <span class="o">=</span> <span class="n">nltk</span><span class="p">.</span><span class="n">word_tokenize</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>  <span class="c1"># 문장을 단어 단위로 토큰화
</span>    <span class="n">stop_words</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="n">stopwords</span><span class="p">.</span><span class="n">words</span><span class="p">(</span><span class="s">'english'</span><span class="p">))</span>  <span class="c1"># 영어 불용어 로드
</span>    <span class="n">tokens</span> <span class="o">=</span> <span class="p">[</span><span class="n">word</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">tokens</span> <span class="k">if</span> <span class="n">word</span><span class="p">.</span><span class="n">isalnum</span><span class="p">()</span> <span class="ow">and</span> <span class="n">word</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">stop_words</span><span class="p">]</span>  <span class="c1"># 특수문자 및 불용어 제거
</span>    <span class="n">lemmatizer</span> <span class="o">=</span> <span class="n">WordNetLemmatizer</span><span class="p">()</span>  <span class="c1"># 형태소 분석을 위한 WordNetLemmatizer 객체 생성
</span>    <span class="n">tokens</span> <span class="o">=</span> <span class="p">[</span><span class="n">lemmatizer</span><span class="p">.</span><span class="n">lemmatize</span><span class="p">(</span><span class="n">word</span><span class="p">)</span> <span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">]</span>  <span class="c1"># 모든 단어에 대해 형태소 분석 수행
</span>    <span class="k">return</span> <span class="s">' '</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">tokens</span><span class="p">)</span>  <span class="c1"># 형태소 분석된 단어를 공백으로 연결하여 반환
</span>
<span class="c1"># 모든 뉴스 데이터에 대해 전처리 수행
</span><span class="n">preprocessed_texts</span> <span class="o">=</span> <span class="p">[</span><span class="n">preprocess_text</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="k">for</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">texts</span><span class="p">]</span>  <span class="c1"># 리스트 컴프리헨션을 사용하여 모든 텍스트 전처리
</span></code></pre></div></div>

<ol>
  <li>단어 사전 생성 및 시퀀스 변환</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 단어 사전 생성 (torchtext 없이 직접 생성)
</span><span class="n">vocab</span> <span class="o">=</span> <span class="p">{</span><span class="s">"&lt;pad&gt;"</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>  <span class="c1"># "&lt;pad&gt;" 토큰을 인덱스 0으로 설정 (패딩 용도)
</span><span class="k">for</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">preprocessed_texts</span><span class="p">:</span>  <span class="c1"># 모든 문서에 대해 반복
</span>    <span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">text</span><span class="p">.</span><span class="n">split</span><span class="p">():</span>  <span class="c1"># 각 문서를 단어 단위로 분리하여 반복
</span>        <span class="k">if</span> <span class="n">token</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">vocab</span><span class="p">:</span>  <span class="c1"># 단어가 단어 사전에 없으면 추가
</span>            <span class="n">vocab</span><span class="p">[</span><span class="n">token</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">vocab</span><span class="p">)</span>  <span class="c1"># 현재 단어 개수를 인덱스로 할당하여 추가
</span>
<span class="c1"># 단어를 정수 인덱스로 변환하여 시퀀스 데이터 생성
</span><span class="n">sequences</span> <span class="o">=</span> <span class="p">[[</span><span class="n">vocab</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">text</span><span class="p">.</span><span class="n">split</span><span class="p">()]</span> <span class="k">for</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">preprocessed_texts</span><span class="p">]</span>  <span class="c1"># 단어를 정수로 변환
</span></code></pre></div></div>

<ol>
  <li>시퀀스 패딩 및 데이터셋 준비</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 시퀀스 패딩 (최대 길이에 맞춰 &lt;pad&gt; 인덱스(0) 추가)
</span><span class="n">max_length</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">seq</span><span class="p">)</span> <span class="k">for</span> <span class="n">seq</span> <span class="ow">in</span> <span class="n">sequences</span><span class="p">)</span>  <span class="c1"># 가장 긴 시퀀스의 길이 계산
</span><span class="k">def</span> <span class="nf">pad_sequence</span><span class="p">(</span><span class="n">seq</span><span class="p">,</span> <span class="n">max_len</span><span class="p">):</span>
    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">seq</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">max_len</span><span class="p">:</span>  <span class="c1"># 시퀀스 길이가 최대 길이보다 짧을 경우
</span>        <span class="n">seq</span> <span class="o">=</span> <span class="n">seq</span> <span class="o">+</span> <span class="p">[</span><span class="n">vocab</span><span class="p">[</span><span class="s">"&lt;pad&gt;"</span><span class="p">]]</span> <span class="o">*</span> <span class="p">(</span><span class="n">max_len</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">seq</span><span class="p">))</span>  <span class="c1"># 패딩을 추가하여 길이를 맞춤
</span>    <span class="k">else</span><span class="p">:</span>
        <span class="n">seq</span> <span class="o">=</span> <span class="n">seq</span><span class="p">[:</span><span class="n">max_len</span><span class="p">]</span>  <span class="c1"># 시퀀스가 너무 길면 최대 길이까지만 유지
</span>    <span class="k">return</span> <span class="n">seq</span>  <span class="c1"># 패딩 완료된 시퀀스 반환
</span>
<span class="c1"># 모든 데이터를 패딩 처리하여 동일한 길이로 변환
</span><span class="n">X</span> <span class="o">=</span> <span class="p">[</span><span class="n">pad_sequence</span><span class="p">(</span><span class="n">seq</span><span class="p">,</span> <span class="n">max_length</span><span class="p">)</span> <span class="k">for</span> <span class="n">seq</span> <span class="ow">in</span> <span class="n">sequences</span><span class="p">]</span>  <span class="c1"># 리스트 컴프리헨션을 사용하여 패딩 적용
</span><span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>  <span class="c1"># NumPy 배열로 변환
</span>
<span class="c1"># 레이블을 NumPy 배열로 변환 (정수 인코딩된 상태 유지)
</span><span class="n">y</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>  <span class="c1"># 레이블을 NumPy 배열로 변환
</span>
<span class="c1"># 학습 및 평가 데이터 분할
</span><span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">y_test</span> <span class="o">=</span> <span class="n">train_test_split</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">test_size</span><span class="o">=</span><span class="mf">0.2</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>  <span class="c1"># 80% 학습, 20% 평가 데이터로 분리
</span></code></pre></div></div>

<ol>
  <li>PyTorch 데이터셋 및 데이터로더 생성</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># NumPy 배열을 PyTorch 텐서로 변환
</span><span class="n">X_train_tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="nb">long</span><span class="p">)</span>  <span class="c1"># 정수 텐서 변환
</span><span class="n">y_train_tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">y_train</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="nb">long</span><span class="p">)</span>  <span class="c1"># 정수 레이블 변환
</span><span class="n">X_test_tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">X_test</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="nb">long</span><span class="p">)</span>  <span class="c1"># 정수 텐서 변환
</span><span class="n">y_test_tensor</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="n">torch</span><span class="p">.</span><span class="nb">long</span><span class="p">)</span>  <span class="c1"># 정수 레이블 변환
</span>
<span class="c1"># TensorDataset과 DataLoader 생성
</span><span class="n">batch_size</span> <span class="o">=</span> <span class="mi">32</span>  <span class="c1"># 배치 크기 설정
</span><span class="n">train_dataset</span> <span class="o">=</span> <span class="n">TensorDataset</span><span class="p">(</span><span class="n">X_train_tensor</span><span class="p">,</span> <span class="n">y_train_tensor</span><span class="p">)</span>  <span class="c1"># 학습 데이터셋 생성
</span><span class="n">test_dataset</span> <span class="o">=</span> <span class="n">TensorDataset</span><span class="p">(</span><span class="n">X_test_tensor</span><span class="p">,</span> <span class="n">y_test_tensor</span><span class="p">)</span>  <span class="c1"># 테스트 데이터셋 생성
</span><span class="n">train_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">train_dataset</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>  <span class="c1"># 학습 데이터 로더 생성 (셔플 활성화)
</span><span class="n">test_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">test_dataset</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">)</span>  <span class="c1"># 테스트 데이터 로더 생성
</span></code></pre></div></div>

<ol>
  <li>모델 정의 및 학습</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># PyTorch 모델 정의 (Embedding -&gt; Global Average Pooling -&gt; Linear)
</span><span class="k">class</span> <span class="nc">TextClassificationModel</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">vocab_size</span><span class="p">,</span> <span class="n">embedding_dim</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">TextClassificationModel</span><span class="p">,</span> <span class="bp">self</span><span class="p">).</span><span class="n">__init__</span><span class="p">()</span>  <span class="c1"># 부모 클래스 초기화
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">embedding</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Embedding</span><span class="p">(</span><span class="n">vocab_size</span><span class="p">,</span> <span class="n">embedding_dim</span><span class="p">)</span>  <span class="c1"># 임베딩 레이어 생성
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">fc</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">embedding_dim</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>  <span class="c1"># 선형 분류기 레이어 생성
</span>
    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">embedding</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>  <span class="c1"># 단어 임베딩 적용
</span>        <span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">dim</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>  <span class="c1"># Global Average Pooling 수행
</span>        <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">fc</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>  <span class="c1"># 선형 분류기 적용
</span>        <span class="k">return</span> <span class="n">x</span>  <span class="c1"># 출력 반환
</span></code></pre></div></div>

<ol>
  <li>모델 학습 및 평가</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 디바이스 설정
</span><span class="n">device</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">device</span><span class="p">(</span><span class="s">"cuda"</span> <span class="k">if</span> <span class="n">torch</span><span class="p">.</span><span class="n">cuda</span><span class="p">.</span><span class="n">is_available</span><span class="p">()</span> <span class="k">else</span> <span class="s">"cpu"</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">TextClassificationModel</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">vocab</span><span class="p">),</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">2</span><span class="p">).</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>

<span class="c1"># 손실 함수 및 옵티마이저 설정
</span><span class="n">criterion</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">CrossEntropyLoss</span><span class="p">()</span>
<span class="n">optimizer</span> <span class="o">=</span> <span class="n">optim</span><span class="p">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span>

<span class="c1"># 모델 학습
</span><span class="k">for</span> <span class="n">epoch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
    <span class="n">model</span><span class="p">.</span><span class="n">train</span><span class="p">()</span>
    <span class="n">total_loss</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">batch_x</span><span class="p">,</span> <span class="n">batch_y</span> <span class="ow">in</span> <span class="n">train_loader</span><span class="p">:</span>
        <span class="n">batch_x</span><span class="p">,</span> <span class="n">batch_y</span> <span class="o">=</span> <span class="n">batch_x</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">),</span> <span class="n">batch_y</span><span class="p">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
        <span class="n">optimizer</span><span class="p">.</span><span class="n">zero_grad</span><span class="p">()</span>
        <span class="n">loss</span> <span class="o">=</span> <span class="n">criterion</span><span class="p">(</span><span class="n">model</span><span class="p">(</span><span class="n">batch_x</span><span class="p">),</span> <span class="n">batch_y</span><span class="p">)</span>
        <span class="n">loss</span><span class="p">.</span><span class="n">backward</span><span class="p">()</span>
        <span class="n">optimizer</span><span class="p">.</span><span class="n">step</span><span class="p">()</span>
        <span class="n">total_loss</span> <span class="o">+=</span> <span class="n">loss</span><span class="p">.</span><span class="n">item</span><span class="p">()</span>
    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Epoch </span><span class="si">{</span><span class="n">epoch</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="s">, Loss: </span><span class="si">{</span><span class="n">total_loss</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="recurrent-neural-network">Recurrent Neural Network</h2>
<ul>
  <li>
    <p>RNN은 순차적 데이터(텍스트, 시간 시계열 데이터 등)을 처리하기 위해 설계된 인공신경망이다.</p>
  </li>
  <li>
    <p>텍스트는 문자의 Sequence로 되어 있다. RNN의 뉴런은 정보를 처리한 후 다시 자기 자신에게 되먹임할 수 있도록 Cycle을 가진다. 이러한 특징으로 데이터가 순환되기 때문에 과거의 정보를 기억하고 최신 데이터로 갱신될 수 있다.</p>
  </li>
  <li>
    <p>RNN architecture는 Input/Hidden/Output Layer로 구성되어 있으며 초기 weight 값들은 랜덤으로 생성된다.<br /></p>

    <p><img src="/assets/images/RNN.png" alt="alt text" /><br /></p>

    <p>$x^{(t)}$는 Input Sequence의 $t$번째 값<br />
  $h^{(t)}$는 Hidden Layer의 $t$번째 Neuron<br />
  $o^{(t)}$는 Output Sequence의 $t$번째 값<br />
  $U, V, W$는 각각의 Layer에서 사용되는 공유된 weight → RNN의 핵심개념<br /></p>

    <p>$h_t$는 상태를 나타내며 $h_t = \tanh(h_{t-1}W_h + x_tW_x + b)$로 계산된다.</p>
  </li>
</ul>

<h3 id="rnn-추론">RNN 추론</h3>

<ul>
  <li>
    <p>RNN의 추론은 보통의 신경망과 같이 오른쪽으로 진행하며 순전파를 수행한다.<br />
  $h_{next} = \tanh(h_{prev}W_h + x_tW_x + b)$</p>
  </li>
  <li>
    <p>Hidden Layer의 뉴런은 $h^{(t)}=f(h^{(t-1)}, x^{(t)})$ 이며 activation function $f$는 hyperbolic tangent ($\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$)를 사용한다.</p>
  </li>
  <li>
    <p>Hidden Neuron은 아래의 식으로 정의된다.<br /></p>

\[h^{(t)} =
  \begin{cases}
  \tanh(W_{xh} \cdot x^{(1)}), t = 1\\
  \tanh(W_{hh} \cdot h^{(h-1)} + W_{xh} \cdot x^{(t)}), t &gt; 1
  \end{cases}\]
  </li>
  <li>
    <p>Output Layer는 $W_{hy}$를 이용해 Hidden Layer의 결과를 다시 한 번 연산하여 Output 산출 $o^{(t)} = W_{hy} \cdot h^{(t)}$</p>
  </li>
</ul>

<h3 id="rnn-학습">RNN 학습</h3>
<ul>
  <li>
    <p>RNN의 학습은 일반적인 오차 역전파법을 적용하여 손실 함수에 대한 매개변수의 기울기를 계산한다.</p>
  </li>
  <li>
    <p>시간 방향으로 펼친 신경망의 오차 역전파법이란 뜻으로 BPTT(Backpropagation Through Time)이라고 한다. RNN은 전후 관계를 갖는 Sequence를 다루기 때문에 기존의 역전파에 추가적인 시간의 개념이 도입된 BPTT를 이용한다.</p>
  </li>
  <li>
    <p>일반적으로 RNN은 Softmax 함수를 사용한다.</p>

\[S(x_i) = \frac{e^{x_i}}{\sum _j e^{x_j}}\]
  </li>
  <li>
    <p>Output Layer는 Softmax 함수를 이용해 $o^{(t)} = softmax(W_{hy} \cdot h^{(t)})$</p>
  </li>
  <li>
    <p>시점 $k$ 에서 output neuron의 mini loss function을 $l^{(k)}$ 라고 하면 BPTT 수행 시 시점 $k$ 에서 단계적으로 고려되는 loss function $L^{(k)}$ 는 시점 $k$ 와 그 이후의 mini loss function들의 합으로 정의된다.</p>

\[L^{(k)} = \sum _{l = k} ^{\tau} l^{(l)}\]
  </li>
  <li>이 이외의 다른 부분은 다른 역전파 방법들과 동일하다.
    <ol>
      <li>Chain rule을 이용한 Gradient 계산</li>
      <li>Gradient를 이용한 Weight 계산</li>
      <li>Cross entropy loss function</li>
    </ol>
  </li>
  <li>BPTT 문제점과 해결방안
    <ol>
      <li>Gradient exploding
        <ul>
          <li>Gradient 크기를 제한하는 weight clipping을 통해 간단히 해결</li>
          <li>$W_{hh}$를 normalization시켜 spectral radius가 1이 넘지 않게 하는 것으로도 해결 가능</li>
        </ul>
      </li>
      <li>Gradient vanishing
        <ul>
          <li>Gradient vanishing은 해결하기가 쉽지 않다. 해당 문제를 해결하지 못하면 RNN은 sequence 전체가 아닌 짧은 범위의 몇 개 원소들만 기억하게 된다.</li>
          <li>긴 sequence를 올바로 학습하기 위해서 LSTM(Long Short Term Memory)를 사용한다.</li>
        </ul>
      </li>
    </ol>
  </li>
</ul>

<h3 id="rnn-구현">RNN 구현</h3>
<ul>
  <li>
    <p>RNN의 구조를 이용하여 NumPy를 사용해 간단한 RNN을 구현할 수 있다. RNN은 반복할 때, 이전에 계산한 정보를 재사용하는 for 루프를 이용하여 구현 가능하다.</p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>

  <span class="n">timesteps</span> <span class="o">=</span> <span class="mi">100</span>
  <span class="n">input_features</span> <span class="o">=</span> <span class="mi">32</span>
  <span class="n">output_features</span> <span class="o">=</span> <span class="mi">64</span>

  <span class="n">inputs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">random</span><span class="p">((</span><span class="n">timesteps</span><span class="p">,</span> <span class="n">input_features</span><span class="p">))</span>

  <span class="n">state_t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">((</span><span class="n">output_features</span><span class="p">,</span> <span class="p">))</span>

  <span class="n">W</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">random</span><span class="p">((</span><span class="n">output_features</span><span class="p">,</span> <span class="n">input_reatures</span><span class="p">))</span>
  <span class="n">U</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">random</span><span class="p">((</span><span class="n">output_features</span><span class="p">,</span> <span class="n">output_features</span><span class="p">))</span>
  <span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">random</span><span class="p">((</span><span class="n">output_features</span><span class="p">,</span> <span class="p">))</span>

  <span class="n">surccesive_outputs</span> <span class="o">=</span> <span class="p">[]</span>

  <span class="k">for</span> <span class="n">input_t</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">:</span>
      <span class="n">output_t</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">tanh</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">input_t</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="n">state_t</span><span class="p">)</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span>
      <span class="n">surccesive_outputs</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">output_t</span><span class="p">)</span>
      <span class="n">state_t</span> <span class="o">=</span> <span class="n">output_t</span>

  <span class="n">final_output_sequence</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">stack</span><span class="p">(</span><span class="n">surccesive_outputs</span><span class="p">,</span> <span class="n">axis</span> <span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="long-short-term-memory">Long Short Term Memory</h2>
<ul>
  <li>
    <p>LSTM은 기존의 RNN에서 출력과 멀리 있는 정보를 기억할 수 없다는 단점을 보완해 장/단기 기억을 가능하게 설계한 신경망 구조이다. 이는 RNN의 기울기 소실 문제 해결할 수 있다.</p>
  </li>
  <li>
    <p>LSTM은 RNN에 과거에서 현재까지 필요한 정보를 기억할 수 있는 기억 셀($c_t$)을 추가한다.<br />
LSTM 전용의 기억 메커니즘으로 3개의 입력($c_{t-1}, h_{t-1}, x_t$)으로부터 기억 셀($c_t$)을 구한다.<br />
출력인 은닉 상태는 $h_t = \tanh(c_t)$ 에 의해 계산한다.</p>
  </li>
  <li>
    <p>LSTM은  RNN에 출력 정보의 양을 조절하는 게이트를 추가한다. 학습 시 기울기를 원만하게 흘려 기울기 소실을 줄일 수 있다.</p>
  </li>
</ul>

<h3 id="lstm의-구조">LSTM의 구조</h3>
<ul>
  <li>
    <p>LSTM은 RNN의 Hidden State($h_t$)에 Cell State($C_t$)를 추가한 구조이다.<br />
  <img src="/assets/images/lstm.png" alt="alt text" /></p>
  </li>
  <li>
    <p>셀 스테이트(Cell state) $C_t$<br />
  LSTM은 셀 스테이트에 정제된 구조를 가진 게이트(gate)라는 요소를 활용해서 정보를 더하거나 제거하는 기능을 수행한다.</p>
  </li>
  <li>
    <p>시그모이드 레이어를 사용한 게이트 구현<br />
  게이트는 각 구성요소가 영향을 주게 될지 결정하는 역할을 한다. 0이라는 값을 가지게 되면 해당 구성요소가 미래의 결과에 아무런 영향을 주지 않으며 1이라는 값을 가지게 되면 해당 구성요소가 확실히 미래의 예측 결과에 영향을 주도록 데이터가 흘러가게 한다.</p>
  </li>
  <li>
    <p>Forget 게이트<br />
  셀 스테이트에서 어떤 정보를 버릴지 선택하는 게이트이다.<br />
  $f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f)$ 로 표현되며 $h_{t-1}$과 $x_t$의 입력 값을 받아 0과 1 사이의 값을 출력한다.<br />
  출력 값이 1인 경우 완전히 이 값을 유지하게 되고 출력 값이 0이 될 경우 완전히 이 값을 버린다.</p>
  </li>
  <li>
    <p>Input 게이트<br />
  새로운 정보가 셀 스테이트에 저장될지를 결정하는 게이트이다.<br />
  $$
  i_t = \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) \</p>

    <p>\tilde{C_t} = \tanh(W_C \cdot [h_{t-1}, x_t] + b_C)
  $$</p>
  </li>
  <li>
    <p>오래된 셀 스테이트($C_{t-1}$)를 새로운 스테이트인 $C_t$로 업데이트<br />
  $C_t = f_t * C_{t-1} + i_t * \tilde{C_t}$</p>
  </li>
  <li>
    <p>Output 게이트<br />
  \(o_t = \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) \\
  h_t = o_t * \tanh(C_t)\)</p>

    <p>어떤 값을 출력할지 결정하는 시그모이드 레이어로 Cell State 값이 tanh함수를 거쳐서 -1과 1 사이의 값으로 출력한다. 시그모이드 레이어에서 얻은 값과 tanh 함수를 거쳐 얻은 값을 곱해서 출력</p>
  </li>
  <li>
    <p>LSTM의 단점</p>
    <ol>
      <li>매개변수가 많아서 계산이 오래걸린다.</li>
      <li>LSTM을 대신할 게이트가 추가된 방법들이 많이 제안되었다. Gated Recurrent Unit(GRU) 등…</li>
    </ol>
  </li>
</ul>

<h2 id="오늘의-회고">오늘의 회고</h2>
<ul>
  <li>NLP 중심으로 RNN과 LSTM을 학습하였다. 다른 모델도 마찬가지지만 해당 부분은 특히나 Architecture가 중요함을 깨달았으며 해당 Architecture을 수식으로 풀어보며 공부할 수 있었다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="7th Week" /><category term="python" /><category term="TensorFlow" /><category term="Pytorch" /><summary type="html"><![CDATA[한 줄 정리]]></summary></entry><entry><title type="html">Pre-Trained Model</title><link href="https://thplus.github.io/today%20i%20learn/6th%20week/addoverfitting/" rel="alternate" type="text/html" title="Pre-Trained Model" /><published>2025-03-05T00:00:00+00:00</published><updated>2025-03-05T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/6th%20week/addoverfitting</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/6th%20week/addoverfitting/"><![CDATA[<h2 id="early-stopping">Early Stopping</h2>
<ul>
  <li>
    <p>Early Stopping은 기계 학습에서 경사 하강법과 같은 반복 방법으로 학습자를 훈련할 때, 과적합을 방지하기 위해 사영되는 정규화의 한 형태이다. 학습 과정에서 모델의 성능이 더 이상 개선되지 않을 때, 학습을 조기에 멈추어 Overfitting을 방지할 수 있다.</p>
  </li>
  <li>
    <p>Early Stopping은 모델의 Overfitting을 방지하고 학습시간을 줄일 수 있다. 또한 최적의 성능을 보이는 지점을 찾아 학습을 조기에 멈추기 위해 사용된다. Validation Loss나 Validation Accuracy와 같은 지표를 모니터링하여 더 이상 성능이 햐상되지 않는 시점에서 훈련을 중지해야한다.</p>
  </li>
</ul>

<h2 id="hyperparameter-tuning">HyperParameter Tuning</h2>
<ul>
  <li>
    <p>HyperParameter는 Learning Rate나 Optimizer 등과 같은 매개변수를 말하며 HyperParameter Tuning은 기계 학습 모델의 성능을 최적화하기 위해 모델의 Parameter값을 조정하는 과정을 뜻한다. 해당 과정은 모델의 성능을 향상시키고 주어진 데이터와 문제에 대해 최상의 예측 성능을 달하는 것을 목표로 한다.</p>
  </li>
  <li>
    <p>HyperParameter 목록</p>

    <table>
      <thead>
        <tr>
          <th>이름</th>
          <th>내용</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Learning Rate</td>
          <td>가중치 업데이트의 크기를 결정하는 값</td>
        </tr>
        <tr>
          <td>Batch Size</td>
          <td>한 번 학습할 데이터 샘플의 개수</td>
        </tr>
        <tr>
          <td>Epochs</td>
          <td>전체 데이터셋을 몇 번 반복하여 학습할 지 결정</td>
        </tr>
        <tr>
          <td>Optimizer</td>
          <td>모델 학습 과정을 최적화하는 알고리즘 선택</td>
        </tr>
        <tr>
          <td>Momentum</td>
          <td>SGD와 같은 Optimizer에서 Gradient 업데이트에 관성을 추가하여 학습을 가속화하고 안정화</td>
        </tr>
        <tr>
          <td>DropOut Rate</td>
          <td>학습 과정에서 무작위로 뉴런을 끄는 비율</td>
        </tr>
        <tr>
          <td>Regularization Parameter</td>
          <td>과적합을 방지하기 위해 가중치에 패널티를 부여하는 값</td>
        </tr>
        <tr>
          <td>Learning Rate Decay</td>
          <td>학습이 진행됨에 따라 학습률을 감소시키는 방법</td>
        </tr>
        <tr>
          <td>Activation Function</td>
          <td>각 뉴런의 출력값을 결정하는 함수</td>
        </tr>
        <tr>
          <td>Initialization Method</td>
          <td>가중치 초기화 방법</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="오늘의-회고">오늘의 회고</h2>
<ul>
  <li>어제 학습하지 못한 Early Stopping과 HyperParameter Tuning에 대해 학습하였다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="6th Week" /><category term="python" /><category term="tensorflow" /><category term="pytorch" /><summary type="html"><![CDATA[Early Stopping Early Stopping은 기계 학습에서 경사 하강법과 같은 반복 방법으로 학습자를 훈련할 때, 과적합을 방지하기 위해 사영되는 정규화의 한 형태이다. 학습 과정에서 모델의 성능이 더 이상 개선되지 않을 때, 학습을 조기에 멈추어 Overfitting을 방지할 수 있다.]]></summary></entry><entry><title type="html">PostTesting</title><link href="https://thplus.github.io/test%20category/PostTesting/" rel="alternate" type="text/html" title="PostTesting" /><published>2025-03-05T00:00:00+00:00</published><updated>2025-03-05T00:00:00+00:00</updated><id>https://thplus.github.io/test%20category/PostTesting</id><content type="html" xml:base="https://thplus.github.io/test%20category/PostTesting/"><![CDATA[<h1 id="hi-my-name-is-brix">Hi My name is Brix</h1>

\[f(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)
= \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}\]

<p>please… MathJax…</p>

<h2 id="prompt-test">Prompt test</h2>
<blockquote>
  <p>[!NOTE]
tip 테스트 입니다.</p>
</blockquote>

<blockquote>
  <p>[!TIP]
tip 테스트</p>
</blockquote>

<blockquote>
  <p>[!INFO]
info test</p>
</blockquote>

<blockquote>
  <p>[!WARNING]
warning test</p>
</blockquote>

<blockquote>
  <p>[!danger]
danger test</p>
</blockquote>

<blockquote class="prompt-tip">
  <h4 id="tip">Tip</h4>

  <p>여기에 팁에 대한 내용을 작성하세요.</p>
</blockquote>

<blockquote class="prompt-info">
  <h4 id="info">Info</h4>

  <p>여기에 정보를 안내하는 내용을 작성하세요.</p>
</blockquote>

<blockquote class="prompt-warning">
  <h4 id="warning">Warning</h4>

  <p>여기에 주의해야 할 내용을 작성하세요.</p>
</blockquote>

<blockquote class="prompt-danger">
  <h4 id="danger">Danger</h4>

  <p>여기에 심각한 위험 또는 경고 내용을 작성하세요.</p>
</blockquote>]]></content><author><name>Buyoung Kim</name></author><category term="Test Category" /><category term="test" /><category term="post" /><category term="python" /><summary type="html"><![CDATA[Hi My name is Brix]]></summary></entry><entry><title type="html">Pre-Trained Model</title><link href="https://thplus.github.io/today%20i%20learn/6th%20week/pretrainedmodel/" rel="alternate" type="text/html" title="Pre-Trained Model" /><published>2025-03-04T00:00:00+00:00</published><updated>2025-03-04T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/6th%20week/pretrainedmodel</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/6th%20week/pretrainedmodel/"><![CDATA[<h2 id="한-줄-정리">한 줄 정리</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>한 줄 정리</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="#pre-trained-model사전-훈련-모델">Pre-trained Model</a></td>
      <td>대규모 데이터셋에서 미리 학습되어 이미 훈련이 끝난 모델</td>
      <td>모델을 처음부터 구축하지 않아도 되어 비용을 절약할 수 있다.</td>
    </tr>
    <tr>
      <td><a href="#transfer-learning">Transfer Learning</a></td>
      <td>사전 훈련된 모델을 그대로 사용하거나 추가 튜닝하여 새로운 문제에 적용하는 것</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#fine-tuning미세-조정">Fine Tuning</a></td>
      <td>Pre-trained model을 새로운 데이터셋에 맞게 재훈련하는 과정</td>
      <td>대규모 데이터셋에서 미리 학습된 파라미터 등을 활용하고 새로운 데이터셋에 맞게 파라미터를 조정하기 위해</td>
    </tr>
    <tr>
      <td><a href="#feature-extraction특징-추출">Feature Extraction</a></td>
      <td>Pre-trained Model의 파라미터는 그대로 사용하고 분류 layer만 새로 학습하는 것</td>
      <td>새로운 데이터셋에서도 특징 추출은 유용할 수 있음</td>
    </tr>
    <tr>
      <td><a href="#overfitting과적합">Overfitting</a></td>
      <td>모델이 학습 데이터에 대해 과도하게 학습하여 일반화 성능이 떨어지는 현상</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#underfitting과소적합">Underfitting</a></td>
      <td>모델이 학습 데이터를 충분히 학습하지 못하여 예측 성능이 떨어지는 현상</td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="model-architecture모델-구성">Model Architecture(모델 구성)</h2>
<ul>
  <li>
    <p>Model Architecture는 신경망에서 각 레이어의 구성, 연결 방식, 활성화 함수, 입력 및 출력 형태 등 전체 모델의 구조이다. 특히 딥러닝 모델에서 다양한 레이어가 어떻게 결합하여 데이터를 처리하고 결과를 도출하는지 정의하는 중요한 개념이다.</p>
  </li>
  <li>
    <p>딥러닝 모델은 기본적으로 학습 과정을 통해 찾아낸 최적 weight들의 집합니다.</p>
  </li>
</ul>

<h3 id="epoch">Epoch</h3>
<ul>
  <li>Training Data와 Validation Data로 나눈 데이터로 학습을 한다고 가정하면 아래와 같은 과정으로 Epoch이 수행된다.
    <ol>
      <li>Training Data마다 각각 다른 비선형 그래프가 그려지고 Learning Rate를 조정하여 학습을 진행하면서 최적의 Loss값을 찾는다.</li>
      <li>모든 Training Data에 대한 학습이 완료되면 모델이 학습한 내용을 바탕으로 Validation Data에 대한 예측을 수행한다.</li>
      <li>Validation Data의 Label과 모델의 예측 값을 비교하여 Loss값과 Accuracy를 계산하여 해당 Epoch에 대한 학습과 검증 결과로 Loss와 Accuracy 값이 출력된 후 학습된 모델이 저장된다.</li>
    </ol>
  </li>
</ul>

<h3 id="loss손실">Loss(손실)</h3>
<ul>
  <li>실제 값과 예측 값의 차이
 $|Y - \hat Y|$ 
 로 정의할 수 있다.</li>
  <li>Loss가 0에 가까울수록 좋다. 그러나 Loss가 낮다고 무조건 좋은 것은 아니며 Overfitting의 경우 Loss가 낮아도 테스트 데이터의 성능이 떨어질 수 있다.</li>
</ul>

<h3 id="accuracy정확도">Accuracy(정확도)</h3>
<ul>
  <li>전체 $n$개의 샘플에 대해 각 샘플 $i$에 대해 모델의 예측과 실제 값이 일치하는 정도<br /></li>
  <li>
    <p>전체 샘플</p>

    <p>\(\text{Accuracy} = \frac{1}{n}\sum_{i=1}^{n} \mathbf{1}\{y_i = \hat{y}_i\}\)
   <br /></p>
  </li>
  <li>
    <p>이진 분류</p>

\[\text{Accuracy} = \frac{TP + TN}{TP + TN + FP + FN}\]
  </li>
</ul>

<h2 id="pre-trained-model사전-훈련-모델">Pre-trained Model(사전 훈련 모델)</h2>
<ul>
  <li>
    <p>사전 훈련 모델은 이미 훈련이 끝난 모델 또는 모델 구성요소를 말하며 이 모델은 대규모 데이터셋에서 미리 학습되어 특정한 작업에 필요한 특성을 이미 학습한 상태이다.</p>
  </li>
  <li>
    <p>사전 훈련 모델을 사용하는 이유는 인공지능 모델을 처음부터 구축하지 않아도 되어 시간과 자원을 절약하며 신속하게 활용할 수 있기 때문이다.</p>
  </li>
</ul>

<h2 id="resnetresidual-network">ResNet(Residual Network)</h2>
<ul>
  <li>
    <p>ResNet은 Neural Network에서 발생하는 기울기 소실 문제를 해결하기 위해 Residual Connections을 도입한 사전 훈련 모델이다.<br />
Residual Connections(Skip connection)을 통해 깊은 네트워크에서도 Vanishing Gradient가 현저히 줄어든 상태로 학습을 진행할 수 있으며 ResNet은 50, 101, 152층 등 다양한 깊이의 모델로 구성된다.</p>
  </li>
  <li>
    <p>ResNet은 매우 깊은 신경망에서도 기울기 소실 문제를 효과적으로 해결하여 더 높은 정확도와 성능을 제공하는 딥러닝 모델을 구축할 수 있다.</p>
  </li>
</ul>

<h2 id="vgg16">VGG16</h2>
<ul>
  <li>
    <p>Visual Geometry Group이라는 영국 옥스포드 대학교의 연구그룹이 제안한 CNN 구조로 13개 층의 Conv Layer와 3개의 Fully-Connected Layer를 합친 CNN 구조이다.</p>
  </li>
  <li>
    <p>VGG16은 깊고 구조화된 CNN 구조의 사전 학습 모델로 주로 이미지 인식과 분류 작업에 사용되는 사전 훈련 모델이다. VGG16은 심층 신경망의 설계를 단순화하면서도 강력한 성능을 유지하는데 초점을 맞춘 모델로 모든 합성곱 계층에서 3x3 크기의 필터를 사용하여 작은 수용영역으로도 복잡한 특징을 효과적으로 학습할 수 있도록 설계되었다.</p>
  </li>
  <li>
    <p>VGG16은 ImageNet 데이터셋으로 사전 훈련된 가중치를 제공하여 Transfer Learning에도 효과적으로 확용될 수 있다. 138M개의 파라미터를 가지는 대규모 모델이므로 연산량과 메모리 사용량이 크다는 단점이 있다.</p>
  </li>
</ul>

<h2 id="transfer-learning">Transfer Learning</h2>
<ul>
  <li>
    <p>Transfer Learning은 사전 훈련된 모델을 그대로 사용하거나 추가 튜닝하여 새로운 문제에 적용함으로써 학습 시간을 단축하고 성능을 향상시키는 머신 러닝 기법이다. Transfer Learning 기법을 사용하면 대규모 데이터셋 또는 특정 과제에서 사전 훈련된 네트워크가 추출해 낸 구수준 특성(Feature)이나 모델 가중치(Weight)를 새로운 과제에 적용함으로써 학습시간을 단축하고 모델 성능을 개선할 수 있게 된다.</p>
  </li>
  <li>
    <p>전이 학습에는 주로 3가지 기법 (Fine-Tuning, Feature Extraction, Zero-Shot Learning)이 있다.</p>
  </li>
</ul>

<h3 id="fine-tuning미세-조정">Fine-tuning(미세 조정)</h3>
<ul>
  <li>
    <p>사전 훈련된 모델의 전체 혹은 일부 계층을 새로운 데이터셋에 맞게 재훈련하여 최적화하는 과정이다. 이미 학습된 가중치와 패턴을 활용하면서도 새로운 문제의 특성을 반영하기 위해 미세한 조정 과정을 거친다.</p>
  </li>
  <li>
    <p>이미 학습된 가중치와 패턴을 활용하면서도 새로운 문제의 특성을 반영하기 위해 미세한 조정 과정을 거친다. 이 기법은 학습 자원이 많이 들 수 있지만 데이터셋 특유의 패턴을 보다 깊이 있게 반영하므로 더 높은 성능을 얻을 가능성이 크다.</p>
  </li>
</ul>

<ol>
  <li>Full Fine Tuning<br />
 모델의 모든 파라미터를 새로운 데이터셋에 맞추어 학습화는 과정이다. 모델이 새로운 작업에 완전히 적응하도록 하기 때문에 가장 높은 성능을 기대할 수 있으나 많은 데이터와 계산 자원이 필요할 수 있으며 학습 시간이 오래 걸릴 수 있다.
    <ul>
      <li>단계<br />
  사전 학습된 모델 불러오기 $\rightarrow$ 모델의 구조 변경 (새로운 분류 레이어 추가) $\rightarrow$ 모든 레이어를 동결 해제 $\rightarrow$ 모델 컴파일 $\rightarrow$ 전체 모델 학습 $\rightarrow$ 모델 평가</li>
    </ul>
  </li>
  <li>Partial Fine Tuning<br />
 모델의 일부 파라미터만 조정하는 방법이다. 모델의 상위 층(layer)만 미세 조정하고 하위 층은 그대로 두는 방식이다. 이렇게 하면 학습 시간이 단축되고 과적합(Overfitting) 문제를 줄일 수 있다.
    <ul>
      <li>단계<br />
  사전 학습된 모델 불러오기 $\rightarrow$ 모델의 구조 변경 (새로운 분류 레이어 추가) $\rightarrow$ 하위 레이어를 동결하고 상위 레이어만 동결 해제 $\rightarrow$ 모델 컴파일 $\rightarrow$ 일부 레이어 학습 $\rightarrow$ 모델 평가</li>
    </ul>
  </li>
  <li>단계적 Fine Tuning <br />
 먼저 모델의 상위 레이어만 재학습하고 그 다음 단계에서 하위 레이어까지 포함하여 재학습하는 접근법이다. 점진적으로 모델을 최적화하는데 사용된다.
    <ul>
      <li>단계<br />
  사전 학습된 모델 불러오기 $\rightarrow$ 모델의 구조 변경 (새로운 분류 레이어 추가) $\rightarrow$ 기본 레이어를 동결 $\rightarrow$ 모델 컴파일 $\rightarrow$ 상위 레이어 학습 $\rightarrow$ 하위 레이어 동결 해제 및 상위 레이어 일부 동결 유지 $\rightarrow$ 모델 재컴파일 및 전체 모델 학습 $\rightarrow$ 모델 평가</li>
    </ul>
  </li>
  <li>하이브리드 방법<br />
 여러 Fine Tuning 방법을 결합하여 사용하는 것으로 예를 들어 일부 레이어 Fine Tuning과 단계적 Fine Tuning을 결합하여 모델을 최적화한다.
    <ul>
      <li>단계<br />
  사전 학습된 모델 불러오기 $\rightarrow$ 모델의 구조 변경 (새로운 분류 레이어 추가) $\rightarrow$ 하위 레이어를 동결하고 상위 레이어만 동결 해제 $\rightarrow$ 모델 컴파일 $\rightarrow$ 상위 레이어 학습 $\rightarrow$ 일부 하위 레이어 동결 해제 $\rightarrow$ 모델 재컴파일 및 전체 모델 학습 $\rightarrow$ 모델 평가</li>
    </ul>
  </li>
</ol>

<h3 id="feature-extraction특징-추출">Feature Extraction(특징 추출)</h3>
<ul>
  <li>
    <p>사전 훈련된 모델이 지닌 중간 계층의 가중치를 그대로 고정하여 특징 추출기(Feature Extractor)로 활용하는 방식이다. 그 후 마지막 분류 레이어만 새로 학습한다. 사전 훈련된 모델이 가진 광범위한 저수준 ~ 고수준 특징을 재활용하므로 데이터셋 규모가 크지 않아도 빠른 시간 내에 괜찮은 성능을 낼 수 있다.</p>
  </li>
  <li>
    <p>새로운 문제와 사전 훈련 모델이 학습된 주제(도메인)가 유사할수록 특징 추출의 효율이 높다.</p>
  </li>
  <li>
    <p>Feature Extraction을 사용하는 이유는 적은 리소스로도 높은 성능을 끌어 올릴 수 있기 때문이다. Feature Extraction 방식은 사전 훈련된 모델의 중간 계층이 이미 학습한 범용적이고 고도화된 특징을 재활용한다는 점에서 매우 효과적인 전이 학습 접근법이다.</p>
  </li>
</ul>

<h3 id="zero-shot-learning제로샷-학습">Zero-Shot Learning(제로샷 학습)</h3>
<ul>
  <li>
    <p>학습에 한 번도 등장하지 않은 클래스에 대해서도 모델이 예측을 수행할 수 있도록 하는 전이 학습 기법니다. 모델이 사전에 개념(Concept) 정보나 멀티모달(텍스트$\cdot$이미지) 표현을 학습해두고 이후 새로운 클래스가 등장했을 때, 유사도나 개념 연결로 그 클래스를 식별한다.</p>
  </li>
  <li>
    <p>데이터가 없는 클래스에 대해서도 추론할 수 있어 확장성이 높고 희귀한 상황이나 긴급상황 분류 등에 활용될 수 있다.</p>
  </li>
  <li>
    <p>Zero-Shot Learning은 학습 데이터에 없는 새로운 클래스나 작업에도 추가학습 없이 즉시 대응하기 위해서 사용한다. 일반적인 머신 러닝이나 딥러닝 기법은 훈련 데이터에 등장한 클래스에 대해서만 예측 성능을 발휘한다는 한계를 가진다. 하지만 현실 세계에서는 학습 데이터로 준비되지 않은 수 많은 상황이나 새로운 분류 항목이 끊임없이 등장하기 때문에 추가적인 데이터 수집이나 재학습이 지속적으로 요구된다.</p>
  </li>
</ul>

<h2 id="model-comparison모델-비교">Model Comparison(모델 비교)</h2>
<ul>
  <li>
    <p>여러 기계학습 모델의 성능을 평가하고 비교해 특정 문제에 대해 가장 효과적인 모델을 선택하는 과정을 말한다.</p>
  </li>
  <li>
    <p>다양한 모델 중에서 성능이 가장 우수한 모델을 선택하여 주어진 문제를 최적의 방식으로 해결하고 예측 정확도를 극대화하기 위해서 사용한다.</p>
  </li>
</ul>

<h2 id="overfitting과적합">Overfitting(과적합)</h2>
<ul>
  <li>
    <p>학습 데이터를 과하게 학습해 실제 데이터에 대해서 오차가 증가하게 되는 것으로 모델이 학습 데이터의 노이즈나 특이한 패턴까지도 학습하여 일반적인 패턴을 제대로 학습하지 못하게 되기 때문에 발생한다.</p>
  </li>
  <li>
    <p>Overfitting의 발생 이유</p>

    <table>
      <thead>
        <tr>
          <th>이유</th>
          <th>설명</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>모델 복잡성</td>
          <td>너무 많은 파라미터나 복잡한 구조를 가진 모델은 학습 데이터에 과적합되기 쉽다.</td>
        </tr>
        <tr>
          <td>데이터 양의 부족</td>
          <td>학습 데이터가 충분하지 않으면 모델이 데이터를 외우게 되어 과적합이 발생할 수 있다.</td>
        </tr>
        <tr>
          <td>노이즈 포함 학습</td>
          <td>데이터에 노이즈가 많을 경우 모델이 노이즈까지 학습하여 새로운 데이터에 대한 성능이 떨어진다.</td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>
    <p>Overfitting은 모델이 새로운 데이터에서도 좋은 성능을 발휘할 수 있도록 일반화 성능을 높이기 위해서 방지해야할 필요가 있다. 과적합된 모델은 학습 데이터에서는 높은 성능을 보일 수 있지만 실제로 사용될 새로운 데이터에 대해서는 성능이 크게 떨어질 수 있다.</p>
  </li>
  <li>
    <p>Overfitting 방지의 중요성</p>

    <table>
      <thead>
        <tr>
          <th>항목</th>
          <th>설명</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>일반화 능력</td>
          <td>모델이 새로운 데이터에 대해서도 좋은 성능을 유지하게 함</td>
        </tr>
        <tr>
          <td>신뢰성</td>
          <td>다양한 데이터 상황에서도 일관된 성능을 보장</td>
        </tr>
        <tr>
          <td>적용 가능성</td>
          <td>실제 환경에서의 예측 및 분석의 정확도 향상</td>
        </tr>
        <tr>
          <td>비용 절감</td>
          <td>잘 일반화 된 모델은 데이터 수집 및 처리 비용을 줄일 수 있음</td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>
    <p>Overfitting 방지 방법</p>

    <table>
      <thead>
        <tr>
          <th>항목</th>
          <th>설명</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>드롭아웃(DropOut)</td>
          <td>학습 과정에서 무작위로 뉴런을 끔으로써 과적합을 방지</td>
        </tr>
        <tr>
          <td>데이터 증강(Data Augmentation)</td>
          <td>학습 데이터를 늘려서 다양한 상황에 대한 모델의 적응력을 높임</td>
        </tr>
        <tr>
          <td>정규화(Regularization)</td>
          <td>L1, L2 정규화를 사용하여 큰 가중치 값을 가지지 않도록 함</td>
        </tr>
        <tr>
          <td>교차 검증(Cross-Validation)</td>
          <td>데이터를 여러 번 나누어 검증하여 모델의 일반화 성능을 평가</td>
        </tr>
        <tr>
          <td>조기 종료(Early Stopping)</td>
          <td>검증 데이터의 성능이 향상되지 않으면 학습을 조기 종료</td>
        </tr>
        <tr>
          <td>앙상블(Ensemble) 기법</td>
          <td>여러 모델을 결합하여 예측 성능을 높임</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="underfitting과소적합">Underfitting(과소적합)</h2>
<ul>
  <li>
    <p>Underfitting은 모델이 데이터의 복잡성을 충분히 학습하지 못해 훈련 데이터와 새로운 데이터 모두에서 낮은 성능을 보이는 것으로 모델이 학습 과정에서 필요한 패턴이나 규칙을 제대로 파악하지 못한 채, 너무 단순화된 (혹은 충분히 훈련되지 않은) 형태로 머물러 있다는 뜻이다.</p>
  </li>
  <li>
    <p>모델이 제대로 학습하지 못한다면 아무리 많은 데이터를 투입하거나 복잡한 아키텍처를 사용해도 원하는 성능을 얻기 어렵다. Underfitting에 대해 공부해야 모델이 학습 데이터의 본질적인 패턴을 충분히 학습하도록 설계$\cdot$최적화할 수 있다.</p>
  </li>
  <li>
    <p>Underfitting 방지 방법</p>

    <table>
      <thead>
        <tr>
          <th>항목</th>
          <th>방법</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>모델 구조 개선</td>
          <td>더 깊거나 복잡한 모델 사용, 비선형 활성화 함수 활용, 적절한 네트워크 아키텍처 선택</td>
        </tr>
        <tr>
          <td>데이터 활용 최적화</td>
          <td>더 많은 데이터 확보, Data Augmentation(데이터 증강)기법 활용, 데이터 전처리 개선</td>
        </tr>
        <tr>
          <td>학습 설정 조정</td>
          <td>적절한 학습률 설정, 충분한 학습 반복(Epoch 증가), 적절한 최적화 기법 선택</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h2 id="오늘의-회고">오늘의 회고</h2>
<ul>
  <li>Pre-Trained Model을 중심으로 모델을 사용하는 과정을 학습하였다. 현대 AI Engineer의 기본 소양은 잘 정제되어 있는 Model을 이용하는 것이다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="6th Week" /><category term="python" /><category term="tensorflow" /><category term="pytorch" /><summary type="html"><![CDATA[한 줄 정리]]></summary></entry><entry><title type="html">카카오테크부트캠프 해커톤 review</title><link href="https://thplus.github.io/project/ktb/hackathon/" rel="alternate" type="text/html" title="카카오테크부트캠프 해커톤 review" /><published>2025-02-28T00:00:00+00:00</published><updated>2025-02-28T00:00:00+00:00</updated><id>https://thplus.github.io/project/ktb/hackathon</id><content type="html" xml:base="https://thplus.github.io/project/ktb/hackathon/"><![CDATA[<h2 id="해커톤-소개">해커톤 소개</h2>
<ul>
  <li>
    <p>이번 해커톤 기간은 25.02.26(수) ~ 25.02.28(금) 3일간 진행된다.<br />
  하지만 28일 10시에 예선발표가 있으므로 실제 개발할 수 있는 기간은 2일 남짓이다.</p>
  </li>
  <li>
    <p>기본적으로 풀스택 2명, 클라우드 2명, AI 2명이 기본 팀 구성이지만 우리 팀은 풀스택 인원이 구성되지 않은채 클라우드 2명, AI 3명이서 팀이 구성되었다.</p>
  </li>
  <li>
    <p>주제는 LLM을 이용한 서비스</p>
  </li>
  <li>
    <p>어떤 서비스가 되었던 LLM에게 어떠한 정보를 주고 return을 받아 우리 서비스에 입력해야한다.</p>
  </li>
</ul>

<h2 id="서비스-소개">서비스 소개</h2>
<ul>
  <li>
    <p>우리는 알 수 없는 알고리즘에 파묻혀 살고 있다. 하루에도 알 수 없는 알고리즘이 우리를 이끈다. 우리는 이 영상을 왜 보는지, 이 노래를 왜 듣고 있는지 알 수 없는 일이 대부분이다. 이번 서비스는 알 수 있는 알고리즘 즉, 내가 이 노래를 왜 추천 받았는지 사용자가 알 수 있도록 하는 것이다.</p>

    <p><img src="/assets/images/hackathon_2.png" alt="alt text" /></p>
  </li>
  <li>
    <p>사람들은 노래 추천을 받을 때, 장소, 기분, 날씨 등을 입력하기 마련이다. 예를 들어 ‘우울할 때 듣기 좋은 노래’, ‘비오는 날 듣기 좋은 노래’, 한강에서 듣기 좋은 노래’ 등으로 검색해보면 그에 맞게 노래 리스트를 만들어 놓았으며 수요 또한 많이 있는 걸 확인할 수 있다.</p>
  </li>
  <li>
    <p>이뿐만 아니라 ‘마이너한 감성’을 꼭 선택하는 사람도 있다. 시간을 돌이켜 보면 ‘혁오 밴드’나 ‘잔나비’ 같은 가수들이 공중파 TV에 나왔을 때, 확인할 수 있던 반응을 생각해보면 ‘아… 나만 알고 있는 밴드였는데…’ 등이 많았다. 이러한 뜻은 메이저한 감성보다는 마이너한 감성을 찾는 수요도 많다는 뜻이다.</p>

    <p><img src="/assets/images/hackathon_3.png" alt="alt text" /></p>
  </li>
  <li>
    <p>위와 같이 <strong>장소, 기분, 날씨, 감성의 모든 조화(Harmony)</strong>를 충족시키며 <strong>노래(Harmony)</strong>와 <strong>AI 추천 서비스</strong>를 합쳐 <strong>HarmonAI</strong>라는 이름이 탄생했다.</p>

    <p><img src="/assets/images/hackathon_4.png" alt="alt text" /></p>
  </li>
  <li>
    <p>HarmonAI가 원하는 User eXperience는 추천받은 노래로 ‘아… 이 기분, 장소, 날씨 그리고… 감성까지’라는 말이 나오는 것이다.</p>

    <p><img src="/assets/images/hackathon_5.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="서비스-데모">서비스 데모</h3>
<p><img src="/assets/images/hackathon_6.png" alt="alt text" />
<img src="/assets/images/hackathon_7.png" alt="alt text" />
<img src="/assets/images/hackathon_8.png" alt="alt text" /></p>

<h2 id="flowchart">FlowChart</h2>

<ul>
  <li>
    <p>우리 팀은 음악 추천 서비스를 하기로 하였다. 우리가 구상한 FlowChart는 아래와 같다.</p>

    <p><img src="/assets/images/hackathon_1.png" alt="alt text" /></p>
  </li>
  <li>
    <p>AI 팀의 주 목적은 프롬프트 엔지니어링과 FastAPI로 ChatGPT가 추천해준 가수와 노래 제목을 백엔드로 전달하는 역할이다.</p>
  </li>
  <li>
    <p>하지만 우리는 백엔드 개발자가 없으므로 대부분의 API를 Python으로 구축하여 프롬프트 엔지니어링 후 백엔드로 전달하기로 하였다.</p>
  </li>
</ul>

<h2 id="mainpy-fastapi-설계">main.py (FastAPI 설계)</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">location</span> <span class="kn">import</span> <span class="n">GetLocation</span>
<span class="kn">from</span> <span class="nn">wheather</span> <span class="kn">import</span> <span class="n">Wheather</span>
<span class="kn">from</span> <span class="nn">recommend_songs</span> <span class="kn">import</span> <span class="n">Recommend_songs</span>

<span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">RequestData</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
    <span class="n">latitude</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">longitude</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">query</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">pop</span><span class="p">:</span> <span class="nb">int</span>

<span class="k">class</span> <span class="nc">ResponseData</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
    <span class="n">title</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">artist</span><span class="p">:</span> <span class="nb">str</span>

<span class="k">class</span> <span class="nc">RecommendationResponse</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
    <span class="n">recommendations</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">ResponseData</span><span class="p">]</span>

<span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">"/api/music/recommend"</span><span class="p">,</span> <span class="n">response_model</span> <span class="o">=</span> <span class="n">RecommendationResponse</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">response_process</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">RequestData</span><span class="p">):</span>
    
    <span class="n">loca</span> <span class="o">=</span> <span class="n">GetLocation</span><span class="p">(</span><span class="n">data</span><span class="p">).</span><span class="n">convert_coordinates_to_address</span><span class="p">()</span>
    <span class="n">now_whea</span> <span class="o">=</span> <span class="n">Wheather</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">loca</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="n">sep</span> <span class="o">=</span> <span class="s">" "</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">loca</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="n">sep</span> <span class="o">=</span> <span class="s">" "</span><span class="p">)[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="n">playlist</span> <span class="o">=</span> <span class="n">Recommend_songs</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
    <span class="n">my_musics</span> <span class="o">=</span> <span class="n">playlist</span><span class="p">.</span><span class="n">recommend</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">loca</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">now_whea</span><span class="p">.</span><span class="n">get_sky</span><span class="p">()</span><span class="si">}</span><span class="s">"</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> 
    <span class="p">{</span><span class="s">"configurable"</span><span class="p">:</span> <span class="p">{</span><span class="s">"thread_id"</span><span class="p">:</span> <span class="s">"Censored"</span><span class="p">}},</span> <span class="s">"Korean"</span><span class="p">)</span>

    <span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">my_musics</span><span class="p">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">columns</span><span class="o">=</span><span class="p">[</span><span class="s">'artist'</span><span class="p">,</span> <span class="s">'title'</span><span class="p">])</span>
    <span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[[</span><span class="s">'title'</span><span class="p">,</span> <span class="s">'artist'</span><span class="p">]]</span>
    <span class="n">songs_list</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="n">to_dict</span><span class="p">(</span><span class="n">orient</span> <span class="o">=</span> <span class="s">'records'</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">JSONResponse</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="p">{</span><span class="s">"recommendations"</span><span class="p">:</span> <span class="n">songs_list</span><span class="p">})</span>
</code></pre></div></div>

<ul>
  <li>
    <p>백엔드와 Json형식으로 주고 받기로 하였다. 해당 규약으로 RequestData class를 짰다. 위도, 경도, 기분, temperature 순이다.</p>
  </li>
  <li>
    <p>우리가 보낼 ResponseData는 제목, 가수 순이다. 하지만 백엔드와의 규약으로 <code class="language-plaintext highlighter-rouge">recommendations</code> 안에 Json형태로 보내야하기 때문에 <code class="language-plaintext highlighter-rouge">List</code>형식으로 다시 묶었다.</p>
  </li>
</ul>

<h2 id="locationpy-위도-경도--지번-주소">location.py (위도, 경도 → 지번 주소)</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">GetLocation</span><span class="p">:</span>
  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">load_dotenv</span><span class="p">()</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">google_map_key</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"GOOLEMAPS_API"</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">convert_coordinates_to_address</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="s">"""
    입력받은 위도, 경도를 도로명 주소 및 지번 주소로 변환하여 반환
    """</span>
    <span class="n">data_dict</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="nb">dict</span><span class="p">()</span>  <span class="c1"># Pydantic 모델을 dict로 변환
</span>    <span class="n">lat</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">data_dict</span><span class="p">[</span><span class="s">"latitude"</span><span class="p">])</span>
    <span class="nb">long</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">data_dict</span><span class="p">[</span><span class="s">"longitude"</span><span class="p">])</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">gmaps</span> <span class="o">=</span> <span class="n">googlemaps</span><span class="p">.</span><span class="n">Client</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="p">.</span><span class="n">google_map_key</span><span class="p">)</span>
    <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">gmaps</span><span class="p">.</span><span class="n">reverse_geocode</span><span class="p">((</span><span class="n">lat</span><span class="p">,</span> <span class="nb">long</span><span class="p">),</span> <span class="n">language</span><span class="o">=</span><span class="s">"ko"</span><span class="p">)</span>  <span class="c1"># language="ko" 추가!
</span>    <span class="k">return</span> <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">'formatted_address'</span><span class="p">]</span>
</code></pre></div></div>

<ul>
  <li>
    <p>API 키는 기본적으로 <code class="language-plaintext highlighter-rouge">.env</code>로 숨겨서 처리하였다.</p>
  </li>
  <li>
    <p>우리는 지오코딩의 기능을 이용할 것이므로 <a href="https://developers.google.com/maps/documentation/javascript/geocoding?hl=ko">해당 링크</a>를 참조하면 된다.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  results[]: {
  types[]: string,
  formatted_address: string,
  address_components[]: {
  short_name: string,
  long_name: string,
  postcode_localities[]: string,
  types[]: string
  },
  partial_match: boolean,
  place_id: string,
  postcode_localities[]: string,
  geometry: {
  location: LatLng,
  location_type: GeocoderLocationType
  viewport: LatLngBounds,
  bounds: LatLngBounds
  }
  }
</code></pre></div>    </div>
  </li>
  <li>
    <p>우리가 필요한 건 <code class="language-plaintext highlighter-rouge">formatted_address</code>이고 나머지는 wheather에서 처리한다.</p>
  </li>
</ul>

<h2 id="wheatherpy-지번-주소--날씨">wheather.py (지번 주소 → 날씨)</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Wheather</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">si</span><span class="p">,</span> <span class="n">gu</span><span class="p">):</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_excel</span><span class="p">(</span><span class="s">'./location_grids.xlsx'</span><span class="p">)</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">serviceKey</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"WEATHER_API"</span><span class="p">)</span>
        <span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">.</span><span class="n">now</span><span class="p">()</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">base_date</span> <span class="o">=</span> <span class="n">now</span><span class="p">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%Y%m%d"</span><span class="p">)</span>
        <span class="n">base_time</span> <span class="o">=</span> <span class="n">now</span><span class="p">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%H%M"</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">si</span> <span class="o">=</span> <span class="n">si</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">gu</span> <span class="o">=</span> <span class="n">gu</span>
        <span class="n">grid</span> <span class="o">=</span> <span class="n">data</span><span class="p">[(</span><span class="n">data</span><span class="p">[</span><span class="s">'1단계'</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="p">.</span><span class="n">si</span><span class="p">)</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">'2단계'</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="p">.</span><span class="n">gu</span><span class="p">)]</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">grid</span><span class="p">.</span><span class="n">empty</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">nx</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">grid</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">'격자 X'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">ny</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">grid</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">'격자 Y'</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>

        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">nx</span> <span class="o">=</span> <span class="s">'60'</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">ny</span> <span class="o">=</span> <span class="s">'127'</span>


        <span class="n">input_d</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">.</span><span class="n">strptime</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">base_date</span> <span class="o">+</span> <span class="n">base_time</span><span class="p">,</span> <span class="s">"%Y%m%d%H%M"</span><span class="p">)</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">hours</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span>
        <span class="n">input_datetime</span> <span class="o">=</span> <span class="n">input_d</span><span class="p">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">"%Y%m%d%H%M"</span><span class="p">)</span>

        <span class="n">input_date</span> <span class="o">=</span> <span class="n">input_datetime</span><span class="p">[:</span><span class="o">-</span><span class="mi">4</span><span class="p">]</span>
        <span class="n">input_time</span> <span class="o">=</span> <span class="n">input_datetime</span><span class="p">[</span><span class="o">-</span><span class="mi">4</span><span class="p">:]</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst?serviceKey=</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">serviceKey</span><span class="si">}</span><span class="s">&amp;numOfRows=60&amp;pageNo=1&amp;dataType=json&amp;base_date=</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">base_date</span><span class="si">}</span><span class="s">&amp;base_time=</span><span class="si">{</span><span class="n">base_time</span><span class="si">}</span><span class="s">&amp;nx=</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">nx</span><span class="si">}</span><span class="s">&amp;ny=</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">ny</span><span class="si">}</span><span class="s">"</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">deg_code</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span> <span class="p">:</span> <span class="s">'N'</span><span class="p">,</span> <span class="mi">360</span> <span class="p">:</span> <span class="s">'N'</span><span class="p">,</span> <span class="mi">180</span> <span class="p">:</span> <span class="s">'S'</span><span class="p">,</span> <span class="mi">270</span> <span class="p">:</span> <span class="s">'W'</span><span class="p">,</span> <span class="mi">90</span> <span class="p">:</span> <span class="s">'E'</span><span class="p">,</span> <span class="mf">22.5</span> <span class="p">:</span><span class="s">'NNE'</span><span class="p">,</span>
           <span class="mi">45</span> <span class="p">:</span> <span class="s">'NE'</span><span class="p">,</span> <span class="mf">67.5</span> <span class="p">:</span> <span class="s">'ENE'</span><span class="p">,</span> <span class="mf">112.5</span> <span class="p">:</span> <span class="s">'ESE'</span><span class="p">,</span> <span class="mi">135</span> <span class="p">:</span> <span class="s">'SE'</span><span class="p">,</span> <span class="mf">157.5</span> <span class="p">:</span> <span class="s">'SSE'</span><span class="p">,</span>
           <span class="mf">202.5</span> <span class="p">:</span> <span class="s">'SSW'</span><span class="p">,</span> <span class="mi">225</span> <span class="p">:</span> <span class="s">'SW'</span><span class="p">,</span> <span class="mf">247.5</span> <span class="p">:</span> <span class="s">'WSW'</span><span class="p">,</span> <span class="mf">292.5</span> <span class="p">:</span> <span class="s">'WNW'</span><span class="p">,</span> <span class="mi">315</span> <span class="p">:</span> <span class="s">'NW'</span><span class="p">,</span>
           <span class="mf">337.5</span> <span class="p">:</span> <span class="s">'NNW'</span><span class="p">}</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">pyt_code</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span> <span class="p">:</span> <span class="s">'강수 없음'</span><span class="p">,</span> <span class="mi">1</span> <span class="p">:</span> <span class="s">'비'</span><span class="p">,</span> <span class="mi">2</span> <span class="p">:</span> <span class="s">'비/눈'</span><span class="p">,</span> <span class="mi">3</span> <span class="p">:</span> <span class="s">'눈'</span><span class="p">,</span> <span class="mi">5</span> <span class="p">:</span> <span class="s">'빗방울'</span><span class="p">,</span> <span class="mi">6</span> <span class="p">:</span> <span class="s">'진눈깨비'</span><span class="p">,</span> <span class="mi">7</span> <span class="p">:</span> <span class="s">'눈날림'</span><span class="p">}</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">sky_code</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span> <span class="p">:</span> <span class="s">'맑음'</span><span class="p">,</span> <span class="mi">3</span> <span class="p">:</span> <span class="s">'구름많음'</span><span class="p">,</span> <span class="mi">4</span> <span class="p">:</span> <span class="s">'흐림'</span><span class="p">}</span>

    <span class="k">def</span> <span class="nf">get_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">url</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>

        <span class="n">informations</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
        
        <span class="n">items</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'response'</span><span class="p">,</span> <span class="p">{}).</span><span class="n">get</span><span class="p">(</span><span class="s">'body'</span><span class="p">,</span> <span class="p">{}).</span><span class="n">get</span><span class="p">(</span><span class="s">'items'</span><span class="p">,</span> <span class="p">{}).</span><span class="n">get</span><span class="p">(</span><span class="s">'item'</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">items</span><span class="p">:</span>
            <span class="c1"># raise ValueError("예보 데이터를 가져오지 못했습니다. API 응답: " + json.dumps(res, ensure_ascii=False))
</span>            <span class="k">return</span> <span class="s">"오"</span><span class="p">,</span> <span class="s">"류"</span>
        
        <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
            <span class="n">cate</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s">'category'</span><span class="p">]</span>
            <span class="n">fcstTime</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s">'fcstTime'</span><span class="p">]</span>
            <span class="n">fcstValue</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s">'fcstValue'</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">fcstTime</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">informations</span><span class="p">:</span>
                <span class="n">informations</span><span class="p">[</span><span class="n">fcstTime</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
            <span class="n">informations</span><span class="p">[</span><span class="n">fcstTime</span><span class="p">][</span><span class="n">cate</span><span class="p">]</span> <span class="o">=</span> <span class="n">fcstValue</span>
            
        <span class="n">key</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">informations</span><span class="p">.</span><span class="n">keys</span><span class="p">())[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">val</span> <span class="o">=</span> <span class="n">informations</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span>

    <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">get_info</span><span class="p">()</span>

        <span class="n">template</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"""</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">base_date</span><span class="p">[</span><span class="si">:</span><span class="mi">4</span><span class="p">]</span><span class="si">}</span><span class="s">년 </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">base_date</span><span class="p">[</span><span class="mi">4</span><span class="si">:</span><span class="mi">6</span><span class="p">]</span><span class="si">}</span><span class="s">월 </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">base_date</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="si">:</span><span class="p">]</span><span class="si">}</span><span class="s">일 </span><span class="si">{</span><span class="n">key</span><span class="p">[</span><span class="si">:</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="s">시 </span><span class="si">{</span><span class="n">key</span><span class="p">[</span><span class="mi">2</span><span class="si">:</span><span class="p">]</span><span class="si">}</span><span class="s">분 </span><span class="si">{</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">nx</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">ny</span><span class="p">))</span><span class="si">}</span><span class="s"> 지역의 날씨는 """</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'SKY'</span><span class="p">]:</span>
            <span class="n">sky_temp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">sky_code</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'SKY'</span><span class="p">])]</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="n">sky_temp</span> <span class="o">+</span> <span class="s">" "</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'PTY'</span><span class="p">]</span> <span class="p">:</span>
            <span class="n">pty_temp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">pyt_code</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'PTY'</span><span class="p">])]</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="n">pty_temp</span>
            <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'RN1'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'강수없음'</span> <span class="p">:</span>
                <span class="n">rn1_temp</span> <span class="o">=</span> <span class="n">val</span><span class="p">[</span><span class="s">'RN1'</span><span class="p">]</span>
                <span class="n">template</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">"시간당 </span><span class="si">{</span><span class="n">rn1_temp</span><span class="si">}</span><span class="s">mm "</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'T1H'</span><span class="p">]</span> <span class="p">:</span>
            <span class="n">t1h_temp</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'T1H'</span><span class="p">])</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">" 기온 </span><span class="si">{</span><span class="n">t1h_temp</span><span class="si">}</span><span class="s">℃ "</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'REH'</span><span class="p">]</span> <span class="p">:</span>
            <span class="n">reh_temp</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'REH'</span><span class="p">])</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">"습도 </span><span class="si">{</span><span class="n">reh_temp</span><span class="si">}</span><span class="s">% "</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'VEC'</span><span class="p">]</span> <span class="ow">and</span> <span class="n">val</span><span class="p">[</span><span class="s">'WSD'</span><span class="p">]:</span>
            <span class="n">vec_temp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">deg_to_dir</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'VEC'</span><span class="p">]))</span>
            <span class="n">wsd_temp</span> <span class="o">=</span> <span class="n">val</span><span class="p">[</span><span class="s">'WSD'</span><span class="p">]</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="sa">f</span><span class="s">"풍속 </span><span class="si">{</span><span class="n">vec_temp</span><span class="si">}</span><span class="s"> 방향 </span><span class="si">{</span><span class="n">wsd_temp</span><span class="si">}</span><span class="s">m/s"</span>

        <span class="k">return</span> <span class="n">template</span>

    <span class="k">def</span> <span class="nf">get_sky</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">get_info</span><span class="p">()</span>
        <span class="k">if</span> <span class="n">val</span> <span class="o">==</span> <span class="s">"류"</span><span class="p">:</span>
            <span class="k">return</span> <span class="s">"맑음"</span>
        
        <span class="n">template</span> <span class="o">=</span> <span class="s">""</span>

        <span class="k">if</span> <span class="n">val</span><span class="p">[</span><span class="s">'SKY'</span><span class="p">]:</span>
            <span class="n">sky_temp</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">sky_code</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="s">'SKY'</span><span class="p">])]</span>
            <span class="n">template</span> <span class="o">+=</span> <span class="n">sky_temp</span>

        <span class="k">return</span> <span class="n">template</span>



    <span class="k">def</span> <span class="nf">deg_to_dir</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">deg</span><span class="p">)</span> <span class="p">:</span>
        <span class="n">close_dir</span> <span class="o">=</span> <span class="s">''</span>
        <span class="n">min_abs</span> <span class="o">=</span> <span class="mi">360</span>
        <span class="k">if</span> <span class="n">deg</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">deg_code</span><span class="p">.</span><span class="n">keys</span><span class="p">()</span> <span class="p">:</span>
            <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">deg_code</span><span class="p">.</span><span class="n">keys</span><span class="p">()</span> <span class="p">:</span>
                <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="n">key</span> <span class="o">-</span> <span class="n">deg</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">min_abs</span> <span class="p">:</span>
                    <span class="n">min_abs</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">key</span> <span class="o">-</span> <span class="n">deg</span><span class="p">)</span>
                    <span class="n">close_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">deg_code</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
        <span class="k">else</span> <span class="p">:</span>
            <span class="n">close_dir</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">deg_code</span><span class="p">[</span><span class="n">deg</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">close_dir</span>
</code></pre></div></div>

<ul>
  <li>
    <p>기상청 단기 예보 서비스 API를 기본적으로 사용한다. <a href="https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15084084">해당 링크</a>를 참조하면 된다.</p>
  </li>
  <li>
    <p>기상청에서 제공하는 <code class="language-plaintext highlighter-rouge">location_grid</code>는 3단계로 나누는데, 3단계까지 하면 search하는데 너무 오래 걸리고 날씨라는게 바로 옆동네라고 아주 달라지지 않으니 3단계는 제거하고 사용하였다.</p>
  </li>
  <li>
    <p>1단계는 <code class="language-plaintext highlighter-rouge">si</code>로 받아오고 2단계는 <code class="language-plaintext highlighter-rouge">gu</code>로 받아와 사용하였다.</p>
  </li>
  <li>
    <p>제대로된 주소를 불러오지 못한다면 60, 127 <code class="language-plaintext highlighter-rouge">서울특별시 종로구</code>로 설정하고 기상청API를 못 불러오는 경우가 있는데 이때 날씨는 <code class="language-plaintext highlighter-rouge">맑음</code>으로 return하기로 합의했다.</p>
  </li>
</ul>

<h2 id="recommend_songspy-주소-날씨-query-pop--추천-노래">recommend_songs.py (주소, 날씨, query, pop → 추천 노래)</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Recommend_songs</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">recommended_songs</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>
        <span class="n">load_dotenv</span><span class="p">()</span>
        
        <span class="n">client_id</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"SPOTIPY_CLIENT_ID"</span><span class="p">)</span>
        <span class="n">client_secret</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"SPOTIPY_CLIENT_SECRET"</span><span class="p">)</span>

        <span class="n">client_credentials_manager</span> <span class="o">=</span> <span class="n">SpotifyClientCredentials</span><span class="p">(</span><span class="n">client_id</span><span class="o">=</span><span class="n">client_id</span><span class="p">,</span> <span class="n">client_secret</span><span class="o">=</span><span class="n">client_secret</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">sp</span> <span class="o">=</span> <span class="n">spotipy</span><span class="p">.</span><span class="n">Spotify</span><span class="p">(</span><span class="n">client_credentials_manager</span><span class="o">=</span><span class="n">client_credentials_manager</span><span class="p">)</span>

        <span class="bp">self</span><span class="p">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s">"gpt-4o-mini"</span><span class="p">,</span> <span class="n">model_provider</span><span class="o">=</span><span class="s">"openai"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">recommend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">my_location</span><span class="p">,</span> <span class="n">my_weather</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">config</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
        <span class="n">data_dict</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="nb">dict</span><span class="p">()</span>  <span class="c1"># Pydantic 모델을 dict로 변환
</span>        <span class="n">pop</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data_dict</span><span class="p">[</span><span class="s">"pop"</span><span class="p">])</span>
        <span class="n">query</span> <span class="o">=</span> <span class="n">data_dict</span><span class="p">[</span><span class="s">"query"</span><span class="p">]</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">prompt_template</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="p">.</span><span class="n">from_messages</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="p">(</span>
                    <span class="s">"system"</span><span class="p">,</span>
                    <span class="s">"사용자가 기분을 입력하면 감성을 분석해서 해당 감성에 맞는 장르의 노래를 추천해줘. "</span>
                    <span class="sa">f</span><span class="s">"현재 장소는 </span><span class="si">{</span><span class="n">my_location</span><span class="si">}</span><span class="s">이고 오늘의 날씨는 </span><span class="si">{</span><span class="n">my_weather</span><span class="si">}</span><span class="s">이야. "</span>
                    <span class="sa">f</span><span class="s">"오늘의 장소와 날씨, 그리고 사용자의 감성을 분석해서 어울리는 노래 </span><span class="si">{</span><span class="n">target</span> <span class="o">*</span> <span class="mi">2</span><span class="si">}</span><span class="s">개를 추천해줘. "</span>
                    <span class="s">"사용자의 언어를 고려하여 해당 언어가 속한 국가의 노래 위주로 70%, "</span>
                    <span class="s">"이외 글로벌한 국가에 대해 30% 비중으로 노래를 추천해줘. "</span>
                    <span class="s">"출력 형식은 반드시 JSON이어야 하며, 자연어는 출력하지 마. "</span>
                    <span class="s">"아티스트나 노래 제목에 쌍따옴표가 있는 경우 작은따옴표로 변환해서 출력해줘."</span>
                    <span class="s">"출력 형식 예시는 다음과 같아: "</span>
                    <span class="s">'iu. '</span>
                    <span class="s">"반드시 Spotify에서 검색 가능한 공식 아티스트명과 곡 제목을 사용해줘."</span>
                <span class="p">),</span>
                <span class="n">MessagesPlaceholder</span><span class="p">(</span><span class="n">variable_name</span><span class="o">=</span><span class="s">"messages"</span><span class="p">),</span>
            <span class="p">]</span>
            <span class="p">)</span>
        <span class="k">class</span> <span class="nc">State</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
            <span class="n">messages</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="n">BaseMessage</span><span class="p">],</span> <span class="n">add_messages</span><span class="p">]</span>
            <span class="n">language</span><span class="p">:</span> <span class="nb">str</span>

        <span class="k">class</span> <span class="nc">CustomState</span><span class="p">(</span><span class="n">State</span><span class="p">):</span>
            <span class="n">messages</span><span class="p">:</span> <span class="nb">list</span>
            <span class="n">language</span><span class="p">:</span> <span class="nb">str</span>

        <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">recommended_songs</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">target</span><span class="p">:</span>
            <span class="k">def</span> <span class="nf">call_model</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">CustomState</span><span class="p">):</span>
                <span class="n">prompt</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">prompt_template</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span>
                    <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="n">state</span><span class="p">[</span><span class="s">"messages"</span><span class="p">],</span> <span class="s">"language"</span><span class="p">:</span> <span class="n">state</span><span class="p">[</span><span class="s">"language"</span><span class="p">]}</span>
                <span class="p">)</span>
                <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
                <span class="k">return</span> <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="n">response</span><span class="p">}</span>

            <span class="n">workflow</span> <span class="o">=</span> <span class="n">StateGraph</span><span class="p">(</span><span class="n">state_schema</span><span class="o">=</span><span class="n">CustomState</span><span class="p">)</span>
            <span class="n">workflow</span><span class="p">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">START</span><span class="p">,</span> <span class="s">"model"</span><span class="p">)</span>
            <span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"model"</span><span class="p">,</span> <span class="n">call_model</span><span class="p">)</span>

            <span class="n">app</span> <span class="o">=</span> <span class="n">workflow</span><span class="p">.</span><span class="nb">compile</span><span class="p">()</span>

            <span class="n">input_messages</span> <span class="o">=</span> <span class="p">[</span><span class="n">HumanMessage</span><span class="p">(</span><span class="n">query</span><span class="p">)]</span>
            <span class="n">output</span> <span class="o">=</span> <span class="n">app</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span>
                <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="n">input_messages</span><span class="p">,</span> <span class="s">"language"</span><span class="p">:</span> <span class="n">language</span><span class="p">}</span>
            <span class="p">)</span>

            <span class="n">music_dict</span> <span class="o">=</span> <span class="n">output</span><span class="p">[</span><span class="s">"messages"</span><span class="p">].</span><span class="n">content</span>
            <span class="n">music_dict</span> <span class="o">=</span> <span class="n">music_dict</span><span class="p">.</span><span class="n">replace</span><span class="p">(</span><span class="s">"'"</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">music_dict</span><span class="p">:</span>
                <span class="k">continue</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">music_dict</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">loads</span><span class="p">(</span><span class="n">music_dict</span><span class="p">)</span>
            <span class="k">except</span><span class="p">:</span>
                <span class="k">continue</span>

            <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">music_dict</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
                <span class="n">artist</span><span class="p">,</span> <span class="n">track</span> <span class="o">=</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span>
                <span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">artist</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="n">track</span><span class="si">}</span><span class="s">"</span>  <span class="c1"># 아티스트 + 곡 제목 검색
</span>                <span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">sp</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="n">q</span><span class="o">=</span><span class="n">query</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s">"track"</span><span class="p">,</span> <span class="n">limit</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

                <span class="k">try</span><span class="p">:</span>
                    <span class="n">track_popularity</span> <span class="o">=</span> <span class="n">results</span><span class="p">[</span><span class="s">"tracks"</span><span class="p">][</span><span class="s">"items"</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">"popularity"</span><span class="p">]</span>
                    <span class="k">if</span> <span class="n">track_popularity</span> <span class="o">&lt;=</span> <span class="n">pop</span><span class="p">:</span>
                        <span class="bp">self</span><span class="p">.</span><span class="n">recommended_songs</span><span class="p">[</span><span class="n">artist</span><span class="p">]</span> <span class="o">=</span> <span class="n">track</span>

                    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">recommended_songs</span><span class="p">)</span> <span class="o">==</span> <span class="n">target</span><span class="p">:</span>
                        <span class="k">break</span>
                <span class="k">except</span><span class="p">:</span>
                    <span class="k">continue</span>
        
        <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">recommended_songs</span>
</code></pre></div></div>

<ul>
  <li>
    <p>프롬프트 엔지니어링은 엔지니어링은 위와 같이 한 것을 알 수 있으며</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">pop</code>으로 불러 온 Temperature 점수를 spotipyAPI로 검증하는 과정을 볼 수 있다.</p>
  </li>
</ul>

<h2 id="local-실행-결과">Local 실행 결과</h2>

<ul>
  <li>
    <p>전달</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      -H "Content-Type: application/json" \
      -d '{
          "latitude": 37.5665,
          "longitude": 126.9780,
          "question": "기분 좋은 노래 추천",
          "pop": 5
          }'
</code></pre></div>    </div>
  </li>
  <li>출력
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  {
      "recommendations": [
          {
              "artist": "아이유",
              "title": "좋은 날"
          },
          {
              "artist": "블랙핑크",
              "title": "Lovesick Girls"
          },
          {
              "artist": "백예린",
              "title": "우주를 건너"
          },
          {
              "artist": "적재",
              "title": "나쁜 사람"
          },
          {
              "artist": "키아라",
              "title": "Gold"
          }
      ]
  }
</code></pre></div>    </div>
  </li>
  <li>정상적으로 출력되는 것을 확인할 수 있었으며 Temperature 점수가 절반(<code class="language-plaintext highlighter-rouge">pop = 5</code>)정도면 5곡 중 2곡 정도가 유명하지 않은 노래로 확인되었다.</li>
</ul>

<h2 id="발전-방향">발전 방향</h2>

<ul>
  <li>
    <p>Spotify API를 사용한 김에 Spotify로 노래 리스트를 뽑으려 했지만 Spotify가 유료라 할 순 없었다. 나중에 Frontend 측에서 Spotify로 로그인 할 수 있게 하면 연동하여 나만의 추천 리스트를 만들 수 있을 것이다.</p>
  </li>
  <li>
    <p>위와 같은 사항으로 YouTube API를 사용하였는데, YouTube API 정책상 play버튼만 만들어 노래를 재생할 수 없다. 따라서 링크로 대체하였는데 이 또한 유료 계정이 있으면 해결할 수 있다. 나중에 Spotify로 바꾼다면 이 걱정은 없어질 것이다.</p>
  </li>
</ul>

<h2 id="회고">회고</h2>

<ul>
  <li>풀스택 인원이 없는 상태에서 2일이라는 짧은 시간동안 밤 세워가며 배포까지 완료해보았다. 실제 테스트 결과 아주 잘 나왔으며 풀스택 인원이 있다면 좀 더 수월하지 않았을까 생각한다. 다른 팀에 비해서 조금 완성도가 떨어진 감이 있지만 이번 해커톤의 목표는 MVP모델이었고 인원도 부족한 상태에서 상당히 만족한 결과가 나왔다.<br />
 첫 목표는 완성이었지만 어떨결에 본선까지 진출했다. 상을 타면 더 좋았겠지만 아쉽게 수상하지는 못했다. 해커톤이 끝난 후로 서비스를 종료하였지만 아주 좋은 경험이었다. 해커톤이 왜 필요한지 협업이 왜 중요한지 제대로 알 수 있는 기회였다.<br />
 인원이 부족한 상태에서도 서로 그때 그때 공부하면서 디버깅하였다. 같이 밤 세워가며 배포까지 무사히 마칠 수 있도록 도와준 팀원들에게 감사하다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Project" /><category term="KTB" /><category term="python" /><category term="langchain" /><category term="fastapi" /><summary type="html"><![CDATA[해커톤 소개 이번 해커톤 기간은 25.02.26(수) ~ 25.02.28(금) 3일간 진행된다. 하지만 28일 10시에 예선발표가 있으므로 실제 개발할 수 있는 기간은 2일 남짓이다.]]></summary></entry><entry><title type="html">CNN</title><link href="https://thplus.github.io/today%20i%20learn/5th%20week/cnn/" rel="alternate" type="text/html" title="CNN" /><published>2025-02-24T00:00:00+00:00</published><updated>2025-02-24T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/5th%20week/cnn</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/5th%20week/cnn/"><![CDATA[<h2 id="한-줄-정리">한 줄 정리</h2>

<table>
  <thead>
    <tr>
      <th> </th>
      <th>한 줄 정리</th>
      <th>비고</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><a href="#fully-connected-neural-network완전-연결-신경망">FCNN</a></td>
      <td>모든 노드들이 이전 노드들과 연결된 신경망 구조</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#backpropagation오차-역전파">역전파</a></td>
      <td>순전파의 반대 방향으로 Gradient를 계산하는 과정</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#optimizer옵티마이저">옵티마이저</a></td>
      <td>Loss Function의 최소값을 찾아가는 알고리즘</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#기울기-소실vanishing-gradient">기울기 소실</a></td>
      <td>역전파를 통해 계산한 기울기를 곱하다보면 gradient 값이 너무 작아 0으로 수렴하는 것</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#adamadaptive-moment-estimation">Adam</a></td>
      <td>딥러닝에서 널리 사용되는 optimizer로 학습 과정에서 파라미터를 자동으로 조정한다는 특징이 있다.</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#convolutional-neural-network-cnn-합성곱-인공신경망">CNN</a></td>
      <td>합성곱 인공 신경망으로 2D tensor 이상의 입력 데이터에서 특징을 추출하는데 용이하다.</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#convolutional-layer합성곱-계층">합성곱 계층</a></td>
      <td>CNN에서 filter를 사용해 입력 데이터의 특징을 추출하는 계층이다.</td>
      <td> </td>
    </tr>
    <tr>
      <td><a href="#pooling-layer풀링-계층">풀링 계층</a></td>
      <td>합성곱 계층에서 나온 주요 특징을 압축하는 과정이다.</td>
      <td> </td>
    </tr>
  </tbody>
</table>

<h2 id="딥러닝">딥러닝</h2>
<h3 id="activation-function비선형-활성화-함수">Activation Function(비선형 활성화 함수)</h3>
<ul>
  <li>
    <p>인공신경망에서 뉴런의 출력을 결정하는 비선형 함수이다.</p>
  </li>
  <li>
    <p>$f =$ weighted sum, $g = $ activation function<br />
  $h(x) = f(g(x))$<br />
  $h’(x) = f’(g(x))\cdot g’(x)$<br />
  노드가 입력신호를 받아 가중합을 계산한 후 이를 비선형 함수에 적용하여 최종 출력을 생성하는 역할</p>
  </li>
</ul>

<h4 id="sigmoid시그모이드">Sigmoid(시그모이드)</h4>
<ul>
  <li>
    <p>시그모이드 함수는 모든 입력 값을 0과 1 사이로 매핑하는 S자 형태의 함수이다.</p>
  </li>
  <li>
    <p>$\sigma(x) = \frac{1}{1+e^{-x}}$<br /></p>

    <p><img src="/assets/images/sigmoid.png" alt="alt text" /></p>
  </li>
</ul>

<h4 id="hyperbolic-tangent-tanh하이퍼볼릭-탄젠트">Hyperbolic Tangent, tanh(하이퍼볼릭 탄젠트)</h4>
<ul>
  <li>
    <p>시그모이드 함수와 유사한 S자 형태의 함수로 모든 입력 값을 -1과 1사이로 매핑한다.</p>

    <p>\(\tanh(x) = \frac{\sinh(x)}{\cosh(x)} = \frac{e^x-e^{-x}}{e^x+e^{-x}} = \frac{e^{2x}-1}{e^{2x}+1}\)
  <br /></p>

    <p><img src="/assets/images/tanh.png" alt="alt text" /></p>
  </li>
</ul>

<h4 id="rectified-linear-unit-relu렐루">Rectified Linear Unit, ReLU(렐루)</h4>
<ul>
  <li>
    <p>“고르게 한다.”는 뜻의 Rectified와 “직선” Linear로 결합된 힘수로 입력이 0 보다 작으면 0이 출력되고 입력이 0 이상이면 출력이 입력과 동일해지는 함수이다.</p>
  </li>
  <li>
    <p>$ReLU(x) = Max (0, x)$<br />
  <img src="/assets/images/ReLU.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="artificial-neural-network인공-신경망">Artificial Neural Network(인공 신경망)</h3>
<ul>
  <li>
    <p>인공신경망은 머신러닝과 인지 과학에서 사용되어 패턴 인식과 문제 해결 능력을 갖구헤나는 뇌의 뉴런 네트워크를 모방한 알고리즘이다.<br />
  <img src="/assets/images/ANN.png" alt="alt text" /></p>
  </li>
  <li>
    <p>ANN의 기본 동작 구조
  <img src="/assets/images/ANN_arch.png" alt="alt text" /></p>
  </li>
  <li>
    <p>Feed-Forward(순방향 전파)<br />
 인공신경망에서 입력 데이터를 출력으로 변환하는 과정을 말한다. 입력 데이터를 받아서 은닉층과 출력층을 거쳐 출력을 생성하는 과정을 포함한다.</p>
  </li>
  <li>
    <p>Loss Function(손실 함수)<br />
 출력층에서 예측된 출력값과 실제 정답을 비교하여 손실(Loss)값을 계산한다.<br />
  $|Y - \hat Y|$</p>
  </li>
  <li>
    <p>Backpropagation(오차 역전파)<br />
 계산된 손실 값을 기반으로 손실을 줄이기 위해 각 가중치에 대한 기울기를 계산한다. 이 과정은 출력 방향의 역방향으로 진행되며 각 층의 가중치에 대한 기울기를 계산한다.</p>
  </li>
</ul>

<h3 id="fully-connected-neural-network완전-연결-신경망">Fully Connected Neural Network(완전 연결 신경망)</h3>
<ul>
  <li>FCNN은 모든 뉴런이 이전 층의 모든 뉴런과 연결된 신경망 구조이다. 입력 데이터의 모든 특징을 활용하여 복잡한 패턴을 학습하고 예측하는데 효과적이다.</li>
</ul>

<ol>
  <li>라이브러리</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">torch</span>
<span class="kn">import</span> <span class="nn">torch.nn</span> <span class="k">as</span> <span class="n">nn</span>
<span class="kn">import</span> <span class="nn">torch.optim</span> <span class="k">as</span> <span class="n">optim</span>
<span class="kn">from</span> <span class="nn">torch.utils.data</span> <span class="kn">import</span> <span class="n">DataLoader</span><span class="p">,</span> <span class="n">TensorDataset</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
</code></pre></div></div>

<ol>
  <li>데이터 준비</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">input_dim</span> <span class="o">=</span> <span class="mi">20</span>
<span class="n">num_classes</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">X_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="n">input_dim</span><span class="p">).</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">float32</span><span class="p">)</span>
<span class="n">y_train</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randint</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">1000</span><span class="p">).</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int64</span><span class="p">)</span>
<span class="n">X_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">rand</span><span class="p">(</span><span class="mi">200</span><span class="p">,</span> <span class="n">input_dim</span><span class="p">).</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">float32</span><span class="p">)</span>
<span class="n">y_test</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">randint</span><span class="p">(</span><span class="n">num_classes</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">200</span><span class="p">).</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int64</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">train_dataset</span> <span class="o">=</span> <span class="n">TensorDataset</span><span class="p">(</span><span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">X_train</span><span class="p">),</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">y_train</span><span class="p">))</span>
<span class="n">test_dataset</span> <span class="o">=</span> <span class="n">TensorDataset</span><span class="p">(</span><span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">X_test</span><span class="p">),</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">y_test</span><span class="p">))</span>
<span class="n">train_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">train_dataset</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">test_loader</span> <span class="o">=</span> <span class="n">DataLoader</span><span class="p">(</span><span class="n">test_dataset</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">32</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</code></pre></div></div>

<ol>
  <li>모델 정의</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">FCNN</span><span class="p">(</span><span class="n">nn</span><span class="p">.</span><span class="n">Module</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_dim</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">FCNN</span><span class="p">,</span> <span class="bp">self</span><span class="p">).</span><span class="n">__init__</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">fc1</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="n">input_dim</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">fc2</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="mi">64</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">fc3</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">Linear</span><span class="p">(</span><span class="mi">64</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">forward</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">relu</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">fc1</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">relu</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">fc2</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
        <span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">fc3</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">x</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">FCNN</span><span class="p">(</span><span class="n">input_dim</span><span class="p">,</span> <span class="n">num_classes</span><span class="p">)</span>
</code></pre></div></div>

<ol>
  <li>Loss Function &amp; Optimizer</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">criterion</span> <span class="o">=</span> <span class="n">nn</span><span class="p">.</span><span class="n">CrossEntropyLoss</span><span class="p">()</span>
<span class="n">optimizer</span> <span class="o">=</span> <span class="n">optim</span><span class="p">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span>
</code></pre></div></div>

<ol>
  <li>Model Train</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">num_epochs</span> <span class="o">=</span> <span class="mi">20</span>

<span class="k">for</span> <span class="n">epoch</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_epochs</span><span class="p">):</span>
    <span class="n">model</span><span class="p">.</span><span class="n">train</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">inputs</span><span class="p">,</span> <span class="n">labels</span> <span class="ow">in</span> <span class="n">train_loader</span><span class="p">:</span>
        <span class="n">optimizer</span><span class="p">.</span><span class="n">zero_grad</span><span class="p">()</span>
        <span class="n">outputs</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">inputs</span><span class="p">)</span>
        <span class="n">loss</span> <span class="o">=</span> <span class="n">criterion</span><span class="p">(</span><span class="n">outputs</span><span class="p">,</span> <span class="n">labels</span><span class="p">)</span>
        <span class="n">loss</span><span class="p">.</span><span class="n">backward</span><span class="p">()</span>
        <span class="n">optimizer</span><span class="p">.</span><span class="n">step</span><span class="p">()</span>

    <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Epoch [</span><span class="si">{</span><span class="n">epoch</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="s">/</span><span class="si">{</span><span class="n">num_epochs</span><span class="si">}</span><span class="s">], Loss: </span><span class="si">{</span><span class="n">loss</span><span class="p">.</span><span class="n">item</span><span class="p">()</span><span class="si">:</span><span class="p">.</span><span class="mi">4</span><span class="n">f</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<ol>
  <li>Evaluation &amp; Predict</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">model</span><span class="p">.</span><span class="nb">eval</span><span class="p">()</span>
<span class="n">correct</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">with</span> <span class="n">torch</span><span class="p">.</span><span class="n">no_grad</span><span class="p">():</span>
    <span class="k">for</span> <span class="n">inputs</span><span class="p">,</span> <span class="n">labels</span> <span class="ow">in</span> <span class="n">test_loader</span><span class="p">:</span>
        <span class="n">outputs</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">inputs</span><span class="p">)</span>
        <span class="n">_</span><span class="p">,</span> <span class="n">predicted</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">outputs</span><span class="p">.</span><span class="n">data</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
        <span class="n">total</span> <span class="o">+=</span> <span class="n">labels</span><span class="p">.</span><span class="n">size</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
        <span class="n">correct</span> <span class="o">+=</span> <span class="p">(</span><span class="n">predicted</span> <span class="o">==</span> <span class="n">labels</span><span class="p">).</span><span class="nb">sum</span><span class="p">().</span><span class="n">item</span><span class="p">()</span>

<span class="n">accuracy</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="n">correct</span> <span class="o">/</span> <span class="n">total</span>
<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Test Accuracy: </span><span class="si">{</span><span class="n">accuracy</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="s">%"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sample_input</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">tensor</span><span class="p">(</span><span class="n">X_test</span><span class="p">[:</span><span class="mi">5</span><span class="p">])</span>
<span class="n">predictions</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">sample_input</span><span class="p">)</span>
<span class="n">_</span><span class="p">,</span> <span class="n">predicted_classes</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="nb">max</span><span class="p">(</span><span class="n">predictions</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Predicted classes: "</span><span class="p">,</span> <span class="n">predicted_classes</span><span class="p">.</span><span class="n">numpy</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="s">"True classes: "</span><span class="p">,</span> <span class="n">y_test</span><span class="p">[:</span><span class="mi">5</span><span class="p">])</span>
</code></pre></div></div>

<h3 id="fully-connected-layer완전-연결-계층">Fully Connected Layer(완전 연결 계층)</h3>
<ul>
  <li>인공 신경망에서 모든 입력 뉴런이 모든 출력 뉴런과 연결된 레이어로 Hidden Layer와 Output Layer가 Fully Connected Layer 부분이라고 생각할 수 있다. 이러한 구조는 데이터의 모든 특징을 종합적으로 분석하고 학습하는데 중요한 역할을 한다.</li>
</ul>

<h3 id="loss-function손실-함수">Loss Function(손실 함수)</h3>
<ul>
  <li>
    <p>손실 함수는 인공신경망이나 기타 머신러닝 모델에서 예측갑과 실제 값 간의 차이를 정량적으로 측정하는 함수이다. 손실함수는 모델이 얼마나 정확한 예측을 하고 있는지를 평가하는데 사용되며 예측 오차를 최소화하는 방향으로 모델을 학습시키기 위한 중요한 역할을 한다.</p>
  </li>
  <li>
    <p>손실 함수의 종류</p>
    <ol>
      <li>회귀(Regression) 문제
        <ol>
          <li>
            <p>평균제곱오차(MSE, Mean Squared Error)<br />
 예측 값과 실제 값의 차이를 제곱한 후 평균을 구하는 손실 함수, 오차가 클 수록 영향이 크다.</p>
          </li>
          <li>
            <p>평균절대오차(MAE)<br />
 예측 값과 실제 값의 차이의 절대값을 평균 내는 손실 함수 이다. 단순히 예측이 실제 값에서 얼마나 벗어났는지를 평균으로 평가</p>
          </li>
        </ol>
      </li>
      <li>분류(Classification) 문제
        <ol>
          <li>
            <p>Cross-Entropy Loss (크로스 엔트로피 손실)<br />
 확률 분포 간 차이를 측정하며 분류 문제에서 예측 확률과 실제 정답 간의 차이를 최소화하는 손실 함수이다. 모델이 정답을 맞출 확률이 높을수록 손실이 작아지고 틀릴 확률이 높을수록 손실이 커진다.</p>
          </li>
          <li>
            <p>Hinge Loss (힌지 손실) <br />
 주로 Support Vector Machine에서 사용되는 손실 함수로 정답과 예측 값 사이의 마진을 기반으로 손실을 계산한다.</p>
          </li>
        </ol>
      </li>
    </ol>
  </li>
</ul>

<h3 id="backpropagation오차-역전파">Backpropagation(오차 역전파)</h3>
<ul>
  <li>
    <p>Neural Network에서 출력값과 실제값 간의 오차를 기분으로 각 뉴런의 weight를 조정하기 위해 사용하는 알고리즘이다.</p>
  </li>
  <li>
    <p>Backpropagation은 Loss Function에 대한 가중치의 기울기(Gradient)를 계산하는 과정이다. 실제 가중치를 조정하는 것은 Optimizer의 역할이다.</p>
  </li>
  <li>
    <p>Backpropagation에서 Gradient를 계산하기 위해 Chain Rule를 이용한다.
  <img src="/assets/images/chainrule.png" alt="alt text" /></p>
  </li>
</ul>

<h3 id="optimizer옵티마이저">Optimizer(옵티마이저)</h3>
<ul>
  <li>
    <p>딥러닝 모델의 손실 함수를 최소화하기 위해 기울기를 기반으로 가중치를 업데이트 하는 알고리즘으로 손실함수를 최소화하도록 가중치를 조정하기 위해 사용한다.</p>
  </li>
  <li>
    <p>Gradient Descent : 가장 기본적인 옵티마이저로 딥러닝 모델의 학습 과정에서 손실 함수를 최소화하기 위해 사용되는 대표적인 알고리즘이다.<br />
  ex. Batch Gradient Descent, Stochastic Gradient Descent, Mini-batch Gradient Descent</p>
  </li>
  <li>
    <p>Adaptive Optimizers : 학습률을 동적으로 조정하여 학습 효율을 높여주는 옵티마이저이다. <br />
  ex. Adagrad, RMSprop, Adam(Adaptive Moment Estimation)</p>
  </li>
  <li>
    <p>Momentum Optimizers : 기울기 벡터의 지수 이동평균을 사용하여 가중치를 업데이트한다. 지수 이동 평균은 기울기 벡터의 변동성을 줄여주기 때문에 SGD의 단점을 보완할 수 있다.
  ex. NAG(Mesterov Acceleated Gradient)</p>
  </li>
  <li>
    <p>Pytorch에서 옵티마이저 선택</p>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1"># SGD 옵티마이저 선택 및 학습률 설정
</span>  <span class="n">optimizer</span> <span class="o">=</span> <span class="n">optim</span><span class="p">.</span><span class="n">SGD</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">0.01</span><span class="p">)</span>

  <span class="c1"># Adam 옵티마이저 사용 예시
</span>  <span class="n">optimizer</span> <span class="o">=</span> <span class="n">optim</span><span class="p">.</span><span class="n">Adam</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">parameters</span><span class="p">(),</span> <span class="n">lr</span><span class="o">=</span><span class="mf">0.001</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
</ul>

<h3 id="gradient-descent">Gradient Descent</h3>
<ul>
  <li>Gradient Descent는 머신러닝과 딥러닝에서 손실 함수를 최소화하기 위해 가중치를 반복적으로 조정하는 최적화 알고리즘</li>
</ul>

<h4 id="기울기-소실vanishing-gradient">기울기 소실(Vanishing Gradient)</h4>
<ul>
  <li>
    <p>Activation Function의 기울기 값이 계속 곱해지다 보면 weight에 따른 결과값의 기울기가 0에 가까워져 weight를 변경할 수 없게 되는 현상을 말한다.</p>
  </li>
  <li>
    <p>주로 Sigmoid 계열 활성화 함수에서 주로 발생하며 신경망의 학습을 어렵게 만든다. ReLU 함수는 이 문제를 일부 완화하지만 음수 영역에서는 뉴런이 죽어버리는 현상을 야기한다.</p>
  </li>
</ul>

<h3 id="adamadaptive-moment-estimation">Adam(Adaptive Moment Estimation)</h3>
<ul>
  <li>
    <p>딥러닝에서 널리 사용되는 최적화 알고리즘으로 학습 과정에서 파라미터의 학습률을 자동으로 조정하여 효과적인 학습을 가능하게 한다.</p>
  </li>
  <li>
    <p>Adam은 학습 속도가 빠르고 메모리 효율적이며 다양한 문제에 대해 안정적인 성능을 보여주기 때문에 사용한다. 기존 옵티마이저(SGD, Momentum, RMSprop)의 단점을 보완하면서도 자동으로 학습률을 조정하여 호과적인 학습이 가능하다.</p>
  </li>
</ul>

<h3 id="convolutional-neural-network-cnn-합성곱-인공신경망">Convolutional Neural Network, CNN (합성곱 인공신경망)</h3>
<ul>
  <li>여러 개의 Convolutional Layer, Pooling Layer, Fully Connected Layer들로 구성된 신경망이다.
  <img src="/assets/images/CNN_arch.png" alt="alt text" /></li>
</ul>

<h4 id="convolution합성곱">Convolution(합성곱)</h4>
<ul>
  <li>
    <p>두 함수 $f$와 $g$에 대해서 $f<em>g$로 표현한다.<br />
  $(f</em>g)(t) = \int f(\tau)g(t-\tau) d\tau$ <br /></p>

    <p><img src="/assets/images/Convolution_of_box_signal_with_itself2.gif" alt="alt text" /><br /></p>
    <blockquote>
      <p>출처: <a href="https://en.m.wikipedia.org/wiki/File:Convolution_of_box_signal_with_itself2.gif">WIKIpedia</a></p>
    </blockquote>
  </li>
</ul>

<h4 id="convolutional-layer합성곱-계층">Convolutional Layer(합성곱 계층)</h4>
<ul>
  <li>Convolutional Layer는 CNN에서의 입력 데이터의 특징을 추출하는 레이어이다. 입력 데이터에 Convolutional Mask(필터/커널)을 적용하고 활성화 함수를 반영하여 특징을 추출하는 레이어이다.<br />
  <img src="/assets/images/ConvLayer.gif" alt="alt text" /></li>
</ul>

<h4 id="pooling-layer풀링-계층">Pooling Layer(풀링 계층)</h4>
<ul>
  <li>
    <p>Pooling Layer는 Convolution Neural Network에서 입력 특징 맵의 공간 크기를 줄여 계산량을 감소시키고 중요한 특징을 추출하며 과적합을 방지하는 역하을 하는 레이어이다.<br />
일반적으로 Pooling은 feature map의 크기를 줄이고 중요한 정보를 추려내는데 활용되는 연산이다.<br />
<img src="/assets/images/Pooling.gif" alt="alt text" /></p>
  </li>
  <li>
    <p>Max Pooling : Pooling 영역 내에서 가장 큰 값 하나를 골라 대표값으로 삼는 방법으로 이미지나 feature map에서 뚜렷하게나타나는 패턴을 강조하는데 유리하며 작은 노이즈나 위치 변동의 영향을 줄일 수 있다.</p>
  </li>
  <li>
    <p>Average Pooling : Pooling 영역 내의 모든 값을 더해 평균을 내는 방식이다. 구역 전체의 통계적 특성을 고르게 반영할 수 있고 극단적으로 큰 값이 존재하더라도 이를 완화해 전체 분포를 안정적으로 유지한다.</p>
  </li>
</ul>

<h4 id="flatten-layer평탄화-계층">Flatten Layer(평탄화 계층)</h4>
<ul>
  <li>Flatten Layer는 다차원 배열 형태의 입력 데이터를 1차원 배열로 변환하여 주로 Fully Connected Layer에 입력으로 사용할 수 있도록 하는 신경망 레이어이다.<br />
<img src="/assets/images/flatten.png" alt="alt text" /></li>
</ul>

<h3 id="오늘의-회고">오늘의 회고</h3>
<ul>
  <li>CNN을 중점으로 딥러닝을 학습하였다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="5th Week" /><category term="python" /><category term="langchain" /><summary type="html"><![CDATA[한 줄 정리]]></summary></entry><entry><title type="html">LangChain 사용해보기</title><link href="https://thplus.github.io/today%20i%20learn/4th%20week/langchain/" rel="alternate" type="text/html" title="LangChain 사용해보기" /><published>2025-02-22T00:00:00+00:00</published><updated>2025-02-22T00:00:00+00:00</updated><id>https://thplus.github.io/today%20i%20learn/4th%20week/langchain</id><content type="html" xml:base="https://thplus.github.io/today%20i%20learn/4th%20week/langchain/"><![CDATA[<h2 id="langchain">LangChain</h2>
<ul>
  <li>
    <p>LangChain is a framework for developing applications powered by large language models (LLMs).
  <img src="/assets/images/langchain.png" alt="alt text" /></p>
  </li>
  <li>LangChain 설치
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">$pip</span> <span class="nb">install </span>langchain
</code></pre></div>    </div>
  </li>
  <li>Environment variables 설정<br />
  Unix 계열
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nb">export </span><span class="nv">LANGSMITH_TRACING</span><span class="o">=</span><span class="s2">"true"</span>
  <span class="nb">export </span><span class="nv">LANGSMITH_API_KEY</span><span class="o">=</span><span class="s2">"..."</span>
</code></pre></div>    </div>

    <p>MS</p>
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nb">set </span><span class="nv">LANGSMITH_TRACING</span><span class="o">=</span><span class="s2">"true"</span>
  <span class="nb">set </span><span class="nv">LANGSMITH_API_KEY</span><span class="o">=</span><span class="s2">"..."</span>
</code></pre></div>    </div>

    <p>Jupyter Notebook</p>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">import</span> <span class="nn">getpass</span>
  <span class="kn">import</span> <span class="nn">os</span>

  <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="s">"LANGSMITH_TRACING"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"true"</span>
  <span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="s">"LANGSMITH_API_KEY"</span><span class="p">]</span> <span class="o">=</span> <span class="n">getpass</span><span class="p">.</span><span class="n">getpass</span><span class="p">()</span>
</code></pre></div>    </div>

    <p>다양한 방법이 가능하지만 우리는 <code class="language-plaintext highlighter-rouge">.env</code>를 사용한다.</p>
  </li>
  <li>Using Language Model<br />
  Chat Model 설치
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">$ </span>pip <span class="nb">install</span> <span class="nt">-qU</span> <span class="s2">"langchain[openai]"</span>
</code></pre></div>    </div>

    <p>모델 가져오기</p>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">init_chat_model</span>

  <span class="n">model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s">"gpt-4o-mini"</span><span class="p">,</span> <span class="n">model_provider</span><span class="o">=</span><span class="s">"openai"</span><span class="p">)</span>
  <span class="c1"># langchain을 이용해 'gpt-4o-mini' 모델을 가져온다.
</span></code></pre></div>    </div>
  </li>
  <li><code class="language-plaintext highlighter-rouge">.env</code>를 이용해 환경설정 저장하기<br />
  dotenv 설치
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">$ </span>pip <span class="nb">install </span>dotenv
</code></pre></div>    </div>
    <p><code class="language-plaintext highlighter-rouge">.env</code>는 Hidden File로 숨김이 가능하다.</p>
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nv">OPENAI_API_KEY</span><span class="o">=</span><span class="s2">"api key 입력"</span>
</code></pre></div>    </div>
  </li>
  <li>API 사용하기
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
  <span class="n">load_dotenv</span><span class="p">()</span>

  <span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">init_chat_model</span>
  <span class="n">model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s">"gpt-4o-mini"</span><span class="p">,</span> <span class="n">model_provider</span><span class="o">=</span><span class="s">"openai"</span><span class="p">)</span>

  <span class="kn">from</span> <span class="nn">langchain_core.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>

  <span class="n">system_template</span> <span class="o">=</span> <span class="s">"Translate the following from English into {language}"</span>

  <span class="n">prompt_template</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="p">.</span><span class="n">from_messages</span><span class="p">(</span>
      <span class="p">[(</span><span class="s">"system"</span><span class="p">,</span> <span class="n">system_template</span><span class="p">),</span> <span class="p">(</span><span class="s">"user"</span><span class="p">,</span> <span class="s">"{text}"</span><span class="p">)]</span>
  <span class="p">)</span>

  <span class="n">prompt</span> <span class="o">=</span> <span class="n">prompt_template</span><span class="p">.</span><span class="n">invoke</span><span class="p">({</span><span class="s">"language"</span><span class="p">:</span> <span class="s">"Korean"</span><span class="p">,</span> <span class="s">"text"</span><span class="p">:</span> <span class="s">"hi!"</span><span class="p">})</span>
  <span class="n">response</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>
  <span class="k">print</span><span class="p">(</span><span class="n">response</span><span class="p">.</span><span class="n">content</span><span class="p">)</span>
</code></pre></div>    </div>
    <p>출력</p>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  안 녕 하 세 요 !
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="api화-하기">API화 하기</h2>
<ul>
  <li>GET 요청에 부가 정보로 경로 파라미터 외에 쿼리 파라미터를 쓸 수 있다.<br />
  쿼리 파라미터: 경로 뒤에 <code class="language-plaintext highlighter-rouge">?key1=value1&amp;key2=value2</code><br />
    <blockquote>
      <p>https://…../say?text=hi<br /></p>
    </blockquote>
  </li>
  <li>class로 바꿔서 사용하기<br />
  <code class="language-plaintext highlighter-rouge">app_model.py</code>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>

  <span class="kn">from</span> <span class="nn">langchain.chat_models</span> <span class="kn">import</span> <span class="n">init_chat_model</span>
  <span class="kn">from</span> <span class="nn">langchain_core.messages</span> <span class="kn">import</span> <span class="n">HumanMessage</span><span class="p">,</span> <span class="n">SystemMessage</span>
  <span class="kn">from</span> <span class="nn">langchain_core.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span>

  <span class="k">class</span> <span class="nc">AppModel</span><span class="p">:</span>
  <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
      <span class="n">load_dotenv</span><span class="p">()</span> 
      <span class="bp">self</span><span class="p">.</span><span class="n">model</span> <span class="o">=</span> <span class="n">init_chat_model</span><span class="p">(</span><span class="s">"gpt-4o-mini"</span><span class="p">,</span> <span class="n">model_provider</span><span class="o">=</span><span class="s">"openai"</span><span class="p">)</span>
      <span class="n">system_template</span> <span class="o">=</span> <span class="s">"Translate the following from English into {language}"</span>
      <span class="bp">self</span><span class="p">.</span><span class="n">prompt_template</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="p">.</span><span class="n">from_messages</span><span class="p">(</span>
      <span class="p">[(</span><span class="s">"system"</span><span class="p">,</span> <span class="n">system_template</span><span class="p">),</span> <span class="p">(</span><span class="s">"user"</span><span class="p">,</span> <span class="s">"{text}"</span><span class="p">)]</span>
      <span class="p">)</span>

  <span class="k">def</span> <span class="nf">get_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">([</span><span class="n">HumanMessage</span><span class="p">(</span><span class="n">message</span><span class="p">)])</span>

  <span class="k">def</span> <span class="nf">get_prompt_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">language</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
      <span class="n">prompt</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">prompt_template</span><span class="p">.</span><span class="n">invoke</span><span class="p">({</span><span class="s">"language"</span><span class="p">:</span> <span class="n">language</span><span class="p">,</span> <span class="s">"text"</span><span class="p">:</span> <span class="n">message</span><span class="p">})</span>
      <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">prompt</span><span class="p">)</span>

  <span class="k">def</span> <span class="nf">get_streaming_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">messages</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">self</span><span class="p">.</span><span class="n">model</span><span class="p">.</span><span class="n">astream</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li>배포하기<br />
  <code class="language-plaintext highlighter-rouge">server.py</code>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span><span class="p">,</span> <span class="n">Query</span>
  <span class="kn">from</span> <span class="nn">fastapi.responses</span> <span class="kn">import</span> <span class="n">StreamingResponse</span>
  <span class="kn">from</span> <span class="nn">fastapi.staticfiles</span> <span class="kn">import</span> <span class="n">StaticFiles</span>

  <span class="kn">import</span> <span class="nn">app_model</span>

  <span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>

  <span class="n">model</span> <span class="o">=</span> <span class="n">app_model</span><span class="p">.</span><span class="n">AppModel</span><span class="p">()</span>

  <span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"/say"</span><span class="p">)</span>
  <span class="k">def</span> <span class="nf">say_app</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Query</span><span class="p">()):</span>
      <span class="n">response</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">get_response</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
      <span class="k">return</span> <span class="p">{</span><span class="s">"content"</span> <span class="p">:</span><span class="n">response</span><span class="p">.</span><span class="n">content</span><span class="p">}</span>

  <span class="o">@</span><span class="n">app</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">"/traslate"</span><span class="p">)</span>
  <span class="k">def</span> <span class="nf">translater</span><span class="p">(</span><span class="n">language</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Query</span><span class="p">(),</span> <span class="n">text</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Query</span><span class="p">()):</span>
      <span class="n">response</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">get_prompt_response</span><span class="p">(</span><span class="n">language</span><span class="p">,</span> <span class="n">text</span><span class="p">)</span>
      <span class="k">return</span> <span class="p">{</span><span class="s">"content"</span> <span class="p">:</span><span class="n">response</span><span class="p">.</span><span class="n">content</span><span class="p">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p>스트리밍<br />
  SSE: Server-Side Event 웹 기술을 사용하여 이벤트 소스를 클라이언트에서 연결하고 서버는 이벤트 스트림으로 내려준다.</p>

    <p>현재의 구조: LangChain LLM + FastAPI 서버</p>
  </li>
</ul>

<h2 id="chatbot">ChatBot</h2>
<ul>
  <li>
    <p>ChatBot은 질문에 대한 적절한 답변을 받는 것이다. 하지만 ChatBot은 이전에 했던 말은 기억하지 못한다. 간단하게 구현해보면 아래와 같다.<br /></p>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">langchain_core.messages</span> <span class="kn">import</span> <span class="n">HumanMessage</span>

  <span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">([</span><span class="n">HumanMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"Hi! I'm Bob"</span><span class="p">)])</span>
</code></pre></div>    </div>

    <p>출력</p>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  AIMessage(content='Hi Bob! How can I assist you today?'... 이하 생략
</code></pre></div>    </div>
    <p><br /></p>
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">([</span><span class="n">HumanMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"What's my name?"</span><span class="p">)])</span>
</code></pre></div>    </div>

    <p>출력</p>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  AIMessage(content="I'm sorry, but I don't have access to personal information about users unless it has been shared with me in the course of our conversation. How can I assist you today?" ... 이하 생략
</code></pre></div>    </div>
  </li>
  <li>따라서 대화를 위해서는 기본적으로 여태 했던 내용을 같이 넣어주어야 한다.
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">langchain_core.messages</span> <span class="kn">import</span> <span class="n">AIMessage</span>

  <span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span>
      <span class="p">[</span>
          <span class="n">HumanMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"Hi! I'm Bob"</span><span class="p">),</span>
          <span class="n">AIMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"Hello Bob! How can I assist you today?"</span><span class="p">),</span>
          <span class="n">HumanMessage</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="s">"What's my name?"</span><span class="p">),</span>
      <span class="p">]</span>
  <span class="p">)</span>
</code></pre></div>    </div>

    <p>출력</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  AIMessage(content='Your name is Bob! How can I help you today, Bob?' ... 이하 생략
</code></pre></div>    </div>
  </li>
  <li>대화내용을 기억하면서 소통하기위해선 메모리가 필요하며 LangGraph를 이용할 수 있다.
    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kn">from</span> <span class="nn">langgraph.checkpoint.memory</span> <span class="kn">import</span> <span class="n">MemorySaver</span>
  <span class="kn">from</span> <span class="nn">langgraph.graph</span> <span class="kn">import</span> <span class="n">START</span><span class="p">,</span> <span class="n">MessagesState</span><span class="p">,</span> <span class="n">StateGraph</span>

  <span class="c1"># Define a new graph
</span>  <span class="n">workflow</span> <span class="o">=</span> <span class="n">StateGraph</span><span class="p">(</span><span class="n">state_schema</span><span class="o">=</span><span class="n">MessagesState</span><span class="p">)</span>


  <span class="c1"># Define the function that calls the model
</span>  <span class="k">def</span> <span class="nf">call_model</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">MessagesState</span><span class="p">):</span>
      <span class="n">response</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">state</span><span class="p">[</span><span class="s">"messages"</span><span class="p">])</span>
      <span class="k">return</span> <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="n">response</span><span class="p">}</span>


  <span class="c1"># Define the (single) node in the graph
</span>  <span class="n">workflow</span><span class="p">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">START</span><span class="p">,</span> <span class="s">"model"</span><span class="p">)</span>
  <span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"model"</span><span class="p">,</span> <span class="n">call_model</span><span class="p">)</span>

  <span class="c1"># Add memory
</span>  <span class="n">memory</span> <span class="o">=</span> <span class="n">MemorySaver</span><span class="p">()</span>
  <span class="n">app</span> <span class="o">=</span> <span class="n">workflow</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">checkpointer</span><span class="o">=</span><span class="n">memory</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
</ul>

<h2 id="오늘의-회고">오늘의 회고</h2>
<ul>
  <li>ChatBot의 기본 원리를 학습할 수 있었고 LLM을 이용한 해커톤을 할 때, 굉장히 유용한 학습이었다.</li>
</ul>]]></content><author><name>Buyoung Kim</name></author><category term="Today I Learn" /><category term="4th Week" /><category term="python" /><category term="langchain" /><summary type="html"><![CDATA[LangChain LangChain is a framework for developing applications powered by large language models (LLMs).]]></summary></entry></feed>