<?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://82153.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://82153.github.io/" rel="alternate" type="text/html" /><updated>2025-11-18T14:36:13+09:00</updated><id>https://82153.github.io/feed.xml</id><title type="html">Blog</title><subtitle>DeepLearning
</subtitle><author><name>김동욱</name></author><entry><title type="html">[Mathematics] 정보 엔트로피</title><link href="https://82153.github.io/mathematics/2025/10/20/entropy.html" rel="alternate" type="text/html" title="[Mathematics] 정보 엔트로피" /><published>2025-10-20T12:54:00+09:00</published><updated>2025-10-20T12:54:00+09:00</updated><id>https://82153.github.io/mathematics/2025/10/20/entropy</id><content type="html" xml:base="https://82153.github.io/mathematics/2025/10/20/entropy.html"><![CDATA[<h3 id="정보-엔트로피">정보 엔트로피</h3>

<ul>
  <li>정보 엔트로피는 어떤 확률 분포를 가진 사건의 <strong>불확실성을 측정하는 값</strong>이며, 그 사건을 표현하기 위해 <strong>필요한 최소 평균 정보량</strong>이다.</li>
  <li>확률이 높은 사건은 자주 나타나므로, 이를 구분하거나 전달하기 위해 필요한 정보량(비트 수)은 작아도 충분하다. 반대로, 확률이 낮은 사건은 드물게 나타나므로, 이를 명확하게 표현하기 위해서는 더 많은 정보량이 필요하게 된다.</li>
  <li>따라서 확률이 낮을수록 정보량은 크고, 불확실성(엔트로피)도 높아지며, 확률이 높을수록 정보량과 불확실성은 낮아집니다.</li>
  <li>이제 정보 엔트로피의 수식을 보면, 아래 수식으로 계산된다.</li>
</ul>

\[H(x) = E[I(x)] = -\sum{P(x)log_{2}{}P(x)}\]

<ul>
  <li>즉 위의 정의대로 $E[]$는 기댓값을 나타내고, $I(x)$는 x에 대한 bit단위의 정보량을 나타낸다. 이 2개를 합쳐 bit 단위의 정보량의 기대값으로 볼 수 있다.</li>
</ul>

<hr />

<h3 id="binary-entropy">Binary Entropy</h3>

<ul>
  <li>이진 엔트로피는 <strong>하나의 확률변수가 두 가지 값 중 하나</strong>를 가질 때, 해당 변수의 불확실성 또는 정보량을 나타낸다.</li>
  <li>여기에서 어떤 사건이 발생할 확률을 $p$라 할 때, 사건이 발생하지 않을 확률은 $(1 - p)$가 된다. 이 때, 이진 엔트로피는 아래와 같이 계산된다. 이는 단순히 위의 엔트로피를 계산했을 때, 이진인 경우로 계산한 것과 동일하다.</li>
</ul>

\[H(x)=-plog_{2}p-(1-p)log_{2}(1-p)\]

<ul>
  <li>이진 엔트로피에서는 $p$가 0인 경우에는 $-(1-p)log_{2}(1-p)$부분만 살아남아 0이 된다. 이와 마찬가지로 $p$가 1인 경우에는 $-plog_{2}p$부분만 살아남아 마찬가지로 0이 된다.</li>
  <li>$p$가 0 또는 1이라는 것은 해당 사건이 무조건 발생하거나, 무조건 발생하지 않는다는 것이다. 이는 해당 사건의 불확실성이 없고, 필요한 정보량이 없다는 것이다.</li>
  <li>$p$가 0.5인 경우 실제로 계산하면 $H(0.5) = -0.5\log_{2}(0.5)-0.5\log_{2}(0.5)=1$이다. $p$가 0.5라는 것은 각 사건이 발생할 확률이 동등하다는 것이고, 이는 가장 불확실한 상황이고, 정보량이 가장 많이 필요하다는 것이다.</li>
  <li>다만 이진 엔트로피는 단일 확률 분포의 불확실성을 측정하는 값이므로, 그대로는 <strong>딥러닝에서 Loss로 사용되지는 않는다.</strong> 딥러닝에서는 정답 분포와 모델의 예측 분포를 비교해야 하므로, Binary Cross Entropy나 Cross Entropy가 Loss로서 사용된다.</li>
</ul>

<hr />

<h3 id="cross-entropy">Cross Entropy</h3>

<ul>
  <li>위에서 본 엔트로피는 하나의 확률 분포에 대해서만 다뤘지만, Cross Entropy는 <strong>서로 다른 확률 분포를 다룬 엔트로피</strong>이다. 그렇기에 머신러닝 분류에서 정답 분포와 예측 분포를 다뤄, Loss로서 주로 사용된다.</li>
  <li>$P(x)$를 정답 분포, $Q(x)$를 예측 분포라 했을 때, 교차 엔트로피는 아래와 같다.</li>
</ul>

\[H(P,Q)=-\sum{P(x)logQ(x)}\]

<ul>
  <li>$P(x)$를 기준으로 $Q(x)$가  얼마나 유사한가를 나타낸다. 따라서 $H(P,Q)$와 $H(Q,P)$의 값은 다르다.</li>
  <li>교차 엔트로피의 범위는 $[0,\infty]$를 가진다. 0일때는 실제와 예측의 두 확률 분포가 완벽하게 일치하고, $\infty$일때는 정답 분포에서 확률이 1인 클래스에 대해 모델 예측 확률 $Q(x)$가 0에 가까워질 때를 말한다.</li>
  <li>이는 실제 데이터와 예측데이터가 일치하면 별도의 필요한 정보가 없고, 완전히 다르면 무한대의 정보가 필요함을 의미한다.</li>
</ul>

<hr />

<h3 id="binary-cross-entropy">Binary Cross Entropy</h3>

<ul>
  <li>이진 교차 엔트로피는 <strong>이진 분류에 특화된 교차 엔트로피</strong>이다.</li>
  <li>수식은 아래와 같다.</li>
</ul>

\[BCE = -\frac{1}{n}\sum \Big( P(x)\log Q(x) + (1-P(x))\log(1-Q(x)) \Big)\]

<ul>
  <li>$P(x)$가 1이라면 앞 부분만 계산된다. 그리고 이때, $Q(x)$가 1이라면 즉, 정답과 일치하면 엔트로피가 0이 된다. 반대로 $Q(x)$가 정답과 다르면(=0) 엔트로피 값은 $\infty$가 된다.</li>
  <li>이진 교차 엔트로피는 단순히 이진 엔트로피와 교차 엔트로피가 합쳐진거라긴 보다는 <strong>교차 엔트로피의 한 종류로 이진 분류에 적용한 결과</strong>라고 보면 된다.</li>
</ul>

<hr />

<h3 id="kl-divergence">KL-Divergence</h3>

<ul>
  <li>쿨백-라이블러 발산은 <strong>두 확률 분포가 얼마나 다른지를 측정</strong>하는 방법으로, <strong>한 확률 분포가 다른 확률 분포와 얼마나 멀리 떨어져 있는지 나타내는 척도</strong>이다.</li>
  <li>쿨백-라이블러 발산의 수식은 아래와 같다.</li>
</ul>

\[D_{KL}(P||Q)=\sum{P(x)log{\frac{P(x)}{Q(x)}}}\]

<ul>
  <li>이 수식을 전개해보면, <strong>교차 엔트로피에서 P에 대한 엔트로피를 빼준 형태</strong>가 된다.</li>
</ul>

\[\sum{P(x)log{\frac{P(x)}{Q(x)}}}=-\sum{P(x)log{Q(x)}}-(-\sum{P(x)log{P(x)}})\]

<ul>
  <li>다만, 쿨백-라이블러는 일반적인 분류에서 Loss로서 사용되지는 않는다. 그 이유는 우선 비대칭적이기 때문이다. $D_{KL}(P||Q)$ 와 $D_{KL}(Q||P)$가 서로 다른 값을 가진다.</li>
  <li>또한 $[0, \infty]$의 무한한 범위를 다루기에 까다롭기 때문이다. 그러나 정규화 항이나 분포 간 거리를 최소화하는 모델(ex. VAE)에서는 자주 사용된다.</li>
</ul>

<hr />

<h3 id="jensen-shannon-divergence">Jensen-Shannon Divergence</h3>

<ul>
  <li>JSD는 KL-Divergence와 같이 두 확률 분포 간의 유사성을 측정하는 방법으로, <strong>KL-Divergence를 두 번 구한 다음 평균을 계산한 개념으로 두 확률분포 간의 거리</strong>를 의미한다.</li>
</ul>

\[JSD=\frac{1}{2}D_{KL}(P||M)+\frac{1}{2}D_{KL}(Q||M) \\ M=\frac{1}{2}(P+Q)\]

<ul>
  <li>JSD는 KL-Divergence를 양쪽 방향에서 계산한 뒤 평균을 취하는 방식이므로 대칭적이다.</li>
  <li>또한 JSD는 항상 0과 1 사이의 유한한 값을 가지므로 KL보다 안정적이며, 실전에서 Loss 또는 분포 유사도 측정에 활용할 수 있다.</li>
</ul>]]></content><author><name>김동욱</name></author><category term="Mathematics" /><category term="Mathematics" /><summary type="html"><![CDATA[정보 엔트로피 정보 엔트로피는 어떤 확률 분포를 가진 사건의 불확실성을 측정하는 값이며, 그 사건을 표현하기 위해 필요한 최소 평균 정보량이다. 확률이 높은 사건은 자주 나타나므로, 이를 구분하거나 전달하기 위해 필요한 정보량(비트 수)은 작아도 충분하다. 반대로, 확률이 낮은 사건은 드물게 나타나므로, 이를 명확하게 표현하기 위해서는 더 많은 정보량이 필요하게 된다. 따라서 확률이 낮을수록 정보량은 크고, 불확실성(엔트로피)도 높아지며, 확률이 높을수록 정보량과 불확실성은 낮아집니다. 이제 정보 엔트로피의 수식을 보면, 아래 수식으로 계산된다. \[H(x) = E[I(x)] = -\sum{P(x)log_{2}{}P(x)}\] 즉 위의 정의대로 $E[]$는 기댓값을 나타내고, $I(x)$는 x에 대한 bit단위의 정보량을 나타낸다. 이 2개를 합쳐 bit 단위의 정보량의 기대값으로 볼 수 있다. Binary Entropy 이진 엔트로피는 하나의 확률변수가 두 가지 값 중 하나를 가질 때, 해당 변수의 불확실성 또는 정보량을 나타낸다. 여기에서 어떤 사건이 발생할 확률을 $p$라 할 때, 사건이 발생하지 않을 확률은 $(1 - p)$가 된다. 이 때, 이진 엔트로피는 아래와 같이 계산된다. 이는 단순히 위의 엔트로피를 계산했을 때, 이진인 경우로 계산한 것과 동일하다. \[H(x)=-plog_{2}p-(1-p)log_{2}(1-p)\] 이진 엔트로피에서는 $p$가 0인 경우에는 $-(1-p)log_{2}(1-p)$부분만 살아남아 0이 된다. 이와 마찬가지로 $p$가 1인 경우에는 $-plog_{2}p$부분만 살아남아 마찬가지로 0이 된다. $p$가 0 또는 1이라는 것은 해당 사건이 무조건 발생하거나, 무조건 발생하지 않는다는 것이다. 이는 해당 사건의 불확실성이 없고, 필요한 정보량이 없다는 것이다. $p$가 0.5인 경우 실제로 계산하면 $H(0.5) = -0.5\log_{2}(0.5)-0.5\log_{2}(0.5)=1$이다. $p$가 0.5라는 것은 각 사건이 발생할 확률이 동등하다는 것이고, 이는 가장 불확실한 상황이고, 정보량이 가장 많이 필요하다는 것이다. 다만 이진 엔트로피는 단일 확률 분포의 불확실성을 측정하는 값이므로, 그대로는 딥러닝에서 Loss로 사용되지는 않는다. 딥러닝에서는 정답 분포와 모델의 예측 분포를 비교해야 하므로, Binary Cross Entropy나 Cross Entropy가 Loss로서 사용된다. Cross Entropy 위에서 본 엔트로피는 하나의 확률 분포에 대해서만 다뤘지만, Cross Entropy는 서로 다른 확률 분포를 다룬 엔트로피이다. 그렇기에 머신러닝 분류에서 정답 분포와 예측 분포를 다뤄, Loss로서 주로 사용된다. $P(x)$를 정답 분포, $Q(x)$를 예측 분포라 했을 때, 교차 엔트로피는 아래와 같다. \[H(P,Q)=-\sum{P(x)logQ(x)}\] $P(x)$를 기준으로 $Q(x)$가 얼마나 유사한가를 나타낸다. 따라서 $H(P,Q)$와 $H(Q,P)$의 값은 다르다. 교차 엔트로피의 범위는 $[0,\infty]$를 가진다. 0일때는 실제와 예측의 두 확률 분포가 완벽하게 일치하고, $\infty$일때는 정답 분포에서 확률이 1인 클래스에 대해 모델 예측 확률 $Q(x)$가 0에 가까워질 때를 말한다. 이는 실제 데이터와 예측데이터가 일치하면 별도의 필요한 정보가 없고, 완전히 다르면 무한대의 정보가 필요함을 의미한다. Binary Cross Entropy 이진 교차 엔트로피는 이진 분류에 특화된 교차 엔트로피이다. 수식은 아래와 같다. \[BCE = -\frac{1}{n}\sum \Big( P(x)\log Q(x) + (1-P(x))\log(1-Q(x)) \Big)\] $P(x)$가 1이라면 앞 부분만 계산된다. 그리고 이때, $Q(x)$가 1이라면 즉, 정답과 일치하면 엔트로피가 0이 된다. 반대로 $Q(x)$가 정답과 다르면(=0) 엔트로피 값은 $\infty$가 된다. 이진 교차 엔트로피는 단순히 이진 엔트로피와 교차 엔트로피가 합쳐진거라긴 보다는 교차 엔트로피의 한 종류로 이진 분류에 적용한 결과라고 보면 된다. KL-Divergence 쿨백-라이블러 발산은 두 확률 분포가 얼마나 다른지를 측정하는 방법으로, 한 확률 분포가 다른 확률 분포와 얼마나 멀리 떨어져 있는지 나타내는 척도이다. 쿨백-라이블러 발산의 수식은 아래와 같다. \[D_{KL}(P||Q)=\sum{P(x)log{\frac{P(x)}{Q(x)}}}\] 이 수식을 전개해보면, 교차 엔트로피에서 P에 대한 엔트로피를 빼준 형태가 된다. \[\sum{P(x)log{\frac{P(x)}{Q(x)}}}=-\sum{P(x)log{Q(x)}}-(-\sum{P(x)log{P(x)}})\] 다만, 쿨백-라이블러는 일반적인 분류에서 Loss로서 사용되지는 않는다. 그 이유는 우선 비대칭적이기 때문이다. $D_{KL}(P||Q)$ 와 $D_{KL}(Q||P)$가 서로 다른 값을 가진다. 또한 $[0, \infty]$의 무한한 범위를 다루기에 까다롭기 때문이다. 그러나 정규화 항이나 분포 간 거리를 최소화하는 모델(ex. VAE)에서는 자주 사용된다. Jensen-Shannon Divergence JSD는 KL-Divergence와 같이 두 확률 분포 간의 유사성을 측정하는 방법으로, KL-Divergence를 두 번 구한 다음 평균을 계산한 개념으로 두 확률분포 간의 거리를 의미한다. \[JSD=\frac{1}{2}D_{KL}(P||M)+\frac{1}{2}D_{KL}(Q||M) \\ M=\frac{1}{2}(P+Q)\] JSD는 KL-Divergence를 양쪽 방향에서 계산한 뒤 평균을 취하는 방식이므로 대칭적이다. 또한 JSD는 항상 0과 1 사이의 유한한 값을 가지므로 KL보다 안정적이며, 실전에서 Loss 또는 분포 유사도 측정에 활용할 수 있다.]]></summary></entry><entry><title type="html">[WandB] WandB 기본</title><link href="https://82153.github.io/wandb/2025/10/17/wandb.html" rel="alternate" type="text/html" title="[WandB] WandB 기본" /><published>2025-10-17T14:27:00+09:00</published><updated>2025-10-17T14:27:00+09:00</updated><id>https://82153.github.io/wandb/2025/10/17/wandb</id><content type="html" xml:base="https://82153.github.io/wandb/2025/10/17/wandb.html"><![CDATA[<h2 id="wandb">WandB</h2>

<ul>
  <li>WandB는 Weights and Bias의 약자로 딥러닝 모델 학습 과정의 <strong>loss, 평가 지표 등을 확인할 수 있는 툴</strong>로 모델 실험에 도움을 주는 툴이다</li>
  <li>print문을 통해 여러 지표들을 출력하거나, 시각화하여 표현하는 것이 필요 없이 metric들이 어케 변하는지 쉽게 확인할 수 있다.</li>
</ul>

<hr />

<h2 id="wandb-사용해보기">WandB 사용해보기</h2>

<ol>
  <li><strong>WandB 설치 및 로그인</strong>
    <ul>
      <li>WandB를 사용하려면 먼저 패키지를 설치하고 로그인(API 키 등록)을 진행해야 한다.</li>
      <li>우선 wandb를 import해준다. 만약 없다면 <code class="language-plaintext highlighter-rouge">pip install wandb</code>로 설치해주면 된다.</li>
      <li>그리고 <code class="language-plaintext highlighter-rouge">wandb.login()</code> 으로 로그인한다. 로그인 시에 API 키가 필요하다.</li>
      <li><code class="language-plaintext highlighter-rouge">wandb.login(key = “api 키”)</code> 로 설정할 수 있다. 또는 <code class="language-plaintext highlighter-rouge">os.environ["WANDB_API_KEY"]=’api키’</code> 로 지정하여 환경 변수로 저장해 놓을 수 있다.</li>
    </ul>
  </li>
  <li><strong>WandB 프로젝트 초기화</strong>
    <ul>
      <li>로그인을 마친 후에는 <code class="language-plaintext highlighter-rouge">wandb.init()</code> 으로 프로젝트를 초기화 해줘야 한다.</li>
      <li>프로젝트는 직접 WandB 사이트에서 직접 만들 수도 있지만, wandb.init()을 통해 자동으로 생성할 수도 있다.</li>
    </ul>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">wandb</span><span class="p">.</span><span class="n">init</span><span class="p">(</span>
     <span class="n">entity</span><span class="o">=</span><span class="s">'kdw6177012-naver'</span><span class="p">,</span> <span class="c1"># 나의 entity 이름 혹은 team의 이름
</span>     <span class="n">project</span> <span class="o">=</span> <span class="s">'wandb-practice'</span><span class="p">,</span> <span class="c1"># 프로젝트 이름
</span>     <span class="n">name</span> <span class="o">=</span> <span class="s">'basic-practice'</span><span class="p">,</span> <span class="c1"># 실험(run) 이름
</span>     <span class="n">config</span> <span class="o">=</span> <span class="p">{</span> <span class="c1"># 해당 실험의 하이퍼 파라미터 등을 기록
</span>         <span class="s">'learning_rate'</span><span class="p">:</span> <span class="mf">1e-2</span><span class="p">,</span>
         <span class="s">'epochs'</span><span class="p">:</span> <span class="mi">150</span><span class="p">,</span>
         <span class="s">'batch_size'</span><span class="p">:</span> <span class="mi">16</span>
     <span class="p">}</span>
 <span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li><strong>학습 중 로깅 남기기</strong>
    <ul>
      <li>위와 같이 프로젝트를 초기화 한 후에는 학습 과정에서 <code class="language-plaintext highlighter-rouge">wandb.log()</code> 를 통해 로그를 남겨 준다.</li>
      <li>내가 어떤 값을 로깅할지 직접 지정해주면 된다.</li>
      <li>step은 wandb가 <strong>로그의 순서를 인식하는 기준</strong>으로, 일반적으로 epoch(학습 단위)나 iteration(배치 단위) 값을 지정한다. 지정하지 않으면 wandb가 자동으로 1씩 증가시키며 관리한다.</li>
    </ul>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">wandb</span><span class="p">.</span><span class="n">log</span><span class="p">({</span>
     <span class="s">"epoch"</span><span class="p">:</span> <span class="n">epoch</span><span class="p">,</span>
     <span class="s">"train/loss"</span><span class="p">:</span> <span class="n">tr_loss</span><span class="p">,</span>
     <span class="s">"train/acc"</span><span class="p">:</span> <span class="n">tr_acc</span><span class="p">,</span>
     <span class="s">"val/loss"</span><span class="p">:</span> <span class="n">val_loss</span><span class="p">,</span>
     <span class="s">"val/acc"</span><span class="p">:</span> <span class="n">val_acc</span><span class="p">,</span>
     <span class="s">"lr"</span><span class="p">:</span> <span class="n">optimizer</span><span class="p">.</span><span class="n">param_groups</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">'lr'</span><span class="p">]</span>
 <span class="p">},</span> <span class="n">step</span><span class="o">=</span><span class="n">epoch</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
  <li><strong>학습 종료 후 wandb 종료</strong>
    <ul>
      <li>학습이 다 끝난 뒤에는 <code class="language-plaintext highlighter-rouge">wandb.finish()</code>로 프로젝트를 종료해주면 된다.</li>
      <li>모든 로그를 서버로 업로드하고, 대시보드에서 해당 run을 <strong>Finished 상태</strong>로 마무리합니다.</li>
    </ul>

    <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">wandb</span><span class="p">.</span><span class="n">finish</span><span class="p">()</span>
</code></pre></div>    </div>
  </li>
</ol>

<ul>
  <li>위 과정을 통해 해당 실험의 Loss, Accuracy 등의 metric의 변화를 실시간으로 추적하고 시각적으로 분석할 수 있다.</li>
</ul>

<p><img width="600" height="400" alt="image" src="https://github.com/user-attachments/assets/4ca60146-21cd-473a-9279-f45015cde696" /></p>]]></content><author><name>김동욱</name></author><category term="WandB" /><category term="WandB" /><summary type="html"><![CDATA[WandB WandB는 Weights and Bias의 약자로 딥러닝 모델 학습 과정의 loss, 평가 지표 등을 확인할 수 있는 툴로 모델 실험에 도움을 주는 툴이다 print문을 통해 여러 지표들을 출력하거나, 시각화하여 표현하는 것이 필요 없이 metric들이 어케 변하는지 쉽게 확인할 수 있다. WandB 사용해보기 WandB 설치 및 로그인 WandB를 사용하려면 먼저 패키지를 설치하고 로그인(API 키 등록)을 진행해야 한다. 우선 wandb를 import해준다. 만약 없다면 pip install wandb로 설치해주면 된다. 그리고 wandb.login() 으로 로그인한다. 로그인 시에 API 키가 필요하다. wandb.login(key = “api 키”) 로 설정할 수 있다. 또는 os.environ["WANDB_API_KEY"]=’api키’ 로 지정하여 환경 변수로 저장해 놓을 수 있다. WandB 프로젝트 초기화 로그인을 마친 후에는 wandb.init() 으로 프로젝트를 초기화 해줘야 한다. 프로젝트는 직접 WandB 사이트에서 직접 만들 수도 있지만, wandb.init()을 통해 자동으로 생성할 수도 있다. wandb.init( entity='kdw6177012-naver', # 나의 entity 이름 혹은 team의 이름 project = 'wandb-practice', # 프로젝트 이름 name = 'basic-practice', # 실험(run) 이름 config = { # 해당 실험의 하이퍼 파라미터 등을 기록 'learning_rate': 1e-2, 'epochs': 150, 'batch_size': 16 } ) 학습 중 로깅 남기기 위와 같이 프로젝트를 초기화 한 후에는 학습 과정에서 wandb.log() 를 통해 로그를 남겨 준다. 내가 어떤 값을 로깅할지 직접 지정해주면 된다. step은 wandb가 로그의 순서를 인식하는 기준으로, 일반적으로 epoch(학습 단위)나 iteration(배치 단위) 값을 지정한다. 지정하지 않으면 wandb가 자동으로 1씩 증가시키며 관리한다. wandb.log({ "epoch": epoch, "train/loss": tr_loss, "train/acc": tr_acc, "val/loss": val_loss, "val/acc": val_acc, "lr": optimizer.param_groups[0]['lr'] }, step=epoch) 학습 종료 후 wandb 종료 학습이 다 끝난 뒤에는 wandb.finish()로 프로젝트를 종료해주면 된다. 모든 로그를 서버로 업로드하고, 대시보드에서 해당 run을 Finished 상태로 마무리합니다. wandb.finish() 위 과정을 통해 해당 실험의 Loss, Accuracy 등의 metric의 변화를 실시간으로 추적하고 시각적으로 분석할 수 있다.]]></summary></entry><entry><title type="html">[Python] Sorting(정렬)</title><link href="https://82153.github.io/python/2025/09/25/sorting.html" rel="alternate" type="text/html" title="[Python] Sorting(정렬)" /><published>2025-09-25T14:27:00+09:00</published><updated>2025-09-25T14:27:00+09:00</updated><id>https://82153.github.io/python/2025/09/25/sorting</id><content type="html" xml:base="https://82153.github.io/python/2025/09/25/sorting.html"><![CDATA[<h3 id="sorted-함수">sorted() 함수</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Sorted()</code> 함수는 정렬을 지원하는 파이썬의 <strong>내장함수</strong>이다.</li>
  <li><strong>정렬 후의 값을 리스트</strong>로 반환한다. 즉, 원본을 수정하지 않는다.</li>
  <li>또한 <strong>모든 iterable객체</strong>(list, dictionary, 문자열, set 등)에 적용할 수 있다.</li>
  <li><code class="language-plaintext highlighter-rouge">reverse</code> 인자를 통해 내림차 순으로 정렬할 수 있고, <code class="language-plaintext highlighter-rouge">key</code> 인자에 함수를 넣어 정렬 기준을 Custom할 수도 있다</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="n">sort_a</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">sort_a</span><span class="p">)</span> <span class="c1"># [1, 2, 4, 5, 6]
</span><span class="k">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># [2, 1, 5, 6, 4] -&gt; 원본 유지
</span></code></pre></div></div>

<hr />

<h3 id="sort-메서드">sort() 메서드</h3>

<ul>
  <li><code class="language-plaintext highlighter-rouge">sort()</code>는 함수가 아니라 <strong>리스트의 메서드</strong>이다.</li>
  <li>리스트의 메서드이기에 당연히 <strong>리스트에만 적용</strong>할 수 있다.</li>
  <li>정렬 후의 값을 반환하는 것이 아닌 <strong>원본을 직접 정렬 상태로 수정</strong>한다.</li>
  <li><code class="language-plaintext highlighter-rouge">reverse</code> 인자를 통해 내림차 순으로 정렬할 수 있고, <code class="language-plaintext highlighter-rouge">key</code> 인자에 함수를 넣어 정렬 기준을 Custom할 수도 있다</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="n">a</span><span class="p">.</span><span class="n">sort</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># [1, 2, 4, 5, 6]
</span></code></pre></div></div>

<hr />

<h3 id="key-인자-활용">key 인자 활용</h3>

<ul>
  <li>예를 들어, 우리가 튜플로 이뤄진 리스트를 정렬한다고 하자. 이때, 튜플의 특정 몇 번째 인자를 기준으로 정렬을 할 수 있다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tup_list</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">15</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">),</span> <span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">9</span><span class="p">)]</span>
<span class="n">tup_list</span><span class="p">.</span><span class="n">sort</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">tup_list</span><span class="p">)</span> <span class="c1"># [(1, 15), (2, 5), (4, 6), (12, 9), (20, 2)]
</span></code></pre></div></div>

<ul>
  <li>위의 코드처럼 하면, 첫번째 인자를 기준으로 오름차 정렬이 이뤄진다.</li>
  <li>두 번쨰 원소를 기준으로 하고 싶다면, <code class="language-plaintext highlighter-rouge">sort()</code>의 <code class="language-plaintext highlighter-rouge">key</code>인자에 함수를 넣어주면 된다.</li>
  <li>주로 <code class="language-plaintext highlighter-rouge">key</code>에 <code class="language-plaintext highlighter-rouge">lambda</code> 함수를 지정하여 사용한다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tup_list</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">15</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">),</span> <span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">9</span><span class="p">)]</span>
<span class="n">tup_list</span><span class="p">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</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="n">tup_list</span><span class="p">)</span> <span class="c1"># [(20, 2), (2, 5), (4, 6), (12, 9), (1, 15)]
</span></code></pre></div></div>

<ul>
  <li>이는 <code class="language-plaintext highlighter-rouge">sort()</code> 메서드 뿐만 아니라 <code class="language-plaintext highlighter-rouge">sorted()</code> 함수도 가능하다.</li>
  <li>예를 들어, dictionary의 value로 정렬한다고 하자. 기본적으로 dictionary에 sorted를 적용하면, <strong>dictionary의 key를 기준</strong>으로 정렬된다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dic</span> <span class="o">=</span> <span class="p">{</span><span class="s">"banana"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
       <span class="s">"apple"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
       <span class="s">"grape"</span><span class="p">:</span> <span class="mi">7</span><span class="p">,</span>
       <span class="s">"peach"</span><span class="p">:</span> <span class="mi">4</span><span class="p">}</span>

<span class="k">print</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">dic</span><span class="p">.</span><span class="n">items</span><span class="p">()))</span> <span class="c1"># [('apple', 3), ('banana', 2), ('grape', 7), ('peach', 4)]
# 주의할 점은 단순히 sorted(dic)만 하면 key값만 정렬되어 반환된다.
# 그래서 items()메서드로 (key, value)쌍으로 반환하여 정렬한다.
</span></code></pre></div></div>

<ul>
  <li>하지만 우리가 key가 기준이 아닌 value를 기준으로 하고 싶다면 key에 함수를 넣어주면 된다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dic</span> <span class="o">=</span> <span class="p">{</span><span class="s">"banana"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
       <span class="s">"apple"</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span>
       <span class="s">"grape"</span><span class="p">:</span> <span class="mi">7</span><span class="p">,</span>
       <span class="s">"peach"</span><span class="p">:</span> <span class="mi">4</span><span class="p">}</span>

<span class="n">sorted_by_value</span> <span class="o">=</span> <span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">dic</span><span class="p">.</span><span class="n">items</span><span class="p">(),</span> 
                          <span class="n">key</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</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="n">sorted_by_value</span><span class="p">)</span> <span class="c1"># [('banana', 2), ('apple', 3), ('peach', 4), ('grape', 7)]
</span></code></pre></div></div>]]></content><author><name>김동욱</name></author><category term="Python" /><category term="Python" /><summary type="html"><![CDATA[sorted() 함수 Sorted() 함수는 정렬을 지원하는 파이썬의 내장함수이다. 정렬 후의 값을 리스트로 반환한다. 즉, 원본을 수정하지 않는다. 또한 모든 iterable객체(list, dictionary, 문자열, set 등)에 적용할 수 있다. reverse 인자를 통해 내림차 순으로 정렬할 수 있고, key 인자에 함수를 넣어 정렬 기준을 Custom할 수도 있다 a = [2, 1, 5, 6, 4] sort_a = sorted(a) print(sort_a) # [1, 2, 4, 5, 6] print(a) # [2, 1, 5, 6, 4] -&gt; 원본 유지 sort() 메서드 sort()는 함수가 아니라 리스트의 메서드이다. 리스트의 메서드이기에 당연히 리스트에만 적용할 수 있다. 정렬 후의 값을 반환하는 것이 아닌 원본을 직접 정렬 상태로 수정한다. reverse 인자를 통해 내림차 순으로 정렬할 수 있고, key 인자에 함수를 넣어 정렬 기준을 Custom할 수도 있다 a = [2, 1, 5, 6, 4] a.sort() print(a) # [1, 2, 4, 5, 6] key 인자 활용 예를 들어, 우리가 튜플로 이뤄진 리스트를 정렬한다고 하자. 이때, 튜플의 특정 몇 번째 인자를 기준으로 정렬을 할 수 있다. tup_list = [(1, 15), (2, 5), (20, 2), (4, 6), (12, 9)] tup_list.sort() print(tup_list) # [(1, 15), (2, 5), (4, 6), (12, 9), (20, 2)] 위의 코드처럼 하면, 첫번째 인자를 기준으로 오름차 정렬이 이뤄진다. 두 번쨰 원소를 기준으로 하고 싶다면, sort()의 key인자에 함수를 넣어주면 된다. 주로 key에 lambda 함수를 지정하여 사용한다. tup_list = [(1, 15), (2, 5), (20, 2), (4, 6), (12, 9)] tup_list.sort(key = lambda x: x[1]) print(tup_list) # [(20, 2), (2, 5), (4, 6), (12, 9), (1, 15)] 이는 sort() 메서드 뿐만 아니라 sorted() 함수도 가능하다. 예를 들어, dictionary의 value로 정렬한다고 하자. 기본적으로 dictionary에 sorted를 적용하면, dictionary의 key를 기준으로 정렬된다. dic = {"banana": 2, "apple": 3, "grape": 7, "peach": 4} print(sorted(dic.items())) # [('apple', 3), ('banana', 2), ('grape', 7), ('peach', 4)] # 주의할 점은 단순히 sorted(dic)만 하면 key값만 정렬되어 반환된다. # 그래서 items()메서드로 (key, value)쌍으로 반환하여 정렬한다. 하지만 우리가 key가 기준이 아닌 value를 기준으로 하고 싶다면 key에 함수를 넣어주면 된다. dic = {"banana": 2, "apple": 3, "grape": 7, "peach": 4} sorted_by_value = (sorted(dic.items(), key = lambda x: x[1])) print(sorted_by_value) # [('banana', 2), ('apple', 3), ('peach', 4), ('grape', 7)]]]></summary></entry><entry><title type="html">[Python] lambda 함수</title><link href="https://82153.github.io/python/2025/09/22/lambda.html" rel="alternate" type="text/html" title="[Python] lambda 함수" /><published>2025-09-22T14:27:00+09:00</published><updated>2025-09-22T14:27:00+09:00</updated><id>https://82153.github.io/python/2025/09/22/lambda</id><content type="html" xml:base="https://82153.github.io/python/2025/09/22/lambda.html"><![CDATA[<h3 id="lambda-함수">lambda 함수</h3>

<ul>
  <li><strong>lambda 함수</strong>란 파이썬에서 이름 없이 정의할 수 있는 <strong>익명 함수(anonymous function)</strong>이다.</li>
  <li>기본 형식은 <code class="language-plaintext highlighter-rouge">lambda 매개변수: 표현식</code> 으로 정의하여 사용한다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">add</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="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span>
</code></pre></div></div>

<ul>
  <li>위 코드는 <code class="language-plaintext highlighter-rouge">def</code>로 정의된 일반 함수이며, 이를 <code class="language-plaintext highlighter-rouge">lambda</code>를 사용하면 같은 기능을 더 간결하게 표현할 수 있습니다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">f</span> <span class="o">=</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="n">x</span><span class="o">+</span><span class="n">y</span><span class="p">)</span>
<span class="n">f</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>위와 같이 <code class="language-plaintext highlighter-rouge">lambda</code> 식을 변수에 대입해 사용할 수 있다.</li>
  <li>만약, 일회용으로 한 번만 사용하고 싶다면 다음과 같이 바로 호출할 수도 있다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>이런 lambda함수는 주로 <code class="language-plaintext highlighter-rouge">map</code>, <code class="language-plaintext highlighter-rouge">filter</code> 등과 같이 사용되어 활용된다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ls</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="n">square_ls</span> <span class="o">=</span> <span class="nb">list</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">x</span><span class="o">**</span><span class="mi">2</span><span class="p">,</span> <span class="n">ls</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">square_ls</span><span class="p">)</span> <span class="c1"># [1, 4, 9, 16, 25]
</span></code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">map(func, iterable)</code>은 반복 가능한 객체의 각 요소에 함수를 적용한다.</li>
  <li><code class="language-plaintext highlighter-rouge">map()</code>은 <strong>이터레이터(iterator)</strong> 를 반환하므로, 리스트로 변환해야 결과를 볼 수 있다.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ls</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="n">bigger_than_3</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">,</span> <span class="n">ls</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">bigger_than_3</span><span class="p">)</span> <span class="c1"># [3, 4, 5]
</span></code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">filter(func, iterable)</code>은 함수 결과가 <code class="language-plaintext highlighter-rouge">True</code>인 요소만 걸러낸다.</li>
  <li><code class="language-plaintext highlighter-rouge">filter()</code>는 <strong>filter 객체(iterator)</strong>를 반환하므로, 결과를 확인하려면 리스트로 변환해야 한다.</li>
</ul>]]></content><author><name>김동욱</name></author><category term="Python" /><category term="Python" /><summary type="html"><![CDATA[lambda 함수 lambda 함수란 파이썬에서 이름 없이 정의할 수 있는 익명 함수(anonymous function)이다. 기본 형식은 lambda 매개변수: 표현식 으로 정의하여 사용한다. def add(x, y): return x + y 위 코드는 def로 정의된 일반 함수이며, 이를 lambda를 사용하면 같은 기능을 더 간결하게 표현할 수 있습니다. f = (lambda x,y: x+y) f(x, y) 위와 같이 lambda 식을 변수에 대입해 사용할 수 있다. 만약, 일회용으로 한 번만 사용하고 싶다면 다음과 같이 바로 호출할 수도 있다. (lambda x, y: x + y)(x, y) 이런 lambda함수는 주로 map, filter 등과 같이 사용되어 활용된다. ls = [1, 2, 3, 4, 5] square_ls = list(map(lambda x: x**2, ls)) print(square_ls) # [1, 4, 9, 16, 25] map(func, iterable)은 반복 가능한 객체의 각 요소에 함수를 적용한다. map()은 이터레이터(iterator) 를 반환하므로, 리스트로 변환해야 결과를 볼 수 있다. ls = [1, 2, 3, 4, 5] bigger_than_3 = list(filter(lambda x: x &gt;= 3, ls)) print(bigger_than_3) # [3, 4, 5] filter(func, iterable)은 함수 결과가 True인 요소만 걸러낸다. filter()는 filter 객체(iterator)를 반환하므로, 결과를 확인하려면 리스트로 변환해야 한다.]]></summary></entry><entry><title type="html">[Docker] Docker mysql 설치 및 DBeaver 연결</title><link href="https://82153.github.io/docker/2025/09/18/Docker-mysql-%EC%84%A4%EC%B9%98-%EB%B0%8F-DBeaver-%EC%97%B0%EA%B2%B0.html" rel="alternate" type="text/html" title="[Docker] Docker mysql 설치 및 DBeaver 연결" /><published>2025-09-18T17:03:00+09:00</published><updated>2025-09-18T17:03:00+09:00</updated><id>https://82153.github.io/docker/2025/09/18/Docker%20mysql%20%EC%84%A4%EC%B9%98%20%EB%B0%8F%20DBeaver%20%EC%97%B0%EA%B2%B0</id><content type="html" xml:base="https://82153.github.io/docker/2025/09/18/Docker-mysql-%EC%84%A4%EC%B9%98-%EB%B0%8F-DBeaver-%EC%97%B0%EA%B2%B0.html"><![CDATA[<h2 id="docker-hub에서-mysql-이미지-불러오기-및-container-실행">Docker Hub에서 mysql 이미지 불러오기 및 Container 실행</h2>

<ul>
  <li>Docker hub에서 mysql 8.0버전의 이미지를 pull한다.</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker pull mysql:8.0
</code></pre></div></div>

<p><img width="800" height="300" alt="스크린샷 2025-09-18 021054" src="https://github.com/user-attachments/assets/36235455-6535-42f0-8398-571605168e87" /></p>

<ul>
  <li>pull한 mysql이미지를 통해 Container를 실행시킨다.</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> <span class="o">{</span>Container 이름<span class="o">}</span> <span class="se">\</span>
	<span class="nt">-e</span> <span class="nv">MYSQL_ROOT_PASSWORD</span><span class="o">={</span>사용할 비번<span class="o">}</span> <span class="se">\ </span><span class="c"># 환경변수 설정</span>
	<span class="nt">-d</span> <span class="se">\ </span><span class="c"># 백그라운드(demon)으로 실행</span>
	<span class="nt">-p</span> <span class="o">{</span><span class="nb">local </span>port<span class="o">}</span>:<span class="o">{</span>container 내부 port<span class="o">}</span> <span class="se">\</span>
	<span class="o">{</span>Image 이름<span class="o">}</span>:<span class="o">{</span>Image Tag<span class="o">}</span>
</code></pre></div></div>

<p><img width="800" height="200" alt="스크린샷 2025-09-18 161554" src="https://github.com/user-attachments/assets/7a3bc6e9-be65-4b56-be4b-ef0b00404450" /></p>

<hr />

<h2 id="dbeaver-연동하기">DBeaver 연동하기</h2>

<ul>
  <li>
    <p>데이터베이스 → 새 데이터베이스 연결을 클릭 한 뒤에 mysql을 선택한다.</p>

    <p><img width="600" height="400" alt="스크린샷 2025-09-18 161922" src="https://github.com/user-attachments/assets/319e12e7-2b32-4279-8de5-584cf4a383e5" /></p>
  </li>
  <li>
    <p>이후에 내가 Docker Container 실행 시에 작성한 <strong>local의 Port</strong>로 맞춰주고, 비번을 작성해준다.</p>

    <p><img width="600" height="400" alt="스크린샷 2025-09-18 162601" src="https://github.com/user-attachments/assets/8fa6e17f-c92a-48df-8120-6819c8075ae1" /></p>
  </li>
  <li>
    <p>그 다음에 Drive properties로 들어가서 <strong>allowPublicKeyRetrieval</strong>을 true로 변경해주고 완료를 누르면 dbeaver에연동은 끝났다.</p>

    <p><img width="600" height="400" alt="스크린샷 2025-09-18 162430" src="https://github.com/user-attachments/assets/1c7b4b36-361a-4555-becf-cde07846bbe7" /></p>
  </li>
</ul>

<hr />

<h2 id="employees-db-다운-받기">Employees DB 다운 받기</h2>

<ul>
  <li>mysql에서 연습용으로 제공하는 employees db를 다운 받을 것이다.</li>
  <li>우선 https://github.com/datacharmer/test_db이 링크에 있는 Repository를 다운받고 압축을 해제한다.</li>
  <li>
    <p>그리고 다운받은 Repository를 Docker Container 내부로 옮겨준다.</p>

    <p><img width="600" height="400" alt="스크린샷 2025-09-18 164553" src="https://github.com/user-attachments/assets/ebd05cc2-a320-4e12-8c6e-6f3567ab9709" /></p>
  </li>
  <li>그리고 mysql Container로 들어간다.</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker <span class="nb">exec</span> <span class="nt">-it</span> mysql-db mysql <span class="nt">-u</span> root <span class="nt">-p</span>
</code></pre></div></div>

<ul>
  <li>마지막으로 employees.sql 파일을 실행해준다.</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SOURCE /employees.sql<span class="p">;</span>
</code></pre></div></div>
<div style="display:flex; gap:10px;">
  <img src="https://github.com/user-attachments/assets/45dde98f-df19-4bc2-87e8-830b8c8f6c1b" width="400" />
  <img src="https://github.com/user-attachments/assets/cbd7941a-1c19-4acc-8670-b0e83167befc" width="400" />
</div>

<ul>
  <li>확인해보면 제대로 DB를 가져온 것을 확인할 수 있다.</li>
</ul>]]></content><author><name>김동욱</name></author><category term="Docker" /><category term="Docker" /><summary type="html"><![CDATA[Docker Hub에서 mysql 이미지 불러오기 및 Container 실행 Docker hub에서 mysql 8.0버전의 이미지를 pull한다. docker pull mysql:8.0 pull한 mysql이미지를 통해 Container를 실행시킨다. docker run --name {Container 이름} \ -e MYSQL_ROOT_PASSWORD={사용할 비번} \ # 환경변수 설정 -d \ # 백그라운드(demon)으로 실행 -p {local port}:{container 내부 port} \ {Image 이름}:{Image Tag} DBeaver 연동하기 데이터베이스 → 새 데이터베이스 연결을 클릭 한 뒤에 mysql을 선택한다. 이후에 내가 Docker Container 실행 시에 작성한 local의 Port로 맞춰주고, 비번을 작성해준다. 그 다음에 Drive properties로 들어가서 allowPublicKeyRetrieval을 true로 변경해주고 완료를 누르면 dbeaver에연동은 끝났다. Employees DB 다운 받기 mysql에서 연습용으로 제공하는 employees db를 다운 받을 것이다. 우선 https://github.com/datacharmer/test_db이 링크에 있는 Repository를 다운받고 압축을 해제한다. 그리고 다운받은 Repository를 Docker Container 내부로 옮겨준다. 그리고 mysql Container로 들어간다. docker exec -it mysql-db mysql -u root -p 마지막으로 employees.sql 파일을 실행해준다. SOURCE /employees.sql; 확인해보면 제대로 DB를 가져온 것을 확인할 수 있다.]]></summary></entry><entry><title type="html">[Docker] 기본 Command</title><link href="https://82153.github.io/docker/2025/09/14/Docker-Command.html" rel="alternate" type="text/html" title="[Docker] 기본 Command" /><published>2025-09-14T15:53:00+09:00</published><updated>2025-09-14T15:53:00+09:00</updated><id>https://82153.github.io/docker/2025/09/14/Docker%20Command</id><content type="html" xml:base="https://82153.github.io/docker/2025/09/14/Docker-Command.html"><![CDATA[<h2 id="general-command">General Command</h2>

<ol>
  <li>
    <p><strong>Docker 버전 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker <span class="nt">--version</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker의 정보 확인(Container, Image의 개수, 저장소 세부사항 등)</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker info
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker의 Command와 옵션 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker <span class="nb">help</span>
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="docker-image-관련-command">Docker Image 관련 Command</h2>

<ol>
  <li>
    <p><strong>Local Machine에 있는 모든 Image 리스트 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker image
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker Hub이나 다른 저장소에서 이미지 불러오기</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker pull <span class="o">{</span>image 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Docker Image 만들기</strong>
    <ul>
      <li>.은 현재 directory의 docker file을 기반으로 만들라는 것.</li>
      <li>-t는 태깅하는 것으로 이름을 붙이는 것이다.</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker build <span class="nt">-t</span> <span class="o">{</span>image 이름<span class="o">}</span> <span class="nb">.</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Docker의 다른 이름이나 버전을 태깅하는 법</strong>
    <ul>
      <li>하나의 이미지에는 여러 개의 tag가 붙을 수 있다.</li>
      <li>즉, 아래 코드는 새로운 tag를 추가하는 것이지 기존 tag를 없애고 새로 tag를 지정하는 것이 아니다.</li>
      <li>source image: tag를 붙일 이미지</li>
      <li>target image:tag : 새로 붙일 image이름과 tag</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker tag <span class="o">{</span><span class="nb">source </span>image<span class="o">}</span> <span class="o">{</span>target image:tag<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Docker Image를 Docker Hub이나 저장소에 push</strong>
    <ul>
      <li>저장소가 연결되어 있으면 해당 저장소로 저장될 것이고, 아니면 Docker Hub에 저장됨</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker push <span class="o">{</span>image 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Docker Image 삭제</strong>
    <ul>
      <li>list로 넣어 한번에 여러 개 삭제 가능</li>
      <li>docker rmi image1 image2 image3 이런 식으로 한번에 삭제 가능</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker rmi <span class="o">{</span>Image <span class="nb">id</span> / Image 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="docker-container-관련-command">Docker Container 관련 Command</h2>

<ol>
  <li><strong>현재 작동중인 Container 확인</strong>
    <ul>
      <li>모든 container를 보고 싶을 때는 -a 옵션 사용</li>
      <li>docker pd -a</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker ps
</code></pre></div>    </div>
  </li>
  <li><strong>이미지로부터 Docker Container 생성</strong>
    <ul>
      <li>만약 Local에 없는 Image를 run한다면 docker hub에서 자동으로 다운 받는다.</li>
      <li>-d: 백그라운드(Demon)에서 실행</li>
      <li>-p {host-port}:{container-port}: 호스트 포트와 컨테이너 포트 연결</li>
      <li>–name {container 이름}: 이름 지정</li>
      <li>-v {host-port}:{container-port}: volume(저장소) 연결</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker run <span class="o">{</span>option<span class="o">}</span> <span class="o">{</span>Image 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Container 삭제</strong>
    <ul>
      <li>-f옵션으로 현재 실행 중인 container도 삭제 가능(rm -f)</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker <span class="nb">rm</span> <span class="o">{</span>container <span class="nb">id</span> / 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Container 중지</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker stop <span class="o">{</span>container <span class="nb">id</span> / 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>중지된 Container 시작</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker start <span class="o">{</span>container <span class="nb">id</span> / 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Container 재시작</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker restart <span class="o">{</span>container <span class="nb">id</span> / 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="container-interaction-command">Container Interaction Command</h2>
<ul>
  <li>현재 실행중인 Container와 소통할 때 사용하는 명령어</li>
</ul>

<ol>
  <li>
    <p><strong>실행중인 Container 내부에서 새로운 프로세스 실행</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker <span class="nb">exec</span> <span class="o">{</span>container <span class="nb">id</span> / name<span class="o">}</span> <span class="o">{</span><span class="nb">command</span><span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Container Log 확인</strong>
    <ul>
      <li>-f/-follow: 실시간 log확인</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker logs <span class="o">{</span>option<span class="o">}</span> <span class="o">{</span>container <span class="nb">id</span> / name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li><strong>Container 죽이기</strong>
    <ul>
      <li>-s: 보낼 signal 정함</li>
      <li>SIGTERM, SiGHUP, SIGINT 등의 signal이 있음</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker <span class="nb">kill</span> <span class="o">{</span>option<span class="o">}</span> <span class="o">{</span>container <span class="nb">id</span> / name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="debugging-command">Debugging Command</h2>

<ol>
  <li><strong>Docker 객체(컨테이너, 이미지, 볼륨, 네트워크 등)의 상세 정보 확인</strong>
    <ul>
      <li>JSON 형식으로 반환하여 보여줌</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker inspect <span class="o">{</span>object <span class="nb">id</span> / name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>실행중인 Container의 실시간 자원 사용량 및 통계량 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker stats <span class="o">{</span>container <span class="nb">id</span> / name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Container 내부의 Process 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker top <span class="o">{</span>container <span class="nb">id</span> / name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker Demon이 보내는 이벤트 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker events
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="docker-volume-command">Docker Volume Command</h2>

<ol>
  <li>
    <p><strong>Docker Volume 생성</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker volume create <span class="o">{</span>volume 이름<span class="o">}</span> <span class="c"># named volume 생성</span>
 docker run <span class="nt">-v</span> <span class="o">{</span>Volume을 mount할 위치<span class="o">}</span> <span class="o">{</span>image 이름<span class="o">}</span> <span class="c"># anonymous volume 생성</span>
 docker run <span class="nt">-v</span> <span class="o">{</span>local의 위치<span class="o">}</span>:<span class="o">{</span>volume을 mount할 위치<span class="o">}</span> <span class="o">{</span>image 이름<span class="o">}</span> <span class="c"># bind mounts 생성</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker Volume들 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker volume <span class="nb">ls</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker Volume에 대한 정보 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker volume inspect <span class="o">{</span>volume 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Docker Volume 삭제</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker volume <span class="nb">rm</span> <span class="o">{</span>volume 이름<span class="o">}</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>사용하지 않는 Volume 삭제</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker volume prune
</code></pre></div>    </div>
  </li>
</ol>

<hr />

<h2 id="docker-compose-command">Docker Compose Command</h2>

<ol>
  <li><strong>Compose 실행</strong>
    <ul>
      <li>compose.yml파일을 기반으로 compose 실행</li>
    </ul>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker-compose up
 <span class="c"># docker-compose up --build: 이미지 build후에 compose 실행</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Compose 중지</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker-compose down
 <span class="c"># -v 옵션을 주어 volume까지 삭제 가능</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Compose 실행 여부 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker-compose ps
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>Compose 로그 확인</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker-compose logs
 <span class="c"># -f 옵션으로 실시간 log확인 가능</span>
</code></pre></div>    </div>
  </li>
  <li>
    <p><strong>특정 Service만 재시작</strong></p>

    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker-compose restart <span class="o">{</span>service_name<span class="o">}</span>
</code></pre></div>    </div>
  </li>
</ol>]]></content><author><name>김동욱</name></author><category term="Docker" /><category term="Docker" /><summary type="html"><![CDATA[General Command Docker 버전 확인 docker --version Docker의 정보 확인(Container, Image의 개수, 저장소 세부사항 등) docker info Docker의 Command와 옵션 확인 docker help Docker Image 관련 Command Local Machine에 있는 모든 Image 리스트 확인 docker image Docker Hub이나 다른 저장소에서 이미지 불러오기 docker pull {image 이름} Docker Image 만들기 .은 현재 directory의 docker file을 기반으로 만들라는 것. -t는 태깅하는 것으로 이름을 붙이는 것이다. docker build -t {image 이름} . Docker의 다른 이름이나 버전을 태깅하는 법 하나의 이미지에는 여러 개의 tag가 붙을 수 있다. 즉, 아래 코드는 새로운 tag를 추가하는 것이지 기존 tag를 없애고 새로 tag를 지정하는 것이 아니다. source image: tag를 붙일 이미지 target image:tag : 새로 붙일 image이름과 tag docker tag {source image} {target image:tag} Docker Image를 Docker Hub이나 저장소에 push 저장소가 연결되어 있으면 해당 저장소로 저장될 것이고, 아니면 Docker Hub에 저장됨 docker push {image 이름} Docker Image 삭제 list로 넣어 한번에 여러 개 삭제 가능 docker rmi image1 image2 image3 이런 식으로 한번에 삭제 가능 docker rmi {Image id / Image 이름} Docker Container 관련 Command 현재 작동중인 Container 확인 모든 container를 보고 싶을 때는 -a 옵션 사용 docker pd -a docker ps 이미지로부터 Docker Container 생성 만약 Local에 없는 Image를 run한다면 docker hub에서 자동으로 다운 받는다. -d: 백그라운드(Demon)에서 실행 -p {host-port}:{container-port}: 호스트 포트와 컨테이너 포트 연결 –name {container 이름}: 이름 지정 -v {host-port}:{container-port}: volume(저장소) 연결 docker run {option} {Image 이름} Container 삭제 -f옵션으로 현재 실행 중인 container도 삭제 가능(rm -f) docker rm {container id / 이름} Container 중지 docker stop {container id / 이름} 중지된 Container 시작 docker start {container id / 이름} Container 재시작 docker restart {container id / 이름} Container Interaction Command 현재 실행중인 Container와 소통할 때 사용하는 명령어 실행중인 Container 내부에서 새로운 프로세스 실행 docker exec {container id / name} {command} Container Log 확인 -f/-follow: 실시간 log확인 docker logs {option} {container id / name} Container 죽이기 -s: 보낼 signal 정함 SIGTERM, SiGHUP, SIGINT 등의 signal이 있음 docker kill {option} {container id / name} Debugging Command Docker 객체(컨테이너, 이미지, 볼륨, 네트워크 등)의 상세 정보 확인 JSON 형식으로 반환하여 보여줌 docker inspect {object id / name} 실행중인 Container의 실시간 자원 사용량 및 통계량 확인 docker stats {container id / name} Container 내부의 Process 확인 docker top {container id / name} Docker Demon이 보내는 이벤트 확인 docker events Docker Volume Command Docker Volume 생성 docker volume create {volume 이름} # named volume 생성 docker run -v {Volume을 mount할 위치} {image 이름} # anonymous volume 생성 docker run -v {local의 위치}:{volume을 mount할 위치} {image 이름} # bind mounts 생성 Docker Volume들 확인 docker volume ls Docker Volume에 대한 정보 확인 docker volume inspect {volume 이름} Docker Volume 삭제 docker volume rm {volume 이름} 사용하지 않는 Volume 삭제 docker volume prune Docker Compose Command Compose 실행 compose.yml파일을 기반으로 compose 실행 docker-compose up # docker-compose up --build: 이미지 build후에 compose 실행 Compose 중지 docker-compose down # -v 옵션을 주어 volume까지 삭제 가능 Compose 실행 여부 확인 docker-compose ps Compose 로그 확인 docker-compose logs # -f 옵션으로 실시간 log확인 가능 특정 Service만 재시작 docker-compose restart {service_name}]]></summary></entry><entry><title type="html">[Docker] 기본 개념</title><link href="https://82153.github.io/docker/2025/09/12/Docker-Basic.html" rel="alternate" type="text/html" title="[Docker] 기본 개념" /><published>2025-09-12T14:59:00+09:00</published><updated>2025-09-12T14:59:00+09:00</updated><id>https://82153.github.io/docker/2025/09/12/Docker%20Basic</id><content type="html" xml:base="https://82153.github.io/docker/2025/09/12/Docker-Basic.html"><![CDATA[<h2 id="가상화">가상화</h2>

<ul>
  <li>개발 시에는 주로 운영 서버가 아닌 Local에서 개발을 한다. 이 때, 개발을 진행한 Local서버와 Production 서버의 OS가 다를 경우 라이브러리 등을 설치할 때 다르게 진행을 해야 하고, 또한 OS가 같더라도 Local과 Production의 환경 변수 차이로 인해 제대로 동작하지 않을 수 있다.</li>
  <li>이러한 문제를 해결하기 위해 README 등에 환경 설정을 기록하고 실행하지만, 이는 사람이 직접 수행해야 하므로 에러가 발생하기 쉽고, 여러 서버에서 반복해야 하는 번거로움이 있다.</li>
  <li>이를 위해 <strong>가상화</strong>를 진행한다. <strong>가상화란 서버환경까지 모두 한번에 소프트웨어화하여 어디서든 동일한 환경이 되도록 하는 것</strong>이다. 이를 통해 특정 소프트웨어 환경을 만들어 Local과 Production서버에 그대로 사용함으로써, 개발과 운영 서버의 환경을 일치 시킬 수 있다.</li>
  <li>과거에는 이 가상화를 위해 VM(Virtual Machine)을 사용하였다. VM이란 실제 물리적 컴퓨터(Host Machine) 위에 OS를 포함한 가상화 소프트웨어를 두는 방식이다.</li>
  <li>하지만 이 VM은 OS 위에 OS를 하나 더 두기에 리소스를 굉장히 많이 사용한다는 단점이 있다. 이런 단점을 극복하기 위해 Container를 사용한다. Container는 <strong>VM과 달리 OS 위에 OS를 두지않고, Host의 OS를 공유하기에 VM보다 더 가볍고 빠른 경량화된  가상화 프로세스이다.</strong></li>
</ul>

<div style="display:flex; gap:10px;">
  <img src="https://github.com/user-attachments/assets/0838033a-7053-45a4-a031-7a55ea61761c" width="400" />
  <img src="https://github.com/user-attachments/assets/039887a3-8739-4b94-be2e-7ae84aa835e2" width="400" />
</div>

<hr />

<h2 id="docker">Docker</h2>

<ul>
  <li>Docker는 Container 기술을 쉽게 사용할 수 있도록 나온 도구로서, Container를 활용하여 개발자가 Application을 가볍고, 이식 가능하며, 일관된 방식으로 Application과 그 실행 환경을 <strong>빌드</strong>, <strong>배포</strong>, <strong>실행</strong>할 수 있도록 도와주도록 설계된 오픈 소스 플랫폼이다.</li>
  <li><strong>Docker의 장점</strong>
    <ol>
      <li><strong>Portability</strong>: 개발자 환경, 테스트 서버, Cloud서버에서 동일한 환경으로 설정 가능하다.</li>
      <li><strong>Scalability</strong>: Docker Container는 필요한 만큼 늘릴 수 있어, 트래픽이 몰릴 경우 Horizontal Scaling으로 트래픽을 분산시킬 수 있다.</li>
      <li><strong>Speed</strong>:  Container는 VM과 달리, OS 커널을 공유하기 때문에 속도가 더 빠르다.</li>
      <li><strong>Efficiency</strong>: Container는 필요한 라이브러리와 애플리케이션만 포함하기 때문에 리소스(메모리, CPU)를 VM보다 적게 사용한다.</li>
      <li><strong>Consistency</strong></li>
    </ol>
  </li>
  <li><strong>Docker의 주요 구성 요소</strong>
    <ol>
      <li><strong>Docker Engine</strong>: Container들을 관리하는 엔진으로 Container를 생성, 실행 관리하는 프레임 워크이다.</li>
      <li><strong>Docker Image</strong>: Scripting된 Docker File로부터 만들어진 바이너리 파일로 <strong>Read-Only</strong>이다.</li>
      <li><strong>Docker Container</strong>: 일반화된 Docker Image를 기반으로 실제 실행 중인 <strong>인스턴스</strong>로 Docker Container간의 Communication이 가능하다.</li>
      <li><strong>Docker File</strong>: <strong>Docker Image를 정의</strong>하는 Script파일이다.</li>
      <li><strong>Docker Compose</strong>: <strong>여러 Docker Container를 실행</strong>할 수 있는 도구다.</li>
      <li><strong>Docker Hub</strong>: Docker Image를 저장, 공유하는 <strong>Cloud 기반의 저장소</strong>이다.</li>
    </ol>
  </li>
  <li><strong>Docker의 Workflow</strong>
    <ol>
      <li>개발 환경을 정의한 Docker File을 작성</li>
      <li>
        <p>Docker Image를 Build한다.</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker build <span class="nt">-t</span> <span class="o">{</span>이미지 이름<span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Docker Image로부터 Container를 실행한다.</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker run <span class="nt">-d</span> <span class="nt">-p</span> <span class="o">{</span>연결할 포트번호<span class="o">}</span> <span class="o">{</span>이미지 이름<span class="o">}</span>
 <span class="c"># -d: Demon(백그라운드)로 돌아가게 하는 것</span>
 <span class="c"># -p: 포트를 연결하는 것</span>
</code></pre></div>        </div>
      </li>
      <li>
        <p>Docker Image를 Docker Hub나 다른 저장소에 저장한다.</p>

        <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> docker push <span class="o">{</span>저장할 이미지<span class="o">}</span>
</code></pre></div>        </div>
      </li>
      <li>Production에서 Container를 적용한다.</li>
    </ol>
  </li>
</ul>

<hr />

<h2 id="docker-volume">Docker Volume</h2>

<ul>
  <li><strong>Docker Container</strong>는 Image 위에 <strong>writable layer</strong>를 덧붙여 실행되는 인스턴스이다. 이 writable layer는 컨테이너와 함께 존재하기 때문에, 컨테이너를 삭제하면 내부에 저장했던 파일도 함께 사라진다. → 즉, Container는 <strong>휘발성</strong></li>
  <li>이러한 컨테이너의 휘발성을 보완하기 위해 나온 개념이 <strong>Docker Volume</strong>으로 <strong>Docker Volume</strong>은 컨테이너 외부에 존재하며, <strong>Docker 엔진이 직접 관리</strong>하는 독립적인 저장소이다. 즉, 특정 host 디렉토리에 종속되지 않고 Docker 자체가 데이터를 관리한다.</li>
  <li>이를 통해 데이터의 <strong>영속성(persistence)을 보장</strong>하고, 여러 컨테이너 간 <strong>데이터 공유</strong>도 가능하다.</li>
  <li><strong>Docker Volume의 종류</strong>
    <ol>
      <li><strong>Anonymous Volume</strong>: 이름 없이 생성되는 볼륨으로, 컨테이너 실행 시 자동으로 만들 수 있다.</li>
      <li><strong>Named Volume</strong>: 이름을 붙여준 볼륨으로 관리 및 재사용이 쉽다.</li>
      <li><strong>Bind Mounts</strong>: Local과 Container의 디렉토리를 연결한 것으로 Docker외부에서 관리한다.</li>
    </ol>
  </li>
</ul>

<hr />

<h2 id="docker-compose">Docker Compose</h2>

<ul>
  <li><strong>Docker Compose</strong>는 Local 환경에서 여러 개의 Docker 컨테이너를 동시에 실행하고 관리할 수 있게 해주는 도구이다. → 즉, 복잡한 애플리케이션을 <strong>단일 애플리케이션처럼</strong> 관리할 수 있다.(<strong>Multi-Container Orchestration</strong>)</li>
  <li>compose.yml 파일에 <strong>services, volumes, networks</strong> 등을 정의하고, 설정된 모든 서비스를 한 번에 생성 및 실행할 수 있다.</li>
  <li>compose.yml 파일에 정의된 서비스들은 서로 <strong>독립적</strong>이며(<strong>Service Independence</strong>), 개발·스테이징·운영 환경 등에서 <strong>일관성 있게 재사용</strong>할 수 있다.(<strong>Portability</strong>)</li>
  <li>또한 단순한 명령어로 쉽게 환경을 구성하거나 해제할 수 있으며(<strong>Simplified Workflow</strong>), compose.yml 파일을 통해 서비스와 네트워크를 <strong>선언적으로 간단히 정의</strong>할 수 있다.(<strong>Declarative Configuration</strong>)</li>
</ul>]]></content><author><name>김동욱</name></author><category term="Docker" /><category term="Docker" /><summary type="html"><![CDATA[가상화 개발 시에는 주로 운영 서버가 아닌 Local에서 개발을 한다. 이 때, 개발을 진행한 Local서버와 Production 서버의 OS가 다를 경우 라이브러리 등을 설치할 때 다르게 진행을 해야 하고, 또한 OS가 같더라도 Local과 Production의 환경 변수 차이로 인해 제대로 동작하지 않을 수 있다. 이러한 문제를 해결하기 위해 README 등에 환경 설정을 기록하고 실행하지만, 이는 사람이 직접 수행해야 하므로 에러가 발생하기 쉽고, 여러 서버에서 반복해야 하는 번거로움이 있다. 이를 위해 가상화를 진행한다. 가상화란 서버환경까지 모두 한번에 소프트웨어화하여 어디서든 동일한 환경이 되도록 하는 것이다. 이를 통해 특정 소프트웨어 환경을 만들어 Local과 Production서버에 그대로 사용함으로써, 개발과 운영 서버의 환경을 일치 시킬 수 있다. 과거에는 이 가상화를 위해 VM(Virtual Machine)을 사용하였다. VM이란 실제 물리적 컴퓨터(Host Machine) 위에 OS를 포함한 가상화 소프트웨어를 두는 방식이다. 하지만 이 VM은 OS 위에 OS를 하나 더 두기에 리소스를 굉장히 많이 사용한다는 단점이 있다. 이런 단점을 극복하기 위해 Container를 사용한다. Container는 VM과 달리 OS 위에 OS를 두지않고, Host의 OS를 공유하기에 VM보다 더 가볍고 빠른 경량화된 가상화 프로세스이다. Docker Docker는 Container 기술을 쉽게 사용할 수 있도록 나온 도구로서, Container를 활용하여 개발자가 Application을 가볍고, 이식 가능하며, 일관된 방식으로 Application과 그 실행 환경을 빌드, 배포, 실행할 수 있도록 도와주도록 설계된 오픈 소스 플랫폼이다. Docker의 장점 Portability: 개발자 환경, 테스트 서버, Cloud서버에서 동일한 환경으로 설정 가능하다. Scalability: Docker Container는 필요한 만큼 늘릴 수 있어, 트래픽이 몰릴 경우 Horizontal Scaling으로 트래픽을 분산시킬 수 있다. Speed: Container는 VM과 달리, OS 커널을 공유하기 때문에 속도가 더 빠르다. Efficiency: Container는 필요한 라이브러리와 애플리케이션만 포함하기 때문에 리소스(메모리, CPU)를 VM보다 적게 사용한다. Consistency Docker의 주요 구성 요소 Docker Engine: Container들을 관리하는 엔진으로 Container를 생성, 실행 관리하는 프레임 워크이다. Docker Image: Scripting된 Docker File로부터 만들어진 바이너리 파일로 Read-Only이다. Docker Container: 일반화된 Docker Image를 기반으로 실제 실행 중인 인스턴스로 Docker Container간의 Communication이 가능하다. Docker File: Docker Image를 정의하는 Script파일이다. Docker Compose: 여러 Docker Container를 실행할 수 있는 도구다. Docker Hub: Docker Image를 저장, 공유하는 Cloud 기반의 저장소이다. Docker의 Workflow 개발 환경을 정의한 Docker File을 작성 Docker Image를 Build한다. docker build -t {이미지 이름} Docker Image로부터 Container를 실행한다. docker run -d -p {연결할 포트번호} {이미지 이름} # -d: Demon(백그라운드)로 돌아가게 하는 것 # -p: 포트를 연결하는 것 Docker Image를 Docker Hub나 다른 저장소에 저장한다. docker push {저장할 이미지} Production에서 Container를 적용한다. Docker Volume Docker Container는 Image 위에 writable layer를 덧붙여 실행되는 인스턴스이다. 이 writable layer는 컨테이너와 함께 존재하기 때문에, 컨테이너를 삭제하면 내부에 저장했던 파일도 함께 사라진다. → 즉, Container는 휘발성 이러한 컨테이너의 휘발성을 보완하기 위해 나온 개념이 Docker Volume으로 Docker Volume은 컨테이너 외부에 존재하며, Docker 엔진이 직접 관리하는 독립적인 저장소이다. 즉, 특정 host 디렉토리에 종속되지 않고 Docker 자체가 데이터를 관리한다. 이를 통해 데이터의 영속성(persistence)을 보장하고, 여러 컨테이너 간 데이터 공유도 가능하다. Docker Volume의 종류 Anonymous Volume: 이름 없이 생성되는 볼륨으로, 컨테이너 실행 시 자동으로 만들 수 있다. Named Volume: 이름을 붙여준 볼륨으로 관리 및 재사용이 쉽다. Bind Mounts: Local과 Container의 디렉토리를 연결한 것으로 Docker외부에서 관리한다. Docker Compose Docker Compose는 Local 환경에서 여러 개의 Docker 컨테이너를 동시에 실행하고 관리할 수 있게 해주는 도구이다. → 즉, 복잡한 애플리케이션을 단일 애플리케이션처럼 관리할 수 있다.(Multi-Container Orchestration) compose.yml 파일에 services, volumes, networks 등을 정의하고, 설정된 모든 서비스를 한 번에 생성 및 실행할 수 있다. compose.yml 파일에 정의된 서비스들은 서로 독립적이며(Service Independence), 개발·스테이징·운영 환경 등에서 일관성 있게 재사용할 수 있다.(Portability) 또한 단순한 명령어로 쉽게 환경을 구성하거나 해제할 수 있으며(Simplified Workflow), compose.yml 파일을 통해 서비스와 네트워크를 선언적으로 간단히 정의할 수 있다.(Declarative Configuration)]]></summary></entry><entry><title type="html">[DL Basic] 정규화(Regularization)</title><link href="https://82153.github.io/dl%20basic/2025/04/20/%EC%A0%95%EA%B7%9C%ED%99%94.html" rel="alternate" type="text/html" title="[DL Basic] 정규화(Regularization)" /><published>2025-04-20T13:54:00+09:00</published><updated>2025-04-20T13:54:00+09:00</updated><id>https://82153.github.io/dl%20basic/2025/04/20/%EC%A0%95%EA%B7%9C%ED%99%94</id><content type="html" xml:base="https://82153.github.io/dl%20basic/2025/04/20/%EC%A0%95%EA%B7%9C%ED%99%94.html"><![CDATA[<h2 id="정규화regularization-규제화">정규화(Regularization, 규제화)</h2>

<ul>
  <li>이전에 신경망을 학습 할 때, 좋은 위치에서 시작하는 가중치 초기화에 대하여 알아보았다. 이와 더불어 최적해로 가는 길을 잘 찾을 수 있도록 해주는 정규화에 대해 알아보려 한다.</li>
  <li><strong>정규화란 최적화 과정에서 최적해를 잘 찾도록 정보를 추가하는 기법</strong>으로, 성능을 개선할 수 있는 포괄적인 기법들을 포함한다.</li>
  <li>여기서 <strong>성능이 좋다는 것은 일반화가 잘 되었다</strong>는 것으로 <strong>훈련 성능과 검증/테스트 성능의 차이를 나타내는 일반화 오류</strong>가 적다는 것이다.</li>
</ul>

<h3 id="정규화의-접근-방식">정규화의 접근 방식</h3>

<ol>
  <li><strong>모델을 최대한 단순하게 만들기</strong>
    <ul>
      <li>복잡한 모델의 파라미터 수를 줄이거나, 파라미터를 제거하는 등의 기법으로 <strong>모델을 단순하게 만들어 과적합을 줄이는 것</strong>이다.</li>
    </ul>
  </li>
  <li><strong>사전 지식을 표현해서 최적해를 빠르게 찾도록 함</strong>
    <ul>
      <li>데이터나 모델에 대한 사전 분포를 이용하여 정확하고 빠르게 해를 찾는 방법으로 가중치 감소가 그 예이다.</li>
    </ul>
  </li>
  <li><strong>확률적 성질을 추가</strong>
    <ul>
      <li>데이터, 모델, 훈련 기법 등에 확률적 성질을 추가하여 조금씩 변형된 형태로 데이터를 다루어 다양한 상황에서 학습하는 효과를 준다.</li>
      <li>이는 손실 함수가 풍부한 데이터를 이용하여 넓은 범위를 세밀하게 표현하도록 하여 더 정확한 해를 찾고, Noise에 민감하지 않다.</li>
      <li>데이터 증강, 잡음 주입, 드롭 아웃 등의 방식을 이용한다.</li>
    </ul>
  </li>
  <li><strong>여러 가설을 고려하여 예측</strong>
    <ul>
      <li>앙상블 같은 방법을 이용하여 하나의 모델이 가지는 편향을 제거하여 오차를 최소화하는 방법이다.</li>
    </ul>
  </li>
</ol>

<hr />

<h3 id="가중치-감소">가중치 감소</h3>

<ul>
  <li>선형 회귀를 가정했을 때, $w^{T}x + b = 0$과 2를 곱한 $2w^{T}x+2b$는 완전히 같은 직선이다. 이렇듯 하나의 직선을 표현할 수 있는 표현은 굉장히 많다.</li>
  <li>이 중에서 가장 좋은 식은 $w^{T}x+b=0$이다. 왜냐하면 <strong>최적화 시에 다루는 숫자의 크기가 작을 수록 오차의 변동성이 낮아지기 때문</strong>이다.(파라미터 값이 작을수록 손실 함수의 변화가 더 매끄럽고 안정적)</li>
  <li><strong>즉, 파라미터 공간이 원점 근처에 있을 때, 정확한 해를 빠르게 찾을 수 있는 것이다.</strong> 그렇기에 학습 시에 weight와 bias는 작은 것이 좋다.</li>
  <li><strong>학습 과정에서 작은 크기의 가중치를 갖게 해주는 것이 가중치 감소</strong>이다.</li>
  <li>
    <p>가중치 감소는 $J(w) = J(w) + \lambda R(w)$와 같이 손실 함수($J(W)$)에 가중치의 크기를 표현하는 정규화 항($\lambda R(W)$)을 더하여 사용한다. $\lambda$는 정규화 상수로서, 가중치의 크기를 조절해주는 역할을 한다.($\lambda$가 크면 정규화 항의 비중이 커지며, 가중치의 크기가 더 작아진다.)</p>

    <table>
      <thead>
        <tr>
          <th> </th>
          <th>$\lambda$  커짐</th>
          <th>$\lambda$ 작아짐</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>정규항의 비중</td>
          <td>비중이 커짐</td>
          <td>비중이 작아짐</td>
        </tr>
        <tr>
          <td>가중치의 크기</td>
          <td>더 작아짐</td>
          <td>더 커짐</td>
        </tr>
      </tbody>
    </table>
  </li>
  <li>주로 정규화 항은  $L_{2}$노름이나 $L_{1}$노름을 사용한다. <strong>$L_{2}$노름을 사용하면 리지 회귀</strong>, <strong>$L_{1}$노름을 사용하면 라소 회귀</strong>라고 한다.</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/d3b16e9c-3790-4920-b6a2-f2f621d3e899" alt="스크린샷 2025-04-15 201116" /></p>

<ul>
  <li><strong>리지 회귀는 주로 가중치의 사전 분포를 모르거나, 가우시안 분포일 경우 사용</strong>하고, <strong>라소 회귀는 데이터의 사전 분포가 라플라스 분포일 경우에 사용</strong>한다.</li>
  <li>또한, 가중치 감소는 정규화의 효과를 볼 수 있다. 원래 손실 함수 값은 최적해 방향으로 가려하지만, 정규화 항은 다른 방향으로 가려고 하기에 최적해 부분이 아닌 정규화 항과 손실 함수의 접점이 해가 된다.</li>
  <li>전역 최적해는 과적합 일수도 있기에, 거기에서 떨어진 부분의 가중치를 사용하여 과적합을 방지하기에 정규화의 효과를 볼 수 있는 것이다.</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/42878b94-c772-42a1-853b-b4fa84c36200" alt="스크린샷 2025-04-15 201714" /></p>

<ul>
  <li>위의 그림을 보면 리지 회귀를 보면, 손실 함수가 어느 곳에 있던지 정규화 항이 원 모양이기에 접할 확률은 손실 함수가 어디에 있던지 동일하다.</li>
  <li>하지만 라소 회귀의 경우, 마름모 모양으로 꼭짓점 부분에서 접할 확률이 가장 높다. 이는 최적해가 특정 축 위에 있을 확률이 높다는 것이고, 나머지 축의 값은 0이 된다는 것이다. → 정규화 접근 방식의 “모델을 최대한 단순하게 만들기<strong>”</strong>에 해당되고, 리지 회귀는 정규화 접근 방식의 “사전 지식을 표현해서 최적해를 빠르게 찾도록한다.”에 해당한다.</li>
</ul>

<hr />

<h3 id="조기-종료">조기 종료</h3>

<ul>
  <li><strong>조기 종료란 모델이 과적합되기 전에 훈련을 멈추는 정규화 기법</strong>이다.</li>
  <li>훈련 성능과 테스트/검증 성능을 비교하여, 이 둘의 차이가 벌어지는 부분 즉, <strong>훈련 성능은 계속 향상하지만, 테스트/검증 성능은 향상 하지 않는 경우에 멈추는 것</strong>이다.(여기에서 성능은 주로 Loss나 평가 지표를 기준)</li>
  <li>이 때, 주의할 점은 <strong>모델의 성능이 향상하지 않더라도 바로 종료하는 것이 아니라, 몇 번 더 지켜본 뒤에 멈추는 것</strong>이다. 이것은 미니 배치로 근사한 그레디언트와 실제 그레디언트는 차이가 있기에 성능이 좋았다 나빴다 할 수 있기 때문이다.</li>
  <li>즉, 일시적인 성능 변동이 아닌 <strong>지속적인 성능의 정체나 하락이 보일 때, 종료하는 것</strong>이 좋다.</li>
  <li>
    <p>조기 종료는 파라미터 공간을 작게 만들어, 크기를 제약시키므로 $L_{2}$<strong>정규화와 동일한 효과</strong>를 볼 수 있다.</p>

    <p><img src="https://github.com/user-attachments/assets/d7602e15-c9ef-492c-91d5-20b465e30414" alt="스크린샷 2025-04-15 204031" /></p>
  </li>
</ul>

<hr />

<h3 id="데이터-증강">데이터 증강</h3>

<ul>
  <li>모델의 복잡도에 비해 충분한 훈련 데이터가 제공되지 않으면 모델이 데이터를 암기해서 과적합이 생기게 된다.</li>
  <li>
    <p>이 과적합을 막는 가장 근본적인 방법은 훈련 데이터의 양을 늘리는 것이다. <strong>훈련 데이터의 양이 크면 훈련 데이터의 오류는 약간 증가하지만, 테스트 오류는 감소하여, 일반화 오류 또는 과적합 정도가 줄어들게 된다.</strong></p>

    <p><img src="https://github.com/user-attachments/assets/ebb84234-6ab2-42e2-acd7-298e8c3230b0" alt="스크린샷 2025-04-15 212600" /></p>
  </li>
  <li>하지만 데이터셋을 증가시키기 위해, 데이터를 더 수집하는 것은 어렵기에 <strong>기존의 가지고 있는 훈련 데이터 셋을 이용하여 새로운 데이터를 만드는 것이 데이터 증강</strong>이다.</li>
  <li>이렇게 증강한 데이터를 미리 훈련 데이터 셋에 추가하여 사용할 수도 있지만, <strong>일반적으로는 훈련 과정에서 실시간으로 데이터를 증강한다.</strong> 이는 데이터를 확률적으로 변형하기에 무한히 많은 변형이 생길 수 있기 때문이다.</li>
  <li>가장 기본적인 데이터 증강으로는 <strong>훈련 데이터를 조금씩 변형해서 새로운 데이터를 만드는 방법</strong>이고, 여기서 좀 더 나아가면, <strong>학습 데이터로 학습한 생성모델로 새로운 데이터를 생성하는 방법</strong>이 있다.</li>
  <li>증강 방법은 굉장히 다양한데 이때는 데이터의 종류와 문제, 하고자 하는 Task에 따라 고려하여 선택해야 한다.</li>
  <li>데이터 증강 시 주의할 점으로는 <strong>클래스 불변 가정</strong>을 따라야 한다. 이는 클래스의 결정 경계 안에서 데이터를 변형해야 하는 것으로 <strong>증강할 때, 클래스가 바뀌지 않도록 해야한다는 것</strong>이다.</li>
</ul>

<hr />

<h3 id="배깅">배깅</h3>

<ul>
  <li>배깅은 여러 모델을 실행하여 하나의 강한 모델을 만드는 방법인 앙상블 기법 중 하나로 <strong>독립된 여러 모델을 동시에 실행</strong>한 뒤 개별 모델의 예측을 이용하여 최종으로 예측하는 방법이다.</li>
  <li>배깅은 모델의 종류와 관계 없이 다양한 모델로 팀을 구성할 수 있다. 단, 성능을 높이려면 <strong>모델 간의 독립을 보장</strong>해야한다.</li>
  <li>배깅에서는 모델 간의 독립을 더욱 보장하기 위해 <strong>모델 별로 부트스트랩 데이터를 사용</strong>한다. 부트스트랩이란 훈련 데이터에서 복원 추출하여 훈련 데이터와 같은 크기로 만드는 것이다.</li>
  <li>하지만 신경망 모델에서는 부트스트랩 안해도 된다.  <strong>랜덤한 값으로 가중치를 초기화</strong> 하고, <strong>미니 배치를 사용하기에 모델 별로 다른 데이터 셋을 사용하는 것 같은 효과</strong>를 주기 때문이다.</li>
  <li>이 후, 추론 단계에서는 <strong>개별 모델의 결과를 집계하여 예측</strong>한다. 예를 들어, 회귀 문제에서는 예측 값들을 평균을 낸다거나, 분류 문제에서는 Voting을 사용하여 추론한다.</li>
  <li>
    <p>배깅의 정규화 효과를 확인하기 위해 개별 모델의 예측 오차가 배깅에서 어떻게 줄어드는지 보자.</p>

    <p><img src="https://github.com/user-attachments/assets/dead2341-182a-4c53-ac41-02e71f4ad926" alt="스크린샷 2025-04-15 214122" /></p>
  </li>
  <li>여기에서 $\epsilon_{i}$는 개별 모델의 오차이고, 개별 모델의 오차는 평균이 0이고, 분산이 $v$이고, 모델 간의 공분산을 $c$로 표현한 것이다. 위 그림에서는 배깅에 의해 오차가 줄었는지 확인하기 위해 오차의 분산을 구한 것이다.</li>
  <li>우선 개별 모델이 독립일 때를 가정하자. 그럼 공분산($c$)가 0이 될 것이다. 그럼 오차의 분산은 $\frac v{k}$가 되어 <strong>모델의 개수(k)에 비례하여 분산이 감소하게 된다.</strong></li>
  <li>이와 반대로 개별 모델 간의 상관성이 커서 공분산($c$)와 $v$가 같다고 가정하면 오차의 분산은 $v$가 되어 오차의 분산이 개별 모델과 동일해진다.</li>
  <li><strong>즉, 배깅으로 효과를 보려면, 개별 모델들이 독립이여야한다.</strong></li>
</ul>

<hr />

<h3 id="드롭아웃">드롭아웃</h3>

<ul>
  <li>
    <p><strong>드롭 아웃은 미니 배치를 실행할 때마다 뉴련을 랜덤하게 잘라 새로운 모델을 생성하는 정규화 기법</strong>이다. 이 때, 각 계층마다 다른 드롭 아웃 확률을 지정할 수 있고, 각 계층의 각 뉴런들마다 지정한 확률로 살아 남는다.(주로 50% 이상으로 지정, 또한 입력과 은닉 뉴런에 지정, 입력은 더 높은 확률 부여, 출력에는 일반적으로 지정 X)</p>

    <p><img src="https://github.com/user-attachments/assets/b2175bdb-c2d3-4776-93f2-5c60f780d9fb" alt="스크린샷 2025-04-15 221018" /></p>
  </li>
  <li>이는 확률적으로 뉴련을 지우기에 하나의 신경망 모델에서 다양한 모델을 생성하는 것으로 볼 수 있기에 배깅과 같은 효과를 볼 수 있다. 하지만 <strong>드롭아웃은 모델 간의 독립성이 보장되지 않는 문제</strong>가 있다.</li>
  <li>그렇다면 배깅과 드롭아웃을 비교해보면, 모델 간의 독립성을 보장하는 <strong>배깅보다는 드롭아웃은 성능이 떨어지겠지만 더 실용적</strong>이라는 장점이 있다.</li>
  <li>훈련 단계에서는 미니배치마다 베르누이 분포에서 각 계층의 뉴런별로 난수를 발생시켜 0과 1로 이루어진 이진 마스크를 생성한다. 이 이진 마스크를 해당 계층에 적용하여 마스크가 1인 부분은 살아남고, 0인 부분은 죽게 된다.</li>
  <li>추론 단계에서는 뉴런을 드롭아웃하지 않고 훈련 과정에서 확률적으로 생성했던 다양한 모델의 평균을 예측한다. 모델들의 평균을 구해보면 원래 output에 드롭아웃 확률(p)의 곱으로 나타나는 것을 알 수 있다. 즉 <strong>드롭아웃의 각 계층의 출력은 원래 출력에 드롭 아웃 확률(p)를 곱</strong>해주면 된다.</li>
  <li>위의 내용을 기반으로 했을 때, 훈련 시점에 각 계층의 출력을 미리 드롭아웃 확률(p)로 나눠주면 원래의 값을 그대로 사용할 수 있다. 이 방식이 <strong>역 드롭아웃</strong>이다. → $a^{(l)} = (a^{(l)} \bigodot r^{(l)}) / p$</li>
</ul>

<hr />

<h3 id="잡음-주입">잡음 주입</h3>

<ul>
  <li>데이터나 모델을 확률적으로 정의할 수 있다면 더 정확하게 추론할 수 있다. 하지만 데이터나 모델이 확률적으로 정의되지 않았다면 <strong>간단한 잡음을 넣어서 확률적 성질을 부여</strong>할 수 있다. 이것이 <strong>잡음 주입</strong>이다.</li>
  <li><strong>잡음 주입 방식</strong>
    <ol>
      <li><strong>입력 데이터에 잡음 주입</strong>
        <ul>
          <li>입력 데이터에 잡음을 추가하는 것은 <strong>데이터 증강 기법에 해당</strong>하고, <strong>아주 작은 분산을 갖는 잡음을 넣으면 가중치 감소</strong>와 동일한 정규화 효과를 볼 수 있다.</li>
        </ul>
      </li>
      <li><strong>특징에 잡음 주입</strong>
        <ul>
          <li><strong>은닉 계층에서 추출된 특성에 잡음을 넣는 것으로 추상화된 상태에서 데이터 증강을 하는 것</strong>이다.</li>
          <li>추상화된 데이터에 확률적 성질을 부여하기에 상대적으로 의미 있는 단위로 데이터 증강이 일어나 성능이 크게 향상된다.</li>
        </ul>
      </li>
      <li><strong>모델 가중치에 잡음 주입</strong>
        <ul>
          <li>
            <p>대표적인 예시가 드롭아웃이다. 드롭아웃에서 뉴런을 제거할 때 확률적으로 가중치를 조절하기에 가중치에 잡음을 넣는 것이라 볼 수 있다.</p>

            <p><img src="https://github.com/user-attachments/assets/839aba0e-e271-4aa9-87a8-631560e31ef4" alt="스크린샷 2025-04-15 232705" /></p>
          </li>
          <li>또한 최소 지점의 경사가 가파른 경우, 일반화 성능이 떨어질 수 있는데 <strong>가중치에 잡음을 넣으면 최소 지점 주변이 평평해져 일반화 성능이 향상된다.</strong></li>
          <li>위의 그림에서 보면 <strong>경사가 가파른 곳의 최소값은 훈련 함수와 테스트 함수가 조금만 달라도 큰 차이를 내는 것</strong>을 볼 수 있기에 최소 지점이 평평한 곳에 있는 것이 좋다.</li>
        </ul>
      </li>
      <li><strong>소프트 레이블링</strong>
        <ul>
          <li>분류 문제에서 훈련 데이터의 레이블에 잡음을 주는 것이다. 예를 들어, [1, 0, 0, 0]의 라벨을 [0.7, 0.1, 0.1, 0.1]로 하는 것이다.</li>
          <li>레이블에 오차가 있을 경우, 모델이 정확히 1이나 0으로 예측하지 못하기 때문에 계속하여 일정한 손실이 발생하고 최적화가 이뤄지지 않을 수 있다.</li>
          <li>이를 일정량의 오차가 있다고 가정하여, 타겟 클래스의 확률을 줄이고, 줄인 만큼을 나머지 클래스에 분배하는 방식이다.(약간의 여지를 준다고 볼 수 있음) 이렇게 레이블에 오차를 반영한 후 학습하면 모델의 성능이 높아진다.</li>
        </ul>
      </li>
    </ol>
  </li>
</ul>]]></content><author><name>김동욱</name></author><category term="DL Basic" /><category term="DL Basic" /><summary type="html"><![CDATA[정규화(Regularization, 규제화) 이전에 신경망을 학습 할 때, 좋은 위치에서 시작하는 가중치 초기화에 대하여 알아보았다. 이와 더불어 최적해로 가는 길을 잘 찾을 수 있도록 해주는 정규화에 대해 알아보려 한다. 정규화란 최적화 과정에서 최적해를 잘 찾도록 정보를 추가하는 기법으로, 성능을 개선할 수 있는 포괄적인 기법들을 포함한다. 여기서 성능이 좋다는 것은 일반화가 잘 되었다는 것으로 훈련 성능과 검증/테스트 성능의 차이를 나타내는 일반화 오류가 적다는 것이다. 정규화의 접근 방식 모델을 최대한 단순하게 만들기 복잡한 모델의 파라미터 수를 줄이거나, 파라미터를 제거하는 등의 기법으로 모델을 단순하게 만들어 과적합을 줄이는 것이다. 사전 지식을 표현해서 최적해를 빠르게 찾도록 함 데이터나 모델에 대한 사전 분포를 이용하여 정확하고 빠르게 해를 찾는 방법으로 가중치 감소가 그 예이다. 확률적 성질을 추가 데이터, 모델, 훈련 기법 등에 확률적 성질을 추가하여 조금씩 변형된 형태로 데이터를 다루어 다양한 상황에서 학습하는 효과를 준다. 이는 손실 함수가 풍부한 데이터를 이용하여 넓은 범위를 세밀하게 표현하도록 하여 더 정확한 해를 찾고, Noise에 민감하지 않다. 데이터 증강, 잡음 주입, 드롭 아웃 등의 방식을 이용한다. 여러 가설을 고려하여 예측 앙상블 같은 방법을 이용하여 하나의 모델이 가지는 편향을 제거하여 오차를 최소화하는 방법이다. 가중치 감소 선형 회귀를 가정했을 때, $w^{T}x + b = 0$과 2를 곱한 $2w^{T}x+2b$는 완전히 같은 직선이다. 이렇듯 하나의 직선을 표현할 수 있는 표현은 굉장히 많다. 이 중에서 가장 좋은 식은 $w^{T}x+b=0$이다. 왜냐하면 최적화 시에 다루는 숫자의 크기가 작을 수록 오차의 변동성이 낮아지기 때문이다.(파라미터 값이 작을수록 손실 함수의 변화가 더 매끄럽고 안정적) 즉, 파라미터 공간이 원점 근처에 있을 때, 정확한 해를 빠르게 찾을 수 있는 것이다. 그렇기에 학습 시에 weight와 bias는 작은 것이 좋다. 학습 과정에서 작은 크기의 가중치를 갖게 해주는 것이 가중치 감소이다. 가중치 감소는 $J(w) = J(w) + \lambda R(w)$와 같이 손실 함수($J(W)$)에 가중치의 크기를 표현하는 정규화 항($\lambda R(W)$)을 더하여 사용한다. $\lambda$는 정규화 상수로서, 가중치의 크기를 조절해주는 역할을 한다.($\lambda$가 크면 정규화 항의 비중이 커지며, 가중치의 크기가 더 작아진다.)   $\lambda$ 커짐 $\lambda$ 작아짐 정규항의 비중 비중이 커짐 비중이 작아짐 가중치의 크기 더 작아짐 더 커짐 주로 정규화 항은 $L_{2}$노름이나 $L_{1}$노름을 사용한다. $L_{2}$노름을 사용하면 리지 회귀, $L_{1}$노름을 사용하면 라소 회귀라고 한다. 리지 회귀는 주로 가중치의 사전 분포를 모르거나, 가우시안 분포일 경우 사용하고, 라소 회귀는 데이터의 사전 분포가 라플라스 분포일 경우에 사용한다. 또한, 가중치 감소는 정규화의 효과를 볼 수 있다. 원래 손실 함수 값은 최적해 방향으로 가려하지만, 정규화 항은 다른 방향으로 가려고 하기에 최적해 부분이 아닌 정규화 항과 손실 함수의 접점이 해가 된다. 전역 최적해는 과적합 일수도 있기에, 거기에서 떨어진 부분의 가중치를 사용하여 과적합을 방지하기에 정규화의 효과를 볼 수 있는 것이다. 위의 그림을 보면 리지 회귀를 보면, 손실 함수가 어느 곳에 있던지 정규화 항이 원 모양이기에 접할 확률은 손실 함수가 어디에 있던지 동일하다. 하지만 라소 회귀의 경우, 마름모 모양으로 꼭짓점 부분에서 접할 확률이 가장 높다. 이는 최적해가 특정 축 위에 있을 확률이 높다는 것이고, 나머지 축의 값은 0이 된다는 것이다. → 정규화 접근 방식의 “모델을 최대한 단순하게 만들기”에 해당되고, 리지 회귀는 정규화 접근 방식의 “사전 지식을 표현해서 최적해를 빠르게 찾도록한다.”에 해당한다. 조기 종료 조기 종료란 모델이 과적합되기 전에 훈련을 멈추는 정규화 기법이다. 훈련 성능과 테스트/검증 성능을 비교하여, 이 둘의 차이가 벌어지는 부분 즉, 훈련 성능은 계속 향상하지만, 테스트/검증 성능은 향상 하지 않는 경우에 멈추는 것이다.(여기에서 성능은 주로 Loss나 평가 지표를 기준) 이 때, 주의할 점은 모델의 성능이 향상하지 않더라도 바로 종료하는 것이 아니라, 몇 번 더 지켜본 뒤에 멈추는 것이다. 이것은 미니 배치로 근사한 그레디언트와 실제 그레디언트는 차이가 있기에 성능이 좋았다 나빴다 할 수 있기 때문이다. 즉, 일시적인 성능 변동이 아닌 지속적인 성능의 정체나 하락이 보일 때, 종료하는 것이 좋다. 조기 종료는 파라미터 공간을 작게 만들어, 크기를 제약시키므로 $L_{2}$정규화와 동일한 효과를 볼 수 있다. 데이터 증강 모델의 복잡도에 비해 충분한 훈련 데이터가 제공되지 않으면 모델이 데이터를 암기해서 과적합이 생기게 된다. 이 과적합을 막는 가장 근본적인 방법은 훈련 데이터의 양을 늘리는 것이다. 훈련 데이터의 양이 크면 훈련 데이터의 오류는 약간 증가하지만, 테스트 오류는 감소하여, 일반화 오류 또는 과적합 정도가 줄어들게 된다. 하지만 데이터셋을 증가시키기 위해, 데이터를 더 수집하는 것은 어렵기에 기존의 가지고 있는 훈련 데이터 셋을 이용하여 새로운 데이터를 만드는 것이 데이터 증강이다. 이렇게 증강한 데이터를 미리 훈련 데이터 셋에 추가하여 사용할 수도 있지만, 일반적으로는 훈련 과정에서 실시간으로 데이터를 증강한다. 이는 데이터를 확률적으로 변형하기에 무한히 많은 변형이 생길 수 있기 때문이다. 가장 기본적인 데이터 증강으로는 훈련 데이터를 조금씩 변형해서 새로운 데이터를 만드는 방법이고, 여기서 좀 더 나아가면, 학습 데이터로 학습한 생성모델로 새로운 데이터를 생성하는 방법이 있다. 증강 방법은 굉장히 다양한데 이때는 데이터의 종류와 문제, 하고자 하는 Task에 따라 고려하여 선택해야 한다. 데이터 증강 시 주의할 점으로는 클래스 불변 가정을 따라야 한다. 이는 클래스의 결정 경계 안에서 데이터를 변형해야 하는 것으로 증강할 때, 클래스가 바뀌지 않도록 해야한다는 것이다. 배깅 배깅은 여러 모델을 실행하여 하나의 강한 모델을 만드는 방법인 앙상블 기법 중 하나로 독립된 여러 모델을 동시에 실행한 뒤 개별 모델의 예측을 이용하여 최종으로 예측하는 방법이다. 배깅은 모델의 종류와 관계 없이 다양한 모델로 팀을 구성할 수 있다. 단, 성능을 높이려면 모델 간의 독립을 보장해야한다. 배깅에서는 모델 간의 독립을 더욱 보장하기 위해 모델 별로 부트스트랩 데이터를 사용한다. 부트스트랩이란 훈련 데이터에서 복원 추출하여 훈련 데이터와 같은 크기로 만드는 것이다. 하지만 신경망 모델에서는 부트스트랩 안해도 된다. 랜덤한 값으로 가중치를 초기화 하고, 미니 배치를 사용하기에 모델 별로 다른 데이터 셋을 사용하는 것 같은 효과를 주기 때문이다. 이 후, 추론 단계에서는 개별 모델의 결과를 집계하여 예측한다. 예를 들어, 회귀 문제에서는 예측 값들을 평균을 낸다거나, 분류 문제에서는 Voting을 사용하여 추론한다. 배깅의 정규화 효과를 확인하기 위해 개별 모델의 예측 오차가 배깅에서 어떻게 줄어드는지 보자. 여기에서 $\epsilon_{i}$는 개별 모델의 오차이고, 개별 모델의 오차는 평균이 0이고, 분산이 $v$이고, 모델 간의 공분산을 $c$로 표현한 것이다. 위 그림에서는 배깅에 의해 오차가 줄었는지 확인하기 위해 오차의 분산을 구한 것이다. 우선 개별 모델이 독립일 때를 가정하자. 그럼 공분산($c$)가 0이 될 것이다. 그럼 오차의 분산은 $\frac v{k}$가 되어 모델의 개수(k)에 비례하여 분산이 감소하게 된다. 이와 반대로 개별 모델 간의 상관성이 커서 공분산($c$)와 $v$가 같다고 가정하면 오차의 분산은 $v$가 되어 오차의 분산이 개별 모델과 동일해진다. 즉, 배깅으로 효과를 보려면, 개별 모델들이 독립이여야한다. 드롭아웃 드롭 아웃은 미니 배치를 실행할 때마다 뉴련을 랜덤하게 잘라 새로운 모델을 생성하는 정규화 기법이다. 이 때, 각 계층마다 다른 드롭 아웃 확률을 지정할 수 있고, 각 계층의 각 뉴런들마다 지정한 확률로 살아 남는다.(주로 50% 이상으로 지정, 또한 입력과 은닉 뉴런에 지정, 입력은 더 높은 확률 부여, 출력에는 일반적으로 지정 X) 이는 확률적으로 뉴련을 지우기에 하나의 신경망 모델에서 다양한 모델을 생성하는 것으로 볼 수 있기에 배깅과 같은 효과를 볼 수 있다. 하지만 드롭아웃은 모델 간의 독립성이 보장되지 않는 문제가 있다. 그렇다면 배깅과 드롭아웃을 비교해보면, 모델 간의 독립성을 보장하는 배깅보다는 드롭아웃은 성능이 떨어지겠지만 더 실용적이라는 장점이 있다. 훈련 단계에서는 미니배치마다 베르누이 분포에서 각 계층의 뉴런별로 난수를 발생시켜 0과 1로 이루어진 이진 마스크를 생성한다. 이 이진 마스크를 해당 계층에 적용하여 마스크가 1인 부분은 살아남고, 0인 부분은 죽게 된다. 추론 단계에서는 뉴런을 드롭아웃하지 않고 훈련 과정에서 확률적으로 생성했던 다양한 모델의 평균을 예측한다. 모델들의 평균을 구해보면 원래 output에 드롭아웃 확률(p)의 곱으로 나타나는 것을 알 수 있다. 즉 드롭아웃의 각 계층의 출력은 원래 출력에 드롭 아웃 확률(p)를 곱해주면 된다. 위의 내용을 기반으로 했을 때, 훈련 시점에 각 계층의 출력을 미리 드롭아웃 확률(p)로 나눠주면 원래의 값을 그대로 사용할 수 있다. 이 방식이 역 드롭아웃이다. → $a^{(l)} = (a^{(l)} \bigodot r^{(l)}) / p$ 잡음 주입 데이터나 모델을 확률적으로 정의할 수 있다면 더 정확하게 추론할 수 있다. 하지만 데이터나 모델이 확률적으로 정의되지 않았다면 간단한 잡음을 넣어서 확률적 성질을 부여할 수 있다. 이것이 잡음 주입이다. 잡음 주입 방식 입력 데이터에 잡음 주입 입력 데이터에 잡음을 추가하는 것은 데이터 증강 기법에 해당하고, 아주 작은 분산을 갖는 잡음을 넣으면 가중치 감소와 동일한 정규화 효과를 볼 수 있다. 특징에 잡음 주입 은닉 계층에서 추출된 특성에 잡음을 넣는 것으로 추상화된 상태에서 데이터 증강을 하는 것이다. 추상화된 데이터에 확률적 성질을 부여하기에 상대적으로 의미 있는 단위로 데이터 증강이 일어나 성능이 크게 향상된다. 모델 가중치에 잡음 주입 대표적인 예시가 드롭아웃이다. 드롭아웃에서 뉴런을 제거할 때 확률적으로 가중치를 조절하기에 가중치에 잡음을 넣는 것이라 볼 수 있다. 또한 최소 지점의 경사가 가파른 경우, 일반화 성능이 떨어질 수 있는데 가중치에 잡음을 넣으면 최소 지점 주변이 평평해져 일반화 성능이 향상된다. 위의 그림에서 보면 경사가 가파른 곳의 최소값은 훈련 함수와 테스트 함수가 조금만 달라도 큰 차이를 내는 것을 볼 수 있기에 최소 지점이 평평한 곳에 있는 것이 좋다. 소프트 레이블링 분류 문제에서 훈련 데이터의 레이블에 잡음을 주는 것이다. 예를 들어, [1, 0, 0, 0]의 라벨을 [0.7, 0.1, 0.1, 0.1]로 하는 것이다. 레이블에 오차가 있을 경우, 모델이 정확히 1이나 0으로 예측하지 못하기 때문에 계속하여 일정한 손실이 발생하고 최적화가 이뤄지지 않을 수 있다. 이를 일정량의 오차가 있다고 가정하여, 타겟 클래스의 확률을 줄이고, 줄인 만큼을 나머지 클래스에 분배하는 방식이다.(약간의 여지를 준다고 볼 수 있음) 이렇게 레이블에 오차를 반영한 후 학습하면 모델의 성능이 높아진다.]]></summary></entry><entry><title type="html">[자료구조] 스택(Stack)과 큐(Queue)</title><link href="https://82153.github.io/%EC%9E%90%EB%A3%8C%20%EA%B5%AC%EC%A1%B0/2025/04/18/stack_queue.html" rel="alternate" type="text/html" title="[자료구조] 스택(Stack)과 큐(Queue)" /><published>2025-04-18T14:27:00+09:00</published><updated>2025-04-18T14:27:00+09:00</updated><id>https://82153.github.io/%EC%9E%90%EB%A3%8C%20%EA%B5%AC%EC%A1%B0/2025/04/18/stack_queue</id><content type="html" xml:base="https://82153.github.io/%EC%9E%90%EB%A3%8C%20%EA%B5%AC%EC%A1%B0/2025/04/18/stack_queue.html"><![CDATA[<h2 id="스택stack">스택(Stack)</h2>

<h3 id="스택stack이란">스택(Stack)이란</h3>

<ul>
  <li>
    <p>스택은 이름 그대로 차곡차곡 <strong>쌓아 올린 형태의 자료 구조</strong>를 나타낸다.</p>

    <p><img width="600" height="400" alt="스크린샷 2025-10-22 145116" src="https://github.com/user-attachments/assets/2bc9eae2-1fcb-4d3d-a15b-f2724fa136ae" /></p>
  </li>
</ul>

<hr />

<h3 id="스택의-특징">스택의 특징</h3>

<ul>
  <li>스택은 기본적으로 <strong>push 작업</strong>과 <strong>pop 작업</strong>이 있다. push는 새로운 데이터를 스택에 삽입하는 것이고, pop은 스택의 자료를 삭제하는 것이다.</li>
  <li>push와 pop 작업은 스택의 맨 위에서만 수행되고, 이 스택의 맨 위를 <strong>top</strong>이라 부른다. 즉, 가장 늦게 들어온 자료가 가장 먼저 삭제되는 <strong>후입 선출(LIFO, Last-In-First-Out)</strong>의 구조를 가진다.</li>
  <li>이 push와 pop 작업은 스택의 top에서만 이루어지기에 O(1)의 시간 복잡도를 가진다.</li>
</ul>

<hr />

<h3 id="스택의-장단점">스택의 장단점</h3>

<ul>
  <li>장점
    <ol>
      <li>스택은 구현이 간단하다.</li>
      <li>삽입 / 삭제의 연산 속도가 빠르다.</li>
      <li>되돌리기(Undo)와 같은 작업에 최적화 되어 있다.</li>
    </ol>
  </li>
  <li>단점
    <ol>
      <li>중간 데이터에 접근하기 어렵다.</li>
      <li>크기가 고정된 경우, 이미 다 차있는 스택에 삽입시에 StackOverflow가 발생한다.</li>
    </ol>
  </li>
</ul>

<hr />

<h2 id="큐queue">큐(Queue)</h2>

<h3 id="큐queue란">큐(Queue)란</h3>

<ul>
  <li>
    <p>큐는 데이터를 차례대로 처리하기 위한, 일종의 대기줄(Queue) 형태의 자료구조이다.</p>

    <p><img width="600" height="400" alt="image" src="https://github.com/user-attachments/assets/05c5c527-d156-444d-a978-396259ae9236" /></p>
  </li>
</ul>

<hr />

<h3 id="큐의-특징">큐의 특징</h3>

<ul>
  <li>큐는 <strong>enqueue와 dequeue 작업</strong>이 있다. enqueue는 큐에 새로운 데이터를 삽입하는 작업이고, dequeue는 큐에 데이터를 삭제하는 과정이다.</li>
  <li>큐가 스택과 다른 점은 스택과 달리 삽입/삭제의 수행 위치가 다르다는 것이다. 큐는 <strong>선입 선출(FIFO, First-In-First-Out)</strong>로 가장 먼저 들어온 데이터가 가장 먼저 삭제되는 구조이다.</li>
  <li>여기서 데이터가 삽입되는 부분을 <strong>rear</strong>, 데이터가 삭제되는 부분이 <strong>front</strong>라고 한다.</li>
  <li>enqueue와 dequeue는 단순히 rear에 데이터를 추가하고, front에서 데이터를 삭제하는 연산이기에 각 작업의 시간 복잡도는 O(1)이다.</li>
</ul>

<hr />

<h3 id="원형-큐circular-queue">원형 큐(Circular Queue)</h3>

<ul>
  <li>원형 큐는 큐의 일종으로, rear가 끝까지 도달하면 다시 front로 돌아가는 <strong>순회하는 구조의 큐</strong>이다.</li>
  <li>순회하지 않는 일반적인 선형 큐에서는 삭제 연산시에 rear가 계속 front쪽으로 오게 되면서 앞의 공간을 재사용할 수 없게 되기에 공간 낭비가 발생한다.</li>
  <li>위와 같은 문제때문에 큐는 주로 원형 큐로 구현하여 사용한다.(혹은 배열이 아닌 연결 리스트로 구현한다.)</li>
</ul>

<hr />

<h3 id="우선순위-큐priority-queue">우선순위 큐(Priority Queue)</h3>

<ul>
  <li>일반 큐와 달리, 데이터가 들어온 순서가 아니라 <strong>우선순위(priority)</strong> 에 따라 삭제된다.</li>
  <li>각 원소는 (key, element) 형태로 구성되며, <strong>key 값이 높은(또는 낮은)</strong> 원소가 먼저 제거된다.</li>
  <li>주로 <strong>힙(Heap)</strong> 구조를 이용하여 구현된다.</li>
</ul>

<hr />

<h3 id="데큐deque-double-ended-queue">데큐(Deque, Double-Ended Queue)</h3>

<ul>
  <li><strong>양쪽 끝(front, rear)에서 모두 삽입과 삭제가 가능한</strong> 큐이다.</li>
  <li>스택과 큐의 특성을 모두 가지고 있어 <strong>양방향 처리나 캐시 구현</strong> 등에 활용된다.</li>
</ul>

<hr />

<h3 id="큐의-장단점">큐의 장단점</h3>

<ul>
  <li>장점
    <ol>
      <li>삽입 / 삭제의 연산 속도가 빠르다.</li>
      <li>차례대로 데이터를 처리하는데 최적화되어 있다.(CPU 스케줄링 등)</li>
    </ol>
  </li>
  <li>단점
    <ol>
      <li>중간 데이터에 접근하기 어렵다.</li>
      <li>크기가 고정된 경우, 이미 다 차있는 큐에 삽입시에 Overflow가 발생한다.</li>
    </ol>
  </li>
</ul>]]></content><author><name>김동욱</name></author><category term="자료 구조" /><category term="자료 구조" /><summary type="html"><![CDATA[스택(Stack) 스택(Stack)이란 스택은 이름 그대로 차곡차곡 쌓아 올린 형태의 자료 구조를 나타낸다. 스택의 특징 스택은 기본적으로 push 작업과 pop 작업이 있다. push는 새로운 데이터를 스택에 삽입하는 것이고, pop은 스택의 자료를 삭제하는 것이다. push와 pop 작업은 스택의 맨 위에서만 수행되고, 이 스택의 맨 위를 top이라 부른다. 즉, 가장 늦게 들어온 자료가 가장 먼저 삭제되는 후입 선출(LIFO, Last-In-First-Out)의 구조를 가진다. 이 push와 pop 작업은 스택의 top에서만 이루어지기에 O(1)의 시간 복잡도를 가진다. 스택의 장단점 장점 스택은 구현이 간단하다. 삽입 / 삭제의 연산 속도가 빠르다. 되돌리기(Undo)와 같은 작업에 최적화 되어 있다. 단점 중간 데이터에 접근하기 어렵다. 크기가 고정된 경우, 이미 다 차있는 스택에 삽입시에 StackOverflow가 발생한다. 큐(Queue) 큐(Queue)란 큐는 데이터를 차례대로 처리하기 위한, 일종의 대기줄(Queue) 형태의 자료구조이다. 큐의 특징 큐는 enqueue와 dequeue 작업이 있다. enqueue는 큐에 새로운 데이터를 삽입하는 작업이고, dequeue는 큐에 데이터를 삭제하는 과정이다. 큐가 스택과 다른 점은 스택과 달리 삽입/삭제의 수행 위치가 다르다는 것이다. 큐는 선입 선출(FIFO, First-In-First-Out)로 가장 먼저 들어온 데이터가 가장 먼저 삭제되는 구조이다. 여기서 데이터가 삽입되는 부분을 rear, 데이터가 삭제되는 부분이 front라고 한다. enqueue와 dequeue는 단순히 rear에 데이터를 추가하고, front에서 데이터를 삭제하는 연산이기에 각 작업의 시간 복잡도는 O(1)이다. 원형 큐(Circular Queue) 원형 큐는 큐의 일종으로, rear가 끝까지 도달하면 다시 front로 돌아가는 순회하는 구조의 큐이다. 순회하지 않는 일반적인 선형 큐에서는 삭제 연산시에 rear가 계속 front쪽으로 오게 되면서 앞의 공간을 재사용할 수 없게 되기에 공간 낭비가 발생한다. 위와 같은 문제때문에 큐는 주로 원형 큐로 구현하여 사용한다.(혹은 배열이 아닌 연결 리스트로 구현한다.) 우선순위 큐(Priority Queue) 일반 큐와 달리, 데이터가 들어온 순서가 아니라 우선순위(priority) 에 따라 삭제된다. 각 원소는 (key, element) 형태로 구성되며, key 값이 높은(또는 낮은) 원소가 먼저 제거된다. 주로 힙(Heap) 구조를 이용하여 구현된다. 데큐(Deque, Double-Ended Queue) 양쪽 끝(front, rear)에서 모두 삽입과 삭제가 가능한 큐이다. 스택과 큐의 특성을 모두 가지고 있어 양방향 처리나 캐시 구현 등에 활용된다. 큐의 장단점 장점 삽입 / 삭제의 연산 속도가 빠르다. 차례대로 데이터를 처리하는데 최적화되어 있다.(CPU 스케줄링 등) 단점 중간 데이터에 접근하기 어렵다. 크기가 고정된 경우, 이미 다 차있는 큐에 삽입시에 Overflow가 발생한다.]]></summary></entry><entry><title type="html">[DL Basic] 배치 정규화(Batch Normalization)</title><link href="https://82153.github.io/dl%20basic/2025/04/16/batch_norm.html" rel="alternate" type="text/html" title="[DL Basic] 배치 정규화(Batch Normalization)" /><published>2025-04-16T13:54:00+09:00</published><updated>2025-04-16T13:54:00+09:00</updated><id>https://82153.github.io/dl%20basic/2025/04/16/batch_norm</id><content type="html" xml:base="https://82153.github.io/dl%20basic/2025/04/16/batch_norm.html"><![CDATA[<h3 id="배치-정규화">배치 정규화</h3>

<ul>
  <li>신경망의 학습이 어려운 이유 중 하나는 <strong>계층을 지날 때마다 데이터의 분포가 보이지 않는 요인에 의해 왜곡</strong>되기 때문이다. 이런 현상을 <strong>내부 공변량 변화</strong>라고 한다. 그리고 <strong>분포를 결정하는 보이지 않는 요인을 내부 공변량</strong>이라 한다.</li>
  <li>이 내부 공변량이 계층을 지나면서 바뀌어서 각 계층에서 데이터의 분포가 원래 분포에서 조금씩 멀어지게 되고, 이는 계층을 지날 때마다 심해진다.</li>
</ul>

<p><img src="https://github.com/user-attachments/assets/e25152da-b552-416b-a942-2867553466d4" alt="스크린샷 2025-04-15 175848" /></p>

<ul>
  <li>기존의 내부 공변량 변화를 막기 위해서 가중치 초기화를 잘하고, 학습률도 작게 사용해야 했다. 하지만 이 경우에는 학습 속도가 느린 문제가 있다.</li>
  <li>이 내부 공변량 변화를 해결하기 위한 것이 배치 정규화이다. 배치 정규화는 <strong>계층을 지날 때마다 매번 정규화</strong>를 하여 내부 공변량 변화를 없앤다.(주로 뉴런의 가중 합산과 활성화 함수 사이에서 진행)</li>
  <li>기존의 정규화와 다른 점은 <strong>모델의 계층 형태로 데이터 정규화를 한다</strong>는 점과 <strong>전체 데이터가 아닌 미니 배치에 대해 정규화</strong>한다는 점이다.</li>
  <li>배치 정규화의 과정은 우선 <strong>표준 가우시안 분포로 정규화</strong>를 한 뒤, 학습 파라미터인 <strong>$\gamma$와 $\beta$를 통해 원래 분포로 복원</strong>하면 된다. 이 $\gamma$는 분포의 스케일링을 다루고, $\beta$는 분포를 translation을 해주는 역할이다.</li>
  <li>이 $\gamma$와 $\beta$는 정해주는 것이 아니라, 학습을 통해 구하는 값이다. 초기 값은 각각 1과 0에 근사한 값으로 설정하여 시작한다. 즉, 단순, 표준화한 값에서 시작한다 볼 수 있다.</li>
  <li>표준 가우시안 분포로 정규화를 하여 데이터가 계층을 지날 때마다 표준 가우시안 분포로 바뀌어 내부 공변량 변화를 최소화 하게 된다.</li>
  <li>하지만, <strong>표준 가우시안 분포는 모델이 비선형성을 제대로 표현할 수 없고</strong>, 우리가 원하는 것은 표준화가 아닌 <strong>입출력의 분포를 맞추는 것</strong>이기에 원래 분포로 복구해주는 작업을 거친다.</li>
  <li><strong>표준 가우시안이 비선형성이 감소하는 이유</strong>
    <ul>
      <li>우선 정규화 이후에 활성화 함수를 거치는데 활성화 함수가 Sigmoid인 경우부터 보자</li>
      <li>정규화를 통해 데이터의 범위는 [-1, 1]이 될 것이다. 하지만 Sigmoid에서 해당 범위는 선형이기에 비선형성이 사라진다.</li>
      <li>ReLU에 적용해보면 [-1, 1] 범위에서 절반은 0이 되어 학습이 어렵고, 나머지 절반도 선형적이므로 비선형성이 줄어든다.</li>
    </ul>

    <p><img src="https://github.com/user-attachments/assets/cd74c792-33fc-4c66-9297-804d555be13e" alt="스크린샷 2025-04-15 175908" /></p>
  </li>
  <li>배치 정규화를 통해 <strong>내부 공변량 변화가 억제되면</strong>, 각 계층의 입력 분포가 안정되기 때문에 <strong>그레디언트 흐름이 안정화되고 학습 속도와 성능이 향상</strong>된다.</li>
  <li>또한 데이터의 분포를 유지하려 하므로, <strong>가중치 초기화의 의존도가 낮아지고 높은 학습률을 사용</strong>할 수 있다.</li>
  <li>
    <p>추가적으로 미니 배치 별로 정규화하여 미니 배치의 조합에 따라 데이터가 조금씩 변형되어 <strong>확률적 성질까지 부여</strong>하여 성능이 올라간다.</p>
  </li>
  <li>위와 같은 내부 공변량 변화 외에도, 활성화 함수의 동작 관점에서도 배치 정규화가 필요한 이유가 있다. 활성화 함수의 입력이 극단적인 값으로 치우치면, 해당 층의 비선형성이 제대로 작동하지 않아 학습이 원활히 이루어지지 않는다.</li>
  <li>활성화 함수를 거치기 전에 우리는 $\sum{wx}$를 계산하는데, 이 값은 우리가 가중치 초기화를 하더라도 어떻게 변화할 지 알 수 없다. 이 값이 극단적인 분포를 가질 경우, 문제가 발생할 수 있다.</li>
</ul>

<p><img width="1200" height="400" alt="image" src="https://github.com/user-attachments/assets/28cb52b4-cb10-4d6e-851c-726e622ec2a8" /></p>

<ul>
  <li>예를 들어 Sigmoid함수를 사용할 때, $\sum{wx}$가 극단적인 음수 분포나 극단적인 양수 분포를 가지게 되었다고 생각해보면, 이 값들의 Sigmoid 값들은 0 혹은 1에 근사하고, 이에 따라 역전파 시에 <strong>Vanishing Gradient문제가 발생</strong>한다.</li>
  <li>ReLU의 경우에서는 극단적인 음수 분포에서는 <strong>Vanishing Gradient문제</strong>가 발생하고, 극단적인 양수 분포에서는 모든 기울기가 1이 되어 모두 동등하게 학습되기에 <strong>특징 추출이 어려워 Overfitting</strong>이 발생할 수 있다.</li>
  <li>배치 정규화는 이러한 문제를 해결하기 위해, $\sum wx$ 값을 미니 배치 단위로 정규화하여 <strong>활성화 함수가 적절한 비선형성을 발휘할 수 있는 범위로 입력을 재배치</strong>해 준다. 이를 통해 각 층의 학습이 더 안정적으로 이루어질 수 있다.</li>
</ul>]]></content><author><name>김동욱</name></author><category term="DL Basic" /><category term="DL Basic" /><summary type="html"><![CDATA[배치 정규화 신경망의 학습이 어려운 이유 중 하나는 계층을 지날 때마다 데이터의 분포가 보이지 않는 요인에 의해 왜곡되기 때문이다. 이런 현상을 내부 공변량 변화라고 한다. 그리고 분포를 결정하는 보이지 않는 요인을 내부 공변량이라 한다. 이 내부 공변량이 계층을 지나면서 바뀌어서 각 계층에서 데이터의 분포가 원래 분포에서 조금씩 멀어지게 되고, 이는 계층을 지날 때마다 심해진다. 기존의 내부 공변량 변화를 막기 위해서 가중치 초기화를 잘하고, 학습률도 작게 사용해야 했다. 하지만 이 경우에는 학습 속도가 느린 문제가 있다. 이 내부 공변량 변화를 해결하기 위한 것이 배치 정규화이다. 배치 정규화는 계층을 지날 때마다 매번 정규화를 하여 내부 공변량 변화를 없앤다.(주로 뉴런의 가중 합산과 활성화 함수 사이에서 진행) 기존의 정규화와 다른 점은 모델의 계층 형태로 데이터 정규화를 한다는 점과 전체 데이터가 아닌 미니 배치에 대해 정규화한다는 점이다. 배치 정규화의 과정은 우선 표준 가우시안 분포로 정규화를 한 뒤, 학습 파라미터인 $\gamma$와 $\beta$를 통해 원래 분포로 복원하면 된다. 이 $\gamma$는 분포의 스케일링을 다루고, $\beta$는 분포를 translation을 해주는 역할이다. 이 $\gamma$와 $\beta$는 정해주는 것이 아니라, 학습을 통해 구하는 값이다. 초기 값은 각각 1과 0에 근사한 값으로 설정하여 시작한다. 즉, 단순, 표준화한 값에서 시작한다 볼 수 있다. 표준 가우시안 분포로 정규화를 하여 데이터가 계층을 지날 때마다 표준 가우시안 분포로 바뀌어 내부 공변량 변화를 최소화 하게 된다. 하지만, 표준 가우시안 분포는 모델이 비선형성을 제대로 표현할 수 없고, 우리가 원하는 것은 표준화가 아닌 입출력의 분포를 맞추는 것이기에 원래 분포로 복구해주는 작업을 거친다. 표준 가우시안이 비선형성이 감소하는 이유 우선 정규화 이후에 활성화 함수를 거치는데 활성화 함수가 Sigmoid인 경우부터 보자 정규화를 통해 데이터의 범위는 [-1, 1]이 될 것이다. 하지만 Sigmoid에서 해당 범위는 선형이기에 비선형성이 사라진다. ReLU에 적용해보면 [-1, 1] 범위에서 절반은 0이 되어 학습이 어렵고, 나머지 절반도 선형적이므로 비선형성이 줄어든다. 배치 정규화를 통해 내부 공변량 변화가 억제되면, 각 계층의 입력 분포가 안정되기 때문에 그레디언트 흐름이 안정화되고 학습 속도와 성능이 향상된다. 또한 데이터의 분포를 유지하려 하므로, 가중치 초기화의 의존도가 낮아지고 높은 학습률을 사용할 수 있다. 추가적으로 미니 배치 별로 정규화하여 미니 배치의 조합에 따라 데이터가 조금씩 변형되어 확률적 성질까지 부여하여 성능이 올라간다. 위와 같은 내부 공변량 변화 외에도, 활성화 함수의 동작 관점에서도 배치 정규화가 필요한 이유가 있다. 활성화 함수의 입력이 극단적인 값으로 치우치면, 해당 층의 비선형성이 제대로 작동하지 않아 학습이 원활히 이루어지지 않는다. 활성화 함수를 거치기 전에 우리는 $\sum{wx}$를 계산하는데, 이 값은 우리가 가중치 초기화를 하더라도 어떻게 변화할 지 알 수 없다. 이 값이 극단적인 분포를 가질 경우, 문제가 발생할 수 있다. 예를 들어 Sigmoid함수를 사용할 때, $\sum{wx}$가 극단적인 음수 분포나 극단적인 양수 분포를 가지게 되었다고 생각해보면, 이 값들의 Sigmoid 값들은 0 혹은 1에 근사하고, 이에 따라 역전파 시에 Vanishing Gradient문제가 발생한다. ReLU의 경우에서는 극단적인 음수 분포에서는 Vanishing Gradient문제가 발생하고, 극단적인 양수 분포에서는 모든 기울기가 1이 되어 모두 동등하게 학습되기에 특징 추출이 어려워 Overfitting이 발생할 수 있다. 배치 정규화는 이러한 문제를 해결하기 위해, $\sum wx$ 값을 미니 배치 단위로 정규화하여 활성화 함수가 적절한 비선형성을 발휘할 수 있는 범위로 입력을 재배치해 준다. 이를 통해 각 층의 학습이 더 안정적으로 이루어질 수 있다.]]></summary></entry></feed>