<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Computer Vision :)</title>
    <link>https://cvml.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 06:31:27 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>족제비다아</managingEditor>
    <image>
      <title>Computer Vision :)</title>
      <url>https://tistory1.daumcdn.net/tistory/3276054/attach/2114f0bafbeb474b8d0236cf5250e0ed</url>
      <link>https://cvml.tistory.com</link>
    </image>
    <item>
      <title>RNN, LSTM 에서 tanh 를 사용하는 이유</title>
      <link>https://cvml.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621906835087&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Activation function between LSTM layers&quot; data-og-description=&quot;I'm aware the LSTM cell uses both sigmoid and tanh activation functions internally, however when creating a stacked LSTM architecture does it make sense to pass their outputs through an activation&quot; data-og-host=&quot;stats.stackexchange.com&quot; data-og-source-url=&quot;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&quot; data-og-url=&quot;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bt1RLH/hyKlmQprRH/Em8Fi6wHGkDoDVTjZsZTjK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/K7UGh/hyKjMJWPSG/41d0ItOqaaHjz5bbZfGI5K/img.png?width=392&amp;amp;height=278&amp;amp;face=0_0_392_278,https://scrap.kakaocdn.net/dn/dsJUoC/hyKjDM1Zgz/MXGFwWOvae2noEHkvHW9jK/img.png?width=392&amp;amp;height=278&amp;amp;face=0_0_392_278&quot;&gt;&lt;a href=&quot;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stats.stackexchange.com/questions/444923/activation-function-between-lstm-layers&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bt1RLH/hyKlmQprRH/Em8Fi6wHGkDoDVTjZsZTjK/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316,https://scrap.kakaocdn.net/dn/K7UGh/hyKjMJWPSG/41d0ItOqaaHjz5bbZfGI5K/img.png?width=392&amp;amp;height=278&amp;amp;face=0_0_392_278,https://scrap.kakaocdn.net/dn/dsJUoC/hyKjDM1Zgz/MXGFwWOvae2noEHkvHW9jK/img.png?width=392&amp;amp;height=278&amp;amp;face=0_0_392_278');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Activation function between LSTM layers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I'm aware the LSTM cell uses both sigmoid and tanh activation functions internally, however when creating a stacked LSTM architecture does it make sense to pass their outputs through an activation&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stats.stackexchange.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RNN을 공부하면서 Activation Function으로 sigmoid보다 tanh를 사용하는 이유는 이해가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sigmoid에 비해 tanh 는 기울기가 0에서 1 사이이므로 Gradient Vanishing problem에 더 강하기 때문인데 그러면 'ReLU는 왜 안쓰지?' 라는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RNN은 CNN과 달리 이전 step의 값을 가져와서 사용하므로 ReLU를 쓰게되면 이전 값이 커짐에 따라 전체적인 출력이 발산하는 문제가 생길 수 있다. 따라서 과거의 값들을 재귀적으로 사용하는 RNN 모델에서는 이를 normalizing 하는 것이 필요하며 이를 위해 sigmoid보다 기울기의 역전파가 더 잘되는 tanh를 사용함으로써 좋은 결과를 볼 수 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://limitsinx.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://limitsinx.tistory.com/62&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621907433196&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[코드로 이해하는 딥러닝 2-11] - RNN(Recurrent Neural Network)/LSTM(Long-Short-Term-Memory)&quot; data-og-description=&quot;[코드로 이해하는 딥러닝 0] - 글연재에 앞서&amp;nbsp;https://limitsinx.tistory.com/27 [코드로 이해하는 딥러닝 1] - Tensorflow 시작&amp;nbsp;https://limitsinx.tistory.com/28 [코드로 이해하는 딥러닝 2] - Tensorflow 변..&quot; data-og-host=&quot;limitsinx.tistory.com&quot; data-og-source-url=&quot;https://limitsinx.tistory.com/62&quot; data-og-url=&quot;https://limitsinx.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/izY0X/hyKjBBGaWl/fb0JwVzheREetJsOcEqcA0/img.png?width=574&amp;amp;height=261&amp;amp;face=0_0_574_261,https://scrap.kakaocdn.net/dn/bqojxE/hyKjIU4hhD/6B9spS7n4MqrDSOkbnZML0/img.png?width=574&amp;amp;height=261&amp;amp;face=0_0_574_261,https://scrap.kakaocdn.net/dn/d4Llkt/hyKjKyDO9p/GKxBjwVnpKKIwNidMMd9sK/img.png?width=968&amp;amp;height=762&amp;amp;face=0_0_968_762&quot;&gt;&lt;a href=&quot;https://limitsinx.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://limitsinx.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/izY0X/hyKjBBGaWl/fb0JwVzheREetJsOcEqcA0/img.png?width=574&amp;amp;height=261&amp;amp;face=0_0_574_261,https://scrap.kakaocdn.net/dn/bqojxE/hyKjIU4hhD/6B9spS7n4MqrDSOkbnZML0/img.png?width=574&amp;amp;height=261&amp;amp;face=0_0_574_261,https://scrap.kakaocdn.net/dn/d4Llkt/hyKjKyDO9p/GKxBjwVnpKKIwNidMMd9sK/img.png?width=968&amp;amp;height=762&amp;amp;face=0_0_968_762');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[코드로 이해하는 딥러닝 2-11] - RNN(Recurrent Neural Network)/LSTM(Long-Short-Term-Memory)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[코드로 이해하는 딥러닝 0] - 글연재에 앞서&amp;nbsp;https://limitsinx.tistory.com/27 [코드로 이해하는 딥러닝 1] - Tensorflow 시작&amp;nbsp;https://limitsinx.tistory.com/28 [코드로 이해하는 딥러닝 2] - Tensorflow 변..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;limitsinx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Machine Learning/Theory</category>
      <category>RNN</category>
      <category>tanh</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/27</guid>
      <comments>https://cvml.tistory.com/27#entry27comment</comments>
      <pubDate>Tue, 25 May 2021 10:51:43 +0900</pubDate>
    </item>
    <item>
      <title>[개념 정리] Batch Normalization in Deep Learning - part 2.</title>
      <link>https://cvml.tistory.com/6</link>
      <description>&lt;p data-ke-size=&quot;size23&quot;&gt;논문에서 저자가 말한 것 처럼 Batch Normalization (BN)는 네트워크 레이어의 Internal Covariate Shift (ICS)문제를 해결하기 위해 나온 기법이다. BN을 이용하면 확실하게 학습 속도가 빨라지고 안정적으로 학습되는 것을 실험적으로 증명하였다. 하지만 실제로 &lt;u&gt;BN은 ICS 문제를 해결한 것이 아니고 Optimization Landscape를 smooth 하게 만들기 때문&lt;/u&gt;에 좋은 성능을 낸다는 것이 &lt;a href=&quot;https://arxiv.org/abs/1805.11604&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2018년 NIPS에 논문&lt;/a&gt;으로 발표되었다.&lt;/p&gt;
&lt;figure id=&quot;og_1620834741455&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How Does Batch Normalization Help Optimization?&quot; data-og-description=&quot;Batch Normalization (BatchNorm) is a widely adopted technique that enables faster and more stable training of deep neural networks (DNNs). Despite its pervasiveness, the exact reasons for BatchNorm's effectiveness are still poorly understood. The popular b&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/1805.11604&quot; data-og-url=&quot;https://arxiv.org/abs/1805.11604v5&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/1805.11604&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/1805.11604&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;How Does Batch Normalization Help Optimization?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Batch Normalization (BatchNorm) is a widely adopted technique that enables faster and more stable training of deep neural networks (DNNs). Despite its pervasiveness, the exact reasons for BatchNorm's effectiveness are still poorly understood. The popular b&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size23&quot;&gt;즉, 정리하자면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size23&quot;&gt;Batch Normalization은 Internal Covariate Shift 현상을 해결하지 못한다.&lt;/li&gt;
&lt;li data-ke-size=&quot;size23&quot;&gt;Internal Covarate Shift 현상이 있더라도 학습에 나쁜 영향을 주지 않는다.&lt;/li&gt;
&lt;li data-ke-size=&quot;size23&quot;&gt;Batch Normalization이 학습 성능을 높여주는 이유는 Optimization Landscape를 smooth하게 만들어주기 때문이다. 이는 BN 말고도 다른 정규화 방법(L1,L2)으로도 같은 효과를 낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Internal Covariate Shift&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위 논문에서 저자는 VGG 네트워크에 CIFAR10 데이터셋을 학습시키면서 BN이 ICS 현상을 없애주는지 실험을 했다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;비교를 위해 VGG 네트워크에 BN을 추가하지 않은 Standard와 BN 직후에 랜덤한 노이즈를 섞은 Standard + Noisy BN 모델을 학습하여 성능과 데이터의 분포를 조사하였고 아래 그림이 그 결과다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ICS측정.jpg&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;875&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chUYE8/btq4JwPhGCy/TBUkkPMhCbCSuBW5crK6Jk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chUYE8/btq4JwPhGCy/TBUkkPMhCbCSuBW5crK6Jk/img.jpg&quot; data-alt=&quot;ICS 측정 실험&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chUYE8/btq4JwPhGCy/TBUkkPMhCbCSuBW5crK6Jk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchUYE8%2Fbtq4JwPhGCy%2FTBUkkPMhCbCSuBW5crK6Jk%2Fimg.jpg&quot; data-filename=&quot;ICS측정.jpg&quot; data-origin-width=&quot;1794&quot; data-origin-height=&quot;875&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ICS 측정 실험&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;확실히 BN을 사용하게 되면 학습 속도가 빨라져서 빠르게 수렴하는 것을 확인할 수 있다. 그리고 위 그림의 오른쪽은 특정 위치의 레이어에 입력으로 들어오는 데이터의 분포를 시각화한 것이다. 각 레이어마다 입력 데이터의 분포가 학습 step에 따라 달라지는데 이것이 바로 ICS 현상이다. ICS는 레이어가 깊을 수록 심해지며 BN이 추가되더라도 이 현상이 없어지지 않는다는 것을 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또 저자는 다른 방법으로도 ICS를 측정해 보았는데 앞쪽 레이어의 가중치만 업데이트 한 다음 현재 레이어의 기울기 값의 변화를 계산하는 것이다. 그렇다면 만일 &lt;u&gt;ICS가 심하다면 입력 데이터의 분포가 이전 step과 크게 달라지므로 역전파로 계산되는 기울기 값이 이전보다 차이가 클 것이다&lt;/u&gt;.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;289&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tmfQL/btq4NHa1Yy9/vPd0gS7AVwUhsyDMwAeNEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tmfQL/btq4NHa1Yy9/vPd0gS7AVwUhsyDMwAeNEK/img.png&quot; data-alt=&quot;(출처: 나동빈님 강의자료)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tmfQL/btq4NHa1Yy9/vPd0gS7AVwUhsyDMwAeNEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtmfQL%2Fbtq4NHa1Yy9%2FvPd0gS7AVwUhsyDMwAeNEK%2Fimg.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;289&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(출처: 나동빈님 강의자료)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;기울기 값의 변화를 계산하기 위해 논문에서는 &lt;b&gt;Cosine Angle&lt;/b&gt;과 &lt;b&gt;L2-distance&lt;/b&gt;를 계산하였다. DLN은 논문에서 실험을 위해 만든 25층 크기의 Deep Linear Network이라고 한다. 이상적으로 BN에 의해 ICS 현상이 줄어들거나 없어졌다면 기울기 변화 값이 작아져서 Cosine Angle은 1에 가까워지고 L2-distance는 0에 가까워질 것이다. 하지만 실험 결과 기울기 변화 값이 작아지지 않았고 오히려 커지는 경우도 확인할 수 있었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlN4dx/btq4MCOPFJx/4rE1EczGK1H5tG7Xkb0CkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlN4dx/btq4MCOPFJx/4rE1EczGK1H5tG7Xkb0CkK/img.png&quot; data-alt=&quot;Measurement in ICS&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlN4dx/btq4MCOPFJx/4rE1EczGK1H5tG7Xkb0CkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlN4dx%2Fbtq4MCOPFJx%2F4rE1EczGK1H5tG7Xkb0CkK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Measurement in ICS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;즉, BN을 적용하더라도 ICS는 그대로이거나 오히려 증가하는 것을 실험적으로 확인할 수 있었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Batch Normalization이 잘 작동하는 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;위 실험으로부터 BN은 ICS 현상을 해결하지 않는다는 것과 그럼에도 모델 학습 성능이 BN을 적용하기 전보다 좋아졌다는 것을 확인할 수 있었다. 그럼 어떤 이유에서 모델의 학습 성능이 좋아진 것일까? 저자는 BN이 &lt;b&gt;Optimization Landscape를 부드럽게(Smoothing) 만들어주기 때문&lt;/b&gt;이라고 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Obrkn/btq4JxneHtr/QwztjCZenVViDPLrFrCOQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Obrkn/btq4JxneHtr/QwztjCZenVViDPLrFrCOQ1/img.png&quot; data-alt=&quot;Visualizing the Loss Landscape in Neural Nets (NIPS 2018)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Obrkn/btq4JxneHtr/QwztjCZenVViDPLrFrCOQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FObrkn%2Fbtq4JxneHtr%2FQwztjCZenVViDPLrFrCOQ1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Visualizing the Loss Landscape in Neural Nets (NIPS 2018)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이를 확인하기 위해 특정 시점에서 loss 값으로 계산된 기울기를 step size를 다르게 하면서 가중치를 업데이트하고, 업데이트된 가중치로 loss를 다시 계산해서 원래 loss 값과의 차이(Variation in Loss)와 새로 계산돤 기울기 값과 원래 기울기 값의 차이(Variation in Gradient)를 비교하는 실험을 진행했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Variation in Loss (Loss Landscape)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;step size를 다르게 하면서 가중치를 업데이트 하였을 때 새로 계산되는 loss를 이용해 원래 loss 값과의 차이(range)를 계산.&lt;/li&gt;
&lt;li&gt;변동 폭이 크다면(Large fluctuation) 이는 &lt;u&gt;최적화가 힘들다는 것&lt;/u&gt;을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;$$range\left(L\left(W^{'}\right)\right)$$&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Variation in Gradient (Gradient Predictiveness)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;step size를 다르게 하면서 가중치를 업데이트 하였을 때 새로 계산되는 loss를 이용해 다시 기울기를 계산하고 원래 기울기와의 차이(range)를 계산.&lt;/li&gt;
&lt;li&gt;변동 폭이 크다면 이는 기존의 &lt;u&gt;기울기 값에대한 신뢰성이 떨어진다는 것&lt;/u&gt;을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$range\left( \left \| \delta_{W} L \left( W^{'} \right) - \delta_{W} L \left( W^{t} \right) \right \| \right) $$&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;221&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBpLbe/btq4OhQQAcE/lkpgQxKJL7jiZ97UKvELOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBpLbe/btq4OhQQAcE/lkpgQxKJL7jiZ97UKvELOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBpLbe/btq4OhQQAcE/lkpgQxKJL7jiZ97UKvELOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBpLbe%2Fbtq4OhQQAcE%2FlkpgQxKJL7jiZ97UKvELOk%2Fimg.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;221&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위 실험 결과를 보게 되면 BN을 적용시켰을 때 Loss와 Gradient의 변화가 적어 smooth한 최적화가 이뤄진다는 것을 확인할 수 있다. (c) 그림에 나오는 &quot;effective&quot; beta-smoothness는 기울기 값 변화에 대한 &lt;u&gt;Lipschitzness&lt;/u&gt;를 계산한 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Lipschitz&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;립시츠(Lipschitz) 함수는 연속적이고 미분 가능하며 어떤 두 점을 잡더라도 기울기가 K 이하인 함수이다. 즉, 급격한 변화 없이 K만큼의 전반적으로 완만한 기울기를 가지는 함수 형태인 것이다. 따라서 파라미터에 대한 loss function이 립시츠를 따른다면 smooth하기 때문에 상대적으로 안정적인 학습을 진행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;$$\frac{|f \left( x_{1} \right ) - f \left( x_{2} \right ) |}{| x_{1} - x_{2} |} \leq K$$&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;논문에서는 &lt;b&gt;Batch Normalization이 Loss function의 Lipschitzness를 향상(imporve)시켜준다고 한다&lt;/b&gt;. 이 말은 현재 기울기 방향으로 큰 step size만큼 이동하더라도 &lt;u&gt;이동한 뒤의 기울기의 크기와 방향이 이전과 유사할 가능성이 높다&lt;/u&gt;는 것이다. 즉, learning rate가 높더라도 기울기가 stable하게 감소하면서 학습이 잘 진행될 수 있도록 도와주는 역할을 BN이 하고 있다는 말이다. 하지만 이는 BN 뿐만이 아니라 L1, L2와 같이 다른 정규화 기법을 사용하더라도 Lipschitzness를 향상시켜주는 효과가 있다고 하며 실험적으로 증명하였다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;211&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn6xN5/btq4NJUeyju/ISv5oiaekVKP8jv5sx6KbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn6xN5/btq4NJUeyju/ISv5oiaekVKP8jv5sx6KbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn6xN5/btq4NJUeyju/ISv5oiaekVKP8jv5sx6KbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn6xN5%2Fbtq4NJUeyju%2FISv5oiaekVKP8jv5sx6KbK%2Fimg.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;211&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;reference&lt;/h3&gt;
&lt;p&gt;[1] &lt;a href=&quot;https://subinium.github.io/introduction-to-normalization/&quot;&gt;https://subinium.github.io/introduction-to-normalization/&lt;/a&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=58fuWVu5DVU&amp;amp;t=3298s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.youtube.com/watch?v=58fuWVu5DVU&amp;amp;t=3298s&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[2] &lt;a href=&quot;https://yjucho1.github.io/deep%20learning%20paper/batchnorm/&quot;&gt;https://yjucho1.github.io/deep%20learning%20paper/batchnorm/&lt;/a&gt;&lt;a href=&quot;https://lifeignite.tistory.com/47&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lifeignite.tistory.com/47&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Machine Learning/Theory</category>
      <category>batch normalization</category>
      <category>Internal Covariate Shift</category>
      <category>Lipschitzness</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/6</guid>
      <comments>https://cvml.tistory.com/6#entry6comment</comments>
      <pubDate>Thu, 13 May 2021 11:29:40 +0900</pubDate>
    </item>
    <item>
      <title>[개념 정리] Batch Normalization in Deep Learning - part 1.</title>
      <link>https://cvml.tistory.com/5</link>
      <description>&lt;p style=&quot;text-align: justify;&quot;&gt;딥러닝을 공부하다 보면 자주 접하는 이론적인 내용이자 실제 구현에서도 라이브러리를 이용하여 쉽게 Layer로 추가하여 사용하는 Batch Normalization에 대해 알아보자.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW0TVZ/btq4F2TX51d/5dw9twkAf6dWus1UzyJTn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW0TVZ/btq4F2TX51d/5dw9twkAf6dWus1UzyJTn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW0TVZ/btq4F2TX51d/5dw9twkAf6dWus1UzyJTn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW0TVZ%2Fbtq4F2TX51d%2F5dw9twkAf6dWus1UzyJTn0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;ICML 2015에 한 논문이 등장했다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/1502.03167&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&quot;Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift&quot; - Sergey loffe and Christian Szegedy[1]&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1620709679774&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift&quot; data-og-description=&quot;Training Deep Neural Networks is complicated by the fact that the distribution of each layer's inputs changes during training, as the parameters of the previous layers change. This slows down the training by requiring lower learning rates and careful param&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/1502.03167&quot; data-og-url=&quot;https://arxiv.org/abs/1502.03167v3&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/1502.03167&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://arxiv.org/abs/1502.03167&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Training Deep Neural Networks is complicated by the fact that the distribution of each layer's inputs changes during training, as the parameters of the previous layers change. This slows down the training by requiring lower learning rates and careful param&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;이는 딥러닝에서 hidden layer의 데이터들을 정규화하는 방법에 대한 논문으로 다음과 같은 성능 향상을 보여주었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;text-align: justify;&quot;&gt;학습 속도(training speed)를 빠르게 할 수 있다.&lt;/li&gt;
&lt;li style=&quot;text-align: justify;&quot;&gt;가중치 초기화(weight initialization)에 대한 민감도를 감소시킨다.&lt;/li&gt;
&lt;li style=&quot;text-align: justify;&quot;&gt;모델 일반화(regularization)효과가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;이 논문이 발표된 이후로 대부분의 딥러닝 학습에&amp;nbsp; Batch Normalization은 선택이 아닌 필수가 되었다. 물론 한계점도 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;text-align: justify;&quot;&gt;이름 그대로 batch size로 normalization을 하기 때문에 batch size의 크기가 성능에 영향을 준다.&lt;/li&gt;
&lt;li style=&quot;text-align: justify;&quot;&gt;RNN과 같이 sequential 데이터를 처리하는 경우에 BN을 적용시키기 어렵다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;그러면 Batch Normalization(BN)이 어떻게 나오게 되었고 어떻게 작동하는 것일까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Covariate Shift&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;u&gt;Covariate shift는 공변량 변화라고 부르며 입력 데이터의 분포가 학습할 때와 테스트할 때 다르게 나타나는 현상을 말한다.&lt;/u&gt; 이는 학습 데이터를 이용해 만든 모델이 테스트 데이터셋을 가지고 추론할 때 성능에 영항을 미칠 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;210&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t6R4Z/btq4DzxYtIX/sZSmkEuDi6v09SoVSbL5H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t6R4Z/btq4DzxYtIX/sZSmkEuDi6v09SoVSbL5H0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t6R4Z/btq4DzxYtIX/sZSmkEuDi6v09SoVSbL5H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft6R4Z%2Fbtq4DzxYtIX%2FsZSmkEuDi6v09SoVSbL5H0%2Fimg.png&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;210&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;예를 들어, 고양이와 강아지를 분류하는 모델을 학습시킬 때 학습 데이터로 고양이 이미지를 '러시안 블루'종만 사용하고 테스트 데이터로 '페르시안'종의 고양이를 분류하려고 한다면 모델은 잘 학습할 수 있을까? 학습 데이터의 분포와 테스트 데이터의 분포가 다르기 때문에 학습시킨 모델의 분류 성능은 떨어질 것이며 이처럼 학습 데이터와 테스트 데이터의 분포가 다른 것을 covariate shift라 부른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;481&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brz8Im/btq4CijbLUR/BaeMc4KJijoX1CdxqjKUr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brz8Im/btq4CijbLUR/BaeMc4KJijoX1CdxqjKUr1/img.png&quot; data-alt=&quot;covariate shift 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brz8Im/btq4CijbLUR/BaeMc4KJijoX1CdxqjKUr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrz8Im%2Fbtq4CijbLUR%2FBaeMc4KJijoX1CdxqjKUr1%2Fimg.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;481&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;covariate shift 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Internal Covariate Shift&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;위에서 언급한 &lt;u&gt;Covariate Shift(공변량 변화)가 뉴럴 네트워크 내부에서 일어나는 현상을 Internal Covariate Shift라고 한다.&lt;/u&gt; 즉, 매 스텝마다 hidden layer에 입력으로 들어오는 데이터의 분포가 달라지는 것을 의미하며 Internal Covariate Shift는 layer가 깊을수록 심화될 수 있다. (&lt;a href=&quot;https://www.youtube.com/watch?v=58fuWVu5DVU&amp;amp;t=3296s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;나동빈님의 강의&lt;/a&gt;를 참고하였습니다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyscr7/btq4AtZz7ST/OXf1ywXwrkCaNhT8bQCaO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyscr7/btq4AtZz7ST/OXf1ywXwrkCaNhT8bQCaO1/img.png&quot; data-alt=&quot;출처:&amp;amp;amp;nbsp;https://github.com/ndb796/Deep-Learning-Paper-Review-and-Practice&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyscr7/btq4AtZz7ST/OXf1ywXwrkCaNhT8bQCaO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcyscr7%2Fbtq4AtZz7ST%2FOXf1ywXwrkCaNhT8bQCaO1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp;https://github.com/ndb796/Deep-Learning-Paper-Review-and-Practice&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;우선 기존에 딥러닝 학습에 있어서 겪고 있던 문제들 중 대표적으로 각 레이어의 가중치들이 역전파 학습을 진행할 때 입력부로 올라오면서 학습이 잘 되지 않는 Gradient Vanishing / Exploding 문제가 있었다. 이를 해결하기 위해 가중치를 초기화하는 방법(Xavier, He), ReLU와 같이 더 나은 활성화 함수(Activation Function) 방법, 규제화(Regularization) 방법을 제안하거나 학습률(Learning Rate)를 낮춰서 모든 레이어들의 가중치가 학습되도록 연구해왔다. 이러한 방법들을 이용함에도 &lt;u&gt;레이어의 수가 많아질수록 여전히 학습이 잘 되지 않아&lt;/u&gt; 근본적인 문제를 해결하지 못하고 있었다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;BN 논문의 저자는 학습이 잘 되지 않는 근본적인 문제를 'Internal Covariate Shift'현상 때문이라고 주장을 하였고 Batch Normalization 기법이 이 현상을 해결해준다고 주장하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Normalization, Whitening&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;다른 분포를 가지는 두 데이터를 같은 분포를 가질 수 있게 변환을 해주는 방법으로 Normalization과 Whitening을 생각해 볼 수 있다. &lt;b&gt;정규화(&lt;span style=&quot;color: #333333;&quot;&gt;Normalization)&lt;/span&gt;&lt;/b&gt;는 데이터를 동일한 범위 내의 값을 갖도록 하는 기법으로 대표적으로 Min-Max, Standardization이 있다. 이 중에서 Standardization은 데이터를 평균 0, 표준편차 1이 되게 변환하여 정규화시킨다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;219&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chmmS3/btq4COCb73H/cLrh4BFqnaxTKUn5hUar5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chmmS3/btq4COCb73H/cLrh4BFqnaxTKUn5hUar5K/img.png&quot; data-alt=&quot;Normalization (Standardization)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chmmS3/btq4COCb73H/cLrh4BFqnaxTKUn5hUar5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchmmS3%2Fbtq4COCb73H%2FcLrh4BFqnaxTKUn5hUar5K%2Fimg.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;219&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Normalization (Standardization)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;화이트닝(Whitening)&lt;/b&gt;은 데이터의 평균을 0, 그리고 공분산을 단위행렬로 갖는 정규분포 형태로 변환하는 기법으로 Decorrelation + Standardization으로 볼 수 있다. 보통 PCA를 이용해 데이터를 decorrelated 시킨다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;218&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpCNWE/btq4HZWzSfK/hLFtMWpqfo0xclWf20dNo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpCNWE/btq4HZWzSfK/hLFtMWpqfo0xclWf20dNo0/img.png&quot; data-alt=&quot;Whitening&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpCNWE/btq4HZWzSfK/hLFtMWpqfo0xclWf20dNo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpCNWE%2Fbtq4HZWzSfK%2FhLFtMWpqfo0xclWf20dNo0%2Fimg.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;218&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Whitening&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Batch Normalization&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;그러면 각 레이어로 들어가는 입력 데이터들의 분포를 고르게 하기 위해 위의 방법처럼 평균 0, 표준편차 1의 값을 갖도록 standardization이나 whitening을 해주면 되는 것일까? 그렇지 않다. 입력 데이터들의 분포가 치우쳐져 있다면 데이터의 특성에 맞게 표준화(normalization)를 해주는 것이 좋은 것은 사실이다. 하지만 모든 데이터들이 평균 0, 표준편차 1이 되도록 변형시켜주는 것은(whitening) 데이터를 제대로 학습하지 못한다. 왜냐하면 whitening을 하게되면 이전 레이어로부터 &lt;u&gt;학습이 가능한 parameters의 영향을 무시해버리기 때문이다&lt;/u&gt;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다시말해,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 Hidden Layer의 입력 데이터 X'은 이전 레이어의 입력 데이터 X로부터 학습 가능한 파라미터(weight, bias)와 계산을 통해 나온다. &lt;span style=&quot;color: #5f6d2b;&quot;&gt;X' = weigth * X + bias&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;정규화 과정에서 입력 데이터 X'의 평균(E[X'])을 입력 데이터에서 빼준다. &lt;span style=&quot;color: #5f6d2b;&quot;&gt;X'' = X' - E[X']&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;E[X'] = weight * E[X] + bias 이므로 식을 정리하면 &lt;span style=&quot;color: #5f6d2b;&quot;&gt;X'' = X' - E[X'] = weight * (X - E[X])&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;이 과정에서 bias가 없어지므로 학습 가능한 파라미터의 영향이 사라져 제대로 학습이 불가능해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;또, 평균 0, 표준편차 1로 데이터의 분표를 변환하게 될 경우 활성화 함수로 Sigmoid를 사용하게 되었을 때 &lt;u&gt;비선형성(non-linearity)의 특징을 잃어버리게 되는 문제가 생긴다&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bexKZp/btq4HIni7I4/un6AyuOAs6bHQnn78XoPR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bexKZp/btq4HIni7I4/un6AyuOAs6bHQnn78XoPR0/img.png&quot; data-alt=&quot;sigmoid&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bexKZp/btq4HIni7I4/un6AyuOAs6bHQnn78XoPR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbexKZp%2Fbtq4HIni7I4%2Fun6AyuOAs6bHQnn78XoPR0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;sigmoid&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;따라서 단순히 평균을 0으로 만들고 표준편차가 1이 되도록 정규화를 하는 것이 아니라 다음의 주요한 특징을 갖는 Batch Normalization을 제안하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ENgn2/btq4F27Avlg/0lGC2vYOp4lHIrW1SUFDo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ENgn2/btq4F27Avlg/0lGC2vYOp4lHIrW1SUFDo0/img.png&quot; data-alt=&quot;batch normalization&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ENgn2/btq4F27Avlg/0lGC2vYOp4lHIrW1SUFDo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FENgn2%2Fbtq4F27Avlg%2F0lGC2vYOp4lHIrW1SUFDo0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;batch normalization&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;training data 전체를 다 학습할 수 없으므로 일정 크기에 해당하는 &lt;b&gt;mini batch&lt;/b&gt; 안에서 &lt;b&gt;평균과 분산을 계산&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;$$\mu_{B}\leftarrow\frac{1}{m}\sum_{i=1}^{m}x_{i}$$&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;$$\sigma^{2}_{B}\leftarrow\frac{1}{m}\sum_{i=1}^{m}\left( x_{i}-\mu_{B} \right)^{2}$$&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 데이터에 대하여 각 차원(feature)별로 &lt;b&gt;normalization&lt;/b&gt;을 수행&lt;/li&gt;
&lt;li&gt;epsilon이 붙는 이유는 0으로 나눠지는 것을 막기 위해&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\hat{x}_{i}\leftarrow\frac{x_{i}-\mu_{B}}{\sqrt{\sigma^{2}_{B}+\epsilon}}$$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;normalization 된 값들에 대해 &lt;b&gt;Scale factor&lt;/b&gt;(gamma)와 &lt;b&gt;Shift factor&lt;/b&gt;(beta)를 더하여 학습이 가능한 파라미터를 추가함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$y_{i}\leftarrow\gamma\hat{x}_{i}+\beta\equiv BN_{\gamma,\beta}\left(x_{i}\right)$$&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Scale factor와 Shift factor를 두게 되면 입력 데이터의 원래 형태(normalization 하기 전)로도 학습이 가능하여 각 층별로 입력 데이터의 optimal uncorrelated distribution을 구할 수 있게 된다. 또 위에서 언급했던 문제중에 하나인 Sigmoid와 같은 활성화 함수에서 비선형성을 잃어버리는 것을 방지할 수 있다. 정규화 이후에 사용되는 두 factors가 학습됨에 따라 non-linearity를 유지하도록 해준다.&lt;/p&gt;
&lt;p&gt;따라서 BN은 &lt;u&gt;학습 가능한 parameters가 존재하는 하나의 레이어 구조가 되며&lt;/u&gt; 이 기법이 발표된 이후 기존의 딥러닝 구조에서 Convolution Layer와 Activation Layer 사이에 BN Layer가 들어간 형태로 발전했다. 이 구조로 큰 성능 효과를 높이게 되어 거의 모든 딥러닝 구조에 BN기법이 사용되기 시작했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;575&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mqPtG/btqzUPDxlJO/35tVK4L1cScUPxhueAsN90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mqPtG/btqzUPDxlJO/35tVK4L1cScUPxhueAsN90/img.png&quot; data-alt=&quot;Batch Normalization architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mqPtG/btqzUPDxlJO/35tVK4L1cScUPxhueAsN90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmqPtG%2FbtqzUPDxlJO%2F35tVK4L1cScUPxhueAsN90%2Fimg.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;575&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Batch Normalization architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Inference with Batch Normalization&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;그러면 이제 학습이 완료되고 난 다음에 추론 과정에서 Batch Normalization layer는 어떻게 정규화를 수행할까?&lt;/p&gt;
&lt;p&gt;추론 과정에서는 테스트 데이터 하나에 대해 답을 내야 하므로 평균과 분산을 계산할 수 없다.&lt;/p&gt;
&lt;p&gt;따라서 추론할 때는 training set의 평균과 분산 값으로 대체하여 정규화를 수행한다. 대체하는 방법으로는 크게 2가지가 있으며 학습할 때 사용했던 mini batch의 평균과 분산 값들을 이용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모집단 추정 방식&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;통계적으로 표본집단 데이터들의 평균, 분산을 이용해 모집단의 평균과 분산을 추정할 수 있다.&lt;/p&gt;
&lt;p&gt;$$E \left [ x^{\left(k\right)}\right] = E_{B}\left[\mu^{\left(k\right)}_{B}\right]$$&lt;/p&gt;
&lt;p&gt;$$Var\left[x^{\left(k\right)}\right] = \frac{m}{m-1}E_{B}\left[\sigma^{\left(k\right)^{2}}_{B}\right]$$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Moving Average 방식&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\hat{\mu}\leftarrow\alpha\hat{\mu}+\left(1-\alpha\right)\mu^{\left(i\right)}_{B}$$&lt;/p&gt;
&lt;p&gt;$$\hat{\sigma}\leftarrow\alpha\hat{\sigma}+\left(1-\alpha\right)\sigma^{\left(i\right)}_{B}$$&lt;/p&gt;
&lt;p&gt;모집단 추정 방식의 경우 모든 mini batch 의 평균, 분산 값들을 저장하고 있어야 하기 때문에 비효율적이며 주로 이전 정보들을 바탕으로 모집단의 정보를 예측하는 방식인 Moving Average를 이용한다고 한다. 지수 추정 방식을 이용하는 Exponential Moving Average도 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size23&quot;&gt;Reference&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;[1] &lt;a href=&quot;https://arxiv.org/pdf/1502.03167.pdf&quot;&gt;https://arxiv.org/pdf/1502.03167.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot;&gt;[2] &lt;a href=&quot;https://www.quora.com/Why-does-batch-normalization-help&quot;&gt;https://www.quora.com/Why-does-batch-normalization-help&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[3] &lt;a href=&quot;https://taeu.github.io/cs231n/deeplearning-cs231n-Neural-Networks-2/&quot;&gt;https://taeu.github.io/cs231n/deeplearning-cs231n-Neural-Networks-2/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[4] &lt;a href=&quot;https://lifeignite.tistory.com/47&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;lifeignite.tistory.com/47&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[5] &lt;a href=&quot;https://shuuki4.wordpress.com/2016/01/13/batch-normalization-%EC%84%A4%EB%AA%85-%EB%B0%8F-%EA%B5%AC%ED%98%84/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;shuuki4.wordpress.com/2016/01/13/batch-normalization-%EC%84%A4%EB%AA%85-%EB%B0%8F-%EA%B5%AC%ED%98%84/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[6] &lt;a href=&quot;https://www.youtube.com/watch?v=58fuWVu5DVU&amp;amp;t=3296s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.youtube.com/watch?v=58fuWVu5DVU&amp;amp;t=3296s&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Machine Learning/Theory</category>
      <category>batch normalization</category>
      <category>deep learning</category>
      <category>Internal Covariate Shift</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/5</guid>
      <comments>https://cvml.tistory.com/5#entry5comment</comments>
      <pubDate>Tue, 11 May 2021 17:06:08 +0900</pubDate>
    </item>
    <item>
      <title>BCEWithLogitsLoss 와 MultiLabelSoftMarginLoss 차이</title>
      <link>https://cvml.tistory.com/26</link>
      <description>&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;(Binary / Multi-label / Multi-class) Classification&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;우리가 보통 Binary Classification(이진 분류) 문제를 풀 때 loss 계산을 위해 &lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;torch.nn.BCEWithLogitsLoss&lt;/span&gt;&lt;/b&gt;를 사용한다. &lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;torch.nn.BCELoss&lt;/span&gt;&lt;/b&gt;도 있는데 BCELoss에 sigmoid 함수를 함께 결합한 것이 BCEWithLogitsLoss다. 보통 이진 분류 모델의 output으로 logit 값이 나오기 때문에 loss 계산 전에 sigmoid를 거쳐야 하므로 해당 과정이 포함된 BCEWithLogitsLoss를 쓰면 편리하다. &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;torch.nn.BCEWithLogitsLoss = torch.nn.BCEWithLoss + torch.sigmoid&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;Binary Classification 문제 말고도 Multi Label Classification(다중 레이블 분류)에서도 loss 계산으로 BCEWithLogitsLoss를 사용할 수 있고 실제로 많이 사용하고 있다. 그 이유는 예를 들어 5개의 label을 분류하는 Multi Label Classification 문제가 있다고 가정해보자. 이때, 모델의 최종 output이 5개의 logit 값이 나오고 각각 sigmoid 함수를 거쳐 일정 threshold 값 이상이 되면 해당 label이 있고 그렇지 않으면 없다고 판단하여 '[1, 0, 1, 0 ,0]' 이런 식으로 나올 것이다. 이때 각 label들은 자기 자신에 해당하는 logit 값만 잘 찾아내면 되므로 5개의 독립적인 이진 분류 문제로 접근할 수 있어 Binary Cross Entropy 함수를 loss 계산에 활용할 수 있는 것이다. 반면에 Multi Class Classification은 최종 output에 softmax를 수행하기 때문에 각 class에 해당하는 logit 값이 서로 영향을 주게 된다. 그래서 Multi Class Classification 문제를 풀 때는&amp;nbsp;&lt;b&gt;torch.nn.CrossEntropyLoss&lt;/b&gt;를 사용한다. &lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;그런데 pytorch를 사용하다보니&amp;nbsp;&lt;b&gt;torch.nn.MultiLabelSoftMarginLoss&lt;/b&gt;&amp;nbsp;모듈을 발견하게 되었고 문서 설명을 읽으면서 '이거 결국 BCEWithLogitsLoss랑 같은 일 하는 모듈 아니야?'라는 생각을 하게 되었고 좀 더 자세하게 찾아보았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BCEWithLogitsLoss / MultiLabelSoftMarginLoss&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;u&gt;결론부터 말하자면 둘은 같은 역할을 하는 모듈이다.&lt;/u&gt; 즉 Multi label classification 문제에서 loss 계산을 위해 둘 중에 아무거나 사용해도 상관은 없다. 하지만 약간의 출력 값이 다를 수가 있어서 왜 다른지 한 번 확인해보고 사용하면 좋을 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1619503180333&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;What is the difference between BCEWithLogitsLoss and MultiLabelSoftMarginLoss&quot; data-og-description=&quot;I think there is no difference between BCEWithLogitsLoss and MultiLabelSoftMarginLoss. BCEWithLogitsLoss = One Sigmoid Layer + BCELoss (solved numerically unstable problem) MultiLabelSoftMargin&amp;rsquo;s fomula is also same with BCEWithLogitsLoss. One difference&quot; data-og-host=&quot;discuss.pytorch.org&quot; data-og-source-url=&quot;https://discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&quot; data-og-url=&quot;https://discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EvqNN/hyJ2s4bFgj/rkvHLNdjpVuKPTvzt8PQE0/img.png?width=420&amp;amp;height=38&amp;amp;face=0_0_420_38,https://scrap.kakaocdn.net/dn/cTPRyN/hyJ0tXVZ01/1iN5SXsG1y4F9no6x77LiK/img.png?width=420&amp;amp;height=38&amp;amp;face=0_0_420_38,https://scrap.kakaocdn.net/dn/cpwVBj/hyJ2pzCMiJ/EoERe7AZ4aqPYGsEMsYbX0/img.png?width=1025&amp;amp;height=205&amp;amp;face=0_0_1025_205&quot;&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://discuss.pytorch.org/t/what-is-the-difference-between-bcewithlogitsloss-and-multilabelsoftmarginloss/14944&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EvqNN/hyJ2s4bFgj/rkvHLNdjpVuKPTvzt8PQE0/img.png?width=420&amp;amp;height=38&amp;amp;face=0_0_420_38,https://scrap.kakaocdn.net/dn/cTPRyN/hyJ0tXVZ01/1iN5SXsG1y4F9no6x77LiK/img.png?width=420&amp;amp;height=38&amp;amp;face=0_0_420_38,https://scrap.kakaocdn.net/dn/cpwVBj/hyJ2pzCMiJ/EoERe7AZ4aqPYGsEMsYbX0/img.png?width=1025&amp;amp;height=205&amp;amp;face=0_0_1025_205');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;What is the difference between BCEWithLogitsLoss and MultiLabelSoftMarginLoss&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;I think there is no difference between BCEWithLogitsLoss and MultiLabelSoftMarginLoss. BCEWithLogitsLoss = One Sigmoid Layer + BCELoss (solved numerically unstable problem) MultiLabelSoftMargin&amp;rsquo;s fomula is also same with BCEWithLogitsLoss. One difference&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;discuss.pytorch.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;위 토론 글에서 ptrblck 형님께서 두 모듈은 같은 일을 하며 두 모듈의 출력 값이 같다는 예시를 들어주셨는데 pytorch 지금 버전으로 돌려보면 값이 달라 오류가 나는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619503618462&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code class=&quot;night-owl&quot;&gt;x = Variable(torch.randn(10, 3))
y = Variable(torch.FloatTensor(10, 3).random_(2))

# double the loss for class 1
class_weight = torch.FloatTensor([1.0, 2.0, 1.0])
# double the loss for last sample
element_weight = torch.FloatTensor([1.0]*9 + [2.0]).view(-1, 1)
element_weight = element_weight.repeat(1, 3)

bce_criterion = nn.BCEWithLogitsLoss(weight=None, reduce=False)
multi_criterion = nn.MultiLabelSoftMarginLoss(weight=None, reduce=False)

bce_criterion_class = nn.BCEWithLogitsLoss(weight=class_weight, reduce=False)
multi_criterion_class = nn.MultiLabelSoftMarginLoss(weight=class_weight, reduce=False)

bce_criterion_element = nn.BCEWithLogitsLoss(weight=element_weight, reduce=False)
multi_criterion_element = nn.MultiLabelSoftMarginLoss(weight=element_weight, reduce=False)

bce_loss = bce_criterion(x, y)
multi_loss = multi_criterion(x, y)

bce_loss_class = bce_criterion_class(x, y)
multi_loss_class = multi_criterion_class(x, y)

bce_loss_element = bce_criterion_element(x, y)
multi_loss_element = multi_criterion_element(x, y)

print(bce_loss - multi_loss)
print(bce_loss_class - multi_loss_class)
print(bce_loss_element - multi_loss_element)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p7Lhw/btq3CzFcKbn/xStpdlcBkbI0PC4g16qh71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p7Lhw/btq3CzFcKbn/xStpdlcBkbI0PC4g16qh71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p7Lhw/btq3CzFcKbn/xStpdlcBkbI0PC4g16qh71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp7Lhw%2Fbtq3CzFcKbn%2FxStpdlcBkbI0PC4g16qh71%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;우선 &lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BCEWithLogitsLoss 모듈에 대한 설명&lt;/a&gt;을 보면 BCEWithLogitsLoss는 기본적으로 one single class에 대한 loss를 계산하기 위해 나온 모듈이라고 한다. 그리고 이를 확장시켜서 multi label에 대해서 활용이 가능하다고 한다. &lt;span style=&quot;color: #333333;&quot;&gt;그래서 만일 데이터가 5개의 class를 가진 multi label이라면 각 class 별로 BCEWithLogitsLoss 값이 나오게 된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSUanz/btq3CegQjjH/U5eZgHtxHrFsIvKVJqK5v0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSUanz/btq3CegQjjH/U5eZgHtxHrFsIvKVJqK5v0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSUanz/btq3CegQjjH/U5eZgHtxHrFsIvKVJqK5v0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSUanz%2Fbtq3CegQjjH%2FU5eZgHtxHrFsIvKVJqK5v0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;그리고 MultiLabelSoftMarginLoss 모듈에 대한 설명을 보면 각 label에 대한 BCE 값을 평균 낸다고 한다. 즉, Multi Label Classification 문제는 애초에 label 별로 계산된 loss 값이 개별적으로 쓰일 필요가 없기 때문에 전체 class 개수로 나눈 값을 반환해주고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqyMzP/btq3Argq7fz/6fjsaIAgKBSweynNahg7c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqyMzP/btq3Argq7fz/6fjsaIAgKBSweynNahg7c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqyMzP/btq3Argq7fz/6fjsaIAgKBSweynNahg7c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqyMzP%2Fbtq3Argq7fz%2F6fjsaIAgKBSweynNahg7c0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예시 코드로 확인해보자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619504489729&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; target = torch.randint(0,2,(3,5), dtype=torch.float32)
&amp;gt;&amp;gt;&amp;gt; target
tensor([[1., 1., 0., 0., 1.],
        [1., 1., 0., 1., 0.],
        [1., 0., 1., 0., 1.]])
&amp;gt;&amp;gt;&amp;gt; output = torch.randn((3,5))
&amp;gt;&amp;gt;&amp;gt; output
tensor([[-0.7480,  0.6282, -1.8508, -0.5212, -0.6264],
        [ 0.0744, -0.2861,  2.3179, -1.2633,  1.0343],
        [ 0.6806, -0.0375, -1.4666, -0.2414,  0.3977]])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;우선 5개의 label을 갖는 3개의 데이터를 만들어 보았다. target은 정답 데이터이고 output은 모델에서 나온 output logits으로 생각하면 되겠다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619504594462&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bce_criterion = nn.BCEWithLogitsLoss(reduction='none')
&amp;gt;&amp;gt;&amp;gt; bce_criterion(output, target)
tensor([[1.1355, 0.4276, 0.1459, 0.4661, 1.0546],
        [0.6567, 0.8464, 2.4118, 1.5123, 1.3385],
        [0.4097, 0.6746, 1.6742, 0.5797, 0.5139]])

&amp;gt;&amp;gt;&amp;gt; multi_criterion = nn.MultiLabelSoftMarginLoss(reduction='none')
&amp;gt;&amp;gt;&amp;gt; multi_criterion(output, target)
tensor([0.6460, 1.3531, 0.7704])

&amp;gt;&amp;gt;&amp;gt; bce_criterion(output, target).mean(axis=-1)
tensor([0.6460, 1.3531, 0.7704])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;BCEWithLogitsLoss, MultiLabelSoftMarginLoss 모듈 둘 다 기본적으로 reduction 파라미터의 default 값이 'mean'으로 되어있어 정확한 출력 값 비교를 위해 '&lt;b&gt;none&lt;/b&gt;'으로 두고 수행을 돌려보았다.&lt;/p&gt;
&lt;p&gt;(위 토론글에서 ptrblck 형님께서 reduce=False로 설정하신 것과 같은 의미인데 pytorch 상위 버전에서는 reduce 파라미터가 사라지고 reduction 파라미터를 써야 한다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;결과를 보게 되면 BCEWithLogitsLoss의 출력 값은 3x5의 형식으로 데이터의 각 label별로 계산한 loss 값을 그대로 보여주고 있다. 반면 MultiLabelSoftMarginLoss는 각 데이터마다 label별로 계산한 loss 값을 평균 내어 보여주고 있다. 따라서 BCEWithLogitsLoss의 출력 값을 데이터 별로 평균 내보면 MultiLabelSoftMarginLoss 값과 같은 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;BCEWithLogitsLoss와 &lt;/b&gt;&lt;b&gt;MultiLabelSoftMarginLoss는 같은 일을 한다. &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;하지만 둘은 Binary Classification을 위해 만들어졌는가 Multi Label Classification을 위해서 만들어졌는가의 차이가 있다. &lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그래서 loss 계산 결과에 있어 형태의 차이가 있고 값은 같은 것을 확인할 수 있다. 보통 우리는 reduction을 'mean'으로 두고(default) 사용하기 때문에 두 모듈을 섞어 사용해도 차이가 없을 것으로 예상된다. &lt;/span&gt;&lt;u style=&quot;letter-spacing: 0px;&quot;&gt;하지만 이런 작은 차이를 알아둔다면 나중에 디버깅할 때 도움이 될 수도 있을 것 같다.&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619506126729&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; bce_criterion = nn.BCEWithLogitsLoss()
&amp;gt;&amp;gt;&amp;gt; multi_criterion = nn.MultiLabelSoftMarginLoss()
&amp;gt;&amp;gt;&amp;gt; print(bce_criterion(output, target), multi_criterion(output, target))
tensor(0.9232) tensor(0.9232)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Deep Learning/Pytorch</category>
      <category>MultiLabelSoftMarginLoss</category>
      <category>pytorch</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/26</guid>
      <comments>https://cvml.tistory.com/26#entry26comment</comments>
      <pubDate>Tue, 27 Apr 2021 15:58:32 +0900</pubDate>
    </item>
    <item>
      <title>[개발팁] 'MultilabelStrarifiedKFold' : Multi-label classification 에 적용 가능한 strarification cross validator</title>
      <link>https://cvml.tistory.com/25</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;StratifiedKFold in scikit-learn&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;우리가 보통 이진분류 같은 문제를 풀기 위해서 제공된 데이터셋을 학습/검증 셋으로 나눌 때 데이터셋의 class별 비율을 동일하게 가져가서 학습한다. 이 때, 주로 사용하는 것이 scikit-learn의 'StratifiedKFold' 함수인데 이것을 사용하면 K-fold 교차검증을 수행하면서 동시에 매 fold마다 데이터셋의 class 비율을 일정하게 나누어서 학습/검증 셋으로 나눠준다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;예를들어, '자동차, 자전거, 오토바이' class가 각각 1000개, 500개, 100개로 총 1600개로 이루어진 데이터셋을 StratifiedKFold 함수를 이용해서 5-fold로 나눈다면 매 fold마다 학습 데이터셋은 1280개 (자동차 800개, 자전거 400개, 오토바이 80개), 검증 데이터셋은 320개 (자동차 200개, 자전거 100개, 오토바이 20개)의 동일한 비율로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1618972406211&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.model_selection import StratifiedKFold

skfolds = StratifiedKFold(n_split=5, random_state=24)

fro train_idx, test_idx in skfolds.split(X_train, y_train):
	X_train_folds = X_train[train_idx]
    y_train_folds = y_train[train_idx]
    X_test_folds = X_train[test_idx]
    y_test_folds = y_train[test_idx]
    
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;하지만 위처럼 입력으로 들어온 데이터가 자동차, 자전거, 오토바이중에 어떤 것인지 판별하는 Multi-class Classification 문제라면 상관 없지만 Multi-label Classification 문제라면 위 방법으로 데이터셋을 나눌 수 없다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi-label Classification&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;[kaggle] &lt;a href=&quot;https://www.kaggle.com/c/plant-pathology-2021-fgvc8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Plant Pathology 2021 competition&lt;/a&gt; - multi-label classficiation 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;multi-label classification 문제는 위의 상황을 예로 들자면 입력으로 들어온 데이터가 사진으로 가정하고 사진 속에 '자동차, 자전거, 오토바이'중에 어떤 것들이 있는지 판별하는 문제로 생각하면 된다. 예를 들어, 샘플 데이터(사진)에 자동차와 오토바이가 등장했다면 해당 데이터의 gt(ground truth)값은 '자동차, 오토바이'로 multi label이 된다. 그래서 모델 학습을 위해 '자동차, 오토바이'가 존재하는 데이터를 해당 label이 존재하면 1, 없으면 0으로 표현하여 [1, 0, 1]처럼 변환하여 사용한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;아쉽게도 scikit-learn에서는 이러한 muilti-label 데이터를 일정한 비율로 나눠주는 strarification 함수를 제공하고 있지 않다. 그렇다고 랜덤으로 추출해서 학습/검증 데이터셋을 나누다보면 overfitting에 빠지는 문제가 발생할 수 있다. 그래서 해결책을 찾아보던 중 이 문제를 해결해주는 라이브러리가 있어서 이를 소개하고자 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/trent-b/iterative-stratification&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/trent-b/iterative-stratification&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618976408650&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;trent-b/iterative-stratification&quot; data-og-description=&quot;scikit-learn cross validators for iterative stratification of multilabel data - trent-b/iterative-stratification&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/trent-b/iterative-stratification&quot; data-og-url=&quot;https://github.com/trent-b/iterative-stratification&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4imzO/hyJWGwA3Pa/XWrEJpbia52siHtuF9j530/img.png?width=1200&amp;amp;height=600&amp;amp;face=965_131_1060_236&quot;&gt;&lt;a href=&quot;https://github.com/trent-b/iterative-stratification&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/trent-b/iterative-stratification&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4imzO/hyJWGwA3Pa/XWrEJpbia52siHtuF9j530/img.png?width=1200&amp;amp;height=600&amp;amp;face=965_131_1060_236');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;trent-b/iterative-stratification&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;scikit-learn cross validators for iterative stratification of multilabel data - trent-b/iterative-stratification&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MultilabelStratifiedKFold&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;친절하게도 iterative-stratification 프로젝트에서 'MultilabelStratifiedKFold'를 사용하면 multi-label을 갖는 데이터들의 비율을 일정하게 나눌 수 있어 학습이 가능하다! 사용 방법도 scikit-learn에서 제공하는 StratifiedKFold 함수와 같은 방식으로 사용하면 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;기본 예제&lt;/p&gt;
&lt;pre id=&quot;code_1618978179933&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from iterstrat.ml_stratifiers import MultilabelStratifiedKFold
import numpy as np

X = np.array([[1,2], [3,4], [1,2], [3,4], [1,2], [3,4], [1,2], [3,4]])
y = np.array([[0,0], [0,0], [0,1], [0,1], [1,1], [1,1], [1,0], [1,0]])

mskf = MultilabelStratifiedKFold(n_splits=2, shuffle=True, random_state=0)

for train_index, test_index in mskf.split(X, y):
   print(&quot;TRAIN:&quot;, train_index, &quot;TEST:&quot;, test_index)
   X_train, X_test = X[train_index], X[test_index]
   y_train, y_test = y[train_index], y[test_index]
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;Output&lt;/p&gt;
&lt;pre id=&quot;code_1618978200740&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TRAIN: [0 3 4 6] TEST: [1 2 5 7]
TRAIN: [1 2 5 7] TEST: [0 3 4 6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;kaggle 에서 진행하고 있는 plant-pathology-2021 competition의 데이터를 가지고 예시 코드를 돌려보았다. (자세한 결과 정보는 아래 kaggle notebook을 확인하면 좋습니다.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.kaggle.com/ljh0128/multi-label-data-split-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.kaggle.com/ljh0128/multi-label-data-split-method&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618976878733&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Multi-label data split method&quot; data-og-description=&quot;Explore and run machine learning code with Kaggle Notebooks | Using data from Plant Pathology 2021 - FGVC8&quot; data-og-host=&quot;www.kaggle.com&quot; data-og-source-url=&quot;https://www.kaggle.com/ljh0128/multi-label-data-split-method&quot; data-og-url=&quot;https://kaggle.com/ljh0128/multi-label-data-split-method&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c7XuKY/hyJWxsRsBs/eqJO7IgJQp7tbjhsd9kkfK/img.jpg?width=100&amp;amp;height=100&amp;amp;face=0_0_100_100&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/ljh0128/multi-label-data-split-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kaggle.com/ljh0128/multi-label-data-split-method&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c7XuKY/hyJWxsRsBs/eqJO7IgJQp7tbjhsd9kkfK/img.jpg?width=100&amp;amp;height=100&amp;amp;face=0_0_100_100');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Multi-label data split method&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Explore and run machine learning code with Kaggle Notebooks | Using data from Plant Pathology 2021 - FGVC8&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.kaggle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1618976935895&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; df.head()
	image			healthy	scab frog_eye_leaf_spot	complex	rust	powdery_mildew
0	800113bb65efe69e.jpg	1	0	0		0	0		0
1	8002cb321f8bfcdf.jpg	0	1	1		1	0		0
2	80070f7fb5e2ccaa.jpg	0	1	0		0	0		0
3	80077517781fb94f.jpg	0	1	0		0	0		0
4	800cbf0ff87721f8.jpg	0	0	0		1	0		0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 대회에서 제공하고 있는 데이터는 ['healthy', 'scab', 'frog_eye_leaf_spot', 'complex', 'rust', 'powdery_mildew'] 라는 6개의 label을 갖는 muilti-label dataset이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1618977087583&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import plotly.express as px
&amp;gt;&amp;gt;&amp;gt; fig = px.parallel_categories(
	df[[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;]], 
    	color=&quot;healthy&quot;, 
    	color_continuous_scale=&quot;sunset&quot;,
    	title=&quot;Parallel categories plot of targets&quot;
    	)
&amp;gt;&amp;gt;&amp;gt; fig.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이를 plotly 라이브러리를 이용해 시각화하면 아래처럼 데이터의 분포를 파악할 수 있다. 간략하게 그림을 설명하자면 각 label별로 1, 0을 갖는 데이터의 분포를 막대로 표현하였고 파란색 연결선 처럼 &lt;span style=&quot;color: #333333;&quot;&gt;['healthy', 'scab', 'frog_eye_leaf_spot', 'complex', 'rust', 'powdery_mildew'] = [1, 0, 0, 0, 0, 0]인 데이터의 개수가 많을 수록 두껍게 표현하였다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;newplot.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmVguh/btq23t7Vhk7/E4WeMskOtqMWrHLA4w2t6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmVguh/btq23t7Vhk7/E4WeMskOtqMWrHLA4w2t6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmVguh/btq23t7Vhk7/E4WeMskOtqMWrHLA4w2t6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmVguh%2Fbtq23t7Vhk7%2FE4WeMskOtqMWrHLA4w2t6k%2Fimg.png&quot; data-filename=&quot;newplot.png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이제 이 데이터셋을 MultiStratifiedKFold 함수를 이용하여 나눠보고 plotly를 이용해 시각화해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1618978076294&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install iterative-stratification&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1618977469718&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X,Y = df['image'].to_numpy(), df[[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;]].to_numpy(dtype=np.float32)

from iterstrat.ml_stratifiers import MultilabelStratifiedKFold

msss = MultilabelStratifiedKFold(n_splits=5, shuffle=True, random_state=1234)

for train_index, test_index in msss.split(X, Y):
    print(&quot;TRAIN:&quot;, train_index, &quot;TEST:&quot;, test_index)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = Y[train_index], Y[test_index]
    
    kfold_train_df = pd.DataFrame(columns=[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;], data=y_train)
    kfold_test_df = pd.DataFrame(columns=[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;], data=y_test)
    
    fig_train = px.parallel_categories(kfold_train_df[[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;]], color=&quot;healthy&quot;, color_continuous_scale=&quot;sunset&quot;,\
                             title=&quot;categories plot of y_train&quot;)
    fig_test = px.parallel_categories(kfold_test_df[[&quot;healthy&quot;, &quot;scab&quot;, &quot;frog_eye_leaf_spot&quot;, &quot;complex&quot;,&quot;rust&quot;,&quot;powdery_mildew&quot;]], color=&quot;healthy&quot;, color_continuous_scale=&quot;sunset&quot;,\
                             title=&quot;categories plot of y_test&quot;)
    
    fig_train.show()
    fig_test.show()
    
    break&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;newplot (1).png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/da1Ph8/btq3atyfZW5/L9g98PEWeELbmO5DvyBqK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/da1Ph8/btq3atyfZW5/L9g98PEWeELbmO5DvyBqK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/da1Ph8/btq3atyfZW5/L9g98PEWeELbmO5DvyBqK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fda1Ph8%2Fbtq3atyfZW5%2FL9g98PEWeELbmO5DvyBqK1%2Fimg.png&quot; data-filename=&quot;newplot (1).png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;newplot (2).png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oV2Ie/btq26Fzsqj1/50dAp5a5fYbZbPLugNewi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oV2Ie/btq26Fzsqj1/50dAp5a5fYbZbPLugNewi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oV2Ie/btq26Fzsqj1/50dAp5a5fYbZbPLugNewi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoV2Ie%2Fbtq26Fzsqj1%2F50dAp5a5fYbZbPLugNewi0%2Fimg.png&quot; data-filename=&quot;newplot (2).png&quot; data-origin-width=&quot;803&quot; data-origin-height=&quot;525&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;MultilabelStratifiedKFold를 이용해서 나누어진 데이터셋을 보게되면 train data와 test data의 분포가 비슷한 것을 확인할 수 있다. 즉, 원본 데이터셋의 multi-label의 비율에 맞게 잘 나누어 주었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;따라서, Multi-label Classification 문제를 풀고자 할 때 데이터셋을 비율에 맞게 나누고 싶다면 iterative-stratification 라이브러리를 이용하자!&lt;/p&gt;</description>
      <category>Deep Learning/Pytorch</category>
      <category>Multi-label classfication</category>
      <category>MultilabelStratifiedKFold</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/25</guid>
      <comments>https://cvml.tistory.com/25#entry25comment</comments>
      <pubDate>Wed, 21 Apr 2021 13:13:09 +0900</pubDate>
    </item>
    <item>
      <title>num_workers &amp;amp; pin_memory in DataLoader</title>
      <link>https://cvml.tistory.com/24</link>
      <description>&lt;p&gt;pytorch를 이용해 딥러닝 모델을 학습시킬 때 custom dataset을 이용할 경우&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;torch.utils.data.Dataset&lt;/span&gt;으로 데이터셋을 정의하고(input data type, augmentation 등)&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;torch.utils.data.DataLoader&lt;/span&gt;로 어떻게 데이터셋을 불러올 지(batch size, sampling 등) 정의한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;학습을 시키다 보면 병목이 생기는 부분이 있는데 특히 데이터를 읽어서 가져올 때 시간이 오래 걸린다. 모델 학습을 하는데 시간을 써도 모자랄 판에 학습하기도 전에 불러오는 데이터에서 시간이 걸린다니... 즉, CPU를 이용해 데이터를 저장된 SSD나 HDD에서 읽어와 호스트의 메모리에 올리고 학습을 위해 GPU 메모리로 전달하는 과정에서 병목이 발생한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이를 좀 더 빠르게 수행할 수 있도록 파라미터를 설정할 수 있는데 대표적인 것이 바로 DataLoader에 있는 'num_workers'와 'pin_memory'다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;num_workers&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;pytorch 공식 문서&lt;/a&gt;에서 num_workers는 다음과 같이 설명되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;text-align: justify;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #333333;&quot;&gt;num_workers (int, optional) &amp;ndash; how many subprocesses to use for data loading. 0 means that the data will be loaded in the main process. (default: 0)&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p&gt;즉, 서브 프로세스를 실행시켜 데이터를 불러오는데 그 때 실행시킬 서프 프로세스의 개수를 의미하는 파라미터다. 멀티프로세싱을 통해 저장된 데이터를 빠르게 가져오도록 하는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러면 많으면 많을수록 좋은거 아니야? 꼭 그렇지만은 않다. 자세한 내용은 아래 토론 글을 읽어보는 것을 추천한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618741908759&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Guidelines for assigning num_workers to DataLoader&quot; data-og-description=&quot;I realize that to some extent this comes down to experimentation, but are there any general guidelines on how to choose the num_workers for a DataLoader object? Should num_workers be equal to the batch size? Or the number of CPU cores in my machine? Or to &quot; data-og-host=&quot;discuss.pytorch.org&quot; data-og-source-url=&quot;https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&quot; data-og-url=&quot;https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3Sy0o/hyJU62Kp6Y/aH3LclIdAqKokr157vkGIk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/BBRSv/hyJURdsI8d/TtH0krlZxRvxV1grUF3ZQK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/dVxcNx/hyJURLihKw/FDnr1R0Mbtwdipwbs2RkJK/img.png?width=1025&amp;amp;height=205&amp;amp;face=0_0_1025_205&quot;&gt;&lt;a href=&quot;https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://discuss.pytorch.org/t/guidelines-for-assigning-num-workers-to-dataloader/813&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3Sy0o/hyJU62Kp6Y/aH3LclIdAqKokr157vkGIk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/BBRSv/hyJURdsI8d/TtH0krlZxRvxV1grUF3ZQK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/dVxcNx/hyJURLihKw/FDnr1R0Mbtwdipwbs2RkJK/img.png?width=1025&amp;amp;height=205&amp;amp;face=0_0_1025_205');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Guidelines for assigning num_workers to DataLoader&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;I realize that to some extent this comes down to experimentation, but are there any general guidelines on how to choose the num_workers for a DataLoader object? Should num_workers be equal to the batch size? Or the number of CPU cores in my machine? Or to&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;discuss.pytorch.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;num_workers가 몇 개가 적당한지에 대한 정답은 없다. 학습 환경의 GPU, CPU개수, I/O속도, 메모리 등과 같이 다양한 조건에 따라 최적의 값이 다르다고 한다. 아래 사진처럼 어떤 사람의 학습 환경에서는 num_workers가 5일 때 최적이지만 다른 사람의 환경에서는 다를 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AwY7S/btq2NcrJPx0/SZEE37AUXNsbCqExIxCoE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AwY7S/btq2NcrJPx0/SZEE37AUXNsbCqExIxCoE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AwY7S/btq2NcrJPx0/SZEE37AUXNsbCqExIxCoE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAwY7S%2Fbtq2NcrJPx0%2FSZEE37AUXNsbCqExIxCoE0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;따라서 어떤 글들에서 보면 num_workers = GPU 개수 * 4 로 지정하면 좋다라는 말이 있는데 항상 그렇다고 생각하면 안된다는 것!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;pin_memory&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;pin_memory&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;/span&gt;&lt;a href=&quot;https://docs.python.org/3/library/functions.html#bool&quot;&gt;bool&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;optional&lt;span&gt;) &amp;ndash; If&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;True&lt;/span&gt;&lt;span&gt;, the data loader will copy Tensors into CUDA pinned memory before returning them. If your data elements are a custom type, or your&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;collate_fn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;returns a batch that is a custom type, see the example below.&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;b&gt;&lt;a href=&quot;https://blog.naver.com/julie_eun1014/221116312880&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blog.naver.com/julie_eun1014/221116312880&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618742682881&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;CUDA 기반의 GPU Memory 이해하기&quot; data-og-description=&quot;1. 메모리 구조 메모리 사용은 커널과 더불어 항상 중요하게 고려해야 하는 요소입니다. 그래픽 메모리는 ...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/julie_eun1014/221116312880&quot; data-og-url=&quot;https://blog.naver.com/julie_eun1014/221116312880&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ehlmyK/hyJU350EIK/rqv21losX8OHTKFyr1ko3K/img.png?width=743&amp;amp;height=650&amp;amp;face=0_0_743_650,https://scrap.kakaocdn.net/dn/bsRQSn/hyJUUVz2ZD/cBqWj2hKfh7thT57FQTbY1/img.png?width=80&amp;amp;height=70&amp;amp;face=0_0_80_70&quot;&gt;&lt;a href=&quot;https://blog.naver.com/julie_eun1014/221116312880&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/julie_eun1014/221116312880&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ehlmyK/hyJU350EIK/rqv21losX8OHTKFyr1ko3K/img.png?width=743&amp;amp;height=650&amp;amp;face=0_0_743_650,https://scrap.kakaocdn.net/dn/bsRQSn/hyJUUVz2ZD/cBqWj2hKfh7thT57FQTbY1/img.png?width=80&amp;amp;height=70&amp;amp;face=0_0_80_70');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;CUDA 기반의 GPU Memory 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;1. 메모리 구조 메모리 사용은 커널과 더불어 항상 중요하게 고려해야 하는 요소입니다. 그래픽 메모리는 ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;데이터를 CPU로 읽어들인 다음 GPU로 보내기 위해서는 GPU와 통신하기 위한 CPU의 메모리 공간이 필요하다. 이 때, 메모리를 할당시키는 기법을 memory pinning이라고 한다. memory pinning을 하는 데 사용되는 메모리의 종류는 pageable memory와 pinned memory가 있는데 pinned memory가 더 빠르다고 한다.&lt;/p&gt;
&lt;p&gt;(pinned memory : Virtual memory를 사용하지 않는 Memory Mapped memory)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqz8qQ/btq2QUi1I8I/pV0JJaVEmXFtQQT8Nrbsck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqz8qQ/btq2QUi1I8I/pV0JJaVEmXFtQQT8Nrbsck/img.png&quot; data-alt=&quot;https://developer.nvidia.com/blog/how-optimize-data-transfers-cuda-cc/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqz8qQ/btq2QUi1I8I/pV0JJaVEmXFtQQT8Nrbsck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdqz8qQ%2Fbtq2QUi1I8I%2FpV0JJaVEmXFtQQT8Nrbsck%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://developer.nvidia.com/blog/how-optimize-data-transfers-cuda-cc/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;즉, &lt;span style=&quot;color: #333333;&quot;&gt;pinned memory는 위에 그림처럼 GPU에서 호스트에서 디바이스로 전송을 위한 staging area이고 pinned data transfer는 pinned memory와 pageable memory의 전송 비용을 줄이기 위해 데이터를 pin memory에 고정시켜 전송하는 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우리가 pin_memory = True로 하게된다면 입력 데이터를 바로 pinned memory에 로드하여 빠르게 데이터 복사를 해 CUDA 연산을 효율적으로 할 수 있게 해준다. 따라서 시스템 메모리가 넉넉하다면 pin_memory = True로 하고 학습을 수행한다면 병목을 개선시킬 수 있다.&lt;/p&gt;</description>
      <category>Deep Learning/Pytorch</category>
      <category>DataLoader</category>
      <category>num_worker</category>
      <category>pin_memory</category>
      <category>pytorch</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/24</guid>
      <comments>https://cvml.tistory.com/24#entry24comment</comments>
      <pubDate>Sun, 18 Apr 2021 20:01:07 +0900</pubDate>
    </item>
    <item>
      <title>[개발팁] Multi-label Classification에 쓸만한 전처리 모듈 'MultiLabelBinarizer'</title>
      <link>https://cvml.tistory.com/23</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi-label Classification problem&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;캐글에서 진행하고 있는 '&lt;a href=&quot;https://www.kaggle.com/c/plant-pathology-2021-fgvc8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Plant Pathology 2021 - FGVC8&lt;/a&gt;' competition을 진행하다가 찾게 된 유용한 모듈.&lt;/p&gt;
&lt;figure id=&quot;og_1618735179807&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Plant Pathology 2021 - FGVC8&quot; data-og-description=&quot;Identify the category of foliar diseases in apple trees&quot; data-og-host=&quot;www.kaggle.com&quot; data-og-source-url=&quot;https://www.kaggle.com/c/plant-pathology-2021-fgvc8&quot; data-og-url=&quot;https://kaggle.com/c/plant-pathology-2021-fgvc8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VPay6/hyJU174ucr/MJ3K2wUZCeWtIjUh2Y34Zk/img.png?width=240&amp;amp;height=240&amp;amp;face=0_0_240_240&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/c/plant-pathology-2021-fgvc8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kaggle.com/c/plant-pathology-2021-fgvc8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VPay6/hyJU174ucr/MJ3K2wUZCeWtIjUh2Y34Zk/img.png?width=240&amp;amp;height=240&amp;amp;face=0_0_240_240');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Plant Pathology 2021 - FGVC8&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Identify the category of foliar diseases in apple trees&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.kaggle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;해당 대회는 Multi-label Image Classification 문제로 사과나무 잎에 어떤 병에 걸렸는지 판별해야 한다.&lt;/p&gt;
&lt;p&gt;제공되는 데이터셋의 label을 보면 문자열로 병명을 제공하고 있으며 건강할 경우 'healthy', 병에 걸려있는 경우 병 이름들을 공백으로 구분하여 보여주고 있다. 즉, 두 개 이상의 병에 걸려있는 경우 '&lt;span style=&quot;color: #333333;&quot;&gt;scab frog_eye_leaf_spot complex&lt;/span&gt;' 이런 식으로 알려주고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618735591632&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; train_df.head()

'''
	image			labels
0	800113bb65efe69e.jpg	healthy
1	8002cb321f8bfcdf.jpg	scab frog_eye_leaf_spot complex
2	80070f7fb5e2ccaa.jpg	scab
3	80077517781fb94f.jpg	scab
4	800cbf0ff87721f8.jpg	complex
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 우리는 모델을 학습시켜서 어떤 병에 걸려있는지 알려줘야 하는데 output을 저런 문자열 형식으로 주는 것은 힘들고 [0, 0, 1, 0, 0, 0] -&amp;gt; 'healthy', [1, 1, 0, 0, 0, 1] -&amp;gt; 'scab frog_eye_leaf_spot complex' 이렇게 0과 1로 이루어진 multi-label class output을 주고 문자열로 매핑해주는 것이 필요하다!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 어떻게 할까?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우선 학습을 위해서 반대로 문자열 label을 0과 1로 이루어진 multi-label class형식으로 바꿔주자!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현재 이 대회에서 분류하고자 하는 병(class)은 다음과 같이 분류된다.&lt;/p&gt;
&lt;p&gt;['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew', 'rust', 'scab']&lt;/p&gt;
&lt;p&gt;처음에 나는 일일이 label을 보면서 해당 class가 있으면 1, 없으면 0을 넣어 만들어 주었는데 &lt;a href=&quot;https://www.kaggle.com/nickuzmenkov/pp2021-ultimate-preprocessing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다른 분들의 커널&lt;/a&gt;을 보다가 &lt;b&gt;scikit-learn&lt;/b&gt;에서 이와 관련된 전처리 모듈이 있어서 참고하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MultiLabelBinarizer 적용하기 (scikit-learn)&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;scikit-learn 공식 문서&lt;/a&gt;에서 다음 예제를 확인할 수 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1618736837299&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;sklearn.preprocessing.MultiLabelBinarizer &amp;mdash; scikit-learn 0.24.1 documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;scikit-learn.org&quot; data-og-source-url=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html&quot; data-og-url=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;sklearn.preprocessing.MultiLabelBinarizer &amp;mdash; scikit-learn 0.24.1 documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;scikit-learn.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1618736878212&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from sklearn.preprocessing import MultiLabelBinarizer
&amp;gt;&amp;gt;&amp;gt; mlb = MultiLabelBinarizer()
&amp;gt;&amp;gt;&amp;gt; mlb.fit_transform([(1, 2), (3,)])
array([[1, 1, 0],
       [0, 0, 1]])
&amp;gt;&amp;gt;&amp;gt; mlb.classes_
array([1, 2, 3])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아주 편하게도 &lt;b&gt;MultiLabelBinarizer&lt;/b&gt; 모듈을 사용하게 되면 알아서 class의 종류(개수) 인식과 multi-label encoding을 수행한다.&lt;/p&gt;
&lt;p&gt;따라서 대회에 적용시켜본다면 label들을 split 하여 저장한 다음 이 모듈에 넣어주기만 하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1618737410948&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; train_df['labels'] = [x.split(' ') for x in train_df['labels']]
&amp;gt;&amp;gt;&amp;gt; train_df.head()
'''
	image			labels
0	800113bb65efe69e.jpg	[healthy]
1	8002cb321f8bfcdf.jpg	[scab, frog_eye_leaf_spot, complex]
2	80070f7fb5e2ccaa.jpg	[scab]
3	80077517781fb94f.jpg	[scab]
4	800cbf0ff87721f8.jpg	[complex]
'''
&amp;gt;&amp;gt;&amp;gt; mlb = MultiLabelBinarizer()
&amp;gt;&amp;gt;&amp;gt; labels = mlb.fit_transform(train_df['labels'].values)
&amp;gt;&amp;gt;&amp;gt; labels
array([[0, 0, 1, 0, 0, 0],
       [1, 1, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 1],
       ...,
       [0, 0, 0, 0, 1, 0],
       [0, 1, 0, 0, 0, 1],
       [0, 0, 1, 0, 0, 0]])
&amp;gt;&amp;gt;&amp;gt; mlb.classes_
array(['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew',
       'rust', 'scab'], dtype=object)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 만들어진 multi-label class 값을 저장하여 딥러닝 모델의 target 값으로 이용하면 된다 :)&lt;/p&gt;
&lt;pre id=&quot;code_1618737663676&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; new_train_df = pd.DataFrame(columns=mlb.classes_, data=labels)
&amp;gt;&amp;gt;&amp;gt; new_train_df.insert(0,'image',train_df['image'])
&amp;gt;&amp;gt;&amp;gt; new_train_df.head()
'''

	image			complex	frog_eye_leaf_spot	healthy	powdery_mildew	rust	scab
0	800113bb65efe69e.jpg	0	0			1	0		0	0
1	8002cb321f8bfcdf.jpg	1	1			0	0		0	1
2	80070f7fb5e2ccaa.jpg	0	0			0	0		0	1
3	80077517781fb94f.jpg	0	0			0	0		0	1
4	800cbf0ff87721f8.jpg	1	0			0	0		0	0
'''&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Deep Learning/Pytorch</category>
      <category>MultiLabelBinarizer</category>
      <category>pytorch</category>
      <category>scikit-learn</category>
      <category>딥러닝</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/23</guid>
      <comments>https://cvml.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 18 Apr 2021 18:28:20 +0900</pubDate>
    </item>
    <item>
      <title>[#05] Text Recognition Model 학습하기(deep-text-recognition-benchmark)</title>
      <link>https://cvml.tistory.com/22</link>
      <description>&lt;p&gt;OCR 모델을 이용하여 약국이나 편의점에서 살 수 있는 일반의약품의 상품명을 인식해보는 과정을 담아보는 글.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지난 글에서는 AI Hub에서 제공하는 Text in the Wild 데이터셋을 가공하여 학습할 수 있게 전처리 과정을 수행하였다. 전처리된 데이터를 이용하여 한글을 인식할 수 있는 Text Recognition Model을 학습해보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/clovaai/deep-text-recognition-benchmark&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618203371843&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;clovaai/deep-text-recognition-benchmark&quot; data-og-description=&quot;Text recognition (optical character recognition) with deep learning methods. - clovaai/deep-text-recognition-benchmark&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot; data-og-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/be60bY/hyJSkZGghT/HG9oAz3CK1QrXLjd01vGEk/img.jpg?width=247&amp;amp;height=247&amp;amp;face=0_0_247_247&quot;&gt;&lt;a href=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/be60bY/hyJSkZGghT/HG9oAz3CK1QrXLjd01vGEk/img.jpg?width=247&amp;amp;height=247&amp;amp;face=0_0_247_247');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;clovaai/deep-text-recognition-benchmark&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Text recognition (optical character recognition) with deep learning methods. - clovaai/deep-text-recognition-benchmark&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Conda 환경 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;deep-text-recognition-benchmark 모델을 학습시키기 위해 conda 환경을 새로 설정한다. CUDA 10.2, python 3.7의 학습 환경이었고 github 페이지에서 실험한 환경과는 다르지만 학습하는 데 문제는 없었다.&lt;/p&gt;
&lt;p&gt;(github에서는 opencv 라이브러리 설치에 대한 언급이 없지만 실제 코드를 돌리기 위해서는 opencv 라이브러리가 필요하니 함께 설치하자)&lt;/p&gt;
&lt;pre id=&quot;code_1618203524841&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;conda create -n ocr python=3.7
conda activate ocr

conda install pytorch torchvision cudatoolkit=10.2 -c pytorch
pip3 install lmdb pillow torchvision nltk natsort openv-python&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;lmdb dataset 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;deep-text-recognition-benchmark 모델을 학습하기 위해서는 데이터를 LMDB 파일로 저장해야한다. 일단 우리가 이전 글에서 AI Hub 데이터를 가공해 train, validation set을 나누었다. 그리고 각각에 대한 annotation인 gt_train.txt, gt_validation.txt도 만들어서 저장하였는데 다음과 같은 폴더 구조로 두어야 한다. (test set도 만들었지만 학습할 때는 사용하지 않으므로 언급하지 않음)&lt;/p&gt;
&lt;pre id=&quot;code_1618203661563&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data
├── gt_train.txt
└── train
    ├── word_1.png
    ├── word_2.png
    ├── word_3.png
    └── ...

# gt_train.txt 포맷 예시 \t 으로 구분되며 문장의 끝에는 \n
train/word_1.png Tiredness
train/word_2.png kills
train/word_3.png A
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러고 나면 주어진 설명대로 이미지와 라벨링 텍스트 파일을 lmdb 파일로 변환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618203833097&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#pip3 install fire
python3 create_lmdb_dataset.py --inputPath data/ --gtFile data/gt_train.txt --outputPath data_lmdb/train

python3 create_lmdb_dataset.py --inputPath data/ --gtFile data/gt_validation.txt --outputPath data_lmdb/validation&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한글 학습을 위한 configuration (train.py)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;github에 현재 공개되어 있는 모델은 IC15, SynthText(ST) 등과 같이 영어 데이터셋으로 학습시키는 것을 기준으로 설명되어 있다. 그래서 train.py 학습 파일을 보면 argument에서 '0123456789abcdefghijklmnopqrstuvwxyz'인 단어들만 학습하도록 character에 설정되어 있다. 물론 sensitive 옵션을 주게 되면 대문자 + 특수문자까지 학습할 수도 있다. 하지만 내가 학습시키고 싶은 것은 주로 한글이며 추가로 숫자+영어(소문자)+특수문자(!,?) 정도라 이에 맞게 조절해줄 필요가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206427565&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;parser.add_argument('--character', type=str,
                        default='0123456789abcdefghijklmnopqrstuvwxyz가각간갇갈감갑값갓강갖같갚갛개객걀걔거걱건걷걸검겁것겉게겨격겪견결겹경곁계고곡곤곧골곰곱곳공과관광괜괴굉교구국군굳굴굵굶굽궁권귀귓규균귤그극근글긁금급긋긍기긴길김깅깊까깍깎깐깔깜깝깡깥깨꺼꺾껌껍껏껑께껴꼬꼭꼴꼼꼽꽂꽃꽉꽤꾸꾼꿀꿈뀌끄끈끊끌끓끔끗끝끼낌나낙낚난날낡남납낫낭낮낯낱낳내냄냇냉냐냥너넉넌널넓넘넣네넥넷녀녁년념녕노녹논놀놈농높놓놔뇌뇨누눈눕뉘뉴늄느늑는늘늙능늦늬니닐님다닥닦단닫달닭닮담답닷당닿대댁댐댓더덕던덜덟덤덥덧덩덮데델도독돈돌돕돗동돼되된두둑둘둠둡둥뒤뒷드득든듣들듬듭듯등디딩딪따딱딴딸땀땅때땜떠떡떤떨떻떼또똑뚜뚫뚱뛰뜨뜩뜯뜰뜻띄라락란람랍랑랗래랜램랫략량러럭런럴럼럽럿렁렇레렉렌려력련렬렵령례로록론롬롭롯료루룩룹룻뤄류륙률륭르른름릇릎리릭린림립릿링마막만많말맑맘맙맛망맞맡맣매맥맨맵맺머먹먼멀멈멋멍멎메멘멩며면멸명몇모목몬몰몸몹못몽묘무묵묶문묻물뭄뭇뭐뭘뭣므미민믿밀밉밌및밑바박밖반받발밝밟밤밥방밭배백뱀뱃뱉버번벌범법벗베벤벨벼벽변별볍병볕보복볶본볼봄봇봉뵈뵙부북분불붉붐붓붕붙뷰브븐블비빌빔빗빚빛빠빡빨빵빼뺏뺨뻐뻔뻗뼈뼉뽑뿌뿐쁘쁨사삭산살삶삼삿상새색샌생샤서석섞선설섬섭섯성세섹센셈셋셔션소속손솔솜솟송솥쇄쇠쇼수숙순숟술숨숫숭숲쉬쉰쉽슈스슨슬슴습슷승시식신싣실싫심십싯싱싶싸싹싼쌀쌍쌓써썩썰썹쎄쏘쏟쑤쓰쓴쓸씀씌씨씩씬씹씻아악안앉않알앓암압앗앙앞애액앨야약얀얄얇양얕얗얘어억언얹얻얼엄업없엇엉엊엌엎에엔엘여역연열엷염엽엿영옆예옛오옥온올옮옳옷옹와완왕왜왠외왼요욕용우욱운울움웃웅워원월웨웬위윗유육율으윽은을음응의이익인일읽잃임입잇있잊잎자작잔잖잘잠잡잣장잦재쟁쟤저적전절젊점접젓정젖제젠젯져조족존졸좀좁종좋좌죄주죽준줄줌줍중쥐즈즉즌즐즘증지직진질짐집짓징짙짚짜짝짧째쨌쩌쩍쩐쩔쩜쪽쫓쭈쭉찌찍찢차착찬찮찰참찻창찾채책챔챙처척천철첩첫청체쳐초촉촌촛총촬최추축춘출춤춥춧충취츠측츰층치칙친칠침칫칭카칸칼캄캐캠커컨컬컴컵컷케켓켜코콘콜콤콩쾌쿄쿠퀴크큰클큼키킬타탁탄탈탑탓탕태택탤터턱턴털텅테텍텔템토톤톨톱통퇴투툴툼퉁튀튜트특튼튿틀틈티틱팀팅파팎판팔팝패팩팬퍼퍽페펜펴편펼평폐포폭폰표푸푹풀품풍퓨프플픔피픽필핏핑하학한할함합항해핵핸햄햇행향허헌험헤헬혀현혈협형혜호혹혼홀홈홉홍화확환활황회획횟횡효후훈훌훔훨휘휴흉흐흑흔흘흙흡흥흩희흰히힘?!', help='character label')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 우리가 만든 자체 데이터셋을 이용하는 것이므로 추가적으로 select_data, batch_ratio 옵션들에 대해 수정해 줄 필요가 있다. &lt;a href=&quot;https://github.com/clovaai/deep-text-recognition-benchmark/issues/85&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;관련 이슈&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618206769587&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;To train on my own dataset &amp;middot; Issue #85 &amp;middot; clovaai/deep-text-recognition-benchmark&quot; data-og-description=&quot;Hi. I created lmdb dataset on my own data by running create_lmdb_dataset.py. then I run the train command on it and got the following output: CUDA_VISIBLE_DEVICES=0 python3 train.py --train_data re...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark/issues/85&quot; data-og-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark/issues/85&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/z2uSF/hyJSkekLaL/iAa4OGkJU1jQQDHpLIo2lK/img.jpg?width=247&amp;amp;height=247&amp;amp;face=0_0_247_247&quot;&gt;&lt;a href=&quot;https://github.com/clovaai/deep-text-recognition-benchmark/issues/85&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/clovaai/deep-text-recognition-benchmark/issues/85&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/z2uSF/hyJSkekLaL/iAa4OGkJU1jQQDHpLIo2lK/img.jpg?width=247&amp;amp;height=247&amp;amp;face=0_0_247_247');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;To train on my own dataset &amp;middot; Issue #85 &amp;middot; clovaai/deep-text-recognition-benchmark&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Hi. I created lmdb dataset on my own data by running create_lmdb_dataset.py. then I run the train command on it and got the following output: CUDA_VISIBLE_DEVICES=0 python3 train.py --train_data re...&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1618206493781&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;parser.add_argument('--select_data', type=str, default='/',
                        help='select training data (default is MJ-ST, which means MJ and ST used as training data)')
parser.add_argument('--batch_ratio', type=str, default='1',
                        help='assign ratio for each selected data in the batch')&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;--character에서 defult='0123456789abcdefghijklmnopqrstuvwxyz'를 학습할 문자들로 고치기&lt;/li&gt;
&lt;li&gt;--select_data에서 default='MJ-ST'를 '/'로 수정
&lt;ul&gt;
&lt;li&gt;MJ, ST 데이터셋이 아닌 우리가 만든 커스텀 데이터셋을 사용할 것이므로&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;--batch_ratio에서 default='0.5-0.5'를 '1'로 수정
&lt;ul&gt;
&lt;li&gt;커스텀 데이터셋이 1종류이기 때문에&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;학습 시작&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;- Multi-GPU 환경으로 돌리기 위해서는 반드시 worker 옵션을 0으로 설정하자&lt;/p&gt;
&lt;p&gt;- 입력으로 들어가는 이미지의 해상도를 높이기 위해 imgW, imgH 옵션을 다르게 해 주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206615818&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CUDA_VISIBLE_DEVICES=0,1,2 python3 train.py --train_data data_lmdb/train --valid_data data_lmdb/validation \
	--Transformation TPS --FeatureExtraction ResNet --SequenceModeling BiLSTM --Prediction CTC \
	--data_filtering_off --workers 0 --imgH 64 --imgW 200&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 드디어 한글을 인식하는 recognition 모델을 학습시킬 수 있다!&lt;/p&gt;
&lt;p&gt;학습이 잘 되고 있다면 다음과 같은 결과가 validation interval마다 나올 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1618206669830&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[1/300000] Train loss: 182.36060, Valid loss: 154.85057, Elapsed_time: 11.88339
Current_accuracy : 0.000, Current_norm_ED  : 0.00
Best_accuracy    : 0.000, Best_norm_ED     : 0.00
--------------------------------------------------------------------------------
Ground Truth              | Prediction                | Confidence Score &amp;amp; T/F
--------------------------------------------------------------------------------
아이스크림을                    | 짜홉남홉굶홉굶홉홀붉                | 0.0000  False
할                         | 짜남디팅홉철남굶남굶홉굶홉홀붉           | 0.0000  False
글                         | 짜남홉남홉굶홉굶잔붉                | 0.0000       False
콩                         | 산짜몰디홉굶홉굶홉굶붉               | 0.0000      False
                          | 짜홉남굶붉                     | 0.0000     False
--------------------------------------------------------------------------------
[2000/300000] Train loss: 1.81739, Valid loss: 0.80669, Elapsed_time: 4313.83391
Current_accuracy : 74.677, Current_norm_ED  : 0.66
Best_accuracy    : 74.677, Best_norm_ED     : 0.66
--------------------------------------------------------------------------------
Ground Truth              | Prediction                | Confidence Score &amp;amp; T/F
--------------------------------------------------------------------------------
111가지                     | 가지                        | 0.3186      False
20s                       | 20                        | 0.4222  False
알려주는                      | 알려주는                      | 0.8682  True
매뉴얼                       | 한                         | 0.0042      False
실제로                       | 실제로                       | 0.8965    True
--------------------------------------------------------------------------------
[4000/300000] Train loss: 0.32394, Valid loss: 0.70662, Elapsed_time: 8566.73364
Current_accuracy : 82.371, Current_norm_ED  : 0.71
Best_accuracy    : 82.371, Best_norm_ED     : 0.71
--------------------------------------------------------------------------------
Ground Truth              | Prediction                | Confidence Score &amp;amp; T/F
--------------------------------------------------------------------------------
미역                        | 미역                        | 0.9915      True
페리오                       | 페리오                       | 0.8009    True
피클용                       | 피클용                       | 0.9577    True
이치로                       | 이치로                       | 0.9878    True
ew                        | ew                        | 0.9518  True
--------------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Deep Learning/OCR</category>
      <category>deep-text-recognition-benchmark</category>
      <category>OCR</category>
      <category>text recognition</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/22</guid>
      <comments>https://cvml.tistory.com/22#entry22comment</comments>
      <pubDate>Mon, 12 Apr 2021 14:54:50 +0900</pubDate>
    </item>
    <item>
      <title>[#04] AI Hub 한국어 글자체 AI 이미지 데이터 전처리</title>
      <link>https://cvml.tistory.com/21</link>
      <description>&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;OCR 모델을 이용하여 약국이나 편의점에서 살 수 있는 일반의약품의 상품명을 인식해보는 과정을 담아보는 글.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;지난 글에서는 정부에서 관리하는 AI Hub 사이트에서 한글 이미지 데이터셋을 구할 수 있었다. 하지만 태깅 데이터 정보가 담겨있는 json 파일은 262Mb의 크기로 대용량이기 때문에 우리가 원하는 정보만 추출해야하며 또 OCR 모델을 학습시키기 위해 전처리를 할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;데이터를 가공해 학습에 사용하자&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;데이터 분석&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;AI Hub에서 제공하는 Text in the Wild 데이터셋의 태깅데이터 textinthewild_data_info.json 파일은 크게 &lt;u&gt;info&lt;/u&gt;, &lt;u&gt;images&lt;/u&gt;, &lt;u&gt;annotations&lt;/u&gt;, &lt;u&gt;licenses&lt;/u&gt; 라는 key들로 이루어져있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1617153290971&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import json
file = json.load(open('./textinthewild_data_info.json'))
file.keys() #dict_keys(['info', 'images', 'annotations', 'licenses'])
file['info'] #{'name': 'Text in the wild Dataset', 'date_created': '2019-10-14 04:31:48'}
type(file['images']) #list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;images key에는 모든 이미지 정보가 담겨 있으며 annotations과 공유하고 있는 id와 파일 이름(file_name), 어떤 종류의 이미지인지(book, goods, signboard, traffic sign) 리스트 형태로 저장되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1617153383421&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;file['images'][:3]

'''
[{'id': '00000001',
  'width': 1920,
  'height': 1440,
  'file_name': 'FFF2F34A08347075F55E72B240EFE691.jpg',
  'type': 'book'},
 {'id': '00000002',
  'width': 1920,
  'height': 1440,
  'file_name': 'FFDE6BAEADC9EDD31E51A1D1F687310F.jpg',
  'type': 'book'},
 {'id': '00000003',
  'width': 1920,
  'height': 1440,
  'file_name': 'FFCFEB9E1D09544D6B458717DB4D6B7C.jpg',
  'type': 'book'}]
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;전체 태깅 데이터 중 내가 사용하고자 하는 상품(goods)이미지만 골라보았는데 개수가 26,358개라고 나왔다... 아니, 다운 받은 상품 이미지 폴더 안에 존재하는 파일의 개수는 37,200개였는데...?&lt;/p&gt;
&lt;p&gt;근데 이후에 데이터 가공을 더 하다보니까 태깅도 잘못 되어있는 부분들도 많고 해서 뭔가 태깅 누락이 발생한 것 같다는 생각이 들었다. 정부가 관리하는 데이터지만 깔끔하지 않다는거 ^^&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1617153666780&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;file['images'][0]['type'] == 'book' # True
goods = [f for f in file['images'] if f['type']=='product']
len(goods) #26358&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1617153705180&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;goods[0]

'''
{'id': '00001128',
 'width': 1920,
 'height': 1441,
 'file_name': 'EB862D328745738A1072A0E28F2E444E.jpg',
 'type': 'product'}
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;첫 번째로 저장된 상품의 태깅 정보를 가져와 보았다. 여기서 주의해야할 점... &lt;b&gt;images 값에 존재하는 id는 annotations 값에서 id가 아닌 image_id와 같은 정보다! 헷갈려 하면 안된다.&lt;/b&gt; 그리고 AI Hub 데이터는 친절(?)하게도 이미지에서 글자 단위와 단어 단위로 각각 태깅이 되어있다. 따라서 단어 단위의 태깅 데이터만 필요한 경우에는 annotations 값에서 &lt;u&gt;attributes['class'] == 'word'&lt;/u&gt;로 골라낼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1617154064548&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;annotation = [a for a in file['annotations'] if a['image_id'] == goods[0]['id'] and a['attributes']['class']=='word']
annotation

'''
[{'id': '00029855',
  'image_id': '00001128',
  'text': '페리덱스',
  'attributes': {'class': 'word'},
  'bbox': [455, 610, 1155, 323]},
 {'id': '00029856',
  'image_id': '00001128',
  'text': '혓바늘,',
  'attributes': {'class': 'word'},
  'bbox': [693, 983, 185, 74]},
 {'id': '00029858',
  'image_id': '00001128',
  'text': '입안이',
  'attributes': {'class': 'word'},
  'bbox': [1160, 967, 169, 77]},
 {'id': '00029859',
  'image_id': '00001128',
  'text': '헐었을',
  'attributes': {'class': 'word'},
  'bbox': [1343, 963, 173, 72]},
 {'id': '00029860',
  'image_id': '00001128',
  'text': '때',
  'attributes': {'class': 'word'},
  'bbox': [1537, 958, 53, 72]}]
'''&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 태깅 정보를 갖고 있는 이미지 사진을 출력해보면 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1617154165245&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import matplotlib.pyplot as plt
import cv2
img = cv2.imread('/data/ljh/dataset/ocr/Goods/'+goods[0]['file_name'])
plt.imshow(img)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled (11).png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;252&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boVwBZ/btq1nITtWGr/FfOJRhozwdwlF3OinNApQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boVwBZ/btq1nITtWGr/FfOJRhozwdwlF3OinNApQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boVwBZ/btq1nITtWGr/FfOJRhozwdwlF3OinNApQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboVwBZ%2Fbtq1nITtWGr%2FFfOJRhozwdwlF3OinNApQ0%2Fimg.png&quot; data-filename=&quot;Untitled (11).png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;252&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터 1차 가공 - AI Hub 데이터 분할&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;우선 태깅 데이터가 용량이 너무 크고 전체 데이터 정보를 담고 있으므로 상품 이미지에 대해서만 데이터를 추려보도록 하자. 학습에 사용하기 위해 상품 이미지를 train, validation, test set으로 70:15:15의 비율로 나눠서 임의의 순서로 이미지를 나누고 각 이미지에 해당하는 annotation 정보를 함께 저장하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1617154248556&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random
import os

ocr_good_files = os.listdir('/data/ocr/Goods/')
len(ocr_good_files) # 37220

random.shuffle(ocr_good_files)

n_train = int(len(ocr_good_files) * 0.7)
n_validation = int(len(ocr_good_files) * 0.15)
n_test = int(len(ocr_good_files) * 0.15)

print(n_train, n_validation, n_test) # 26054 5583 5583

train_files = ocr_good_files[:n_train]
validation_files = ocr_good_files[n_train: n_train+n_validation]
test_files = ocr_good_files[-n_test:]

## train/validation/test 이미지들에 해당하는 id 값을 저장

train_img_ids = {}
validation_img_ids = {}
test_img_ids = {}

for image in file['images']:
    if image['file_name'] in train_files:
        train_img_ids[image['file_name']] = image['id']
    elif image['file_name'] in validation_files:
        validation_img_ids[image['file_name']] = image['id']
    elif image['file_name'] in test_files:
        test_img_ids[image['file_name']] = image['id']

## train/validation/test 이미지들에 해당하는 annotation 들을 저장

train_annotations = {f:[] for f in train_img_ids.keys()}
validation_annotations = {f:[] for f in validation_img_ids.keys()}
test_annotations = {f:[] for f in test_img_ids.keys()}

train_ids_img = {train_img_ids[id_]:id_ for id_ in train_img_ids}
validation_ids_img = {validation_img_ids[id_]:id_ for id_ in validation_img_ids}
test_ids_img = {test_img_ids[id_]:id_ for id_ in test_img_ids}

for idx, annotation in enumerate(file['annotations']):
    if idx % 5000 == 0:
        print(idx,'/',len(file['annotations']),'processed')
    if annotation['attributes']['class'] != 'word':
        continue
    if annotation['image_id'] in train_ids_img:
        train_annotations[train_ids_img[annotation['image_id']]].append(annotation)
    elif annotation['image_id'] in validation_ids_img:
        validation_annotations[validation_ids_img[annotation['image_id']]].append(annotation)
    elif annotation['image_id'] in test_ids_img:
        test_annotations[test_ids_img[annotation['image_id']]].append(annotation)

with open('train_annotation.json', 'w') as file:
    json.dump(train_annotations, file)
with open('validation_annotation.json', 'w') as file:
    json.dump(validation_annotations, file)
with open('test_annotation.json', 'w') as file:
    json.dump(test_annotations, file)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 아래와 같이 train, validation, test에 쓰이는 상품 이미지들의 파일 이름과 annotation 정보가 담긴 json 파일이 민들어지게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled (12).png&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KVp3r/btq1s410EEd/JfYCAKxzEIdQ0kkFjoupnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KVp3r/btq1s410EEd/JfYCAKxzEIdQ0kkFjoupnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KVp3r/btq1s410EEd/JfYCAKxzEIdQ0kkFjoupnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKVp3r%2Fbtq1s410EEd%2FJfYCAKxzEIdQ0kkFjoupnK%2Fimg.png&quot; data-filename=&quot;Untitled (12).png&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;552&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터 2차 가공 - Preprocessing&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;이제 이 태깅 데이터를 맨 처음에 보았던 IC15 데이터셋과 같은 형태로 가공할 필요가 있다. 내가 사용할 Text Recognition 모델은 Naver Clova AI에서 발표한 모델로 &lt;a href=&quot;https://github.com/clovaai/deep-text-recognition-benchmark&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github&lt;/a&gt;에 학습 데이터 가이드라인이 친절하게 제시되어 있다. 또 &lt;a href=&quot;https://ropiens.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;블로그 글&lt;/a&gt;을 참고하여 데이터 가공을 진행하였다.&lt;/p&gt;
&lt;figure id=&quot;og_1617154376500&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;네이버 deep-text-recognition 모델을 custom data로 학습 &amp;amp; 아키텍쳐 분석&quot; data-og-description=&quot;작성자 : 한양대학원 융합시스템학과 석사과정 유승환 네이버 Clova AI팀에서 연구한 OCR 딥러닝 모델을 custom data로 학습하는 과정을 정리해보겠습니다~! * 2021년 3월 8일자 기준으로 내용 보완 중 &quot; data-og-host=&quot;ropiens.tistory.com&quot; data-og-source-url=&quot;https://ropiens.tistory.com/35&quot; data-og-url=&quot;https://ropiens.tistory.com/35&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bekuV0/hyJJPThK3M/QxqyAVKcuHGsKZ9qfhDfu0/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252,https://scrap.kakaocdn.net/dn/ceN0fZ/hyJH6vCsaQ/im0J1ewsstKLZK5GGkuAqK/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252,https://scrap.kakaocdn.net/dn/jzAwt/hyJIcCAOzQ/SqUvO3j0eSVwd49iJDSeH0/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252&quot;&gt;&lt;a href=&quot;https://ropiens.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ropiens.tistory.com/35&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bekuV0/hyJJPThK3M/QxqyAVKcuHGsKZ9qfhDfu0/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252,https://scrap.kakaocdn.net/dn/ceN0fZ/hyJH6vCsaQ/im0J1ewsstKLZK5GGkuAqK/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252,https://scrap.kakaocdn.net/dn/jzAwt/hyJIcCAOzQ/SqUvO3j0eSVwd49iJDSeH0/img.png?width=674&amp;amp;height=252&amp;amp;face=0_0_674_252');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;네이버 deep-text-recognition 모델을 custom data로 학습 &amp;amp; 아키텍쳐 분석&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;작성자 : 한양대학원 융합시스템학과 석사과정 유승환 네이버 Clova AI팀에서 연구한 OCR 딥러닝 모델을 custom data로 학습하는 과정을 정리해보겠습니다~! * 2021년 3월 8일자 기준으로 내용 보완 중&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ropiens.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;dataset_guideline.png&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;616&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y65I7/btq1nH78scq/nCKM9bjNd9kW9pA8fFbuL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y65I7/btq1nH78scq/nCKM9bjNd9kW9pA8fFbuL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y65I7/btq1nH78scq/nCKM9bjNd9kW9pA8fFbuL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy65I7%2Fbtq1nH78scq%2FnCKM9bjNd9kW9pA8fFbuL0%2Fimg.png&quot; data-filename=&quot;dataset_guideline.png&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;616&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위와 같은 방식으로 각 이미지에 해당하는 annotation 값을 이용해 'bbox'위치 정보로 단어 영역을 자르고 'text'정보와 함께 저장하였다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;여기서! 태깅된 정보들 중에 잘못된 값들이 상당히 존재했다. bounding box에서 좌상단 좌표를 의미하는 x,y와 너비 및 높이를 의미하는 w,h 값이 0이거나 음수인 경우가 있다는 것을 학습 중에 오류가 발생해 디버깅을 하다가 발견했다.&lt;/b&gt; 따라서 처음 데이터를 저장할 때 예외처리를 진행하여 걸러내는 것이 필요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1617154521044&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import json
import os
import cv2
import matplotlib.pyplot as plt
from tqdm import tqdm

## aihub 데이터 annotation을 읽어서 단어 단위로 잘라서 data에 저장하기

data_root_path = '/data/ljh/dataset/ocr/Goods/'
save_root_path = '/data/ljh/OCR/deep-text-recognition-benchmark/data/'

test_annotations = json.load(open('./test_annotation.json'))
gt_file = open(save_root_path+'gt_test.txt', 'w')
for file_name in tqdm(test_annotations):
    annotations = test_annotations[file_name]
    image = cv2.imread(data_root_path+file_name)
    for idx, annotation in enumerate(annotations):
        x,y,w,h = annotation['bbox']
        if x&amp;lt;= 0 or y&amp;lt;= 0 or w &amp;lt;= 0 or h &amp;lt;= 0:
            continue
        text = annotation['text']
        crop_img = image[y:y+h,x:x+w]
        crop_file_name = file_name[:-4]+'_{:03}.jpg'.format(idx+1)
        cv2.imwrite(save_root_path+'test/'+crop_file_name, crop_img)
        gt_file.write(&quot;test/{}\t{}\n&quot;.format(crop_file_name, text))

validation_annotations = json.load(open('./validation_annotation.json'))
gt_file = open(save_root_path+'gt_validation.txt', 'w')
for file_name in tqdm(validation_annotations):
    annotations = validation_annotations[file_name]
    image = cv2.imread(data_root_path+file_name)
    for idx, annotation in enumerate(annotations):
        x,y,w,h = annotation['bbox']
        if x&amp;lt;= 0 or y&amp;lt;= 0 or w &amp;lt;= 0 or h &amp;lt;= 0:
            continue        
        text = annotation['text']
        crop_img = image[y:y+h,x:x+w]
        crop_file_name = file_name[:-4]+'_{:03}.jpg'.format(idx+1)
        cv2.imwrite(save_root_path+'validation/'+crop_file_name, crop_img)
        gt_file.write(&quot;validation/{}\t{}\n&quot;.format(crop_file_name, text))
        
train_annotations = json.load(open('./train_annotation.json'))
gt_file = open(save_root_path+'gt_train.txt', 'w')
for file_name in tqdm(train_annotations):
    annotations = train_annotations[file_name]
    image = cv2.imread(data_root_path+file_name)
    for idx, annotation in enumerate(annotations):
        x,y,w,h = annotation['bbox']
        if x&amp;lt;= 0 or y&amp;lt;= 0 or w &amp;lt;= 0 or h &amp;lt;= 0:
            continue        
        text = annotation['text']
        crop_img = image[y:y+h,x:x+w]
        crop_file_name = file_name[:-4]+'_{:03}.jpg'.format(idx+1)
        cv2.imwrite(save_root_path+'train/'+crop_file_name, crop_img)
        gt_file.write(&quot;train/{}\t{}\n&quot;.format(crop_file_name, text))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다음 글에서 다룰 내용&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;이렇게 하고 나면 Text Recognition 모델을 학습시기키 위한 준비는 다 끝났다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 실제 학습을 진행하는 과정과 한글 학습을 위해 기존 모델 코드에서 변경된 점 그리고 학습 결과에 대한 내용을 다뤄보겠다.&lt;/p&gt;</description>
      <category>Deep Learning/OCR</category>
      <category>AI Hub</category>
      <category>OCR 데이터 전처리</category>
      <category>text recognition</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/21</guid>
      <comments>https://cvml.tistory.com/21#entry21comment</comments>
      <pubDate>Wed, 31 Mar 2021 10:48:00 +0900</pubDate>
    </item>
    <item>
      <title>[#03] 한글 데이터셋 수집하기</title>
      <link>https://cvml.tistory.com/20</link>
      <description>&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;OCR 모델을 이용하여 약국이나 편의점에서 살 수 있는 일반의약품의 상품명을 인식해보는 과정을 담아보는 글.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OCR 데이터셋은 어떻게 생겼을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;앞서 언급한 OCR 대회를 주최하는 ICDAR 학회에서 제공하는 데이터셋들을 둘러보자. 대회 Task별로 데이터셋의 형태는 다양하다. 내가 그중에서 찾고자 하는 것은 Text Recognition Task의 데이터셋이다. 2015년에 열린 ICDAR IC(Incidental Scene Text) 대회의 &lt;a href=&quot;https://rrc.cvc.uab.es/?ch=4&amp;amp;com=tasks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Task 4.3 Word Recognition&lt;/a&gt;을 한 번 보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;IC15 Dataset(Task 4.3)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled (8).png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;511&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0DRsF/btq1qOyBPRD/sHjxuEYK8hTWP5VCyGBOM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0DRsF/btq1qOyBPRD/sHjxuEYK8hTWP5VCyGBOM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0DRsF/btq1qOyBPRD/sHjxuEYK8hTWP5VCyGBOM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0DRsF%2Fbtq1qOyBPRD%2FsHjxuEYK8hTWP5VCyGBOM1%2Fimg.png&quot; data-filename=&quot;Untitled (8).png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;511&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;보통 Text Recognition의 데이터셋은 단어가 잘린(cropped)형태로 이미지 데이터와 이미지 파일 이름과 매칭 되는 단어 정답('gt.txt') 형태로 존재한다. 왜냐하면 Text Detection모델이 영상에서 검출된 단어들을 위와 같이 bounding box 형태로 알려준다. 따라서 저 형태 그대로 Text Recognition모델의 input으로 들어가 학습을 시키면 편리하기 때문이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;한글 데이터셋&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;ICDAR 학회는 국제 학회이며 많이 쓰는 영어를 기반으로 데이터셋을 만들기 때문에 나의 문제를 해결하기 위해서는 한글 데이터셋이 필요하다. 공개되어있는 Text Recognition 모델들의 github 저장소를 보게 되면 한국어를 학습한 모델이 없어 쉽게 가져다 쓸 수 없다. 이를 위해 공개적으로 제공하는 대량의 한글 이미지 데이터셋이 필요하며 마침 AI hub에서 이를 제공하고 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AI Hub&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;정부에서 주관하는 사이트로 인공지능 관련하여 경진대회나 연구과제 공고, 학습에 필요한 데이터셋 등을 공개하고 생각보다 유용한 자료들이 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.aihub.or.kr/aidata/133&quot; data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;&lt;span&gt;[한국어 글자체 AI 이미지 데이터] - Korean Font Image AI Training Dataset&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1617152549812&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;한국어 글자체 이미지 AI 데이터 | AI Hub&quot; data-og-description=&quot;데이터셋 구축 담당자&quot; data-og-host=&quot;www.aihub.or.kr&quot; data-og-source-url=&quot;https://www.aihub.or.kr/aidata/133&quot; data-og-url=&quot;https://www.aihub.or.kr/aidata/133&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EFStT/hyJJQEEZXY/L2Iku4f9JjqzPz2Zxrnlq1/img.png?width=1429&amp;amp;height=1125&amp;amp;face=0_0_1429_1125&quot;&gt;&lt;a href=&quot;https://www.aihub.or.kr/aidata/133&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aihub.or.kr/aidata/133&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EFStT/hyJJQEEZXY/L2Iku4f9JjqzPz2Zxrnlq1/img.png?width=1429&amp;amp;height=1125&amp;amp;face=0_0_1429_1125');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;한국어 글자체 이미지 AI 데이터 | AI Hub&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;데이터셋 구축 담당자&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.aihub.or.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled (9).png&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ihq0T/btq1ov7lxKP/Dq5Vkv8zSFkHFOYbjAqLYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ihq0T/btq1ov7lxKP/Dq5Vkv8zSFkHFOYbjAqLYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ihq0T/btq1ov7lxKP/Dq5Vkv8zSFkHFOYbjAqLYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIhq0T%2Fbtq1ov7lxKP%2FDq5Vkv8zSFkHFOYbjAqLYk%2Fimg.png&quot; data-filename=&quot;Untitled (9).png&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;642&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;AI Hub에서 제공하는 한글 이미지 데이터는 &lt;b&gt;손글씨&lt;/b&gt;, &lt;b&gt;인쇄체&lt;/b&gt;, &lt;b&gt;Text in the Wild&lt;/b&gt;(실제 생활 속 한글 이미지)로 세가지 종류가 있다. 다양한 종류의 한글 이미지를 제공하고 있기 때문에 사용하고자 하는 목적에 맞게 데이터를 선택할 수 있다. 나는 약 봉투 또는 일반 약 포장지 속 한글을 인식하고 싶기 때문에 인쇄체나 Text in the Wild 데이터가 필요하다. 그중에서 나는 일단 'Text in the Wild'데이터를 이용해 학습해보기로 했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Text in the Wild&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Untitled (10).png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;142&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch6hCn/btq1nIzaEIw/HrkA6rILUovHzTukBgJisK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch6hCn/btq1nIzaEIw/HrkA6rILUovHzTukBgJisK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch6hCn/btq1nIzaEIw/HrkA6rILUovHzTukBgJisK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch6hCn%2Fbtq1nIzaEIw%2FHrkA6rILUovHzTukBgJisK%2Fimg.png&quot; data-filename=&quot;Untitled (10).png&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;142&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Text in the Wild 데이터는 세부적으로 &lt;b&gt;책(Book), 상품(Goods), 간판(Signboard), 교통 표지판(Traffic Sign)&lt;/b&gt; 4 종류의 이미지로 10만장의 파일이 존재한다. 그중 책과 상품 이미지를 다운로드하여 봤는데 각각 16,333장과 37,200장으로 구성되어 있었다. 하나의 이미지 안에 태깅되어 있는 단어는 더 많을 테니까 일단 상품 이미지들로 학습하기로 하였다. 근데... 태깅 데이터인 '데이터 정보'는 네 종류의 이미지 데이터를 다 포함하는 하나의 json 파일이라 262MB의 크기를 갖고 있어 윈도우 환경에서 단순히 더블 클릭으로 열었다가는 멘붕의 상황이 올 것이다 &lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;다음 글에서 다룰 내용&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span&gt;다음 글에서는 다운받은 데이터를 코드상에서 확인해보고 학습을 위한 전처리 과정을 수행하는 부분에 대해 다룰 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Deep Learning/OCR</category>
      <category>AI Hub</category>
      <category>OCR</category>
      <category>한국어 글자체 이미지 AI 데이터</category>
      <category>한글 데이터셋</category>
      <author>족제비다아</author>
      <guid isPermaLink="true">https://cvml.tistory.com/20</guid>
      <comments>https://cvml.tistory.com/20#entry20comment</comments>
      <pubDate>Wed, 31 Mar 2021 10:17:14 +0900</pubDate>
    </item>
  </channel>
</rss>