<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>너드팩토리 블로그</title>
    <description>너드팩토리에서 운영하는 블로그 입니다.</description>
    <link>https://blog.nerdfactory.ai/</link>
    <atom:link href="https://blog.nerdfactory.ai/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 03 Apr 2024 01:39:22 +0000</pubDate>
    
      <item>
        <title>ICT인턴십 후기</title>
        <authors>
          
          
          <author>
            <name>김영신</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Poto.png</image>
          </author>
          
          
          
          <author>
            <name>나창원</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Noah.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2023-01-20-ict-intern-review/nerdfactory-moto.png</thumbnail>
        <description>&lt;p&gt;안녕하세요! 22년도 하반기 ICT 인턴십에 백엔드 엔지니어로 참여한 &lt;strong&gt;포토, 노아&lt;/strong&gt;입니다.
길다면 길고, 짧다면 짧은 4개월 동안의 인턴십이 끝났습니다!
무사히 끝낸 저희와 옆에서 적응할 수 있도록 도와준 팀원들에게.. 박수~~~! 👏
그동안 너드팩토리에서 ICT인턴십을 진행하면서 보고, 듣고, 경험했던 것들을 적어보고자 합니다 🎉&lt;/p&gt;

&lt;h2 id=&quot;참여-동기&quot;&gt;참여 동기&lt;/h2&gt;

&lt;h3 id=&quot;노아&quot;&gt;&lt;strong&gt;노아&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;저는 정보보안을 전공해 보안 전문가로서 꿈을 키우며 전공 공부를 즐겨 하고 있었습니다.&lt;/p&gt;

&lt;p&gt;그러나 정보보호병으로 복무하며 실무를 직간접 체험하고 나니 “보안을 계속하는 게 맞을까?” 하는 진로 고민이 들었습니다.&lt;/p&gt;

&lt;p&gt;특히 졸업을 앞둔 4학년 복학이었기에 효과적으로 진로를 탐색할 수 있는 경험을 하고자 했고,
마침 ICT인턴십이라는 학기를 병행하면서 실무를 수행할 수 있는 프로그램의 존재를 알게 되어 참여하게 됐습니다.&lt;/p&gt;

&lt;p&gt;불편을 해소할 수 있는 도구 만드는 것을 좋아했기 때문에 개발도 도전해보자! 라는 마인드로
세 개의 회사 선택지 중 하나는 개발을, 두 개는 보안을 지원했고 매우 빠른 속도로 너드팩토리 인턴이 되었습니다! (?)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;많은 개발 회사 중, 하나의 개발 회사로 플랜아이를 선택했던 이유&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;ICT 인턴십 프로그램을 초기부터 진행해온 회사로 축적된 인턴 시스템이 갖춰져 있을 것으로 기대되었습니다.&lt;/li&gt;
  &lt;li&gt;너드 블로그에 게시된 ICT인턴십 후기들을 보았을 때 너드의 문화가 긍정적으로 느꼈습니다.&lt;/li&gt;
  &lt;li&gt;플랜아이의 “정보를 쉽게 표현하고 명확하게 전달하는 것을 가장 잘 하는 회사” 문구가 와 닿았습니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;포토&quot;&gt;&lt;strong&gt;포토&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;‘인턴십을 해야겠다’라는 생각을 한 건 오직 졸업 학점을 채우기 위해서였습니다. 학교에서 기업과 직접 연계해주는 인턴십에 참여하려던 중 ICT인턴십을 알게 되었습니다.&lt;/p&gt;

&lt;p&gt;사실 본래 참여하려던 인턴십은 기업별로 선배들의 후기가 천차만별이었고, 실무와 가까이 경험해볼 수 있는 경우는 극히 드물어 보였습니다. 그에 반해 ICT인턴십은 학점을 부여받으면서 실무와 관련 있는 인턴십을 할 수 있었고, 다양한 지역에서 기회가 열려있었습니다. 더불어, 여러 기관이 연계되어있어서 인턴십 관련 관리가 잘되지 않을까? 하고 생각했고 위 점들이 맞물려 참여하게 되었습니다!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;대전이쥬 ~&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;대전에 연고도, 아무것도 없는 제가 여러 지역 중 대전 소재를 선택한 이유는 ,,
그냥 대전을 좋아해서입니다! 사실 노후에 오려고 했는데,, 시기가 너무 앞당겨졌네요 🫢&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;플랜아이를 선택한 이유&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;그러면 왜 플랜아이였나? 너드 팩토리였나? 라고 물어보신다면, 회사 선택에 있어 중요하게 생각한 몇 가지 중 하나는 회사 규모였습니다.
인턴 경험을 통해 회사는 어떻게 돌아가는지, 업무는 어떤 식으로 진행되는지, 타 부서와 협업은 어떻게 하는지 등 전반적인 회사 프로세스와 조직문화를 얻어가고자 했습니다.&lt;/p&gt;

&lt;p&gt;그리고 서비스하는 제품들을 보며, 핵심 가치와 미션을 잘 수행하고 있다는 느낌을 받았습니다. 제일 중요한 건! 회사가 지향하는 가치와 미션이 제 가치관과 부합한다고 생각되었습니다. 😀 oO(이건 운명…?)&lt;/p&gt;

&lt;p&gt;관리되고 있는 멋들어진 회사 홈페이지에서 좋은 이미지를 받았고, ICT인턴십 프로그램에 참여한 이력이 꽤 되었기에 인턴을 위한 프로세스가 있을 것으로 생각했습니다.&lt;/p&gt;

&lt;h2 id=&quot;무엇을-했을까요&quot;&gt;무엇을 했을까요?&lt;/h2&gt;

&lt;p&gt;첫날은 회사 전반적인 이야기를 들을 수 있던 &lt;strong&gt;온보딩 교육&lt;/strong&gt;을 받은 후, 개발환경 세팅을 하다 끝났습니다. 정말 새롭고 정신없었죠,,&lt;/p&gt;

&lt;p&gt;이후 이슈가 좀 있었지만, 과제형 코딩테스트를 받고 코드 리뷰 후 업무를 할당받았습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/aivoryq-logo.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/aivoryq-logo.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;저희가 맡았던 첫 업무는 실제 서비스되는 개인화 추천 서비스 &lt;strong&gt;‘AIVORY Q’&lt;/strong&gt; 버그 수정이었습니다.
추천 기본정보가 표시되지 않는 버그를 수정해야 하는 일로, 지금은 간단한 일이라는걸 알 수 있지만
당시엔 실서비스의 코드를 건드린다는 게 겁도 나고 어디서부터 해야 할지 몰라서 선뜻 손대지 못했던 기억이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AIVORY Q&lt;/strong&gt;는 &lt;strong&gt;Django, Elasticsearch, Docker, MySQL&lt;/strong&gt; 등의 기술 스택을 사용하고 있습니다.
위 도구들을 처음 사용하는 것이라 학습하는 데 어려움도 있었지만
팀원들의 독려와 이야기 나눌 수 있던 인턴 동기가 있어서 해낼 수 있었습니다.
그리고! 처음 이슈를 해결하고 개발 서버에 반영되는 걸 눈으로 확인한 날은.. 🌟  무지 뿌듯했습니다 🥹&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/issue.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/issue.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 경험을 시작으로 스프린트에 참여해 AIVORY Q의 여러 이슈를 처리했습니다.
저희가 처리했던 이슈는 다음과 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;누적 개인화 추천 수 리스트 값 표기 수정&lt;/li&gt;
  &lt;li&gt;종료된 추천 그래프 날짜 표기 문제 수정&lt;/li&gt;
  &lt;li&gt;세그먼트 별 데이터를 볼 수 있도록 수정&lt;/li&gt;
  &lt;li&gt;노출될 추천 상품 리스트 API 문서 작성&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 이슈들을 처리하면서 백엔드 챕터 내에서 &lt;strong&gt;Django 테스트 모듈&lt;/strong&gt;을 활용해 &lt;strong&gt;TDD&lt;/strong&gt;를 적용해보자는 의견이 나왔습니다.&lt;/p&gt;

&lt;p&gt;좋은 경험으로 생각됐기 때문에 TDD 방법론을 따라 &lt;strong&gt;단위 테스트&lt;/strong&gt;를 진행하며 이슈를 대응했습니다.
처음으로 테스트를 먼저 하고 구현하는 경험을 하게 되었는데, 허점이 생길 수 있는 부분을 사전에 방지할 수 있는 장점이 있었습니다.&lt;/p&gt;

&lt;p&gt;단점으로는 테스트 코드를 먼저 작성하고 실제 제품화를 위한 코드작성을 후에 하기 때문에 일반적인 경우보다 시간이 더 소요된다는 점이었습니다.
어떤 경우건 100% 정답은 없어서 작업에 따라 유연하게 적용시키면 될 것 같습니다.
저희는 위 작업들을 진행하면서 &lt;strong&gt;테스트의 중요성&lt;/strong&gt;을 느꼈습니다.&lt;/p&gt;

&lt;p&gt;치명적인 이슈는 개발자 스스로도 바로 인지가 가능하지만, 사소한 버그들은 바로 인지가 되지 않습니다.
너드에서는 팀원끼리 테스트 해주는 문화가 활발히 자리해있었고, 보다 나은 제품을 개발하고자 하고 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/voda-logo.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/voda-logo.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이후에는 웹 서비스 데이터 분석 솔루션 &lt;strong&gt;‘VODA’&lt;/strong&gt;를 &lt;strong&gt;분석&lt;/strong&gt;하고 &lt;strong&gt;문제점&lt;/strong&gt;과 &lt;strong&gt;해결방안을 도출&lt;/strong&gt;했습니다.
제품 분석이 처음이고, 초기엔 목표와 방향성을 잡지 못해서 어려움을 겪었습니다.
이를 해소하기 위해 소장님과 계속 미팅을 진행하면서 방향성을 잡았습니다.&lt;/p&gt;

&lt;p class=&quot;center center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/uml-blur-1.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/uml-blur-1.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/uml-blur-2.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/uml-blur-2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;제품 구성을 잘 파악했는지 확인하고 문서화하기 위해서 UML을 작성했습니다. 도식화된 자료를 바탕으로 설명해 보며 이해도를 점검할 수 있었고, 코드 분석을 진행할 때는 레포지토리 별로 분담 후 서로 분석한 것에 대해 질의응답 하며 크로스체크할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;VODA 분석은 이름만 익히 듣고 생소했던 &lt;strong&gt;AWS, NginX, 배치 스케줄러 설정, 크롤러&lt;/strong&gt; 등을 자세히 들여다볼 기회였습니다.
제품을 서비스하기 위해 구성된 AWS 서비스들의 역할과 연결고리들을 알 수 있었습니다. 이들을 고려하면서 문제점에 대한 해결방안을 도출해내야 했는데, 클라우드 비용 산정 기준과 효과적인 AWS 구축법을 몰라 꽤 헤매기도 했습니다. &lt;del&gt;(물론.. 지금도 어렵습니다)&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;분석을 진행하면서 제품 분석할 때는 어림짐작으로 넘어가는 것은 절대 금물이라는 것을 알게 되었습니다.
어떠한 데이터를 어디에서 수집해서 어떻게 쓰이고 하는 사소한 부분부터 큼직한 제품의 전반적인 흐름까지 파악해야 했습니다.
제품 분석이 잘 돼야 이후 코드 분석, 제품 개선을 위한 해결방안 도출까지 잘 도달할 수 있기 때문입니다.&lt;/p&gt;

&lt;p&gt;앞서 처리한 AIVORY Q의 이슈 처리는 &lt;strong&gt;코드 스킬을 향상&lt;/strong&gt;하고, &lt;strong&gt;인프라에 적응&lt;/strong&gt;할 수 있도록 하는 경험이었다면
VODA 분석은 코드 스킬 외의 &lt;strong&gt;기획에 대한 시각&lt;/strong&gt;을 넓혀주는 경험이었습니다.&lt;/p&gt;

&lt;p&gt;서로의 경험과 지식을 나누는 &lt;strong&gt;기술 세미나&lt;/strong&gt;도 참여했습니다.
너드 멤버 개개인의 분야에서 얻게 된 지식과 경험을 어떻게 하면 너드에 도움이 될 수 있을지 공유하는 시간이었습니다.
저희는 각자 학부생 때의 전공을 살려 보안에 관련한 주제를 선정, 발표했습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;노아&lt;/strong&gt; - 암호&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;포토&lt;/strong&gt; - Python 시큐어 코딩&lt;/p&gt;

&lt;p&gt;( 다른 너드들의 기술세미나 발표 주제는 이 기술블로그에 잘 포스팅되어있으니 한 번 둘러보시길 바랍니다! 😎 )&lt;/p&gt;

&lt;h2 id=&quot;배운-점--소감&quot;&gt;🔎 배운 점 &amp;amp; 소감&lt;/h2&gt;

&lt;p&gt;애자일을 지향하고 있는 너드에서 새로운 경험을 많이 할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;매일 아침 데일리 스크럼을 진행하며 진행 사항과 특이 이슈를 공유합니다.&lt;/p&gt;

&lt;p&gt;또, 애자일하게 일하기 위해서 다양한 도구를 활용하여 소통하고 협업하고 있습니다.&lt;/p&gt;

&lt;p&gt;슬랙, 노션, 지라, 깃헙 등 처음 들어보는 것부터 익히 들어본 제품까지 사용해 볼 수 있었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/nerdfactory-moto.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/nerdfactory-moto.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;노아-1&quot;&gt;&lt;strong&gt;노아&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;너드 문화의 전반을 잘 설명하는 문장을 추리자면 곳곳에 있는 너드팩토리 가훈이라고 생각합니다.&lt;/p&gt;

&lt;p&gt;애자일하게 일하기를 추구하는 너드팩토리에서는 일단 해보고,
안되면 이를 경험 삼아 더 나은 방법을 선택할 수 있도록 독려합니다.
원래는 실패를 두려워하는 사람 중 한 사람이었으나, 실패는 값진 경험이라고 생각하고 두려워하지 않게 됐습니다.&lt;/p&gt;

&lt;p&gt;또한 코드를 작성하는 것이 기승전결을 고려하는 하나의 글을 쓰는 것과 비슷하다고 느꼈고,
이 과정에서 모델링의 중요성을 깨닫는 계기가 됐습니다.&lt;/p&gt;

&lt;p&gt;학부에서 많은 공부를 하지만 결국 실무에 적용해봐야 적성에 맞는지 알 수 있다는 걸 경험한 시간이었습니다.
개발자로서의 진로 고민이 든다면 기회가 가득한 팀, 너드팩토리에서 경험해보시는 걸 추천해 드립니다 ^-^b&lt;/p&gt;

&lt;h3 id=&quot;포토-1&quot;&gt;&lt;strong&gt;포토&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;실서비스의 코드 이슈를 처음 처리하게 되었을 때는 ‘내가 해도 되나?’ 덜컥 겁이 났었는데, 이러다 보니 꽤 시간이 소요됐습니다.
지금은 일단 시도해보자! 라는 태도로 극복 중입니다. 아무것도 하지 않으면 아무 일도 일어나지 않으니까요. (그런데 데이터를 몽땅 날리지 않는 이상 큰일은 안 났을 것 같네요.🧐)&lt;/p&gt;

&lt;p&gt;물론 회사와 부서마다 다르겠지만, 실무에서 일하는 방식과 분위기도 알 수 있었습니다.&lt;/p&gt;

&lt;p&gt;저는 평소 한 사안에 대해서 넘겨짚거나 대충 이렇겠지~ 하기도 하고, 좋은 게 좋은 거지라는 태도를 가지고 있는데 이게 개발 관점에서는 독이 되는 태도인 것을 알게 되었습니다.
프로그래밍할 때는 데이터 기반으로 생각하고 정확하게, 특히 정책은 명확하게 해야 한다는 것을 깨닫게 되었습니다.&lt;/p&gt;

&lt;p&gt;수많은 인턴 후기에 보이는 멘트인 ‘학교에서 배운 것이 이렇게 쓰이는구나’를 생각하게 되다니! 굉장히 뻔한 말 같지만 직접 와서 보고 듣고 경험하니까 크게 와닿았습니다. 또, 그 많은 인턴 후기를 보고 너드팩토리에 와서 느낀 점은 인턴에게도 신입에게도 제한 없는 기회가 열려있다는 거였습니다.
사실 처음 오게 되었을 때는 ‘내가 할 수 있을까?’ 지레 겁을 먹었는데, 상황에 던져지니까 뭐라도 하게 되긴 하더라고요!&lt;/p&gt;

&lt;p&gt;소장님께서 저희한테 첫 회사 생활을 너무 좋은 데로 와서 이후 다른 곳으로 갔을 때가 걱정이라고 말씀해주셨는데,, 너무 공감되는 말씀이었습니다. 어쩔 수 없죠.. 저와 플랜아이가 서로를 책임져야겠어요.&lt;/p&gt;

&lt;h2 id=&quot;여담&quot;&gt;⭐여담⭐&lt;/h2&gt;

&lt;h3 id=&quot;노아-2&quot;&gt;&lt;strong&gt;노아&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;출퇴근이 멀다는 건 정말 힘듭니다. 타지역에서 오신다면 꼭 가까운 곳으로 자취하세요. 추가로 공부할 체력이 남지 않아요..&lt;/p&gt;

&lt;p&gt;아…. 이건 오면 이해하실 텐데 추후 제 자리에서 “뒷집”을 속삭이시면…. 놀라운 일이 벌어집니다.&lt;/p&gt;

&lt;h3 id=&quot;포토-2&quot;&gt;&lt;strong&gt;포토&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;인턴 생활 중 지내던 곳이 너무 멀었어요….. 게다가 퇴근길이 극악!
전 환승을 해야 했는데 버스 20분 거리가 퇴근길엔 4~50분이 되는 마법이 펼쳐져요.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/sunset.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/sunset.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;참고로 제 출근길 버스 밖 풍경은 … 아시겠죠?
출발한 지 20여 분 지난 뒤랍니다.. 사진은 잘 나왔네요..&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2023-01-20-ict-intern-review/chair.png&quot; alt=&quot;/assets/images/posts/2023-01-20-ict-intern-review/chair.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그리고!! 중요한 팁이 하나 있어요
뻐근한 날엔 안마의자와 둘만의 오붓한 시간을 보낼 수 있답니다. 사실 뻐근하지 않아도..
회사가 허락한…. 안마의자와 데이트&lt;/p&gt;
</description>
        <pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2023/01/20/ict-intern-review.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2023/01/20/ict-intern-review.html</guid>
        <tags>
          
          <tag>ICT 인턴십</tag>
          
          <tag>인턴</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>우리 서비스에 데이터를 어떻게 보여줄까?</title>
        <authors>
          
          
          <author>
            <name>이지원</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ljw-1.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/아트보드–1.png</thumbnail>
        <description>&lt;h3 id=&quot;성적이-더-좋은-학생이-누구일까요&quot;&gt;&lt;strong&gt;성적이 더 좋은 학생이 누구일까요?&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;평균 점수만 놓고 본다면 유지하는 학생이 더 좋지만 성장하는 모습을 보이는 학생도 나쁘다고는 볼 수가 없습니다.&lt;/p&gt;

&lt;p&gt;이것처럼 데이터를 볼 때에는 해당 지표의 숫자 뿐아니라 데이터의 추이,&lt;/p&gt;

&lt;p&gt;즉 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;시각화를 통한 흐름을 보는 것&lt;/code&gt;이 중요합니다.&lt;/p&gt;

&lt;p&gt;해서 데이터 시각화에 대해 간단히 보고 우리 서비스에 어떻게 적용했는지를 공유해보려고 합니다.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;데이터-시각화란&quot;&gt;데이터 시각화란?&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;수많은 데이터 속에서 &lt;strong&gt;유의미한 정보를&lt;/strong&gt; 찾고, &lt;strong&gt;시각화&lt;/strong&gt; 하는 것&lt;/li&gt;
  &lt;li&gt;데이터를 &lt;strong&gt;한 눈에 파악하기&lt;/strong&gt; 좋게 만드는것&lt;/li&gt;
  &lt;li&gt;데이터의 패턴, 비교 등을 파악하고, 시각화를 통한 인사이트를 얻을 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;데이터-시각화에서-중요한-것&quot;&gt;데이터 시각화에서 중요한 것&lt;/h2&gt;

&lt;h2 id=&quot;데이터&quot;&gt;데이터&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;당연하게도 데이터를 보여주려면 데이터가 필요&lt;/li&gt;
  &lt;li&gt;더 나아가 &lt;strong&gt;풍부하고 유용한 데이터&lt;/strong&gt;가 필요하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;독자&quot;&gt;독자&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;흥미와 필요 정도를 고려해서 &lt;strong&gt;독자의 범위를 선정&lt;/strong&gt;해야 한다.&lt;/li&gt;
  &lt;li&gt;독자가 &lt;strong&gt;어떤 정보를 원하는지 요구 사항(+느낀부분들)을 파악&lt;/strong&gt;해야 한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;➡️ 최근 진행했던 내부, 외부 &lt;strong&gt;QA&lt;/strong&gt;가 첫 걸음으로 보임&lt;/p&gt;

&lt;h2 id=&quot;구성&quot;&gt;구성&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;내용 구성은 데이터에서 출발하는 것과, 분석에서 출발하는 것으로 나뉜다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;데이터에서 출발&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;데이터에 대한 복잡한 분석 과정이나, 의미 해석 없이 
&lt;strong&gt;데이터에서 바로 측정 가능한 수치 값을 이용&lt;/strong&gt;해서 시각화 하는 방식&lt;/li&gt;
      &lt;li&gt;데이터 그 자체를 내용으로 구성하게 된다.&lt;/li&gt;
      &lt;li&gt;주로 수치정보를 필요로 하는 대시보드, 모니터링 시스템에서 사용한다.&lt;/li&gt;
      &lt;li&gt;예 : 클릭률, 모바일 또는 pc 사용률 등&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;분석에서 출발&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;데이터에서 보이는 양상&lt;/strong&gt;으로 소결을 만들며, 
&lt;strong&gt;데이터 분석과 증명을 반복하고 의미있는 결론을 도출&lt;/strong&gt;해서 시각화 하는 방식&lt;/li&gt;
      &lt;li&gt;분석으로 도출된 결론과, 그 일련의 과정을 내용으로 구성하게 된다.&lt;/li&gt;
      &lt;li&gt;분석 과정과 결론을 시각화 하기 때문에, 주로 스토리 텔링 방식으로 진행된다.&lt;/li&gt;
      &lt;li&gt;예 : 보다의 미래 예측과 관련된 지표, AB 테스트에서 나온 지표, 추천 효율 지표 등&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;➡️ 단순한 데이터 및 시각화 제공보다는 이를 통해 활용할 수 있는 지표를 제공하는게 더 유의미하다고 생각됨&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;-좋은-데이터-시각화라고-한다면&quot;&gt;+ 좋은 데이터 시각화라고 한다면?&lt;/h2&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;👍&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;심미성과&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;명료함을&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;두루&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;갖춘&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;명료하고&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;보기&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;좋은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;시각화가&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;좋은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;데이터&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;시각화다&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;심미성과 명료성 중 우선 순위를 따져야 한다면 &lt;strong&gt;명료성을 우선&lt;/strong&gt;하자.&lt;/li&gt;
  &lt;li&gt;주제에 따른 필요한 정보만을 보여주도록 하자.&lt;/li&gt;
  &lt;li&gt;인지를 해치지 않는 적절한 시각적 구성을 가지도록 하자.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;시각화에-활용되는-컬러&quot;&gt;시각화에 활용되는 컬러&lt;/h1&gt;

&lt;p&gt;색을 활용하여 데이터를 구분하거나 값을 표현하고 특정 부분을 강조하기도 합니다.&lt;/p&gt;

&lt;h3 id=&quot;1-정성적-색상-스케일qualitative-color-scale&quot;&gt;1. 정성적 색상 스케일(qualitative color scale)&lt;/h3&gt;

&lt;p&gt;질적 팔레트로 불리기도하고 순서나 우선순위 없이 튀는 색상 없이 서로 동등하게 치부되는 색상(범주에 활용)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/아트보드–1.png&quot; alt=&quot;아트보드 – 1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;→ 고객군 비율에 활용하여 현재 쇼핑몰에 분포된 고객 비율을 확인하기&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-순차적-색상-스케일-sequential-color-scale&quot;&gt;2. 순차적 색상 스케일 (sequential color scale)&lt;/h3&gt;

&lt;p&gt;색에 순서를 부여해서 값의 크기차이 특정한 두 값의 사이 거리를 보여줌(낮은값 → 높은값)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/아트보드–2.png&quot; alt=&quot;아트보드 – 2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;➡️ 히트맵에 활용할 수 있지만 데이터 차이가 크지 않을 경우 눈에 읽히지 않을수 있을 것 같음&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-발산형-색상-스케일-diverging-color-scale&quot;&gt;3. 발산형 색상 스케일 (diverging color scale)&lt;/h3&gt;

&lt;p&gt;두개 공통의 중간점을 연결한 것으로 데이터 범위의 양쪽 끝에서 중간 범위 임계값과 극단값을 동일하게 강조&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/아트보드–3.png&quot; alt=&quot;아트보드 – 3.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;➡️ 2번 형태의 색상보다는 발산형을 활용하면 보다 데이터 차이를 한눈에 볼 수 있을 것으로 판단됨
추후 VODA 사용자 시간대별 그래프에 활용하기&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;그래서-서비스에는-어떻게-적용하면-좋을까&quot;&gt;그래서 서비스에는 어떻게 적용하면 좋을까?&lt;/h1&gt;

&lt;p&gt;초기 보리큐 디자인&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/AIVORY_Q_Dashboard–1.png&quot; alt=&quot;AIVORY_Q_Dashboard – 1.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;대시보드라고 하기엔 다소 단조로운 형태&lt;/li&gt;
  &lt;li&gt;개인화 추천 리스트를 통해 볼 수 있는 데이터가 한정되어있음&lt;/li&gt;
  &lt;li&gt;클릭률과 구매율은 이어지는 지표지만 나뉘어있어서 한눈에 지표의 추이가 보이지 않음&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/master-225.png&quot; alt=&quot;마스크 그룹 225.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;추천 분석을 클릭 했을 때 우측 그래프가 바뀐다고 상상이 잘 안됨&lt;/li&gt;
  &lt;li&gt;카드 외부에 차트가 있기 때문에 연결된 지표라고 보이지 않음&lt;/li&gt;
  &lt;li&gt;추천 이름, 기본정보, 추천 분석의 디자인이 통일되지 않은 형태&lt;/li&gt;
  &lt;li&gt;전체적인 색감이 흐릿하여 명확하지 않음 → 자신감이 없어보임&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h1 id=&quot;qa를-통해-얻은-제안들&quot;&gt;QA를 통해 얻은 제안들&lt;/h1&gt;

&lt;h3 id=&quot;디자인-관련&quot;&gt;디자인 관련&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/design.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;제안하고-싶은-형태&quot;&gt;제안하고 싶은 형태&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/AIVORY_Q_Dashboard–4.png&quot; alt=&quot;AIVORY_Q_Dashboard – 4.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;추천과 고객군을 나누어서 지표를 확인하자&lt;/li&gt;
  &lt;li&gt;클릭률과 구매율처럼 연결되어 볼 수 있는 지표는 하나의 차트로 확인하자&lt;/li&gt;
  &lt;li&gt;중요한건 이목을 끌 수 있는 대시보드가 필요하다 → 생동감있는 화면&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;👉&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;고객군&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;별&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;추천&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이용률의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;막대&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;차트&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;활용&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이유&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;여러&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;항목의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;수량을&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;비교하는데&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;효과적이며&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;집단간의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;데이터&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;차이&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;최고&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;최저&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;표현하기에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;적합함&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;👉&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;고객군&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;별&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;비율의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;도넛&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;차트&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;활용&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이유&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;각&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;부분이&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;차지하는&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;비율을&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;보여주기에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;적합함&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;색상은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;컬러브루어&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Set2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;발산형태를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;적용&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;그래프지만&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;눈에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;띄지&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;않고&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;자연스러운&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;색상&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;👉&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;추천&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;지표의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;꺾은선&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;차트&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;활용&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이유&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;시간에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;따른&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;데이터의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;변화를&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;막대그래프보다&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;확인하기에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;적합함&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h3 id=&quot;개인화-추천-관리&quot;&gt;개인화 추천 관리&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-how-show-the-data-to-our-service/AIVORY_Q_Recommened–4.png&quot; alt=&quot;AIVORY_Q_Recommened – 4.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;드롭다운 형태보다 모달로 안정감있게 보는게 더 중요하다고 판단&lt;/li&gt;
  &lt;li&gt;마찬가지로 생동감을 함께 넣어주자 → 아이콘 및 색상 변경 부분&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;👉&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;필요한&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;정보만&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;보여주자&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;데이터가&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;없는&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;경우는&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;제외하고&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;있는&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;부분부터&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;매끄럽게&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;보일&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;수있도록&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;하자&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;→&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;꺾은선&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;그래프&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;해당&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;추천이&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;각&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;날짜별&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;어떤&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;형태의&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;추이&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;파악에&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;막대그래프보다&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;효과적임&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;클릭률&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;구매율과&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;추천&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이용률은&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;따로&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;나누어서&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;보여줄&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;필요가&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;있을것&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;같음&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;아직&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;고민중&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;개인화-추천-분석새로운-부분&quot;&gt;개인화 추천 분석(새로운 부분)&lt;/h3&gt;

&lt;p&gt;개인화 추천을 보여주는 것도 중요하지만 어떤 고객군이 어떤 페이지에서 어떤 추천 알고리즘에 대한 활용도를 판단하는 것도 중요하다&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;필터를 통해 리스트를 정렬해서 보기 : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;고객군별&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;적용 페이지별&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;추천 알고리즘별&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;VODA의 월간 리포트처럼 추천 지표의 결과와 예측을 전달해줄 수 있으면 좋겠다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;아쉬운-부분&quot;&gt;아쉬운 부분&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;보리큐 제품 명과 BI가 확정된 상태가 아닌 것&lt;/li&gt;
  &lt;li&gt;알파버전 디자인시 선택한 컬러의 대비감이 다소 떨어진다는 점
화면 명암 계산할 경우 색감이 어두워져 전체적인 분위기가 다운되는 문제 발생&lt;/li&gt;
  &lt;li&gt;새로운 BI를 제작하고 해당 컬러를 통해 차트에 활용할 수 있는 색상을 뽑아 사용하고 싶다.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 04 Oct 2022 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2022/10/04/how-show-the-data-to-our-service.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2022/10/04/how-show-the-data-to-our-service.html</guid>
        <tags>
          
          <tag>AdobeXd</tag>
          
          <tag>Design</tag>
          
          <tag>Data-visualize</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>TDD 적용하기 (Python Django)</title>
        <authors>
          
          
          <author>
            <name>김기강</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/alton.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled.png</thumbnail>
        <description>&lt;h1 id=&quot;1-개요&quot;&gt;1. 개요&lt;/h1&gt;

&lt;p&gt;‘TDD(Test-Driven-Development) 개발을 적용하자’라는 의견이 제시됐고 팀에서는 동의했다.&lt;/p&gt;

&lt;p&gt;하지만, 테스트 코드를 통해 테스트를 진행해본 경험도 적고 TDD가 무엇인지도 리서치가 필요했다.&lt;/p&gt;

&lt;p&gt;길을 잃고 또 다시 TDD 적용이 무산되는 것을 지켜만 볼 수 없었기에&lt;/p&gt;

&lt;p&gt;직접 적용해보고 공유하기 위해 이 글을 작성했다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled.png&quot; alt=&quot;tdd&quot; /&gt;
&lt;em&gt;출처: &lt;a href=&quot;https://wooaoe.tistory.com/33&quot;&gt;https://wooaoe.tistory.com/33&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;2-사전준비&quot;&gt;2. 사전준비&lt;/h1&gt;

&lt;p&gt;추천 이름 변경 API 개발이 필요한 상황이다.&lt;/p&gt;

&lt;p&gt;우선 API에 필요한 기능을 나열해보자.&lt;/p&gt;

&lt;p&gt;어떤 테스트 코드를 작성해야하는지 감 잡는데 도움이 된다.&lt;/p&gt;

&lt;p&gt;지도 없이 보물을 찾는건 쉽지 않은 일이다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;API를 호출할 수 있는 url이 있다.&lt;/li&gt;
  &lt;li&gt;header로 테넌트 값을 받는다.
    &lt;ul&gt;
      &lt;li&gt;해당 테넌트가 있는지 확인한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;필수 argument인 ak(API 키)와 name(바꿀 이름)을 받는다.&lt;/li&gt;
  &lt;li&gt;동일한 이름으로 존재하는 추천이 있는지 확인한다.&lt;/li&gt;
  &lt;li&gt;ak를 기반으로 추천 정보를 가져온다.&lt;/li&gt;
  &lt;li&gt;이름을 수정한 뒤, 저장한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;3-개발&quot;&gt;3. 개발&lt;/h1&gt;

&lt;p&gt;TestCase와 APITestCase로 나뉘어 작성되어 있다.&lt;/p&gt;

&lt;p&gt;함수인지, API 호출과 관련된 기능인지에 따라 구분지었다.&lt;/p&gt;

&lt;h2 id=&quot;apitestcase&quot;&gt;APITestCase&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;API를 호출할 수 있는 url이 있다.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;API 호출을 테스트하기 때문에 APITestCase를 사용했다.&lt;/li&gt;
      &lt;li&gt;모든 기능을 다 만든 뒤, 통합 테스트 단계에서 이 class를 수정할 예정이다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(1).png&quot; alt=&quot;testCode&quot; /&gt;
&lt;em&gt;API가 존재하지 않는 상태에서 실패하는 테스트 코드 작성&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(2).png&quot; alt=&quot;fail&quot; /&gt;
&lt;em&gt;결과는 당연히 실패&lt;/em&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-실제-코드-구현&quot;&gt;2. 실제 코드 구현&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(3).png&quot; alt=&quot;testcode2&quot; /&gt;
&lt;em&gt;테스트 코드를 통과하는 코드 구현&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(4).png&quot; alt=&quot;success&quot; /&gt;
&lt;em&gt;성공!&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;refactor 할 거리가 없는 매우 단순한 코드이기에 다시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;red&lt;/code&gt;로 돌아간다.&lt;/p&gt;

    &lt;p&gt;이렇게 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;실패 테스트 코드 작성, 성공 실제 코드 구현, 리팩토링&lt;/code&gt;을 반복하면 된다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;header로 Tenant 값을 받는다.&lt;/p&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성-1&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(5).png&quot; alt=&quot;seantestcode&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;선 테스트 코드&lt;/em&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-실제-코드-구현-1&quot;&gt;2. 실제 코드 구현&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(6).png&quot; alt=&quot;realcode&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;후 구현&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;필수 argument를 받는다.&lt;/p&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성-2&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;ul&gt;
      &lt;li&gt;이전 작업으로 인해 header 값도 있어야한다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(7).png&quot; alt=&quot;header&quot; /&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-실제-코드-구현-2&quot;&gt;2. 실제 코드 구현&lt;/h3&gt;

    &lt;ul&gt;
      &lt;li&gt;중복이 있지만, 우선 만든다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(8).png&quot; alt=&quot;untitle&quot; /&gt;&lt;/p&gt;

    &lt;h3 id=&quot;3-yellow&quot;&gt;3. Yellow&lt;/h3&gt;

    &lt;ul&gt;
      &lt;li&gt;argument 검사로 인해 이전 테스트 코드가 실패하게 된다.
        &lt;ul&gt;
          &lt;li&gt;동일한 내용이 포함된 테스트가 있기 때문에 없애준다.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;중복된 코드 및 코드 구조를 리팩토링한다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(9).png&quot; alt=&quot;header 검사 코드에는 argument 확인 로직이 없어 실패한다.&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;header 검사 코드에는 argument 확인 로직이 없어 실패한다.&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(10).png&quot; alt=&quot;중복을 없애고, 유효성 검사 로직을 추가했다.&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;중복을 없애고, 유효성 검사 로직을 추가했다.&lt;/em&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(11).png&quot; alt=&quot;성공&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;성공&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;testcase&quot;&gt;TestCase&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;동일한 이름으로 존재하는 추천이 있는지 확인한다.&lt;/p&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성-3&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(12).png&quot; alt=&quot;이미 있는 이름 → True, 없는 이름 → False&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;이미 있는 이름 → True, 없는 이름 → False&lt;/em&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-실제-코드-구현-3&quot;&gt;2. 실제 코드 구현&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(13).png&quot; alt=&quot;objects.get()은 값이 없으면 에러가 발생한다.&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;objects.get()은 값이 없으면 에러가 발생한다.&lt;/em&gt;&lt;/p&gt;

    &lt;h3 id=&quot;3-리팩토링&quot;&gt;3. 리팩토링&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(14).png&quot; alt=&quot;스크린샷 2022-09-16 오후 5.50.18.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;해당 Tenant가 존재하는지 확인한다.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;tenant_check() 함수는 기작성된 함수이므로, 테스트 코드만 작성해준다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(15).png&quot; alt=&quot;스크린샷 2022-09-16 오후 6.07.26.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ak를 기반으로 추천 정보를 가져온다.&lt;/p&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성-4&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(16).png&quot; alt=&quot;스크린샷 2022-09-19 오후 2.11.23.png&quot; /&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-구현&quot;&gt;2. 구현&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(17).png&quot; alt=&quot;스크린샷 2022-09-19 오후 2.11.37.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(18).png&quot; alt=&quot;테스트 통과&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;테스트 통과&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;이름을 수정한 뒤, 저장한다.&lt;/p&gt;

    &lt;h3 id=&quot;1-테스트-코드-작성-5&quot;&gt;1. 테스트 코드 작성&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(19).png&quot; alt=&quot;스크린샷 2022-09-19 오후 3.05.57.png&quot; /&gt;&lt;/p&gt;

    &lt;h3 id=&quot;2-구현-1&quot;&gt;2. 구현&lt;/h3&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(20).png&quot; alt=&quot;스크린샷 2022-09-19 오후 2.43.56.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(21).png&quot; alt=&quot;잘 된다.&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;잘 된다.&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이후 API를 테스트하는 코드를 작성하고&lt;/p&gt;

&lt;p&gt;기작성된 코드를 리팩토링해, 하나의 API로 구성해서 API 통합 테스트를 진행한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(22).png&quot; alt=&quot;API 호출과 결과 확인&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;API 호출과 결과 확인&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-10-04-apply-tdd-with-python-django/Untitled(23).png&quot; alt=&quot;성공&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;성공&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;4-회고&quot;&gt;4. 회고&lt;/h1&gt;

&lt;h3 id=&quot;테스트-코드&quot;&gt;테스트 코드&lt;/h3&gt;

&lt;p&gt;TDD로 개발하는 것과 더불어 테스트 코드를 작성해서 테스트를 진행하는 것도 처음 해봤다.&lt;/p&gt;

&lt;p&gt;개발중에 데이터 생성, 수정 등 확인하는데 귀찮거나 시간이 오래 걸리는 부분을 편하게 테스트 할 수 있었다.&lt;/p&gt;

&lt;h3 id=&quot;적용-시기&quot;&gt;적용 시기&lt;/h3&gt;

&lt;p&gt;TDD는 개발 초기나 아키텍처를 뒤엎는 경우에 적용하는게 좋아보인다.&lt;/p&gt;

&lt;p&gt;테스트 코드가 없는 기작성 코드에 대해 TDD를 적용하는건 불편할 것 같다.&lt;/p&gt;

&lt;h3 id=&quot;작업-시간&quot;&gt;작업 시간&lt;/h3&gt;

&lt;p&gt;아직 익숙하지 않은 사이클로 개발을 했기 때문에 바로 코드를 구현하는 것보다 완성되는 시간은 늦었다.&lt;/p&gt;

&lt;p&gt;하지만, 테스트 코드를 통해 리팩토링도 동시에 진행하면서,&lt;/p&gt;

&lt;p&gt;추후 발생하는 이슈나 해당 코드를 이해하는데 걸리는 시간을 줄여줄 수 있다는 이점 덕분에 충분히 적용할 가치가 있다.&lt;/p&gt;

&lt;p&gt;만약 TDD에 익숙해진다면, 전체적인 시간으로 봤을 때 많은 이점이 있을 것 같고,&lt;/p&gt;

&lt;p&gt;팀에서 발생하는 휴먼 이슈와 불화 또한 줄일 수 있을 것 같다.&lt;/p&gt;

&lt;h3 id=&quot;정답을-알려줘&quot;&gt;정답을 알려줘&lt;/h3&gt;

&lt;p&gt;TDD는 개발 방법론인 것이니 ‘무조건 이렇게 해야한다’는 정답은 없고 생각한다.&lt;/p&gt;

&lt;p&gt;우리식으로 하는게 우리의 개발 문화다.&lt;/p&gt;

&lt;p&gt;이상 개발 문화에 TDD를 적용하기 위한 첫 발걸음을 내딛었다.&lt;/p&gt;

&lt;p&gt;나만 열심히 해서 이뤄지는게 아니고 모든 팀원이 노력해야 비로소 완성된다고 생각한다.&lt;/p&gt;

&lt;p&gt;(1인 개발자인 조직이라면 가능할지도..)&lt;/p&gt;
</description>
        <pubDate>Tue, 20 Sep 2022 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2022/09/20/apply-tdd-with-python-django.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2022/09/20/apply-tdd-with-python-django.html</guid>
        <tags>
          
          <tag>TDD</tag>
          
          <tag>Django</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>자연어처리 모델을 활용한 개인화 추천시스템</title>
        <authors>
          
          
          <author>
            <name>이유나</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Ella.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/untitle.png</thumbnail>
        <description>&lt;h2 id=&quot;여는-글&quot;&gt;여는 글&lt;/h2&gt;

&lt;p&gt;오늘은 주로 자연어 처리 분야에서 사용하는 기법을 개인화 추천 분야에 어떻게 적용하는지에 대해 알아보겠습니다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/untitle.png&quot; alt=&quot;title&quot; /&gt;
&lt;em&gt;출처 - 카카오 기술블로그&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;1-개인화-추천-기술란&quot;&gt;1. 개인화 추천 기술란?&lt;/h1&gt;

&lt;p&gt;먼저 예시를 들어보겠습니다.
아래는 인터넷 쇼핑몰에서 Best 추천 상품을 받아보는 화면입니다.&lt;/p&gt;

&lt;p&gt;가장 앞단에 추천되고 있는 김치에 대해 평균적으로 기대할 수 있는 구매율을 N%라고 계산했을 때, 이는 &lt;strong&gt;모든 사람에게 동일하게 기대할 수 있는 값은 아닙니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/category.png&quot; alt=&quot;category&quot; /&gt;
&lt;em&gt;출처 - 아자몰&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;예를들어, 사용자1은 평소에 김치 소비를 많이하는 편이고, 매번 김치를 사먹기때문에 이 상품을 보자마자 클릭 할 가능성이 높은 편입니다.
반면 사용자2는 김치 소비가 적은 편이고, 집에서 직접 김장을 하기때문에 이 상품을 보더라도 구매(심지어는 클릭조차)하지 않을 수도 있습니다.&lt;/p&gt;

&lt;p&gt;이처럼 각 개인별 각 상품에 대한 기대 구매율을 계산하고 기대 구매율이 가장 높은 상품들을 &lt;strong&gt;맞춤형으로 제시해 주는 것&lt;/strong&gt;이 &lt;strong&gt;개인화 추천 기술&lt;/strong&gt;이라고 합니다.&lt;/p&gt;

&lt;p&gt;다양한 개인화 추천 방법론이 있지만 그 중에서 자연어처리에서 주로 사용되던 기법인 &lt;strong&gt;토픽 모델링&lt;/strong&gt;을 개인화 추천 시스템에서 어떻게 적용하는지 알아보겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-토픽-모델링이란&quot;&gt;2. &lt;strong&gt;토픽 모델링이란?&lt;/strong&gt;&lt;/h1&gt;

&lt;h3 id=&quot;배경&quot;&gt;배경&lt;/h3&gt;

&lt;p&gt;기계 학습 및 자연언어 처리 분야에서 주로 사용하던 비지도학습 알고리즘&lt;/p&gt;

&lt;h3 id=&quot;위키-정의&quot;&gt;위키 정의&lt;/h3&gt;

&lt;p&gt;문서 집합의 추상적인 “주제”를 발견하기 위한 통계적 모델 중 하나로, 텍스트 본문의 숨겨진 의미구조를 발견하기 위해 사용되는 텍스트 마이닝 기법 중 하나이다.&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%86%A0%ED%94%BD_%EB%AA%A8%EB%8D%B8&quot;&gt;출처 - 위키 백과 토픽모델링&lt;/a&gt;)&lt;/p&gt;

&lt;h3 id=&quot;컨셉&quot;&gt;컨셉&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;단어 관점
&lt;img src=&quot;/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/topic-model.png&quot; alt=&quot;topic-model&quot; /&gt;
&lt;em&gt;출처 - 강필성 교수님 강의 영상&lt;/em&gt;
    &lt;ol&gt;
      &lt;li&gt;특정한 문서의 집합(Corpus)으로부터 사전에 정의된 K개의 주제(Topic)를 만들어냄&lt;/li&gt;
      &lt;li&gt;각 Topic에 대응하는 높은 빈도의 Corpus의 단어들을 할당함&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;문서 관점
&lt;img src=&quot;/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/topic-model-2.png&quot; alt=&quot;topic-model-2&quot; /&gt;
&lt;em&gt;출처 - 강필성 교수님 강의 영상&lt;/em&gt;
    &lt;ol&gt;
      &lt;li&gt;각 개별적인 문서가 어느 토픽을 많이 포함하고 있는가?&lt;/li&gt;
      &lt;li&gt;각 문서에서 특정 토픽이 차지하는 비중 산출&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;정리&quot;&gt;정리&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;개별 토픽 관점
    &lt;ol&gt;
      &lt;li&gt;어떤 단어들이 주로 빈번하게 등장하는가?&lt;/li&gt;
      &lt;li&gt;주요 어휘들이 무엇인가?&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;개별 문서 관점
    &lt;ol&gt;
      &lt;li&gt;각각의 문서에는 각 토픽들이 얼마만큼의 비중을 가지고 섞여있는가?&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;토픽 모델링은 비교적으로 오래된 기법 중 하나지만, 정답이 있는 데이터가 없어도 문서들 내에 속한 단어들만으로도 학습할 수 있기 때문에 지금까지도 많이 사용되고 있는 알고리즘입니다.&lt;/p&gt;

&lt;p&gt;(* &lt;a href=&quot;https://www.youtube.com/watch?v=J1ri0EQnUOg&amp;amp;list=PLetSlH8YjIfVzHuSXtG4jAC2zbEAErXWm&amp;amp;index=13&quot;&gt;&lt;strong&gt;고려대학교 강필성 교수님 강의 영상&lt;/strong&gt;&lt;/a&gt;을 참고하시면, 토픽모델링 알고리즘에 대해 더 자세하게 이해할 수 있으니 한번쯤 보시는 것을 추천드립니다!)&lt;/p&gt;

&lt;h1 id=&quot;3-개인화-추천에서의-토픽-모델링&quot;&gt;3. 개인화 추천에서의 토픽 모델링&lt;/h1&gt;

&lt;p&gt;위 방식과 동일하게 토픽 모델링으로 사용자들과 콘텐츠들의 &lt;strong&gt;특징을 추출&lt;/strong&gt;하게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;단어들&lt;/strong&gt;을 바탕으로 &lt;strong&gt;한 문서 안의 여러 개의 주제&lt;/strong&gt;를 찾을 수 있는 것처럼, &lt;strong&gt;상품들&lt;/strong&gt;을 바탕으로 &lt;strong&gt;한 명의 사용자 안에 내포되어 있는 여러 개의 주제를 찾을 수 있다&lt;/strong&gt;고 볼 수 있기 때문에, 토픽 모델링 기법을 개인화 추천에 적용할 수 있는 것입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-personalized-recommendation-with-NLP/topic-model-3.png&quot; alt=&quot;topic-model-3&quot; /&gt;
&lt;em&gt;출처 - 카카오 기술블로그&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;용어만 달리하면, 단순히 “문서”, “단어”를 “사용자”, “상품 이용데이터”으로 바꿔서 보면, 아래와 같아집니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;자연어 처리: 문서들 내의 단어들로 토픽 모델링을 수행한다.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;추천 시스템: 사용자들 내의 상품 이용데이터들로 토픽 모델링을 수행한다.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;결론적으로 &lt;strong&gt;사용자의 행동 데이터&lt;/strong&gt;를 가지고 &lt;strong&gt;토픽 모델링을 수행&lt;/strong&gt;할 수 있게 됩니다.&lt;/p&gt;

&lt;p&gt;그 결과, 위 그림처럼 각 사용자에 대한 주제 벡터를 구할 수 있습니다.
이때, &lt;strong&gt;벡터의 크기 k&lt;/strong&gt;는 주제(토픽)의 개수이며 &lt;strong&gt;각각의 값&lt;/strong&gt;은 주제에 속할 확률을 의미하게 됩니다.&lt;/p&gt;

&lt;p&gt;추천시스템 관점에서 다시 정리하자면, &lt;strong&gt;토픽 모델링&lt;/strong&gt;을 수행하여 각 사용자별 이용한 상품데이터들이 각 주제(토픽)에 얼만큼의 비율로 속하는지를 판단하고, 이를 통해 개인화 추천을 수행합니다.&lt;/p&gt;

&lt;h1 id=&quot;4-예고편&quot;&gt;4. 예고편&lt;/h1&gt;

&lt;p&gt;추천 시스템에서 주요한 개념은 &lt;strong&gt;사용자가 관심있어 할 상품을 어떻게 정의하냐&lt;/strong&gt;입니다.&lt;/p&gt;

&lt;p&gt;영화 평점과 같이 이미 정답이 정해져있는 데이터가 아닌, 실제 사용자들의 행동 데이터를 분석하여 사용자가 관심있는 상품에 대한 정의를 내려야합니다.&lt;/p&gt;

&lt;p&gt;전통적으로 사용하던 협업필터링과 같은 기법들은 사전에 정의된 사용자별 관심 상품들의 정답 데이터가 필요하고, 행동 데이터에서 이를 정의하는 과정에서 다양한 모순이 발생하는 경우가 생깁니다.&lt;/p&gt;

&lt;p&gt;예를들어, 최근 한 달간 사용자1이 상품 a를 구매한 이력이 있을 경우, 사용자1은 상품 a에 관심이 있다고 판단하고 있습니다. 그런데 막상 사용해보니 사용자1은 상품 a가 마음에 들지 않았고, 환불과 같은 부정적인 피드백을 돌려주지 않았습니다. 이 상황에서 추천 시스템은 부정적인 피드백이 없었으니 사용자1과 비슷한 구매 패턴을 가진 사용자2에게 상품a를 추천해줍니다.&lt;/p&gt;

&lt;p&gt;또 다른 예로, 2번이상 연달아 구매가 발생한 상품b에 관심이 있다고 판단을 할 경우, 매번 인기 있는 상품 몇 가지에 대해서만 추천이 일어나게되어 사용자들은 다양한 추천을 받을 수 없게 됩니다. 또 새로 추가된 신상품들은 추천 받지 못합니다.&lt;/p&gt;

&lt;p&gt;위와 같은 모든 시나리오들을 고려하다보면, 로직이 복잡해지고 오히려 불필요한 고민들을 하게됩니다.&lt;/p&gt;

&lt;p&gt;다음 포스팅에서는 위와 같은 고민을 덜 수 있도록, 강화학습을 추천 시스템에 이용하는 방법을 소개하겠습니다!&lt;/p&gt;

&lt;h2 id=&quot;reference&quot;&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Probabilistic_latent_semantic_analysis&quot;&gt;Probabilistic latent semantic analysis - 위키백과&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%86%A0%ED%94%BD_%EB%AA%A8%EB%8D%B8&quot;&gt;토픽 모델링 - 위키 백과&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=J1ri0EQnUOg&amp;amp;list=PLetSlH8YjIfVzHuSXtG4jAC2zbEAErXWm&amp;amp;index=13&quot;&gt;고려대학교 강필성 교수님 토픽 모델링 강의 영상 - youtube&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tech.kakao.com/2021/06/25/kakao-ai-recommendation-01/&quot;&gt;카카오 기술블로그&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 11 Aug 2022 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2022/08/11/personalized-recommendation-with-NLP.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2022/08/11/personalized-recommendation-with-NLP.html</guid>
        <tags>
          
          <tag>NLP</tag>
          
          <tag>Recommend-system</tag>
          
          <tag>Unsupervised-Learning</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Gatsby를 어떻게 적용할 수 있을까? (+ gatsby에 typescript 적용하기)</title>
        <authors>
          
          
          <author>
            <name>조현준</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Owen.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-09-30-setting-gatsby-with-typescript/gatsby-logo.png</thumbnail>
        <description>&lt;h1 id=&quot;들어가며&quot;&gt;들어가며&lt;/h1&gt;

&lt;p&gt;이번 포스팅에서는 Gatsby.js에 대해서 간단히 소개하고 어떻게 적용할 수 있는지, 우리는 어떻게 적용했고 어떻게 사용하려 하는지에 대해서 소개하려고 합니다. 추가로 gatsby 프로젝트에 TypeScript을 사용하기 위한 개발환경을 세팅하는 내용을 담고있습니다.&lt;/p&gt;

&lt;h2 id=&quot;gatsbyjs&quot;&gt;Gatsby.js&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-setting-gatsby-with-typescript/gatsby-logo.png&quot; alt=&quot;gatsby&quot; /&gt;
&lt;em&gt;정적 웹사이트 생성기&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gatsby는 프론트엔드 라이브러리 React를 기반으로 하며 최근 프론트엔드 시장에서 자주 등장하며 빠르게 성장하고 있는 &lt;strong&gt;JAM Stack&lt;/strong&gt; 기반의 &lt;strong&gt;정적 사이트 생성 프레임워크&lt;/strong&gt; 입니다.&lt;/p&gt;

&lt;h3 id=&quot;jam-stack과-동작원리&quot;&gt;JAM Stack과 동작원리&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://jamstack.org/&quot;&gt;JAM Stack 공식문서&lt;/a&gt;에서는 아래와 같이 정의하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Fast and secure sites and apps delivered by pre-rendering files and serving them directly from a CDN, removing the requirement to manage or run web servers.&lt;/p&gt;

  &lt;p&gt;웹 애플리케이션에서 렌더링 할 화면을 pre-rendering 하고 이를 CDN에서 제공하여 빠르고 안전한 앱으로서, 웹 서버를 따로 관리하거나 실행할 필요가 없다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;일반적인 웹사이트는 프론트엔드의 시각화와 백엔드의 데이터를 통해서 웹페이지를 사용자에게 보여주게 됩니다. 위 방법은 페이지를 렌더링할때마다 해당 과정이 필요하기 때문에 페이지를 로딩하는데 시간이 오래걸립니다. &lt;strong&gt;렌더링 + API 통신&lt;/strong&gt; 단계를 거치기 때문이죠&lt;/p&gt;

&lt;p&gt;하지만 Jamstack은 모든 데이터를 서버에서 미리 불러와서 화면으로 만들어 놓은 다음, 사용자가 홈페이지에 접속하게 되면 만들어 놓은 화면을 그려줍니다. 그렇기 때문에 빠른 로딩 속도를 장점으로 가지고 갈 수 있습니다.&lt;/p&gt;

&lt;p&gt;이와 같은 장점을 가지고 있는 Jam Stack을 기반으로 하는 대표적인 프레임워크로는 많이 다운로드 된 순으로 &lt;strong&gt;Next, Gatsby, Jekyll, Nuxt&lt;/strong&gt; 등이 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;우리는-왜-gatsby를-사용하려고-하는가&quot;&gt;우리는 왜 Gatsby를 사용하려고 하는가&lt;/h2&gt;

&lt;h3 id=&quot;1-reactjs-기반-프레임워크이다&quot;&gt;1. React.js 기반 프레임워크이다&lt;/h3&gt;

&lt;p&gt;너드팩토리의 프론트엔드 챕터에서는 React + TypeScript를 가장 활발하게 사용하고 있습니다. 그렇기 때문에 react를 어느정도 다룰 수 있다면 큰 어려움 없이 개발 가능할 것이라 생각했습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-성능이-좋다&quot;&gt;2. 성능이 좋다&lt;/h3&gt;

&lt;p&gt;JavaScript가 실행되면 빈 HTML 페이지 안에 마크업을 추가해주는 일반적인 React SPA(Single Page Application)과는 다르게, 페이지 개발 후 Build를 하는 과정에서 마크업이 생성되기 때문에 SPA 페이지보다 빠르게 페이지를 렌더링 할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;3-seo에-유리하다&quot;&gt;3. SEO에 유리하다.&lt;/h3&gt;

&lt;p&gt;위 2번 단락과 이어서 build 과정에서 마크업이 생성됩니다. 그 결과로 페이지 내 모든 콘텐츠가 생성이 되어있게 되는 것이고, SPA과는 다르게 SEO(검색엔진최적화)에 유리합니다.&lt;/p&gt;

&lt;p&gt;JAM Stack 프레임워크 다운로드 횟수를 보면 Next.js가 가장 많이 다운로드 되었지만, Next.js는 정적 사이트 생성의 기능도있지만 주로 SSR(Server Side Rendering)을 사용하는 프레임워크입니다. 즉, 서버와 통신을 하며 요청을 받을 때 마다 동적으로 웹사이트를 생성하기 때문에 SEO에 불리하다는 단점이 있습니다.&lt;/p&gt;

&lt;p&gt;이와 같은 장점을 가지고 있는 Gatsby는 너드팩토리의 &lt;strong&gt;웹사이트의 사용자 행동데이터 분석 도구 서비스 VODA&lt;/strong&gt;의 소개페이지에도 적용되어 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-setting-gatsby-with-typescript/voda-landing-page.png&quot; alt=&quot;voda&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://voda.nerdfactory.ai/&quot;&gt;VODA 서비스 소개페이지&lt;/a&gt; ← 클릭&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;gatsby-기술-스택을-어떻게-잘-사용할수-있을까&quot;&gt;Gatsby 기술 스택을 어떻게 잘 사용할수 있을까&lt;/h2&gt;

&lt;h3 id=&quot;기술-블로그-마이그레이션&quot;&gt;기술 블로그 마이그레이션&lt;/h3&gt;

&lt;p&gt;지금까지 설명한 gatsby의 장점을 통해서 우리는 gatsby를 통해 기술블로그를 마이그레이션 및 개편하려는 계획을 가지고 있습니다.&lt;/p&gt;

&lt;p&gt;기존의 너드팩토리의 기술블로그는 github pages를 이용해 jekyll 기반의 정적 사이트를 배포하는 방식으로 구성되어 있습니다. 따라서 아래의 문제점으로 기술블로그에 대한 지속적인 관리와 커스터마이징이 어렵습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;너드팩토리 프론트엔드 챕터는 React 기술 스택을 주로 사용한다.&lt;/li&gt;
  &lt;li&gt;간단하고 쉽게 사용가능하지만, Ruby 기반인 jekyll의 구조와 Ruby에 익숙하지 않은 이상 커스터마이징에 어려움이 있습니다.&lt;/li&gt;
  &lt;li&gt;Ruby에 대한 지식(Bundler, Gemfile)이 필요한 경우가 있기에 어려움이 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;gatsby에-typescript-적용하기&quot;&gt;Gatsby에 TypeScript 적용하기&lt;/h1&gt;

&lt;p&gt;지금까지 설명한 gatsby에 typescript를 통해 개발을 할 수 있도록 개츠비 프로젝트에 typescript를 플러그인을 사용하여 적용해 봅시다.&lt;/p&gt;

&lt;p&gt;해당 포스트에서는 아래 버전을 따릅니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;node version: 16.13.1&lt;/li&gt;
  &lt;li&gt;Gatsby CLI version : 4.22.0&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;install&quot;&gt;Install&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;gatsby-cli install&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn global add gatsby-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;프로젝트 생성&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gatsby new &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;프로젝트 이름]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;해당 프로젝트에서 typescript install&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn add gatsby-plugin-typescript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이까지 설치가 완료되었다면 타입스크립트를 사용하기 위해 gatsby 프로젝트에 타입스크립트 플러그인을 추가해주는 작업이 필요합니다&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;...,&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;`gatsby-plugin-typescript`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;...,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;gatsby는 많은 플러그인을 지원하여 확장성이 좋다는 장점을 가지고 있습니다. 만약 내가 필요한 기능이 있다면 플러그인을 추가하면 됩니다! (해당 포스트에서는 타입스크립트 플러그인을 적용하는 것 까지 진행합니다.)&lt;/p&gt;

&lt;p&gt;플러그인 추가 후 tsconfig.json 파일을 생성하여 타입스크립트를 활성화 합니다. 해당 명령어를 입력했다면 루트 디렉터리에 tsconfig.json 파일이 생성되며, 주석 처리 되어있는 옵션을 직접 선택하여 변경할 수 있습니다. 해당 포스트에서는 다음과 같이 옵션을 수정하겠습니다&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn tsc &lt;span class=&quot;nt&quot;&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;tsconfig.json 파일을 사용하려는 환경에 맞춰 세팅해줍니다.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Language&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;es2016&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;preserve&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Modules&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;commonjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;baseUrl&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;paths&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;components/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./components/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;utils/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./utils/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hooks/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./hooks/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;icons/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../static/icons/*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;resolveJsonModule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;allowSyntheticDefaultImports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;esModuleInterop&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;forceConsistentCasingInFileNames&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Checking&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;strict&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;noUnusedLocals&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;noUnusedParameters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;noImplicitReturns&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;noFallthroughCasesInSwitch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Completeness&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;skipLibCheck&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exclude&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;node_modules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;gatsby-node.js 파일에서 webpack config를 추가합니다.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`path`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createFilePath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`gatsby-source-filesystem`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onCreateWebpackConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setWebpackConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;src/components&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;src/utils&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;hooks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;src/hooks&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여기까지 진행했다면 문제없이 gatsby 프로젝트에 타입스크립트를 적용이 완료되었으며 타입스크립트로 개발이 가능한 상태입니다.&lt;/p&gt;

&lt;h1 id=&quot;마치며&quot;&gt;마치며&lt;/h1&gt;

&lt;p&gt;해당 포스팅을 작성하면서 얼른 너드팩토리 기술블로그 마이그레이션 및 개편을 완료하고 싶다는 생각이 듭니다. 더불어 기술블로그 뿐만 아니라 제품 소개페이지, 너드팩토리 소개페이지 까지 적용해보고 싶습니다.&lt;/p&gt;

&lt;p&gt;다음 포스팅에는 Gatsby를 통해 기술블로그를 개편하는 과정을 가지고 돌아오도록 하겠습니다.&lt;/p&gt;
</description>
        <pubDate>Fri, 24 Jun 2022 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2022/06/24/setting-gatsby-with-typescript.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2022/06/24/setting-gatsby-with-typescript.html</guid>
        <tags>
          
          <tag>React</tag>
          
          <tag>Typescript</tag>
          
          <tag>Gatsby</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Message Queue vs Load Balancer</title>
        <authors>
          
          
          <author>
            <name>김규태</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/sean.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-09-30-message-queue-vs-load-balancer/message-queue.png</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;h2 id=&quot;트래픽을-견디기-위해-어떤-것을-사용해야할까&quot;&gt;트래픽을 견디기 위해 어떤 것을 사용해야할까?&lt;/h2&gt;

&lt;p&gt;너드팩토리의 제품들은 매우 많은 데이터를 수집하고 있다보니 서비스가 불안정한 경우가 종종 있었습니다.&lt;/p&gt;

&lt;p&gt;예를 들면 고객사에서 특별한 이벤트를 진행하거나 급성장하여 트래픽이 급증할 수 있습니다.&lt;/p&gt;

&lt;p&gt;소프트웨어 아키텍트 입장에서 안정적으로 트래픽을 감당하기 위해 Message Queue와 Load Balancer를 고려해보았습니다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;물론 더 다양한 방법이 존재하지만 여기서는 두 방법론에 대해서만 다루겠습니다.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;본 포스팅에서는 두 방법을 비교하여 적절하게 활용하는 관점을 제공하고자 합니다.&lt;/p&gt;

&lt;h1 id=&quot;기술-설명&quot;&gt;기술 설명&lt;/h1&gt;

&lt;p&gt;기술 비교에 앞서 각 기술을 간략히 설명해두었습니다.&lt;/p&gt;

&lt;h2 id=&quot;message-queuemq란&quot;&gt;Message Queue(MQ)란?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-message-queue-vs-load-balancer/message-queue.png&quot; alt=&quot;messagequeue&quot; /&gt;&lt;/p&gt;

&lt;p&gt;MQ는 메시지 큐(Message Queue)의 줄임말로 인스턴스 간 데이터 교환 시 통신하는 방법입니다.&lt;/p&gt;

&lt;p&gt;메시지 큐는 대용량 데이터를 처리하기 위해 배치 작업에 사용하거나 비동기 동작을 위해서 사용하게 됩니다.&lt;/p&gt;

&lt;p&gt;일반적으로 Django, Flask는 사용자가 많아지거나 서비스의 크기가 증가함에 따라, 응답 시간이 길어지거나 서비스가 무너지게 됩니다.&lt;/p&gt;

&lt;p&gt;이 경우에는 생산자(Producers)와 소비자(Consumers)가 붙어있는 형태로 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;MQ가 도입될 경우 위 그림처럼 생산자와 소비자 사이에 브로커(broker)가 추가됩니다.&lt;/p&gt;

&lt;p&gt;생산자는 교환대의 역할을 수행하는 Exchange에 접근하여 요청을하고 Exchange에서는 정해진 규칙에 따라 알맞은 큐에 메시지를 전달합니다.&lt;/p&gt;

&lt;p&gt;큐에 전달된 메시지는 Consumer에게 전달됩니다.&lt;/p&gt;

&lt;h2 id=&quot;load-balancer란&quot;&gt;Load Balancer란?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-message-queue-vs-load-balancer/load-balancer.png&quot; alt=&quot;loadbalancer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;로드 밸런서는 다수의 컴퓨팅 리소스로 분산하기 위해 사용합니다.&lt;/p&gt;

&lt;p&gt;서비스를 확장하는 방법에는 2가지 방법이 있습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Scale-up: 서버의 성능을 향상 (수직 확장)&lt;/li&gt;
  &lt;li&gt;Scale-out: 서버의 수를 증대 (수평 확장)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;로드 밸런서는 Scale-out 방법론에 해당합니다.&lt;/p&gt;

&lt;p&gt;단일 서버가 아닌 다수의 서버를 구성하여 로드 밸런서가 정해진 알고리즘에 따라 서버에 요청을 분산합니다.&lt;/p&gt;

&lt;p&gt;클라이언트는 서버에 직접 접근하는 것이 아닌 로드 밸런서로 접근하게 됩니다. 이는 서버 또한 동일합니다.&lt;/p&gt;

&lt;p&gt;클라이언트가 로드 밸런서로 요청을 전달하면, 로드 밸런서는 분배 알고리즘을 통해 서버에 전달합니다.&lt;/p&gt;

&lt;p&gt;서버는 로드 밸런서로 응답을 하면, 로드 밸런서가 클라이언트에게 응답 결과를 전달합니다.&lt;/p&gt;

&lt;h1 id=&quot;어느-방법이-적합할까&quot;&gt;어느 방법이 적합할까?&lt;/h1&gt;

&lt;p&gt;이를 활용하는데 있어 적합한 방법을 찾는 관점이 필요합니다.&lt;/p&gt;

&lt;p&gt;아래 내용에는 적합한 방법을 찾는 관점에 대해 기술하였습니다.&lt;/p&gt;

&lt;h2 id=&quot;mq를-사용하기-적절한-경우&quot;&gt;MQ를 사용하기 적절한 경우&lt;/h2&gt;

&lt;p&gt;이미지, 영상, 대용량 처리를 수행하는 경우 동시에 처리할 수 있는 작업량은 비교적 적습니다.&lt;/p&gt;

&lt;p&gt;메시지 큐를 사용할 경우, 동시에 처리할 양만 서버에서 가져가 처리하게 됩니다.&lt;/p&gt;

&lt;p&gt;이와 같이 대용량 데이터를 처리하는 작업을 수행할 경우 MQ가 적합합니다.&lt;/p&gt;

&lt;h2 id=&quot;mq를-사용하기-부적절한-경우&quot;&gt;MQ를 사용하기 부적절한 경우&lt;/h2&gt;

&lt;p&gt;MQ의 경우 기본적으로 서버가 큐로부터 작업을 가져가야만 처리가 이루어집니다.&lt;/p&gt;

&lt;p&gt;따라서 응답속도가 비교적 느립니다.&lt;/p&gt;

&lt;p&gt;빠른 응답속도가 보장되어야 하는 서비스의 경우 MQ가 적합하지 않습니다.&lt;/p&gt;

&lt;h2 id=&quot;load-balancer를-사용하기-적절한-경우&quot;&gt;Load Balancer를 사용하기 적절한 경우&lt;/h2&gt;

&lt;p&gt;MQ를 사용하기 부적절한 경우의 반대로 생각하시면 간단합니다.&lt;/p&gt;

&lt;p&gt;Load Balancer는 서버에 즉시 작업을 전달하여 빠르게 처리가 이루어집니다.&lt;/p&gt;

&lt;p&gt;따라서 빠른 응답속도가 보장되어야 할 경우 Load Balancer가 적합합니다.&lt;/p&gt;

&lt;h2 id=&quot;load-balancer를-사용하기-부적절한-경우&quot;&gt;Load Balancer를 사용하기 부적절한 경우&lt;/h2&gt;

&lt;p&gt;MQ를 사용하기 적절한 경우의 반대로 생각하시면 간단합니다.&lt;/p&gt;

&lt;p&gt;Load Balancer는 모든 서버가 바쁘더라도 작업을 전달하게 됩니다.&lt;/p&gt;

&lt;p&gt;서버에 무거운 작업이 전달될 경우 서버의 안정성을 보장하기가 힘듭니다.&lt;/p&gt;

&lt;p&gt;대용량 처리 작업 같이 무거운 작업을 수행할 경우 Load Balancer가 적합하지 않습니다.&lt;/p&gt;

&lt;h1 id=&quot;결론&quot;&gt;결론&lt;/h1&gt;

&lt;p&gt;소프트웨어 아키텍트 관점에서 서비스를 개선하기 위해 여러 방법들을 선택할 수 있습니다.&lt;/p&gt;

&lt;p&gt;본 포스팅에서는 두 기술의 특성과 장단점을 파악하고 적재적소에 활용하는 관점을 제공하였습니다.&lt;/p&gt;
</description>
        <pubDate>Wed, 20 Apr 2022 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2022/04/20/message-queue-vs-load-balancer.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2022/04/20/message-queue-vs-load-balancer.html</guid>
        <tags>
          
          <tag>Architecture</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>추천시스템 평가 지표 - 1 (Precision@K / Recall@K)</title>
        <authors>
          
          
          <author>
            <name>안정현</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Richard.jpg</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2022-09-30-recommend-system-classification-metric/example.png</thumbnail>
        <description>&lt;h2 id=&quot;개요&quot;&gt;개요&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;머신러닝 분야는 모델 구축만큼 성능평가가 중요함&lt;/li&gt;
  &lt;li&gt;추천시스템 또한 머신러닝의 비지도학습에 속하기 때문에, 성능평가가 중요&lt;/li&gt;
  &lt;li&gt;추천시스템에서는 Precision/Recall@K, MAP, NDCG@K 등 다양한 성능 평가지표가 존재함&lt;/li&gt;
  &lt;li&gt;본 포스트에서는 추천 시스템에서 일반적으로 많이 사용되는 &lt;strong&gt;Precision@k / Recall@k&lt;/strong&gt;에 대한 개념과 구현 코드에 대해 설명하고자 함&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;precisionk--recallk-개념&quot;&gt;&lt;strong&gt;Precision@k / Recall@k 개념&lt;/strong&gt;&lt;/h2&gt;

&lt;h3 id=&quot;1-precisionk-정의&quot;&gt;&lt;strong&gt;1. Precision@k 정의&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Precision은 예측값 중 옳게 예측한 비율을 의미&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-recommend-system-classification-metric/define-precision.png&quot; alt=&quot;precision&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;추천 시스템에서 Precision은 모델이 추천한 아이템 중에 사용자가 관심있는 아이템의 비율을 의미&lt;/li&gt;
  &lt;li&gt;Precision@k는 k개 추천 결과에 대한 Precision을 계산한 것으로, 모델이 추천한 아이템 k개 중에 실제 사용자가 관심있는 아이템의 비율을 의미&lt;/li&gt;
  &lt;li&gt;Average of Precision@k는 Precision@k의 평균으로 AP@K와 다름
    &lt;ul&gt;
      &lt;li&gt;아래 논문에 따르면, Average of Precision@k는 각 추천에 대한 Precision@k에 대한 평균을 의미하고, AP@K는 서로 다른 k에 대한 Precision의 평균을 의미
&lt;img src=&quot;/assets/images/posts/2022-09-30-recommend-system-classification-metric/paper-precision.png&quot; alt=&quot;paper&quot; /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-recallk-정의&quot;&gt;2. &lt;strong&gt;Recall@k 정의&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Recall은 실제 옳은 것 중에서 옳다고 예측한 것의 비율을 의미
&lt;img src=&quot;/assets/images/posts/2022-09-30-recommend-system-classification-metric/define-recall.png&quot; alt=&quot;recall1&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;추천 시스템에서 Recall은 사용자가 실제로 관심있는 아이템 중에 모델이 추천한 아이템의 비율을 의미&lt;/li&gt;
  &lt;li&gt;Recall@k는 k개 추천 결과에 대한 Recall을 계산한 것으로, 사용자가 관심있는 모든 아이템 중에서 모델의 추천한 아이템 k개가 얼마나 포함되는지 비율을 의미
&lt;img src=&quot;/assets/images/posts/2022-09-30-recommend-system-classification-metric/define-recall-2.png&quot; alt=&quot;recall2&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-precisionk--recallk-예시&quot;&gt;3. &lt;strong&gt;Precision@K / Recall@K 예시&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;k=5이고, 사용자가 관심있는 아이템 수가 6개일 때,&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Precision@5=0.6 (사용자가 관심있는 추천 아이템 수(=3) / 추천한 아이템 수(=5))&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Recall@5 =0.5 (사용자가 관심있는 추천 아이템 수(=3) / 사용자가 실제로 관심있는 모든 아이템 수(=6))&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2022-09-30-recommend-system-classification-metric/example.png&quot; alt=&quot;example&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;precisionk--recallk-구현-코드-예시&quot;&gt;&lt;strong&gt;Precision@k / Recall@k 구현 코드 예시&lt;/strong&gt;&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;성능 지표 정의 코드&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;위에서 설명한 Precision@k / Recall@k를 다음과 같이 코드로 구현할 수 있음&lt;/p&gt;

        &lt;ol&gt;
          &lt;li&gt;모델을 통해 사용자가 어떤 아이템에 관심이 있을지 예측한 데이터인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;predictions&lt;/code&gt;과 예측한 값이 실제로 사용자가 관심있는 아이템인지 확인하기 위한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt;, 추천 수 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;k&lt;/code&gt;를 파라미터로 받음&lt;/li&gt;
          &lt;li&gt;최종적으로 k개만 추천할 것이기 때문에, 예측 데이터 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;predictions&lt;/code&gt; 에 대해 k만큼 슬라이싱&lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;Top-k 예측값(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pred&lt;/code&gt;)과 사용자가 실제 관심있는 아이템 리스트(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt;)의 교집합을 통해 hit 수(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;num_hit&lt;/code&gt;)를 구함&lt;/p&gt;

            &lt;p&gt;→ hit는 k개 추천 아이템 중에 사용자가 실제로 관심 있는 상품이 존재하는 경우를 의미하며, 위 수식에서 TP에 해당함&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;구한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;num_hit&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pred&lt;/code&gt;를 활용하여 Precision@k, Recall@k 값을 계산하여 반환&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_compute_precision_recall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
		targets : 테스트 데이터 중, 사용자의 피드백이 있는 item 인덱스 리스트
		predictions : 학습 데이터에 피드백이 존재하는 item을 제외한 예측 데이터
		k : 추천 수
    &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;num_hit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intersection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;precision&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_hit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_hit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;precision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recall&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;성능 측정 코드&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;위에서 정의한 성능 지표를 활용하여 Average of Precision@k / Recall@k 값 측정
        &lt;ol&gt;
          &lt;li&gt;학습 모델 객체 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt;, train / test 데이터셋, 추천 수 k를 파라미터로 받음&lt;/li&gt;
          &lt;li&gt;각 사용자 별 성능 측정을 하기 위해 반복문 실행&lt;/li&gt;
          &lt;li&gt;학습 모델을 활용하여 해당 사용자에 대한 예측값(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;predictions&lt;/code&gt;) 구함&lt;/li&gt;
          &lt;li&gt;학습 데이터셋에서 해당 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_id&lt;/code&gt;의 피드백이 있는 아이템 리스트(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rated&lt;/code&gt;)를 구한 다음, 예측값 중 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rated&lt;/code&gt;에 존재하지 않는(=학습 데이터에 피드백이 없는) 아이템만 예측값으로 할당&lt;/li&gt;
          &lt;li&gt;테스트 데이터 중, 사용자의 피드백이 있는 item 인덱스 리스트(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt;)를 구함&lt;/li&gt;
          &lt;li&gt;위에서 정의한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_compute_precision_recall&lt;/code&gt; 함수를 실행하여 해당 사용자에 대한 Precision@k, Recall@k 값을 구함&lt;/li&gt;
          &lt;li&gt;c~f번 까지 반복하여 전체 사용자에 대한 Average of Precision@k / Recall@k 값 구함&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;evaluate_ranking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
		model : 학습 모델 객체
		test : test 데이터셋, csr형식의 피벗테이블 (m*n1)
		train : train 데이터셋, csr형식의 피벗테이블 (m*n2)
		k : 추천 수
    &quot;&quot;&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tocsr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tocsr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# ks : 서로 다른 k의 리스트
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;precisions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recalls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'''
        user_id : 고유 사용자 ID (0~m-1)
        row : 각 user에 대한 피드백이 있는 열(상품) 인덱스(튜플)
        '''&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argsort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# rated : train 피벗테이블에서 해당 user_id의 피드백이 있는 열(상품) 인덱스 리스트
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;rated&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;rated&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# 예측값(추천 상품ID=열 인덱스) 중 구매 이력(rated) 없는 예측값만 필터링
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# test 피벗테이블에서 해당 user_id의 피드백이 있는 열(상품) 인덱스 리스트
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indices&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# 여러 개의 k에 대한 테스트를 위해 반복문 실행
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;precision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recall&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_compute_precision_recall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predictions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;precisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;precision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# precisions : k별 각 사용자의 precision@k 측정 리스트
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;recalls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# recalls : k별 각 사용자의 recalln@k 측정 리스트
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;precisions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;precisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;recalls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recalls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;precisions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recalls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.researchgate.net/publication/335439095_Twitter_User_Modeling_Based_on_Indirect_Explicit_Relationships_for_Personalized_Recommendations&quot;&gt;Twitter User Modeling Based on Indirect Explicit Relationships for Personalized Recommendations&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sungkee-book.tistory.com/11&quot;&gt;[추천시스템] 성능 평가 방법 - Precision, Recall, NDCG, Hit Rate, MAE, RMSE&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/graytowne/caser_pytorch&quot;&gt;https://github.com/graytowne/caser_pytorch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 23 Sep 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/09/23/recommend-system-classification-metric-1.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/09/23/recommend-system-classification-metric-1.html</guid>
        <tags>
          
          <tag>recommend-system</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Flask를 활용한 iOS Networking 1 - 사진 전송하기</title>
        <authors>
          
          
          <author>
            <name>유예지</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Lizzy.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/0.png</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/main.png&quot; alt=&quot;0.png&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;시작&quot;&gt;시작&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;와이파이나 데이터가 터지지 않는 환경에서는 어떤 앱을 쓸 수 있을까요? 유튜브, 카카오톡 등 우리가 즐겨 쓰는 대부분의 앱은 제 기능을 하지 못할 것입니다. 모바일 앱 사용에 있어서 서버와의 통신은 빼놓을 수 없는 관계입니다.&lt;/p&gt;

&lt;p&gt;서버와의 통신은 우리가 정보를 검색해서 읽고 글, 사진을 업로드 또는 수정을 하기 위해 사용합니다. 이러한 모바일과 서버 간의 네트워킹을 어떻게 구현하는지 알아보기 위해 예시로 iOS용 사진 전송 앱을 만들어 보며 데이터를 주고받는 기능을 구현해보겠습니다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/2.png&quot; alt=&quot;2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 그림과 같이 앱에서 원하는 사진을 서버에 보내고, 처리 값(이미지 크기)을 받아와 출력하는 기능을 통해 네트워킹 과정을 살펴봅시다.&lt;/p&gt;

&lt;h1 id=&quot;ios-앨범-or-카메라로-사진-선택&quot;&gt;[iOS] 앨범 or 카메라로 사진 선택&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;우선 앱에서 원하는 사진을 서버로 보내기 위해서는 앨범이나 카메라를 실행해야 합니다.&lt;/p&gt;

&lt;p&gt;UIImagePickerController를 사용하면 사진 촬영, 동영상 녹화, 앨범에서 항목 선택을 위한 시스템 인터페이스를 관리할 수 있습니다.&lt;/p&gt;

&lt;p&gt;UIImagePickerController를 실행하기 전, Info.plist에서 권한을 설정해 줍시다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/3.png&quot; alt=&quot;3.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;현재 필요한 기능은 앨범에서 사진 선택(photoLibrary), 카메라 촬영(camera)이므로 다음과 같이 코드를 작성해 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 앨범 사용 가능 여부 확인&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UIImagePickerController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isSourceTypeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;photoLibrary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)){&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 이미지 피커의 델리케이트 self로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 이미지 피커의 소스 타입을 PhotoLibrary로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sourceType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;PhotoLibrary&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 미디어 타입 kUTTypeImage로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mediaTypes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kUTTypeImage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 편집을 허용&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allowsEditing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 현재 뷰 컨트롤러를 imagePicker로 대체. 즉 뷰에 imagePicker가 보이게 함&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;animated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;completion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 카메라 사용 가능 여부 확인&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UIImagePickerController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isSourceTypeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)){&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 이미지 피커의 델리케이트 self로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delegate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 이미지 피커의 소스 타입을 camera로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sourceType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;camera&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 미디어 타입 kUTTypeImage로 설정&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mediaTypes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kUTTypeImage&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 편집을 허용하지 않음&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;allowsEditing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// 현재 뷰 컨트롤러를 imagePicker로 대체. 즉 뷰에 imagePicker가 보이게 함&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagePicker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;animated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;completion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;앨범, 카메라 각각 사용 가능 여부를 확인해 주고 원하는 동작 및 예외 처리를 작성해 주면 다음 사진들과 같이 각 기능들이 실행되는 것을 볼 수 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/4.png&quot; alt=&quot;4.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;[photoLibrary] 앨범 실행 화면&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/5.png&quot; alt=&quot;5.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;[camera] 카메라 실행 화면&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;ios-서버-통신-코드-작성&quot;&gt;[iOS] 서버 통신 코드 작성&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;사진 선택을 완료했다면, 선택한 사진을 서버에 보내는 기능이 필요합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/6.png&quot; alt=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/6.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;iOS 네트워킹에는 Alamofire, Moya 등 여러 가지 방법들이 있는데, 그중 가장 기본이 되는 URLSession을 사용해서 진행하겠습니다. URLSession은 애플에서 HTTP/HTTPS를 통해 콘텐츠를 다운로드, 업로드하기 위해 제공된 완성된 네트워킹 API입니다. 위 Task 중 어플에서 웹 서버로 Data 객체 또는 파일 데이터를 업로드할 수 있는 URLSessionUploadTask를 사용합니다.&lt;/p&gt;

&lt;p&gt;여기서 HTTP Method를 설정해 주어야 합니다! URLSessionUploadTask는 POST 혹은 PUT 메소드를 이용합니다. 하지만 자주 사용되는 메소드인 POST와 GET 비교를 통해 HTTP Method를 살펴보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/7.png&quot; alt=&quot;7.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GET과 POST 차이&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;구분&lt;/th&gt;
      &lt;th&gt;GET&lt;/th&gt;
      &lt;th&gt;POST&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;사용&lt;/td&gt;
      &lt;td&gt;Read or Retrieve&lt;/td&gt;
      &lt;td&gt;Create&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;URL에 데이터 노출 여부&lt;/td&gt;
      &lt;td&gt;O&lt;/td&gt;
      &lt;td&gt;X&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;데이터 위치&lt;/td&gt;
      &lt;td&gt;Header&lt;/td&gt;
      &lt;td&gt;Body&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;캐싱 가능 여부&lt;/td&gt;
      &lt;td&gt;O&lt;/td&gt;
      &lt;td&gt;X&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;이처럼 HTTP Method의 메소드는 용도와 필요성에 맞게 사용할 수 있습니다. 저는 POST 방식이 가장 적절하다고 판단했습니다. 그렇다면 코드를 작성해보겠습니다!&lt;/p&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;uploadImg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;uiImg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UIImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;semaphore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DispatchSemaphore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 세마포어 선언&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSMutableURLRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NSURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://0.0.0.0:8080/api/test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;URLSession&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shared&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;httpMethod&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application/octet-stream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;forHTTPHeaderField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;img&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;forHTTPHeaderField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;X-FileName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pngData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uiImg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pngData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	   &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;uploadTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;URLRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pngData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;completionHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;httpResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as?&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;HTTPURLResponse&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                 &lt;span class=&quot;c1&quot;&gt;// statusCode 처리&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

				 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;responseData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;responseString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 응답 처리&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// 에러 처리&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

         &lt;span class=&quot;c1&quot;&gt;// 네트워킹이 끝나면 신호 보내기&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;resume&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	   &lt;span class=&quot;c1&quot;&gt;// 네트워킹이 끝날때까지 대기&lt;/span&gt;
	   &lt;span class=&quot;n&quot;&gt;semaphore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;코드를 살펴보면, 세마포어(Semaphore)를 사용한 것을 볼 수 있습니다. 세마포어의 사전적 의미는 수기 신호입니다. 즉, 두 개 이상의 프로세스가 동시에 공유 메모리와 같은 공유 자원을 접근할 때 동기화를 걸어주는 역할을 합니다.&lt;/p&gt;

&lt;p&gt;현재 어플에서 “서버에 사진 전송 → 서버에서 처리 → 결과 화면에 출력” 순서로 진행이 되어야 하는데, 서버에서 처리하는 동안 결과 화면으로 넘어가는 등 시간적인 차이 같은 문제로 인해 의도하지 않은 결과가 나올 수 도 있습니다. 따라서 공유 자원의 독점을 보장할 수 있도록 임계 영역(Critical Section)을 만들어줌으로써 문제를 해결할 수 있습니다.&lt;/p&gt;

&lt;p&gt;마지막으로 서버 쪽에서 결과를 확인해보면 통신이 잘 이루어진 것을 볼 수 있습니다!!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-iOS-Networking-1-with-Flask-Sending-Photos/8.png&quot; alt=&quot;8.png&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;the-end&quot;&gt;The End&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;여기까지는 앱에서 사진을 전송하는 기능을 구현해봤습니다! 다음 2장에서는 사진을 받아서 원하는 작업을 해주는 API를 만들어 서버에 올리고, 결과를 받아와서 처리하는 방법을 다루겠습니다.&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/07/05/iOS-Networking-1-with-Flask-Sending-Photos.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/07/05/iOS-Networking-1-with-Flask-Sending-Photos.html</guid>
        <tags>
          
          <tag>API</tag>
          
          <tag>Flask</tag>
          
          <tag>Swift5</tag>
          
          <tag>iOS</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>GAN을 이용한 이상탐지</title>
        <authors>
          
          
          <author>
            <name>안정현</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Richard.jpg</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-07-05-Anomaly-detection-using-GAN/Untitled.png</thumbnail>
        <description>&lt;p&gt;2014년, 이안 굿펠로우(Ian Goodfellow)에 의해 고안된 GAN(Generative Adversarial Network)은 생성 모델과 딥러닝 분야에 큰 혁신을 불러일으켰습니다. 특히, GAN은 이미지 생성, 스타일 변환, 영상/음성 합성 등 다양한 분야에서 우수한 성능을 보였으며, 최근 이상탐지 분야에서도 사용되고 있습니다. 이번 글에서는 이상탐지에서의 GAN의 활용에 대해 다루어 보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;생성-모델과-판별-모델&quot;&gt;&lt;strong&gt;생성&lt;/strong&gt; &lt;strong&gt;모델과&lt;/strong&gt; &lt;strong&gt;판별&lt;/strong&gt; &lt;strong&gt;모델&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;기계 학습에서 분류(Classification) 문제를 해결하기 위한 알고리즘은 생성 모델(Generative Model)과 판별 모델(Discriminative Model) 크게 2가지 종류가 있습니다. 판별 모델은 분류 경계를 찾는 것을 목적으로 학습하는 반면에, 생성 모델은 데이터의 분포를 학습합니다. 예를 들어, 판별 모델 관점에서 개와 고양이 분류는 개와 고양이의 샘플 데이터로부터 각각의 특징을 학습한 후, 두 클래스(개, 고양이)의 특징을 구분 짓는 경계선을 찾는 방식으로 진행됩니다. 반면에, 생성 모델을 활용한 분류는 개와 고양이의 샘플 데이터가 따르는 분포를 학습하여 두 집단을 구분하고, 학습이 끝난 후 모델을 활용하여 유사한 데이터를 생성합니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-Anomaly-detection-using-GAN/Untitled.png&quot; alt=&quot;Untitled.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;생성 모델과 판별 모델 비교&amp;gt;&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;gan-개념&quot;&gt;&lt;strong&gt;GAN 개념&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;GAN(Generative Adversarial Network)은 ‘진짜 같은 가짜 데이터’를 생성하는 대표적인 생성 모델입니다.  GAN이라는 이름에서 알 수 있듯이, GAN은 두 개의 모델이 적대적(Adversarial)으로 경쟁하듯이 학습하면서, 진짜 같은 가짜 데이터를 생성하는(Generative) 신경망 모델(Network) 입니다. 여기서 ‘생성’은 실제 데이터 분포에 근사하도록 학습하는 것을 전제로 합니다. 즉, 실제 데이터 분포에 근사하게 모델을 학습하면, 유사한 샘플 데이터를 생성할 수 있습니다. 그리고, ‘적대적(Adversarial)’은 GAN 모델의 학습 원리를 상징하는 용어이며, 생성자(Generator)와 구분자(Discriminator) 두 개의 모델을 경쟁하여 성능을 향상시키는 방향으로 학습하는 것을 의미합니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-Anomaly-detection-using-GAN/Untitled1.png&quot; alt=&quot;Untitled1.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;GAN 아키텍처&amp;gt;&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;gan-기반-이상탐지&quot;&gt;GAN 기반 이상탐지&lt;/h3&gt;

&lt;p&gt;이상탐지(Anomaly Detection)는 데이터에서 비정상적인 값을 탐지하는 것을 의미합니다. 이상탐지를 위한 기법은 분포, boxplot 등을 활용하여 이상치를 찾는 통계적 방법부터 모델을 이용하여 예측하는 방법까지 다양합니다. 최근에는 이미지 데이터 상의 이상부분을 탐지하기 위하여 GAN을 이용한 연구가 진행되고 있습니다.  AnoGAN, GANomaly 등 이상탐지를 위한 다양한 GAN 기반 모델들이 연구되었으며, 여기서는 GANomaly를 소개하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;GANomaly는 생성자(Generator)가 Encoder-Decoder-Encoder의 구조를 갖습니다. 구성된 네트워크 수가 많은 만큼 Generator의 손실 함수(Loss Function)도 여러 개 Loss (Encoder Loss, Contextual Loss, Adversarial Loss)의 합으로 구성됩니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-Anomaly-detection-using-GAN/Untitled2.png&quot; alt=&quot;Untitled2.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;GANomaly 아키텍처&amp;gt;&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;아래는 GANomaly의 Generator Loss를 구현한 코드입니다. 코드는 MNIST의 ‘1’과 ‘7’을 각각 정상/비정상으로 간주하고 분류한 알고리즘을 구현한 것입니다. Encoder Loss는 G_E(x)의 출력값과 E(x_hat)의 출력값에 대한 MSE로 정의됩니다. Contextual Loss는 G_E(x)의 출력값과 E(x_hat)의 출력값에 대한 MAE로 정의됩니다. Adversarial Loss는 D(x, x_hat)의 출력값에 대한 MSE로 계산됩니다.&lt;/p&gt;

&lt;p&gt;이 3개의 Loss에 가중치를 각각 곱해서 합한 값을 최종적으로 Generator Loss로 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EncLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keras&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EncLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ori&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ori&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_output_shape_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CntLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keras&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CntLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ori&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ori&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_output_shape_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AdvLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keras&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AdvLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ori_feature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feature_extractor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;gan_feature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;feature_extractor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ori_feature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gan_feature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_output_shape_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'input'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;channels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# g(x)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adv_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AdvLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'adv_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cnt_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CntLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'cnt_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;enc_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EncLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'enc_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gan_trainer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keras&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adv_loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cnt_loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enc_loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# loss function
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;yt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yp&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;losses&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;'adv_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;'cnt_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;'enc_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;lossWeights&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'cnt_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;20.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'adv_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'enc_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# compile
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gan_trainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'adam'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;losses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss_weights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lossWeights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Loss 정의 후, ‘d’(=Discriminator)를 학습가능하게 설정하고 ‘train_on_batch’ 메소드를 사용하여 학습합니다. 그리고 구분자 ‘d’를 학습 범위에서 제외하고, 생성자 ‘gan_trainer’를 학습시킵니다. 이 과정을 iteration 수만큼 반복합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iin&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;niter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;### get batch x, y ###
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_data_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__next__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;c1&quot;&gt;### train disciminator ###
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trainable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;fake_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;d_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concatenate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fake_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;d_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;concatenate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ones&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fake_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;d_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_on_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c1&quot;&gt;### train generator ###
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trainable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;g_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gan_trainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_on_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'niter:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, g_loss:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g_loss&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, d_loss:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d_loss&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;학습이 끝난 후, 테스트 데이터를 입력하여 각 네트워크 별 예측값을 구하고, 이 예측값들을 이용하여 이상탐지 점수(Anomaly Score)를 구합니다. 이상탐지 점수는 논문에 따라 Encoder Loss에 기반하여 G_E(x)의 예측값과 E(G(x))의 예측값에 대한 SSE로 정의합니다. 그리고, Min-max 정규화를 통해 0부터 1사이 범위로 변환합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gan_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;encoded_gan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g_e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gan_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoded&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoded_gan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# map to 0~1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;최종적으로 Min-max 정규화된 이상탐지 점수(Anomaly Score)를 산점도로 시각화하면 아래 그림과 같습니다. 이상탐지 점수가 약 0.3일 때를 기준으로 두 클래스가 구분되는 것을 볼 수 있습니다. 따라서, 약 0.3 정도를 임계값으로 정하여서 테스트 데이터에 대한 이상 여부를 판단할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pylab&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rcParams&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rcParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'figure.figsize'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'skyblue'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'pink'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-05-Anomaly-detection-using-GAN/Untitled3.png&quot; alt=&quot;Untitled3.png&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;결-론&quot;&gt;결 론&lt;/h2&gt;

&lt;p&gt;이번 글에서는 이상탐지를 위한 GAN 모델을 설명하기에 앞서, 생성 모델과 판별 모델의 차이와 GAN 개념을 설명하였습니다. 그리고 다양한 이상탐지를 위한 GAN 모델 중, GANomaly 모델을 소개하였습니다. 특히, GANomaly의 전체적인 아키텍처와 손실 함수 정의, 테스트 및 시각화를 중점적으로 다루었습니다.&lt;/p&gt;

&lt;p&gt;다음 글에서는 CNN기반 이상데이터 분류에 대해 다루어 보도록 하겠습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;reference&quot;&gt;Reference&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://ratsgo.github.io/generative%20model/2017/12/17/compare/&quot;&gt;https://ratsgo.github.io/generative%20model/2017/12/17/compare/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://learnopencv.com/generative-and-discriminative-models/&quot;&gt;https://learnopencv.com/generative-and-discriminative-models/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dreamgonfly.github.io/2018/03/17/gan-explained.html&quot;&gt;https://dreamgonfly.github.io/2018/03/17/gan-explained.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.semanticscholar.org/paper/Generative-adversarial-networks-(GAN)-based-of-for-Dan-Zhao/5342490c6de6e262f3cd3c960c1785d476146c0e&quot;&gt;Dan, Y., Zhao, Y., Li, X., Li, S., Hu, M., &amp;amp; Hu, J. (2020). Generative adversarial networks (GAN) based efficient sampling of chemical composition space for inverse design of inorganic materials. npj Computational Materials, 6, 1-7.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://arxiv.org/pdf/1805.06725v1.pdf&quot;&gt;Akçay, S., Atapour-Abarghouei, A., &amp;amp; Breckon, T. (2018). GANomaly: Semi-Supervised Anomaly Detection via Adversarial Training. ACCV.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/leafinity/keras_ganomaly&quot;&gt;https://github.com/leafinity/keras_ganomaly&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 05 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/07/05/Anomaly-detection-using-GAN.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/07/05/Anomaly-detection-using-GAN.html</guid>
        <tags>
          
          <tag>Anomaly detection</tag>
          
          <tag>GAN</tag>
          
          <tag>TensorFlow</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>ICT 인턴십 후기</title>
        <authors>
          
          
          <author>
            <name>임혜민</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Maem.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-06-30-ict-intern-maem/1.png</thumbnail>
        <description>&lt;h1 id=&quot;ict-인턴십-후기&quot;&gt;ICT 인턴십 후기&lt;/h1&gt;

&lt;p&gt;안녕하세요. &lt;strong&gt;너드팩토리&lt;/strong&gt;에서 2021년도 상반기 &lt;strong&gt;ICT 인턴십&lt;/strong&gt;에 참가한 &lt;strong&gt;맴&lt;/strong&gt; 입니다.&lt;/p&gt;

&lt;p&gt;4개월간의 &lt;strong&gt;ICT 인턴십&lt;/strong&gt;이 끝났습니다. 너드팩토리에서의 하루하루는 매번 새로웠고, 자유롭게 도전할 수 있는 분위기였습니다. &lt;strong&gt;제가 꿈꾸던 분위기의 회사였죠.&lt;/strong&gt; 사람들은 자유분방하고 열정이 넘쳤고, 그런 분위기 속에서 저는 좋은 경험들을 할 수 있었습니다. 😉&lt;/p&gt;

&lt;p&gt;이번 블로그에서는 짧다면 짧고, 길다면 길었던 4개월간의 경험들을 바탕으로 제가 인턴십 과정을 통해 무엇을 배우고 느꼈는지를 공유하고자 합니다.&lt;/p&gt;

&lt;h3 id=&quot;지원-계기&quot;&gt;지원 계기&lt;/h3&gt;

&lt;p&gt;올해 초, 저는 휴학을 할 계획이었습니다. 막상 휴학을 신청했지만, 계속되는 코로나로 어디론가 떠난다는 것조차 불투명했습니다. 그러던 와중, ‘&lt;strong&gt;&lt;em&gt;인턴을 해볼까&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;‘&lt;/em&gt;라는 생각이 들었고, 무작정 3학년을 막 마친 학생이 할 수 있는 인턴을 찾기 시작했습니다. 그렇게 알게된 &lt;strong&gt;ICT 인턴십은 학점을 받으면서 인턴을 할 수 있다는 점이 굉장히 매력적으로 다가왔습니다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;인턴십 공고를 본 당일, 바로 자기소개서와 포트폴리오를 작성했고, 세 군데의 기업에 지원을 했습니다. 저는 단순히 개발뿐 아니라 &lt;strong&gt;IT 서비스 기획&lt;/strong&gt;의 직무가 궁금했기 때문에 IT 관련 다양한 업무를 경험해볼 수 있는 회사에 지원했습니다.&lt;/p&gt;

&lt;p&gt;일주일 후, 차례로 세 군데의 기업에서 면접을 보았고, 결과적으로 &lt;strong&gt;(주)플랜아이&lt;/strong&gt;에서 ICT 인턴십을 수행하기로 결정하게 되었습니다. 휴학을 하려던 저의 상반기 계획이 ICT 인턴십으로 바뀌게 된 것입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/0.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/0.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;플랜아이와 ICT 인턴으로 매칭되었다.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;매칭이 되고 바로 다음주부터 출근을 해야 하는 빡빡한 일정이었지만, 출근을 앞둔 주말에 부모님과 회사를 미리 가보기도 하면서 설레었던 기억이 납니다. 인생 첫 인턴을 앞두고 느꼈던 설렘은 잊을 수 없습니다. ☺️&lt;/p&gt;

&lt;h3 id=&quot;두근두근-첫-날&quot;&gt;두근두근 첫 날&lt;/h3&gt;

&lt;p&gt;출근 첫 날이 기억에 납니다. 버스 배차간격이 20분이나 되는 줄도 모르고 나왔다가 지각하는 줄 알고 식은땀을 흘리던 그 날. 제 속도 모르고 천천히 가는 버스 안에서 오만가지 생각이 다들었습니다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;‘첫 날부터 지각하는 인턴이라니..’&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;정말 다행히 9시 전에 회사에 도착할 수 있었고, 저를 담당해주시는 에드워드님을 만나 함께 3층 사무실로 올라갔습니다. 어색한 분위기 속에 마주한 책상에서 앞으로의 4개월이 어떨지 기대와 걱정이 몰려왔습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/1.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/1.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;내 자리 노트북, 모니터, 키보드&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;걱정도 잠시, 바로 너드팩토리에서 사용하는 notion과 slack 계정을 부여 받으면서 책임감이 생겼습니다. 맡은 일을 잘 해내야겠다는 책임감은 인턴기간 동안 꾸준히 자기계발을 할 수 있는 원동력이 되었습니다.&lt;/p&gt;

&lt;p&gt;첫 날 오후에는 너드팩토리 구성원들 모두가 &lt;strong&gt;몰디브&lt;/strong&gt;에 모여 &lt;strong&gt;아이스브레이킹&lt;/strong&gt;을 했습니다. 알고 보니 새로 사람이 올 때마다 나이 순서 맞추기를 진행하는 문화가 있었는데, 얼굴도, 이름도 익숙치 않은데 나이 순서를 맞추라고 하니 난감 했던 기억이 납니다. 😵 ㅋㅋ &lt;del&gt;나중에 누군가 너드팩토리에 입사하게 되면 나이맞출 각오? 하세요…&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;그래도 이 시간 이후로 조금은 사람들 얼굴을 익히고 이름을 외우는게 수월했습니다. 조금은 너드팩토리 구성원들과 가까워진 시간 아니었을까 싶습니다~ ㅎㅎ&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/2.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/2.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;자주 사용한 회의실, 몰디브&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;팀-배정&quot;&gt;팀 배정&lt;/h3&gt;

&lt;p&gt;현재 너드팩토리는 사인스쿼드와 보리스쿼드로 구성되어 있습니다. 사인스쿼드에서는 정부과제 사업계획서 작성 등 연구과제 기획과 관련된 업무를 수행하였고, 보리스쿼드에서는 서비스 기획 업무에 참여하였습니다. 스쿼드 별로 하는 일이 분리가 되어 있어 혼동도 있었지만, 동료들이 도와준 덕분에 잘 적응할 수 있었습니다.&lt;/p&gt;

&lt;h3 id=&quot;너드팩토리-그곳이-알고싶다&quot;&gt;너드팩토리, 그곳이 알고싶다&lt;/h3&gt;

&lt;p&gt;(주)플랜아이의 기업부설연구소인 너드팩토리에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;애자일 방법론&lt;/code&gt;으로 일하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/3.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/3.png&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;애자일 방법론&lt;/code&gt;이란, 소프트웨어 개발 방법에서 아무런 계획이 없는 개발 방법과 계획이 지나치게 많은 개발 방법들 사이에서 &lt;strong&gt;타협점&lt;/strong&gt;을 찾고자 하는 방법론 입니다&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;너드팩토리는 &lt;strong&gt;데일리 스크럼&lt;/strong&gt;을 통한 업무 공유로 서로의 업무를 빠르게 알고 협업을 좀 더 유기적으로 진행합니다. 자신의 업무를 공유 함으로써 책임감이 생기고, 자기계발을 할 수 있는 동기부여가 됩니다. 의사소통은 &lt;strong&gt;노션&lt;/strong&gt;과 &lt;strong&gt;슬랙&lt;/strong&gt;, &lt;strong&gt;제플린&lt;/strong&gt; 등 협업 툴을 사용해 효과적으로 진행합니다.&lt;/p&gt;

&lt;!-- {:.center}
![/assets/images/posts/2021-06-30-ict-intern-maem/4.png](/assets/images/posts/2021-06-30-ict-intern-maem/4.png)

{:.center}
![/assets/images/posts/2021-06-30-ict-intern-maem/5.png](/assets/images/posts/2021-06-30-ict-intern-maem/5.png) --&gt;

&lt;p&gt;또, 너드팩토리에서는 서로 영어이름을 부르며 자유롭게 의사소통을 합니다. 직급과 계급이 없는 수평조직으로 모두가 자유롭게 생각을 말할 수 있습니다. 😉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;보리 스쿼드&lt;/strong&gt;의 경우 프론트엔드 개발자, 백엔드 개발자, AI 개발자, 프로덕트 디자이너, 그리고 프로덕트 오너로 구성되어 있습니다. G의 구o애널리틱스나 F사의 뷰oo 같은 웹사이트 분석 및 최적화 도구인 &lt;strong&gt;VODA&lt;/strong&gt;가 개발되고 있는 시점에 인턴으로 오게 된 저는, 같이 일하면서 각각의 역할이 어떤 일을 하고 어떻게 소통하고 협업 하는지를 알 수 있었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/6.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/6.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;업무는 &lt;strong&gt;스프린트&lt;/strong&gt; 단위로 진행됩니다. 스프린트는 주로 일주일에서 길게는 10일 단위로 나뉩니다. 매번 스프린트가 완료될 때마다 노션에 업무를 공유하고, 리뷰를 진행합니다. 회의를 통해 서로의 업무 진행 현황을 파악하고, 개발자간의 소통, 개발자와 디자이너 사이의 소통 등 여러 역할 간의 소통이 이루어지는 것입니다.&lt;/p&gt;

&lt;p&gt;매주 서비스가 한 단계 업그레이드 되는 모습을 보면서, 감탄에서 그치지 않고 더 좋은 서비스가 되도록 다같이 고민하고 개선해나가는 시간이 저에게는 큰 경험이 되었습니다. 서비스의 론칭 프로세스를 알게 되었고 서비스 기획을 배울 수 있었습니다.&lt;/p&gt;

&lt;h3 id=&quot;무엇을-했는가&quot;&gt;무엇을 했는가&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;In 사인스쿼드&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;처음에 에드워드님께서 ‘기획’을 처음 접하는 제게 권해주신 책이 바로 &lt;strong&gt;“모든 기획자와 디자이너가 알아야 할 사람에 대한 100가지 사실”&lt;/strong&gt; 입니다. 어떤 식으로 서비스를 기획 하는지 막연했던 저에게 기획에 앞서 사람을 알아야 함을 깨우쳐 준 책입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/7.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/7.png&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/8.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/8.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 책에 관련해서 각 챕터별로 리뷰를 남겨 보고서를 작성했고, 처음으로 팀원들 앞에서 책 리뷰와 더불어 제 의견을 발표하게 된 주제였습니다.&lt;/p&gt;

&lt;p&gt;그리고 AI 관련 서비스 기획을 목표로 하면서 &lt;strong&gt;AI 기사리포팅&lt;/strong&gt;을 통해 기술에 대한 이해와 현황을 살펴보기도 했습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/9.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/9.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;AI 기사리포팅&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;이 후, 지디웹서비스 코리아의 웹 어워즈들을 벤치마킹 하여 기존에 있던 서비스를 개선해보자는 주제로 프로젝트를 진행했습니다. 저는개선할 앱으로 &lt;strong&gt;“오늘의집”&lt;/strong&gt; 을 선택하여 장단점을 분석한 다음 UX 디자인을 바꿔 보았습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/10.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/10.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;해당 발표에서 A/B 테스트를 통해 변경한 내용이 어떤 개선 효과가 있었는지 볼 수 있다면 좋겠다는 피드백을 받았고, 이후에 A/B 테스팅에 대해 공부하게 된 계기가 되었습니다. 또한, 단순히 “이렇게 바꾸면 더 좋겠다”라는 추상적인 생각에 근거한 기획이 아닌, &lt;strong&gt;데이터 기반&lt;/strong&gt;의기획에 대해 생각해보게 되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In 보리스쿼드&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;보리스쿼드에서는 현재 개발이 한창 진행중인 &lt;strong&gt;VODA&lt;/strong&gt;의 서비스 기획에 참여하게 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VODA&lt;/strong&gt;는 기업의 데이터 트랜스포메이션을 도와줄 웹사이트 분석 및 최적화 도구로, 구o애널리틱스와 뷰oo의 장점을 융합하여 데이터를 기반의 서비스 운영에 대한 인사이트 제공을 목적으로 개발되고 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/14.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/14.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;VODA 관련 신규 기능의 기획에 앞서 뉴비 기획자인 저에게 먼저 주어진 일은 지금까지 개발된 &lt;strong&gt;VODA&lt;/strong&gt; 기능들을 &lt;strong&gt;와이어프레임&lt;/strong&gt;으로 작성하는 연습이었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;와이어프레임&lt;/strong&gt;이란, 화면 청사진이라고도 하며, &lt;strong&gt;선(Wire)&lt;/strong&gt;으로 &lt;strong&gt;틀(Frame)&lt;/strong&gt;을 잡는다는 뜻으로 화면단위의 레이아웃을 설계하는 작업을 말합니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;건축에서 설계도면을 그리듯, 서비스를 개발하기 앞서 와이어프레임을 그려야 합니다. 전통적인 기획과는 다르게현재는 디자이너와의 유연한 소통을 위한 도구ㅇ로 Figma 등의 UI 디자인 툴을 와이어프레임 작성에 이용하기도 합니다. 저는 Figma를 사용하여 UI 레이아웃의 흐름과 각 화면의 설명을 상세히 작성해보았고, VODA의 전반적인 서비스 흐름을 파악하는데 도움이 되었습니다. 서비스 기획자로서 한 발짝 성장하는 느낌을 받았습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/15.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/15.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;수 많은 연습 끝에 figma를 능숙하게 다룰 수 있게 되었고, &lt;strong&gt;VODA&lt;/strong&gt; 라이센스 관리 등이 가능한 서비스 관리자페이지의 기획을 다니엘님과 함께 진행하게 되었습니다.&lt;/p&gt;

&lt;p&gt;먼저 서비스에 필요한 기능들을 정의하기 위해 실제 서비스 관리자 페이지를 사용하게 될 운영팀의 needs를 수집하였고, 서비스 사용을 가정했을 때 필요한 기능들의 ideation을 진행하였습니다. 이후에 서비스 운영을 위한 주요 기능들을 선정 및 분류하였고, 주요 기능별로 구체적인 서비스 흐름을 작성하고 후에 이를 합치는 형태로 UX 흐름을 완성하였습니다. 이 때, 서비스의 흐름을 어떻게 시각화 할지에 대해 고민을 거듭해보면서 여러 경우의 수를 빠짐없이 그릴 수 있었습니다. 또한, 기능들의 정책 설정 과정에서도 &lt;strong&gt;&lt;em&gt;그냥 이럴 것 같아~&lt;/em&gt;&lt;/strong&gt; 가 아닌 &lt;strong&gt;데이터가 기반&lt;/strong&gt;이 되어야 한다는 것을 배울 수 있었습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VODA&lt;/strong&gt; 서비스의 핵심 중 하나인 &lt;strong&gt;리포팅&lt;/strong&gt; 의 일부 기능에 대한 기획도 경험하게 되었습니다.&lt;/p&gt;

&lt;p&gt;리포팅할 부분을 골라 기준 별로 세세하게 나누고, 그 안에서도 또 다른 기준을 세우는 과정에서 어려움이 많았지만, 데이터를 기반으로 최선의 기획을 해야된다는 고민을 거듭했습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/16.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/16.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 외에도 부사장님께서 요청하신 웹사이트 UX 벤치마킹을 통해 서비스 기획 직무를 경험할 수 있었습니다. 또, 요즘 핫하다는 리액트를 배워보고 싶어 주말에 나와 준님에게 배우기도 했는데, 간단하게 웹페이지를 제작해보기도 했습니다. 앞으로 더 해보면서 어떤 분야로 쭉 나아갈지 고민해보고 결정하게되겠죠. 🤔&lt;/p&gt;

&lt;p&gt;너드팩토리에서의 인턴생활은 제 진로에 대한 방향성을 찾을 수 있게 이끌어줬습니다. 이곳에는 프론트, 백엔드, AI 개발자, 그리고 디자이너, PO 등 글로만 보던 각 직군들이 눈앞에 있기 때문에 많이 물어볼 수 있었습니다. 어디서도 쉽게 얻을 수 없는 경험이었지요. 진짜 다들 감사했습니다. 😎&lt;/p&gt;

&lt;h3 id=&quot;마지막-인사&quot;&gt;마지막 인사&lt;/h3&gt;

&lt;p&gt;이곳 너드팩토리의 구성원들은 자기계발에 소홀한 사람 없이 다들 목표의식을 갖고 열정적으로 일합니다. 옆에서 보면서 정말 많이 배울 수 있는 환경이라고 생각합니다. 본인의 커리어를 확장 시키려는 열정 있는 사람들이 모인 만큼 분위기가 좋습니다. 특히, 회사 내의 다른 부서와는 다른 자유로운 분위기로 스타트업 같기도 해 즐겁게 인턴생활을 할 수 있었습니다. 😆&lt;/p&gt;

&lt;p&gt;생일날에 깜짝 축하파티를 해준 사람들, 문지동, 전민동의 여러 맛집들을 다니던 나날들, 지금까지 마신 아메리카노의 컵홀더로 쌓았던 탑들, 함께 수다떨던 동료들. 모두 다 잊지 못할 것 같아요. 너무나도 행복했던 인턴생활 보낼 수 있게 도와주셔서 감사했고, 앞으로도 너드팩토리의 성공을 응원하겠습니다!&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/11.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/11.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;그리울거에요..사무실.&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/12.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/12.png&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/13.png&quot; alt=&quot;/assets/images/posts/2021-06-30-ict-intern-maem/13.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;비와이이&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 30 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/06/30/ict-intern-maem.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/06/30/ict-intern-maem.html</guid>
        <tags>
          
          <tag>ICT 인턴십</tag>
          
          <tag>인턴</tag>
          
          <tag>어시스턴트</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>정규화 정리1 - Scaling, Regularization, Standardization</title>
        <authors>
          
          
          <author>
            <name>이유나</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Ella.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-07-01-Normalization-Theorem-1/0.png</thumbnail>
        <description>&lt;h2 id=&quot;개요&quot;&gt;개요&lt;/h2&gt;

&lt;p&gt;정규화 관련 정보들을 검색하다보면, 단어들이 혼재되어 사용되기 때문에 처음 보거나 오랜만에 보면 헷갈릴 수 있습니다.&lt;/p&gt;

&lt;p&gt;또한 사람들마다 조금씩 용어를 다르게 정의하고 있기도 합니다.&lt;/p&gt;

&lt;p&gt;이러한 상황에서 혼동되는 용어와 해석의 차이 때문에 헤매게 되는 시간을 줄이고자, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;관련 용어&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;정의&lt;/code&gt;에 대해 큰 틀에서 가볍게 훑고 가 보자는 취지에서 이번 글을 작성하게 되었습니다.&lt;/p&gt;

&lt;p&gt;(정규화 방법에 대한 설명과 계산 과정 등 생략 된 부분들은 이후 추가로 업로드 할 예정입니다.)&lt;/p&gt;

&lt;h1 id=&quot;본문&quot;&gt;본문&lt;/h1&gt;

&lt;h2 id=&quot;용어의-일반적인-정의&quot;&gt;용어의 일반적인 정의&lt;/h2&gt;

&lt;p&gt;이번 포스팅에선 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scaling&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Standardization&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regularization&lt;/code&gt; 에 대해서 짚고 넘어가보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;( Normalization 은 내용이 방대하고, 한번에 너무 많은 내용을 담으면 혼동이 올 수 있어서, 다음 포스팅에서 설명 하려고 합니다. )&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Scaling:&lt;br /&gt;
일반적으로 데이터의 범위를 임의로 조정하는 것을 의미합니다.&lt;/strong&gt;&lt;br /&gt;
데이터 분포의 모양은 변하지않고 기존 데이터와 동일한 비율을 유지한 채 범위를 조정합니다.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/0.png&quot; alt=&quot;0.png&quot; /&gt;&lt;br /&gt;
 &lt;em&gt;출처: &lt;a href=&quot;https://towardsdatascience.com/all-about-feature-scaling-bcc0ad75cb35&quot; target=&quot;\_blank&quot; class=&quot;markdown-link-caption&quot;&gt;towardsdatascience&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Standardization:&lt;br /&gt;
일반적으로 평균으로 구한 분포의 표준 편차를 1로 맞추기 위해 데이터를 바꾸는 것을 의미합니다.&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;각 feature 간의 상대적 거리를 왜곡시킬 수 있는 점을 고려하여 사용해야 합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/1.png&quot; alt=&quot;1.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;출처: &lt;a href=&quot;https://towardsdatascience.com/normalization-vs-standardization-quantitative-analysis-a91e8a79cebf&quot; target=&quot;\_blank&quot; class=&quot;markdown-link-caption&quot;&gt;towardsdatascience&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Regularization:&lt;br /&gt;
일반적으로 가중치를 조정할 때 추가적인 제약을 주는 것을 의미합니다.&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/2.png&quot; alt=&quot;2.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;용어-설명&quot;&gt;용어 설명&lt;/h2&gt;

&lt;h3 id=&quot;scaling&quot;&gt;Scaling&lt;/h3&gt;

&lt;p&gt;사용 목적은 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;독립된 여러 개의 변수를 사용할 때 각 변수 별로 단위가 다를 경우, 학습 시에 미치는 중요도가 달라지는 문제를 방지할 수 있습니다.&lt;/p&gt;

    &lt;p&gt;(ex. 키와 나이 변수를 사용할 때, 키 변수가 학습에 더 큰 영향을 끼치는 문제가 발생합니다.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;경사 하강법과 같은 방법론을 사용할 때 수렴 속도를 높여줍니다.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;신경망에서 시그모이드 함수와 같은 활성 함수를 사용할 때, saturation현상이 빨리 일어나지 않도록 도와줍니다.&lt;/p&gt;

    &lt;p&gt;(&lt;a href=&quot;https://nittaku.tistory.com/267&quot;&gt;*참고: saturation 현상 관련 글&lt;/a&gt;)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;딥러닝에서 Local Minimum에 빠질 위험을 감소 시켜줍니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;대표적으로 사용하는 기법들은 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Min Max&lt;/li&gt;
  &lt;li&gt;Max Abs&lt;/li&gt;
  &lt;li&gt;Robust&lt;/li&gt;
  &lt;li&gt;Standard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;( 그러나 Robust, Standard 두 스케일러의 경우 용어 정리에서 제시한  scaling의 조건을 온전히 충족하지 못합니다. )&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Min Max Scaling&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 최소 값은 0 최대 값은 1으로, 모든 데이터가 [0, 1] 범위안에 들어가도록 조절하는 기법입니다.&lt;/p&gt;

&lt;p&gt;= Min max normalization, Rescaling, 최소 최대 정규화, Scaling, Normalization&lt;/p&gt;

&lt;p&gt;( 협업 할 때 Scaling, Normalization과 같이 포괄적인 단어 사용은 지양하는 것을 추천합니다. )&lt;/p&gt;

&lt;p&gt;$x_{new} = \frac{x - x_{min}}{x_{max} - x_{min}}$&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pandas&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;166&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;158&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;182&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;161&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;155&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'height'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'age'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 시각화
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Origin Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Scaled Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdvnQV/btq8ppRFJX6/QKfPoBD7YapkeBj6ottcVK/img.png&quot; alt=&quot;https://blog.kakaocdn.net/dn/cdvnQV/btq8ppRFJX6/QKfPoBD7YapkeBj6ottcVK/img.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/3.png&quot; alt=&quot;3.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Max Abs&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 절댓값이 가장 큰 수의 절대값으로 전체를 나누어 모든 데이터의 범위를 [-1, 1 ]으로 조절하는 기법입니다.&lt;/p&gt;

&lt;p&gt;$x_{new} = \frac{x}{\left\vert x \right\vert_{max}}$&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pandas&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'sight'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'age'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 시각화
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Origin Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Scaled Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;df_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0kAoS/btq8s6R60BQ/EQrIARjZhetNHufzQpFKpk/img.png&quot; alt=&quot;https://blog.kakaocdn.net/dn/b0kAoS/btq8s6R60BQ/EQrIARjZhetNHufzQpFKpk/img.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/4.png&quot; alt=&quot;4.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Robust&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 중앙값과 IQR을 활용하여 아웃라이어의 영향을 적게 받는 것이 특징인 기법입니다.&lt;/p&gt;

&lt;p&gt;( 단, 미리 결정된 범위로 조정하는 것이 아니기 때문에 앞에서 정의한 Scaling의 조건을 온전히 만족하지 못합니다. )&lt;/p&gt;

&lt;p&gt;$x_{new} = \frac{x-x_{median}}{IQR}$&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Standard&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 아래의 Z-Score Normalization와 같은 기법입니다.&lt;/p&gt;

&lt;p&gt;( Robust와 같은 이유로 scaling이라고 보기에는 어려움이 있고, Standardization으로 구분하여 지칭하는 것을 추천드립니다. )&lt;/p&gt;

&lt;h3 id=&quot;standardization&quot;&gt;Standardization&lt;/h3&gt;

&lt;p&gt;사용 목적은 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;정규분포를 표준 정규분포로 변환시켜주어 서로 다른 자료들을 쉽게 비교 분석할 수 있도록 만들어 줍니다.&lt;/li&gt;
  &lt;li&gt;모든 정규 분포에 대한 확률을 쉽게 구할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;딥러닝 알고리즘에서 (특히 회귀 타입의 모델을 사용할 때), zero mean and unit variance 데이터를 필요로 하는 경우에도 종종 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;( &lt;a href=&quot;https://datascience.stackexchange.com/questions/32109/zero-mean-and-unit-variance&quot;&gt;*참고: why it’s important to give the features zero mean and unit variance?&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Standardization&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 데이터를 평균 0, 표준편차 1인 표준정규분포로 만들어주는 기법입니다.&lt;/p&gt;

&lt;p&gt;= Z-Score Normalization, 표준화, 일반화, Z-점수 정규화&lt;/p&gt;

&lt;p&gt;$x_{new} = \frac{x-mean}{std}$&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://youtu.be/2tuBREK_mgE&quot;&gt;*참고: z-score 개념 관련 영상&lt;/a&gt;)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pandas&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.datasets&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_iris&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;iris_arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_iris&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;iris_df_standarded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 시각화
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Origin Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Standarded Dataset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df_standarded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iris_df_standarded&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/da2rLU/btq8q1K4ff8/VK4T1yEhWF5sYubdRevBd1/img.png&quot; alt=&quot;https://blog.kakaocdn.net/dn/da2rLU/btq8q1K4ff8/VK4T1yEhWF5sYubdRevBd1/img.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/5.png&quot; alt=&quot;5.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;regularization&quot;&gt;Regularization&lt;/h3&gt;

&lt;p&gt;사용 목적은 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;학습 데이터에 대한 민감도를 낮춰줍니다.&lt;/li&gt;
  &lt;li&gt;(결과적으로) 과적합을 방지하기 위해 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;대표적으로 사용하는 기법은 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ridge&lt;/li&gt;
  &lt;li&gt;Lasso&lt;/li&gt;
  &lt;li&gt;Elastic Net&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Ridge&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; L2 norm을 사용하여 가중치에 규제를 가하는 기법입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 가장 일반적으로 사용되는 기법으로, 변수간 상관관계가 높아도 좋은 성능을 보이고, 크기가 큰 변수를 우선적으로 줄이는 것이 특징입니다.&lt;/p&gt;

&lt;p&gt;= L2 regularization, L2 정칙화, L2 규제, 릿지, Normalization&lt;/p&gt;

&lt;p&gt;( 그러나, Normalization과 같이 포괄적인 단어 사용은 지양하는 것을 추천합니다. )&lt;/p&gt;

&lt;p&gt;$f(Cost) = f(Loss) + \Lambda\sum{w}^2$&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/6.png&quot; alt=&quot;6.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/7.png&quot; alt=&quot;7.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/8.png&quot; alt=&quot;8.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Lasso&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; L1 norm을 사용하여 가중치에 규제를 가하는 기법입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 변수 선택이 가능하고, 비중요 변수를 우선적으로 줄이는 것이 특징입니다.&lt;/p&gt;

&lt;p&gt;= L1 regularization, L1 정칙화, L1 규제, 라쏘&lt;/p&gt;

&lt;p&gt;$f(Cost) = f(Loss) + \Lambda\sum{\left\vert w \right\vert}$&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/9.png&quot; alt=&quot;9.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/7.png&quot; alt=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/7.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7AWDt/btq8s6kny29/IRiKc8ysrrNNKQKv4Kzsc0/img.png&quot; alt=&quot;https://blog.kakaocdn.net/dn/7AWDt/btq8s6kny29/IRiKc8ysrrNNKQKv4Kzsc0/img.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Elastic Net&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; Ridge와 Lasso 두 방법론을 혼합한 유형입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;:&lt;/strong&gt; 변수 선택이 가능하고, 상관관계가 큰 변수를 동시에 선택하고 배제 있는 것이 특징입니다.&lt;/p&gt;

&lt;p&gt;= 엘라스틱 넷&lt;/p&gt;

&lt;p&gt;$f(Cost) = f(Loss) + \Lambda\sum{w^2} + \Lambda\sum{\left\vert w \right\vert}$&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/10.png&quot; alt=&quot;10.png&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;적용 예시&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/7.png&quot; alt=&quot;/assets/images/posts/2021-07-01-Normalization-Theorem-1/7.png&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u0X3k/btq8q1RUKlw/Il4tIWyWqvPegagGuBk7l0/img.png&quot; alt=&quot;https://blog.kakaocdn.net/dn/u0X3k/btq8q1RUKlw/Il4tIWyWqvPegagGuBk7l0/img.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;추가적으로 자주 사용되는 Regularization 기법들 아래와 같습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;Fused Lasso&lt;/em&gt;&lt;/strong&gt;: 인접한 변수들을 동시에 선택하는 정칙화 기법입니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;Group Lasso&lt;/em&gt;&lt;/strong&gt;: 사용자가 정의한 그룹 단위로 변수를 선택하는 정칙화 기법입니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;em&gt;Graph Constrained Regularization&lt;/em&gt;&lt;/strong&gt;: 사용자가 정의한 그래프의 연결관계에 따라 변수를 선택하는 정칙화 기법입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;reference&quot;&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://sebastianraschka.com/Articles/2014_about_feature_scaling.html#about-standardization&quot;&gt;https://sebastianraschka.com/Articles/2014_about_feature_scaling.html#about-standardization&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://towardsdatascience.com/scale-standardize-or-normalize-with-scikit-learn-6ccc7d176a02&quot;&gt;https://towardsdatascience.com/scale-standardize-or-normalize-with-scikit-learn-6ccc7d176a02&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://medium.com/@isalindgren313/transformations-scaling-and-normalization-420b2be12300&quot;&gt;https://medium.com/@isalindgren313/transformations-scaling-and-normalization-420b2be12300&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://towardsdatascience.com/all-about-feature-scaling-bcc0ad75cb35&quot;&gt;https://towardsdatascience.com/all-about-feature-scaling-bcc0ad75cb35&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.analyticsvidhya.com/blog/2017/06/a-comprehensive-guide-for-linear-ridge-and-lasso-regression/&quot;&gt;https://www.analyticsvidhya.com/blog/2017/06/a-comprehensive-guide-for-linear-ridge-and-lasso-regression/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://towardsdatascience.com/regularization-the-path-to-bias-variance-trade-off-b7a7088b4577&quot;&gt;https://towardsdatascience.com/regularization-the-path-to-bias-variance-trade-off-b7a7088b4577&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/06/15/Normalization-Theorem-1.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/06/15/Normalization-Theorem-1.html</guid>
        <tags>
          
          <tag>Pytorch</tag>
          
          <tag>VODA</tag>
          
          <tag>statistics</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>You Only Look Once. YOLO</title>
        <authors>
          
          
          <author>
            <name>조현준</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/Owen.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/yolo.png</thumbnail>
        <description>&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/yolo.png&quot; alt=&quot;yolo&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;머리&quot;&gt;머리&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;흔히 &lt;strong&gt;YOLO(욜로)&lt;/strong&gt;라고 하면 &lt;strong&gt;You only Live Once&lt;/strong&gt; 의 약자로 ‘인생은 오직 한번뿐’ 이라는 의미로 자유로운 라이프 스타일을 나타냅니다😎&lt;/p&gt;

&lt;p&gt;하지만 이 포스팅에서는 조금 다른 YOLO를 다룹니다. ‘You Only &lt;strong&gt;Look&lt;/strong&gt; Once.’ 즉 한번에 보고 바로 처리를 하겠다. 라는 속도가 빠르다는 장점을 내세운 Object Detection 신경망 입니다. YOLO는 yolov1부터 2020년 7월 기준으로 yolov5 까지 공개되어 개발자분들 뿐만 아니라 비전공자들부터 학생들까지, 많은 사람들이 인용하여 활용 및 연구중입니다. 이번 포스팅에서는 YOLOv1부터 YOLOv2까지 모델 구조와 특징들에 대해 차근차근 설명해보려고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;가슴&quot;&gt;가슴&lt;/h1&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;yolov1&quot;&gt;YOLOv1&lt;/h2&gt;

&lt;p&gt;기존의 Object Detection은 single window나 regional proposal methods등을 통해 바운딩 박스를 잡은 후 탐지된 바운딩 박스에 대해 분류 수행하는 2 stage detection 으로, image detection을 완료하는 알고리즘을 통해 진행되었습니다. 파이프라인이 복잡하기 때문에 당연히 학습과 예측이 느려지고 최적화도 느려집니다.
YOLOv1은 하나의 컨볼루션 네트워크를 통해 대상의 위치와 클래스를 한번에 예측합니다.
&lt;em&gt;(한 번만에 image detection을 할 수 있는 1 stage detection 알고리즘)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;YOLO가 등장했을 당시 장점으로 주목을 받았던 내용들입니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;학습 파이프라인이 기존의 detection 모델들에 비해 간단하기 때문에 학습과 예측의 속도가 빠르다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;모든 학습 과정이 이미지 전체를 통해 일어나기 때문에 단일 대상의 특징뿐 아니라 이미지 전체의 맥락을 학습하게 된다.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;대상의 일반적인 특징을 학습하기 때문에 다른 영역으로의 확장에서도 뛰어난 성능을 보인다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;yolo-모델의-구조&quot;&gt;YOLO 모델의 구조&lt;/h3&gt;

&lt;p&gt;테두리상자 조정 (Bounding Box Coordinate)과 분류(Classification)를 동일 신경망 구조를 통해 동시에 실행하는 통합인식(Unified Detection)을 구현하는 큰 특징을 가지고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;이미지를 SxS 의 그리드로 분할합니다. (논문에서는 S = 7로 예시를 두었습니다.)&lt;/li&gt;
  &lt;li&gt;이미지 전체를 신경망에 넣고 특징 추출을 통해 예측 텐서(Prediction Tensor) 생성합니다.
&lt;em&gt;여기서 예측 텐서는 그리드 별 테두리상자 정보, 신뢰 점수, 분류 클래스 확률을 포함합니다.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;그리드 별 예측 정보를 바탕으로 테두리 상자 조정 및 분류 작업 수행합니다.&lt;/li&gt;
  &lt;li&gt;각각의 Grid cell 은 B개의 Bounding Box와 각 Bounding box에 대한 Confidence-Score를 가집니다.
&lt;strong&gt;Confidence-Score :&lt;/strong&gt; $Pr(Object) * IOU$&lt;/li&gt;
  &lt;li&gt;각각의 Grid cell 은 C개의 Conditional Class Probability를 가집니다.&lt;/li&gt;
  &lt;li&gt;각각의 Bounding box는 x, y좌표, w, h, confidence를 지닙니다.
(x, y) : Bounding box의 중심점을 의미하며 grid cell 범위에 대한 상대 값
(ex) x가 grid cell 가장 왼쪽, y가 grid cell 중간에 있다면 x=0, y=0.5&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;yolov1-network&quot;&gt;YOLOv1 Network&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled1.png&quot; alt=&quot;Untitled%201&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled2.png&quot; alt=&quot;Untitled%202&quot; /&gt;&lt;/p&gt;

&lt;p&gt;논문의 YOLO Network&lt;/p&gt;

&lt;p&gt;Inception 블럭 대신 단순한 224x224 크기의 ImageNet Classification으로 pretrain을 진행했습니다. 이후 448x448 이미지를 input image로 받아 24개의 Conv Layer 중 앞의 20개의 컨볼루션 레이어는 고정한 채 뒷 단의 4개의 레이어와 2개의 Fully Connected Layer만 object detection task에 맞게 학습하게 됩니다. 이후 예측 텐서(Prediction Tensor)를 뽑아내게 됩니다. 이것을 바탕으로 디텍션 및 분류작업을 수행하게 됩니다.&lt;/p&gt;

&lt;p&gt;이제 네트워크의 출력인 Conv Layer, FC Layer를 통과한 Prediction Tensor (7 x 7 x 30) 피쳐맵에 대해서 알아보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled3.png&quot; alt=&quot;Untitled%203&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위의 그림에서는 Prediction Tensor가&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SxSx(Bx5+C)&lt;/code&gt;와 같이 되어 있습니다. 위에서 알 수 있듯이 YOLO 논문에서는 S의 크기를 7로 명시한 것을 알 수 있습니다. 7x7은 그리드의 숫자를 의미하며 7x7의 그리드 별로 30의 길이를 가지는 값을 의미하게 됩니다.&lt;/p&gt;

&lt;p&gt;그럼&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(Bx5+C)&lt;/code&gt;는 어떻게 나왔을까요?
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;는 각각의 그리드별로 갖는 Bounding Box 후보의 개수를 나타냅니다. (논문에서는 2개씩 가지겠다. 라고 설정을 했죠) 이것은 다시 말해 하나의 그리드 안에 (x, y)가 위치해있는(바운딩 박스의 중앙점이 위치해있는) 바운딩 박스들을 2개를 선정하겠다는 말이 됩니다.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5&lt;/code&gt; 라는 값은 x, y, w, h, confidence score 의 의미를 갖습니다.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;는 클래스의 개수를 나타내며 20개의 클래스를 갖습니다.&lt;/p&gt;

&lt;p&gt;자, 이제 정리를 해보면 Image → CNN → FC → PT(Prediction Tensor) 과정을 거치게 되고 이 과정으로 PT를 뽑아내는데, Conv Layer, FC Layer를 통과한 PT에 대해서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;30(PT) = 5(x,y,w,h,confidence score) x 2(bounding box) + 20(ImageNet 클래스 개수)&lt;/code&gt;과 같이 말할 수 있으며, 이 PT 바탕으로 값을 조정하여 학습을 한다. 라고 할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;loss&quot;&gt;Loss&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled4.png&quot; alt=&quot;Untitled%204&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MULTI Loss
= Coordinate Loss + Confidence-Score Loss + No-Object Penalties + Classification Loss&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PT = (x, y, w, h, Confidence-Score) x B + Classes&lt;/code&gt; 에 대해서 x, y는 수식의 1번 라인. w, h는 2번 라인. Confidence-Score는 3~4번 라인. Classes는 5번 라인에 대한 것들을 의미합니다.&lt;/p&gt;

&lt;p&gt;그래서 MULTI Loss를 보면 Coordinate Loss(x, y, w, h)에 대한 수식이 있고(1~2번 라인) Confidence-Score Loss에 대한 수식(3번 라인), No-Object Penalties에 대한 수식(4번 라인), Classification Loss에 대한 수식(5번 라인)으로 이루어진 구조로 되어있습니다&lt;/p&gt;

&lt;p&gt;수식만 보게 되면 굉장히 복잡해 보입니다.. 하지만 간단히 보면 x, y, w, h, Confidence-Score의 값이 예측값과 Ground-truth 값의 차를 구해 모두 더해준다는, 크게 어렵지 않은 내용입니다. 이후 패널티 단락에서 찾지 못한 물체들에 대한 패널티를 부여합니다. 다시 말해 물체로 찾아냈어야 하는데 찾지 못한 인덱스에 대해 C의 값의 차를 구해 loss에 더해줍니다. 마지막 단락에서 모든 물체가 있다고 판단된 인덱스들에 대해 모든 클래스들에 대해 예측 값과 실제 값의 차를 구해서 더해줍니다.&lt;/p&gt;

&lt;p&gt;이번 포스팅에서는 간략히 개념에 대해서 짚고 가기 위해 여기까지만 짚고 넘어가겠습니다.🤦🏻‍♂️&lt;/p&gt;

&lt;h3 id=&quot;yolov1의-한계&quot;&gt;YOLOv1의 한계&lt;/h3&gt;

&lt;p&gt;YOLOv1에서는 여러 물체들이 겹쳐있으면 제대로 된 예측이 어렵습니다. 또한 물체가 작을 수록 정확도가 감소하며 바운딩박스 형태가 data를 통해 학습되므로 새로운 형태의 바운딩박스의 경우 정확히 예측하지 못한다는 단점이 있습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;yolov2&quot;&gt;YOLOv2&lt;/h1&gt;

&lt;p&gt;이러한 YOLOv1 모델의 문제점을 보완하여 정확도를 높인 YOLOv2 가 등장하였습니다.&lt;/p&gt;

&lt;p&gt;YOLOv2는 기존의 YOLO에서 성능을 올리기 위해 많은 점을 보완하였습니다. YOLOv2 에서의 핵심은 이전의 YOLO와는 다르게 Anchor Box의 개념 도입, Batch Normalization 적용, features map 크기를 7x7 에서 13x13으로 변경 하는 등의 방법을 통해 성능개선을 이뤘습니다.&lt;/p&gt;

&lt;h3 id=&quot;개선-사항&quot;&gt;개선 사항&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Batch Normalization 적용&lt;/strong&gt;
YOLO의 Convolution Layer에 Batch Normalization을 적용하여 mAP를 2% 가량 향상시켰습니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;High Resolution Classifier&lt;/strong&gt;
YOLOv1은 VGG16 모델을 기반으로 224x224 크기의 해상도로 학습을 하고, 448x448 크기의 이미지에 대해서 Object Detection을 수행하도록 설계되어 성능이 좋지 않았습니다. YOLOv2에서는 학습 전 이미지 분류 모델을 큰 해상도의 이미지에 대해 fine-tuning 단계를 거쳐 고해상도 이미지로 CNN 신경망을 학습 할 수 있었습니다. 그 결과 약 4%의 mAP 증가의 결과를 도출했습니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Convolutional With Anchor Boxes&lt;/strong&gt;
기존의 YOLOv1은 24개의Conv layer와 마지막 단락의 2개의 Fully Connected layer로부터 바운딩박스의 좌표정보를 예측했습니다. YOLOv2는 마지막 단의 Fully Connected layer을 떼어내고 Convolutional Network 형태로 prediction을 계산합니다.
또한, Anchor Box의 개념을 도입하여 바운딩 박스의 좌표를 예측하기 보다는 사전에 정의한 앵커 박스에서 offset을 예측하여 더욱 간단하게 학습을 할 수 있게 되었습니다. Anchor Box의 핵심은 사전에 크기와 비율이 모두 결정되어 있는 박스를 전제로, 학습을 통해서 이 박스의 위치나 크기를 세부 조정하는 것을 말합니다.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dimension Cluster&lt;/strong&gt;
YOLOv2는 앵커박스를 수정하면서 바운딩 박스를 예측합니다. 그렇기 때문에 실제 경계 박스들을 클러스터링 하여 최적의 앵커박스를 찾습니다.
클러스터링 갯수 k 를 크게 늘릴수록 클러스터링 결과와 라벨과의 IOU가 커져 Recall이 상승합니다. 그러나 k가 커지면 높은 정확도를 얻을 수 있지만 속도가 느려지기 때문에 YOLOv2에서는 k=5라는 값을 사용합니다. (YOLOv2 에서는 앵커 박스를 5개 사용합니다.) 그 결과 recall과 precision 측면에서 성능을 향상시킬 수 있었습니다.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled5.png&quot; alt=&quot;Untitled5.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Direct location prediction&lt;/strong&gt;
YOLOv2에서는 앵커 박스에 따라 하나의 셀에서 5차원 벡터로 이루어진 바운딩 박스를 예측하며, 경계 박스가 그리드 셀에서 벗어나지 않도록 제약을 둡니다. 기존의 YOLO가 그리드의 중심점을 예측하였다면 v2에서는 left top 꼭지점으로부터 얼마나 이동하는지 예측하게 됩니다.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled6.png&quot; alt=&quot;Untitled6.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fine-Grained Features&lt;/strong&gt;
위에서 YOLOv2는 13x13 feature map을 출력한다고 설명했었습니다. 하지만 13x13의 크기는 작은 물체 검출에 대해서 약하다는 단점이 있습니다. 이와 같은 문제해결을 위해 상위 레이어의 피쳐맵을 하위 피쳐맵에 합쳐주는 passthrough layer를 도입했습니다. 이전 layer의 26x26 feature map을 가지고 와서 13x13 feature map에 이어 붙입니다. 크기가 달라 그냥 이어붙일 수 없으므로 26x26x512의 feature map을 13x13x(512*4)의 feature map으로 변환합니다. 26x26 크기의 feature map에 고해상도 특징이 담겨 있기때문에 이를 활용 하는 것입니다.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled7.png&quot; alt=&quot;Untitled7.png&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Multi-Scale Training&lt;/strong&gt;
YOLOv2는 작은 물체도 detection 하기 위해 여러 스케일의 이미지를 학습하도록 하였습니다. 10 epoch 마다 {320, 352, …, 608} 과 같이 32 픽셀 간격으로 입력 이미지의 해상도를 바꿔주며 학습을 진행합니다. 따라서 다양한 입력 크기에도 예측을 잘할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;yolov2-network&quot;&gt;YOLOv2 Network&lt;/h3&gt;

&lt;p&gt;위에서 설명한 것들을 다시 한번 참고하여 YOLOv2의 네트워크에 대해서 한번 더 짚고 갑시다.&lt;/p&gt;

&lt;p&gt;먼저 YOLOv2 가 더 빨라진 이유는 기존의 YOLO는 VGG-16 신경망을 사용했다면 YOLOv2는 Darknet 19 신경망을 구축하여 이용했습니다. VGG-16 신경망에서 대부분의 가중치가 쓰인 FC layer를 제거하여 가중치 파라미터 수를 낮춰줬기 때문에 훨씬 빠른 속도로 detection이 가능하게 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled7.png&quot; alt=&quot;Untitled7.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;YOLOv2 Network&lt;/p&gt;

&lt;p&gt;위에서 이미 한 번 보고온 네트워크 구조입니다. 기존의 YOLO 구조에서 변경된 점은 위의 &lt;strong&gt;Fine-Grained Features&lt;/strong&gt; 에서 설명한 것과 같은 내용과 같습니다. YOLOv1과 YOLOv2의 output 을 비교해보면 v1의 최종 output은 7x7x30 이며 채널 30의 값은 (5xB+C)로 즉, (5x(바운딩박스 수)+(클래스 개수)) 이기 때문이라고 설명했었습니다. 그럼 YOLOv2 의 최종 output은 위에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;13x13x125&lt;/code&gt; 임을 확인할 수 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;125&lt;/code&gt;라는 값이 어떻게 나올까요? 보기 쉽게 정리된 그림입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled8.png&quot; alt=&quot;Untitled8.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;YOLOv2에서 앵커박스를 적용했을 때 각각의 앵커박스에 대해서 classification 정보를 가지고 있습니다. 다시 말해 하나의 anchor box에 대해 prediction을 하는데 각 prediction은 x, y, w, h, confidence, class갯수(20) 이렇게 총 25개를 의미합니다. 따라서 YOLOv2는 총 5개의 anchor box를 가지고 있기때문에&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;13x13x(Bx(5+C))&lt;/code&gt; 로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;13x13x125&lt;/code&gt; 라는 output이 최종적으로 나오는 것을 확인 할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;yolov2-성능-및-결과&quot;&gt;YOLOv2 성능 및 결과&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled9.png&quot; alt=&quot;Untitled9.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-You-Only-Look-Once-YOLO/Untitled10.png&quot; alt=&quot;Untitled10.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;YOLOv2는 상당히 빠르면서도 높은 성능을 보여줍니다. voc 207 과 coco 결과를 보면 voc에서는 SSD 알고리즘 보다 높은 성능을 보이지만, coco에서는 좀더 낮은 성능을 보여줍니다.&lt;/p&gt;

&lt;h1 id=&quot;배&quot;&gt;배&lt;/h1&gt;

&lt;hr /&gt;

&lt;p&gt;복잡하지 않은 pipeline과 빠른 예측속도를 유지하면서도 정확도에 대해 높은 성능을 예측한다는 장점이 더 부각되기 때문에 YOLO가 Object Detection 분야에서 한 획을 그었으며 관심을 받고 있는 것이라 생각이 듭니다.&lt;/p&gt;

&lt;p&gt;다음 포스팅에서는 보다 더 발전한 YOLOv3 부터 YOLOv5 까지의 구조를 가지고 다시 찾아오겠습니다!&lt;/p&gt;

&lt;h3 id=&quot;참고자료&quot;&gt;참고자료&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1506.02640&quot;&gt;You Only Look Once: Unified, Real-Time Object Detection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1612.08242&quot;&gt;YOLO9000: Better, Faster, Stronger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6fdclSGgeio&amp;amp;t=1271s&quot;&gt;PR-023: YOLO9000: Better, Faster, Stronger&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8DjIJc7xH5U&amp;amp;t=778s&quot;&gt;십분딥러닝_14_YOLO(You Only Look Once)&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 06 May 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/05/06/You-Only-Look-Once.-YOLO.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/05/06/You-Only-Look-Once.-YOLO.html</guid>
        <tags>
          
          <tag>CNN</tag>
          
          <tag>Image-Classification</tag>
          
          <tag>Object-Detection</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Ubuntu 20.04 LTS (CLI-Server)에 CUDA 11.1 GPU 가속 연산 환경 세팅 하기</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-07-01-Setting-up-CUDA-11.1/0.png</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;GPU 가속을 활용한 딥러닝 연산 및 학습을 위해선, 적절한 환경 설정이 필요합니다.&lt;/p&gt;

&lt;p&gt;딥러닝 개발 환경 설정은 GPU 장비의 모델명이나 Nvidia-Driver 의 호환성, CUDA 지원 정보 및 Pytorch/TensorFlow 버전 등등… 파편적으로 흩어져 있는 글을 찾아가며 상호 호환성 확인을 하고 설치하기 때문에 자료를 찾는 시간이 실제 환경 설정하는 시간보다 훨씬 길어지게 됩니다.&lt;/p&gt;

&lt;p&gt;이러한 시간 낭비를 줄이고, 저희와 유사한 환경에 계신 다른 분들의 유연한 환경 설정을 돕고자 내용을 작성하게 되었습니다.&lt;/p&gt;

&lt;p&gt;특히 일반적으로 개인이 많이 쓰는 GUI 버전의 Ubuntu 가 아닌 CLI(Server 용) Ubuntu 의 경우, GUI 출력에 사용되는 불필요한 패키지를 배제하고 설치하여 패키지 최적화를 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;참고 : 너드팩토리의 딥러닝 연구 장비 환경&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# 기본 장비 환경&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;OS&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Ubuntu 20.04 LTS CLI-Server&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;GPU-Model&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;RTX 2080 Ti * &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 설치 할 CUDA 환경&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Nvidia-Driver&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;450.119.03&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# nvidia-headless-450-server&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;CUDA-Driver&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;11.1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# cuda-toolkit-11-1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cudnn&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8.2.0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# cuda-toolkit-11-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;1-전체-시스템-호환성-확인&quot;&gt;1. 전체 시스템 호환성 확인&lt;/h1&gt;

&lt;p&gt;딥러닝에 GPU 가속을 활용하기 위해선
아래 명시된 4가지 항목 사이의 상호 버전 호환성이 모두 성립되어야 합니다&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GPU Device&lt;/li&gt;
  &lt;li&gt;Nvidia-Driver&lt;/li&gt;
  &lt;li&gt;CUDA + cudnn&lt;/li&gt;
  &lt;li&gt;AI FrameWork ( Pytorch / TensorFlow )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;따라서 이에 대한 시스템 호환 버전을 먼저 파악 해둔 뒤, 정해진 버전을 설치하는게 필요합니다&lt;/p&gt;

&lt;hr /&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;GPU 확인&lt;/p&gt;

    &lt;p&gt;먼저 설치된 GPU 장치가 어떤 모델인지 확인합니다&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;lspci &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt;                &lt;span class=&quot;c&quot;&gt;# 전체 장치 정보 열람&lt;/span&gt;
  or
lspci &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;NVIDIA  &lt;span class=&quot;c&quot;&gt;# 장치 정보가 너무 많아서 파악하기 어려운 경우 NVIDIA 키워드로 필터&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;호환성 체크&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;설치된 GPU 와 OS 버전에 맞는 그래픽 드라이버를 검색하여 적합한 Nvidia-Driver 를 확인
        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;https://www.nvidia.co.kr/Download/Find.aspx?lang=kr&quot;&gt;&lt;strong&gt;NVIDIA-Driver 고급 검색&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Nvidia-Driver 와 호환 가능한 CUDA 버전을 확인&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;&lt;strong&gt;Nvidia-Driver &amp;amp; CUDA Check&lt;/strong&gt;&lt;/li&gt;
        &lt;/ul&gt;

        &lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Setting-up-CUDA-11.1/0.png&quot; alt=&quot;0&quot; /&gt;&lt;/p&gt;

        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  ex) CUDA 11.1 을 설치하려면, 450.80.02 보다 최신 버전의 Nvidia-Driver 설치가 필요
  출처  -  [https://docs.nvidia.com/deploy/cuda-compatibility/index.html](https://docs.nvidia.com/deploy/cuda-compatibility/index.html)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;설치된 GPU 의 연산 성능에 따른 지원 CUDA 버전을 확인합니다&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;
            &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CUDA#GPUs_supported&quot;&gt;&lt;strong&gt;GPU Support&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

            &lt;ul&gt;
              &lt;li&gt;
                &lt;p&gt;버전 확인 예시&lt;/p&gt;

                &lt;p&gt;GeForce RTX 2080 Ti 의 경우, 위 링크의 Compute capability 값이 7.5 이고,&lt;/p&gt;

                &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CUDA SDK 10.0 – 10.2 support &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;compute capability 3.0 – 7.5
CUDA SDK 11.0 support &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;compute capability 3.5 – 8.0
CUDA SDK 11.1 – 11.3 support &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;compute capability 3.5 – 8.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;                &lt;/div&gt;

                &lt;p&gt;로 확인 되므로, 해당 GPU 장비는 CUDA &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10.0 – 10.2&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.0 – 11.3&lt;/code&gt; 를 설치할 수 있습니다&lt;/p&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;AI FrameWork 의 CUDA 지원 확인&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;
            &lt;p&gt;&lt;strong&gt;Pytorch&lt;/strong&gt;&lt;/p&gt;

            &lt;p&gt;&lt;a href=&quot;https://download.pytorch.org/whl/torch_stable.html&quot;&gt;https://download.pytorch.org/whl/torch_stable.html&lt;/a&gt;&lt;/p&gt;

            &lt;p&gt;위 torch_stable 아카이브 링크를 통해 사용하려는 torch 버전과 이를 지원하는 CUDA 버전이 있는지 확인합니다&lt;/p&gt;

            &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;예시 &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
cu111/torch-1.8.0%2Bcu111-cp36-cp36m-linux_x86_64.whl 와 같은 경우,
cuda-11.1 과 torch-1.8.0 을 호환하는 python3.6 버전 용 linux 기반 라이브러리를 지원한다는 의미
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;            &lt;/div&gt;

            &lt;p&gt;지원하는 버전 확인 후, 구체적인 설치 명령어는 아래 링크를 통해 확인 가능합니다
&lt;a href=&quot;https://pytorch.org/get-started/previous-versions/&quot;&gt;https://pytorch.org/get-started/previous-versions/&lt;/a&gt;&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;&lt;strong&gt;TensorFlow&lt;/strong&gt;&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-Setting-up-CUDA-11.1/Untitled.png&quot; alt=&quot;1&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;2-nvidia-driver-세팅-for-cli-server&quot;&gt;2. Nvidia-Driver 세팅 for CLI Server&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Nvidia-Driver 설치 확인&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /proc/driver/nvidia/version
  or
nvidia-smi

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 드라이버 미 설치시 응답&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt;: /proc/driver/nvidia/version: No such file or directory

&lt;span class=&quot;c&quot;&gt;# 드라이버가 설치 되어 있는 경우 응답&lt;/span&gt;
NVRM version: NVIDIA UNIX x86_64 Kernel Module  450.119.03  Mon Mar 29 17:51:27 UTC 2021
GCC version:  gcc version 9.3.0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Ubuntu 9.3.0-17ubuntu1~20.04&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 이미 드라이버가 설치 되어 있는 경우,&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 호환성 체크 후, 필요에 따라 드라이버 제거 후 맞는 버전으로 재설치 진행합니다&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Nvidia-Driver 설치를 위한 패키지 리스트 수집&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Ubuntu 버전을 &quot;release&quot; 변수 에 저장&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ubuntu&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;lsb_release &lt;span class=&quot;nt&quot;&gt;-sr&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;//g&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; ubuntu2004

&lt;span class=&quot;c&quot;&gt;# Nvidia 아카이브로부터 드라이버 리스트 수집&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install sudo &lt;/span&gt;gnupg
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key adv &lt;span class=&quot;nt&quot;&gt;--fetch-keys&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://developer.download.nvidia.com/compute/cuda/repos/&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/x86_64/7fa2af80.pub&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'echo &quot;deb http://developer.download.nvidia.com/compute/cuda/repos/'&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/x86_64 /&quot; &amp;gt; /etc/apt/sources.list.d/nvidia-cuda.list'&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'echo &quot;deb http://developer.download.nvidia.com/compute/machine-learning/repos/'&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/x86_64 /&quot; &amp;gt; /etc/apt/sources.list.d/nvidia-machine-learning.list'&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;설치하려는 드라이버 확인&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-cache search nvidia-driver

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
nvidia-driver-418 - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-430
nvidia-driver-435 - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-455
nvidia-driver-440 - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-450
nvidia-driver-450 - NVIDIA driver metapackage
nvidia-driver-450-server - NVIDIA Server Driver metapackage
nvidia-driver-455 - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-460
nvidia-driver-460 - NVIDIA driver metapackage
nvidia-headless-450 - NVIDIA headless metapackage
nvidia-headless-450-server - NVIDIA headless metapackage
nvidia-headless-460 - NVIDIA headless metapackage
nvidia-headless-no-dkms-450 - NVIDIA headless metapackage - no DKMS
nvidia-headless-no-dkms-450-server - NVIDIA headless metapackage - no DKMS
nvidia-headless-no-dkms-460 - NVIDIA headless metapackage - no DKMS
nvidia-driver-418-server - NVIDIA Server Driver metapackage
nvidia-driver-440-server - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-450-server
nvidia-driver-460-server - NVIDIA Server Driver metapackage
nvidia-headless-418-server - NVIDIA headless metapackage
nvidia-headless-460-server - NVIDIA headless metapackage
nvidia-headless-no-dkms-418-server - NVIDIA headless metapackage - no DKMS
nvidia-headless-no-dkms-460-server - NVIDIA headless metapackage - no DKMS
nvidia-driver-430 - Transitional package &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;nvidia-driver-465
nvidia-driver-465 - NVIDIA driver metapackage
nvidia-headless-465 - NVIDIA headless metapackage
nvidia-headless-no-dkms-465 - NVIDIA headless metapackage - no DKMS
  ...... &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;중략&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;나타난 리스트 중, 우리는 GUI 출력을 전혀 사용하지 않는 서버용 CLI 버전을 설치
→ headless 드라이버를 설치 ( ex. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-headless-450-server&lt;/code&gt; )&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;참고&lt;/p&gt;

        &lt;p&gt;GUI 가 포함된 일반 데스크탑 버전을 설치하려면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-driver-450&lt;/code&gt; 을 설치하면 됩니다
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-driver-450&lt;/code&gt; 와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-driver-450-server&lt;/code&gt; 는 저장 경로상의 차이만 있을 뿐 패키지 구성은 동일해서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-driver-450-server&lt;/code&gt; 를 설치해도 GUI 출력 모듈이 같이 설치되므로 GPU 메모리 자원을 아끼려면 꼭! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvidia-headless-450-server&lt;/code&gt; 를 설치해야 됩니다&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;Ref : &lt;a href=&quot;https://linustechtips.com/topic/1263727-installing-nvidia-drivers-on-ubuntu-also-installs-gui-environment/&quot;&gt;https://linustechtips.com/topic/1263727-installing-nvidia-drivers-on-ubuntu-also-installs-gui-environment/&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;드라이버 설치 후 Reboot&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nvidia-headless-450-server
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nvidia-utils-450
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;dkms nvidia-modprobe

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;reboot now
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;최종 설치 확인&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo cat&lt;/span&gt; /proc/driver/nvidia/version
  or
nvidia-smi

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
NVRM version: NVIDIA UNIX x86_64 Kernel Module  450.119.03  Mon Mar 29 17:51:27 UTC 2021
GCC version:  gcc version 9.3.0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Ubuntu 9.3.0-17ubuntu1~20.04&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ref : &lt;a href=&quot;https://hiseon.me/linux/ubuntu/install_nvidia_driver/&quot;&gt;https://hiseon.me/linux/ubuntu/install_nvidia_driver/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;3-cuda--cudnn-세팅-for-cli-server&quot;&gt;3. CUDA &amp;amp; cudnn 세팅 for CLI Server&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;호환성 확인 된 Nvidia-Driver 가 이미 설치 되어 있는것을 전제로 합니다. Nvidia-Driver 가 아직 준비되지 않았다면 해당 드라이버를 먼저 설치 후 진행해주세요&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;CUDA 설치 확인&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; /usr/local | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;cuda

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# CUDA 미 설치시 응답&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;응답 내용 없음&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# CUDA 가 설치 되어 있는 경우 응답&lt;/span&gt;
lrwxrwxrwx  1 root root   22 May  6 10:59 cuda -&amp;gt; /etc/alternatives/cuda
lrwxrwxrwx  1 root root   25 May  6 10:59 cuda-11 -&amp;gt; /etc/alternatives/cuda-11
drwxr-xr-x 14 root root 4096 May  6 10:59 cuda-11.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;설치를 위한 패키지 리스트 수집&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Ubuntu 버전을 &quot;release&quot; 변수 에 저장&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ubuntu&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;lsb_release &lt;span class=&quot;nt&quot;&gt;-sr&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;//g&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; ubuntu2004

&lt;span class=&quot;c&quot;&gt;# Nvidia 아카이브로부터 드라이버 리스트 수집&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install sudo &lt;/span&gt;gnupg
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key adv &lt;span class=&quot;nt&quot;&gt;--fetch-keys&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://developer.download.nvidia.com/compute/cuda/repos/&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/x86_64/7fa2af80.pub&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'echo &quot;deb http://developer.download.nvidia.com/compute/cuda/repos/'&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/x86_64 /&quot; &amp;gt; /etc/apt/sources.list.d/nvidia-cuda.list'&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'echo &quot;deb http://developer.download.nvidia.com/compute/machine-learning/repos/'&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$release&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/x86_64 /&quot; &amp;gt; /etc/apt/sources.list.d/nvidia-machine-learning.list'&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;설치하려는 CUDA 드라이버 확인 및 설치&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-cache search cuda

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
cuda-11-0 - CUDA 11.0 meta-package
cuda-11-1 - CUDA 11.1 meta-package
cuda-11-2 - CUDA 11.2 meta-package
cuda-11-3 - CUDA 11.3 meta-package
  ......
cuda-toolkit-11-0 - CUDA Toolkit 11.0 meta-package
cuda-toolkit-11-1 - CUDA Toolkit 11.1 meta-package
cuda-toolkit-11-2 - CUDA Toolkit 11.2 meta-package
cuda-toolkit-11-3 - CUDA Toolkit 11.3 meta-package
  ...... &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;중략&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;나타난 리스트 중, 우리는 GUI 출력을 전혀 사용하지 않는 서버용 CLI 버전 CUDA 를 설치&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--no-install-recommends&lt;/span&gt; cuda-toolkit-11-1
&lt;span class=&quot;c&quot;&gt;# --no-install-recommends 옵션을 추가해 GUI 용 패키지는 설치 제외&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;GUI 출력 모듈 배제 및 nvidia-driver 패키지가 업데이트 되어 섞이는 일이 발생하지 않기 위해선,
꼭! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-install-recommends&lt;/code&gt; 옵션이 추가된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cuda-toolkit-11-1&lt;/code&gt; 을 설치해야 됩니다
( GUI 가 포함된 일반 데스크탑 버전을 설치하려면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cuda-11-1&lt;/code&gt; 을 설치하면 됩니다 )&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;cudnn 드라이버 확인 및 설치&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-cache search cudnn

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
libcudnn7 - cuDNN runtime libraries
libcudnn7-dev - cuDNN development libraries and headers
libcudnn8 - cuDNN runtime libraries
libcudnn8-dev - cuDNN development libraries and headers
  ...... &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;중략&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;적합한 cudnn 라이브러리 설치&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;libcudnn8-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;최종 설치 버전 확인&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;CUDA 확인&lt;/p&gt;

        &lt;ol&gt;
          &lt;li&gt;
            &lt;p&gt;설치된 시스템 경로를 통한 확인&lt;/p&gt;

            &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; /usr/local | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;cuda

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# CUDA 미 설치시 응답&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;응답 내용 없음&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# CUDA 가 설치 되어 있는 경우 응답&lt;/span&gt;
lrwxrwxrwx  1 root root   22 May  6 10:59 cuda -&amp;gt; /etc/alternatives/cuda
lrwxrwxrwx  1 root root   25 May  6 10:59 cuda-11 -&amp;gt; /etc/alternatives/cuda-11
drwxr-xr-x 14 root root 4096 May  6 10:59 cuda-11.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;            &lt;/div&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvcc --version&lt;/code&gt; 으로 확인&lt;/p&gt;

            &lt;p&gt;해당 명령은 cuda 전체 패키지 - GUI 출력 모듈 포함 - 을 설치 할 때, 자동으로 설정되는 시스템 변수를 통해 cuda version 을 출력하는 명령입니다. 현재 시스템은 CLI Only 이므로 수동으로 시스템 변수를 설정해 줘야, nvcc 를 통한 버전 확인이 가능합니다&lt;/p&gt;

            &lt;ul&gt;
              &lt;li&gt;nvcc 시스템 변수 설정 방법
                &lt;ol&gt;
                  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ sudo vi ~/.profile&lt;/code&gt;&lt;/li&gt;
                  &lt;li&gt;해당 파일의 가장 밑 단락에 아래 내용 추가
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export PATH=/usr/local/cuda-11.1/bin:$PATH&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64:$LD_LIBRARY_PATH&lt;/code&gt;&lt;/li&gt;
                  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ source ~/.profile&lt;/code&gt;&lt;/li&gt;
                &lt;/ol&gt;
              &lt;/li&gt;
            &lt;/ul&gt;

            &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nvcc &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 시스템 변수 설정 전, 혹은 CUDA 미 설치시 응답&lt;/span&gt;
Command &lt;span class=&quot;s1&quot;&gt;'nvcc'&lt;/span&gt; not found ~

&lt;span class=&quot;c&quot;&gt;# CUDA 가 설치 및 시스템 변수 설정 완료 후 응답&lt;/span&gt;
nvcc: NVIDIA &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Cuda compiler driver
Copyright &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2005-2020 NVIDIA Corporation
Built on Mon_Oct_12_20:09:46_PDT_2020
Cuda compilation tools, release 11.1, V11.1.105
Build cuda_11.1.TC455_06.29190527_0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;            &lt;/div&gt;
          &lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;cudnn 확인&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;whereis cudnn
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
cudnn: /usr/include/cudnn.h
&lt;span class=&quot;c&quot;&gt;# OS에 따라 위치가 다를 수 있음&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 위에서 검색한 cudnn.h 경로와 동일한 곳의 cudnn_verion.h 에서 탐색&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /usr/include/cudnn_version.h | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;CUDNN_MAJOR &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; 2
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#define CUDNN_MAJOR 8&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#define CUDNN_MINOR 2&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#define CUDNN_PATCHLEVEL 0&lt;/span&gt;
  ...... &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;중략&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
→ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; cudnn 8.2.0 ver &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;※ nvidia-smi 를 입력해서 나오는 CUDA 버전은 해당 nvidia-driver 가 지원하는 CUDA 버전을 나타내는 것이지, 실제 서버에 설치된 CUDA 버전을 나타내는것이 아닙니다 ※&lt;/p&gt;

&lt;h1 id=&quot;마무리&quot;&gt;마무리&lt;/h1&gt;

&lt;p&gt;지금까지 RTX 2080 Ti 가 탑재된 Ubuntu 20.04 LTS CLI-Server 에 CUDA 환경 설정을 진행해보았습니다.&lt;/p&gt;

&lt;p&gt;이후에는 각자 필요한 딥러닝 프레임워크 (Pytorch/TensorFlow) 의 GPU 가속 버전을 설치한 뒤, 실제 GPU 가속이 가능한지 확인해보면 됩니다 (확인 방법은 아래와 같습니다)&lt;/p&gt;

&lt;p&gt;이번 포스팅을 통해 환경 설정 때문에 생기는 불필요한 시간 낭비를 줄이고, 빠르게 CUDA 작업 환경을 설정하는데 도움이 되길 기대합니다&lt;/p&gt;

&lt;h3 id=&quot;gpu-가속-확인&quot;&gt;GPU 가속 확인&lt;/h3&gt;

&lt;p&gt;Pytorch : Pytorch-GPU 버전이 설치된 Python 환경에서 다음 실행&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# False 로 출력된다면 GPU 가속 사용이 불가능
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'11.1'&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Pytorch 가 인식하고 있는 CUDA 버전
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device_count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# 사용 가능한 GPU 개수 반환
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_device_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 0번 GPU 장치 모델 &amp;gt; 숫자를 바꿔서 다른 장치 확인 가능
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;TensorFlow : TensorFlow-GPU 버전이 설치된 Python 환경에서 다음 실행&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tensorflow.python.client&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;device_lib&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;device_lib&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list_local_devices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# GPU 가속이 가능하다면 사용 가능한 GPU device 가 출력
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;reference&quot;&gt;Reference&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.nvidia.co.kr/Download/Find.aspx?lang=kr&quot;&gt;https://www.nvidia.co.kr/Download/Find.aspx?lang=kr&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.nvidia.com/deploy/cuda-compatibility/index.html&quot;&gt;https://docs.nvidia.com/deploy/cuda-compatibility/index.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CUDA#GPUs_supported&quot;&gt;https://en.wikipedia.org/wiki/CUDA#GPUs_supported&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://linustechtips.com/topic/1263727-installing-nvidia-drivers-on-ubuntu-also-installs-gui-environment/&quot;&gt;https://linustechtips.com/topic/1263727-installing-nvidia-drivers-on-ubuntu-also-installs-gui-environment/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hiseon.me/linux/ubuntu/install_nvidia_driver/&quot;&gt;https://hiseon.me/linux/ubuntu/install_nvidia_driver/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 30 Apr 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/04/30/Setting-up-CUDA-11.1.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/04/30/Setting-up-CUDA-11.1.html</guid>
        <tags>
          
          <tag>CUDA</tag>
          
          <tag>Nvidia-Driver</tag>
          
          <tag>Pytorch</tag>
          
          <tag>TensorFlow</tag>
          
          <tag>Ubuntu 20.04 LTS</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>VODA 디자인 시스템 2</title>
        <authors>
          
          
          <author>
            <name>유보람</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/allison.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-04-01-voda-design-system-1/thumbnail.svg</thumbnail>
        <description>&lt;p&gt;안녕하세요, 너드팩토리 프로덕트 디자이너 Allison입니다.&lt;/p&gt;

&lt;p&gt;지난번에는 디자인 시스템을 구축한 계기, 필요한 이유와 구축 기준(타이포그래피와 그리드와 간격)을 알아봤습니다. 이번 편에는 브랜드 컬러를 정한 기준과 UI 컴포넌트 구성에 대해 말할게요. 하단 링크를 통해 먼저 1편을 보고 오는 것을 권장합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.nerdfactory.ai/2021/01/11/voda-design-system-1.html&quot;&gt;https://blog.nerdfactory.ai/2021/01/11/voda-design-system-1.html&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-colors&quot;&gt;3) Colors&lt;/h2&gt;

&lt;p&gt;컬러는 서비스를 대표하고 브랜드의 성격을 말해주는 요소입니다. 너무 많은 컬러를 사용할 경우 브랜드 아이덴티티가 약해져 일관된 사용자 경험을 제공하기 어렵습니다. 그러나 너무 적은 컬러로는 디자인할 때 한계에 부딪힐 수 밖에 없어요. 그래서 명암에 따라 10단계로 나누고 이것을 기반으로 브랜드 아이덴티티를 지키며 유연한 디자인을 합니다.&lt;/p&gt;

&lt;h3 id=&quot;3-1-gray-scale-colors&quot;&gt;3-1) Gray Scale Colors&lt;/h3&gt;

&lt;p&gt;GUI 디자인 작업을 하기 전 정보의 계층구조를 나타낼 때 사용합니다. 그 외에 텍스트, 정보를 나누기 위한 구분선 요소에 사용해요. Grey 컬러가 필요할 때마다 마법사처럼 혹은 그 날의 기분에 따라 매번 다른 그레이 컬러를 사용할 수 없으니 Grey50, 100, 200, 300, 400, 500, 600, 700, 800 ,900까지 총 10단계로 나눕니다. 필요에 따라 더 세분화하거나 간소화할 수 있으며 브랜드 분위기에 따라 Cool Tone/Warm Tone으로 바꿀 수 있어요.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/Gray_scale.svg&quot; alt=&quot;Gray_scale&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-2-brand-colors&quot;&gt;3-2) Brand Colors&lt;/h3&gt;

&lt;h3 id=&quot;primary&quot;&gt;Primary&lt;/h3&gt;

&lt;p&gt;VODA의 브랜드 컬러를 지정할 때 두 가지 요소를 고려했습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;첫 번째, 유사 서비스와 다른 컬러를 사용하여 브랜드 컬러만으로 시각적 인지도를 얻자&lt;/li&gt;
  &lt;li&gt;두 번째, 기존 운영 중인 AIVORY와 다른 서비스를 제공하므로 컬러 자산을 계승하지 않고 독자적인 컬러를 갖자.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그래서 결정한 Primary Color는 #7851e7입니다.&lt;/p&gt;

&lt;h3 id=&quot;secondary&quot;&gt;Secondary&lt;/h3&gt;

&lt;p&gt;Primary Color와 조화와 전체적인 브랜드 방향성을 고려해 결정합니다. VODA에서 Secondary Colors는 대부분 그래프에서 요소 구분을 위해 사용하므로 이 또한 고려해야 합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;퍼플 계열(Primary Color)과 사용했을 때 구분이 확실 해야 하므로 난색 계열로 갈 것&lt;/li&gt;
  &lt;li&gt;함께 사용했을 때 Primary Color와 조화로울 것&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그래서 결정한 컬러는 오렌지 계열인 #ff9931와 난색에 가까운 올리브 그린 컬러 #b0b900로 결정했어요.&lt;/p&gt;

&lt;p&gt;VODA는 데이터를 시각화할 일이 많고 그에 따라 더 많은 컬러 팔레트가 필요해요. 그래서 이 컬러들을 중심으로 바리에이션 하여 더 다양한 팔레트를 만들어 상황에 따라 사용합니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/Palette.svg&quot; alt=&quot;Palette&quot; /&gt;&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;Eva 디자인 시스템에서 Color Generator를 사용하면 더 쉽게 팔레트를 만들 수 있습니다.&lt;/dt&gt;
  &lt;dd&gt;&lt;a href=&quot;https://colors.eva.design/&quot;&gt;https://colors.eva.design/&lt;/a&gt;&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;&lt;a href=&quot;https://colors.eva.design&quot;&gt;Eva Design System: Deep learning color generator&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-3-system-colors&quot;&gt;3-3) System Colors&lt;/h3&gt;

&lt;p&gt;브랜드 컬러와는 별개로 사용자에게 직관적으로 시스템의 상태를 전달하기 위해 사용하는 컬러입니다. Danger(Error), Warning, Success, Info로 구분하여 순서대로 Red, Yellow, Green, Blue 계열로 설정합니다. 시스템의 상태를 효과적으로 전달하기 위해 아이콘, 텍스트와 함께 디자인할 것을 권장해요. (UI 컴포넌트-Input 섹션 참고)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/System_Colors.svg&quot; alt=&quot;System_Colors&quot; /&gt;&lt;/p&gt;

&lt;p&gt;또한 VODA에서는 Heatmap에서 사용할 그라데이션 컬러가 필요했습니다. 이때부터 컬러 지옥에 빠졌어요..:( 슬프지만 침착하게 일러스트레이터를 켭니다. 컬러 변경의 기점이 되는 시스템 컬러들을 적당한 간격을 두고 일직선에 배치한 후 블랜딩 툴(W)을 이용하여 그라데이션을 줍니다. 어도비 선생님께 감사한 순간이에요.&lt;/p&gt;

&lt;p&gt;(블랜딩 툴 사용법: &lt;a href=&quot;https://www.youtube.com/watch?v=tQdWx_PbawU&quot;&gt;https://www.youtube.com/watch?v=tQdWx_PbawU&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tQdWx_PbawU&quot;&gt;#08 블렌드툴 I 일러스트레이터 왕초보 기초강좌 I 블렌드 툴에 대해서 알아보아요I 디자이너깜짝의 친절한 그래픽&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;블랜딩해서 나온 컬러들을 복사, Xd나 Figma으로 가져옵니다. 일러스트레이터에 출력 된 컬러를 모두 사용하면 너무 많으니 이 중에서 10~15개 정도 추려 정리합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/Heatmap_gradation_Colors.svg&quot; alt=&quot;Heatmap_gradation_Colors&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;4-ui-components&quot;&gt;4) UI Components&lt;/h3&gt;

&lt;p&gt;서비스 안에서 공통으로 사용하는 UI 컴포넌트로 Icons, Input, Button, Modal, Table 등이 여기에 해당합니다. 현재 VODA는 Web 서비스만 제공하므로 Web UI 컴포넌트를 기준으로 했어요. 전체 서비스에서 두 개 이상 들어갈 시 컴포넌트로 등록하고 구성요소에서 불러와 사용하는 것이 수정에 용이하고 디자이너 정신건강에 이롭습니다. UI 컴포넌트에서 중요한 사항은 단순한 디자인 리소스를 만드는 것이 아니라는 점입니다. 팀원 간의 약속을 만드는 작업으로 컴포넌트 쓰임에 대한 이해를 기반으로 명확한 규칙을 세워 팀원 모두가 보고 이해할 수 있어야 합니다.&lt;/p&gt;

&lt;p&gt;VODA 디자인 시스템의 UI 컴포넌트 중 일부만 공개합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/input.svg&quot; alt=&quot;input&quot; /&gt;&lt;/p&gt;

&lt;p&gt;아이콘은 4의 배수로 결정하고(원형 제외) 비율에 맞게 Keyline 내에서 작업하여 전체적인 아이콘 크기를 맞춰 일관성을 유지합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-07-01-voda-design-system-2/ICONS_(1).svg&quot; alt=&quot;ICONS_(1)&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 외에도 로고 가이드 디자인, UI 텍스트 가이드라인(UX Writings) 등 프로젝트 상황 또는 필요에 맞게 추가할 수 있습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;5-지속가능한-디자인-시스템&quot;&gt;5. 지속가능한 디자인 시스템&lt;/h2&gt;

&lt;p&gt;디자인 시스템에서 중요한 것은 단순히 좋아 보이게 만드는 것이 아닌 팀원 모두가 디자인 시스템에 대해 이해할 수 있도록 만드는 것입니다. 이러한 디자인 시스템은 디자인에 대한 의사결정을 하는 데 있어 도움을 주고 커뮤니케이션 비용을 줄여 업무의 효율성을 높여줍니다. 그러나 디자인 시스템은 효율적인 도구일 뿐 절대적인 가이드라인이 될 수 없어요. 그러니 프로젝트 상황에 맞게 수정하고 유연히 적용하길 바랍니다. VODA 디자인 시스템 또한 서비스의 지속적인 운영과 더 나은 사용자 경험을 제공하기 위해 수정을 거듭하며 발전할게요!&lt;/p&gt;

&lt;p&gt;끝 🙌&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Reference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ridi.design/&quot;&gt;https://ridi.design/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ridi.design/&quot;&gt;RIDI Design System&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 05 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/03/05/voda-design-system-2.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/03/05/voda-design-system-2.html</guid>
        <tags>
          
          <tag>VODA</tag>
          
          <tag>Design System</tag>
          
          <tag>Adobe Xd</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>백마 인턴십 후기</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
          
          <author>
            <name>김인철</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/chris.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-03-03-review-of-baekma-internship/140836.png</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;지난 2020년 12월 21일부터 진행된 충남대학교 백마 인턴십을 통해 너드팩토리에서는 3명의 인턴분들이 지원하여 참여하였습니다. 2개월이 된 지금, 너드팩토리 안에서 인턴으로 활동한 내용과 느낀점에 대해 인터뷰를 진행했습니다.&lt;/p&gt;

&lt;h2 id=&quot;q-자기소개-부탁드립니다&quot;&gt;&lt;strong&gt;Q. 자기소개 부탁드립니다.&lt;/strong&gt;&lt;/h2&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/140836.png&quot; alt=&quot;140836&quot; /&gt;&lt;br /&gt;
&lt;em&gt;왼쪽부터 버스터(오재성), 조(조윤혁), 홉스(김민중)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Buster : 너드팩토리에 백마인턴십으로 지원해 인공지능 이미지 처리 개발을 담당한 Buster 오재성입니다.&lt;/p&gt;

&lt;p&gt;Jo : 안녕하세요. 충남대학교 백마 인턴십을 통해 2개월 동안 플랜아이에서 근무하게 된 Jo 조윤혁입니다. 저는 인공지능 개발을 담당하게 되었습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 너드팩토리에서 인턴십 활동을 진행하면서 백엔드 개발을 담당한 Hobbes 김민중 입니다.&lt;/p&gt;

&lt;h2 id=&quot;q-인턴십에-지원한-동기가-무엇인가요&quot;&gt;&lt;strong&gt;Q. 인턴십에 지원한 동기가 무엇인가요?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Buster : 학교에서 배웠던 기계학습 같은 인공지능 강의나 여러 IT업계 유튜버들의 인공지능 이론 및 개발에 대한 지식을 접하며 해당 내용을 실제 개발 현장에서 어떻게 활용하고 프로젝트가 진행되는지 호기심이 생겼습니다. 이에 대한 현장의 경험을 쌓고 싶어서 플랜아이 기업부설연구소 인턴에 지원하게 되었습니다.&lt;/p&gt;

&lt;p&gt;Jo : 학교에서 배운 인공지능 지식이 현업에서는 어떻게 쓰이는지 경험해보고 싶었습니다. 또 현업에 종사하시는 개발자들이 협업을 어떤식으로 진행하는지도 궁금했습니다. 마침 플랜아이 너드팩토리에서 요구하는 사항이 인공지능 지식과 Git에 대한 사용 여부였기에 적합하다고 생각하여 지원하게 되었습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 학과에 배운 전공 관련 교과 과목들에 대한 실제 직무에서의 직접적 활용 방법과 현역 개발자분들의 협업 과정에 대하여 직접 경험하고 싶어 인턴십 활동에 지원하였습니다.&lt;/p&gt;

&lt;h2 id=&quot;q-인턴십에서-어떤-업무를-하였고-무엇을-배웠나요&quot;&gt;&lt;strong&gt;Q. 인턴십에서 어떤 업무를 하였고 무엇을 배웠나요?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Buster : AI개발 중 이미지 처리 프로젝트를 진행하면서 DenseNet 모델과 Pytorch라이브러리를 활용한 유사 이미지 분류기 제작 업무를 진행하였습니다. 처음 모델에 대한 깊은 이해를 위해 같은 업무를 하게된 Jo님과 같이 연구실 내의 인공지능 관련 수학 책이나 교제, github내 이미지 처리 모델 소스코드 그리고 논문 등의 많은 자료를 참고하면서 이미지 처리 모델의 동작과 코드 구성에 관한 구체적인 지식을 배울수 있었습니다. 같이 활용한 Pytorch도 이전에 사용했었던 sklearn이나 keras 등과 다른 처음 사용하는 라이브러리라서 익숙하지 않은 부분이 많았지만 인터넷 내의 튜토리얼 자료들과 루카스 님의 가이드라인으로 익숙하지 않은 라이브러리를 활용하고 배우는 것도 흥미로웠습니다.&lt;/p&gt;

&lt;p&gt;Jo : 검색도구의 자료로 활용될 수 있는 유사이미지분류 기술을 학습하고 구현하였습니다. 전반적인 틀은 전이학습기반으로 구성하고 사전에 학습된 모델은 DenseNet모델을 적용했기에 구현하기 전에 전이학습에 대해 학습하고 DensNet모델을 면밀히 분석하는 시간을 가졌습니다. 이렇게 인공지능 모델을 세세하게 분석하고 논문까지 본 적은 없었기에 어려운 부분이 있었지만 실제 구현하는 부분에서 많은 도움이 되었습니다. 또 Buster님과 협업을 진행하면서 한 프로젝트를 완성하는데 커뮤니케이션이 정말 중요하다는 것을 경험할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 주로 Backend 개발에 대하여 업무를 진행하였는데, 파이썬의 Django 프레임워크에서 Model 생성 후 데이터베이스에 Model 값들을 추가하여 Django rest-framework 를 활용하여 restful API 를 직접 만들어서 관리하는 업무를 진행하였습니다. 과거에 오픈 API 를 사용해 본 경험은 있지만 API 가 어떤 원리로 만들어지고 배포되는 과정에 대하여는 알지 못하였습니다. 하지만 인턴십 동안 진행한 업무를 통하여 직접 모델 생성하는 것부터 시작하여 사용자가 필요한 조건을 만족시키는 API를 설계하는 작업을 하면서 Backend 개발에 대한 많은 지식과 경험을 얻을 수 있었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/131419.png&quot; alt=&quot;131419&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/DB981628.png&quot; alt=&quot;DB981628&quot; /&gt;&lt;br /&gt;
&lt;em&gt;DenseNet 모델 아키텍처 설명&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;q-인턴십을-통해-느낀점은-무엇인가요&quot;&gt;&lt;strong&gt;Q. 인턴십을 통해 느낀점은 무엇인가요?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Buster : 실무 환경에서 어떻게 협업이 이루어지고 Notion을 통한 업무 관리 그리고 Jo님과의 협업을 통한 디테일한 의사소통의 중요성이 크게 느껴졌습니다.
특히, 단순 학교에서 개인 텀 프로젝트를 진행하거나 흔히 버스탄다고 이야기하는 특정 누군가 주도하는 학교 팀 프로젝트가 아닌 동등한 비중을 담당하는 프로젝트를 진행하며 시행착오를 겪어 본 게 앞으로 큰 경험이 될 것같다는 느낌을 받았습니다.&lt;/p&gt;

&lt;p&gt;Jo : 이번 인턴십에서 프로젝트를 진행하면서 매주 notion을 통해 업무를 계획하고 slack으로 소통하며 git으로 서로 코드를 공유하면서 협업을 경험한 점이 유익했습니다. 다만 처음 해보는 협업이기에 소통하는 부분에서 어려움이 있었습니다. 오해로 인해 코드가 분리되기도 해서 아쉬웠지만 이런 점을 해결하기 위해 노력하고 서로 다름을 공감했던 점이 좋은 경험이었던 것 같습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 데일리 스크럼, notion의 sprint 관리, slack을 통한 커뮤니케이션 등의 현재 너드팩토리에서 협업하는 과정에 대하여 직접 일원이 되어 함께 진행하면서 협업에 대한 경험을 할 수 있었던 점이 좋았습니다. 또한, Backend 개발에 대한 많은 경험을 통하여 관련 지식을 얻은 점이 매우 만족스럽습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/131750.png&quot; alt=&quot;131750&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/131814.png&quot; alt=&quot;131814&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Django Backend 코드 리뷰&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;q-앞으로의-목표가-무엇인가요&quot;&gt;&lt;strong&gt;Q. 앞으로의 목표가 무엇인가요?&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Buster : 인턴십 이후 학기로 넘어가 졸업 프로젝트도 연계해 진행하게 되었는데 이번 경험을 바탕으로 발생했던 문제들을 개선하며 성공적으로 졸업 프로젝트도 주도하는 것이 목표입니다.&lt;/p&gt;

&lt;p&gt;Jo : 인턴십을 통해 얻은 경험과 자신감을 가지고 졸업 후에는 가고자 하는 기업에 필요한 사람이 되고 싶습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 너드팩토리에서 인턴십을 진행하면서 백엔드 개발에 대한 많은 지식들을 얻을 수 있었는데, 이를 바탕으로 실제 구동되고 있는 서버 및 데이터베이스 관리까지 할 수 있는 백엔드 개발자가 되는것이 목표입니다.&lt;/p&gt;

&lt;h2 id=&quot;q-너드팩토리에게-한마디&quot;&gt;&lt;strong&gt;Q. 너드팩토리에게 한마디&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Buster : 처음 하는 인턴이라 걱정도 많고 긴장도 많이 한 상태였지만 모두 친절히 대해주시면서 형성된 편안한 분위기 덕분에 빠르게 적응할수 있었던거 같습니다. 감사하다는 말씀을 먼저 드리면서 이러한 긍정적인 문화를 앞으로도 실천해나갈수 있는 개발자가 되겠습니다.&lt;/p&gt;

&lt;p&gt;Jo : 너드팩토리 플랜아이 인턴 기간 초반에는 잘 적응할 수 있을지 걱정이 됐었지만, 회사에 빨리 익숙해지도록 노력해주셔서 감사했습니다. 또 현업에서의 경험에 관한 얘기를 많이 해주시고 바쁘신 와중에 진로에 대해 조언도 아낌없이 해주셔서 얻어가는 것이 많은 시간이었던 것 같아 정말 감사한다는 말씀 전하고 싶습니다.&lt;/p&gt;

&lt;p&gt;Hobbes : 많이 부족한 상태로 처음 인턴십을 시작하였지만, 매주 스프린트 설계, 데일리 스크럼 및 너드님들의 지속적인 리뷰를 통하여 조금은 발전하여 인턴십을 마무리하는 것 같습니다. 이에 바쁘신데도 수많은 도움을 주신 너드팩토리의 너드님들에게 정말 감사합니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-03-review-of-baekma-internship/140559.png&quot; alt=&quot;140559&quot; /&gt;&lt;br /&gt;
&lt;em&gt;사내 카페 AROPA 에서&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;마치며&quot;&gt;&lt;strong&gt;마치며&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;2개월 정도의 짧은 기간 이었지만, 인턴으로 오신 3분과 함께 연구소의 문제를 함께 해결하며 많은 것을 경험할 수 있었습니다. 특히 협업과 조화, 의사소통의 가치에 대해 기존의 너드팩토리 구성원들 역시 많은 것을 깨달을 수 있는 유익한 시간이었습니다.&lt;/p&gt;

&lt;p&gt;아쉽게도 인턴 기간이 종료되어 이별을 하게 되었지만, 너드팩토리와 함께한 소중한 경험을 바탕으로 더욱 발전된 앞날을 만들어가시길 응원합니다.&lt;/p&gt;

&lt;p&gt;감사합니다&lt;/p&gt;
</description>
        <pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/03/03/review-of-baekma-internship.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/03/03/review-of-baekma-internship.html</guid>
        <tags>
          
          <tag>Internship</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Django REST Framework로 API 만들기 &amp; HTML 요소 수집하기</title>
        <authors>
          
          
          <author>
            <name>김민중</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/cnu_hobbs.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-02-24-creating-an-api-&-collecting-html-elements-with-django-rest-framework/Untitled.png</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;이 포스팅은 Django 설치부터, Django Rest Framework 를 활용한 API 개발 방법, 이를 응용한 웹페이지의 요소별 정보를 바탕으로 API 개발을 하는 과정에 대하여 소개합니다.&lt;/p&gt;

&lt;p&gt;Django 는 Django Software Foundation이 관리하는 Python 으로 작성된 오픈소스 웹 애플리케이션 프레임워크로, Model - View - Controller(MVC) 패턴을 따르고 있습니다.&lt;/p&gt;

&lt;p&gt;고도의 데이터베이스 기반 웹 사이트를 작성하는 데에 있어서 수고를 더는것이 Django 의 주된 목표이자 철학입니다. 이에 따라 Django를 사용하면 데이터베이스 기반 웹 사이트를 개발하는데 굉장히 쉽고 빠르게 접근할 수 있습니다.&lt;/p&gt;

&lt;p&gt;Instagram, NASA, Mozila 등 다양한 기업들이 서비스에 Django를 사용하는 것으로 알려져 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;django-rest-framework-를-사용한-restful-api-개발&quot;&gt;Django Rest Framework 를 사용한 restful API 개발&lt;/h1&gt;

&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;

&lt;p&gt;Django 는 Python 을 기반으로 하는 프레임워크입니다. Python(3.4버전 이상)이 설치되어 있어야 합니다.&lt;/p&gt;

&lt;p&gt;Install Django&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;Django
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;장고 설치가 완료되었다면, 장고의 프로젝트 관리 도구 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-admin&lt;/code&gt; 을 사용할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;django-admin startproject djangoProject
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-admin&lt;/code&gt; 의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startproject&lt;/code&gt; 를 통하여 새로운 프로젝트를 생성할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;djangoProject&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;│&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;│&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;│&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;│&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;│&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;└──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wsgi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;├──&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;manage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startproject&lt;/code&gt; 로 프로젝트를 생성한 뒤 디렉토리 모습입니다.&lt;/p&gt;

&lt;p&gt;데이터베이스 파일인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;db.sqlite3&lt;/code&gt; , Django 기능들을 관리하는 &lt;a href=&quot;http://manage.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manage.py&lt;/code&gt;&lt;/a&gt; 가 생성되었습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runserver&lt;/code&gt; 를 통하여 &lt;a href=&quot;http://localhost:8000&quot;&gt;http://localhost:8000&lt;/a&gt; 에 접속하면,&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-24-creating-an-api-&amp;amp;-collecting-html-elements-with-django-rest-framework/Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이러한 화면을 볼 수 있으면 문제없이 Django 설치가 완료된 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;model&quot;&gt;Model&lt;/h2&gt;

&lt;p&gt;장고는 Model-View-Template(MVT) 패턴으로 이루어져있는데, 먼저 Model 을 생성 후, 데이터베이스에 해당 Model을 생성할 것입니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django-admin&lt;/code&gt; 의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;startapp&lt;/code&gt; 을 사용하여 새로운 product 를 생성합니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;django-admin startapp product

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;tree

&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── djangoProject
│  ├── __init__.py
│  ├── asgi.py
│  ├── settings.py
│  ├── urls.py
│  └── wsgi.py
├── manage.py
├── product
│  ├── __init__.py
│  ├── admin.py
│  ├── apps.py
│  ├── migrations
│  │  └── __init__.py
│  ├── models.py
│  ├── tests.py
│  └── views.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;새로운 app, product 를 생성하였습니다. 그 후 디렉토리 모습을 보면 product 디렉토리가 생성된 것을 볼 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;product 디렉토리 내부의 모습입니다. 여기서 자신이 만든 app 의 Model, View 등을 작성하여 기능을 추가할 수 있습니다.&lt;/p&gt;

&lt;p&gt;먼저, Model을 생성하겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#models.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntegerField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;created_at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DateTimeField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_now_add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__str__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Product 라는 Model 을 생성하였습니다.&lt;/p&gt;

&lt;p&gt;Product Model 에는 name, price, created_at 3가지의 값이 있는데, 해당 값의 Type 에 맞게 model Field 를 설정해줍니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;djangoProject/settings.py&lt;/code&gt; 에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSTALLED_APPS&lt;/code&gt; 에 자신이 생성한 app 을 추가합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#djangoProject/settings.py
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.admin'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.auth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.contenttypes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.sessions'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.messages'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'django.contrib.staticfiles'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'product'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#추가
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;변경 사항을 기반으로 새 마이그레션을 생성합니다&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;venv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Kimminjung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gimminjung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ui&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MacBook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Air&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;djangoProject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;manage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;makemigrations&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Migrations&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;‘&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;’&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Create&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;venv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Kimminjung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gimminjung&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ui&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MacBook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Air&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;djangoProject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;manage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;py&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrate&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Operations&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Apply&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contenttypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Running&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;migrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Applying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contenttypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OK&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Applying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OK&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Applying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OK&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Applying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OK&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Applying&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0001&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이러한 메세지가 출력되면 정상적으로 새 마이그레이션이 생성됩니다.&lt;/p&gt;

&lt;h2 id=&quot;django-rest-framework&quot;&gt;Django REST Framework&lt;/h2&gt;

&lt;p&gt;Django REST Framework 는 웹 API를 구축할 수 있는 툴킷입니다. 이 프레임워크를 통하여 생성한 Model 을 바탕으로 조건에 맞는 API를 개발할 수 있습니다.&lt;/p&gt;

&lt;p&gt;Install Django REST Framework&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;djangorestframework
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;django-filter &lt;span class=&quot;c&quot;&gt;#Filtering support&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#/djangoProject/settings.py
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'product'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;'rest_famework'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#추가
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSTALLED_APPS&lt;/code&gt; 에 rest_framework 를 추가하면 Django REST Framework 의 기능들을 사용할 준비가 끝났습니다.&lt;/p&gt;

&lt;h2 id=&quot;serializer&quot;&gt;Serializer&lt;/h2&gt;

&lt;p&gt;Serializer 는 queryset 과 model instance 같은 것들을 쉽게 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON&lt;/code&gt; 또는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XML&lt;/code&gt; 의 데이터 형태로 렌더링 할 수 있게 해줍니다. 우리는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product&lt;/code&gt; 모델을 serialize 해줘야 하기 때문에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ModelSerializer&lt;/code&gt;를 사용합니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;product&lt;/code&gt; 디렉토리에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[serializers.py](http://serializers.py)&lt;/code&gt; 파일을 생성합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#product/serializers.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serializers&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# product 모델 사용
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'__all__'&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# 모든 필드 포함
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://serializers.py&quot;&gt;serializers.py&lt;/a&gt; 의 코드입니다.&lt;/p&gt;

&lt;h2 id=&quot;view&quot;&gt;View&lt;/h2&gt;

&lt;p&gt;View 에서는 생성한 Model 에 대하여 기능들을 추가할 수 있습니다. product app 은 생성한 Model 에 대하여 관련 API 개발이 목적이기 때문에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;product/view.py&lt;/code&gt; 에서는 rest_framework 의 view 를 사용하여 API View 를 작성합니다.&lt;/p&gt;

&lt;p&gt;rest_framework 의 API View 는 크게 두가지로 나뉘는데, CBV(Class Based View) 와 FBV(Function Based View) 로 구분 할 수 있습니다. product 모델의 API view 는 CBV 중 APIView 를 사용합니다.&lt;/p&gt;

&lt;p&gt;CBV는 Class 의 장점을 모두 사용할 수 있어 코드의 효율을 극대화 할 수 있는 장점이 있고, 여러가지 조건들에 맞게 API 를 개발할 시, 중복되는 코드의 길이를 줄여 효율을 높일 수 있는 점 등으로 인하여 CBV 중 APIView 를 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#view.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework.response&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;APIView&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.serializers&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProductSerializer&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ProductListAPI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;APIView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;serializer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProductSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;many&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://view.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view.py&lt;/code&gt;&lt;/a&gt; 의 코드 입니다.&lt;/p&gt;

&lt;p&gt;Model을 생성하고 목적에 맞는 &lt;a href=&quot;http://view.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;view.py&lt;/code&gt;&lt;/a&gt; 를 작성하였다면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt;을 매핑 해 주어야 합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#/djangoProject/url.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;product.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProductListAPI&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'admin/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'api/product/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProductListAPI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;product의 API 를 나타내는 json 이 있는 페이지 이므로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'api/product/'&lt;/code&gt; 로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;url&lt;/code&gt;을 매핑 해 주었습니다.&lt;/p&gt;

&lt;p&gt;이제 Django ORM 의 query 에 값들을 입력해 준다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runserver&lt;/code&gt; 를 통하여 &lt;a href=&quot;http://localhost:8000&quot;&gt;localhost:8000&lt;/a&gt;/admin 으로 접속하여 Django admin 페이지에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product&lt;/code&gt; Model에 맞는 값들을 입력합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#Django admin 페이지에 Product 모델을 등록하는 코드
#admin.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.contrib&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;site&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-24-creating-an-api-&amp;amp;-collecting-html-elements-with-django-rest-framework/Untitled%201.png&quot; alt=&quot;Untitled%201&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product&lt;/code&gt; 모델이 추가 되었습니다&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-24-creating-an-api-&amp;amp;-collecting-html-elements-with-django-rest-framework/Untitled%202.png&quot; alt=&quot;Untitled%202&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Model 의 type 에 맞게 값들을 입력합니다.&lt;/p&gt;

&lt;p&gt;빠른 방법으로 하기 위하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;admin&lt;/code&gt; 페이지에서 모델의 값들을.추가하였지만, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; 에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_queryset()&lt;/code&gt; 함수를 사용하여 값들이 입력되게 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product&lt;/code&gt; 모델의 query 에 값들이 입력되었다면 매핑한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/product/&lt;/code&gt; 에 API 출력이 정상적으로 되는지 확인해봅니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-24-creating-an-api-&amp;amp;-collecting-html-elements-with-django-rest-framework/Untitled%203.png&quot; alt=&quot;Untitled%203&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이러한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON&lt;/code&gt; 파일 양식이 출력되었다면 정상적인 API 개발 코드를 완성한 것입니다.&lt;/p&gt;

&lt;h1 id=&quot;django-rest-framework를-활용하여-웹페이지의-html-요소별-api-개발&quot;&gt;Django Rest Framework를 활용하여 웹페이지의 HTML 요소별 API 개발&lt;/h1&gt;

&lt;h2 id=&quot;preview&quot;&gt;Preview&lt;/h2&gt;

&lt;p&gt;웹 페이지를 이루고 있는 HTML 소스를 사용하여 해당 소스의 모든 요소별 정보(요소 이름, 가로/세로 크기, 요소의 위치(좌표)) 등을 크롤링 하여 Django 데이터베이스에 정보를 입력한 후, 해당 정보를 바탕으로 API 개발을 하는 작업입니다. 요소별 정보를 갖고 있는 API 를 활용하는 개발이 이루어질 때, 필요한 API 를 개발하는것이 목적입니다.&lt;/p&gt;

&lt;h2 id=&quot;model-view-serializiers&quot;&gt;Model, View, Serializiers&lt;/h2&gt;

&lt;p&gt;HTML의 요소들은 많은 정보를 갖고 있는데, 이 중 요소의 크기(width / height), 요소의 위치(x 좌표, y좌표)를 크롤링 할 것입니다. 이들 4가지와 요소를 구별해 줄 수 있는 요소별 id 까지 총 5개의 정보로 이루어진 Model을 생성합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#models.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Create your models here.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;specific_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'specific_id'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;156&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;horizon_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'horizon_width'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vertical_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'vertical_width'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'x_location'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'y_location'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__str__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;specific_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;해당 Model 생성 후 migrate를 진행합니다.&lt;/p&gt;

&lt;p&gt;Data Model 을 serialize 하는 &lt;a href=&quot;http://serialziers.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;serialziers.py&lt;/code&gt;&lt;/a&gt; 를 작성합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#serializers.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;serializers&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'__all__'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Django REST Framework 에서 API 를 만들어주도록 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[views.py](http://views.py)&lt;/code&gt; 를 작성합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#views.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework.response&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;rest_framework.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;APIView&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.serializers&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataSerializer&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DataListAPI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;APIView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;serializer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataSerializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;queryset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;many&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;serializer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;url을 매핑 해 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#urls.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.urls&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;.views&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataListAPI&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;urlpatterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'api/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataListAPI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Django 에서 API 개발에 관련한 작업을 마쳤습니다.&lt;/p&gt;

&lt;h2 id=&quot;parserpy&quot;&gt;parser.py&lt;/h2&gt;

&lt;p&gt;웹페이지를 크롤링 할 수 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python&lt;/code&gt; 실행파일을 만듭니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DjangoProject&lt;/code&gt; 디렉토리와 같은 레벨에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parser.py&lt;/code&gt; 파일을 생성합니다.&lt;/p&gt;

&lt;h3 id=&quot;web-crawler&quot;&gt;Web Crawler&lt;/h3&gt;

&lt;p&gt;웹페이지를 크롤링하여 HTML 소스를 얻을 수 있는 라이브러리는 여러 가지가 있는데, 대표적으로 Beautifulsoup4, Selenium 이 사용되고 있습니다. 우리는 요소별 크기, 좌표값을 얻어야 하므로, 이에 더 용이한 라이브러리를 제공하는 Selnium 을 사용합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#parser.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#driver 선언을 통하여 webdriver.Chrome을 사용할 수 있다.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/Users/Kimminjung/Desktop/hobbes/aivory-django-bootstrap/chromedriver'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'https://d-startup.kr/index.es?sid=a1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Selenium 으로 웹 페이지 크롤링을 진행하는 코드 입니다. Selenium 은 웹 드라이버를 사용하여 크롤링을 진행하는데, 우리는 Chrome 을 사용하기 때문에 Chrome web driver를 설치하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;driver&lt;/code&gt; 선언 시 설치된 경로를 명시하여 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#print(page)
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ko&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    ...
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://dstartup.kr/images/kor/main/logo.png&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;property=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;og:image&quot;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;대전창업온라인&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    ...
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page&lt;/code&gt; 를 print 한 결과입니다. 페이지의 HTML 소스가 크롤링 되는 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#parser.py
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#driver 선언을 통하여 webdriver.Chrome을 사용할 수 있다.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/Users/Kimminjung/Desktop/hobbes/aivory-django-bootstrap/chromedriver'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'https://d-startup.kr/index.es?sid=a1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_element_by_xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//xpath&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#e 의 좌표가 딕셔너리 타입으로 출력된다.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#e의 크기가 딕셔너리 타입으로 출력된다.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Selenium 은 많은 기능을 갖고 있는데, 이 중 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;find_element_by_xpath&lt;/code&gt; 를 사용합니다. 이 함수는 요소들의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xpath&lt;/code&gt; 를 기준으로 찾는 기능을 갖고있는 함수입니다. &lt;a href=&quot;http://parser.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parser.py&lt;/code&gt;&lt;/a&gt; 는 모든 웹페이지를 대상으로 작동해야 하기 때문에 웹페이지 별로 다른 값을 가지는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; 등을 기준으로 크롤링을 진행하는 것은 목적에서 벗어납니다.&lt;/p&gt;

&lt;p&gt;이에 따라 트리 구조를 갖고 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xpath&lt;/code&gt; 를 기준으로 크롤링을 진행합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;51&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'height'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;39&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'width'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;148&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위의 코드에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location&lt;/code&gt; 과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size&lt;/code&gt; 를 print 한 결과입니다. Selenium 을 사용하여 이렇게 요소의 좌표 및 크기 값을 얻을 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;lxmletree&quot;&gt;lxml.etree&lt;/h3&gt;

&lt;p&gt;모든 요소를 크롤링 하는것이 목적입니다. 이를 위하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lxml&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etree&lt;/code&gt; 라이브러리의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getpath()&lt;/code&gt; 를 사용하여 모든 요소의 XPath 를 얻어 올 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTMLParser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getroot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;htmlTree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElementTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;먼저, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;etree.HTMLParser()&lt;/code&gt; 를 사용하여 전체 HTML 소스를 파싱 하여 줍니다. 이는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getpath()&lt;/code&gt; 를 사용하기 위함인데, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getpath()&lt;/code&gt; 는 파싱된 트리의 최상위 노드인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; 를 사용하여 하위 트리의 모든 요소의 XPath 를 얻어오는 함수이기 때문입니다. 위 코드를 사용하여 전체 HTML 소스의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; 를 얻어옵니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
	  &lt;span class=&quot;n&quot;&gt;x_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;htmlTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter()&lt;/code&gt; 는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; 요소에 대한 iterator를 만든 뒤, 문서 순서대로 모든 요소를 반복하하며 순회하는 기능을 가진 함수입. 위의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; 문을 통하여 모든 요소의 XPath를 가져올 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;head&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; 문을 출력한 값입니다. 이 방법을 통하여 모든 요소의 XPath를 가져왔습니다.&lt;/p&gt;

&lt;h2 id=&quot;parserpy-with-django&quot;&gt;&lt;a href=&quot;http://parser.py&quot;&gt;parser.py&lt;/a&gt; with Django&lt;/h2&gt;

&lt;p&gt;이제 &lt;a href=&quot;http://parser.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parser.py&lt;/code&gt;&lt;/a&gt; 로 크롤링 한 데이터들을 Django ORM을 통해서 DB에 넣어주어야 합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lxml&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setdefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DJANGO_SETTINGS_MODULE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;djangoProject.settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;django&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;minjung.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os&lt;/code&gt;를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; 하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parser.py&lt;/code&gt; 가 실행될 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;DJANGO_SETTINGS_MODULE&quot;&lt;/code&gt;이라는 환경 변수에 현재 프로젝트의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;settings.py&lt;/code&gt;파일 경로가 등록됩니다.
그리고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Django&lt;/code&gt;를 사용하기 위하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Django&lt;/code&gt;를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; 하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;django.setup()&lt;/code&gt;을 통하여 프로젝트를 사용할 수 있도록 환경을 세팅한 뒤, 우리의 Model, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data&lt;/code&gt; 를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; 합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;selenium&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;lxml&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setdefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DJANGO_SETTINGS_MODULE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;djangoProject.settings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;django&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;minjung.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 옵션 생성
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ChromeOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 창 숨기는 옵션 추가
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_argument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;headless&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#driver 선언을 통하여 webdriver.Chrome을 사용할 수 있다.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;webdriver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/Users/Kimminjung/Desktop/hobbes/aivory-django-bootstrap/chromedriver'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'__main__'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'https://d-startup.kr/index.es?sid=a1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_source&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HTMLParser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getroot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;htmlTree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;etree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ElementTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;x_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;htmlTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_element_by_xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;specific_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;horizon_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'width'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;vertical_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'height'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;x_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;y_location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://parser.py&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parser.py&lt;/code&gt;&lt;/a&gt; 의 전체 코드 입니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;specific_id&lt;/code&gt; 는 요소들의 고유한 값인 XPath로 설정해 줍니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data().save&lt;/code&gt; 코드를 통하여 Django에 크롤링한 정보를 연동시킬 수 있습니다.&lt;/p&gt;

&lt;p&gt;자, 이제 runserver 를 통하여 API 가 정상적으로 개발되었는지 확인하겠습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-24-creating-an-api-&amp;amp;-collecting-html-elements-with-django-rest-framework/Untitled%204.png&quot; alt=&quot;Untitled%204&quot; /&gt;&lt;/p&gt;

&lt;p&gt;JSON이 정상적으로 출력되는 것을 확인할 수 있습니다.&lt;/p&gt;
</description>
        <pubDate>Wed, 24 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/02/24/creating-an-api-&-collecting-html-elements-with-django-rest-framework.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/02/24/creating-an-api-&-collecting-html-elements-with-django-rest-framework.html</guid>
        <tags>
          
          <tag>Django</tag>
          
          <tag>DRF</tag>
          
          <tag>HTML Elements</tag>
          
          <tag>API</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Custom Data 로 이미지 분류 전이학습 하기</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
          
          <author>
            <name>오재성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/cnu_buster.png</image>
          </author>
          
          
          
          <author>
            <name>조윤혁</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/cnu_jo.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%202.png</thumbnail>
        <description>&lt;h1 id=&quot;abstract&quot;&gt;Abstract&lt;/h1&gt;

&lt;p&gt;검색도구를 이용하는 고객들의 단순한 키워드만으로 검색 의도를 완벽하게 파악하기 어려운 경우가 많습니다. 하지만 유사 이미지 분류기술을 활용한 이미지 검색 기술은 고객이 직접 대상의 특징을 서술하지 않아도 특정 이미지를 입력하여 이와 유사한 이미지를 분류하고 검색도구에 힘을 실어 줄 수 있는 기술입니다.&lt;/p&gt;

&lt;p&gt;이번 글에서는 이러한 검색 자료에 활용될 수 있고 사용자의 이미지 객체를 인식하여 기존에 데이터베이스에 저장된 객체와 얼마나 유사한지 분류하기 위한 방법인 유사이미지 분류 기술을 학습하고 구현한 방법을 소개하려고 합니다.&lt;/p&gt;

&lt;p&gt;앞서 큰 틀이 되는 인공지능 기술인 전이학습(Transfer Learning)과 전이학습에 사용될 모델의 이해, 학습용 데이터셋에 대해 어떻게 이해하고 활용 했는지에 대한 내용을 기술합니다.&lt;/p&gt;

&lt;h1 id=&quot;1-전이학습-기술이해--학습을-위한-모델-선정&quot;&gt;1. 전이학습 기술이해 &amp;amp; 학습을 위한 모델 선정&lt;/h1&gt;

&lt;h2 id=&quot;1-1-전이학습-이해&quot;&gt;1-1. 전이학습 이해&lt;/h2&gt;

&lt;p&gt;⇒ ‘유사 이미지 분류’ 기술을 구현하는데 앞서 큰 틀은 전이학습(Transfer Learning)기반이 되며 이 기술은 특정 Task 또는 도메인에서 얻은 모델을 다른 Task에 적용하는 기술로, 이미 학습된 모델의 가중치를 가져와서 분류하고 싶은 다른 데이터셋에 적용하는 것으로 이해할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;전이학습을-사용하는-세가지-특징&quot;&gt;전이학습을 사용하는 세가지 특징&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;적은 데이터셋을 사용하여 모델 학습&lt;/li&gt;
  &lt;li&gt;대부분의 경우 전이학습한 모델이 처음부터 쌓은 모델보다 성능이 뛰어나다.&lt;/li&gt;
  &lt;li&gt;시간이 절약이 된다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;처음에 위의 특징 중 2번이 이해가 되지 않았습니다. ‘&lt;strong&gt;왜 내가 다루고자하는 데이터셋을 기존에 다른 데이터셋에 맞추어 학습된 모델에 학습을 시키는데 처음부터 쌓은 모델보다 성능이 좋을까?’&lt;/strong&gt; 라는 의문이 들었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/level_feature.png&quot; alt=&quot;level_feature&quot; /&gt;&lt;/p&gt;

&lt;p&gt;질문에 대한 해답은 딥러닝은 &lt;strong&gt;“계층적인 특징”&lt;/strong&gt;을 &lt;strong&gt;“스스로”&lt;/strong&gt; 학습한다. 라는 점이 었습니다. 모델의 low level layer는 general feature를 추출하고 모델이 쌓여갈 수록 high level layer에서는 specific한 feature을 추출해내는 고도화된 학습이 이루어집니다. 따라서 초기 layer의 general feature들은 학습할 때 재사용해도 되지만 후반부에 위치한 layer의 specific feature들은 재학습이 필요합니다.&lt;/p&gt;

&lt;p&gt;예를 들어 쉽게 설명하자면 MNIST와 같은 데이터셋에 따라 학습을 시킨 모델의 경우, 초기 layer는 직선이나 곡선 같은 general한 feature를 추출할 것이고 이렇게 추출된 feature map은 한글이나 영어문자에 대한 데이터셋에도 효과적으로 재사용할 수 있다고 추측하는 것입니다.&lt;/p&gt;

&lt;h3 id=&quot;전이학습의-주요-키워드-세가지&quot;&gt;전이학습의 주요 키워드 세가지&lt;/h3&gt;

&lt;p&gt;전이학습을 이해하는데 있어서 주요한 세가지의 키워드가 있습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ConvNet as fixed feature extractor(=고정 기능 추출기)&lt;/strong&gt;
⇒ 처음에는고정기능추출기라는 용어를 이해하는데 힘들었던 것 같습니다. 하지만 이해를 한다면 왜 고정기능추출기이라고 불리는지 금방 이해할 수 있습니다. 예를 들어 어느 특정 데이터셋에 대해 이미 학습된 ConvNet 모델을 가져온 후 위에 특징 2번에서 말했듯 초기 layer는 고정합니다. 후에 마지막 Classifier부분을 제거하고 새로 분류하고 자하는 데이터셋의 카테고리 수에 맞게 초기화 해주는 것입니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fine-tuning the convNet(=미세조정)&lt;/strong&gt;
⇒ 두 번째 키워드인 Fine-tuning은 고정된 부분도 학습을 재진행할 수 있지만 교체한 마지막 fc(fully-connected)부분만 다시 재학습을 시켜주는 것 뿐만 아니라 역전파를 계속하는 것을 뜻하기에 ‘미세조정’이라는 말을 쓴 것 같습니다. 참고로 ConvNet의 모든 계층을 fine tuning하거나 초기 layer 중 일부를 고정상태로 유지할 수 있습니다. 초기 layer 중 일부를 고정하는 것은 overfitting문제를 방지하기도 합니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Pretrained models&lt;/strong&gt;
⇒ model의 weight를 공유해서 fine-tuning하는 것은 시간이 절약된다는 장점이 있습니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;fine-tuning을-어떤-상황에서-해야하는지에-대한-4가지-시나리오&quot;&gt;fine-tuning을 어떤 상황에서 해야하는지에 대한 4가지 시나리오&lt;/h3&gt;

&lt;p&gt;신경써야할 두가지 중요한 요소는 아래와 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;데이터셋의 크기&lt;/li&gt;
  &lt;li&gt;pretrained된 모델에 사용한 데이터셋과의 유사도&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;데이터셋에 따른 4가지 시나리오&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;New Dataset&lt;/th&gt;
      &lt;th&gt;크기&lt;/th&gt;
      &lt;th&gt;유사도&lt;/th&gt;
      &lt;th&gt;fine-tuning 적용여부&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;A Dataset&lt;/td&gt;
      &lt;td&gt;small&lt;/td&gt;
      &lt;td&gt;high&lt;/td&gt;
      &lt;td&gt;데이터셋이 너무 작아 ConvNet의 overfitting문제를 해결하려고 fine-tuning을 하는 것은 좋지 않은 생각이입니다. 원본 데이터셋과 유사도가 높기때문에 higher-level의 feature가 새 데이터셋과 관련이 있을 것으로 예상되며 linear classifier만 train시키는 쪽으로 생각하면 됩니다.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;B Dataset&lt;/td&gt;
      &lt;td&gt;small&lt;/td&gt;
      &lt;td&gt;low&lt;/td&gt;
      &lt;td&gt;linear classifier만 학습하는 것이 좋은 방법입니다. 또한 데이터셋이 매우 다르기에 후반부의 layer만 fine-tuning하는 것은 좋은 방법이 아니며 초기 layer에서 재학습하는 것이 효과적일 수 있습니다.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;C Dataset&lt;/td&gt;
      &lt;td&gt;big&lt;/td&gt;
      &lt;td&gt;high&lt;/td&gt;
      &lt;td&gt;이 경우는 문제가 되는 부분이 없습니다. 다만 fine-tuning만 해주면 overfit하지 않을 것이라는 확신만 있을 뿐입니다.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;D Dataset&lt;/td&gt;
      &lt;td&gt;big&lt;/td&gt;
      &lt;td&gt;low&lt;/td&gt;
      &lt;td&gt;fine-tuning 수행의미가 없다고 생각합니다. 처음 부터 모델링을 만드는 것이나 마찬가지 이기 때문입니다.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;실습은 &lt;a href=&quot;http://pytorch.org/&quot;&gt;PyTorch.org&lt;/a&gt; 사이트에서 전이 학습에 대한 코드를 Colab, Jupyter notebook, GitHub으로 공유하고 있고 이 공유된 코드를 통해 전이학습에 대한 이해를 깊게 할 수 있습니다. → &lt;a href=&quot;http://tutorials.pytorch.kr/beginner/transfer_learning_tutorial.html&quot;&gt;&lt;strong&gt;실습링크&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;1-2-densenet-모델-선정&quot;&gt;1-2. DenseNet 모델 선정&lt;/h2&gt;

&lt;h3 id=&quot;resnet과-densenet&quot;&gt;ResNet&lt;strong&gt;과 DenseNet&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;ResNet은 2015년에 열린 ILSVRC에서 등장해 우승을 차지한 이미지 분류 모델로 깊은 네트워크 층으로 부터 생기는 학습 에러와 복잡도 문제를 해결하기 위해 고안되었습니다.&lt;/p&gt;

&lt;p&gt;입력에서 바로 출력으로 연결되어 기존의 출력값(H(x))에서 입력값(x)을 뺀 차이를 얻기 위해 학습하는 (출력 : H(x) = F(x) + x) Skip Connection이라는 개념을 도입해서 높은 수준의 정확도를 보여주게 되었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%201.png&quot; alt=&quot;Untitled%201&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(좌) Resnet의 설계 구조, (우) Densenet의 설계구조&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그러던 중 레이어 간 정보 흐름을 좀 더 자연스럽게 한 DenseNet의 등장은 이러한 Skip Connection을 빽빽하게(Dense) 늘려서 핵심 특징을 잘 추출하는 동시에 그레디언트 소멸 문제에도 대응하도록 보완하며 발전하게 되었습니다.&lt;/p&gt;

&lt;p&gt;이러한 바탕 속 ResNet을 비롯한 이전 전통적인 CNN모델과 차별되는 특징 추출 능력은 DenseNet이 저희의 트레이너 모델로 선정하는 계기가 되기도 하였습니다.&lt;/p&gt;

&lt;h3 id=&quot;모델을-탐구하는-이유&quot;&gt;모델을 탐구하는 이유&lt;/h3&gt;

&lt;p&gt;: 보통 Pytorch나 Keras 같은 라이브러리에서 제공하는 모델을 호출할때는 기본적으로 필요한 parameter값만 확인해 적절히 넣어주면 문제 없이 동작하는 모습을 보여줍니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision.models&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;resnet18&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resnet18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;alexnet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alexnet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;squeezenet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;squeezenet1_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vgg16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vgg16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;densenet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;densenet161&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;inception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inception_v3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;googlenet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;googlenet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hufflenet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shufflenet_v2_x1_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mobilenet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mobilenet_v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resnext50_32x4d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resnext50_32x4d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wide_resnet50_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wide_resnet50_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sresnext50_32x4d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resnext50_32x4d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wide_resnet50_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wide_resnet50_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mnasnet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mnasnet1_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pretrained&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;torchvision에 models 하위 카테고리에만 해도 이렇게 다양한 모델을 버전별로 호출해서 사용할수 있기에 일반적으로 학습을 위한 데이터만 구축되있다면 이미지 분류, 처리 분야에 있어서 검증된 모델을 통해 원하는 카테고리에 대한 학습을 진행할수 있습니다. 하지만 직접적으로 기존 모델을 커스터마이징 할필요가 생긴다면 라이브러리로 불러오는 모델의 내부 구조와 코드를 어느정도 이해하는 편이 도움이 될 수 있을 것입니다.&lt;/p&gt;

&lt;p&gt;예를들어 다양한 모델을 적용한 것같은 효과를 볼수 있는 DropOut을 적용하거나 학습 속도를 빠르게 하기 위해 일부분을 변경한다던가 하는 상황이 충분히 있을 수 있기 때문입니다.&lt;/p&gt;

&lt;p&gt;목표로 설정된 트레이너 제작에서도 사용자 혹은 협업자의 편의성 및 성능 향상 등을 목적으로 한 커스터마이징 작업을 위해선 구조를 제대로 파악해 엉뚱한 코드를 건드리지 않도록 혹은 모델의 구조와 구조에 대응하는 코드에 대해 전반적인 이해가 필요할 것입니다.&lt;/p&gt;

&lt;p&gt;사용할 torchvision의 DenseNet모델에 대한 코드 분석을 진행해보도록 하겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;densenet-의-아키텍처&quot;&gt;Densenet 의 아키텍처&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://github.com/pytorch/vision/blob/master/torchvision/models/densenet.py&quot;&gt;github.com/pytorch/vision/blob/master/torchvision/models/densenet.py&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;→ 트레이너애 사용된 modeling_densenet.py 코드의 전신인 torchvision densenet의 원본 코드&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%202.png&quot; alt=&quot;Untitled%202&quot; /&gt;&lt;/p&gt;

&lt;p&gt;코드를 살펴보기 전에 먼저 Densenet의 구조와 특징에 대해서 알아보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;사진에서 나와있는 것처럼 Resnet을 이미 접해본 분들에게는 살짝 익숙한 느낌이 들수 있는 설계 구조가 나타납니다. 차이점이라면 Resnet은 직전 레이어의 입력 값만 출력에 반영되어 다음 레이어로 가는 입력에 반영되는 반면 Densenet은 직전 레이어 입력 뿐 아니라 블록 내에서 거처간 레이어들이 모두 다음 레이어 입력에 반영된다는 특징을 가지고있습니다. 텐서의 차원같은 느낌인 채널이 블록이 끝날 때까지 지속적으로 쌓이는 구조라 생각하시면 될 것 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;http://arxiv.org/pdf/1608.06993.pdf&quot;&gt;arxiv.org/pdf/1608.06993.pdf&lt;/a&gt; → 포스팅에 바탕이 된 원본 논문&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;만약 Block내에 x개의 레이어가 존재한다면 Resnet에서는 각 레이어 당 1개 총 x개의 지름길이 형성되지만 densenet은 각 레이어 당 1, 2, 3 … 참조하는 이전 레이어 입력(초기 입력되는 채널 포함 )이 1씩 증가하는 등차수열로 형성되어서 등차수열의 합 공식을 적용하면 총 x(x+1)/2 개의 지름길이 형성됩니다.&lt;/p&gt;

&lt;p&gt;논문에서는 이러한 Densenet의 강점으로 이러한 부분을 소개하고 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;alleviate the vanishing gradient (-&amp;gt; 그레디언트 소멸 문제 완화)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;strengthen feature propagation (-&amp;gt; 강력한 특징 전파력)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;encourage feature reuse (-&amp;gt; 특징 값 재사용 활성화)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;substantially reduce the number of parameters (-&amp;gt; 계산량을 줄이기 위해 필요한 파라미터 갯수 감소)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%203.png&quot; alt=&quot;Untitled%203&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위에 사진은 Densenet전체의 한 블록 내의 구조를 표현한 것이며 3개의 Block이 합쳐진 전체 구조를 표현한 논문 내의 그림입니다. 비록, 그림에는 3개의 블록이 표시되었지만 이번에 사용할 torchvision의 기본적으로 block의 갯수는 4개의 형태를 보여줍니다.&lt;/p&gt;

&lt;p&gt;마지막 블록을 제외하면 Transition Layer라고 불리는 배치 정규화 + Relu 활성함수+ 1x1 컨볼루션을 거치는 구조로 이루어진 합성합수와 평균 풀링으로 이루어진 레이어가 등장하는데, 위에서 계속 지나간 이전 레이어들의 입력 값을 반영하다 보면 다음 레이어가 들어갈 입력값의 채널이 지나치게 비대해 질수 있습니다.&lt;/p&gt;

&lt;p&gt;각 레이어의 입력에는 파이토치의 텐서가 들어가는데  Transition Layer는 이 텐서의 채널을 반토막으로 줄여주고 이미지 사이즈에 해당하는 크기를 1/4로 줄여줍니다. 안에 있는 평균 풀링의 보폭이 기본적으로 2 이므로 1/4사이즈로 줄어드는 것이고 보폭을 늘리면 1/보폭의 제곱 만큼 사이즈가 줄어들 것입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%204.png&quot; alt=&quot;Untitled%204&quot; /&gt;&lt;/p&gt;

&lt;p&gt;채널 수의 증가는 파라미터의 증가로 이어져 계산량이 폭발적으로 늘어나게 되는데 1x1컨볼루션은 채널을 줄여줘 우리들의 GPU(혹은 CPU)와 RAM 연산 부담을 줄여주는 담당해주며 이렇게 채널을 줄였다 늘렸다 조절하는 구조를 bottleneck구조라고 합니다.&lt;/p&gt;

&lt;p&gt;마지막에 Linear라고 표시된 부분은 마지막 block을 지나고 출력된 채널 수 만큼의 1차원 텐서가 분류하고 싶은 속성 값에 해당되는 Tensor 배열(torchvision에서의 default값은 1000)에 각각 Fully Connect를 해주는 부분으로 이번에 전이학습을 통해 트레이너를 제작할시 바꿔줄 부분입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%205.png&quot; alt=&quot;Untitled%205&quot; /&gt;&lt;/p&gt;

&lt;p&gt;마지막으로 알아둬야 할 부분은 Densenet버전에 따라서 모델 내의 레이어 수가 달라진다는 점 입니다. 트레이너에 사용할 121모델 같은 경우는 각 블록 마다 6(첫번째), 12(두번째), 24 ,16의 레이어로 구성되어있으며 169 모델은 6, 12, 32, 32의 레이어 숫자를 가진 블록으로 구성되어 있는 등 버전 마다 레이어 수가 조금씩 다르고 경우에 따라선 모델 내 입출력 텐서도 다를수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;객체-지향적-모델-코드&quot;&gt;&lt;strong&gt;객체 지향적 모델 코드&lt;/strong&gt;&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%206.png&quot; alt=&quot;Untitled%206&quot; /&gt;&lt;/p&gt;

&lt;p&gt;torchvision 내의 densenet.py코드는 이러한 레이어 , 블록, 그리고 본체의 모델은 각각 class로 선언되어 상위 객체가 하위객체를 호출하는 객체지향적 방식으로 구성되어 있습니다.&lt;/p&gt;

&lt;p&gt;전반적인 Densenet의 구조와 특징을 알아보았다면 코드를 살펴보도록 하겠습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DenseNet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;num_init_features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DenseNet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# First convolution
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderedDict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'conv0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Conv2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_init_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kernel_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stride&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'norm0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BatchNorm2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_init_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'relu0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReLU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inplace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'pool0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MaxPool2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kernel_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stride&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Each denseblock
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_init_features&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_DenseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# block객체 생성
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;num_input_features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'denseblock%d'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# transition layer객체 생성
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;trans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Transition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_input_features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;n&quot;&gt;num_output_features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'transition%d'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trans&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Final batch norm
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'norm5'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BatchNorm2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Linear layer
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;인자로 들어가는 파라미터 중 핵심 요소에 대한 짧은 설명을 하자면&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;growth_rate&lt;/strong&gt; : 각 레이어에서는 growth_rate크기 만큼의 고정된 크기의 채널을 가진 텐서를 output으로 출력합니다. 아까 위에서 이전 레이어들의 입력 값들이 반영되 채널이 쌓이게 되는 것이 Densenet의 핵심인데 growth rate를 직역하면 성장률이 되기때문에 채널의 성장을 표현한 네이밍이 될 것 같습니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;block_config&lt;/strong&gt; : Densenet에 들어갈 block들의 레이어 수를 튜플로써 표현한 것으로 기본 default값은 6, 12, 24, 16으로 121버전이 설정되어있음을 알수 있습니다. (첫 블록은 6개 두번째는 12개 세번째는 24개 네번째는 16개의 레이어로 이루어짐)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;num_init_features&lt;/strong&gt; : 처음으로 입력 값이 들어가는 Convolution층에는 3개의 채널로 이루어진 이미지 텐서가 들어가게 됩니다. 3가지 채널은 빛의 3원색인 RGB를 뜻해서 3개의 채널인데 이 입력 텐서를 처음에 몇 채널로 바꿔줄지 결정하는 역할을 수행합니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;num_classes&lt;/strong&gt; : 분류하려는 클래스의 갯수를 의미합니다. 여기서는 default값이 &lt;del&gt;ImageNet이 생각나는&lt;/del&gt; 1000이라 그냥 모델을 인자를 수정해주며 활용만 하는게 목적이라고 해도 이 부분은 직접 설정을 해주어야합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;_DenseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_input_features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_DenseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;layer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_DenseLayer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# layer객체 생성
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;num_input_features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bn_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drop_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memory_efficient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'denselayer%d'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;모든 블록, 레이어를 포함하는 상위 객체인 DenseNet클래스가 하위 객체인 dense_block과 trainsition_layer를 호출하고 dense_block이 자기 보다 하위 객체인 dense_layer를 호출하는 자료구조의 Tree 프론트엔드의 DOM같은 구조를 띄고 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;2-구현한-내용-및-결과&quot;&gt;2. 구현한 내용 및 결과&lt;/h1&gt;

&lt;h2 id=&quot;2-1-모델-세팅&quot;&gt;2-1. 모델 세팅&lt;/h2&gt;

&lt;h3 id=&quot;모델-초기화&quot;&gt;모델 초기화&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;초기화 부분&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;class_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;class_length&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cuda&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cpu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'config_file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'UTF-8'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;densenet_cfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# config_file : model의 hyper parameter
&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# Prepare Model
&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Loading DenseNet121 network.....&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DenseNet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;growth_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;densenet_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;growth_rate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;block_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;densenet_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;block_config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;num_init_features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;densenet_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;num_init_features&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'weight_file'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델에게 가중치 부여
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;: 위에 설명한 yaml파일에서 미리 설정해둔 값을 property 변수에 담아서 필요한 파일에 대한 참조를 진행합니다. 그 중 모델에 대한 초기 설정을 가지고 있는 config파일을 가져와 원하는 값으로 설정 및 초기화를 진행해줍니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;마지막 classifier 분리 후 데이터셋의 카테고리 수에 맞도록 초기화 해주는 부분&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;'''
여기서 각 출력의 크기는 데이터셋의 카테고리 수로 설정합니다.
nn.Linear(num_ftrs, len (class_names))로 일반화할 수 있습니다.
output을 parameter로 받아주도록 해야한다!!
'''&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;num_ftr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model_conv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_feature&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model_conv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_ftr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;: 분류기에 대한 전이 학습에 알맞게 기존 densenet 가중치 파일이 적용된 classifier 부분을 랜덤한 가중치를 가진 Fully Connected부분으로 초기화 시켜주는 것이 핵심입니다.&lt;/p&gt;

&lt;p&gt;해당 부분을 통해 분류를 원하는 카테고리에 따라서 다르게 Classifier를 학습 후 적용하는 것이 가능해집니다.&lt;/p&gt;

&lt;h2 id=&quot;2-2-트레이너-설정-학습-및-평가&quot;&gt;2-2. 트레이너 설정, 학습 및 평가&lt;/h2&gt;

&lt;h3 id=&quot;busters-trainer&quot;&gt;Buster’s trainer&lt;/h3&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;train_classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.00005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'''해당 파일의 알파이자 오메가. 이미 학습되있는 모델 본체의 pth파일과 학습이 필요한 classifier를
        불러와 머신러닝을 진행한다. 중간중간 validate_and_save함수를 호출해 평가를 진행하고 필요시 저장한다'''&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;train_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageFolder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address_book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train_address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                                                      &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;data_loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;drop_last&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ 먼저 여타 다른 모델 훈련처럼 위에 설명한 yaml파일에 설정한 학습 데이터의 경로에서 ImageFolder 함수를 이용하여 카테고리 이름으로 명명된 디렉토리로 구분된 이미지 데이터들을 가져옵니다. 만약 이미지 데이터 이외에 데이터의 경우 해당 파일은 ImageFolder함수에서 자동으로 필터링됩니다. 데이터를 카테고리 분류별로 불러오고 학습을 위해 다음 두 가지를 추가로 수행해야 합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;dataloader에서 마찬가지로 사전에 설정한 batch_size를 가져와서 해당 batch_size만큼 ImageFolder로 가져온 데이터들을 나눈 후 나머지 부분을 drop하는 경우 없이 섞어줍니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;criterion(목적함수 혹은 손실함수)과 optimizer로는 각각 교차 엔트로피와 dagrad와 RMSProp의 장점을 합친 Adam을 설정해줍니다. Adam에 경우 step의 크기나 그레디언트의 크기에 영향을 받지 않으며 어떤 목적 함수에도 호환되고 안정적인 최적화를 위한 하강이 가능하다는 장점을 가지고 있는게 눈에 띄어서 선택하게 되었습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;추가로 현재 트레이너에서는 오직 분류기 부분만 학습을 진행할 것이기 때문에 생성자 부분에서 따로 분리한 객체 내 classifier의 가중치만 optimizer에 넣어주도록 해야합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;추가적으로,학습률(learning_rate) 또한 yaml에서 설정 가능합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;train_classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.00005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch_idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;samples&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;samples&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;prediction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prediction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

                &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ dataloader에 저장된 이미지 tensor 값과 카테고리 번호에 해당하는 값을 x와 y에 저장하고&lt;/p&gt;

&lt;p&gt;→ device등록&lt;/p&gt;

&lt;p&gt;→ 생성자의 model에 넣고 block과 각종 레이어를 거쳐 &lt;strong&gt;순전파&lt;/strong&gt;된 결과를 원래 카테고리 번호와 비교&lt;/p&gt;

&lt;p&gt;→ 교차 엔트로피를 통해 오차를 계산하고 해당 오차(손실)값을 이전 레이어에 &lt;strong&gt;역전파&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;등의 과정을 반복하며 트레이너의 학습이 진행됩니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;train_classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.00005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;minEpoch_toSave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;You just activate my val Card&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;models_score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;validate_and_save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models_score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                    &lt;span class=&quot;c1&quot;&gt;# in more than three epoch statem every 100 step, save weight file temporary
&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

	&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;validate_and_save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models_score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;( ※ minEpoch_toSave는 yaml파일에서 설정하는 속성으로 평가를 진행하기 위해 순회해야할 최소 epoch수를 의미합니다. 즉, 아직 데이터를 전체적으로 보지 못해 학습이 안된 초기부터 평가를 진행하면 무의미한 결과가 나올 가능성이 높아서 일정량의 학습이 이루어진 후 평가가 진행되기 위해 설정한 속성 )&lt;/p&gt;

&lt;p&gt;⇒ 설정된 batch_size를 1step으로 해서, epoch마다 평가를 원하는 일정 step수가 지나면 따로 저장된 검증 데이터를 통해 정확도 평가를 진행하고 이전보다 개선된 결과가 나오면 현재 가중치 상태를 저장합니다.&lt;/p&gt;

&lt;p&gt;마지막 코드 라인에서 사용자가 설정한 step주기 뿐 아니라 학습 종료 시에도 평가를 진행하며 정확도에 개선되었을 경우 모델 가중치의 최종본을 따로 저장해둡니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;train_classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.00005&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batchs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reduceLR_term&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reduce_LR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# for prevent overfitting, adaptive learning rate used
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reduce_LR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'''적응적 학습률을 구현. train함수에게 호출되며 사용자가 임의로 조절 가능하다.'''&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learning_rate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;85&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'reduce learning rate to'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;( ※ reduceLR_term은 yaml파일에서 학습률을 조정할 epoch 주기를 설정하는 속성입니다. )&lt;/p&gt;

&lt;p&gt;⇒ 추가적으로 적응적 학습률을 도입하여 사용자가 설정한 일정 epoch주기마다 현재 학습률을 15% 감소시키는 기능을 추가하였습니다. 해당 기능을 통해 경사하강법(Gradient Descent With Momentum)에서 진동을 줄이는 것처럼 모델 내에서 미세한 조정을 가능하게 해서 더 정확한 결과를 유도하게 됩니다.&lt;/p&gt;

&lt;h3 id=&quot;jos-trainer&quot;&gt;Jo’s trainer&lt;/h3&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SGD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;learning_rate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;momentum&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr_scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StepLR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;step_size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;gamma&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ 손실함수와 optimizer를 학습을 진행하기전에 설정하며 optimizer와 scheduler에 사용되는 parameter 값은 위의 yaml파일에서 설정한 값입니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;dl&gt;
      &lt;dt&gt;criterion&lt;/dt&gt;
      &lt;dd&gt;손실함수는 CrossEntropyLoss를 사용합니다.&lt;/dd&gt;
    &lt;/dl&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;dl&gt;
      &lt;dt&gt;optimizer&lt;/dt&gt;
      &lt;dd&gt;SGD(Stochastic Gradiant Descent)를 사용하여 mini batch에 대해서 손실함수를 계산하고 최적점으로 이동하는 과정에서 Momentum이라는 성질을 이용한다는 특징이 있습니다.
이 특징은 mini batch에 대해 손실함수를 계산하고 weight 업데이트를 하기에 learning rate가 작아도 업데이트되는 weight가 noisy합니다. Momentum알고리즘을 추가하여 업데이트되는 weight의 비율을 줄여 일부 데이터의 모음만 가지고 효과적으로 weight를 갱신합니다.&lt;/dd&gt;
    &lt;/dl&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;dl&gt;
      &lt;dt&gt;sheduler&lt;/dt&gt;
      &lt;dd&gt;Learning Rate Scheduler를 사용하면 좀 더 효율적으로 Global Minimam에 수렴할 수 있도록 도와줍니다.&lt;/dd&gt;
    &lt;/dl&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;best_model_wts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deepcopy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;best_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_epochs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'val'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# train mode와 validation mode순으로 진행
&lt;/span&gt;	    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'train'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
	        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델을 train 모드로 설정
&lt;/span&gt;	    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
	        &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델을 eval(=val) 모드로 설정
&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;running_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;running_corrects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;# 데이터를 반복
&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_step&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# yaml파일에서 정한 step을 기준으로 평가 및 기록
&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_step&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;best_step_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# step마다 정확도를 최초에 평가할때 최소 0.7을 넘겨야 함
&lt;/span&gt;
		  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataloaders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))):&lt;/span&gt;
	        &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	        &lt;span class=&quot;n&quot;&gt;labels&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

				  &lt;span class=&quot;c1&quot;&gt;# 매개변수 Gradiant를 0으로 초기화
&lt;/span&gt;	        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	        &lt;span class=&quot;c1&quot;&gt;# 순전파(foward)
&lt;/span&gt;	        &lt;span class=&quot;c1&quot;&gt;# 학습 시(train)에만 연산 기록을 추적
&lt;/span&gt;	        &lt;span class=&quot;c1&quot;&gt;# CustomModel클래스에서 모델생성시 결정됨
&lt;/span&gt;	        &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_grad_enabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'train'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;preds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	        &lt;span class=&quot;c1&quot;&gt;# 학습 단계인 경우 역전파 + 최적화
&lt;/span&gt;	        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'train'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	            &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

					&lt;span class=&quot;n&quot;&gt;running_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;running_corrects&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'val'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;step_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;running_corrects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hyper_parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'batch_size'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# step을 일단 10으로 지정 --&amp;gt; 나중에 step이라는 hyper parameter표시
&lt;/span&gt;              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;best_step_acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;best_step_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step_acc&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;best_step_wts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deepcopy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'train'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
	          &lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

				&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'val'&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;best_acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;best_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch_acc&lt;/span&gt;
						&lt;span class=&quot;n&quot;&gt;best_model_wts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deepcopy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 높은 정확도일때 weight를 저장
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 가장 나은 모델 가중치를 불러옴
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load_state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_model_wts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 가장 나은 모델 가중치를 저장
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight_save_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;model_weight_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_model_wts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;weight_save_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ 학습(Training)과 검사(Test or Val)을 나누지 않고 한 테스크로 이루어지도록 구성하였습니다. 이런 구성은 매epoch마다 train, test 정확도를 확인을 하며 최적의 epoch값을 구할 수 있습니다.&lt;/p&gt;

&lt;p&gt;→ 먼저, 한 에폭을 돌때 train인지 val인지 따라 모드가 설정되며 train일 경우에만 역전파와 최적화를 해주도록 되어있습니다.&lt;/p&gt;

&lt;p&gt;→ 중간에 step변수를 할당받는데 이는 이미 yaml파일에 지정된 값입니다. 사용자가 Dataset의 크기를 고려해 수정이 가능하며 이번 과제에서는 10으로 설정하였고 step 10마다 기록 및 평가를 진행합니다.&lt;/p&gt;

&lt;p&gt;→ 정리하자면 val 평가가 종료되면 step, epoch마다 최고의 정확도를 가질때의 weight저장과 통계지표 csv파일, heatmap을 기록하고 저장하게 됩니다.&lt;/p&gt;

&lt;h2 id=&quot;2-3-학습-결과-시각화&quot;&gt;2-3. 학습 결과 시각화&lt;/h2&gt;

&lt;h3 id=&quot;csv파일-통계&quot;&gt;csv파일 통계&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Buster&lt;/strong&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%207.png&quot; alt=&quot;Untitled%207&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jo&lt;/strong&gt;&lt;/p&gt;

&lt;dl class=&quot;center&quot;&gt;
  &lt;dt&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%208.png&quot; alt=&quot;Untitled%208&quot; /&gt;&lt;/dt&gt;
  &lt;dd&gt;
    &lt;p&gt;첫 번째 시각화 방법으로 콤마(‘,’)를 통해 셀을 나누는 csv파일을 통해 카테고리 별 정확도에 대한 수치를 나타내었습니다.&lt;/p&gt;
  &lt;/dd&gt;
&lt;/dl&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;record_output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;answer_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;index_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;category_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&quot;&lt;/span&gt;
						&lt;span class=&quot;c1&quot;&gt;# category_str -&amp;gt; csv에 작성할 문자열 값
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;index_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;category_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;answer_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each_val_sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ,&quot;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 정확도를 분수형태로 넣어줌
&lt;/span&gt;								&lt;span class=&quot;c1&quot;&gt;# 해당 카테고리 중 맞은 정답 갯수 / 해당 카테고리 중 검증 데이터 총 갯수
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;data_for_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;answer_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;each_val_sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
								&lt;span class=&quot;c1&quot;&gt;# heatmap에 표현할
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;category_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;output_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ 다른 프로그래밍 언어의 파일 쓰기 형식처럼 ( 예를 들어 C언어의 fwrite같이 ) 작성할 스크립트를 담은 문자열 변수를 open으로 선언한 csv파일에 write해주는 형식으로 csv를 작성해주면 통계용 파일이 완성됩니다.&lt;/p&gt;

&lt;h3 id=&quot;heatmap-이미지-통계&quot;&gt;heatmap 이미지 통계&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%209.png&quot; alt=&quot;Untitled%209&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%2010.png&quot; alt=&quot;Untitled%2010&quot; /&gt;&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;( ※ 각각 Buster(좌)와 Jo(우)의 각 카테고리 별 평가용 데이터에 따른 정확도를 히트맵으로 시각화한 결과를 보여줍니다. )&lt;/dt&gt;
  &lt;dd&gt;
    &lt;p&gt;두 번째 방법으로 기존에 사용하던 matplotlib을 이용하여 각 카테고리 별 정확도 퍼센트를 heatmap으로 표현해 기록하였습니다.&lt;/p&gt;
  &lt;/dd&gt;
&lt;/dl&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;make_heatmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_for_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'''히트맵으로 csv파일에 기록된 정확도를 단순 확률로 간략화해서 보여줌'''&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 그래프를 불러오는 함수
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gca&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;im&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data_for_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;color_bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colorbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;im&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;color_bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_ylabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;accuracy each category&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;va&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;c1&quot;&gt;# title에 해당하는 부분 작성
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_for_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                               &lt;span class=&quot;n&quot;&gt;ha&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;va&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# append text to ax
&lt;/span&gt;								&lt;span class=&quot;c1&quot;&gt;# heatmap그래프 각 칸에 들어갈 확률 값을 채움
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;⇒ 위에 csv 파일에 write할 때와 비슷하게 plt의 내장 함수를 통해 불러온 heatmap 중 그래프 형식의 공간에 text를 채워넣는 형식으로 구동되게 설정해 놓았습니다.&lt;/p&gt;

&lt;h1 id=&quot;3-conclusion&quot;&gt;3. Conclusion&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;전체 학습과 분류기 부분만 학습 두 가지 옵션을 선택 가능하며 분류기 학습만 진행시 GPU를 사용하지 않더라도 일반적인 densenet모델을 통한 이미지 처리 학습보다 더 빠른 속도의 학습이 이뤄지는 것을 알수 있습니다.&lt;/li&gt;
  &lt;li&gt;다른 카테고리 분류 상황에서도 분류기 부분만 따로 학습해 필요할 때마다 적절한 가중치 파일 선택으로 여러 상황에 대처할수 있게 설계되었습니다. 기존에 ImageNet 으로 학습되어 general 한 특징을 추출할수 있는 원본 가중치에서 안에 dictionary 형태로 저장된 분류기 부분만 바꿔서 동작시키면 원하는 카테고리에 맞게 분류를 해줄수 있게 됩니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;: 결론적으로, 위에 장점을 기반으로 두 학습기 모두 테스트 학습에 대한 평균 정확도가 90% 중후반을 보여주면서 문제 없이 학습이 이루어 지는 것을 확인 할수 있었습니다.&lt;/p&gt;

&lt;h1 id=&quot;번외--개발-도중의-시행착오&quot;&gt;번외 : 개발 도중의 시행착오&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;소통 부재로 yaml파일 tester파일의 분리&lt;/strong&gt;&lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-23-image-classification-transfer-learning-with-custom-data/Untitled%2011.png&quot; alt=&quot;Untitled%2011&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;→ Trainer를 분리해서 작성하는건 사전에 어느정도 이야기가 되고 예측가능한 상황이었지만 Trainer에서 호출할 yaml파일의 속성 값들도 따로 작성하며 트레이닝의 테스트를 진행해 이후 통합하기 어려울 정도로 각 yaml의 속성 관계가 복잡해지게 되었습니다.&lt;/p&gt;

    &lt;p&gt;결국 yaml은 trainer코드에 대한 전면적인 수정을 해야해서 분리되는 방향으로 결정됬지만 tester같은 경우는 큰 변화가 필요없어서 처음 주어진 코드를 기반으로 서로 추가된 기능들을 충돌없이 따로 반영하는 것을 통해 하나로 통합되었습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;약속되지 않은 모델 변경 및 파일 추가&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;→ 위에 소통 문제와 연계해 처음 densenet 원본 모델 클래스가 있는 modeling_densenet.py파일을 수정할려고 했었던 것이나 트레이너를 위한 개별 파일을 추가 혹은 삭제(특히 시스템 파일) 하는 것 등 사전에 협의되지 않은 변경 사항으로 다른 트레이너 코드에 영향을 줄수 있는 부분을 다시 정리하는 것도 하나의 홍역이었던거 같습니다.&lt;/p&gt;

    &lt;p&gt;github를 통해 conflict나는 부분을 대조해보기도 하고 서로의 변경사항을 각자 코드에 추가해 맞춰줌으로써 해결되었지만 다른 협업자의 코드에 영향을 줄수있는 부분의 수정 등을 신중히 접근해야 한다는 것을 깨닫게 해주는 작업이기도 하였습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;예외 처리의 중요성&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;→ 워크스테이션에서의 트레이닝 도중 출력된 divide by zero에러와 프로세스가 kill되는 문제에서 후자의 경우는 코드를 잘못 타이핑해 CPU와 GPU에 데이터가 따로 노는 것이 원인이었지만 나머지 divide by zero같은 경우 예외 처리의 문제로 판명되었습니다.&lt;/p&gt;

    &lt;p&gt;시스템 파일 같은 이미지 외에 필요 파일들의 존재 등을 고려하지 않은 문제 때문에 코드 1줄이면 해결될 문제가 이틀 가까이를 소모하게 만들었습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;다른 분야의 협업자 배려 + default값 설정&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;→ 기존 yaml을 서로가 다른 트레이너를 자기 환경에서 테스트할 때나 일반적인 자기 환경 내의 테스트 상황에서도 편하게 테스트하기 위한 용도로 값이 설정되어 있어서 워크스테이션 동작 시 호환이 안되는 문제가 발생하기도 하였습니다.&lt;/p&gt;

    &lt;p&gt;만약 AI쪽은 잘 모르는 사람과 협업을 할 경우 default값을 신중히 세팅하거나 협업자의 테스트 환경에 대한 소통을 진행하여 해당 문제의 유발을 최소화하도록 하는 것도 중요한 사안이라는 점을 알게되었습니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;reference&quot;&gt;Reference&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pytorch/vision/blob/master/torchvision/models/densenet.py&quot;&gt;https://github.com/pytorch/vision/blob/master/torchvision/models/densenet.py&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tutorials.pytorch.kr/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py&quot;&gt;https://tutorials.pytorch.kr/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 23 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/02/23/image-classification-transfer-learning-with-custom-data.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/02/23/image-classification-transfer-learning-with-custom-data.html</guid>
        <tags>
          
          <tag>Transfer-Learning</tag>
          
          <tag>Image-Classification</tag>
          
          <tag>DenseNet</tag>
          
          <tag>Pytorch</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>솔루션 납품 자동화하기 - Docker편</title>
        <authors>
          
          
          <author>
            <name>김기강</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/alton.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-02-02-automating-solution-delivery-docker/0.png</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-02-02-automating-solution-delivery-docker/0.png&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;aivory 검색엔진은 docker를 통해 간단하게 서버에 올려 사용이 가능합니다.&lt;/p&gt;

&lt;p&gt;이를 위해 당연히 검색엔진이 납품될 서버에 도커를 설치해야합니다.&lt;/p&gt;

&lt;h1 id=&quot;기존-설치-방법---매뉴얼-따라가기&quot;&gt;기존 설치 방법 - 매뉴얼 따라가기&lt;/h1&gt;

&lt;p&gt;도커를 설치하는 것은 어렵지 않습니다.&lt;/p&gt;

&lt;p&gt;만능 구글에 ‘docker install’이라고만 쳐도 공식 문서가 나오며
간단한 영어 실력을 발휘해(혹은 마우스 우클릭과 번역 😉), 몇 줄의 코드만 복사 붙여넣기를 하면 도커 설치는 끝납니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/get-docker/&quot;&gt;Get Docker&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;폐쇄망의-경우&quot;&gt;폐쇄망의 경우&lt;/h1&gt;

&lt;p&gt;솔루션 납품을 위해 서버에 도커를 깔려니, 폐쇄망이라 네트워크를 사용하지 못한다는 충격적인 소식을 전달 받았습니다.&lt;/p&gt;

&lt;p&gt;다행스럽게도 폐쇄망에서 도커를 사용할 수 있는 방법은 있습니다.
폐쇄망을 위한 방식은 도커를 실행할 수 있는 파일들을 미리 설치해서 옮기면 됩니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Docker&lt;/p&gt;

    &lt;p&gt;&lt;a href=&quot;https://download.docker.com/linux/static/stable/x86_64/&quot;&gt;Index of linux/static/stable/x86_64/&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Docker Compose&lt;/p&gt;

    &lt;p&gt;&lt;a href=&quot;https://github.com/docker/compose/releases&quot;&gt;Releases · docker/compose&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;귀찮고-복잡한-설치-방법--시간-낭비&quot;&gt;귀찮고 복잡한 설치 방법 → 시간 낭비&lt;/h1&gt;

&lt;p&gt;폐쇄망이 아니더라도 코드 한줄한줄을 복붙해서 설치하는 방법도 결국 납품건이 많아질수록 시간 낭비의 주범이 될 것입니다.&lt;/p&gt;

&lt;p&gt;또한, 이번 방법을 문서로 정리해 남겨둬야하는 귀찮은 일을 해야하고, 추후 폐쇄망 납품을 위해 해당 문서를 찾고 따라하며 시간을 낭비하게 될 것입니다.&lt;/p&gt;

&lt;p&gt;이에 자동화를 위해 스크립트를 작성하는 것을 결심하게 되었습니다.&lt;/p&gt;

&lt;h1 id=&quot;개선---설치-스크립트-제작&quot;&gt;개선 - 설치 스크립트 제작&lt;/h1&gt;

&lt;p&gt;귀찮은 코드 복붙을 한번에 실행 시킬 방법은 매우 간단합니다.
쉘 스크립트로 설치 명령 코드들을 모아둔 뒤, 해당 스크립트를 실행하면 됩니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;일반망&lt;/p&gt;

    &lt;p&gt;우선 솔루션이 납품될 서버의 os는 centos와 ubuntu로 두가지 경우가 있습니다.&lt;/p&gt;

    &lt;p&gt;도커를 설치하는 코드가 위 두가지 os에서 다르기 때문에 os를 구별해서 명령 코드를 실행시켜야합니다.&lt;/p&gt;

    &lt;p&gt;os를 확인하는 것은 여러 방법이 있지만 두가지 os 모두에서 사용할 수 있어야 합니다.
따라서 os를 확인하기 위한 명령어는 ‘cat /proc/version’을 사용했습니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;OS_CHECK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /proc/version&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;이때, os가 정확하게 ‘CentOS 7’ 혹은 ‘Ubuntu’ 문자열로 나오는 것이 아니기 때문에&lt;/p&gt;

    &lt;p&gt;결과 문자열에서 =~ 를 통해 ‘centos’나 ‘ubuntu’가 포함되는지 검사해서 os를 구분했습니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$OS_CHECK&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;s2&quot;&gt;&quot;ubuntu&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$OS_CHECK&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;s2&quot;&gt;&quot;Ubuntu&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;apt-transport-https ca-certificates curl gnupg-agent software-properties-common
        curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key add -
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key fingerprint 0EBFCD88 &lt;span class=&quot;c&quot;&gt;# 안해도 됨&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class=&quot;s2&quot;&gt;&quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;lsb_release &lt;span class=&quot;nt&quot;&gt;-cs&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; stable&quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;usermod &lt;span class=&quot;nt&quot;&gt;-aG&lt;/span&gt; docker &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service docker restart
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Docker for Ubuntu download complete!&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$OS_CHECK&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;s2&quot;&gt;&quot;centos&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yum &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; yum-utils
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yum-config-manager &lt;span class=&quot;nt&quot;&gt;--add-repo&lt;/span&gt; https://download.docker.com/linux/centos/docker-ce.repo
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yum &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl start docker
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;usermod &lt;span class=&quot;nt&quot;&gt;-aG&lt;/span&gt; docker &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service docker restart
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Docker for CentOS download complete!&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;check OS version is ubuntu or centos&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;도커 컴포즈는 파일이 경로에 존재만 하면 되기에 비교적 간단합니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Download docker-compose...&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://github.com/docker/compose/releases/download/1.27.4/docker-compose-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; /usr/local/bin/docker-compose
&lt;span class=&quot;nb&quot;&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/docker-compose
&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;docker-compose download complete!&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;폐쇄망&lt;/p&gt;

    &lt;p&gt;폐쇄망의 경우엔 완전 ‘무’의 상태에서 도커와 컴포즈를 만들어 내는 것은 불가능하기 때문에
솔루션 패키지 내부에 도커와 도커 컴포즈 파일을 미리 준비했습니다. (‘폐쇄망의 경우’의 링크 참고)
도커를 설치하는 명령어가 os마다 다를 뿐이지 설치하게 되는 파일은 동일합니다. 따라서 폐쇄망에선 os 체크가 필요 없습니다.&lt;/p&gt;

    &lt;p&gt;솔루션 패키지의 상위 디렉토리에서 도커를 설치해야하기 때문에 HOME을 설정했습니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;도커 파일이 이미 존재하기에 파일을 옮기고 도커를 실행하는 명령어를 이용했습니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Setting docker without internet...&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;docker-18.09.0.tgz &lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/../
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../
&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xzf&lt;/span&gt; docker-18.09.0.tgz
&lt;span class=&quot;nb&quot;&gt;sudo cp &lt;/span&gt;docker/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; /usr/bin/
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;dockerd &amp;amp;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Docker setting complete!&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;폐쇄망에서 도커를 실행하기 위해서는 기존에 사용하던 service나 systemctl 명령어 대신 ‘dockerd &amp;amp;’ 명령어를 사용해 도커를 실행시켜야합니다.&lt;/p&gt;

    &lt;p&gt;이어서 도커 컴포즈 또한 파일이 있기 때문에 일반망 명령어에서 curl을 cp로 바꿔줍니다.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Setting docker-compose...&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
&lt;span class=&quot;nb&quot;&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/docker-compose
&lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;docker-compose download complete!&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;이렇게 일반망과 폐쇄망에서의 도커와 도커 컴포즈를 자동으로 설치, 실행하는 스크립트를 완성하게 되었습니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;마치며&quot;&gt;마치며&lt;/h1&gt;

&lt;p&gt;납품에 소요되는 시간을 줄이는 것은 매우 중요합니다.&lt;/p&gt;

&lt;p&gt;그를 위한 나의 첫 걸음은 성공적으로 마쳤습니다.&lt;/p&gt;

&lt;p&gt;다음 걸음은 색인에 필요한 쿼리를 전달 받으면 따로 다듬어줘야하는 추가 작업이 필요한 경우가 있습니다. 이를 방지하기 위한 확실한 가이드라인을 제작할 예정입니다.&lt;/p&gt;

&lt;p&gt;그럼 다음 시간에 또 봅시다 ✋&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Feb 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/02/02/automating-solution-delivery-docker.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/02/02/automating-solution-delivery-docker.html</guid>
        <tags>
          
          <tag>Docker</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>VODA 디자인 시스템 1</title>
        <authors>
          
          
          <author>
            <name>유보람</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/allison.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-04-01-voda-design-system-1/thumbnail.svg</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/thumbnail.svg&quot; alt=&quot;thumbnail&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;0-들어가기-전에&quot;&gt;0. 들어가기 전에&lt;/h2&gt;

&lt;p&gt;안녕하세요, 너드팩토리 프로덕트 디자이너 Allison 입니다.&lt;/p&gt;

&lt;p&gt;너드팩토리에서는 현재 신규 서비스 VODA를 준비하고 있습니다.&lt;/p&gt;

&lt;p&gt;이번 글은 VODA 서비스 구축 프로젝트를 시작하기 전 진행한 VODA 디자인 시스템 제작기를 들려 드리고자 합니다. 디자인 시스템을 설명하는 글은 다른 곳에서도 쉽게 찾을 수 있으니 여기서는 어떤 기준으로 디자인 시스템을 구축하는 지에 대해 이야기를 할게요.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;1-계기&quot;&gt;1. 계기&lt;/h2&gt;

&lt;p&gt;VODA 프로젝트는 프로덕트 오너, 프로덕트 디자이너, 프론트엔드 개발자, 백엔드 개발자 그리고 AI 개발자가 함께 만들고 있습니다. 최종 목표는 모두 같지만 VODA 브랜드에 대한 생각은 완전히 같을 수 없어요. 그래서 일관성 있는 프로젝트를 구축하고 사용자에게 일관된 서비스를 제공하기 위해 디자인 시스템을 구축하기로 했습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2-디자인시스템을-왜-사용할까&quot;&gt;2. 디자인시스템을 왜 사용할까?&lt;/h2&gt;

&lt;p&gt;매번 다른 폰트, 간격, 색상을 사용한다면 디자이너의 퇴근은 자연스레 늦어집니다. 따라서 하나의 서비스 전반에 공통으로 쓰이는 타이포그래피, 그리드, 간격, 색상 그리고 UI 구성요소를 체계적으로 정리하여 디자인 시간을 단축 시키고 불필요한 소통과 수정을 최소화합니다. 프로젝트 도중 디자인팀 인원이 늘어나거나 담당 프로덕트 디자이너가 바뀌어도 체계화된 디자인 시스템으로 사용자에게 일관성 있는 디자인을 제공할 수 있습니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-디자인-시스템에는-어떤-요소가-들어가야할까&quot;&gt;3. 디자인 시스템에는 어떤 요소가 들어가야할까?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Typography&lt;/li&gt;
  &lt;li&gt;Grids and Space&lt;/li&gt;
  &lt;li&gt;Colors&lt;/li&gt;
  &lt;li&gt;UI Components: Buttons, Forms, icons, Modals, Picker 등&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;4-어떤-기준으로-만들까&quot;&gt;4. 어떤 기준으로 만들까?&lt;/h2&gt;

&lt;h3 id=&quot;1-typography&quot;&gt;1) Typography&lt;/h3&gt;

&lt;p&gt;타이포그래피에서 고려해야 할 사항은 다음과 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;pt는 디스플레이 장치에서 ppi에 따라 각각 크기가 달라지니 웹 개발에서 단위는 px를 사용합니다.&lt;/li&gt;
  &lt;li&gt;웹 페이지 트래픽과 로딩 시간을 고려해 될 수 있으면 웹 폰트 사용을 권장합니다.&lt;/li&gt;
  &lt;li&gt;일반 웹 사이트의 본문 텍스트 크기는 14~16px이므로 사용자 층과 가독성을 고려하여 본문 텍스트 크기를 결정합니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;VODA는 웹 폰트인 Noto Sans Kr(국문)와 Robot(영문)을 사용하고 본문 텍스트 크기는 14px로 결정했습니다. 이 기준을 바탕으로 하단 이미지와 같이 일정한 규칙을 가지고 정보의 위계에 따라 Header는 4가지, text는 5가지로 구성합니다.&lt;/p&gt;

&lt;p&gt;여기까지 왔다면 디자인 시스템을 거의 다 구축한 거나 다름없습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/typo.svg&quot; alt=&quot;typo&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/header.png&quot; alt=&quot;header&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/text.svg&quot; alt=&quot;text&quot; /&gt;&lt;/p&gt;

&lt;p&gt;행간값은 텍스트의 양과 폰트 크기에 따라 달라지지만, 일반적으로 행간값은 폰트 크기 X 1.7~1.75 사이 값으로 설정합니다. 위와 같이 사용할 타이포그래피를 정리한 후에 반드시 Asset에 등록하여 사용하는 것이 디자이너 정신 건강에 이롭습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-grids-and-space&quot;&gt;2) Grids and Space&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://gs.statcounter.com/&quot;&gt;StatCounter Global Stats - Browser, OS, Search Engine including Mobile Usage Share&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;위의 사이트에서 데이터를 보며 최소 화면 크기를 결정합니다. VODA는 노트북에서도 불편함 없이 서비스를 이용할 수 있도록 1280px까지 지원하기로 했습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/breakpoint.svg&quot; alt=&quot;breakpoint&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/gridsystem.svg&quot; alt=&quot;gridsystem&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그리드를 효율적으로 활용하기 좋은 12 Grid System(Max width:1600px, Gutter:24px, Margin:62px)을 사용하기로 했어요. 하단 사이트에서 그리드를 계산하면 편리합니다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://gridcalculator.dk/#/1920/12/16/62&quot;&gt;Grid Calculator by Nicolaj Kirkgaard Nielsen&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;그리드 시스템은 UI를 배치할 때 기준을 제시할 뿐이니 반드시 그리드에 맞출 필요 없고 상황에 따라 유연하게 사용하면 됩니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-04-01-voda-design-system-1/space.svg&quot; alt=&quot;space&quot; /&gt;&lt;/p&gt;

&lt;p&gt;간격을 1px 단위씩 움직이면 디자이너는 또 퇴근할 수 없습니다. 그래서 간격에도 일정한 규칙을 정합니다. VODA는 4의 배수를 기반으로 총 6가지 간격 크기를 두고 이를 조합하여 사용했어요.&lt;/p&gt;

&lt;p&gt;🙋🏻‍♀️ Colors, UI Components 부분은 VODA 디자인 시스템 2에 이어집니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;reference&quot;&gt;Reference&lt;/h3&gt;

&lt;p&gt;스포카 디자인 가이드라인:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://bi.spoqa.com/&quot;&gt;Spoqa Design Guidelines&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;리메인 스타일 가이드:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;http://styleguide.co.kr/index.php&quot;&gt;리메인 스타일가이드&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1편 끝 🔚&lt;/p&gt;
</description>
        <pubDate>Mon, 11 Jan 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/01/11/voda-design-system-1.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/01/11/voda-design-system-1.html</guid>
        <tags>
          
          <tag>VODA</tag>
          
          <tag>Design System</tag>
          
          <tag>Adobe Xd</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>react + typescript에 redux-saga 셋팅하기</title>
        <authors>
          
          
          <author>
            <name>고지훈</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ict_june.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-01-02-setting-redux-saga/3.png</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-01-02-setting-redux-saga/3.png&quot; alt=&quot;img3&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Typescript&lt;/code&gt;를 적용하고 null able로 인한 고통을 쉽게 줄일 수 있었습니다. 그리고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Saga&lt;/code&gt;를 적용하여 중복 액션에 대한 비동기 처리를 쉽게 해결하였습니다.&lt;/p&gt;

&lt;p&gt;위 두 가지를 적용하고 개발의 질도 올라갔고 (특히 typescript를 적용하고) 원래 javascript는 이랬어야 하지~ 라고 느낍니다.&lt;/p&gt;

&lt;p&gt;이번 포스트에서는 어떤 이유로 위 두 가지를 적용했는지를 말하기보다는 실제 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;React+Typescript&lt;/code&gt;에 어떻게 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redux&lt;/code&gt;와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redux-saga&lt;/code&gt;를 적용하고 사용할 수 있는지를 말하려고 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;이 포스트는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redux&lt;/code&gt;를 사용해 보셨고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Saga&lt;/code&gt;를 처음 접해보시는 분들께 도움이 됩니다.&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;install&quot;&gt;Install&lt;/h1&gt;

&lt;p&gt;이 포스트에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CRA&lt;/code&gt;에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Typescript&lt;/code&gt; 설치를 진행하겠습니다.&lt;/p&gt;

&lt;p&gt;node version : 12.13.1&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CRA와 typescript 설치&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yarn create react-app test-app &lt;span class=&quot;nt&quot;&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;redux와 redux-saga 설치&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yarn add redux react-redux @types/react-redux redux-saga
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;typesafe-actions 설치 (v5)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;redux-actions와 같은 Typescript 용 라이브러리입니다.
액션 생성 함수와 Reducer를 더 편하게 작성하고 사용할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;yarn add typesafe-actions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;h2 id=&quot;1-리덕스-모듈-구조-잡기&quot;&gt;1. 리덕스 모듈 구조 잡기&lt;/h2&gt;

&lt;p&gt;개발 방법론을 설명하려고 하지 않았지만, 그보단 덜 무거운 주제인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redux&lt;/code&gt; 디렉터리 구조를 같이 소개하려고 합니다.&lt;/p&gt;

&lt;p&gt;타입스크립트를 사용하기 전에는 완전한 덕스패턴을 이용하고 있었습니다. 하나의 파일에 액션 생성 함수, 리듀서 등을 같이 정의했으나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Typescript&lt;/code&gt;를 사용함으로써 생기는 state의 타입 선언 등 코드가 상당히 길어지는 불편함이 있었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-01-02-setting-redux-saga/0.png&quot; alt=&quot;img0&quot; /&gt;&lt;br /&gt;
&lt;em&gt;300줄이나 되는 하나의 모듈 코드&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;위 모듈은 크게 보면 액션생성함수가 5개밖에 되지 않고 타입 선언이 빠져있음에도 300줄이나 되는 모습을 보입니다. 새로운 함수가 추가될 수록 코드의 길이는 기하급수적으로 길어지고 늘어나는 스크롤 속에서 원하는 코드를 찾는 작업은 점점 힘들어질 수 밖에 없습니다.&lt;/p&gt;

&lt;p&gt;위의 구조를 해결하기 위해 디렉터리 구조 변경과 vs code의 장점을 이용하여 해결할 수 있습니다.
아래 구조는 벨로퍼트님의 강의를 참고하였습니다. 참고 : &lt;a href=&quot;https://react.vlpt.us/&quot;&gt;https://react.vlpt.us/&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── actions.ts
├── index.ts
├── reducer.ts
├── saga.ts
└── types.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;하나의 모듈 파일을 위와 같이 분리하는 것으로 간단하게 해결할 수 있습니다. 파일명만 봐도 모듈에서 어떤 것을 정의하고 있는지 감이 오실 겁니다. 하나씩 어떻게 작성하고 있는지 설명하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;2-리덕스-모듈-작성하기&quot;&gt;2. 리덕스 모듈 작성하기&lt;/h2&gt;

&lt;p&gt;리덕스 모듈을 작성하기에 앞서 VS Code를 사용해서 작성하면 더 좋습니다. 번역 시간에 대한 에러(컴파일 에러)를 어느 정도 미리 잡아줍니다. 그리고 CommonJS나 AMD로 정의된 각 모듈을 파일 여러 곳에서 사용하기 때문에 여러 파일을 탐색하면서 수정하게 되는데 이때 맥기준으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd+import한 모듈 명을 좌클릭&lt;/code&gt;하면 바로 모듈이 정의된 파일로 이동하게 됩니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-01-02-setting-redux-saga/1.png&quot; alt=&quot;img1&quot; /&gt;&lt;br /&gt;
&lt;em&gt;정의된 모듈을 사용하는 경우 정의된 모듈 파일로 바로 이동할 수 있다.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;무엇보다 Typescript를 사용하는 React에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;props&lt;/code&gt;로 전달받는 데이터에 대한 검사도 컴파일 이전에 잡을 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-0-리덕스-스토어-작성&quot;&gt;2. 0. 리덕스 스토어 작성&lt;/h3&gt;

&lt;p&gt;모듈들을 적용할 루트 리듀서를 작성해야 합니다. test 모듈은 아래 예제에서 작성하게 될 모듈입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modules / index.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;combineReducers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;combineReducers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//컴포넌트에서 사용하게될 스토어에 저장된 데이터의 타입입니다.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RootState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이후에 미들웨어를 편하게 등록시키기 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configureStore.ts&lt;/code&gt;를 미리 만들어 둡니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modules / configureStore.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createStore&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;configureStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 프로젝트에 적용하면 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReactDOM&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react-dom&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Provider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react-redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;configureStore&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./modules/configureStore&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./containers/App&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;configureStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;ReactDOM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Provider&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-1-actionsts&quot;&gt;2. 1. actions.ts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / test / actions.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;typesafe-actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//액션 타입&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test/SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test/SET_OBJECT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//액션 생성 함수&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setStringArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;액션 타입을 선언하고 액션 생성함수는 ‘typesafe-actions’의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createAction&lt;/code&gt;모듈을 사용합니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createAction&lt;/code&gt;은 무제한으로 인수를 받을 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;2-2-typests&quot;&gt;2. 2. types.ts&lt;/h3&gt;

&lt;p&gt;store에 저장될 데이터의 타입과 액션 생성함수에 대한 타입을 정의합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modules / test / types.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;typesafe-actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;testStringArrData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;testObjectData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testAction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ActionType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActionType&lt;/code&gt; 모듈은 선언된 액션 생성 함수의 타입을 정의해줍니다. 새로운 액션 생성함수를 만들어도 새롭게 타입을 정의하지 않아도 됩니다.&lt;/p&gt;

&lt;h3 id=&quot;2-3-reducerts&quot;&gt;2. 3. reducer.ts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / test / reducer.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createReducer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;typesafe-actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testState&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./types&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;initialState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;uxAnalyticsState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;testStringArrData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;testObjectData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//createReducer는 reducer를 쉽게 작성할 수 있도록 하는 모듈이며&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//타입 오류를 방지 할 수 있습니다.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reducer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createReducer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testAction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;testStringArrData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;testObjectData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;‘typesafe-actions’ 혹은 자바스크립트에서 ‘redux-actions’를 사용할 때는 reducer를 객체 형태로 작성할 수 있어 switch 문으로 작성하는 것보다 가독성이 좋다고 생각하고 있습니다. 그리고 VS code에서는 액션 생성 함수의 타입과 store의 타입에서 정의된 형식의 데이터만 코드로 작성할 수 있기 때문에 자바스크립트를 쓸 때 보다 더 null-able과 정의되지 않는 데이터 오류에 대한 고민을 많이 줄 일 수 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-01-02-setting-redux-saga/2.png&quot; alt=&quot;img2&quot; /&gt;&lt;br /&gt;
&lt;em&gt;Ctrl + Space 단축키로 action 인자에 정의된 객체를 탐색할 수 있다.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-4-indexts&quot;&gt;2. 4. index.ts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / test / index.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./reducer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./types&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;어렵지 않습니다. 리덕스 스토어에 등록하기 위해 지금까지 작성했던 export 가능한 모듈들을 전부 불러와 export 합니다.&lt;/p&gt;

&lt;h2 id=&quot;3-redux-saga-적용하기&quot;&gt;3. Redux-Saga 적용하기&lt;/h2&gt;

&lt;p&gt;가장 중요한 비동기 로직을 적용하는 방법입니다. 보통 프로젝트에서 비동기 로직을 구현할 때 대부분 API 처리에 관해 로직을 구현하게 됩니다. 그러한 관점에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Saga&lt;/code&gt;를 어떻게 작성하는지 알아보겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;3-0-apits-typets&quot;&gt;3. 0. api.ts, type.ts&lt;/h3&gt;

&lt;p&gt;api의 파라미터 타입과 리스폰스 타입을 정의합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;api / test / type.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// type.ts&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 세션 유효성 체크&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionPramType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;api에 관한 정의를 작성합니다. axios 모듈로 작성하였습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;api / test / api.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//api.ts&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionPramType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../config-api.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;apiInfo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;apiGetCheckSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionPramType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;GetCheckSessionResponseType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;(
    `$&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apiInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;api_url&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;/check_session/`,
    &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;withCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
  );

  return response.data;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-1-actionts&quot;&gt;3. 1. action.ts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / test / actions.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAsyncAction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;typesafe-actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AxiosError&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;GetCheckSessionPramType&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../../api/test/type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//액션 타입&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/SET_OBJECT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//액션 생성 함수&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setStringArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_STRING_ARR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SET_OBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//비동기 액션 타입&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/GET_CHECK_SESSION&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION_SUCCESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/GET_CHECK_SESSION_SUCCESS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION_ERROR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test/GET_CHECK_SESSION_ERROR&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//비동기 액션 생성 함수&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createAsyncAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION_ERROR&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;GetCheckSessionPramType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AxiosError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;‘typesafe-actions’의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;createAsyncAction&lt;/code&gt; 모듈은 비동기 흐름(요청 / 성공 / 실패) 처리를 단순화하기 위해 세 가지로 구분된 액션 생성 함수를 포함하는 개체를 생성합니다. 각 액션 생성 함수의 리턴 타입을 정의합니다.&lt;/p&gt;

&lt;h3 id=&quot;3-2-sagats&quot;&gt;3. 2. saga.ts&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;action.ts&lt;/code&gt;와 같은 디렉터리 위치에서 파일을 작성합니다. 비동기 로직을 작성하는 부분입니다. 위에 작성한 액션 생성 함수가 시작되면 아래의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Saga&lt;/code&gt; 로직이 실행되는 구조입니다.&lt;/p&gt;

&lt;p&gt;아래 코드를 작성하기 앞서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Redux-Saga&lt;/code&gt;에서 말하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Saga&lt;/code&gt;는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;제너레이터 함수&lt;/code&gt; 이기 때문에 자바스크립트 제너레이터에 대해 이해하고 있어야 로직이 어떻게 동작하는지 이해가 가능합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modules / test / saga.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;takeLatest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux-saga/effects&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;apiGetCheckSession&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../api/test/api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../api/test/type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//액션을 모니터링 하고 있고 특정 액션 발생 시 요청 액션 생성 함수에 대해 파라미터로 받아 올 수 있습니다.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//해당 액션의 payload 값을 인자로 넣어줄 수 있습니다.&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetCheckSessionResponseType&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;apiGetCheckSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//actions.ts에서 선언한 비동기 처리를 위한 액션 생성함수를 각 특성에 맞게 디스패칭 합니다.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//당연히 디스패치를 할 때 넣어줄 인자는 actions.ts에서 정의한 성공, 실패에 대한 타입이 일치해야 합니다.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;failure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;takeLatest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;GET_CHECK_SESSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testSaga&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;제너레이터 함수에서 비동기로 특정 함수를 실행해야 할 때 제너레이터를 사용하지 않고 쉽게 사용할 수 있는 것이 saga의 이펙트입니다.&lt;/p&gt;

&lt;p&gt;각 이펙트의 특성에 따라 특정 조건을 만족하게 되면 제너레이터의 메서드인 next()를 실행합니다.
모듈별 특정 조건은 다음과 같습니다. (코드에 포함된 이펙트 모듈도 있고 없는 모듈도 있으니 잘 참고 하시길 바랍니다.)&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; 모듈은 동기 실행을 하며 Promise를 반환하는 함수를 호출합니다. 첫 번째 파라미터는 Promise를 반환하는 함수, 두 번째 파라미터는 해당 함수에 넣을 인수입니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fork&lt;/code&gt; 모듈은 비동기 실행을 하고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt;과 같은 기능을 합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;put&lt;/code&gt;은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dispatch&lt;/code&gt;와 동일한 기능을 합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;takeEvery&lt;/code&gt;은 호출되는 모든 액션에 대해 수신합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;takeLatest&lt;/code&gt;은 A라는 액션이 종료되지 않은 상태일 때 같은 액션이 요청된다면 현재 실행 중인 액션을 취소합니다. 그리고 새롭게 들어온 A 액션에 대해 처리합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;takeLeading&lt;/code&gt;은 A라는 액션이 완료될 때까지 같은 액션 호출을 차단합니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;3-3-indexts&quot;&gt;3. 3. index.ts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / test / index.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./reducer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./types&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//test 모듈에 대한 saga역시 export합니다.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./saga&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-4-미들웨어-등록하기&quot;&gt;3. 4. 미들웨어 등록하기&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;modules / index.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//index.ts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;combineReducers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux-saga/effects&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testSaga&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;combineReducers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RootState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ReturnType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;all&lt;/code&gt;은 미들웨어가 여러 이펙트를 병렬로 실행하고 모두 완료될 때까지 기다리도록 지시하는 이펙트입니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;modules / configureStore.ts&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;applyMiddleware&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createSagaMiddleware&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux-saga&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserHistory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;composeWithDevTools&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;redux-devtools-extension&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rootSaga&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;configureStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;customHistory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BrowserHistory&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sagaMiddleware&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createSagaMiddleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;customHistory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;rootReducer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;composeWithDevTools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;applyMiddleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sagaMiddleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;//이제 선언한 모든 Saga를 미들웨어에 등록하고 미들웨어는 계속해서 액션을 감지한다.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sagaMiddleware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rootSaga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;history 객체와 redux 개발자도구도 같이 적용해 줍니다. (옵션이에요)&lt;/p&gt;

&lt;h2 id=&quot;4-컨테이너에서-사용하기&quot;&gt;4. 컨테이너에서 사용하기&lt;/h2&gt;

&lt;p&gt;이제 거의 다 왔습니다! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hooks&lt;/code&gt;를 쓰면 간단하게 redux를 사용할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-tsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useEffect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useSelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useDispatch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;react-redux&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RootState&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../modules&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;../../modules/test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestComponent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//store에 저장된 state는 useSelector를 이용하세요&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testObjectData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useSelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RootState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;//액션을 호출할 때는 useDispatch를 이용하세요&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dispatch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;useDispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onGetCheckSession&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getCheckSessionAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;...&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TestComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;result&quot;&gt;Result&lt;/h1&gt;

&lt;p&gt;프로젝트가 커질수록 비즈니스 로직이 점점 복잡해지고 그에 따라 개발자가 구현해야 하는 로직 또한 난도가 높아지고 있습니다. 특정 상황에서 특정 API를 취소시켜야 하는 로직을 구현해야 했고 그런 복잡한 로직들을 앞으로도 다양하게 구현해야 했기 때문에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;saga&lt;/code&gt;뿐만 아니라 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typescript&lt;/code&gt; 역시 같이 적용하였습니다.&lt;/p&gt;

&lt;p&gt;redux-saga가 싱글톤 패턴의 state 관리를 위한 최선의 비동기 처리 미들웨어는 아닙니다. redux-observable 혹은 redux를 버리고 Mobx와 Observable로 가는 방법도 있습니다.&lt;/p&gt;

&lt;p&gt;위의 기술들 혹은 최신의 기술이 최고의 기술이라고 생각하지는 않습니다. 본인의 개발 스타일과 프로젝트의 비즈니스 로직에 맞는 최적의 기술을 찾아보시길 바랍니다.&lt;/p&gt;
</description>
        <pubDate>Sat, 02 Jan 2021 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2021/01/02/setting-redux-saga.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2021/01/02/setting-redux-saga.html</guid>
        <tags>
          
          <tag>React</tag>
          
          <tag>Typescript</tag>
          
          <tag>Redux</tag>
          
          <tag>Redux-Saga</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>(1) 평균을 비교하는 A/B 테스트</title>
        <authors>
          
          
          <author>
            <name>최동희</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/cdh-1.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2020-12-24-(1)-A-B-test-comparing-averages/0.png</thumbnail>
        <description>&lt;h1 id=&quot;방학숙제와-ab-테스트&quot;&gt;방학숙제와 A/B 테스트&lt;/h1&gt;

&lt;p&gt;환경오염 관련 이슈가 핫 했던 90년대 말, 초등학교 방학숙제로&lt;/p&gt;

&lt;p&gt;세탁세제가 식물의 성장에 미치는 영향에 대해 실험을 했던 기억이 있습니다.&lt;/p&gt;

&lt;p&gt;아마도 세탁세제가 풀린 물에서 자라는 식물과, 생수에서 자라는 식물의 평균 길이를 비교하려 했던 것 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;아마 이 방학숙제가 필자의 첫 A/B 테스트였을 것 입니다.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;세탁세제가 식물의 성장에 영향을 미칠 것이다&lt;/strong&gt; 라는 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;가설&lt;/code&gt;&lt;/strong&gt;이 있었고&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;일반 생수에서 자라는 식물&lt;/strong&gt;(&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A안&lt;/code&gt;&lt;/strong&gt;)과 &lt;strong&gt;세탁세제가 풀린 물에서 자라는 식물&lt;/strong&gt;(&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B안&lt;/code&gt;&lt;/strong&gt;)을&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;해가 잘 드는 베란다&lt;/strong&gt;에서 자라게 하였으니 (&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;실험하고자 하는 변수 이외의 변수는 동일한 조건으로 통제&lt;/code&gt;&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;훌륭하게 A/B 테스트를 수행했다고 생각됩니다&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;그래서 실험의 결과도 훌륭했나요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;탐구 일지에 적혀있는 결과는 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'눈에 띄는 차이는 없었다'&lt;/code&gt;&lt;/strong&gt; 였습니다.&lt;/p&gt;

&lt;p&gt;하지만 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;정량적인 통계분석&lt;/code&gt;&lt;/strong&gt;을 진행했다면 결과가 달라졌을지도 모르겠습니다.&lt;/p&gt;

&lt;!-- {:.center}
![img0](&lt;/assets/images/posts/2020-12-24-(1)-A-B-test-comparing-averages/0.png&gt;) --&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;ab-테스트와-관련된-간단한-통계지식&quot;&gt;A/B 테스트와 관련된 간단한 통계지식&lt;/h1&gt;

&lt;p&gt;최근 A/B 테스트를 서비스에 적용해 성공 또는 실패한 스토리들이 쏟아져 나오는것을 보며 최근 A/B 테스트가 핫한 이슈임을 다시금 깨닫게 되었습니다. 대부분의 기업에서는 서비스의 빠른 성장을 도와주는 마법같은 툴이라는 기대를 가지고 저마다 서비스에 A/B 테스트를 도입하고 싶어합니다. 하지만 대부분의 실무자들은 막연한 어려움을 가지고 있는것이 현실입니다.&lt;/p&gt;

&lt;p&gt;여전히 많은 사람들이 A/B 테스트는 통계 분석에 기반한 기능이라는 사실을 모르고 있습니다. 지금 이 순간에도 단순히 서로 다른 색깔의 컴포넌트를 배치하거나 위치를 변경하여 A/B 테스트를 진행하고, 더 나은 전환률을 보이는 웹페이지를 선택하고 있을수도 있습니다.&lt;/p&gt;

&lt;p&gt;물론 어려운 통계까지는 모르더라도 실무에 문제 될 것은 없다고 개인적으로 생각합니다.&lt;/p&gt;

&lt;p&gt;그러나 &lt;strong&gt;&lt;u&gt;정확한 A/B 테스트 설계와 결과 해석을 위해&lt;/u&gt;&lt;/strong&gt; 활용되는 &lt;strong&gt;&lt;u&gt;통계 지식&lt;/u&gt;&lt;/strong&gt;을 한번쯤은 짚고 넘어갈 필요가 있습니다.&lt;/p&gt;

&lt;p&gt;그래서 너드팩토리 블로그에서는 이러한 어려움을 떨쳐내는데 조금이나마 도움을 드리고자 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A/B 테스트와 통계 시리즈&lt;/code&gt;&lt;/strong&gt;를 통해 A/B 테스트와 관련된 통계지식들을 정리하며 함께 공부해보고자 합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A/B 테스트와 통계 시리즈&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(1) 평균을 비교하는 A/B 테스트&lt;/p&gt;

&lt;p&gt;(2) 통계적 오류 없이 A/B 테스트 하기&lt;/p&gt;

&lt;p&gt;(3) 평균 통계가 주는 함정&lt;/p&gt;

&lt;hr /&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;1-평균을-비교하는-ab-테스트&quot;&gt;(1) 평균을 비교하는 A/B 테스트&lt;/h1&gt;

&lt;h2 id=&quot;1-많은-ab-테스트-케이스들은-평균을-비교합니다&quot;&gt;1. 많은 A/B 테스트 케이스들은 평균을 비교합니다.&lt;/h2&gt;

&lt;p&gt;A/B 테스트는 일정 기간 테스트를 진행하여 전환율, 클릭률 같은 지표에 대해 A, B 두 안의 평균을 비교합니다.&lt;/p&gt;

&lt;p&gt;기간의 전체 평균을 비교할지, 기간의 일 평균을 비교할지 등은 테스트 기획자가 수립한 가설에 따라 달라집니다.&lt;/p&gt;

&lt;h2 id=&quot;2-두-집단의-관측된-평균값을-단순히-비교하는-것이-아닙니다&quot;&gt;2. 두 집단의 관측된 평균값을 단순히 비교하는 것이 아닙니다!&lt;/h2&gt;

&lt;p&gt;팀이 100개가 있는 회사가 있습니다.
그 중 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A팀의&lt;/code&gt;&lt;/strong&gt; 30대 하루 평균 운동량이 20대보다 많을때, &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;회사 전체&lt;/code&gt;&lt;/strong&gt;에도 그렇다고 할 수 있을까요?&lt;/p&gt;

&lt;p&gt;관측된 평균값을 단순히 비교하려면 &lt;em&gt;&lt;u&gt;'일반적으로 전체 집단이 그럴 거야~'&lt;/u&gt;&lt;/em&gt; 하는 확신이 필요합니다.&lt;/p&gt;

&lt;p&gt;하지만 관측된 데이터가 전체 집단을 대표할 수 있다고 확신할 수 없기 때문에 위험한 방법입니다.&lt;/p&gt;

&lt;p&gt;그래서 우리는 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;통계적 분석 방법을 활용&lt;/code&gt;&lt;/strong&gt;하여 관측된 일부 데이터만을 가지고 &lt;em&gt;&lt;u&gt;'일반적으로 전체 집단이 그럴 거야~'&lt;/u&gt;&lt;/em&gt; 라고 할 수 있는 확률을 구하는 것입니다. 이 과정을 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;통계적 추론&lt;/code&gt;&lt;/strong&gt;이라고 합니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2020-12-24-(1)-A-B-test-comparing-averages/1.png&quot; alt=&quot;img1&quot; /&gt;
&lt;em&gt;통계적 추론&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-통계적-가설검정-방법을-활용해-평균을-비교합니다&quot;&gt;3. 통계적 가설검정 방법을 활용해 평균을 비교합니다.&lt;/h2&gt;

&lt;p&gt;가설을 세우고, 실험을 통해 데이터를 수집하고, 통계 분석으로 전체 집단에 대한 추론을 거쳐 가설을 평가합니다.&lt;/p&gt;

&lt;p&gt;일반적으로 &lt;strong&gt;t-test&lt;/strong&gt; 라는 가설 검정 방법을 활용해 &lt;u&gt;두 집단&lt;/u&gt;의 평균값을 비교합니다.&lt;/p&gt;

&lt;p&gt;또한 &lt;strong&gt;ANOVA&lt;/strong&gt; 등의 통계 분석 방법을 활용하면 A/B/n 테스트처럼 &lt;u&gt;여러 집단&lt;/u&gt;의 평균값을 비교 할 수 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2020-12-24-(1)-A-B-test-comparing-averages/2.png&quot; alt=&quot;img2&quot; /&gt;
&lt;em&gt;두 집단 (또는 세 집단 이상)의 평균 비교&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;4-관측된-평균의-비교가-전체-집단-비교로-일반화-될-수-있는지-확인해야-합니다&quot;&gt;4. 관측된 평균의 비교가 전체 집단 비교로 일반화 될 수 있는지 확인해야 합니다.&lt;/h2&gt;

&lt;p&gt;A/B 테스트 이후 우리는 p 값을 확인해야 합니다.&lt;/p&gt;

&lt;p&gt;p 값은 보통 A/B 테스팅 툴, 엑셀, 통계분석 도구 등을 이용했다면 제공될 것입니다.&lt;/p&gt;

&lt;p&gt;p 값은 쉽게 &lt;em&gt;&lt;u&gt;'일반적으로 전체 집단이 그럴 거야~'&lt;/u&gt;&lt;/em&gt; 라고 할 수 있는 확률이라 생각하시면 됩니다.&lt;/p&gt;

&lt;p&gt;이를 통계학에서는 통계적 유의성 이라고 표현합니다.&lt;/p&gt;

&lt;p&gt;위키백과에서는 통계적 유의성을 다음과 같이 정의하고 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;통계적 유의성(統計的 有意性)은 모집단에 대한 가설이 가지는 통계적 의미를 말한다.
다시 말해서, 어떤 실험 결과 자료를 두고 &quot;통계적으로 유의하다.&quot;라고 하는 것은 `확률적으로 봐서 단순한 우연이라고 생각되지 않을 정도로 의미가 있다`는 뜻이다.
반대로 &quot;통계적으로 유의하지 않다.&quot;라고 하는 것은 실험 결과가 단순한 우연일 수도 있다는 뜻이다.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;통계적 유의성을 따지려 들때 p-value (p 값), ɑ (알파) 등의 용어들을 들어보셨을 수도 있습니다.&lt;/p&gt;

&lt;p&gt;하지만 우리는 내 테스트의 결과가 통계적으로 유의한지만 살펴볼 줄 알면 됩니다.&lt;/p&gt;

&lt;p&gt;일반적으로 많은 상황에서 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p 값이 0.05 이하라면 통계적으로 유의하다&lt;/code&gt;&lt;/strong&gt;고 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;두 집단의 평균을 비교하는 A/B 테스트에서는 &lt;strong&gt;p 값이 0.05 이하&lt;/strong&gt;라면 &lt;strong&gt;두 집단 간 차이가 유의하다&lt;/strong&gt;고 해석할 수 있으며 평균 값이 더 높은 안을 채택하면 됩니다 :)&lt;/p&gt;

&lt;h2 id=&quot;5-p-값과-관련된-중요한-사실-한-가지&quot;&gt;5. p 값과 관련된 중요한 사실 한 가지!&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;통계적 유의성이 중요한가요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;결론부터 말하자면 중요합니다. 하지만 굉장히 중요한 것 같지는 않습니다. (정도로 표현하고 싶습니다)&lt;/p&gt;

&lt;p&gt;유의성 검정과 관련해서는 학계에서도 이미 많은 논란이 있으며 논란을 간단히 정리하면 다음과 같습니다.&lt;/p&gt;

&lt;p&gt;p 값을 0.05를 기준으로 이하면 유의하고, 넘어가면 유의하지 않다 라고 &lt;u&gt;이분법적으로 해석&lt;/u&gt;하는 것은 문제라는 것입니다.&lt;/p&gt;

&lt;p&gt;그래서 p 값에 대해서는 &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;융통성있게 해석하는 것을 권장&lt;/code&gt;&lt;/strong&gt;드립니다.&lt;/p&gt;

&lt;p&gt;A/B 테스트에서 p 값이 0.05를 넘어서 0.06 0.07…0.1 정도의 결과가 나온다 하더라도 실패한 실험이구나 좌절하지 마시고 다음과 같이 해석하시면 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;통계적으로 유의하지는 않으나 두 집단 간 평균은 어느정도 차이는 있다고 볼 수 있다! 따라서 어느 안 하나를 선택할 근거는 충분하다!&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;물론 p 값이 0.3, 0.5.. 0.99 가 나온다면 당연히 유의하지 않은 것이니 고민하지 마세요! 🙂&lt;/p&gt;

&lt;hr /&gt;

&lt;hr /&gt;

&lt;p&gt;다음 포스트에서는 통계적 오류 없이 A/B 테스트를 수행하는 방법에 대해 작성하려고 합니다.&lt;/p&gt;

&lt;p&gt;A/B 테스트의 설계 방법과 통계적 분석 방법을 공부할 수 있으니 다음 포스트를 기대해 주세요~!&lt;/p&gt;

&lt;hr /&gt;
</description>
        <pubDate>Thu, 24 Dec 2020 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2020/12/24/(1)-A-B-test-comparing-averages.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2020/12/24/(1)-A-B-test-comparing-averages.html</guid>
        <tags>
          
          <tag>A/B test</tag>
          
          <tag>statistics</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>딥러닝 모델 Trainer 개발을 위한 Tutorial-2 (with Pytorch)</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;인공지능(딥러닝) 모델을 활용해 원하는 문제를 해결하기 위해선, 작성된 모델이 원하는 기능을 수행 할 수 있도록 구성된 학습기의 개발이 필요합니다.&lt;/p&gt;

&lt;p&gt;지난 튜토리얼에 이어 이번 포스팅에선 Basic-Trainer 를 토대로 학습 및 평가의 편의성을 향상시킨, Image-Classification-Trainer 를 만들어보려고 합니다.&lt;/p&gt;

&lt;p&gt;수집된 이미지 데이터로부터 이미지 분류를 파악하고, 분류에 적합한 모델을 생성하여 학습까지 이루어지도록 구성 할 예정입니다.&lt;/p&gt;

&lt;p&gt;지난 포스팅을 아직 보지 않으셨다면 아래 링크에서 보실 수 있습니다.&lt;/p&gt;

&lt;p&gt;( &lt;a href=&quot;https://blog.nerdfactory.ai/2020/10/08/Tutorial-1-for-Deep-Learning-Model-Trainer-Development.html&quot;&gt;지난 포스팅 링크&lt;/a&gt; )&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;개발&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;환경&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pytorch&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상을&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;권장합니다&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;image-classification&quot;&gt;Image-Classification&lt;/h1&gt;

&lt;p&gt;지난 포스팅에서 언급한, 학습기의 필수 구성 요소를 하나씩 되 짚으며 고도화 해 보겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;1-dataset--dataloader&quot;&gt;1. DataSet &amp;amp; DataLoader&lt;/h2&gt;

&lt;p&gt;이전 포스팅에서는 연습용으로 MNIST 데이터 셋을 불러왔지만, 이번에는 내가 학습하려고 하는 이미지들로 구성된 커스텀 데이터셋을 만들어 보려고 합니다.&lt;/p&gt;

&lt;p&gt;먼저 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataset.py&lt;/code&gt; 라는 이름의 파일을 생성하고, 동일한 stage 에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/datasets&lt;/code&gt; 폴더를 만듭니다.&lt;/p&gt;

&lt;p&gt;그리고 그 하위에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/train&lt;/code&gt; , &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/evaluation&lt;/code&gt; 폴더를 만든 뒤, 내부에 각 &lt;strong&gt;class&lt;/strong&gt; 별로 이름을 가진 이미지 폴더들을 구성합니다.&lt;/p&gt;

&lt;p&gt;예시로 개(dog), 고양이(cat), 새(bird) 이미지를 구분하고자 한다면 프로젝트 폴더 내부는 아래와 같을 것입니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PROJECT-BASE-DIRECTORY
    ├── /datasets
    │   ├── /train       # train_dataset
    │   │   ├── /bird
    │   │   ├── /cat
    │   │   └── /dog
    │   │
    │   └── /evaluation  # eval_dataset
    │       ├── /bird
    │       ├── /cat
    │       └── /dog
    │
    └── dataset.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataset.py&lt;/code&gt; 내부에 내용을 작성 할 차례입니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/datasets&lt;/code&gt; 폴더 하위의 내용을 수집해 자동으로 클래스에 따른 index 를 생성하고, 학습용 이미지 데이터셋을 구성하도록 합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# dataset.py
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 필요한 패키지 import
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;json&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.utils.data&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;image_folder_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
    Make Train &amp;amp; Evaluation Image-Dataset from Image-Folder
    :param train_img_dir: Train Image data directory (str)
    :param eval_img_dir: Evaluation Image data directory (str)
    :return: dict{
                      train_dataloader (torch.utils.data.DataLoader),
                      eval_dataloader (torch.utils.data.DataLoader),
                      class_index (dict)
                  }
    &quot;&quot;&quot;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# 이미지 전처리
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;preprocess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Resize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;                             &lt;span class=&quot;c1&quot;&gt;# 이미지의 크기를 256 으로 Resize
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CenterCrop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;                         &lt;span class=&quot;c1&quot;&gt;# 256 사이즈의 이미지 중앙에 정사각형 영역 (224 * 224 사이즈) 을 Crop
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ToTensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;                              &lt;span class=&quot;c1&quot;&gt;# RGB 3 채널에 대해 픽셀별로 0~1 사이의 값을 갖는 Float 형 Tensor 로 변환
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.485&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.456&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.406&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 입력된 mean, std 로 정규화 → 연산 효율을 올리기 위함 입니다. 정규화를 거치지 않아도 학습 가능
&lt;/span&gt;                             &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.229&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.224&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.225&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# 작성된 mean, std 는 ImageNet 으로부터 추출된 일반적인 이미지의 평균/표준편차 값
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 하나의 이미지는 주어진 mean, std 값으로 정규화 된 (3, 224, 224) 사이즈의 Float 텐서로 변환
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Tensor 차원 해석 : (RGB-Channel, Image-Height, Image-Width)
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 이미지 폴더로부터 데이터 생성
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageFolder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ImageFolder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                        &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;preprocess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# train_dataset.classes 로 생성된 이미지 dataset 의 class 를 확인 가능
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# class 와 index 매칭을 위해 dict 형식으로 작성 및 json 파일로 저장
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;datasets/class_index.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;datasets/class_index.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 저장 확인
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 두 dataset 의 class 가 다른지 확인
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;train &amp;amp; validation classes are not same&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;train.classes = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;evaluation.classes = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# DataLoader 생성
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 임의의 batch_size
&lt;/span&gt;                                  &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# 학습 데이터를 랜덤하게 호출
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 임의의 batch_size
&lt;/span&gt;                                 &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# 평가시엔 랜덤하게 데이터를 호출할 필요가 없으므로 False
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;train_dataloader&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;eval_dataloader&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;class_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;train_img_dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;datasets/train&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;datasets/evaluation&quot;&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_folder_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# 생성된 dataset 확인
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train_dataloader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input batch shape = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;target batch = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 1 iter 만 확인하도록 break
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# &amp;gt;&amp;gt;&amp;gt; input batch shape = torch.Size([16, 3, 224, 224])
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# &amp;gt;&amp;gt;&amp;gt; target batch = tensor([0, 1, 1, 0, 1, 1, 2, 0, 0, 2, 2, 0, 1, 0, 1, 2])
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# dataloader 에서 배치 사이즈를 지정한 뒤, iterator 로 호출하면 input: torch.Size([batch, 3, 224, 224]), target: torch.Size([batch]) 로 batch tensor 출력
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;class_index : &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'class_index'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# &amp;gt;&amp;gt;&amp;gt; class_index : {'0': 'bird', '1': 'cat', '2': 'dog'}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if __name__ == &quot;__main__&quot;&lt;/code&gt; 이하에 작성되어 있는 내용을 참고해, 이후 작성할 trainer 파일에서 완성된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dataloader&lt;/code&gt; 를 호출 할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;2-model-구성&quot;&gt;2. Model 구성&lt;/h2&gt;

&lt;p&gt;이번 포스팅에선 Convolution 레이어를 활용한 딥러닝 모델을 활용해 보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;VGGNet 모델 구조를 활용하기 위해 vgg_model.py 파일에 모델을 작성해 줍니다.&lt;/p&gt;

&lt;p&gt;VGGNet 에 대한 자세한 내용은 논문을 참고 부탁드립니다. ( &lt;a href=&quot;https://arxiv.org/abs/1409.1556v6&quot;&gt;https://arxiv.org/abs/1409.1556v6&lt;/a&gt; )&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# vgg_model.py
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 작성된 모델은 VGG11 의 구조를 뼈대로 classifier layer 와 default class 를 줄인 소형 모델입니다.
# 필요한 패키지 import
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.nn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VGG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_weights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VGG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_make_layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# VGG 모델의 구조 정보(cfg) 로부터, Feature 추출기 작성
&lt;/span&gt;        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;avgpool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AdaptiveAvgPool2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# 이미지에서 추출된 특징(Feature)으로부터 class 를 추측하는 분류기 작성
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReLU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inplace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dropout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_weights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;                             &lt;span class=&quot;c1&quot;&gt;# 가중치 초기화 로직
&lt;/span&gt;            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_initialize_weights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;forward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;avgpool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_make_layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;in_channels&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MaxPool2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kernel_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stride&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;conv2d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Conv2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in_channels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kernel_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conv2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReLU&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inplace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;in_channels&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;layers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_initialize_weights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Conv2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kaiming_normal_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'fan_out'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nonlinearity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'relu'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bias&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constant_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BatchNorm2d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constant_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constant_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;constant_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;vgg11_cfg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# VGG 모델의 구조 정보
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VGG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vgg11_cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_weights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# model 빌드
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 테스트 데이터 입력 후 출력 확인
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;test_input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;224&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Model is Ready&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;VGG 모델의 구조 정보로부터 CNN 기반의 모델을 빌드하고, 테스트 텐서를 넣어서 출력이 나오는 것 까지 확인을 해보는 코드 입니다.&lt;/p&gt;

&lt;p&gt;마찬가지로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if __name__ == &quot;__main__&quot;&lt;/code&gt; 이하에 작성되어 있는 내용을 참고해, 이후 작성할 trainer 파일에서 완성된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model&lt;/code&gt; 을 호출 할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;3-criterion-loss_function&quot;&gt;3. Criterion (loss_function)&lt;/h2&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Loss_Function&lt;/code&gt; 의 경우, 지난번과 동일하게 class 분류에 많이 사용하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CrossEntropyLoss&lt;/code&gt; 를 지정하였습니다.&lt;/p&gt;

&lt;p&gt;CrossEntropyLoss 에 대한 보다 자세한 이해를 원하시면 아래 Pytorch 공식 문서를 참고해주세요.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&quot;&gt;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;4-optimizer-의-구성-with-scheduler&quot;&gt;4. Optimizer 의 구성 (with Scheduler)&lt;/h2&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 역전파 연산을 할 모델의 파라미터
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.003&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# 임의의 learning_rate
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 주어진 step 이 지날때마다 학습률(Learning Rate)을 선형으로 변환해주는 스케줄러
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr_scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StepLR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# 학습률을 조절할 optimizer
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;step_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# 학습률을 변환할 주기 (step)
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.9&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# 변환할 학습률 (상대값)
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;역전파 된 loss 의 gradient 결과를 활용하여 모델을 학습하도록 하는 Optimizer 입니다.&lt;/p&gt;

&lt;p&gt;이번에는 Adam(Adaptive Moment Estimation) Optimizer 를 적용해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;지난번과 마찬가지로, 학습하고자 하는 모델의 파라미터(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model.parameters()&lt;/code&gt;)와 학습률(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;learning_rate&lt;/code&gt;) 를 지정해주면, 해당 파라미터를 학습률 만큼 변형하며 모델을 학습합니다&lt;/p&gt;

&lt;p&gt;optimizer.step() 명령어를 활용하여 모델의 파라미터를 수정합니다.&lt;/p&gt;

&lt;p&gt;거기에 더해 이번에는 step 에 따라 학습률(Learning Rate)을 선형으로 변환해주는 스케줄러를 함께 활용해보도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;초기에 너무 작은 값의 학습률을 지정하면, 모델이 수렴하기까지 긴 시간이 걸리게 되지만, 충분한 학습이 이루어진 이후에 적절히 학습률을 감소 시키면 학습에 필요한 시간도 단축하면서, 작은 보폭으로 보다 정확하게 수렴하는 파라미터를 찾을 수 있게 됩니다.&lt;/p&gt;

&lt;p&gt;여기서는 간단한 적용을 위해, 주어진 step 이 지나면 주어진 값만큼 학습률을 변환하는 선형 스케줄러를 구성하였습니다.&lt;/p&gt;

&lt;p&gt;( 필요에 따라 다양한 형태의 스케줄러 사용이 가능하고, 커스텀 할 수도 있습니다 )&lt;/p&gt;

&lt;h2 id=&quot;5-train-iterator&quot;&gt;5. Train Iterator&lt;/h2&gt;

&lt;p&gt;Train Iterator 부분은 기존과 큰 차이가 없습니다.&lt;/p&gt;

&lt;p&gt;앞서 구성해 놓은 dataloader 와 model, optimizer, scheduler 들을 한데 모아 train step 을 진행하면 됩니다.&lt;/p&gt;

&lt;p&gt;다만 이번에는 추가로 GPU 가속을 활용할 수 있도록 Device 세팅을 포함하고, 학습의 상태를 확인할 수 있도록 tqdm 을 활용해 학습 상태를 시각화하는 코드를 작성 해보겠습니다.&lt;/p&gt;

&lt;p&gt;trainer.py 파일에 내용을 작성될 내용을 간단히 요약하면 아래와 같습니다.&lt;/p&gt;

&lt;p&gt;( Loss Function &amp;amp; Optimizer &amp;amp; Scheduler 등의 요소가 작성되어있지 않아서 실제 바로 동작하진 않습니다. Train 에 직접적인 영향을 주는 구성 요소들만 추려놓은 것으로 이해바랍니다 )&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# 필요한 패키지 import
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tqdm&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trange&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# CUDA 를 활용한 GPU 가속 여부에 따라, 장치를 할당 할 수 있도록 변수로 선언
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cuda&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cpu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Prepare Custom Model
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VGG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'vgg11_cfg'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_weights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# model 빌드
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# 모델의 장치를 device 에 할당
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 모델 gradient 초기화
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Train 모드로 모델 설정
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Train Start
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Epoch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 학습 상태 출력을 위한 tqdm.trange 초기 세팅
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Epoch 루프
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch: X/X, global: XXX/XXX, tr_loss: XXX'&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Description 양식 지정
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Step(batch) 루프
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 모델이 할당된 device 와 동일한 device 에 연산용 텐서 역시 할당 되어 있어야 함
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# device 에 연산용 텐서 할당
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Calculate
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# loss 연산
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Backward and optimize
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Update learning rate schedule
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# One train step Done
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Step Description
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'epoch: {}/{}, global: {}/{}, tr_loss: {:.3f}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;전체 학습 Dataset 에 대해, Dataloader 로 생성된 iteration 을 돌면서 step 마다 학습을 진행 합니다.&lt;/p&gt;

&lt;p&gt;기존과 동일하게 1 step 마다 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loss&lt;/code&gt; 를 계산하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;optimizer&lt;/code&gt; 를 초기화 한 뒤, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loss&lt;/code&gt; 를 역전파 하고, 역전파된 정보에 따라 모델의 파라미터를 수정하는 일련의 과정이 코드에 작성되어 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;6-evaluation-logic&quot;&gt;6. Evaluation Logic&lt;/h2&gt;

&lt;p&gt;기존에 구성된 학습기과 마찬가지로 학습된 모델의 정확도 평가를 위한 로직 입니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Evaluation
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 비활성화하고 평가 연산 모드로 설정 (메모리 사용 및 연산 효율화를 위해)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mean_loss&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mean_acc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Description 양식 지정
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Evaluating - mean_loss: XXX, mean_acc: XXX'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Evaluate
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# device 에 연산용 텐서 할당
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Calculate
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Calculate acc &amp;amp; loss
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 정답과 추론 값이 일치하는 경우 정답으로 count
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# 평가 결과 업데이트
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mean_loss&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                        &lt;span class=&quot;s&quot;&gt;&quot;mean_acc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Step Description
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;'Evaluating - mean_loss: {:.3f}, mean_acc: {:.3f}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_acc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 평가 과정이 모두 종료 된 뒤, 다시 모델을 train 모드로 변경
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Evaluation 로직은 함수로 분리하여, 각 Epoch 이 종료되는 시점마다 평가를 진행할 수 있도록 구성할 수 있습니다&lt;/p&gt;

&lt;h1 id=&quot;전체-학습기-구성&quot;&gt;전체 학습기 구성&lt;/h1&gt;

&lt;p&gt;지금까지의 단계를 토대로 trainer.py 파일을 완성하면 다음과 같습니다&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# trainer.py
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 필요한 패키지 import
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;tqdm&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trange&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.optim&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr_scheduler&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;dataset&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_folder_dataset&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;vgg_model&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VGG&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# CUDA 를 활용한 GPU 가속 여부에 따라, 장치를 할당 할 수 있도록 변수로 선언
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cuda&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cuda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cpu&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Prepare Image DataSets
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;train_image_dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_folder_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_image_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_img_dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                         &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'batch_size'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Train &amp;amp; Eval Dataloader
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train_dataloader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'eval_dataloader'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'class_index'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;train_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Prepare Custom Model
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VGG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'vgg11_cfg'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_classes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init_weights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# model 빌드
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# 모델의 장치를 device 에 할당
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델 gradient 초기화
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Train 모드로 모델 설정
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Loss Function
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# loss function
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Optimizer &amp;amp; LR_Scheduler setting
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Adam 옵티마이저 세팅
&lt;/span&gt;                     &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'learning_rate'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr_scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StepLR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 선형 스케줄러 세팅 - 학습률 조정용 스케줄러
&lt;/span&gt;                                    &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'scheduler_step'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                                    &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'scheduler_gamma'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Train Start
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;train_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Epoch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 학습 상태 출력을 위한 tqdm.trange 초기 세팅
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Epoch 루프
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;train_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch: X/X, global: XXX/XXX, tr_loss: XXX'&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Description 양식 지정
&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Step(batch) 루프
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# 모델이 할당된 device 와 동일한 device 에 연산용 텐서 역시 할당 되어 있어야 함
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# device 에 연산용 텐서 할당
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# Calculate
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# loss 연산
&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Backward and optimize
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;scheduler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Update learning rate schedule
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# One train step Done
&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Step Description
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;epoch_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;'epoch: {}/{}, global: {}/{}, tr_loss: {:.3f}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;global_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'epoch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# -- Evaluate &amp;amp; Save model result -- #
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# 한 Epoch 종료 시 평가, 평가 결과 정보를 포함한 이름으로 학습된 모델을 지정된 경로에 저장
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Set Save Path
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;makedirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train_output'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist_ok&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;save_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'train_output'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; \
                    &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/epoch-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-acc-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_acc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-loss-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Save
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save_path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-model.pth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Evaluation
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 비활성화하고 평가 연산 모드로 설정 (메모리 사용 및 연산 효율화를 위해)
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mean_loss&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mean_acc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tqdm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Description 양식 지정
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;eval_dataloader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Evaluating - mean_loss: XXX, mean_acc: XXX'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Evaluate
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;device&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# device 에 연산용 텐서 할당
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image_tensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Calculate
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Calculate acc &amp;amp; loss
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dim&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 정답과 추론 값이 일치하는 경우 정답으로 count
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# 평가 결과 업데이트
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mean_loss&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                            &lt;span class=&quot;s&quot;&gt;&quot;mean_acc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_eval_loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Step Description
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;eval_iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'Evaluating - mean_loss: {:.3f}, mean_acc: {:.3f}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_loss'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'mean_acc'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 평가 과정이 모두 종료 된 뒤, 다시 모델을 train 모드로 변경
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_result&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Train Parameter
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;datasets&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;datasets/train&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;datasets/evaluation&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;                            &lt;span class=&quot;c1&quot;&gt;# 학습용 데이터 경로
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;vgg11_cfg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'M'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# VGG 모델의 구조 정보
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;class_info_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;datasets/class_index.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;                                   &lt;span class=&quot;c1&quot;&gt;# 학습용 데이터의 class_info_file
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;epoch&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;                &lt;span class=&quot;c1&quot;&gt;# 전체 학습 Epoch
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;batch_size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;# Batch Size
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;learning_rate&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# 학습률
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;scheduler_step&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# 어느정도 step 주기로 학습률을 감소할지 지정
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;scheduler_gamma&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# 학습률의 감소 비율
&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;&quot;train_output&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;output&quot;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 학습된 모델의 저장 경로
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# train
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Train Complete&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;초기 parameters 를 받아 학습을 진행합니다. (개인의 선호에 따라 파라미터는 수정하시면 됩니다)&lt;/p&gt;

&lt;p&gt;앞서 구성한대로, 미리 Custom Dataset &amp;amp; DataLoader 를 만들고, Class 정보에 따라 자동으로 Custom 모델을 빌드 한 후, 학습을 진행합니다.&lt;/p&gt;

&lt;p&gt;1 Epoch 이 완료되면 모델을 평가하고, 평가 결과 정보를 포함한 이름으로 모델을 저장합니다.&lt;/p&gt;

&lt;h2 id=&quot;project-skeleton&quot;&gt;Project Skeleton&lt;/h2&gt;

&lt;p&gt;전체 학습기가 구성된 프로젝트의 스켈레톤은 다음과 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PROJECT-BASE-DIRECTORY
    ├── /datasets
    │   ├── /train         # train_dataset
    │   │   ├── /bird
    │   │   ├── /cat
    │   │   └── /dog
    │   │
    │   ├── /evaluation    # eval_dataset
    │   │   ├── /bird
    │   │   ├── /cat
    │   │   └── /dog
    │   │
    │   └── class_index.json  - # dataset &amp;amp; dataloader 구성 시 자동 생성
    │
    ├── /output               - # 학습된 모델 저장시 자동으로 생성 (이하 경로에 학습된 모델 저장)
    │
    ├── dataset.py
    ├── trainer.py
    └── vgg_model.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;( 예시 데이터로 예시로 개(dog), 고양이(cat), 새(bird) 를 구성하였지만, 필요에 따라 적절한 학습 데이터를 구성하시길 바랍니다 )&lt;/p&gt;

&lt;h2 id=&quot;repository&quot;&gt;Repository&lt;/h2&gt;

&lt;p&gt;최종적으로 완성된 전체 프로젝트의 저장소 입니다.&lt;/p&gt;

&lt;p&gt;( 지난번 튜토리얼-1 의 학습기도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;basic-trainer.py&lt;/code&gt; 파일에 작성되어있습니다 )&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/NerdFactoryAI/Trainer-Tutorial&quot;&gt;https://github.com/NerdFactoryAI/Trainer-Tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;학습&quot;&gt;학습&lt;/h2&gt;

&lt;p&gt;적절한 가상환경을 구성한 뒤, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python trainer.py&lt;/code&gt; 명령어를 통해 학습을 진행하면 됩니다.&lt;/p&gt;

&lt;p&gt;tqdm 을 활용해 학습 과정을 시각화 하여, 어느정도 학습이 진행되고 있는지 파악할 수 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-07-08-Tutorial-2-for-Deep-Learning-Model-Trainer-Development/0.png&quot; alt=&quot;0.png&quot; /&gt;&lt;br /&gt;
&lt;em&gt;학습 중간 캡쳐&lt;/em&gt;&lt;/p&gt;

&lt;h1 id=&quot;결론&quot;&gt;결론&lt;/h1&gt;

&lt;p&gt;이것으로 Pytorch 기반의 딥러닝 학습기 Tutorial 을 마무리 하였습니다. 부족한 내용이지만 여러분들의 딥러닝 학습기에 대한 이해를 높이는데 도움이 되었길 기대합니다.&lt;/p&gt;

&lt;p&gt;여기에 작성되어있는 학습기는 이해를 돕기 위해 가독성을 우선하여 작성되었습니다.&lt;/p&gt;

&lt;p&gt;따라서 개개인의 필요에 따라 더욱 최적화, 자동화가 이루어진 발전된 학습기를 작성할 여지가 충분히 있습니다.&lt;/p&gt;

&lt;p&gt;커스텀된 데이터셋과 모델, 적절한 스케줄러와 옵티마이저를 활용해 여러분만의 Task 를 수행할 수 있는 모델을 학습해보시길 바랍니다.&lt;/p&gt;

&lt;h1 id=&quot;reference&quot;&gt;Reference&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pytorch/pytorch&quot;&gt;Pytorch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/pytorch/vision&quot;&gt;Pytorch torchvision&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/yunjey/pytorch-tutorial&quot;&gt;Pytorch Tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.nerdfactory.ai/2020/10/08/Tutorial-1-for-Deep-Learning-Model-Trainer-Development.html&quot;&gt;딥러닝 모델 Trainer 개발을 위한 Tutorial-1 (with Pytorch)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Wed, 04 Nov 2020 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2020/11/04/Tutorial-2-for-Deep-Learning-Model-Trainer-Development.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2020/11/04/Tutorial-2-for-Deep-Learning-Model-Trainer-Development.html</guid>
        <tags>
          
          <tag>DNN</tag>
          
          <tag>Pytorch</tag>
          
          <tag>Supervised Learning</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>딥러닝 모델 Trainer 개발을 위한 Tutorial-1 (with Pytorch)</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;인공지능(딥러닝) 모델을 활용해 원하는 문제를 해결하기 위해선, 작성된 모델이 원하는 기능을 수행 할 수 있도록 구성된 학습기의 개발이 필요합니다.&lt;/p&gt;

&lt;p&gt;이번 포스팅에선 인공지능 학습기. 특히 지도학습을 위한 학습기가 동작하기 위해 필요한 구성 요소에 대해 알아보고, Pytorch 프레임워크를 활용하여 간단한 코드를 작성해보고자 합니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;개발&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;환경&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;python&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.6&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pytorch&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;이상을&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;권장합니다&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;model-trainer-의-필수-구성-요소&quot;&gt;Model-Trainer 의 필수 구성 요소&lt;/h1&gt;

&lt;p&gt;지도학습은 입력된 데이터를 기반으로 모델에게 정답을 추론시키고, 그 결과와 실제 정답을 비교해 추출한 loss 를 역전파 하여, 최종적으로 모델이 정답을 추론 할 수 있도록 학습합니다.&lt;/p&gt;

&lt;p&gt;이러한 일련의 과정을 위해서 필요한 필수 요소들은 다음과 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;DataSet - 학습 &amp;amp; 평가를 위한 (입력, 정답) 쌍으로 구성된 학습용 데이터 셋&lt;/li&gt;
  &lt;li&gt;Model - 추론을 위한 딥러닝 모델&lt;/li&gt;
  &lt;li&gt;Criterion - loss 연산을 위한 함수&lt;/li&gt;
  &lt;li&gt;Optimizer - 학습을 위한 Optimizer&lt;/li&gt;
  &lt;li&gt;Train Iterator - 학습을 위한 Train Step&lt;/li&gt;
  &lt;li&gt;Evaluation Logic - 모델이 얼마나 잘 학습되었는지 확인하기 위한 평가&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;( 위의 요소들 중 하나라도 부족하면 지도학습을 진행 할 수 없게 됩니다. )&lt;/p&gt;

&lt;h1 id=&quot;basic-trainer-개발&quot;&gt;Basic-Trainer 개발&lt;/h1&gt;

&lt;p&gt;학습기의 기본적인 요소들을 포함하여 최소 기능을 하는 학습기를 작성해 봅시다.&lt;/p&gt;

&lt;p&gt;먼저 Pytorch 프레임워크와 필요 모듈들을 import 합니다&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.nn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision.transforms&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Dataset 과 Dataloader 세팅&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abspath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__file__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# MNIST dataset
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MNIST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ToTensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MNIST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ToTensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Data loader
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 임의 지정 batch
&lt;/span&gt;                                           &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;eval_loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# 임의 지정 batch
&lt;/span&gt;                                          &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;필수 요소 중 1번. 학습 &amp;amp; 평가를 위한 (입력, 정답) 쌍으로 구성된 학습용 데이터 셋을 불러옵니다.&lt;/p&gt;

    &lt;p&gt;연습용 데이터로 MNIST 학습 데이터를 불러왔습니다&lt;/p&gt;

    &lt;p&gt;(처음 실행시키는 경우, Pytorch 아카이브로부터 데이터셋을 다운받아 코드를 실행하는 경로의 /data 하위에 MNIST 학습 데이터를 저장합니다)&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;dataset&lt;/p&gt;

        &lt;p&gt;(입력, 정답) 쌍을 활용해 학습용 데이터를 구축할 수 있도록 해주는 class 입니다. (입력, 정답) 각각의 tensor 형은 모델의 입력과 출력 tensor 모양과 동일해야 합니다.&lt;/p&gt;

        &lt;p&gt;MNIST 데이터셋은 28*28 사이즈의 흑백 이미지므로, 입력 tensor 의 포멧은 (batch, 28, 28) 이 되고, 정답은 10개의 class 중 하나의 인덱스를 갖게 됩니다.&lt;/p&gt;

        &lt;p&gt;(입력, 정답) 쌍은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;train_dataset[0]&lt;/code&gt; 과 같이 숫자형 인덱스로 호출 가능합니다.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;dataloader&lt;/p&gt;

        &lt;p&gt;dataset 을 받아서 dataset 내부의 학습 &amp;amp; 평가 데이터를 학습 batch 로 만들어 출력합니다.&lt;/p&gt;

        &lt;p&gt;순서를 무작위로 섞는 옵션도 가능하며 (shuffle=True), for loop 의 요소로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input_batch&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;output_batch&lt;/code&gt; 를 출력합니다&lt;/p&gt;

        &lt;p&gt;위 예시의 경우 임의로 64개 batch 를 할당하였으며, 1번의 step 동안 64개 데이터를 한번에 본 뒤 64개의 추론 결과를 동시에 출력하도록 함을 의미합니다.&lt;/p&gt;

        &lt;p&gt;batch 에 대한 확인을 해보고 싶다면 아래와 같은 간단한 스크립트로 확인이 가능합니다 (tensor 사이즈의 1차원 요소값이 batch 입니다)&lt;/p&gt;

        &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output_batch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;output_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;이렇게 학습을 위한 입력 &amp;amp; 정답 쌍을 준비했습니다&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Model 의 준비&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;784&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;28 * 28 개의 노드로부터 입력을 받고(MNIST format), 1024 차원의 히든 벡터를 갖는 2개 층의 간단한 DNN 모델을 생성하였습니다.&lt;/p&gt;

    &lt;p&gt;이 모델은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 784)&lt;/code&gt; 모양의 tensor 입력을 받아, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(batch, 10)&lt;/code&gt; 모양의 tensor 를 추론 결과로 출력하도록 구성되어 있습니다.&lt;/p&gt;

    &lt;p&gt;(모델은 필요에 따라 VggNet, ResNet, DenseNet 등 다양한 모델을 활용 할 수 있습니다. 입력과 출력 tensor 의 형태에만 주의를 바랍니다)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;loss 함수의 준비&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;class 를 분류하는데 많이 사용하는 CrossEntropyLoss 를 loss 함수로 지정하였습니다.&lt;/p&gt;

    &lt;p&gt;여러 class 중 가장 높은 값을 갖는 class 가 정답이 되도록 추론 할 수 있습니다.&lt;/p&gt;

    &lt;p&gt;CrossEntropyLoss 에 대한 보다 자세한 이해를 원하시면 아래 Pytorch 공식 문서를 참고해주세요.&lt;/p&gt;

    &lt;p&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&quot;&gt;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;CrossEntropyLoss 는 추론 결과로 생성된 (batch, classes) 텐서와 (batch) 정답 텐서를 비교해 Loss 를 연산합니다.&lt;/p&gt;

    &lt;p&gt;위의 MNIST 데이터를 연산하는 모델의 경우, 모델에서 (batch, classes=10) 의 텐서가 출력되고, 정답은 tensor([0, 2, 1, 6, 4, …. (정답 class 의 index 값이 batch 만큼 존재)]) 형태의 텐서가 됩니다.&lt;/p&gt;

    &lt;p&gt;pytorch 는 loss.backward() 명령어를 활용하여 loss 의 역전파를 진행할 수 있습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Optimizer&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SGD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 역전파 연산을 할 모델의 파라미터
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.003&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;# 임의의 learning_rate
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;위에서 계산한 loss 값을 역전파 한 뒤, 해당 역전파의 gradient 결과를 활용하여 모델을 학습하도록 하는 Optimizer 입니다.&lt;/p&gt;

    &lt;p&gt;예시에서는 확률적 경사 하강법이 적용된 SGD(Stochastic Gradient Descent)을 활용하였습니다.&lt;/p&gt;

    &lt;p&gt;학습하고자 하는 모델의 파라미터(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model.parameters()&lt;/code&gt;)와 학습률(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;learning_rate&lt;/code&gt;) 를 지정해주면, 해당 파라미터를 학습률 만큼 변형하며 모델을 학습합니다&lt;/p&gt;

    &lt;p&gt;optimizer.step() 명령어를 활용하여 모델의 파라미터를 학습합니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Train Iterator&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Model 학습
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 전체 데이터를 모두 학습하는 epoch 를 몇번 반복할 것인지. 임의 값
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 활성화하는 학습 모드로 설정
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# epoch 루프
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# step 루프
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# MNIST 텐서는 (batch, 28, 28) 의 형태이므로,
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# 테스트 모델에 적합하도록 (batch, 768) 의 형태로 Reshape 합니다
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 순전파 - 모델의 추론 및 결과의 loss 연산
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Backward and optimize
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# optimizer 초기화 (과거 학습 step 의 gradient 영향을 받지 않기 위해 필요)
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# loss 의 역전파
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 학습
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 학습 상태 정보 출력
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;전체 학습 Dataset 에 대해, Dataloader 로 생성된 iteration 을 돌면서 step 마다 학습을 진행 합니다.&lt;/p&gt;

    &lt;p&gt;1 step 마다 batch 사이즈 만큼의 데이터를 학습하며, epoch 횟수 만큼 전체 데이터셋을 반복해서 학습하게 됩니다.&lt;/p&gt;

    &lt;p&gt;학습을 위해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loss&lt;/code&gt; 를 계산하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;optimizer&lt;/code&gt; 를 초기화 한 뒤, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loss&lt;/code&gt; 를 역전파 하고, 역전파된 정보에 따라 모델의 파라미터를 수정하는 일련의 과정이 코드에 작성되어 있습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Evaluation Logic&lt;/p&gt;

    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 비활성화하고 평가 연산 모드로 설정 (메모리 사용 및 연산 효율화를 위해)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 학습 step 과 동일하게 추론 및 결과의 loss 연산을 진행
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predicted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 가장 큰 값을 갖는 class index 가 모델이 추론한 정답
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predicted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 정답과 추론 값이 일치하는 경우 정답으로 count
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Model Accuracy: {:.2f} %'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 평가가 모두 완료되었으므로 다시 학습 모드로 전환
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;일정 step 만큼 학습이 되면, 실제 학습된 모델의 정확도가 어느정도인지 평가가 필요합니다.&lt;/p&gt;

    &lt;p&gt;이를 위한 Evaluation Logic 으로, 1번 단계에서 선언한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval_dataset&lt;/code&gt; 과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval_loader&lt;/code&gt; 를 활용합니다.&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;model.eval()&lt;/code&gt; 은 모델의 AutoGradient 연산을 비활성화하고, DropOut 및 Batch Normalize 같은 학습용 파라미터를 스킾하여, 모델이 평가모드로 동작할 수 있도록 합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;위의 단계를 토대로 전체 학습기 코드를 작성하면 아래와 같습니다&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Trainer-Tutorial-1 의 MNIST 기초 학습기 입니다
&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torch.nn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;torchvision.transforms&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abspath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__file__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# MNIST dataset
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MNIST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ToTensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torchvision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datasets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MNIST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BASE_DIR&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/datasets'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transforms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ToTensor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Data loader
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 임의 지정 batch
&lt;/span&gt;                                           &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;eval_loader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DataLoader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dataset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eval_dataset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 임의 지정 batch
&lt;/span&gt;                                          &lt;span class=&quot;n&quot;&gt;shuffle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# model
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sequential&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;784&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Linear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Loss Function &amp;amp; Optimizer
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# loss function
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SGD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 역전파 연산을 할 모델의 파라미터
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.003&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 임의의 learning_rate
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Model 학습
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 전체 데이터를 모두 학습하는 epoch 를 몇번 반복할 것인지. 임의 값
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 활성화하는 학습 모드로 설정
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# epoch 루프
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# step 루프
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# MNIST 텐서는 (batch, 28, 28) 의 형태이므로,
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# 테스트 모델에 적합하도록 (batch, 768) 의 형태로 Reshape 합니다
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 순전파 - 모델의 추론 및 결과의 loss 연산
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Backward and optimize
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_grad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# optimizer 초기화 (과거 학습 step 의 gradient 영향을 받지 않기 위해 필요)
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;backward&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# loss 의 역전파
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;optimizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 학습
&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 학습 상태 정보 출력
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epochs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# 한 epoch 가 모두 돈 뒤, Model 평가
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 모델의 AutoGradient 연산을 비활성화하고 평가 연산 모드로 설정 (메모리 사용 및 연산 효율화를 위해)
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_loader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# 학습 step 과 동일하게 추론 및 결과의 loss 연산을 진행
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 28 * 28 = 784
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;criterion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;predicted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 가장 큰 값을 갖는 class index 가 모델이 추론한 정답
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;predicted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 정답과 추론 값이 일치하는 경우 정답으로 count
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'Model Accuracy: {:.2f} %'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;correct_cnt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_cnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;train&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 평가가 모두 완료되었으므로 다시 학습 모드로 전환
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Model Checkpoint 저장
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;torch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'mnist_dnn_model.pth'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;결론&quot;&gt;결론&lt;/h1&gt;

&lt;p&gt;이번 포스팅에선 지도학습을 위한 최소한의 학습기 구성 요소를 활용해, 간단한 Basic-Trainer 를 작성하였습니다.&lt;/p&gt;

&lt;p&gt;아무리 복잡해보이는 Trainer 라도 지도학습을 위한 학습기는 기본적으로 위와 같은 요소들로 구성되어있기 때문에, 전체 학습기의 구조를 이해하고 코드를 해석하는것이 이에 대한 이해 없이 바로 코드부터 들여다 보는것보다 효율적일 것으로 생각됩니다.&lt;/p&gt;

&lt;p&gt;다음 포스팅에선 위의 Basic-Trainer 를 바탕으로 학습 및 평가의 편의성을 향상시킨 학습기를 작성해보도록 하겠습니다.&lt;/p&gt;

&lt;h1 id=&quot;reference&quot;&gt;Reference&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/yunjey/pytorch-tutorial&quot;&gt;https://github.com/yunjey/pytorch-tutorial&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&quot;&gt;https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 08 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2020/10/08/Tutorial-1-for-Deep-Learning-Model-Trainer-Development.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2020/10/08/Tutorial-1-for-Deep-Learning-Model-Trainer-Development.html</guid>
        <tags>
          
          <tag>DNN</tag>
          
          <tag>Pytorch</tag>
          
          <tag>Supervised Learning</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Object-Detection 을 위한 Image Augmentation</title>
        <authors>
          
          
          <author>
            <name>조은성</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/lucas.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2021-03-31-image-augmentation-for-object-detection/image.png</thumbnail>
        <description>&lt;h1 id=&quot;개요&quot;&gt;개요&lt;/h1&gt;

&lt;p&gt;인공지능의 학습을 위한 데이터가 부족할 때, 우리는 적절한 전처리를 통해 학습 데이터를 증가하곤 합니다. 이러한 과정을 Data Augmentation 이라고 하며, 사진(Image) 데이터의 경우 Augmentation 을 위한 많은 방법들이 알려져 있습니다.&lt;/p&gt;

&lt;p&gt;하지만 객체 인식(Object-Detection)을 위한 Image Augmentation 의 경우, 단순히 알려진 방법으로 이미지 데이터만을 증가시킬 경우, 증가된 이미지에 해당되는 객체 영역(Bounding Box)에 대한 정보를 다시 잡아줘야 하는 문제가 발생합니다. 이는 굉장히 수고스러운 일이기에, 이미지에 포함된 객체 정보 역시 함께 증가를 할 필요가 있습니다.&lt;/p&gt;

&lt;p&gt;이번 포스팅에서는 일반적인 Image Augmentation 방법들에 따른 Bounding Box 값의 연산에 대해 알아보고자 합니다.&lt;/p&gt;

&lt;h1 id=&quot;image-augmentation&quot;&gt;Image Augmentation&lt;/h1&gt;

&lt;p&gt;Bounding Box 를 포함한 Augmentation 을 하려면 이미지 좌표에 대해 먼저 정의를 할 필요가 있습니다. 객체인식 학습 데이터를 위한 이미지 라벨링 툴 LabelImg 의 픽셀 좌표 연산 방식을 따라 좌표계를 정의하도록 하겠습니다.&lt;/p&gt;

&lt;p&gt;이미지의 경우 좌상단의 꼭지점을 원점(0, 0)으로 보고 오른쪽 가로 축으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+x&lt;/code&gt;, 아래쪽 세로 축으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+y&lt;/code&gt; 를 잡습니다. 따라서 가로×세로 = 400×300 픽셀인 이미지라면, 이미지의 좌상단이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(0,0)&lt;/code&gt;, 우상단은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(400,0)&lt;/code&gt;, 좌하단 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(0,300)&lt;/code&gt;, 우하단 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(400,300)&lt;/code&gt; 으로 좌표가 세팅 됩니다.&lt;/p&gt;

&lt;p&gt;Bounding Box 의 좌표 역시 위와 같은 좌표 표기법을 사용하며 Box 의 좌상단과 우하단 좌표를 기록해 Box 의 위치를 특정합니다.&lt;/p&gt;

&lt;p&gt;(y_min, x_min) = (a, b), (y_max, x_max) = (c, d)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/2021-03-31-image-augmentation-for-object-detection/image.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이러한 좌표 연산을 통해 Image 와 Bounding Box 를 함께 증가해 보겠습니다.&lt;/p&gt;

&lt;p&gt;(이미지의 밝기, 대비, 색 필터를 변환하는 방식은 Box의 좌표가 변하지 않아 기존의 Augmentation 만을 활용해도 무방하므로 이번 포스팅에서는 다루지 않겠습니다 )&lt;/p&gt;

&lt;h2 id=&quot;1-resize&quot;&gt;1. Resize&lt;/h2&gt;

&lt;p&gt;가장 일반적인 Augmentation 방법으로 이미지의 크기를 변환하는 방식입니다. 이미지 사이즈의 증감 비율을 R 이라고 했을 때,&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;resize_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resize_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;로 계산 가능하고, Bounding Box 역시&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;resize_x_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_x_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resize_y_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_y_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resize_x_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_x_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;resize_y_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_y_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;로 계산 가능합니다.&lt;/p&gt;

&lt;h2 id=&quot;2-좌우반전&quot;&gt;2. 좌우반전&lt;/h2&gt;

&lt;p&gt;반전의 경우, 이미지의 크기는 변화하지 않기 때문에 이미지의 height &amp;amp; width 는 동일하게 유지 됩니다.&lt;/p&gt;

&lt;p&gt;Bounding Box 의 좌표는&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# 상하 좌표에는 영향을 주지 않으므로 y_min, y_max 는 동일
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fliped_x_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_x_min&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fliped_x_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_x_max&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;가 됩니다. (상하 반전은 x가 고정되고, y 좌표에 대해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fliped_y = height - original_y&lt;/code&gt;)&lt;/p&gt;

&lt;h2 id=&quot;3-이미지-회전&quot;&gt;3. 이미지 회전&lt;/h2&gt;

&lt;p&gt;Object-Detection 용 이미지 증가에 가장 복잡한 계산을 필요로 하는 Augmentation 방법입니다. 이 포스팅을 작성하기로 생각한 핵심 이유이기도 합니다.&lt;/p&gt;

&lt;p&gt;이미지를 회전하는경우, 레터박스 같은 영역이 생기며 이미지 전체 사이즈가 커지게 됩니다. 이에 의해 전체 좌표 역시 바뀌게 됩니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-31-image-augmentation-for-object-detection/re_wgle1.png&quot; alt=&quot;re_wgle1&quot; /&gt;&lt;br /&gt;
&lt;em&gt;회전된 모서리마다 빈 영역이 생김&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;원본 이미지 크기 = &lt;em&gt;(w, h)&lt;/em&gt; 에서,&lt;/p&gt;

&lt;p&gt;이러한 좌표 변환에 대응하기 위해 이미지의 중앙(기존 ($\frac{w}{2}$, $\frac{h}{2}$) 지점)을 원점 (0, 0)으로 하고 좌표를 다시 쓰면,&lt;/p&gt;

&lt;p&gt;→ 좌상단($-\frac{w}{2}$, $\frac{h}{2}$), 우상단($\frac{w}{2}$, $\frac{h}{2}$), 좌하단($-\frac{w}{2}$, $-\frac{h}{2}$), 우하단($\frac{w}{2}$, $-\frac{h}{2}$)&lt;/p&gt;

&lt;p&gt;또한 Bounding Box의 각 모서리 좌표를 &lt;em&gt;P1&lt;/em&gt; ~ &lt;em&gt;P4&lt;/em&gt; 로 아래 그림과 같이 할당하면, 이미지 중앙을 기준으로 좌표를 다시 쓸 수 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-31-image-augmentation-for-object-detection/image2.png&quot; alt=&quot;image2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P1&lt;/em&gt; = ($b-\frac{w}{2}$, $\frac{h}{2}-a$)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P2&lt;/em&gt; = ($b-\frac{w}{2}$, $\frac{h}{2}-c$)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P3&lt;/em&gt; = ($d-\frac{w}{2}$, $\frac{h}{2}-a$)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P4&lt;/em&gt; = ($d-\frac{w}{2}$, $\frac{h}{2}-c$)&lt;/p&gt;

&lt;p&gt;이제 회전된 이미지에 대한 좌표를 계산해보도록 하겠습니다. (너무 큰 각도의 회전은 학습에 방해가 되므로 ±5 도 이내의 각도로만 회전하는것을 상정합니다)&lt;/p&gt;

&lt;p&gt;2차원 좌표 평면에서 점 &lt;em&gt;(X , Y)&lt;/em&gt;를 원점(0, 0)을 중심으로 &lt;em&gt;θ&lt;/em&gt; 만큼 회전 하였을 때, 변경된 좌표는&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Xcosθ - Ysinθ , Xsinθ + Ycosθ)&lt;/em&gt; 로 표기됩니다.&lt;/p&gt;

&lt;p&gt;따라서, 회전된 이미지의 크기 &lt;em&gt;(rw, rh)&lt;/em&gt; = &lt;em&gt;(w×cosθ - h×sinθ , w×sinθ + h×cosθ)&lt;/em&gt; 이고,&lt;/p&gt;

&lt;p&gt;마찬가지로 회전된 Bounding Box 의 좌표 &lt;em&gt;P1’ , P2’ , P3’ , P4’&lt;/em&gt; 역시 구할 수 있습니다.&lt;/p&gt;

&lt;p&gt;이제 변환된 Box의 좌표로부터 다시 이미지의 좌상단을 원점으로 하는 박스의 x_min, y_min, x_max, y_max 를 구할 차례입니다. 이때, 회전한 각도의 ± 부호에 따라 min, max 값을 추출하는 좌표가 달라집니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2021-03-31-image-augmentation-for-object-detection/image3.png&quot; alt=&quot;image3&quot; /&gt;&lt;br /&gt;
&lt;em&gt;반시계 방향의 경우 (-) 각도, 시계 방향의 경우 (+) 각도로 회전&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;이러한 일련의 과정을 Python 코드로 나타내면 다음과 같습니다.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rotate_xyminmax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xmax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# (width/2, height/2)를 중심으로 degree 회전
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# ±5도 이내의 각도에서 랜덤하게 degree 지정
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;180&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# radian 으로 변환
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 회전하여 확장된 이미지 영역 re_width, re_height
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 픽셀 좌표는 정수형만 가능하므로 int로 자료형을 변환
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Bounding Box 좌상단을 첫번째 점으로 두고, 반시계방향으로 Box Point 4개를 지정
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P1
&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P2
&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P3
&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ymin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P4
&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# 회전된 Box 의 좌표(P1', P2', P3', P4') 연산
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radian&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# 좌표 변환 후, Image Range를 벗어나지 않도록 if 문으로 예외처리
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 시계방향 회전
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Image Range를 벗어나지 않도록 if 문으로 예외처리
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P1'의 x좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P4'의 y좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P3'의 x좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P2'의 y좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 반시계방향 회전
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Image Range를 벗어나지 않도록 if 문으로 예외처리
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P2'의 x좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P1'의 y좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P4'의 x좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_width&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rotation_point&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# P3'의 y좌표
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_height&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;degree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_xmax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re_ymax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;마무리&quot;&gt;마무리&lt;/h1&gt;

&lt;p&gt;지금까지 Object-Detection 을 위한 Image Augmentation 방법에 대해 알아보았습니다. 포스팅의 주요 전달 내용이 Bounding Box 정보를 포함한 Data Augmentation 이라서 이미지의 밝기, 대비, 색 필터를 변환하는 방식의 Augmentation 은 다루지 않았지만, 해당 방법들과 위의 방법들을 조합해 다양한 방식의 Data Augmentation 을 시도 해 볼 수 있습니다. 적절한 데이터 증가 방법을 활용하여 적은 데이터로도 인공지능 학습 정확도를 향상 시키는데 도움이 되길 기대합니다.&lt;/p&gt;
</description>
        <pubDate>Thu, 10 Sep 2020 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2020/09/10/image-augmentation-for-object-detection.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2020/09/10/image-augmentation-for-object-detection.html</guid>
        <tags>
          
          <tag>Data-Augmentation</tag>
          
          <tag>Object-Detection</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>왜 기술블로그를 유지할까?</title>
        <authors>
          
          
          <author>
            <name>황종택</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/hjt-1.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/why-we-blog/0.jpg</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/why-we-blog/0.jpg&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;백만년만&quot;&gt;백만년만&lt;/h1&gt;

&lt;p&gt;너드팩토리 기술블로그의 마지막 포스트 업데이트는 작년 12월 이었습니다. 해가 넘어간 지도 반년이 넘었네요! 첫 포스트 이후로 대략 1년이 유지되었습니다. 죽은 사람이 숨을 쉬지 않듯 너드팩토리의 블로그는 그렇게 가사상태를 보내고 다시 숨을 쉽니다. 포스트 업데이트가 없었던 지난 반년동안 너드팩토리에 많은 변화와 고민이 있었습니다. 본 포스트에서는 그 중 기술블로그에 대한 고민을 풀어보고자 합니다.&lt;/p&gt;

&lt;h1 id=&quot;블로그&quot;&gt;블로그?&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;weBLOG&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;익히 알려졌듯이 블로그의 어원은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;web + log&lt;/code&gt; 로써 사전적으로 웹에 남기는 기록이라는 뜻이 됩니다. 또한 이러한 합성어의 유래는 개인이 알리고자 하는 바를 웹에 업로드하는 일기(log) 로써 상당히 개인적인 동기에 의한 웹사이트 입니다. 위키피디아에 의하면 최초의 블로그는 게임 제작자 이자 영화 제작자인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Justin Hall&lt;/code&gt; 이 작성한 온라인 일기 라고 합니다. 이후 블로그가 대중화 되면서 신문사에 준하는 뉴스를 제공하는 블로그가 탄생하고, 대형 포탈에서 플랫폼 형태의 블로그를 제공하는 등 다양한 형태로 변모하게 되었습니다.&lt;/p&gt;

&lt;h1 id=&quot;개발자의-블로그&quot;&gt;개발자의 블로그&lt;/h1&gt;

&lt;p&gt;개발자는 특성 상 생산하는 결과물 (코드) 를 종이에 기록하기 매우 까다롭습니다. (도움이 전혀 되지 않는다는 의미는 아닙니다.) 그렇기에 개발자들은 본인의 학습 결과 등을 블로그에 기록하는 문화가 존재했습니다. 온라인에 차곡차곡 쌓인 이러한 포스트 들은 개발자들에게 상호 참고 및 도움을 주는 역할을 담당합니다. 이는 속한 조직과 분야를 뛰어넘어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;개발자&lt;/code&gt; 들 간 상부상조의 문화가 되는 수준에 이르렀습니다. 개발자는 블로그를 통해 본인의 노하우를 공개하고 서로간의 피드백을 주고 받습니다. (물론 SNS 도 이러한 역할을 담당합니다.)&lt;/p&gt;

&lt;h1 id=&quot;기업의-블로그&quot;&gt;기업의 블로그&lt;/h1&gt;

&lt;p&gt;어원에서 알 수 있듯이 블로그의 기원은 극히 개인적은 동기에 의한 기록 입니다. 하지만 대중의 요구에 따라, 혹은 기발한 시도에 의해 다양한 형태의 블로그가 제시되었고 소비되고 있습니다. 기업이 블로그를 활용하게 된 계기 또한 이러한 대중의 수요에 의해 탄생했다고 볼 수 있습니다. 인터넷 사용이 대중화된 현대에 전통적인 매스미디어를 벗어나 저비용으로 기업의 아이덴티티를 제공하고 제품을 홍보할 수 있는 수단이 되었 던 것입니다. 이렇게 기업의 블로그는 다분히 상업적인 성격을 띄고 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;소프트웨어-기업의-블로그&quot;&gt;소프트웨어 기업의 블로그&lt;/h1&gt;

&lt;p&gt;흥한 소프트웨어 기업이 늘어나면서 소위 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;인하우스 개발자가 속한 기업&lt;/code&gt; 이 늘고 있습니다. 이러한 기업에서는 특별한 형태의 블로그가 등장하게 되는데 바로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;기술에 대해 이야기 하는 블로그!&lt;/code&gt; 가 그것입니다. 이러한 블로그는 아래에 나열한 사항에 대해 중요한 의미를 지닌다고 생각합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;기술이 제품 수준을 견인한다.&lt;/li&gt;
  &lt;li&gt;뛰어난 인재의 관심을 유도한다.&lt;/li&gt;
  &lt;li&gt;기술을 공유하고 상호 발전한다.&lt;/li&gt;
  &lt;li&gt;뛰어난 기술이 제품 홍보에 도움이 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;너드팩토리-블로그의-의미&quot;&gt;너드팩토리 블로그의 의미&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;“너드팩토리는 우리의 이야기를 통해 기술 생태계가 더 나아지길 바라며
우리가 연구한 다양한 기술 이야기를 공유하고 있습니다.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;너드팩토리의 블로그의 목적 또한 소프트웨어 기업 블로그의 의미 상당히 계승하고 있습니다. 특히 너드팩토리의 기술이 기술 생태계에 미약하나마 기여하길 바라는 마음이 담겨 있습니다. (제품 홍보는 덤 ^^) 너드팩토리는 지난 6개월 간 조직의 기술연구를 지속하며 내실을 다지는 시간을 가졌습니다. 이를 통해 너드팩토리 기술이 사회에 공익적인 역할을 담당하고 기술생태계에 좋은 영향을 미치는 그날까지 달려보고자 합니다.&lt;/p&gt;
</description>
        <pubDate>Mon, 10 Aug 2020 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2020/08/10/why-we-blog.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2020/08/10/why-we-blog.html</guid>
        <tags>
          
          <tag>블로그</tag>
          
          <tag>기술블로그</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>ICT 인턴십 수기</title>
        <authors>
          
          
          <author>
            <name>고지훈</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ict_june.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/2019-12-20-ict-intern-june/0.png</thumbnail>
        <description>&lt;h1 id=&quot;시작-그리고-시작&quot;&gt;시작 그리고 시작&lt;/h1&gt;

&lt;p&gt;인턴으로 근무했던 4개월이 이렇게 빨리 지나갈 줄은 꿈에도 몰랐습니다. 시작 전에는 4개월이 길다고 느껴졌는데 지금은 4개월의 끝에 와서 저 자신의 부족한 점을 깨닫고 도약하기 위해 준비를 하고 있습니다. 다행인 점은 인턴으로 끝나는 것이 아닌 너드팩토리의 구성원들과 함께 할 수 있다는 점, 그리고 너드팩토리에서 도약을 할 수 있다는 점입니다.&lt;/p&gt;

&lt;h1 id=&quot;너드팩토리의-문화&quot;&gt;너드팩토리의 문화&lt;/h1&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/0.png&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;너드팩토리에서 저의 직무와 관련된 업무에 성실하게 임하면서 최신 기술, 디자인 패턴 등 꾸준히 공부하고 성장하려고 노력했습니다. 하지만 그보다 더 중요한 것은 너드팩토리만의 에자일한 문화를 경험했다는 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;에자일-모델을-적용하기-위한-너드팩토리만의-문화&quot;&gt;에자일 모델을 적용하기 위한 너드팩토리만의 문화&lt;/h2&gt;

&lt;p&gt;에자일 방법론은 매우 빠르고 긴박하게 움직여야 하므로 빠른 의사소통과 대처 그리고 즉각적인 테스트가 중요합니다. 이를 위해서는 팀의 문화가 뒷받침되어야 합니다. 그래서 너드팩토리는 다음과 같은 문화를 가지고 있었습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;영어 호칭 + 님 ⇒ 수평적 의사소통&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;직무만 존재할 뿐 직급과 계급은 없다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;데일리 스크럼을 통한 업무 공유&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;위의 조건들로 다음과 같은 시너지가 발생했습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;회의나 스크럼을 통해 수평적 의사소통의 효과가 더욱 극대화됩니다. 구성원들은 저를 인턴으로 바라보는 것이 아닌 한 명의 개발자로 인식하고 회의에 참여하여 서로의 의견 및 지식을 공유하게 됩니다. 회의라는 것이 불편하고 답답한 분위기가 아닌 활기찬 분위기에서 진행이 되고 그에 따라 더욱더 창의적이고 다방면의 생각을 서로가 효과적으로 도출할 수 있는 환경이 조성되어 있습니다.&lt;/li&gt;
  &lt;li&gt;데일리 스크럼을 비롯하여 각종 회의나 일상에서도 서로의 업무를 공유하게 됩니다. 이때 서로의 업무를 빠르게 알고 협업을 좀 더 유기적으로 진행 할 수 있지만, 그보다 더 중요한 것은 자신의 업무를 공유함으로써 생기는 책임감입니다. 업무의 수준과 강도 등에서 구성원과 비교될 수 있는 상황은 자기계발을 이뤄질 수 있게 하는 동기부여가 됩니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이렇게 질 높은 문화를 유지하기 위해서는 구성원 전부가 자기계발을 꾸준히 해야 합니다. 팀의 문화와 회사의 문화가 실력이 있고 신뢰가 있는 사람을 만들고 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;즐거운-성장&quot;&gt;즐거운 성장&lt;/h2&gt;

&lt;p&gt;너드팩토리의 문화를 경험하면서 학교에의 삶의 태도에 반성하게 되는 순간이 많았습니다. 단순히 게으르게 살았다기보다는 정확한 목표 없이 학부 과정만 이수하면서 흥미를 찾으려고 노력하지 않고 그냥 기계처럼 할당된 과제만 하는 것에 안주했었습니다. 자의적으로 무언가를 탐구하기보다는 성적을 잘 받기 위해라는 목적에 의해 교과목을 공부하고 프로젝트를 진행하였습니다. 제가 하는 프로그래밍적 지식을 넓히는 데는 재미있고 흥미로웠으나 무엇을 위해 배워야 하는지 목표가 없었습니다.&lt;/p&gt;

&lt;p&gt;인턴십 기간은 학부 과정과는 다른 치열함이 있었고 대학에 있을 때 보다 훨씬 바쁜 시기를 보냈습니다. 당연히 처음에는 잘 해내고 싶다, 인정받고 싶다는 마음이 컸기에 제 능력을 초과해서 사용하기도 했고 새벽에 일어나서 프로젝트와 관련된 공부를 하고 출근하기도 했었습니다. 하루하루가 시험 전날과 같은 느낌이었습니다. 하지만 저 스스로가 발전시키는 프로젝트의 규모, 제품의 질이 높아질수록 너무나 즐거웠습니다. 물론 이러한 조직의 문화가 맞지 않는 사람들도 있겠지만 저는 다행히 너드팩토리의 문화가 좋았고 능동적이고 행복한 저 자신을 찾게 되어서 구성원과 문화에 감사했습니다.&lt;/p&gt;

&lt;h1 id=&quot;인턴십-프로젝트&quot;&gt;인턴십 프로젝트&lt;/h1&gt;

&lt;p&gt;저는 웹 프론트엔드 직군으로 지원을 했었고 그에 따라 인턴 기간 동안 크게 두 가지의 프로젝트를 진행했습니다. 프로젝트는 전부 React 기반에서 작업을 했습니다.&lt;/p&gt;

&lt;h2 id=&quot;우리아이-애플리케이션-웹-소개페이지-개발&quot;&gt;우리아이 애플리케이션 웹 소개페이지 개발&lt;/h2&gt;

&lt;p&gt;개발 간 협업의 방식 그리고 겪은 문제와 해결할 수 있었던 방법들을 터득할 수 있었습니다. 그리고 반응형 디자인과 인터렉션, SVG 등 UI/UX에 대한 부분도 공부할 수 있었습니다.&lt;/p&gt;

&lt;h3 id=&quot;재플린을-통한-디자인-공유&quot;&gt;재플린을 통한 디자인 공유&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/1.png&quot; alt=&quot;img1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;프론트엔드 영역은 디자이너와의 의사소통과 상호작용이 활발 해야 하고 즉각적인 피드백이 많이 이루어집니다. 노션앱에서도 그러한 의견이 코멘트 형식으로 자유롭게 전달되긴 하지만 디자인 협업 툴에서 더 극대화됩니다. 너드팩토리에서는 Zeplin이라는 프로그램을 이용하여 디자인을 공유하고 의견을 주고받습니다.&lt;/p&gt;

&lt;h3 id=&quot;컴포넌트-스타일링의-중요성&quot;&gt;컴포넌트 스타일링의 중요성&lt;/h3&gt;

&lt;p&gt;React는 컴포넌트 기반으로 View를 구성합니다. 그에 따라 스타일링 역시 컴포넌트 기반으로 하게 됩니다. 소개페이지 특성상 재활용 되는 View가 많고 동적인 요소와 애니메이션들이 많이 들어가 있습니다. 이를 좀 더 쉽게 구현하기 위해 CSS in JS 라이브러리 중 Styled-Components를 사용하였습니다.&lt;/p&gt;

&lt;p&gt;사실 숙련된 개발자이거나 HTML과 CSS를 순서대로 학습했다면 의심 없이 순수한 CSS를 사용했을 수도 있습니다. 하지만 저는 이전에 Vue.js 라는 프레임워크로 웹을 처음 접했고 Vue의 스타일링 방식이 어느 정도 state에 따라 스타일 바인딩이 가능했었다는 점입니다. 그렇기에 React에서 순수 css를 적용하는 것이 나빠 보일 수밖에 없었습니다.&lt;/p&gt;

&lt;h3 id=&quot;순수-css만을-사용했을때의-문제점&quot;&gt;순수 CSS만을 사용했을때의 문제점&lt;/h3&gt;

&lt;p&gt;우선 state에 따른 css의 동적인 UI를 구성하려고 할 때 기존의 프로그래밍적 사고방식으로는 해결하기가 힘든 점이 있었습니다. 그렇기에 인라인 스타일 형식으로 조건부 스타일링을 구현하거나 여러 개의 클래스를 선언하고 state에 따라 매핑 시켜야 한다는 문제가 있었습니다. 그래서 제가 생각한 문제는 다음과 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;state 값에 따라 스타일을 바인딩 해야 하는 경우&lt;/li&gt;
  &lt;li&gt;props가 많아지고 그에 따른 조건부 스타일링도 많아질 때&lt;/li&gt;
  &lt;li&gt;거의 같은 형태의 스타일링을 가지고 있으나 일부분만 변경하여 새로운 컴포넌트를 만들어야 할 때&lt;/li&gt;
  &lt;li&gt;같은 스타일을 가지고 있는 다른 선택자의 경우&lt;/li&gt;
  &lt;li&gt;색상 값과 같은 반복되는 키워드가 존재할 때&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;그래서-선택한-styled-component-라이브러리&quot;&gt;그래서 선택한 Styled-Component 라이브러리&lt;/h3&gt;

&lt;p&gt;물론 Sass 혹은 Less를 사용하여 위의 문제들을 해결할 수 있습니다. 프로그래밍적 동작 방식을 지원하지만, 여전히 CSS 클래스를 사용하고 있다는 점 네이밍을 고려한 개발을 해야 한다는 점 등 여러 가지 귀찮은 점들이 있었습니다. 그래서 CSS in JS 중 대표적인 Styled-Component 라이브러리를 사용하였습니다. 자세한 내용은 너드팩토리 기술 블로그에 있으니 참고하시기 바랍니다.&lt;/p&gt;

&lt;h2 id=&quot;aivory-관리자페이지-개발&quot;&gt;AIVORY 관리자페이지 개발&lt;/h2&gt;

&lt;p&gt;아키텍처의 필요성과 버전 관리의 중요성을 알 수 있었습니다.&lt;/p&gt;

&lt;h3 id=&quot;버전관리&quot;&gt;버전관리&lt;/h3&gt;

&lt;p&gt;너드팩토리는 크게 스프린트 단위로 버전 관리를 하고 있습니다. 버전에 대한 목표나 정책은 스프린트를 계획할 때 확립하고 버그에 대한 반영 버전은 마이너 픽스로 반영을 하고 있습니다. 너드팩토리는 코드 버전 관리를 GitLab의 원격저장소를 활용하고 있습니다. 대학에 있을 때 역시 과제나 프로젝트 관리를 GitLab을 이용했기 때문에 인터페이스를 다루는 데 있어서 어려움은 없었습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/2.png&quot; alt=&quot;img2&quot; /&gt;
&lt;em&gt;마일스톤을 통한 버전 관리&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/3.png&quot; alt=&quot;img3&quot; /&gt;
&lt;em&gt;이슈 리스트&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;github보다 버전관리와 이슈트래킹이 좀 더 세분되어있고 GUI 역시 더 이쁩니다 . 다만 서버 상태가 불안정하고 가끔 503 에러가 떠서 당황할 때가 있었습니다. 이슈에 대한 브랜치를 생성하여 작업이 완료되면 Merge를 하는 형식입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/4.png&quot; alt=&quot;img4&quot; /&gt;
&lt;em&gt;Merge request 리뷰&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;위와 같이 MR을 하였을 때 MR 담당자와 코드리뷰를 진행하고 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/5.png&quot; alt=&quot;img5&quot; /&gt;
&lt;em&gt;SourceTree&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;그리고 저는 GitBash을 사용하지 않고 소스트리를 이용하여 git을 관리하고 있습니다. GUI를 사용하고 명령어를 콘솔에서 일일이 계속 입력할 필요가 없어서 좋습니다. 오히려 더 직관적이라 브랜치를 빠르게 넘나들면서 이슈를 관리하고 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;디자인패턴에-적합한-리팩토링&quot;&gt;디자인패턴에 적합한 리팩토링&lt;/h3&gt;

&lt;p&gt;AIVORY 관리자페이지는 Flux 패턴에 따라 state들을 관리하고 있습니다. 인계를 받을 당시 디자인 패턴에 따르지 않는 여러 문제가 있었고 현재는 그것들을 해결하기 위해 리팩토링을 하고 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/6.png&quot; alt=&quot;img6&quot; /&gt;&lt;/p&gt;

&lt;p&gt;기존 코드에서는 View 영역에 집중된 Axios 기반 비동기 API 로직들이 존재했습니다. 인턴 기간에 AIVORY GS인증을 위해 에러 검출 및 테스트를 진행하였는데 이때 에러를 찾는 과정이 조금 힘들었습니다. Flux의 단방향 데이터 흐름의 이점을 전혀 살리지 못한 구조였습니다. 그래서 현재는 데이터 변화와 흐름을 예측할 수 있도록 리팩토링을 진행하고 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;생기는 이슈들
    &lt;ul&gt;
      &lt;li&gt;에러 메세지 중복 팝업&lt;/li&gt;
      &lt;li&gt;컴포넌트 리랜더링&lt;/li&gt;
      &lt;li&gt;기타…&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;마치며&quot;&gt;마치며..&lt;/h1&gt;

&lt;p&gt;인턴 기간 모르는 게 많아 구성원분들을 많이 괴롭혔습니다. 제가 모르는 부분에 대해 같이 고민해 주시고 길을 알려주시는 모습에 매우 감사했습니다. 그러한 너드팩토리의 구성원들과 앞으로 함께할 수 있어 기쁘고 고객이 행복한 제품 그리고 내가 행복한 제품 만들기 위해 노력하겠습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/7.jpeg&quot; alt=&quot;img7&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/2019-12-20-ict-intern-june/8.jpeg&quot; alt=&quot;img8&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 20 Dec 2019 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2019/12/20/ict-intern-june.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2019/12/20/ict-intern-june.html</guid>
        <tags>
          
          <tag>ICT 인턴십</tag>
          
          <tag>인턴</tag>
          
          <tag>어시스턴트</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>ICT 인턴십 수기</title>
        <authors>
          
          
          <author>
            <name>임새미</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ict_daisy.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/digging-ict-internship/0.jpg</thumbnail>
        <description>&lt;h1 id=&quot;인턴십-기간동안-내가-경험한-것들&quot;&gt;인턴십 기간동안 내가 경험한 것들&lt;/h1&gt;

&lt;p&gt;안녕하세요~! 너드팩토리에서 PO(Product Owner) 어시를 맡고있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;데이지&lt;/code&gt;입니다.😎
제가 ict 인턴십을 통해 너드팩토리에서 4개월 조금 안되는 기간동안 한 경험을 소개해드릴게요!
너드팩토리의 문화에 관심이 있거나 궁금하신 분들이 읽으시면 좋을 것 같습니다.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;color:gray&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;간단한 소개&lt;/code&gt;
입사 초반에 저는 너드팩토리에서 기획, 마케팅 직무를 맡게 되었습니다.
컴퓨터 공학을 전공했지만 기획직군의 일을 경험해보고 싶어서 선택한 일이었죠.
일을 하다보니 영역이 확장되어 PO도 하게 되었습니다.
&lt;/span&gt;&lt;/p&gt;

&lt;h1 id=&quot;-데일리-스크럼을-통한-의사소통-방식&quot;&gt;🗣 데일리 스크럼을 통한 의사소통 방식&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/digging-ict-internship/0.jpg&quot; alt=&quot;데일리 스크럼&quot; /&gt;&lt;/p&gt;

&lt;p&gt;첫 출근한 날, 오전에 &lt;a href=&quot;https://blog.nerdfactory.ai/2019/07/23/nerdfactory-design-agile.html&quot;&gt;애자일 방법론&lt;/a&gt;과 데일리 스크럼에 대한 설명을 들었습니다.
데일리 스크럼이란 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'날마다 하는 짧은 회의'&lt;/code&gt;로 매일 현재상태를 업데이트하고 조율하는 것을 말합니다.&lt;/p&gt;

&lt;p&gt;기획직군의 경험이 전무하고 무엇을 해야 할지도 명확하지 않았기 때문에&lt;br /&gt;
저는 매일 아침 스크럼때 어떤 말을 해야할지 항상 고민이 많았습니다. 솔직히 말하면 스트레스 였습니다.&lt;/p&gt;

&lt;p&gt;하지만 해야할 일을 찾고 구체적인 계획을 세우고나니 내가 하는 일과 관련된 구성원들과 소통할 수 있게 되고 소통을 통해 더 나은 제품을 만들 수 있는 환경이 형성되었습니다.&lt;/p&gt;

&lt;p&gt;이 과정에서 계획의 중요성을 알게 되었고 내가 맡은 일에 대한 책임감을 갖게 되었습니다.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;일의 진행을 한 눈에 확인하고 조율&lt;/code&gt;할 수 있어서 PO뿐 아니라 구성원 모두에게 좋은 제도라고 생각합니다.&lt;/p&gt;

&lt;h1 id=&quot;-능동적인-업무-환경&quot;&gt;🤓 능동적인 업무 환경&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/digging-ict-internship/1.jpg&quot; alt=&quot;to-do list&quot; /&gt;&lt;/p&gt;

&lt;p&gt;인생의 대부분을 수동적으로 살아온 저에게 능동적인 업무 환경은 낯설었지만
 저의 직무인 기획, 마케터에 대해 공부를 하여 점차 일을 만들어갔습니다.&lt;/p&gt;

&lt;p&gt;초반에는 갈피를 잡지 못해 주어진 일만 했지만 ‘서당개 3년이면 풍월을 읊는다’고 (아직 그 정도는 아니지만) 스스로 일을 찾아서 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;능동적으로 업무를 계획하고 이루어가는 과정&lt;/code&gt;에서 성취감을 느꼈고 자존감도 상승했습니다.&lt;/p&gt;

&lt;p&gt;평소 계획을 잘 세우지 않고 ‘무계획이 계획’이라고 여기던 저의 가치관에 변화를 준 아주 좋은 경험이었습니다. 이런 능동적인 자세는 앞으로 무슨 일을 하더라도 필요한 부분이라고 생각합니다.&lt;/p&gt;

&lt;p&gt;업무 중에 구성원들과 급하게 상의해야할 일이 생기면 양해를 구하고 벙개를 요청하거나 
데일리 스크럼 시간에 회의목적을 밝히고 회의를 요청하며 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;자유롭게 제품을 위한 이야기를 할 수 있습니다.&lt;/code&gt;
이러한 제도가 좋은 제품을 생산하는 바탕이 되어주는 것 같습니다.&lt;/p&gt;

&lt;h1 id=&quot;-실무-경험&quot;&gt;👩‍🔧 실무 경험&lt;/h1&gt;

&lt;p&gt;저는 비전공 편입생입니다. 전적대학교에서는 입시 성적에 맞춰 제약공학과를 들어갔고 제약공학, 화학 등을 시작으로 실험과목이 정말 많았습니다. 2학년 한학기동안 하기 싫은 실험수업을 하고 있던 중 제약회사 견학을 갔을 때 저는 깨달았습니다.&lt;/p&gt;

&lt;p&gt;‘내가 이 전공을 살려서 취업을 하면 오래 버티지 못하고 포기할 것이다’라는 것을. 그때 편입을 결심하고 컴퓨터 공학과로 편입했습니다.&lt;/p&gt;

&lt;p&gt;편입을 한 계기는 코드 몇 줄로 인해 다양한 변화를 줄 수 있다는 점이 흥미로웠고 새로운 것을 배우는게 즐거워서 입니다. 하지만 심화과정을 배우는 3학년들과 함께 수업을 듣다보니 ‘내가 이곳을 졸업하면 무엇을 해야하지? 실제로 회사에서는 어떤 일들을 할까? 학교에서 배우는 것과 차이가 큰가? 등의 다양한 생각과 고민들을 하던 중 좋은 기회로 ict인턴십 제도를 통해 너드팩토리에서 실무경험을 할 기회를 얻게 되었습니다.&lt;/p&gt;

&lt;p&gt;제가 실무경험을 통해 느낀점은 다음과 같습니다.
제품을 만드는 것은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'여러가지의 부품을 가지고 하나의 결과물을 창조하는 것이다.'&lt;/code&gt;라고 생각합니다.&lt;/p&gt;

&lt;p&gt;제가 설계한 설계안을 가지고 회의를 진행하고 디자이너가 디자인을 하고 디자인 회의를 진행하고 디자인을 보면서 개발을 진행하고 이슈가 생기면 설계자, 디자이너, 개발자 모두 모여 회의를 진행하는 방식으로 업무를 진행했습니다.
위처럼 모든 직군의 사람들이 모든 직군의 사람들이 한 제품을 가지고 업무를 진행합니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;기획 - 디자인 - 개발 - 기획 - 개발 - 디자인 - 개발&lt;/code&gt;(애자일) 또 중간중간 회의들… 
다양한 사람들과 기술, 노력의 화합으로 하나의 제품을 만들어본 것과 그 화합의 과정을 직접 경험했다는 것이 가장 뜻깊은 경험이었습니다.&lt;/p&gt;

&lt;h1 id=&quot;-구성원들과-의사소통-하는-법&quot;&gt;😯🤫 구성원들과 의사소통 하는 법&lt;/h1&gt;

&lt;p&gt;너드팩토리에서는 영어호칭을 사용합니다. 처음에는 영어호칭을 사용하기가 다소 민망😊 했지만 계속 사용하다보니 편하게 구성원들과 이야기 할 수 있어 오히려 더 좋았습니다!&lt;/p&gt;

&lt;p&gt;그리고 메터모스트를 통해 업무에 관한 내용, 벙개 소집 그리고 &lt;del&gt;말장난&lt;/del&gt;을 하며 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;소통하는 방식이 정말 편리하고 트렌디&lt;/code&gt;하다고 느껴졌습니다.
상사에게 보고하지 않고 회의가 필요할때 언제든지 양해를 구하고 회의를 진행할 수 있고,
인터넷 상으로 간편하게 의견을 물을 수 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;-끝으로&quot;&gt;🚪 끝으로&lt;/h1&gt;

&lt;p&gt;너드팩토리를 세마디로 요약해 보았습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;기회가 된다면 꼭 한번 경험해 보기를 추천! &lt;br /&gt;
최고의 조직 문화 &lt;br /&gt;
트렌디한 의사소통 방식과 구성원들&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Fri, 20 Dec 2019 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2019/12/20/ict-intern-daisy.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2019/12/20/ict-intern-daisy.html</guid>
        <tags>
          
          <tag>ict인턴십</tag>
          
          <tag>nerdfactory</tag>
          
          <tag>daisy</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>2019 패밀리데이</title>
        <authors>
          
          
          <author>
            <name>백승빈</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/bsb-1.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.aihttp://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/0.jpg</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/0.jpg&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;배경&quot;&gt;배경&lt;/h1&gt;

&lt;p&gt;너드팩토리는 독특한 이름을 가지고 있습니다. 특히 가족분들은 ‘너드’라는 단어가 생소하고 그 뜻이 이해하기 힘든 난해함을 가지고 있어 구성원들이 우리를 가족들에게 소개하기 어렵다는 문제를 토로해왔습니다. 사실 가족이란 구성원 개인 삶의 원동력인 만큼 너드팩토리는 이 문제가 그냥 지나칠 문제가 아니라고 생각하고 어떻게 이 문제를 해결할 수 있을지 고민했습니다. 사실 어떤 솔루션이 제시되어도 결국 ‘백문이불여일견’이라는 것에 모두가 동의하고 2019년 송년회는 가족과 함께 우리를 보여주자는 이야기에 모두 동의했습니다.&lt;/p&gt;

&lt;h1 id=&quot;패밀리-데이&quot;&gt;패밀리 데이&lt;/h1&gt;

&lt;p&gt;사실 갑자기 추진하려다 보니 난제도 많았습니다. 여러 행사와 모임이 있는 연말까지 늦출 수는 없어 이야기가 나온 바로 일주일 뒤에 진행하기로 했고, PT준비부터 다과, 현수막 준비 등 많은 걸 보여드리고 더 풍성한 내용으로 차리고 싶었던 저희의 마음은 급해지기만 했습니다. 다행스럽게도 1층 아로파홀이 연말 준비를 위해 크리스마스 느낌을 내고 있어 우리는 우리 본연의 모습을 보여드리는 것에 집중하고 지금부터 할 수 있는 것에 집중하여 잘 준비하는 것을 목표로 했습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/1.jpg&quot; alt=&quot;img1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;행사 당일이 되자 떨림과 설렘은 모두 발표자인 제 몫이었고 구성원들은 한껏 들뜬 마음으로 가족들과 연락을 주고 받으며 마지막 준비에 박차를 가했습니다. 가족들의 위치를 묻고, 언제 오는지 연락하며 기대하는 구성원들의 표정을 보며 잘 해야한다는 부담감과 압박감도 느꼈지만 어차피 이렇게 된 것 즐기자는 마음가짐으로 조금씩 부담을 즐기기 시작했습니다.&lt;/p&gt;

&lt;p&gt;발표 직전 생각보다 많은 가족분들이 회사에 들어오시자 회사 임원분들도 긴장되었는지 행사 세션을 시작 직전까지 저희 행사 내용들을 검토하시기도 했습니다. 어렵게 모신 귀한 분들이 제대로 된 행사처럼 느껴지게 준비하지 않았다는 핀잔과 함께 시작한 행사에서 30~40분 가량 준비된 발표로 우리를 전부 보여드릴 수는 없겠지만 조직이 어떤 마음인지 조금이라도 전달할 수 있지 않을까라는 생각으로 본격적인 행사를 시작했습니다.&lt;/p&gt;

&lt;p&gt;발표는 새로 합류할 예정인 분들의 가족 분들까지 모시고 시작되었고, 돌도 안된 1살짜리 아이부터 50~60대 부모님들까지 참석하셔서 자리를 빛내주셨습니다. 개인적으로 제법 다양한 발표 자리에 서봤는데 연령층이 이렇게나 다양한 발표는 처음이었습니다. 아니나 다를까 준비해둔 개그 코드는 하나도 먹히지 않고 분위기도 냉랭했었는데 그래도 타깃한 연령대에 속하신 분들은 웃어주셔서 다행이라고 생각했습니다.&lt;/p&gt;

&lt;p&gt;그렇게 준비된 발표가 끝나고 사무실을 구경하며 둘러보실 수 있는 투어가 시작되었습니다. 직접 눈으로 우리 가족이 일하는 사무실을 마주하시자 새롭고 신선한 충격을 받으신 것 같았습니다. 워낙 자유로운 느낌의 회사가 신기하다고 여기시는 분부터 아늑하다는 분까지 다양한 감상평을 남겨주셨습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/2.jpg&quot; alt=&quot;img2&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/3.jpg&quot; alt=&quot;img3&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/4.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;회고&quot;&gt;회고&lt;/h1&gt;

&lt;p&gt;투어를 모두 마치고 원래 가족분들과의 시간을 위해 조기 퇴근을 계획했는데 회사에서 식사라도 대접하고 싶다는 마음에 잠시 기다림의 시간을 갖게 되었습니다. 아무래도 같이 식사하는 것은 불편하니 식사권이라도 드리자는 의미였는데 너무 갑작스러워 준비가 덜 되어 있는 상황에서 경영지원실의 도움을 받아 여기저기 전화로 알아보느라 시간이 지체되었습니다. 그동안 아무 말이라도 하며 지루하지 않게 해드린다는게 아무 말 대잔치가 되어버려 회고 글을 쓰는 지금도 얼굴이 붉어집니다.&lt;/p&gt;

&lt;p&gt;그래도 가족분들의 미소와 손 잡고 응원한다며 내년에도 초대해달라는 멋진 말씀을 들으며 이번 행사 준비하길 정말 잘했다고 혼자 굉장히 뿌듯해 했습니다. 저 뿐만 아니라 너드팩토리의 구성원 모두 즐거움이 가득했으리라 믿으며, 행사 당일 스냅 사진과 하이라이트 영상 방출합니다. (사진과 영상 촬영해준 데이지님, 도로시님 감사드리며 영상은 제일 밑에 있습니다!)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/posts/nerdfactory-family-day-2019/NerdFactory_Familyday_2019.zip&quot; target=&quot;\_blank&quot; class=&quot;markdown-link-body&quot;&gt;원본 사진 다운로드&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/6.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/7.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/8.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/9.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/11.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/12.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/16.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/17.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/18.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/19.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/21.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;http://demo-media.nerdfactory.ai/blog-images/nerdfactory-familyday-2019/22.jpg&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 18 Dec 2019 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2019/12/18/nerdfactory-familyday-2019.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2019/12/18/nerdfactory-familyday-2019.html</guid>
        <tags>
          
          <tag>패밀리데이</tag>
          
          <tag>Nerd Family</tag>
          
          <tag>너드팩토리 패밀리데이</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>Styled-Components를 이용한 React 컴포넌트 스타일링</title>
        <authors>
          
          
          <author>
            <name>고지훈</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ict_june.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/react-styled-components/0.png</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/0.png&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;/h1&gt;

&lt;p&gt;‘우리아이’ 소개페이지를 개발하면서 경험했던 컴포넌트 스타일링 방법과 그 중 React 기반의 ‘CSS-in-JS’ 방식 중 하나인 Styled-Components 라이브러리를 소개하려고 합니다. 그중 조건부 스타일링을 하는 방법으로 기존의 순수 CSS가 어떤 문제를 가졌는지 파악하고 개선하려는 방법으로 Styled-Components 라이브러리는 어떠한 방식으로 작동하는지 코드를 통해서 알아보겠습니다. 개발은 React 환경에서 진행되었습니다.&lt;/p&gt;

&lt;h1 id=&quot;순수-css의-조건부-스타일링&quot;&gt;순수 CSS의 조건부 스타일링&lt;/h1&gt;

&lt;p class=&quot;center&quot;&gt;다음은 Dropdown 버튼을 눌렀을 때 하단으로 Link 메뉴가 등장하는 화면입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/1.png&quot; alt=&quot;img1&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;인라인-형식&quot;&gt;인라인 형식&lt;/h2&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const DropdownContent = ({ show }) =&amp;gt; (
  &amp;lt;div
    className={
      show ? &quot;dropdown-content  dropdown-content-visible&quot; : &quot;dropdown-content&quot;
    }
  &amp;gt;
    &amp;lt;a href=&quot;#&quot;&amp;gt;Link 1&amp;lt;/a&amp;gt;
    &amp;lt;a href=&quot;#&quot;&amp;gt;Link 2&amp;lt;/a&amp;gt;
    &amp;lt;a href=&quot;#&quot;&amp;gt;Link 3&amp;lt;/a&amp;gt;
  &amp;lt;/div&amp;gt;
);

const App = () =&amp;gt; {
  const [dropdownVisible, setDropdownVisible] = useState(false);

  const toggleDropdown = () =&amp;gt; {
    setDropdownVisible(!dropdownVisible);
  };
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div className=&quot;dropdown&quot;&amp;gt;
        &amp;lt;button className=&quot;dropbtn&quot; onClick={toggleDropdown}&amp;gt;
          Dropdown
        &amp;lt;/button&amp;gt;
        &amp;lt;DropdownContent show={dropdownVisible} /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;css-클래스-명을-활용한-조건부-스타일링&quot;&gt;CSS 클래스 명을 활용한 조건부 스타일링&lt;/h2&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const App = () =&amp;gt; {
  const [dropdownVisible, setDropdownVisible] = useState(false);

  const toggleDropdown = () =&amp;gt; {
    setDropdownVisible(!dropdownVisible);
  };
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div className=&quot;dropdown&quot;&amp;gt;
        &amp;lt;button className=&quot;dropbtn&quot; onClick={toggleDropdown}&amp;gt;
          Dropdown
        &amp;lt;/button&amp;gt;
        &amp;lt;div
          className=&quot;dropdown-content&quot;
          style=
        &amp;gt;
          &amp;lt;a href=&quot;#&quot;&amp;gt;Link 1&amp;lt;/a&amp;gt;
          &amp;lt;a href=&quot;#&quot;&amp;gt;Link 2&amp;lt;/a&amp;gt;
          &amp;lt;a href=&quot;#&quot;&amp;gt;Link 3&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;문제점&quot;&gt;문제점&lt;/h2&gt;

&lt;p&gt;가장 대표적인 방법 두 가지를 이용하여 순수 CSS에서 state 변화에 따른 조건부 스타일링은 어떤 방식으로 하는지 보았습니다. 여기서 생기는 문제점은 다음과 같습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;state 값에 따라 스타일을 바인딩 해야 하는 경우&lt;/li&gt;
  &lt;li&gt;props가 많아지고 그에 따른 조건부 스타일링도 많아질 때&lt;/li&gt;
  &lt;li&gt;거의 같은 형태의 스타일링을 가지고 있으나 일부분만 변경하여 새로운 컴포넌트를 만들어야 할 때&lt;/li&gt;
  &lt;li&gt;같은 스타일을 가지고 있는 다른 선택자의 경우&lt;/li&gt;
  &lt;li&gt;색상 값과 같은 반복되는 키워드가 존재할 때&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이러한 고질적인 CSS의 문제점 때문에 CSS 클래스가 많아 질 수도 있고 인라인 스타일링 길이가 길어질 수도 있습니다.&lt;/p&gt;

&lt;h1 id=&quot;css-전처리기---sass&quot;&gt;CSS 전처리기 - Sass&lt;/h1&gt;

&lt;p&gt;CSS의 언어적 특성과 위의 불편함을 해결하기 위해 중첩, 변수, 믹스인, 확장 및 로직을 스타일시트에 구현한 전처리 엔진 형태의 Sass, Less와 같은 CSS 전처리기가 등장했습니다.&lt;/p&gt;

&lt;h2 id=&quot;sass의-효율적인-css-구조-설계&quot;&gt;Sass의 효율적인 CSS 구조 설계&lt;/h2&gt;

&lt;p&gt;사실 순수 CSS에서 &lt;link /&gt; 태그 혹은 @import 를 사용해서 CSS 파일을 구조화 할 수는 있습니다. 다만 각 CSS 파일 호출이 매번 새로운 HTTP 요청을 발생시키고 성능저하의 원인이 될 수도 있습니다. 그러나 Sass의 @import는 개발 환경에서 많은 CSS 파일이 복잡하게 얽혀있더라도 하나의 스타일시트로 컴파일이 됩니다. 즉 HTTP 요청에 의한 성능 이슈를 해결하였습니다.&lt;br /&gt;
결과적으로 CSS의 구조화가 가능해짐에 따라 스타일시트를 한눈에 파악하기 쉬워졌습니다. 협업 관계에서도 스타일시트 구조를 논리적으로 파악할 수 있게 도와줄 수 있습니다.&lt;/p&gt;

&lt;p&gt;다음은 Sass를 이용한 스타일시트 구조 트리의 일부분입니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;│  _bootstrap.scss
│  _custom.scss
│  _reset.scss
│  __core.scss
│  __pages.scss
│  __variables.scss
│
├─core
│  │  _animations.scss
│  │  _components.scss
│  │  _forms.scss
│  │  _mixins.scss
│  │  _utilities.scss
│  │
│  ├─animations
│  │      _animations.scss
│  │      _base.scss
│  │      _bubbles.scss
│  │      _floating.scss
│  │
│  ├─components
│  │      _collapse.scss
│  │      _lists.scss
│  │      _nav.scss
│  │      _navbar.scss
│  │
│  ├─forms
│  │      _buttons.scss
│  │      _checkbox.scss
│  │      _form.scss
│  │      _inputs.scss
│  │
│  ├─mixins
│  │      _animations.scss
│  │      _arrow-variant.scss
│  │      _buttons-variant.scss
│  │      _devices.scss
│  │      _font-awesome.scss
│  │      _icons-variant.scss
│  │      _keyframes.scss
│  │      _patterns.scss
│  │      _position.scss
│  │      _sections.scss
│  │      _shapes.scss
│  │
│  └─utilities
│          _background.scss
│          _border.scss
│          _brands.scss
│          _curve-svg-background.scss
│          _devices.scss
│          _gradients.scss
│          _icons.scss
│          _links.scss
│          _misc.scss
│          _mockup.scss
│          _overlay.scss
│          _position.scss
│          _responsive.scss
│          _shapes.scss
│          _spacing.scss
│          _speech-bubble.scss
│          _text.scss
│          _type.scss
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;기타 기능적인 부분은 Styled-Components에서도 지원하기 때문에 Sass를 사용했을 때 문제점만 언급하고 넘어가겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;문제점-1&quot;&gt;문제점&lt;/h2&gt;

&lt;p&gt;그렇다 하더라도 다음과 같은 문제가 있습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;정해진 가이드가 없으면 구조가 복잡해진다.&lt;/li&gt;
  &lt;li&gt;CSS 클래스 명에 대한 고민은 여전하다.&lt;/li&gt;
  &lt;li&gt;스크롤 지옥도 여전하다&lt;/li&gt;
  &lt;li&gt;여전히 CSS 클래스로 조건부 스타일링을 하고 있다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;실제로 CSS 전처리기를 사용하더라도 CSS의 난해함을 정리하기에는 부족합니다.
이것은 CSS 자체의 문제이기도 합니다. CSS는 변수도 없고, 루프문과 함수사용이 불가합니다. 그런데 요소를 쓰던, 클래스나 id를 쓰던 아니면 그 어떤 선택자를 쓰던 다 받아주는 관대함도 있습니다.&lt;br /&gt;
물론 BEM과 같은 CSS 클래스 명을 정의하는 방법론 등이 있지만, 언어 레벨에서 느끼는 불편함은 사라지지 않습니다.&lt;/p&gt;

&lt;h1 id=&quot;styled-components&quot;&gt;Styled-Components&lt;/h1&gt;

&lt;p&gt;Styled-Components는 위의 문제를 해결하려는 방법들 중 하나이며 Tagged 템플릿 리터럴을 이용해 스타일 정보를 실제 CSS 코드를 사용하여 자바스크립트 파일 안에 스타일을 선언하는 ‘CSS-in-JS’ 방식 중 하나입니다. (인라인 방식과는 다릅니다.) 컴포넌트와 스타일 간의 매핑을 제거하고 SASS나 LESS와 같은 전처리기가 제공하는 프로그래밍적 동작 방식도 제공합니다.&lt;/p&gt;

&lt;h3 id=&quot;라이브러리-설치&quot;&gt;라이브러리 설치&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;yarn add styled-components&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;basic&quot;&gt;Basic&lt;/h2&gt;

&lt;p&gt;더 이상 HTML 요소에 스타일을 입힐 필요도, 클래스 명과 HTML 요소를 기반으로 컴포넌트를 만들 필요가 없습니다.&lt;/p&gt;

&lt;h3 id=&quot;순수-css&quot;&gt;순수 CSS&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/2.png&quot; alt=&quot;img2&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;styled-components-1&quot;&gt;Styled-Components&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/3.png&quot; alt=&quot;img3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위의 두 방식을 비교해 보면 그다지 차이가 없다고 느낄 수도 있지만 일단 Styled-Components를 사용했을 때 CSS 클래스를 사용하지 않는다는 것을 중요시 봐야합니다.&lt;br /&gt;
우선 CSS는 구조와 스타일을 분리하려는 방법입니다.
그 구조와 연결고리를 하는 역할인 클래스 계층을 없애 버리는 방식은 처음 접하는 입장에서는 직관적인 방법이 아니라고 생각이 들 수 있습니다. 그렇지만 스타일과 구조의 분리가 오히려 복잡도의 증가를 일으킬 수 있습니다. 그러나 Styled-Components는 이러한 문제를 자바스크립트의 기능을 이용하여 해결하였습니다.&lt;/p&gt;

&lt;h2 id=&quot;code-samples&quot;&gt;Code samples&lt;/h2&gt;

&lt;h3 id=&quot;props를-통한-조건부-스타일링&quot;&gt;Props를 통한 조건부 스타일링&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;styled-components를 import해서. js에서 스타일링 할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;여러 개의 CSS 클래스를 사용하여 스타일을 적용하는 것처럼 props를 사용하여 특정 스타일을 부여해줄 수 있습니다.&lt;/li&gt;
  &lt;li&gt;&amp;amp; 문자를 사용하여 Sass처럼 자기 자신 선택이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled from &quot;styled-components&quot;;

const Container = styled.div`
  background-color: lightgray;
  width: 100%;
  height: 100vh;
`;

const Button = styled.button`
  color: white;
  min-width: 120px;

  /* props로 넣어 준 값을 직접 전달해 줄 수 있습니다. */
  background-color: ${props =&amp;gt; props.color || &quot;blue&quot;};

  /* &amp;amp; 문자를 사용하여 Sass 처럼 자기 자신 선택이 가능합니다. */
  &amp;amp;:hover {
    background-color: white;
    color: black;
  }
  &amp;amp; + button {
    margin-left: 1rem;
  }
`;

const App = () =&amp;gt; {
  return (
    &amp;lt;Container&amp;gt;
      &amp;lt;Button&amp;gt;버튼1&amp;lt;/Button&amp;gt;
      &amp;lt;Button color=&quot;red&quot;&amp;gt;버튼2&amp;lt;/Button&amp;gt;
    &amp;lt;/Container&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/4.png&quot; alt=&quot;img4&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;global-style&quot;&gt;Global Style&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;body를 위해서 컴포넌트를 만들 필요가 없습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    import React from &quot;react&quot;;
    import styled, { createGlobalStyle } from &quot;styled-components&quot;;

    const GlobalStyle = createGlobalStyle`
      body {
        margin: 50px;
        padding: 50px;
        background-color: black;
      }
    `;
    ...
    const App = () =&amp;gt; {
      return (
        &amp;lt;Container&amp;gt;
          &amp;lt;GlobalStyle /&amp;gt;
          &amp;lt;Button&amp;gt;버튼1&amp;lt;/Button&amp;gt;
          &amp;lt;Button color=&quot;red&quot;&amp;gt;버튼2&amp;lt;/Button&amp;gt;
        &amp;lt;/Container&amp;gt;
      );
    };
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/5.png&quot; alt=&quot;img5&quot; /&gt;&lt;/p&gt;

&lt;p&gt;혹은 전역으로 font-family를 다음과 같이 설정할수도 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const GlobalStyles = createGlobalStyle`
      body {
        @import url('https://fonts.googleapis.com/earlyaccess/notosanskr.css');
        font-family: &quot;Noto Sans KR&quot;, sans-serif !important;
      }
    `;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;extension&quot;&gt;Extension&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;컴포넌트를 재활용하면서 추가 html 태그를 부여하고 싶을 때 기존 컴포넌트를 확장해서 새로운 태그를 만들 수 있습니다.
ex) 버튼을 앵커, 링크로 사용하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    import React from &quot;react&quot;;
    import styled, { createGlobalStyle } from &quot;styled-components&quot;;
    ...
    const Button = styled.button`
      color: white;
      min-width: 120px;

      /* props로 넣어 준 값을 직접 전달해 줄 수 있습니다. */
      background-color: ${props =&amp;gt; props.color || &quot;blue&quot;};

      /* &amp;amp; 문자를 사용하여 Sass 처럼 자기 자신 선택이 가능합니다. */
      &amp;amp;:hover {
        background-color: white;
        color: black;
      }
      &amp;amp; + button {
        margin-left: 1rem;
      }
    `;
    const Anchor = Button.withComponent(&quot;a&quot;);
    ...
    const App = () =&amp;gt; {
      return (
        &amp;lt;Container&amp;gt;
          &amp;lt;GlobalStyle /&amp;gt;
          &amp;lt;Button&amp;gt;버튼1&amp;lt;/Button&amp;gt;
          &amp;lt;Button color=&quot;red&quot;&amp;gt;버튼2&amp;lt;/Button&amp;gt;
    			&amp;lt;Anchor href=&quot;http://google.com&quot;&amp;gt;google&amp;lt;/Anchor&amp;gt;
        &amp;lt;/Container&amp;gt;
      );
    };
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;추가로 확장된 태그에 스타일링이 가능합니다.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const Anchor = styled(Button.withComponent(&quot;a&quot;))`
  color: black;
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;animation&quot;&gt;Animation&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;keyframes를 import 합니다. CSS3의 keyframes와 같은 기능입니다. 각 프레임의 스타일을 정의하는 것과 동일합니다.&lt;/li&gt;
  &lt;li&gt;props를 통해 rotateAni일 경우 animation CSS가 작동하도록 하였습니다.&lt;/li&gt;
  &lt;li&gt;역시 props를 통해 duration과 같은 속성값을 넘겨줄 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    import React from &quot;react&quot;;
    import styled, { createGlobalStyle, keyframes, css } from &quot;styled-components&quot;;
    ...
    const rotation = keyframes`
      from{
        transform: rotate(0deg);
      }
      to{
        transform: rotate(360deg);
      }
    `;
    ...
    const Button = styled.button`
      color: white;
      min-width: 120px;

      /* props로 넣어 준 값을 직접 전달해 줄 수 있습니다. */
      background-color: ${props =&amp;gt; props.color || &quot;blue&quot;};

      /* &amp;amp; 문자를 사용하여 Sass 처럼 자기 자신 선택이 가능합니다. */
      &amp;amp;:hover {
        background-color: white;
        color: black;
      }
      &amp;amp; + button {
        margin-left: 1rem;
      }

      ${props =&amp;gt; {
        if (props.rotateAni) {
          return css`
            animation: ${rotation} ${props.duration}s linear infinite;
          `;
        }
      }}
    `;
    ...
    const App = () =&amp;gt; {
      return (
        &amp;lt;Container&amp;gt;
          &amp;lt;GlobalStyle /&amp;gt;
          &amp;lt;Button&amp;gt;버튼1&amp;lt;/Button&amp;gt;
          &amp;lt;Button color=&quot;red&quot; rotateAni duration={2}&amp;gt;
            버튼2
          &amp;lt;/Button&amp;gt;
          &amp;lt;Anchor href=&quot;http://google.com&quot;&amp;gt;google&amp;lt;/Anchor&amp;gt;
        &amp;lt;/Container&amp;gt;
      );
    };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/6.png&quot; alt=&quot;img6&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;extra-attributes&quot;&gt;Extra Attributes&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;custom attribute를 부여하고 싶을 때 attrs 메소드를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    import React from &quot;react&quot;;
    import styled, { createGlobalStyle} from &quot;styled-components&quot;;
    import resticon from '../../img2/common/restLeft.png';
    ...
    const RestIcon = styled.img.attrs({
      src: resticon,
    })`
      color: white;
      position: absolute;
      top: 37%;
      left: -7%;
      width: 41px;
      height: 33px;
    `;

    const App2 = () =&amp;gt; {
      return (
        &amp;lt;Container&amp;gt;
          &amp;lt;GlobalStyle /&amp;gt;
          &amp;lt;RestIcon /&amp;gt;
        &amp;lt;/Container&amp;gt;
      );
    };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;nesting&quot;&gt;Nesting&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;특정 부모 컴포넌트에서 자식 컴포넌트는 스타일 속성을 특정하게 부여받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    const Card = styled.div`
      background-color:white;
    `
    ...
    const Container = styled.div`
      height: 100%;
      width: 100vh;
      background-color: yellow;
      ${Card}{
        background-color: blue;
      }
    `
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;mixin-and-group&quot;&gt;Mixin and Group&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;CSS 그룹을 의미합니다.&lt;/li&gt;
  &lt;li&gt;다중 상속이 가능하므로 재사용 가능한 스타일들을 유연하게 사용할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;CSS 키워드로 CSS 블록을 만들고 사용할 컨테이너에서 적용 가능하며 재사용 가능합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const Sticky = css`
  position: fixed !important;
  background-color: white;
  border-bottom: 1px solid rgba(0, 0, 0, 0.11);
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.11);
  transition: all 0.6s ease-in-out;
  color: black;
`;
const Navigation = styled.nav`
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  z-index: 1030;
  background-color: transparent;
  min-height: 70px;
  transition: all 0.3s ease 0s;
  display: flex;
  align-content: center;
  padding: 0;
  flex-flow: row nowrap;
  justify-content: flex-start;
  ${Sticky}
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;아래와 같이 Mixin을 만들 수도 있습니다.&lt;br /&gt;
파라미터를 설정할 수 있고 실제 사용하는 컴포넌트에 따라 파라미터를 변경하면서 스타일을 간단하게 변경할 수 있습니다.&lt;br /&gt;
실제로 디자이너가 10개의 모양과 색상이 다른 원 모양의 디자인을 주문할 때 순수 CSS라면 많은 CSS 클래스를 만들어야 하지만 Mixin을 이용하면 간단하고 직관적으로 스타일을 할 수가 있습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/7.png&quot; alt=&quot;img7&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const RingVariant = (radius, stroke = &quot;10&quot;) =&amp;gt; css`
  position: absolute;
  border-radius: 50%;
  height: ${radius * 2}px;
  width: ${radius * 2}px;
  border: ${stroke}px solid rgba(0, 0, 0, 0.5);
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const ShapeRing1 = styled.div`
  ${RingVariant(40, 15)};
  top: 30%;
  left: 0;
  transform: translateX(-50%);
`;

const ShapeRing2 = styled.div`
  ${RingVariant(60, 15)};
  top: 15%;
  left: 0;
  transform: translateX(50%);
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;또한 Mixin을 만들때 디폴트값을 주어 파라미터가 없어도 디폴트한 디자인을 생성할 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;컴포넌트의-재활용&quot;&gt;컴포넌트의 재활용&lt;/h3&gt;

&lt;p&gt;소개페이지 특성상 원페이지로 작성되고 폼마다 좌우 마진이 일정하고 반복되는 스타일이 많기 때문에 재활용에 가장 큰 이점을 가집니다. 더는 CSS 코드를 컴포넌트별로 불필요하게 생산할 필요가 없습니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/8.png&quot; alt=&quot;img8&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/9.png&quot; alt=&quot;img9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;아래 형식으로 스타일된 컴포넌트를 구성하고 랜더링을 하는 컴포넌트들에서 import 하여 사용할수있습니다.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export const ContentLayout = styled.div`
      display: block;
      height: 100%;
      max-width: 1220px;
      margin-left: auto;
      margin-right: auto;
`;

export const FeatureTitle = styled.div`
      font-family: Handon3gyeopsal600g;
      font-size: 58px;
      letter-spacing: -2.07px;
`;

export const FeatureDesc = styled.div`
  font-family: Handon3gyeopsal300g;
   color: #454f5d;
   font-size: 38px;
   line-height: 1.39;
   letter-spacing: -1.35px;
`;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;각 폼마다 좌우가 대칭되어야 하거나 디자인 가이드에 제공되는 스타일 이외의 것이 필요할 때 폼에 맞게 컴포넌트를 수정할 수 있으며 당연히 그렇게 변경된 스타일은 폼 내부에만 적용됩니다.&lt;br /&gt;
아래 코드는 스크롤 위치에 따라 bool 값이 props로 넘어오며 그에 따라 애니메이션을 작동시키는 로직입니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/10.png&quot; alt=&quot;img10&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;theme&quot;&gt;Theme&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;색상 혹은 색상 팔레트를 이용한 글로벌 작업 혹은 글로벌한 정의가 필요한 스타일이 있으면 Redux처럼 사용이 가능합니다.&lt;/li&gt;
  &lt;li&gt;ThemeProvider를 import 합니다.&lt;/li&gt;
  &lt;li&gt;모든 컴포넌트를 ThemeProvider에 연결해야합니다.&lt;/li&gt;
  &lt;li&gt;컴포넌트에 props로 글로벌 정의한 스타일을 가져옵니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;theme.js;

const theme = {
  Secondary01: &quot;#323b45&quot;,
  Secondary02: &quot;#6d747b&quot;,
  Soft_Pink: &quot;#ffa1a3&quot;,
  Inactive_Button: &quot;#f5f5f5&quot;,
  Placeholder_Text: &quot;#b6b9bd&quot;,
  Cancle_Text: &quot;#8a8c8f&quot;,
  Status_Critical: &quot;#ff3b30&quot;,
  White: &quot;#ffffff&quot;,
  Black: &quot;#000000&quot;
};

export default theme;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import styled, { createGlobalStyle, ThemeProvider } from &quot;styled-components&quot;;
import theme from &quot;./theme&quot;;

const GlobalStyle = createGlobalStyle`
      body {
        margin: 0px;
        padding: 0px;
      }
    `;
const Container = styled.div`
  height: 100%;
  width: 100vh;
`;

const Button = styled.button`
  border-radius: 30px;
  padding: 25px 15px;
  background-color: ${props =&amp;gt; props.theme.Soft_Pink};
`;

const App = () =&amp;gt; {
  return (
    &amp;lt;ThemeProvider theme={theme}&amp;gt;
      &amp;lt;Container&amp;gt;
        &amp;lt;GlobalStyle /&amp;gt;
        &amp;lt;Button&amp;gt;hello&amp;lt;/Button&amp;gt;
      &amp;lt;/Container&amp;gt;
    &amp;lt;/ThemeProvider&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;styled-theming&quot;&gt;Styled-theming&lt;/h3&gt;

&lt;p&gt;theme을 보다 쉽게 관리할수있는 Styled-Components의 확장 tool입니다.&lt;br /&gt;
예를 들어 요소를 같이 전달 해줄 수 있기 때문에 Light vs Dark mode에 대한 솔루션이 될 수 있습니다.&lt;br /&gt;
각 모드의 색상을 미리 정의하고 props값 단 하나의 변화로 전역으로 설정된 모든 컴포넌트의 색상이 해당 모드에 맞게 변경됩니다.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/react-styled-components/11.png&quot; alt=&quot;img11&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;result&quot;&gt;Result&lt;/h1&gt;

&lt;p&gt;결과적으로 본문에서 언급한 Sass나 Less를 이용한 CSS 구조 설계와 같은 방식들이 유용하기는 하지만 조건부 스타일링의 방법 등 여전히 제한적인 문제가 있었습니다. 그러나 Styled-Components 라이브러리는 위의 문제들을 해결할 수 있는 방법을 제시하고 있습니다.&lt;/p&gt;

&lt;p&gt;다음과 같은 고민을 하고 있는 리액트 개발자라면 Styled-Components를 사용해 볼 것을 추천합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CSS 작업 시 SASS, LESS 혹은 Webpack을 이용한 구조화 작업에서 시간을 엄청나게 소비한 적이 있을 때&lt;/li&gt;
  &lt;li&gt;CSS 파일 새로 만들고, 클래스명 만들고, 컴포넌트에서 CSS 파일을 왔다 갔다 하면서 시간을 소비한 적이 있을 때&lt;/li&gt;
  &lt;li&gt;Sass를 좋아하고 Nesting, variable, Mixin을 사용하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;마지막으로 CSS의 계속되는 진화로 인해 개발 방법 또한 바뀌고 있습니다. 순수 CSS, Sass, CSS 모듈, Styled-Components 등으로 발전되는 형태에서 무조건 최신의 기술을 사용해야 하는 법은 없습니다. 개발자의 코드에 최적으로 정의된 스타일링 방법을 따라갈 수는 없다고 생각합니다. 그럼에도 불구하고 개발자라면 최신의 기술을 알고 추구하는 것이 더 나은 개발자가 되는 길이라고 생각합니다.&lt;/p&gt;
</description>
        <pubDate>Fri, 25 Oct 2019 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2019/10/25/react-styled-components.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2019/10/25/react-styled-components.html</guid>
        <tags>
          
          <tag>React</tag>
          
          <tag>CSS</tag>
          
          <tag>Styled-Components</tag>
          
        </tags>
        
      </item>
    
      <item>
        <title>SNS 마케팅 파헤치기</title>
        <authors>
          
          
          <author>
            <name>임새미</name>
            <image>https://blog.nerdfactory.ai/assets/images/authors/ict_daisy.png</image>
          </author>
          
          
        </authors>
        <thumbnail>https://blog.nerdfactory.ai/assets/images/posts/digging-sns-marketing/0.jpg</thumbnail>
        <description>&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/digging-sns-marketing/0.jpg&quot; alt=&quot;img0&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;sns-마케팅-파헤치기&quot;&gt;SNS 마케팅 파헤치기&lt;/h1&gt;

&lt;p&gt;마케터는 기업에서 소비자와 가장 가까운 사람이라고 생각합니다.&lt;br /&gt;
좋은 마케터는 소비자에게 친근하고 자연스럽게 다가가야 하고 그러기 위해서 소비자를 잘 파악해야 하고 소비자가 있는 시장을 잘 분석해야 합니다.&lt;/p&gt;

&lt;p&gt;지금부터 제가 너드팩토리에서 마케터로 일하면서 알게 된 마케팅 방법과 진행 과정을 공유해 드리려고 합니다.&lt;/p&gt;

&lt;h1 id=&quot;sns-마케팅을-선택한-이유&quot;&gt;sns 마케팅을 선택한 이유&lt;/h1&gt;

&lt;p&gt;마케팅 타깃 매체, 도구, 방법은 정말 다양합니다. 매체 선택만 하더라도 tv광고, 유튜브 배너 광고, 전단 등 다양한 방법이 있죠.
그 중 제가 선택한 것은 sns 마케팅으로 많은 회사에서 사용하고 있는 마케팅 방법 중 하나 입니다.&lt;br /&gt;
당근마켓같은 경우에는 마케팅의 70%정도를 페이스북에 의존하고 있다고 합니다.
세대가 바뀌고 기술이 발전하면서 전자기기(모바일 기기)의 사용이 꾸준히 늘고 있습니다.
마케팅 타깃이 소셜 미디어를 사용하고 있을 경우, 전파력이 높아 홍보대상이 자연스럽게 확산될 수 있기 때문에  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'이거 잘만 홍보하면 적은 돈으로 많은 사람들에게 홍보할 수 있겠다'&lt;/code&gt;라는 생각에 sns 마케팅 시장에 관심을 가지게 되었습니다.&lt;/p&gt;

&lt;p&gt;간단하게 말하자면 아래 순서와 같습니다.&lt;/p&gt;

&lt;p&gt;모바일 기기 사용자가 증가 &amp;gt; 모바일 기기의 sns 이용률 증가 &amp;gt; 국내 소셜미디어 이용자 규모가 증가 &amp;gt; sns를 활용한 마케팅 시장 확장&lt;/p&gt;

&lt;h2 id=&quot;sns-마케팅의-좋은-점&quot;&gt;sns 마케팅의 좋은 점&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;링크를 통해 블로그, 페이스북, 트위터 등의 상호 연동이 가능하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;한 번에 통합하여 홍보&lt;/code&gt;할 수 있습니다.&lt;br /&gt;
블로그에 올린 글을 다시 작성해서 페이스북에 올릴 필요가 없습니다.
토스같은 경우 토스 블로그를 운영하며 작성한 글을 페이스북 게시글에 링크를 다는 방식으로 운영하고 있습니다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sns 마케팅이 곧 바이럴 마케팅(Viral Marketing)&lt;/code&gt;이 될 수 있습니다.&lt;br /&gt;
예를 들어, 페이스북의 ‘좋아요’ 표현은 내가 아는 지인의 sns에 빠르게 보여 지고 다른 사람들에게 확산되어 자동으로 넓은 범위로 홍보 할 수 있습니다.
이것이 sns 마케팅의 최고 장점이라고 생각합니다.(개인적 의견)&lt;/li&gt;
  &lt;li&gt;sns는 온라인 광고로, 오프라인 광고들과 달리 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;큰 자본 없이도 운영이 가능&lt;/code&gt;하며 sns에는 타임라인, 좋아요 등 활용할 수 있는 서비스가 많고 다양합니다.
 그리고 고객과의 소통을 통한 제품의 피드백이나 블로거와의 연동을 통한 유도성을 자유롭게 활용할 수 있습니다.
뷰티, 패션 쪽에서는 유튜브 크리에이터들과 홍보 캠페인을 진행하며 높은 광고 효과를 보고 있습니다.&lt;br /&gt;
한국 고용 정보원의 김중진 연구위원은 “기업들이 유튜브 크리에이터에게 광고를 주는 이유는 기존 연예인 등 특정인에게 들이는 비용보다 훨씬 낮은 비용을 가지고도 전 세계적으로 홍보할 수 있기 때문”이라고 했습니다.&lt;/li&gt;
  &lt;li&gt;고객이 기업 sns에 글을 쓰면 관리자가 고객의 댓글에 실시간으로 답변을 해주는 등의 고객의 요구를 쉽게 파악할 수 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;실시간 커뮤니케이션&lt;/code&gt;이 가능합니다. 이로 인해 친근한 이미지를 줄 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;마케팅-대상과-매체-정하기&quot;&gt;마케팅 대상과 매체 정하기&lt;/h1&gt;

&lt;h2 id=&quot;마케팅-대상-정하기&quot;&gt;마케팅 대상 정하기&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'적을 알고 나를 알자'&lt;/code&gt;라는 말이 있습니다.
복싱 경기를 앞둔 선수가 상대전수의 경기 방식을 알고 그에 맞는 전략을 세우면 경기에서 승리할 수 있습니다.&lt;br /&gt;
따라서, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;마케팅 타깃을 정확히 파악&lt;/code&gt;해야 마케팅 전략을 잘 세울 수 있겠죠?(네~)
서비스의 내용에 따라서 소비자의 연령대, 성별 등을 짐작해 볼 수 있고 이것들이 마케팅 전략에 큰 영향을 미칩니다.&lt;/p&gt;

&lt;p&gt;제가 우리아이 서비스 마케팅을 어떤 식으로 진행했는지 공유해 드리겠습니다.
‘아이를 위한 육아일기’ 컨셉으로 ‘일기 작성’과 ‘작성한 일기장 공유’ 등의 기능을 제공하는 ‘우리아이’ 서비스의 경우에는 마케팅 대상을 다음과 같이 특정지어 보았습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;평균 출산 연령은 32.8세&lt;/li&gt;
  &lt;li&gt;평균초혼연령이 남편 33.15세, 아내 30.40세 결혼생활 중 첫째아 출산까지의 평균 기간 이 2.16년 인 것으로 보아 ‘우리아이’ 서비스 주요 사용자는 남편 35.31세, 아내 32.56세 이상&lt;/li&gt;
  &lt;li&gt;‘우리아이’ 서비스의 주요 사용자는 25-29세 ~ 35-39세 여성&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이렇게 서비스 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;예상 사용자를 특정&lt;/code&gt;하면 마케팅 범위가 줄어들어 비교적 수월하게 홍보할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;마케팅-매체-정하기&quot;&gt;마케팅 매체 정하기&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;적이 누군지 알았다면 이제는 적의 본거지를 알아봐야 합니다.&lt;/code&gt;
타깃의 본거지를 치기 위해 타깃이 주로 활동하는 매체를 알아보았습니다.&lt;br /&gt;
위에서 조사한 성별, 연령대를 기준으로 선호하는 소셜 미디어(sns)를 알아보았습니다.&lt;/p&gt;

&lt;h3 id=&quot;성별-연령별-선호-sns&quot;&gt;성별, 연령별 선호 sns&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;‘우리아이’ 서비스 주요 고객층인 25~39세 남성과 여성의 선호도가 가장 높은 sns는 `인스타그램, 네이버 밴드, 페이스북, 카카오 스토리, 네이버 카페&lt;/li&gt;
  &lt;li&gt;여성과 남성 모두 연령대가 높아질수록 네이버 밴드, 카페, 카카오 스토리와 같은 친목과 소통이 주된 목적인 sns를 이용하는 경향이 있습니다.&lt;/li&gt;
  &lt;li&gt;‘우리아이’ 서비스의 예상 주요 사용자인 20-40대는 인스타그램, 페이스북, 네이버 밴드 사용이 많습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위의 내용을 바탕으로 타깃 매체는 페이스북, 인스타그램, 네이버 밴드, 카카오스토리, 네이버 카페로 범위를 줄이고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;매체 별 발전 가능성&lt;/code&gt;을 살펴보았습니다.
공들여서 마케팅을 했는데 시장이 퇴보하고 있으면 말짱 도루묵이기 때문에 신중해야 합니다.(참고로 저는 도루묵 좋아합니다.)&lt;/p&gt;

&lt;h3 id=&quot;sns-채널별-점유율-추이&quot;&gt;sns 채널별 점유율 추이&lt;/h3&gt;

&lt;p&gt;소셜 미디어 서비스별 사용시간 조사 그래프를 바탕으로 sns 채널별 점유율 추이를 정리해 보았습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;주로 이용하는 소셜 미디어는 페이스북 &amp;gt; 인스타그램 &amp;gt; 네이버 카페 &amp;gt; 네이버 밴드 순&lt;/li&gt;
  &lt;li&gt;인스타그램과 네이버 카페 사용률은 증가하고, 페이스북과 카카오 스토리는 감소하는 경향을 보였습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;위의 두 가지를 기준으로 마케팅 매체를 페이스북, 인스타그램, 네이버 밴드로 선정하였습니다. 이제 타깃이 주로 활동하는 매체가 어떤 특성을 가지고 있는지 조사하여 더 구체적인 홍보 전략을 수립해 볼까요?(네~)&lt;/p&gt;

&lt;h1 id=&quot;매체별-시장-분석&quot;&gt;매체별 시장 분석&lt;/h1&gt;

&lt;p&gt;특성, 기대효과, 예산을 큰 틀로 잡고 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;선정 매체 시장 분석&lt;/code&gt;을 진행했습니다.&lt;/p&gt;

&lt;h3 id=&quot;페이스북&quot;&gt;페이스북&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/digging-sns-marketing/1.png&quot; alt=&quot;img1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;페이스북 페이지 광고 모델&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;페이스북 페이지의 ‘홍보’버튼 활용
비즈니스 계정으로 브랜드 페이지를 제작한 뒤, 올린 게시물을 필요에 따라 홍보할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;관심사와 연령을 선택하여 타겟을 지정할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;엄마, 아빠, 육아, 일상, 유아, 자녀, 일기, 임신, 딸, 아들, 맘을 관심사로 지정하고 연령을 25-45세로 타겟팅, 기간 30일로 하여 지출을 계산해 보았을 때,&lt;br /&gt;
하루당 1,000원 기준으로 추산 도달 수 30~100명씩 증가하여&lt;br /&gt;
예1) 30일 _ 일일 1,000원(추산 도달 수: 72-210) = 지출 30,000원&lt;br /&gt;
예2) 30일 _ 일일 2,000원(추산 도달 수: 106-307) = 지출 60,000원&lt;br /&gt;
예상 소요 예산과 추산 도달 수는 위와 같습니다.&lt;/p&gt;

    &lt;p&gt;※추산 도달 수: 일일 기준&lt;br /&gt;
※ 캠페인의 종류와 타깃, 노출 위치에 따라 예산이 변동 될 수 있음.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;인스타그램&quot;&gt;인스타그램&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/digging-sns-marketing/3.png&quot; alt=&quot;img2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;인스타그램 비즈니스 계정 광고 모델&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;행동 유도 버튼에 url을 추가할 수 있습니다.&lt;br /&gt;
‘행동 유도 버튼’이란 게시물에 링크를 버튼 형태로 다는 것으로 이것을 활용하여 링크 페이지의 접근도를 높이고 자연스럽게 노출시킬 수 있습니다.&lt;/li&gt;
  &lt;li&gt;관심사와 연령을 선택하여 타겟을 지정할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;페이스북과 연동하여 홍보할 수 있습니다.&lt;br /&gt;
만약 브랜드에서 페이스북과 인스타그램 두 가지 매체를 사용하여 홍보를 한다면 인스타그램 스토리 또는 게시물을 게시할 때 연동 유무를 선택하여 한 번에 두 매체에 게시물을 업로드 할 수 있습니다.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;엄마, 아빠, 육아, 일상, 유아, 자녀, 일기, 임신, 딸, 아들, 맘을 관심사로 지정하고 연령을 25-45세로 타겟팅하여 지출을 계산해 보았을 때,&lt;br /&gt;
하루당 1,000원 기준으로 추산 도달 수 1000~1100명씩 증가하여&lt;br /&gt;
예1) 30일 _ 일일 1,000원(추산 도달 수: 1100-2800) = 지출 30,000원&lt;br /&gt;
예2) 30일 _ 일일 2,000원(추산 도달 수: 2100-5700) = 지출 60,000원&lt;br /&gt;
예상 소요 예산과 추산 도달 수는 위와 같습니다.&lt;/p&gt;

    &lt;p&gt;※추산 도달 수: 30일 기준&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;네이버-밴드&quot;&gt;네이버 밴드&lt;/h3&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;/assets/images/posts/digging-sns-marketing/3.png&quot; alt=&quot;img3&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;밴드-페이지-관리&quot;&gt;밴드 페이지 관리&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;육아정보 공유페이지를 만들어서 유용한 정보를 공유하며 페이지 멤버 모집(육아정보 제휴 업체에게 공유 받아서 노출)&lt;/li&gt;
  &lt;li&gt;멤버가 100명 이상 모이면 어플리케이션 노출 게시글 작성&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;밴드-페이지-상위-노출-전략&quot;&gt;밴드 페이지 상위 노출 전략&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;검색 키워드와 밴드이름 유사하게 설정
밴드 이름으로 설정한 단어 중심으로 검색 상위에 노출됩니다.
예를 들어, ‘우리아이’의 경우에는 ‘육아’, ‘일기’, ‘일상’ 등의 단어를 조합하여 밴드이름으로 설정하면 되겠습니다.&lt;/li&gt;
  &lt;li&gt;나열 순서에 맞는 밴드 이름(특수기호, 숫자, 영문, 한글 순으로 나열됨)&lt;/li&gt;
  &lt;li&gt;대표태그 설정(같은 태그 글끼리 모아보기에 활용) #육아#맘#일상 등&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;밴드-멤버-모집하기&quot;&gt;밴드 멤버 모집하기&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;‘새로 시작한 밴드’ 홍보 신청하기(무료)
‘새로 시작한 밴드’를 신청하면 새글 피드의 상단에 ‘추천 정보’ 항목으로 나타납니다.&lt;/li&gt;
  &lt;li&gt;밴드 페이지 소개말, 제목 -&amp;gt; 검색 키워드와 일치시켜 줍니다.&lt;/li&gt;
  &lt;li&gt;내용, 공지사항, 키워드 설정, 지역 설정 -&amp;gt; 타깃에 맞춤 설정
예상 지출 예산: 0원&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;네이버-밴드가-유료광고-매체에서-제외된-이유&quot;&gt;네이버 밴드가 유료광고 매체에서 제외된 이유&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;네이버 밴드의 프로모션 진행 시, 약정금액(고정가)가 4천 만원이기 때문에 위험부담을 안고 광고를 할 수 없었습니다….&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;그-다음&quot;&gt;그 다음..&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;위처럼 사용자, 마케팅 매체 선정, 매체 별 분석의 과정을 거친 후에 각 항목들을 한 차례 더 세분화하여(마케팅 대상의 관심사, 경험, *광고 방식까지 고려) 구체적인 계획을 세우고 선정한 매체에 서비스를 시험 홍보합니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;도달율, 접근성 등의 시험 홍보 결과를 바탕으로 마케팅 전략을 수정 및 보완하여 다시 진행합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*광고 방식: CPM, CPC, CPA 등이 있음.&lt;/p&gt;

&lt;p&gt;지금까지 햇병아리 마케터의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;‘sns마케팅 파헤치기’&lt;/code&gt; 글 이었습니다. 언젠가 프로 마케터가 될 그 날을 위해… to be continued…&lt;/p&gt;
</description>
        <pubDate>Fri, 25 Oct 2019 00:00:00 +0000</pubDate>
        <link>https://blog.nerdfactory.ai/2019/10/25/digging-sns-marketing.html</link>
        <guid isPermaLink="true">https://blog.nerdfactory.ai/2019/10/25/digging-sns-marketing.html</guid>
        <tags>
          
          <tag>“마케팅”</tag>
          
          <tag>marketing</tag>
          
        </tags>
        
      </item>
    
  </channel>
</rss>