<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Make headway towards solving the problem</title>
    <link>https://iostream.tistory.com/</link>
    <description>AI/ML Software Engineering</description>
    <language>ko</language>
    <pubDate>Wed, 24 Jun 2026 15:56:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>가마뫼</managingEditor>
    <item>
      <title>주니어 엔지니어 때 알았더라면 좋았을 것들 (2)</title>
      <link>https://iostream.tistory.com/193</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://iostream.tistory.com/192&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1편&lt;/a&gt;에 이어서 2편에서도 내가 주니어 엔지니어 때 알았더라면 좋았을 것들에 대해서 정리해 본다. 마찬가지로 이는 나의 주관적인 의견이며 누군가에게는 잘 맞지 않는 내용일 수도 있다. 모든 내용을 비판 없이 받아들이기보다는 본인 상황과 환경에 맞게 적절히 취사선택한다면 더할 나위 없을 것이다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 독서&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;조금은&amp;nbsp;뜬금없는&amp;nbsp;주제일지도&amp;nbsp;모르겠다.&amp;nbsp;2025년&amp;nbsp;기준으로&amp;nbsp;ChatGPT를&amp;nbsp;위시한&amp;nbsp;생성형&amp;nbsp;인공지능&amp;nbsp;시스템들이&amp;nbsp;즐비하며,&amp;nbsp;우리가&amp;nbsp;원하는&amp;nbsp;정보는&amp;nbsp;인터넷에서&amp;nbsp;쉽게&amp;nbsp;찾을&amp;nbsp;수&amp;nbsp;있으니&amp;nbsp;말이다.&amp;nbsp;역설적이지만&amp;nbsp;그러므로&amp;nbsp;독서의&amp;nbsp;중요성은&amp;nbsp;더&amp;nbsp;올라간다고&amp;nbsp;생각한다.&amp;nbsp;그래서&amp;nbsp;누군가가&amp;nbsp;나에게&amp;nbsp;독서가&amp;nbsp;중요하냐고&amp;nbsp;물어보면&amp;nbsp;짧은&amp;nbsp;답은&amp;nbsp;'그렇다'이다.&amp;nbsp;이때&amp;nbsp;독서의&amp;nbsp;부류는&amp;nbsp;기술&amp;nbsp;서적과&amp;nbsp;일반적인&amp;nbsp;서적&amp;nbsp;모두를&amp;nbsp;포괄한다.&amp;nbsp;하지만&amp;nbsp;이렇게&amp;nbsp;얘기하는&amp;nbsp;것은&amp;nbsp;다소간의&amp;nbsp;반발이&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있으니,&amp;nbsp;그에&amp;nbsp;대한&amp;nbsp;긴&amp;nbsp;답을&amp;nbsp;내&amp;nbsp;나름대로&amp;nbsp;정리하자면&amp;nbsp;다음과&amp;nbsp;같다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블로그에 파편화 되어있는 내용은 최종적인 지식 구조화에 나쁜 영향을 줄 가능성이 있다&lt;/li&gt;
&lt;li&gt;책으로 출간된 내용은 기본적으로 출판사와 베타 리더 등 여러 검수를 거치므로 최소한의 검증이 된다&lt;/li&gt;
&lt;li&gt;짧은 글에 자꾸 익숙해지면 긴 글을 읽고 쓰는 데 어려움을 겪을 수밖에 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아마도&amp;nbsp;신문이나&amp;nbsp;유튜브&amp;nbsp;등을&amp;nbsp;통해&amp;nbsp;문해력에&amp;nbsp;관한&amp;nbsp;얘기를&amp;nbsp;들어본&amp;nbsp;사람이&amp;nbsp;있을&amp;nbsp;것이다.&amp;nbsp;좋은&amp;nbsp;책을&amp;nbsp;읽고&amp;nbsp;그것에&amp;nbsp;대해서&amp;nbsp;생각을&amp;nbsp;재정리하며&amp;nbsp;해석해&amp;nbsp;보는&amp;nbsp;연습은&amp;nbsp;누가&amp;nbsp;뭐래도&amp;nbsp;좋은&amp;nbsp;엔지니어가&amp;nbsp;되기&amp;nbsp;위한&amp;nbsp;기본적인&amp;nbsp;조건이라고&amp;nbsp;생각한다.&amp;nbsp;독서가&amp;nbsp;중요한&amp;nbsp;것&amp;nbsp;알겠는데&amp;nbsp;일하느라&amp;nbsp;바쁜데&amp;nbsp;시간&amp;nbsp;내기가&amp;nbsp;어렵다는&amp;nbsp;사람도&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;내&amp;nbsp;기준&amp;nbsp;하루&amp;nbsp;30분&amp;nbsp;정도&amp;nbsp;독서를&amp;nbsp;꼭&amp;nbsp;하려는&amp;nbsp;편인데,&amp;nbsp;30분&amp;nbsp;기준으로는&amp;nbsp;20~40페이지(배경지식에&amp;nbsp;따라&amp;nbsp;편차는&amp;nbsp;조금&amp;nbsp;있음)를&amp;nbsp;읽을&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;300페이지&amp;nbsp;분량의&amp;nbsp;책은&amp;nbsp;단순히&amp;nbsp;계산했을&amp;nbsp;때&amp;nbsp;10일이면&amp;nbsp;한&amp;nbsp;권을&amp;nbsp;본다는&amp;nbsp;얘기다.&amp;nbsp;하루&amp;nbsp;30분&amp;nbsp;시간&amp;nbsp;내는&amp;nbsp;것이&amp;nbsp;정말&amp;nbsp;어려운가는&amp;nbsp;본인이&amp;nbsp;아마&amp;nbsp;가장&amp;nbsp;잘&amp;nbsp;알&amp;nbsp;것이다.&amp;nbsp;추가로&amp;nbsp;어떤&amp;nbsp;책을&amp;nbsp;읽으면&amp;nbsp;좋겠냐고&amp;nbsp;물어보는&amp;nbsp;사람이&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같아서&amp;nbsp;나름의&amp;nbsp;추천&amp;nbsp;도서를&amp;nbsp;남겨놓는다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;기술 서적&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;너무 좋은 책들이 많이 있지만 아래 2권은 꼭 읽어봤으면 하는 책이라 추천해 본다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실용주의 프로그래머&lt;/li&gt;
&lt;li&gt;코드 컴플리트 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;교양 서적&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 자기계발서 같이 성장을 위한 책이 아니라, 재미를 위한 소설도 좋다. 실제로 나 역시 독서의 즐거움을 알게 된 계기는 SF소설을 읽기 시작하면서였고, 업무와 직접적인 연관은 없더라도 개인의 정서적 건강에도 도움이 되었다고 생각한다. 어디서부터 시작해야 할지 막막하다면 아래 책 또는 이전에 작성한 포스팅의 문화체육관광부 추천 도서부터 시작하면 좋을 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;닥치는 대로 끌리는 대로 오직 재미있게 이동진 독서법 (책 후반부에 이동진의 추천도서 800권이 있다)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://iostream.tistory.com/187&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문화체육관광부 추천 도서 (성인과 유아/청소년)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 조언은 누구에게 받을 수 있을까요?&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;제발 전문가에게 물어보길 바란다. 당신의 인생 진로에 어쩌면 큰 나비효과를 일으킬 수 있는 조언을 아무에게나 받아서는 되겠는가? 직접적으로 얘기하면 디시인사이드와 같은 커뮤니티나 카카오 오픈 채팅과 같이 진입 장벽이 낮은 곳에서는 정말 운이 좋지 않은 한 당신이 원하는 조언을 받을 가능성이 거의 없다고 봐도 된다. 특히 대학생들은 경험이 많지 않다 보니 속된 말로 커뮤니티의 글이 사실인지 아닌지 구분하는 것조차 힘들어서, 확실한 이유가 없다면 애초에 본인 진로를 위해서 저런 커뮤니티는 거리를 두는 것이 좋다고 본다. 그러면 어디서 조언을 얻을 수 있을까요에 대한 답을 해야 할 것 같은데 내가 생각하는 이상적인 경로는 다음과 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약,&amp;nbsp;대학원&amp;nbsp;진학이나&amp;nbsp;연구&amp;nbsp;쪽에&amp;nbsp;관심이&amp;nbsp;있다면&amp;nbsp;지도&amp;nbsp;교수님&amp;nbsp;혹은&amp;nbsp;본인이&amp;nbsp;관심&amp;nbsp;있는&amp;nbsp;분야의&amp;nbsp;교수님을&amp;nbsp;활용하자.&amp;nbsp;다만&amp;nbsp;워낙&amp;nbsp;바쁜&amp;nbsp;분들이니&amp;nbsp;무턱대고&amp;nbsp;찾아가거나&amp;nbsp;하는&amp;nbsp;것은&amp;nbsp;결례이므로&amp;nbsp;이메일을&amp;nbsp;활용하여&amp;nbsp;질문을&amp;nbsp;정리하여&amp;nbsp;보내거나,&amp;nbsp;일정을&amp;nbsp;잡아&amp;nbsp;직접&amp;nbsp;찾아뵙고&amp;nbsp;궁금한&amp;nbsp;것들을&amp;nbsp;해결하면&amp;nbsp;좋겠다.&amp;nbsp;실제&amp;nbsp;회사의&amp;nbsp;업무나&amp;nbsp;특정&amp;nbsp;회사에&amp;nbsp;대해서&amp;nbsp;궁금하다면&amp;nbsp;LinkedIn을&amp;nbsp;활용해&amp;nbsp;보자.&amp;nbsp;예를&amp;nbsp;들어&amp;nbsp;내가&amp;nbsp;&amp;nbsp;Coupang의&amp;nbsp;backend&amp;nbsp;engineer에&amp;nbsp;대해서&amp;nbsp;궁금하다면&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;검색해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BTuJC/btsM3hznyXH/EXCTwkKMVaQ8y5PHbeVJaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BTuJC/btsM3hznyXH/EXCTwkKMVaQ8y5PHbeVJaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BTuJC/btsM3hznyXH/EXCTwkKMVaQ8y5PHbeVJaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBTuJC%2FbtsM3hznyXH%2FEXCTwkKMVaQ8y5PHbeVJaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;656&quot; height=&quot;191&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아마 현재 Coupang에 재직 중이거나 이전에 재직했던 엔지니어들을 볼 수 있을 것이다. 리스트 중 운이 좋다면 본인과 학연 또는 지연이 있는 사람이 있을 수도 있을 것이고, 대부분은 많은 선배 소프트웨어 엔지니어들은 도움을 주고 싶어 한다. 궁금한 내용이 있다면 현재 재직 중인 사람에게 물어보는 것이 가장 정확할 것이다. 다만 대외비나 민감한 내용에 대해서는 거절할 수 있으며, 그것에 대해서도 너무 마음 상하지 말기를 바란다. 마지막으로 &lt;a href=&quot;https://www.inflearn.com/mentors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인프런의 멘토링&lt;/a&gt;과 같은 서비스도 필요하다면 활용해 볼 수 있겠다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 근로 소득 외의 자산 관리&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;앞으로는&amp;nbsp;근로&amp;nbsp;소득&amp;nbsp;외에&amp;nbsp;개인&amp;nbsp;재무&amp;nbsp;관리가&amp;nbsp;점점&amp;nbsp;더&amp;nbsp;중요해질&amp;nbsp;것으로&amp;nbsp;생각한다.&amp;nbsp;단순히&amp;nbsp;주식하고&amp;nbsp;말고가&amp;nbsp;중요한&amp;nbsp;것이&amp;nbsp;아니라&amp;nbsp;경제&amp;nbsp;용어나&amp;nbsp;시장의&amp;nbsp;변화&amp;nbsp;등에&amp;nbsp;우리의&amp;nbsp;신경을&amp;nbsp;집중해야&amp;nbsp;한다는&amp;nbsp;얘기다.&amp;nbsp;우리&amp;nbsp;삶에&amp;nbsp;영향을&amp;nbsp;직접&amp;nbsp;주는&amp;nbsp;중요한&amp;nbsp;내용임에도&amp;nbsp;불구하고&amp;nbsp;정규&amp;nbsp;교육과정&amp;nbsp;등&amp;nbsp;제대로&amp;nbsp;가르치는&amp;nbsp;곳이&amp;nbsp;없다는&amp;nbsp;것이&amp;nbsp;안타깝다.&amp;nbsp;다음&amp;nbsp;링크를&amp;nbsp;봤을&amp;nbsp;때&amp;nbsp;이는&amp;nbsp;한국만&amp;nbsp;그런&amp;nbsp;것이&amp;nbsp;아니라&amp;nbsp;외국의&amp;nbsp;소프트웨어&amp;nbsp;엔지니어들도&amp;nbsp;비슷한&amp;nbsp;상황이라&amp;nbsp;스탠퍼드에서&amp;nbsp;엔지니어를&amp;nbsp;위한&amp;nbsp;재무&amp;nbsp;강의를&amp;nbsp;따로&amp;nbsp;만들었을&amp;nbsp;정도라고&amp;nbsp;하니&amp;nbsp;말을&amp;nbsp;다&amp;nbsp;한&amp;nbsp;것이&amp;nbsp;아닐까.&amp;nbsp;찾아보면&amp;nbsp;좋은&amp;nbsp;자료들이&amp;nbsp;생각보다&amp;nbsp;많이&amp;nbsp;있다.&amp;nbsp;앞에서&amp;nbsp;얘기한&amp;nbsp;기술&amp;nbsp;공부,&amp;nbsp;영어,&amp;nbsp;독서보다&amp;nbsp;어쩌면&amp;nbsp;더&amp;nbsp;중요한&amp;nbsp;내용일지도&amp;nbsp;모르니&amp;nbsp;꼭&amp;nbsp;읽어보고&amp;nbsp;빠르게&amp;nbsp;자산&amp;nbsp;관리를&amp;nbsp;시작해&amp;nbsp;보자.&amp;nbsp;개인적으로&amp;nbsp;빠르면&amp;nbsp;빠를수록&amp;nbsp;좋다고&amp;nbsp;생각한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스탠포드 엔지니어를 위한 재무 강의 ( &lt;a href=&quot;https://news.hada.io/topic?id=9431&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://news.hada.io/topic?id=9431&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;금융감독원 / 생애주기별 금융생활 가이드북 1권 ( &lt;a href=&quot;https://www.fss.or.kr/edu/fec/contMng/view.do?menuNo=300018&amp;amp;contentsSlno=138&amp;amp;check=2&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.fss.or.kr/edu/fec/contMng/view.do?menuNo=300018&amp;amp;contentsSlno=138&amp;amp;check=2&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;금융감독원 / 대학생을 위한 실용금융 4판 ( &lt;a href=&quot;https://www.fss.or.kr/edu/fec/contMng/view.do?menuNo=300018&amp;amp;check=2&amp;amp;contentsSlno=688&amp;amp;pageIndex=&amp;amp;search=&amp;amp;searchWrd=&amp;amp;certYn=&amp;amp;order=regDt&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.fss.or.kr/edu/fec/contMng/view.do?menuNo=300018&amp;amp;check=2&amp;amp;contentsSlno=688&amp;amp;pageIndex=&amp;amp;search=&amp;amp;searchWrd=&amp;amp;certYn=&amp;amp;order=regDt&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;토스 / THE MONEY BOOK ( &lt;a href=&quot;https://www.yes24.com/product/goods/132290741&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.yes24.com/product/goods/132290741&lt;/a&gt; )\&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 최신 기술 트렌드 따라잡기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 리서치와 같은 연구는 기본적으로 Google Scholar를 활용한다. 아예 백그라운드가 없는 상태라면 서베이 논문 혹은 리뷰 논문을 통해 시작하면 좋은데, 다음과 같은 템플릿을 활용해 볼 수 있겠다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;Topic&amp;gt; survey paper&lt;/li&gt;
&lt;li&gt;&amp;lt;Topic&amp;gt; review paper&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 그림은 deep learning quantization review paper에 대한 검색어 결과이다. 출간 년도와 인용 수를 적절히 필터링하면 좋은 리뷰 페이퍼를 찾을 수 있을 것이고, 리뷰 페이퍼에서 세부적인 페이퍼에 대한 인용이 있으므로 더 자세한 내용을 해당 논문을 참조해나가면서 관심 분야의 트렌드를 따라갈 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFQkMS/btsM04B0ke4/txi7kNVUOMbImZHE7zC8zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFQkMS/btsM04B0ke4/txi7kNVUOMbImZHE7zC8zK/img.png&quot; data-alt=&quot;Quantization review paper&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFQkMS/btsM04B0ke4/txi7kNVUOMbImZHE7zC8zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFQkMS%2FbtsM04B0ke4%2Ftxi7kNVUOMbImZHE7zC8zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;681&quot; height=&quot;419&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Quantization review paper&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;엔지니어링의 경우도 운이 좋다면 관심 분야의 리뷰 페이퍼를 찾을 수 있으나, 보통은 기술 블로그를 통해서 최신 트렌드를 따라가는 편이다. 본인이 E-commerce 도메인에 있다면 Amazon의 테크블로그를, 또는 소셜 미디어 도메인이라면 LinkedIn과 같은 유사한 기업의 테크 블로그를 잘 살펴보면 좋은 아이디어를 얻을 수 있을 것이다. 그 외 한국의 여러 빅테크들도 테크 블로그를 대체로 운영하고 있으니 RSS와 같은 서비스를 활용하거나 테크 블로그를 큐레이션하는 다음과 같은 서비스 ( &lt;a href=&quot;https://www.velopers.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.velopers.kr/&lt;/a&gt; )도 활용해보면 좋을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdx17A/btsM12Xuika/8rYrpTBTXdPPuh0gHFY8DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdx17A/btsM12Xuika/8rYrpTBTXdPPuh0gHFY8DK/img.png&quot; data-alt=&quot;비정상 액션을 감지하기 위한 LinkedIn 테크 블로그&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdx17A/btsM12Xuika/8rYrpTBTXdPPuh0gHFY8DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdx17A%2FbtsM12Xuika%2F8rYrpTBTXdPPuh0gHFY8DK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;497&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;비정상 액션을 감지하기 위한 LinkedIn 테크 블로그&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마치며&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;주니어&amp;nbsp;엔지니어&amp;nbsp;때&amp;nbsp;알았다면&amp;nbsp;좋았을&amp;nbsp;것들이라는&amp;nbsp;주제를&amp;nbsp;빌미로&amp;nbsp;여러&amp;nbsp;잔소리를&amp;nbsp;늘어놓은&amp;nbsp;것&amp;nbsp;같아&amp;nbsp;누군가에게는&amp;nbsp;듣기&amp;nbsp;싫은&amp;nbsp;내용이었을지도&amp;nbsp;모르겠다.&amp;nbsp;그렇지만&amp;nbsp;후배&amp;nbsp;엔지니어들은&amp;nbsp;가능하면&amp;nbsp;내가&amp;nbsp;했었던&amp;nbsp;시행착오를&amp;nbsp;안&amp;nbsp;하고&amp;nbsp;올바른&amp;nbsp;방향으로&amp;nbsp;갔으면&amp;nbsp;하는&amp;nbsp;마음에서&amp;nbsp;잔소리라고&amp;nbsp;생각해&amp;nbsp;주면&amp;nbsp;고맙겠다.&amp;nbsp;이&amp;nbsp;외에도&amp;nbsp;본인만의&amp;nbsp;좋은&amp;nbsp;팁이&amp;nbsp;있다면&amp;nbsp;댓글로&amp;nbsp;남겨주길&amp;nbsp;바란다.&lt;/p&gt;</description>
      <category>개발 이야기</category>
      <category>소프트웨어 엔지니어</category>
      <category>주니어 엔지니어</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/193</guid>
      <comments>https://iostream.tistory.com/193#entry193comment</comments>
      <pubDate>Sun, 30 Mar 2025 20:13:53 +0900</pubDate>
    </item>
    <item>
      <title>주니어 엔지니어 때 알았더라면 좋았을 것들 (1)</title>
      <link>https://iostream.tistory.com/192</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;대학원&amp;nbsp;석사&amp;nbsp;과정&amp;nbsp;2년이&amp;nbsp;나에게는&amp;nbsp;정말로&amp;nbsp;쉽지&amp;nbsp;않은&amp;nbsp;시간이었는데,&amp;nbsp;오히려&amp;nbsp;졸업하고&amp;nbsp;나서야&amp;nbsp;&lt;a href=&quot;https://www.yes24.com/Product/Goods/72231788&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;대학원생&amp;nbsp;때&amp;nbsp;알았더라면&amp;nbsp;좋았을&amp;nbsp;것들&lt;/a&gt;이라는 책을 보게 되었고 이걸 진작 알았더라면 하는 생각이 많이 들었었다. 소프트웨어 엔지니어로서 8년 가까이 일을 한 이제는 모든 것이 적절한 때가 있다는 얘기가 많이 공감된다. 최근에 글또 내에서 주니어 엔지니어분들과 커피챗을 할 기회가 있었는데 그들의 고민하는 부분과 이전에 모 대학교 특강에서 자주 묻는 말들로 정리한 것들이 꽤 많이 겹치는 것이 있어 이번 기회에 내가 생각하는 주니어 엔지니어 때 알았더라면 좋았을 것들을 정리해 본다. 시작하기에 앞서 글 작성자는 컴퓨터 공학을 전공했고 머신러닝 관련 석사를 했으며, 운이 좋게도 경력 시작부터 좋은 조직들을 거쳐왔기 때문에 모든 사람이 공감할 수 있는 내용이 아닐 수 있다는 점을 미리 밝힌다. 비록 시작점은 다르더라도 글 내용 중 일부를 본인 상황에 맞게 잘 취사선택하여 어제보다 나은 내가 될 수 있으면 충분하다고 생각한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Software Engineer에게 가장 중요한 스킬셋&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;내가&amp;nbsp;생각하는&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;기술&amp;nbsp;셋은&amp;nbsp;전산학&amp;nbsp;관련&amp;nbsp;전공&amp;nbsp;지식,&amp;nbsp;영어,&amp;nbsp;그리고&amp;nbsp;체력이라고&amp;nbsp;생각한다.&amp;nbsp;각각에&amp;nbsp;대해서&amp;nbsp;아래에서&amp;nbsp;조금&amp;nbsp;더&amp;nbsp;자세히&amp;nbsp;설명을&amp;nbsp;해본다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 전산학 지식&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;직군 (Front-end engineer, Back-end engineer, Data engineer 등)에 따라 조금씩 중요도의 차이는 있겠지만, 좋은 엔지니어가 되기 위한 기반은 결국 튼튼한 전산학 전공 지식이라고 생각한다. 소프트웨어 엔지니어는 결국 문제를 해결하는 사람들이고 그 문제를 적절히 풀기 위해서는 시간/공간 복잡도를 고려해야하며, 우리가 실행하는 애플리케이션이 어떤 형태로 스케줄링되는지 그리고 데이터는 어떻게 효율적으로 관리할 지를 매일같이 고민한다. 이전 문장에서 서술한 내용을 대표하는 전산학 전공 과목들이 데이터 구조와 알고리즘, 운영체제/컴퓨터 구조, 데이터베이스와 같은 것들이라고 할 수 있겠다. 토이 프로젝트나 간단한 프로그램에서는 어떻게든 돌아가게 만드는 것이 큰 문제가 되지 않지만, 대규모 트래픽을 다루는 서비스나 로우레벨 소프트웨어 구현 시 이런 튼튼한 백그라운드는 Problem Solver로서 자신의 가치를 더 빛나게 해줄 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;전산학&amp;nbsp;지식이&amp;nbsp;중요하다는&amp;nbsp;말은&amp;nbsp;아마&amp;nbsp;이&amp;nbsp;글이&amp;nbsp;아니더라도&amp;nbsp;주위에서&amp;nbsp;꽤&amp;nbsp;들어봤을&amp;nbsp;것이고,&amp;nbsp;그래서&amp;nbsp;어떻게&amp;nbsp;전공&amp;nbsp;지식을&amp;nbsp;공부하고&amp;nbsp;쌓아나가면&amp;nbsp;좋을지에&amp;nbsp;대한&amp;nbsp;답변을&amp;nbsp;해주는&amp;nbsp;것이&amp;nbsp;좋을&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;만약&amp;nbsp;이&amp;nbsp;글을&amp;nbsp;보는&amp;nbsp;독자가&amp;nbsp;대학생이라면&amp;nbsp;당신은&amp;nbsp;행운아다.&amp;nbsp;전공자라면&amp;nbsp;대체로&amp;nbsp;졸업을&amp;nbsp;위해서&amp;nbsp;필수로&amp;nbsp;지정된&amp;nbsp;전공과목이&amp;nbsp;있을&amp;nbsp;것이니&amp;nbsp;해당&amp;nbsp;수업을&amp;nbsp;열심히&amp;nbsp;따라가면&amp;nbsp;될&amp;nbsp;것이다.&amp;nbsp;전공자가&amp;nbsp;아니라면&amp;nbsp;복수전공이나&amp;nbsp;부전공을&amp;nbsp;하면&amp;nbsp;좋겠으나,&amp;nbsp;여의치&amp;nbsp;않다면&amp;nbsp;수강이라도&amp;nbsp;하는&amp;nbsp;것&amp;nbsp;(학교마다&amp;nbsp;명칭은&amp;nbsp;다를&amp;nbsp;것&amp;nbsp;같은데&amp;nbsp;보통&amp;nbsp;선택과목&amp;nbsp;정도로&amp;nbsp;표현하는&amp;nbsp;것&amp;nbsp;같다)을&amp;nbsp;추천한다.&amp;nbsp;요즘&amp;nbsp;같은&amp;nbsp;정보화&amp;nbsp;시대에&amp;nbsp;유튜브나&amp;nbsp;인터넷에&amp;nbsp;찾아보면&amp;nbsp;공개된&amp;nbsp;강의도&amp;nbsp;많은데&amp;nbsp;꼭&amp;nbsp;수업을&amp;nbsp;들으라고&amp;nbsp;하는지&amp;nbsp;의아한&amp;nbsp;사람도&amp;nbsp;있을&amp;nbsp;것이다.&amp;nbsp;나는&amp;nbsp;개인적으로&amp;nbsp;어렵게&amp;nbsp;공부해야&amp;nbsp;그것이&amp;nbsp;정말&amp;nbsp;머리에&amp;nbsp;남는다고&amp;nbsp;생각한다.&amp;nbsp;따라서&amp;nbsp;수업을&amp;nbsp;듣고&amp;nbsp;과제를&amp;nbsp;직접&amp;nbsp;풀거나&amp;nbsp;프로그램하고&amp;nbsp;시험을&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;약간은&amp;nbsp;고전적&amp;nbsp;형태인&amp;nbsp;수업을&amp;nbsp;직접&amp;nbsp;듣는&amp;nbsp;것을&amp;nbsp;이런&amp;nbsp;이유로&amp;nbsp;추천한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약 이미 졸업했다면 어떻게 하면 좋을까? 이때는 어쩔 수 없지만 외부에 공개된 강의나 아니면 사놓고 책장에 꽂아둔 (...) 전공책들을 보는 등의 방법을 활용해야 할 것 같다. 아래는 내가 추천하는 몇 가지 자료들이나, 아마도 내가 모르는 좋은 책이나 강의가 많이 있을 것이니 검색을 통해서 찾아보고 비교해 보면 좋겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모두를 위한 컴퓨터과학 (CS50)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.boostcourse.org/cs112&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.boostcourse.org/cs112&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cs50.harvard.edu/x/2025/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://cs50.harvard.edu/x/2025/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://csapp.cs.cmu.edu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CSAPP: Computer Systems: A Programmer's Perspective&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://missing-semester-kr.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The Missing Semester&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.deeplearning.ai/courses/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Deeplearning.ai&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Mathematics for Machine Learning and Data Science&lt;/li&gt;
&lt;li&gt;Data Engineering&lt;/li&gt;
&lt;li&gt;Machine Learning / Deep Learning Specialization&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 영어&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;구글&amp;nbsp;번역기나&amp;nbsp;ChatGPT를&amp;nbsp;위시한&amp;nbsp;생성형&amp;nbsp;AI들이&amp;nbsp;이제는&amp;nbsp;너무나&amp;nbsp;잘&amp;nbsp;번역해&amp;nbsp;주고&amp;nbsp;있는데,&amp;nbsp;영어가&amp;nbsp;중요하다고&amp;nbsp;얘기하니&amp;nbsp;고개를&amp;nbsp;갸우뚱하는&amp;nbsp;사람도&amp;nbsp;분명히&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;그런데도&amp;nbsp;나는&amp;nbsp;전공만큼이나&amp;nbsp;영어가&amp;nbsp;중요하다고&amp;nbsp;생각한다.&amp;nbsp;위에서&amp;nbsp;추천한&amp;nbsp;강의나&amp;nbsp;책들이&amp;nbsp;대표적인&amp;nbsp;장점일&amp;nbsp;텐데,&amp;nbsp;좋은&amp;nbsp;책과&amp;nbsp;강의는&amp;nbsp;영어로&amp;nbsp;먼저&amp;nbsp;공개되는&amp;nbsp;경우가&amp;nbsp;대부분이다&amp;nbsp;(좋은&amp;nbsp;한국어책과&amp;nbsp;강의가&amp;nbsp;없다는&amp;nbsp;얘기가&amp;nbsp;아니다.&amp;nbsp;다만&amp;nbsp;절대적인&amp;nbsp;자료의&amp;nbsp;수가&amp;nbsp;아주&amp;nbsp;큰&amp;nbsp;차이가&amp;nbsp;난다는&amp;nbsp;점을&amp;nbsp;얘기하고&amp;nbsp;싶음).&amp;nbsp;운이&amp;nbsp;좋다면&amp;nbsp;CS50이나&amp;nbsp;The&amp;nbsp;Missing&amp;nbsp;Semester처럼&amp;nbsp;번역이&amp;nbsp;제공되겠지만,&amp;nbsp;그렇지&amp;nbsp;않은&amp;nbsp;경우도&amp;nbsp;상당히&amp;nbsp;많이&amp;nbsp;존재한다.&amp;nbsp;이런&amp;nbsp;강의나&amp;nbsp;책이&amp;nbsp;아니라도&amp;nbsp;해외&amp;nbsp;기술&amp;nbsp;블로그나&amp;nbsp;선행&amp;nbsp;연구&amp;nbsp;논문&amp;nbsp;등은&amp;nbsp;결국&amp;nbsp;영어를&amp;nbsp;피할&amp;nbsp;수가&amp;nbsp;없다.&amp;nbsp;번역기나&amp;nbsp;생성&amp;nbsp;AI를&amp;nbsp;쓰면&amp;nbsp;되지&amp;nbsp;않냐고&amp;nbsp;물어본다면,&amp;nbsp;회사&amp;nbsp;장비에서는&amp;nbsp;허가&amp;nbsp;되지&amp;nbsp;않은&amp;nbsp;번역&amp;nbsp;서비스&amp;nbsp;(Google&amp;nbsp;Translate)나&amp;nbsp;생성&amp;nbsp;AI를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;경우도&amp;nbsp;빈번하게&amp;nbsp;존재한다.&amp;nbsp;설령&amp;nbsp;번역기를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있더라도&amp;nbsp;기술적인&amp;nbsp;내용의&amp;nbsp;경우&amp;nbsp;사용하는&amp;nbsp;어휘나&amp;nbsp;표현이&amp;nbsp;일반적인&amp;nbsp;구어/문어와&amp;nbsp;다르므로&amp;nbsp;오역이&amp;nbsp;발생할&amp;nbsp;가능성도&amp;nbsp;꽤&amp;nbsp;높다.&amp;nbsp;따라서&amp;nbsp;적어도&amp;nbsp;읽더라도&amp;nbsp;불편함&amp;nbsp;없도록&amp;nbsp;시간을&amp;nbsp;내서&amp;nbsp;공부하면&amp;nbsp;반드시&amp;nbsp;도움이&amp;nbsp;된다고&amp;nbsp;본다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약에 영어 읽기에 더해 말하고 듣기까지 수월하다면 더 좋을까? 이 경우 지원할 수 있는 회사의 범위가 외국계 회사로 확장되기 때문에 더 좋다고 할 수 있다. 반드시 그런 것은 아니지만 주위 사례나 &lt;a href=&quot;https://www.levels.fyi/t/software-engineer/locations/seoul-capital-area&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;levels.fyi&lt;/a&gt;에서 제공하는 정보 등을 종합했을 때 전체적인 보수 (Total Compensation)의 상방이 외국계 회사가 한국 회사에 비해 열려있으며, 회사 내에서 자리를 잘 잡는다면 해외 Relocation 기회도 얻을 수 있다는 장점이 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KozBI/btsMNrh1jT3/zQcDhJ8Nr5Oyj6YGwsyKI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KozBI/btsMNrh1jT3/zQcDhJ8Nr5Oyj6YGwsyKI1/img.png&quot; data-alt=&quot;대표적인 외국계 서비스 회사 Coupang의 TC&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KozBI/btsMNrh1jT3/zQcDhJ8Nr5Oyj6YGwsyKI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKozBI%2FbtsMNrh1jT3%2FzQcDhJ8Nr5Oyj6YGwsyKI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1157&quot; height=&quot;339&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대표적인 외국계 서비스 회사 Coupang의 TC&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그러면&amp;nbsp;어떻게&amp;nbsp;영어&amp;nbsp;공부를&amp;nbsp;하면&amp;nbsp;좋을까?&amp;nbsp;이것&amp;nbsp;역시&amp;nbsp;정답은&amp;nbsp;없고&amp;nbsp;본인의&amp;nbsp;성향에&amp;nbsp;따라&amp;nbsp;다를&amp;nbsp;것이다.&amp;nbsp;해외에서&amp;nbsp;영어를&amp;nbsp;쓸&amp;nbsp;수밖에&amp;nbsp;없는&amp;nbsp;환경&amp;nbsp;(유학,&amp;nbsp;워킹&amp;nbsp;홀리데이&amp;nbsp;등)에&amp;nbsp;노출된다면&amp;nbsp;가장&amp;nbsp;좋겠지만,&amp;nbsp;현실적으로&amp;nbsp;모든&amp;nbsp;사람이&amp;nbsp;그렇게&amp;nbsp;하기는&amp;nbsp;어려울&amp;nbsp;것이다.&amp;nbsp;글&amp;nbsp;작성자&amp;nbsp;역시&amp;nbsp;해외&amp;nbsp;체류&amp;nbsp;없이&amp;nbsp;영어&amp;nbsp;공부를&amp;nbsp;했기&amp;nbsp;때문에&amp;nbsp;많은&amp;nbsp;도움을&amp;nbsp;받는&amp;nbsp;자료들을&amp;nbsp;남겨본다.&amp;nbsp;아마도&amp;nbsp;글을&amp;nbsp;쓰는&amp;nbsp;시점에서는&amp;nbsp;좋은&amp;nbsp;자료들이&amp;nbsp;더&amp;nbsp;많이&amp;nbsp;있을&amp;nbsp;것이다.&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;것은&amp;nbsp;어떤&amp;nbsp;강의,&amp;nbsp;책을&amp;nbsp;보는&amp;nbsp;것보다&amp;nbsp;그것을&amp;nbsp;끝까지&amp;nbsp;꾸준히&amp;nbsp;유지하는&amp;nbsp;것임을&amp;nbsp;강조한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영어 읽기를 위한 구문과 문법 공부를 위한 교재들
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/61331399&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;박상효의 영문법 콘서트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/4250858&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;실용 영문법 백과사전 2nd Edition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;영어 말하기/듣기를 위한 강의들
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/@LVACDMY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라이브 아카데미&lt;/a&gt; / &lt;a href=&quot;https://www.youtube.com/@LA-TDLR&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;라이브 아카데미 토들러&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/@ILBANGBANG&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;일빵빵 영어회화&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 체력&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;프로그램을&amp;nbsp;작성하고&amp;nbsp;디버깅하고&amp;nbsp;고치는&amp;nbsp;작업은&amp;nbsp;상당히&amp;nbsp;고된&amp;nbsp;작업임은&amp;nbsp;자명하다.&amp;nbsp;대개&amp;nbsp;주&amp;nbsp;5일,&amp;nbsp;하루&amp;nbsp;8시간&amp;nbsp;근무를&amp;nbsp;기본으로&amp;nbsp;하며&amp;nbsp;때에&amp;nbsp;따라&amp;nbsp;야근까지&amp;nbsp;있는&amp;nbsp;소프트웨어&amp;nbsp;엔지니어들은&amp;nbsp;앉아&amp;nbsp;있는&amp;nbsp;시간이&amp;nbsp;대체로&amp;nbsp;길&amp;nbsp;것이다.&amp;nbsp;20대&amp;nbsp;때는&amp;nbsp;크게&amp;nbsp;문제가&amp;nbsp;없었던&amp;nbsp;체력이&amp;nbsp;나이가&amp;nbsp;들어가면서&amp;nbsp;결국엔&amp;nbsp;업무&amp;nbsp;생산성에&amp;nbsp;영향을&amp;nbsp;미치는&amp;nbsp;경험은&amp;nbsp;나만&amp;nbsp;겪은&amp;nbsp;것이&amp;nbsp;아닐&amp;nbsp;것으로&amp;nbsp;생각한다.&amp;nbsp;체력이&amp;nbsp;부족하면&amp;nbsp;그것이&amp;nbsp;결국&amp;nbsp;정신적인&amp;nbsp;부분에도&amp;nbsp;영향을&amp;nbsp;주고,&amp;nbsp;사소한&amp;nbsp;것에도&amp;nbsp;감정&amp;nbsp;제어가&amp;nbsp;어려워지는&amp;nbsp;악순환으로까지&amp;nbsp;이어질&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;733&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yWvbT/btsMNiyLdIR/pKGtu64JxiwHXnST8JUvE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yWvbT/btsMNiyLdIR/pKGtu64JxiwHXnST8JUvE0/img.png&quot; data-alt=&quot;https://otr.co.kr/academy/?vid=13262&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yWvbT/btsMNiyLdIR/pKGtu64JxiwHXnST8JUvE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyWvbT%2FbtsMNiyLdIR%2FpKGtu64JxiwHXnST8JUvE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;616&quot; height=&quot;618&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;733&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://otr.co.kr/academy/?vid=13262&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면&amp;nbsp;어떻게&amp;nbsp;하면&amp;nbsp;좋을까?&amp;nbsp;나는&amp;nbsp;개인적으로&amp;nbsp;어떤&amp;nbsp;운동이든&amp;nbsp;좋다고&amp;nbsp;생각하고&amp;nbsp;심지어&amp;nbsp;하루하루가&amp;nbsp;아니라&amp;nbsp;주에&amp;nbsp;2~3회&amp;nbsp;정도만&amp;nbsp;해도&amp;nbsp;아예&amp;nbsp;하지&amp;nbsp;않는&amp;nbsp;것보다는&amp;nbsp;무조건&amp;nbsp;좋다고&amp;nbsp;장담한다.&amp;nbsp;아마도&amp;nbsp;흔하게&amp;nbsp;접할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;운동은&amp;nbsp;아래와&amp;nbsp;같은&amp;nbsp;것들이&amp;nbsp;있을&amp;nbsp;것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아예&amp;nbsp;운동&amp;nbsp;경험이&amp;nbsp;없고&amp;nbsp;가볍게&amp;nbsp;시작해&amp;nbsp;보고&amp;nbsp;싶다면&amp;nbsp;런데이&amp;nbsp;앱을&amp;nbsp;통해서&amp;nbsp;걷기부터&amp;nbsp;시작하는&amp;nbsp;것을&amp;nbsp;추천한다.&amp;nbsp;단계별로&amp;nbsp;시간을&amp;nbsp;조금씩&amp;nbsp;늘려가며&amp;nbsp;걷기&amp;nbsp;훈련,&amp;nbsp;달리기&amp;nbsp;훈련&amp;nbsp;등이&amp;nbsp;제공되므로&amp;nbsp;본인의&amp;nbsp;수준에&amp;nbsp;맞게&amp;nbsp;체계적으로&amp;nbsp;시작해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDq9EH/btsMLwrP1bU/gL7J3afmVjjG547AjpF1m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDq9EH/btsMLwrP1bU/gL7J3afmVjjG547AjpF1m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDq9EH/btsMLwrP1bU/gL7J3afmVjjG547AjpF1m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDq9EH%2FbtsMLwrP1bU%2FgL7J3afmVjjG547AjpF1m0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;415&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마치며&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 내가 생각하는 중요한 소프트웨어 엔지니어를 위한 스킬셋 세 가지에 대해서 그렇게 생각하는 이유와 몇 가지 자료들을 제공하면서 마친다. 생각보다 내용이 길어져서 다음 포스트에서는 독서, 채용 과정 준비, 개인 재무 그리고 최신 기술 트렌드를 따라가는 방법에 대해서 정리하려고 한다.&lt;/p&gt;</description>
      <category>개발 이야기</category>
      <category>소프트웨어 엔지니어</category>
      <category>주니어 엔지니어</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/192</guid>
      <comments>https://iostream.tistory.com/192#entry192comment</comments>
      <pubDate>Sun, 16 Mar 2025 20:26:17 +0900</pubDate>
    </item>
    <item>
      <title>코드트리 (Codetree) 두 달 이용 후기</title>
      <link>https://iostream.tistory.com/191</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://iostream.tistory.com/188&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코드트리 (Codetree) 한 달간 사용 후기&lt;/a&gt;에서 첫&amp;nbsp;한&amp;nbsp;달&amp;nbsp;이용&amp;nbsp;후기를&amp;nbsp;남긴지가&amp;nbsp;엊그제&amp;nbsp;같은데&amp;nbsp;벌써&amp;nbsp;두&amp;nbsp;달이&amp;nbsp;지났다.&amp;nbsp;추가&amp;nbsp;한&amp;nbsp;달은&amp;nbsp;기존&amp;nbsp;트레일보다는&amp;nbsp;조금&amp;nbsp;난도가&amp;nbsp;있는&amp;nbsp;내용들을&amp;nbsp;주로&amp;nbsp;살펴보고&amp;nbsp;문제&amp;nbsp;풀이를&amp;nbsp;했었는데,&amp;nbsp;특히&amp;nbsp;처음&amp;nbsp;코딩테스트를&amp;nbsp;접하는&amp;nbsp;사람들이&amp;nbsp;힘들어하는&amp;nbsp;부분인&amp;nbsp;재귀함수&amp;nbsp;관련&amp;nbsp;내용이&amp;nbsp;그림으로&amp;nbsp;자세히&amp;nbsp;설명하고,&amp;nbsp;숙달될&amp;nbsp;때까지&amp;nbsp;유사한&amp;nbsp;유형을&amp;nbsp;제공해&amp;nbsp;주는&amp;nbsp;부분이&amp;nbsp;좋았다.&amp;nbsp;특히&amp;nbsp;시중의&amp;nbsp;코딩테스트&amp;nbsp;책들이&amp;nbsp;배열이나&amp;nbsp;트리와&amp;nbsp;같은&amp;nbsp;자료구조를&amp;nbsp;먼저&amp;nbsp;얘기하고&amp;nbsp;트리나&amp;nbsp;필요한&amp;nbsp;상황이&amp;nbsp;있을&amp;nbsp;때&amp;nbsp;재귀&amp;nbsp;호출&amp;nbsp;코드를&amp;nbsp;바로&amp;nbsp;설명하는&amp;nbsp;경우가&amp;nbsp;많은데,&amp;nbsp;코드&amp;nbsp;트리의&amp;nbsp;경우&amp;nbsp;앞부분에서&amp;nbsp;함수&amp;nbsp;호출과&amp;nbsp;재귀&amp;nbsp;호출에&amp;nbsp;관한&amp;nbsp;내용을&amp;nbsp;먼저&amp;nbsp;서술하면서&amp;nbsp;자연스럽게&amp;nbsp;완전&amp;nbsp;탐색까지&amp;nbsp;이어지는&amp;nbsp;커리큘럼이&amp;nbsp;신경을&amp;nbsp;많이&amp;nbsp;썼다는&amp;nbsp;생각이&amp;nbsp;들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그&amp;nbsp;외에&amp;nbsp;첫&amp;nbsp;한&amp;nbsp;달&amp;nbsp;후기에서&amp;nbsp;남겼던&amp;nbsp;아쉬운&amp;nbsp;점들&amp;nbsp;역시&amp;nbsp;스타트업답게&amp;nbsp;(?)&amp;nbsp;빠르게&amp;nbsp;개선&amp;nbsp;및&amp;nbsp;의견&amp;nbsp;수렴이&amp;nbsp;되는&amp;nbsp;모습이었는데,&amp;nbsp;특히&amp;nbsp;충분한&amp;nbsp;사용&amp;nbsp;전에&amp;nbsp;요금&amp;nbsp;결제에&amp;nbsp;부담을&amp;nbsp;느낄&amp;nbsp;수&amp;nbsp;있다&amp;nbsp;보니&amp;nbsp;무료로&amp;nbsp;제공하는&amp;nbsp;트레일이&amp;nbsp;추가되었고,&amp;nbsp;포인트를&amp;nbsp;쌓아서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;곳이&amp;nbsp;없다는&amp;nbsp;피드백도&amp;nbsp;사이트&amp;nbsp;내에서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;일종의&amp;nbsp;재화로&amp;nbsp;제공하는&amp;nbsp;것으로&amp;nbsp;보인다.&amp;nbsp;자잘한&amp;nbsp;UI/UX나&amp;nbsp;제출&amp;nbsp;시&amp;nbsp;채점&amp;nbsp;속도&amp;nbsp;같은&amp;nbsp;부분도&amp;nbsp;내가&amp;nbsp;생각했을&amp;nbsp;때는&amp;nbsp;꽤&amp;nbsp;많은&amp;nbsp;개선이&amp;nbsp;있었던&amp;nbsp;것으로&amp;nbsp;보인다.&amp;nbsp;쉬운&amp;nbsp;트레일부터&amp;nbsp;많은&amp;nbsp;문제는&amp;nbsp;아니지만&amp;nbsp;난이도&amp;nbsp;있는&amp;nbsp;트레일까지&amp;nbsp;풀어본&amp;nbsp;경험으로&amp;nbsp;봤을&amp;nbsp;때&amp;nbsp;코드&amp;nbsp;트리는&amp;nbsp;사용자들이&amp;nbsp;충분히&amp;nbsp;믿고&amp;nbsp;사용해&amp;nbsp;볼만한&amp;nbsp;서비스라고&amp;nbsp;생각된다.&amp;nbsp;앞으로도&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;개선과&amp;nbsp;좋은&amp;nbsp;사용자&amp;nbsp;경험을&amp;nbsp;제공했으면&amp;nbsp;한다는&amp;nbsp;말로&amp;nbsp;두&amp;nbsp;달&amp;nbsp;이용&amp;nbsp;후기를&amp;nbsp;마친다.&lt;/p&gt;</description>
      <category>개발 이야기</category>
      <category>codeTree</category>
      <category>코드트리</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/191</guid>
      <comments>https://iostream.tistory.com/191#entry191comment</comments>
      <pubDate>Sun, 9 Mar 2025 19:24:12 +0900</pubDate>
    </item>
    <item>
      <title>Cache를 활용해서 똑똑하게 중복 로그를 방지해보자!</title>
      <link>https://iostream.tistory.com/190</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;배경&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;최근&amp;nbsp;Quantization&amp;nbsp;Simulation&amp;nbsp;내용이&amp;nbsp;포함된&amp;nbsp;Machine&amp;nbsp;Learning&amp;nbsp;Pipeline&amp;nbsp;스크립트를&amp;nbsp;작성할&amp;nbsp;일이&amp;nbsp;있었다.&amp;nbsp;비교적&amp;nbsp;최근에&amp;nbsp;AI&amp;nbsp;조직으로&amp;nbsp;합류하게&amp;nbsp;된&amp;nbsp;엔지니어의&amp;nbsp;교육용이자&amp;nbsp;Hands-on을&amp;nbsp;위한&amp;nbsp;스크립트였는데,&amp;nbsp;각&amp;nbsp;블록이&amp;nbsp;어떤&amp;nbsp;역할을&amp;nbsp;하는지&amp;nbsp;코드&amp;nbsp;레벨로&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;로그를&amp;nbsp;심는&amp;nbsp;부분이&amp;nbsp;있었다.&amp;nbsp;회사&amp;nbsp;내의&amp;nbsp;업무라&amp;nbsp;정확한&amp;nbsp;내용을&amp;nbsp;얘기하기는&amp;nbsp;좀&amp;nbsp;어렵지만,&amp;nbsp;다루는&amp;nbsp;모델의&amp;nbsp;크기가&amp;nbsp;크기&amp;nbsp;때문에&amp;nbsp;모델에&amp;nbsp;대한&amp;nbsp;특정&amp;nbsp;정보를&amp;nbsp;로깅&amp;nbsp;해서&amp;nbsp;단순히&amp;nbsp;남길&amp;nbsp;때&amp;nbsp;너무&amp;nbsp;많은&amp;nbsp;로그가&amp;nbsp;생성되고&amp;nbsp;그중&amp;nbsp;많은&amp;nbsp;부분이&amp;nbsp;중복되는&amp;nbsp;정보여서&amp;nbsp;여간&amp;nbsp;신경&amp;nbsp;쓰이는&amp;nbsp;것이&amp;nbsp;아니었다.&amp;nbsp;사실&amp;nbsp;교육용&amp;nbsp;스크립트고,&amp;nbsp;읽는&amp;nbsp;사람이&amp;nbsp;약간의&amp;nbsp;귀찮음을&amp;nbsp;감수하면&amp;nbsp;큰&amp;nbsp;문제는&amp;nbsp;없었지만,&amp;nbsp;코드&amp;nbsp;리뷰&amp;nbsp;때&amp;nbsp;비슷한&amp;nbsp;질의를&amp;nbsp;다른&amp;nbsp;엔지니어들에게도&amp;nbsp;몇&amp;nbsp;번&amp;nbsp;받았고&amp;nbsp;이런&amp;nbsp;부류의&amp;nbsp;문제는&amp;nbsp;어떤&amp;nbsp;식으로&amp;nbsp;해결하는지&amp;nbsp;개인적으로&amp;nbsp;궁금하기도&amp;nbsp;하여&amp;nbsp;비슷한&amp;nbsp;상황을&amp;nbsp;모사할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;스크립트와&amp;nbsp;해결&amp;nbsp;방식을&amp;nbsp;남겨둔다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;초기 구현&lt;/h3&gt;
&lt;pre id=&quot;code_1740913009549&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import logging

import torch
from torch.nn.modules.module import register_module_forward_pre_hook
from transformers import AutoModelForCausalLM

logger = logging.getLogger(__name__)
logger.setLevel('INFO')
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)

checkpoint = 'HuggingFaceTB/SmolLM2-135M'
model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16)


def module_type_hook(module, _) -&amp;gt; None:
    logger.info(f'Model contains {type(module)} module')


register_module_forward_pre_hook(module_type_hook)

dummy_input = torch.zeros(1, 64, dtype=torch.long)
with torch.inference_mode():
    model(dummy_input)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;유사한&amp;nbsp;상황을&amp;nbsp;모사할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;초기&amp;nbsp;스크립트를&amp;nbsp;우선&amp;nbsp;작성해&amp;nbsp;봤다.&amp;nbsp;우선&amp;nbsp;Logger를&amp;nbsp;하나&amp;nbsp;생성&amp;nbsp;후&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;설정&amp;nbsp;(Level,&amp;nbsp;Handler&amp;nbsp;등)을&amp;nbsp;하고&amp;nbsp;HuggingFace에서&amp;nbsp;제공하는&amp;nbsp;작은&amp;nbsp;크기의&amp;nbsp;모델&amp;nbsp;중&amp;nbsp;하나인&amp;nbsp;SmolLM2-135M를&amp;nbsp;가져온다.&amp;nbsp;해당&amp;nbsp;스크립트의&amp;nbsp;목적은&amp;nbsp;모델을&amp;nbsp;구성하고&amp;nbsp;있는&amp;nbsp;PyTorch&amp;nbsp;module의&amp;nbsp;종류를&amp;nbsp;파악하기&amp;nbsp;위해서&amp;nbsp;hook&amp;nbsp;함수를&amp;nbsp;하나&amp;nbsp;만들고,&amp;nbsp;최종적으로는&amp;nbsp;dummy_input을&amp;nbsp;forward&amp;nbsp;함수에&amp;nbsp;태워서&amp;nbsp;로그를&amp;nbsp;출력하는&amp;nbsp;것이&amp;nbsp;목적이다.&amp;nbsp;아마&amp;nbsp;대부분의&amp;nbsp;ML&amp;nbsp;Engineer에&amp;nbsp;해당&amp;nbsp;스크립트는&amp;nbsp;아주&amp;nbsp;어렵지&amp;nbsp;않을&amp;nbsp;것이지만,&amp;nbsp;혹시&amp;nbsp;Logger,&amp;nbsp;HF&amp;nbsp;transformers&amp;nbsp;패키지,&amp;nbsp;또는&amp;nbsp;PyTorch&amp;nbsp;Hook에&amp;nbsp;대해서&amp;nbsp;익숙하지&amp;nbsp;않다면&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;페이지들을&amp;nbsp;참고로&amp;nbsp;남겨둔다.&amp;nbsp;해당&amp;nbsp;페이지들을&amp;nbsp;읽은&amp;nbsp;후&amp;nbsp;위&amp;nbsp;코드를&amp;nbsp;직접&amp;nbsp;실행해&amp;nbsp;보면&amp;nbsp;의도를&amp;nbsp;더&amp;nbsp;쉽게&amp;nbsp;이해할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3.13/howto/logging.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.python.org/3.13/howto/logging.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/docs/transformers/main/en/index&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/docs/transformers/main/en/index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pytorch.org/docs/stable/nn.html#containers&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pytorch.org/docs/stable/nn.html#containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 스크립트를 실행해 보면 다음과 같은 결과를 얻을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1740913375348&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaForCausalLM'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaModel'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.sparse.Embedding'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRotaryEmbedding'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaDecoderLayer'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRMSNorm'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaSdpaAttention'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRMSNorm'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaMLP'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.activation.SiLU'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaDecoderLayer'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRMSNorm'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaSdpaAttention'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
# 이하 중략&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;작은&amp;nbsp;크기의&amp;nbsp;모델이라고는&amp;nbsp;해도&amp;nbsp;Decoder&amp;nbsp;Layer가&amp;nbsp;30개나&amp;nbsp;되다&amp;nbsp;보니&amp;nbsp;전체&amp;nbsp;로그&amp;nbsp;수가&amp;nbsp;모듈&amp;nbsp;개수만큼&amp;nbsp;기록되고,&amp;nbsp;한눈에&amp;nbsp;봐도&amp;nbsp;중복되는&amp;nbsp;로그가&amp;nbsp;많이&amp;nbsp;보인다.&amp;nbsp;만약에&amp;nbsp;더&amp;nbsp;큰&amp;nbsp;크기의&amp;nbsp;모델을&amp;nbsp;같은&amp;nbsp;스크립트에&amp;nbsp;대해서&amp;nbsp;실행하면&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;의미&amp;nbsp;없는&amp;nbsp;로그들이&amp;nbsp;많이&amp;nbsp;쌓이게&amp;nbsp;될&amp;nbsp;것은&amp;nbsp;쉽게&amp;nbsp;짐작할&amp;nbsp;수&amp;nbsp;있겠다.&amp;nbsp;즉,&amp;nbsp;우리는&amp;nbsp;의미&amp;nbsp;있는&amp;nbsp;정보&amp;nbsp;그러니까&amp;nbsp;우리가&amp;nbsp;관심&amp;nbsp;있는&amp;nbsp;정보인&amp;nbsp;모델을&amp;nbsp;구성하는&amp;nbsp;모듈&amp;nbsp;타입의&amp;nbsp;종류에&amp;nbsp;대해서만&amp;nbsp;적절하게&amp;nbsp;로그를&amp;nbsp;남길&amp;nbsp;수&amp;nbsp;있으면&amp;nbsp;좋겠다는&amp;nbsp;결론에&amp;nbsp;이르게&amp;nbsp;된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cache를 활용한 트릭&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이런&amp;nbsp;중복&amp;nbsp;로그를&amp;nbsp;남기지&amp;nbsp;않는&amp;nbsp;방법으로는&amp;nbsp;여러&amp;nbsp;구현&amp;nbsp;방식이&amp;nbsp;있겠지만,&amp;nbsp;Python에서&amp;nbsp;제공하는&amp;nbsp;@functools.cache&amp;nbsp;또는&amp;nbsp;@functools.lru_cache(None)을&amp;nbsp;활용해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;기본적으로&amp;nbsp;캐시는&amp;nbsp;비싼&amp;nbsp;연산을&amp;nbsp;매번&amp;nbsp;계산하지&amp;nbsp;않기&amp;nbsp;위해서,&amp;nbsp;사전에&amp;nbsp;연산에&amp;nbsp;대해서&amp;nbsp;계산한&amp;nbsp;값을&amp;nbsp;저장&amp;nbsp;후&amp;nbsp;이후에&amp;nbsp;같은&amp;nbsp;입력에&amp;nbsp;대해서는&amp;nbsp;계산&amp;nbsp;없이&amp;nbsp;캐싱해&amp;nbsp;둔&amp;nbsp;값을&amp;nbsp;반환하는&amp;nbsp;개념인데요.&amp;nbsp;중복&amp;nbsp;로깅을&amp;nbsp;방지하는&amp;nbsp;트릭에서도&amp;nbsp;&amp;nbsp;캐싱&amp;nbsp;기능을&amp;nbsp;활용해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;캐시&amp;nbsp;자체에&amp;nbsp;대한&amp;nbsp;개념은&amp;nbsp;해당&amp;nbsp;포스트의&amp;nbsp;범위를&amp;nbsp;조금&amp;nbsp;벗어나니&amp;nbsp;필요하다면&amp;nbsp;&lt;a href=&quot;https://docs.python.org/3/library/functools.html#functools.cache&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.python.org/3/library/functools.html#functools.cache&lt;/a&gt; 문서를&amp;nbsp;참고하세요.&amp;nbsp;거두절미하고&amp;nbsp;트릭을&amp;nbsp;적용한&amp;nbsp;스크립트를&amp;nbsp;보겠습니다&lt;/p&gt;
&lt;pre id=&quot;code_1740919456916&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import functools
import logging

import torch
from torch.nn.modules.module import register_module_forward_pre_hook
from transformers import AutoModelForCausalLM

logger = logging.getLogger(__name__)
logger.setLevel('INFO')
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)


@functools.lru_cache(None)
def info_once(msg):
    logger.info(msg)


checkpoint = 'HuggingFaceTB/SmolLM2-135M'
model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16)


def module_type_hook(module, _) -&amp;gt; None:
    info_once(f'Model contains {type(module)} module')


register_module_forward_pre_hook(module_type_hook)

dummy_input = torch.zeros(1, 64, dtype=torch.long)
with torch.inference_mode():
    model(dummy_input)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;info_once라는 lru_cache로 데코레이트 된 메서드를 하나 선언하고, 기존에 hook 함수에서 호출하던 logger.info를 info_once로 바꿔주는 단순한 변경입니다. 다시 말하자면 처음 맞이하는 로그 메시지에 대해서는 logger.info(msg)를 호출하게 되고, 그 이후에 동일 msg에 대해서는 이미 캐싱이 되어있으므로 logger.info(msg)를 호출하는 대신 캐싱 된 결과를 반환하는데요. 이때 logger.info(msg)의 결과는 None이기 때문에 자연스럽게 중복된 로그에 대해서는 더 이상 로그가 찍히지 않게 됩니다. 실제 실행 결과는 아래와 같습니다&lt;/p&gt;
&lt;pre id=&quot;code_1740919513334&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaForCausalLM'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaModel'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.sparse.Embedding'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRotaryEmbedding'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaDecoderLayer'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaRMSNorm'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaSdpaAttention'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.linear.Linear'&amp;gt; module
Model contains &amp;lt;class 'transformers.models.llama.modeling_llama.LlamaMLP'&amp;gt; module
Model contains &amp;lt;class 'torch.nn.modules.activation.SiLU'&amp;gt; module&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;무시무시한&amp;nbsp;(?)&amp;nbsp;LLM의&amp;nbsp;명성과&amp;nbsp;다르게&amp;nbsp;실제로&amp;nbsp;구성하고&amp;nbsp;있는&amp;nbsp;모듈의&amp;nbsp;타입은&amp;nbsp;꽤&amp;nbsp;단순하죠?&amp;nbsp;Leaf&amp;nbsp;레벨의&amp;nbsp;모듈만&amp;nbsp;고려하면&amp;nbsp;6가지&amp;nbsp;모듈로만&amp;nbsp;구성되어&amp;nbsp;있습니다.&amp;nbsp;본&amp;nbsp;포스트에서는&amp;nbsp;단순한&amp;nbsp;시나리오에&amp;nbsp;대해서&amp;nbsp;중복&amp;nbsp;로그를&amp;nbsp;방지하는&amp;nbsp;예제&amp;nbsp;코드를&amp;nbsp;다뤘는데요.&amp;nbsp;조금&amp;nbsp;변형하면&amp;nbsp;각자의&amp;nbsp;상황에&amp;nbsp;맞춰서&amp;nbsp;더&amp;nbsp;개선할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐싱의 성질을 활용하여 중복으로 남는 로그를 똑똑하게 방지할 수 있다!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;References&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/66062313&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/a/66062313&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/huggingface/transformers/blob/dcbdf7e962c4b36140cc9ee76f870016121e69e5/src/transformers/utils/logging.py#L321&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/huggingface/transformers/blob/dcbdf7e962c4b36140cc9ee76f870016121e69e5/src/transformers/utils/logging.py#L321&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발 이야기</category>
      <category>cache</category>
      <category>LRU</category>
      <category>로그</category>
      <category>로깅</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/190</guid>
      <comments>https://iostream.tistory.com/190#entry190comment</comments>
      <pubDate>Sun, 2 Mar 2025 19:13:43 +0900</pubDate>
    </item>
    <item>
      <title>양자화 (Quantization)와 반올림 (Rounding)</title>
      <link>https://iostream.tistory.com/189</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;배경&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;LLM을&amp;nbsp;비롯한&amp;nbsp;AI&amp;nbsp;Application의&amp;nbsp;배포&amp;nbsp;타겟은&amp;nbsp;Cloud&amp;nbsp;기반에서&amp;nbsp;실행되는&amp;nbsp;서버&amp;nbsp;향도&amp;nbsp;존재하지만,&amp;nbsp;여러&amp;nbsp;장점&amp;nbsp;(개인&amp;nbsp;프라이버시,&amp;nbsp;저전력/저발열&amp;nbsp;등)을&amp;nbsp;가지고&amp;nbsp;있는&amp;nbsp;On-device도&amp;nbsp;활발히&amp;nbsp;연구/개발&amp;nbsp;중인&amp;nbsp;분야입니다.&amp;nbsp;특히&amp;nbsp;상대적으로&amp;nbsp;연산의&amp;nbsp;성능이나&amp;nbsp;메모리&amp;nbsp;제약으로&amp;nbsp;인해&amp;nbsp;On-device&amp;nbsp;AI의&amp;nbsp;경우&amp;nbsp;양자화&amp;nbsp;(Quantization)을&amp;nbsp;높은&amp;nbsp;비율로&amp;nbsp;채용하게&amp;nbsp;되는데요.&amp;nbsp;양자화는&amp;nbsp;결국&amp;nbsp;정보&amp;nbsp;손실을&amp;nbsp;필연적으로&amp;nbsp;가지므로&amp;nbsp;Application의&amp;nbsp;성능&amp;nbsp;(Accuracy&amp;nbsp;등)에서&amp;nbsp;손해를&amp;nbsp;어느&amp;nbsp;정도는&amp;nbsp;감수할&amp;nbsp;수밖에&amp;nbsp;없습니다.&amp;nbsp;문제는&amp;nbsp;매번&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;양자화&amp;nbsp;실험을&amp;nbsp;한&amp;nbsp;후에&amp;nbsp;타겟&amp;nbsp;Device에&amp;nbsp;모델을&amp;nbsp;배포하고&amp;nbsp;성능을&amp;nbsp;측정하는&amp;nbsp;것이&amp;nbsp;굉장히&amp;nbsp;귀찮고&amp;nbsp;번거로운&amp;nbsp;작업일&amp;nbsp;텐데요.&amp;nbsp;따라서,&amp;nbsp;직접&amp;nbsp;하드웨어까지&amp;nbsp;배포하지&amp;nbsp;않더라도&amp;nbsp;양자화를&amp;nbsp;통해서&amp;nbsp;하드웨어에&amp;nbsp;배포했을&amp;nbsp;때의&amp;nbsp;효과를&amp;nbsp;시뮬레이션하는&amp;nbsp;도구들이&amp;nbsp;많이&amp;nbsp;존재합니다.&amp;nbsp;흔히&amp;nbsp;인기&amp;nbsp;있는&amp;nbsp;딥러닝&amp;nbsp;프레임워크인&amp;nbsp;PyTorch나&amp;nbsp;TensorFlow에서도&amp;nbsp;자체적으로&amp;nbsp;양자화&amp;nbsp;시뮬레이션을&amp;nbsp;지원하며,&amp;nbsp;특정&amp;nbsp;하드웨어&amp;nbsp;제조사&amp;nbsp;(Qualcomm&amp;nbsp;등)&amp;nbsp;역시&amp;nbsp;해당&amp;nbsp;하드웨어에&amp;nbsp;모델을&amp;nbsp;배포했을&amp;nbsp;때의&amp;nbsp;양자화&amp;nbsp;시뮬레이션을&amp;nbsp;해볼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;AIMET과&amp;nbsp;같은&amp;nbsp;도구를&amp;nbsp;오픈소스로&amp;nbsp;공개하고&amp;nbsp;있습니다.&amp;nbsp;즉,&amp;nbsp;시뮬레이터는&amp;nbsp;하드웨어의&amp;nbsp;동작을&amp;nbsp;그대로&amp;nbsp;모사할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;하는데요.&amp;nbsp;이번&amp;nbsp;글의&amp;nbsp;동기는&amp;nbsp;시뮬레이터의&amp;nbsp;결과와&amp;nbsp;실제&amp;nbsp;하드웨어에&amp;nbsp;배포했을&amp;nbsp;때의&amp;nbsp;결과가&amp;nbsp;차이가&amp;nbsp;나는지에&amp;nbsp;대해서&amp;nbsp;팀원이&amp;nbsp;조사해서&amp;nbsp;발견한&amp;nbsp;원인에&amp;nbsp;대해&amp;nbsp;이야기해&amp;nbsp;보려고&amp;nbsp;합니다.&amp;nbsp;이런&amp;nbsp;차이가&amp;nbsp;발생하는&amp;nbsp;데는&amp;nbsp;다양한&amp;nbsp;이유가&amp;nbsp;있지만,&amp;nbsp;그중&amp;nbsp;하나였던&amp;nbsp;반올림&amp;nbsp;방식의&amp;nbsp;차이가&amp;nbsp;문제였는데요.&amp;nbsp;반올림&amp;nbsp;방식에&amp;nbsp;관해서&amp;nbsp;얘기하기&amp;nbsp;전에&amp;nbsp;양자화&amp;nbsp;(Quantization)에&amp;nbsp;대해서&amp;nbsp;먼저&amp;nbsp;간략하게&amp;nbsp;설명하는&amp;nbsp;것이&amp;nbsp;이해에&amp;nbsp;도움이&amp;nbsp;될&amp;nbsp;것&amp;nbsp;같습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;양자화 (Quantization) 개념&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;양자화라는&amp;nbsp;개념은&amp;nbsp;사실&amp;nbsp;머신러닝&amp;nbsp;외에도&amp;nbsp;디지털&amp;nbsp;신호처리&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;분야에서&amp;nbsp;사용되고&amp;nbsp;있었는데요.&amp;nbsp;간단하게&amp;nbsp;얘기하면&amp;nbsp;아래&amp;nbsp;그림과&amp;nbsp;같이&amp;nbsp;연속적인&amp;nbsp;값은&amp;nbsp;유한한&amp;nbsp;이산값들로&amp;nbsp;근사하는&amp;nbsp;과정이라고&amp;nbsp;얘기할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjr1jW/btsMjFbNfw6/nPIHpLPVmmooFKCnKfYJ40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjr1jW/btsMjFbNfw6/nPIHpLPVmmooFKCnKfYJ40/img.png&quot; data-alt=&quot;Quantization&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjr1jW/btsMjFbNfw6/nPIHpLPVmmooFKCnKfYJ40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjr1jW%2FbtsMjFbNfw6%2FnPIHpLPVmmooFKCnKfYJ40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;717&quot; height=&quot;369&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Quantization&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;일반적인&amp;nbsp;머신러닝&amp;nbsp;모델들은&amp;nbsp;FP32/FP16&amp;nbsp;부동소수점&amp;nbsp;데이터&amp;nbsp;타입을&amp;nbsp;하고&amp;nbsp;있고,&amp;nbsp;이런&amp;nbsp;연속적인&amp;nbsp;값을&amp;nbsp;INT8/INT4와&amp;nbsp;같이&amp;nbsp;이산값으로&amp;nbsp;변환하여&amp;nbsp;에너지&amp;nbsp;소모&amp;nbsp;(사람도&amp;nbsp;정수&amp;nbsp;덧셈/곱셈이&amp;nbsp;실수&amp;nbsp;덧셈/곱셈보다&amp;nbsp;쉽죠?),&amp;nbsp;메모리&amp;nbsp;사용량&amp;nbsp;(FP32&amp;nbsp;-&amp;gt;&amp;nbsp;INT4,&amp;nbsp;8배&amp;nbsp;이득)&amp;nbsp;등&amp;nbsp;스마트폰이나&amp;nbsp;Embedded&amp;nbsp;장비처럼&amp;nbsp;자원이&amp;nbsp;제약된&amp;nbsp;환경에서&amp;nbsp;애플리케이션을&amp;nbsp;잘&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;도와줄&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;됩니다.&amp;nbsp;그렇다면&amp;nbsp;어떻게&amp;nbsp;실수형&amp;nbsp;연속변수를&amp;nbsp;정수형&amp;nbsp;연속변수로&amp;nbsp;변환하는지를&amp;nbsp;살펴보겠습니다.&amp;nbsp;사실&amp;nbsp;변환하는&amp;nbsp;수식은&amp;nbsp;그렇게&amp;nbsp;어렵지&amp;nbsp;않은데요.&amp;nbsp;기본적으로는&amp;nbsp;아래와&amp;nbsp;같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTuSd6%2FbtsMj9J4d07%2Fctoeua9uX6iTb6R0kaLDf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;367&quot; height=&quot;58&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;우선 변환할 이산변수의 bitwidth를 결정하고 (e.g., INT4라면 b=4), 양자화 파라미터인 scale과 zero point를 계산하면 연속 변수를 이산 변수로 변환할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLByIu/btsMkybPKqn/IIVOetkuC4eIgJCc6xXTTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLByIu/btsMkybPKqn/IIVOetkuC4eIgJCc6xXTTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLByIu/btsMkybPKqn/IIVOetkuC4eIgJCc6xXTTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLByIu%2FbtsMkybPKqn%2FIIVOetkuC4eIgJCc6xXTTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;252&quot; height=&quot;105&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Scale은 위와 같은 식으로 구할 수 있고, 예를 들어 현재 데이터의 분포가 [-100, 100] 사이의 값이고 INT4로 변환한다면 Scale 값은 (100 - (-100)) / (15 - 0) = 13.33과 같이 계산할 수 있습니다. Zero point 역시 아래처럼 구할 수 있는데요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kMizZ/btsMkaa9VcL/UdmtBwFGCgvBRreeqyrkik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kMizZ/btsMkaa9VcL/UdmtBwFGCgvBRreeqyrkik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kMizZ/btsMkaa9VcL/UdmtBwFGCgvBRreeqyrkik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkMizZ%2FbtsMkaa9VcL%2FUdmtBwFGCgvBRreeqyrkik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;434&quot; height=&quot;401&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 과정을 통해서 Scale과 Zero point를 알고 있다면 이제 X라는 데이터에 대해서 Scale을 나눠준 후 반올림 연산을 하고 Zero point를 더한 후 최종적으로는 우리가 표현할 수 있는 범위 [0, 2^b - 1] 사이로 clamp를 하는 것이 전부입니다. 기본적인 양자화에 대한 수식은 이렇고, 오차를 최소화하기 위해서 단순히 min/max가 아닌 방식을 사용하거나 분포에 따라 (특히 weight 등) 연속 변수 0을 이산 변수 0으로 대응하는 symmetric quantization 같은 방식들이 있으나 해당 내용은 이번 포스트에서 다루고자 하는 내용에서는 조금 벗어나므로 키워드만 남겨놓습니다. 설명했던 것처럼 반올림 연산들이 포함되어있는데요. 시뮬레이터 상의 결과와 하드웨어 결과가 달랐던 원인 중 하나가 나중에 확인해보니 반올림 방식의 차이때문이었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반올림 (Rounding) 방식&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;반올림 방식은 한 두개가 아니라 너무 다양하지만, 이번 포스트에서는 크게 2가지 Rounding half to even과 Rounding half away from zero 2가지 경우에 대해서만 얘기하려고 합니다. 전자는 Python에서의 기본 Rounding 방식이며, 후자는 C에서의 Rounding 방식인데요. Rounding half to even은 5를 초과하는 값은 올림, 5 미만은 버림하며 마지막으로 5일 경우 앞자리 숫자가 짝수면 버리고 홀수면 올림하여 짝수로 맞춰줍니다. 이 방식은 통계적으로 오차가 적은 것으로 알려져있기 때문에 자연과학이나 공학에서 널리 쓰이는 방식이며 IEEE 754의 부동소수점 연산의 반올림 표준이라고 합니다. 반대로 Rounding half away from zero는 우리가 일반적으로 알고 있는 반올림 연산이라고 생각할 수 있습니다. 0에서 멀어지는 방향으로 반올림하므로 2.5는 3으로 -2.5는 -3으로 반올림하는 것이죠. 또한 구현 역시 상대적으로 더 간단한 편입니다. 파이썬에서는 아래와 같이 해당 반올림 방식을 모사해볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739702636400&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def c_round(x):
    return int(x + (0.5 if x &amp;gt;= 0 else -0.5))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-3.5부터 3.5사이의 값을 각각의 방식으로 반올림 했을 때 결과는 아래와 같습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xKyoi/btsMkKbZULo/yZ8BqswlP4Np3qVVjLlYBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xKyoi/btsMkKbZULo/yZ8BqswlP4Np3qVVjLlYBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xKyoi/btsMkKbZULo/yZ8BqswlP4Np3qVVjLlYBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxKyoi%2FbtsMkKbZULo%2FyZ8BqswlP4Np3qVVjLlYBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;746&quot; height=&quot;308&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 눈에 봐도 차이가 보이죠? 다시 양자화 수식을 떠올려볼까요?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTuSd6/btsMj9J4d07/ctoeua9uX6iTb6R0kaLDf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTuSd6%2FbtsMj9J4d07%2Fctoeua9uX6iTb6R0kaLDf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;367&quot; height=&quot;58&quot; data-origin-width=&quot;367&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;작은&amp;nbsp;bitwidth일&amp;nbsp;수록&amp;nbsp;rounding&amp;nbsp;방식에&amp;nbsp;따라&amp;nbsp;그&amp;nbsp;차이가&amp;nbsp;굉장히&amp;nbsp;벌어질&amp;nbsp;수&amp;nbsp;있음을&amp;nbsp;이제는&amp;nbsp;눈치챌&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같습니다.&amp;nbsp;어찌&amp;nbsp;보면&amp;nbsp;사소하지만,&amp;nbsp;큰&amp;nbsp;차이를&amp;nbsp;만들어내는&amp;nbsp;나비효과로도&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있겠네요!&amp;nbsp;시뮬레이터와의&amp;nbsp;결과&amp;nbsp;차이가&amp;nbsp;나는&amp;nbsp;이유는&amp;nbsp;이것&amp;nbsp;하나만은&amp;nbsp;아니었지만,&amp;nbsp;여러분들도&amp;nbsp;양자화&amp;nbsp;시뮬레이션을&amp;nbsp;한다면&amp;nbsp;타겟&amp;nbsp;장치에서의&amp;nbsp;반올림&amp;nbsp;연산이&amp;nbsp;어떤&amp;nbsp;방식으로&amp;nbsp;동작하는지&amp;nbsp;미리&amp;nbsp;확인해&amp;nbsp;보면&amp;nbsp;불필요한&amp;nbsp;차이&amp;nbsp;중&amp;nbsp;하나를&amp;nbsp;예방할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;References&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Nagel,&amp;nbsp;Markus,&amp;nbsp;et&amp;nbsp;al.&amp;nbsp;&quot;&lt;a href=&quot;https://arxiv.org/abs/2106.08295&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;A&amp;nbsp;white&amp;nbsp;paper&amp;nbsp;on&amp;nbsp;neural&amp;nbsp;network&amp;nbsp;quantization.&lt;/a&gt;&quot;&amp;nbsp;arXiv&amp;nbsp;preprint&amp;nbsp;arXiv:2106.08295&amp;nbsp;(2021).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mathsisfun.com/numbers/rounding-methods.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.mathsisfun.com/numbers/rounding-methods.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Rounding#Rounding_to_the_nearest_integer&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://en.wikipedia.org/wiki/Rounding#Rounding_to_the_nearest_integer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hanlab.mit.edu/courses/2024-fall-65940&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hanlab.mit.edu/courses/2024-fall-65940&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발 이야기/Machine learning</category>
      <category>Quantization</category>
      <category>rounding</category>
      <category>반올림</category>
      <category>사사오입</category>
      <category>양자화</category>
      <category>오사오입</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/189</guid>
      <comments>https://iostream.tistory.com/189#entry189comment</comments>
      <pubDate>Sun, 16 Feb 2025 18:03:41 +0900</pubDate>
    </item>
    <item>
      <title>코드트리 (Codetree) 한 달간 사용 후기</title>
      <link>https://iostream.tistory.com/188</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;개발자&amp;nbsp;커뮤니티인&amp;nbsp;글또와&amp;nbsp;제휴를&amp;nbsp;맺은&amp;nbsp;다양한&amp;nbsp;기업&amp;nbsp;및&amp;nbsp;서비스를&amp;nbsp;체험해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;여러&amp;nbsp;기회가&amp;nbsp;있었는데,&amp;nbsp;나는&amp;nbsp;이번에&amp;nbsp;코딩테스트&amp;nbsp;및&amp;nbsp;자료구조/알고리즘&amp;nbsp;공부&amp;nbsp;플랫폼인&amp;nbsp;코드트리&amp;nbsp;(Codetree)에&amp;nbsp;챌린지&amp;nbsp;지원을&amp;nbsp;하여&amp;nbsp;약&amp;nbsp;한&amp;nbsp;달간&amp;nbsp;사용&amp;nbsp;후&amp;nbsp;후기를&amp;nbsp;남겨본다.&amp;nbsp;소프트웨어&amp;nbsp;엔지니어로&amp;nbsp;현재&amp;nbsp;일하고&amp;nbsp;있거나&amp;nbsp;대학생의&amp;nbsp;경우라도&amp;nbsp;구직&amp;nbsp;준비&amp;nbsp;중이라면&amp;nbsp;코딩&amp;nbsp;테스트에&amp;nbsp;대해서는&amp;nbsp;어느&amp;nbsp;정도&amp;nbsp;알고&amp;nbsp;있을&amp;nbsp;것인데,&amp;nbsp;기존에&amp;nbsp;잘&amp;nbsp;알려진&amp;nbsp;플랫폼으로는&amp;nbsp;LeetCode나&amp;nbsp;프로그래머스와&amp;nbsp;같은&amp;nbsp;서비스가&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;우선&amp;nbsp;구체적인&amp;nbsp;후기를&amp;nbsp;남기기&amp;nbsp;전에&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;나의&amp;nbsp;배경&amp;nbsp;및&amp;nbsp;면책&amp;nbsp;조항을&amp;nbsp;먼저&amp;nbsp;얘기하고&amp;nbsp;시작하는&amp;nbsp;것이&amp;nbsp;좋을&amp;nbsp;것&amp;nbsp;같아서&amp;nbsp;명시하고&amp;nbsp;넘어가&amp;nbsp;본다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배경 및 면책 조항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배경:&amp;nbsp;나는&amp;nbsp;17년부터&amp;nbsp;소프트웨어&amp;nbsp;엔지니어로&amp;nbsp;근무를&amp;nbsp;시작했고,&amp;nbsp;지원자로서&amp;nbsp;코딩&amp;nbsp;테스트와&amp;nbsp;면접관&amp;nbsp;관점에서&amp;nbsp;코딩&amp;nbsp;테스트&amp;nbsp;모두에&amp;nbsp;어느&amp;nbsp;정도&amp;nbsp;익숙한&amp;nbsp;케이스이다.&amp;nbsp;다만,&amp;nbsp;신입&amp;nbsp;공채&amp;nbsp;수준의&amp;nbsp;악명&amp;nbsp;높은&amp;nbsp;알고리즘은&amp;nbsp;이제는&amp;nbsp;빠르게&amp;nbsp;풀어내진&amp;nbsp;못하며&amp;nbsp;경력직&amp;nbsp;코딩테스트&amp;nbsp;수준에서&amp;nbsp;자주&amp;nbsp;빈출&amp;nbsp;되는&amp;nbsp;주요&amp;nbsp;자료&amp;nbsp;구조&amp;nbsp;(Hash,&amp;nbsp;Stack,&amp;nbsp;Graph&amp;nbsp;등)와&amp;nbsp;알고리즘&amp;nbsp;(DFS/BFS,&amp;nbsp;정렬&amp;nbsp;등)&amp;nbsp;정도의&amp;nbsp;문제&amp;nbsp;풀이를&amp;nbsp;최근까지&amp;nbsp;주로&amp;nbsp;했었음&lt;/li&gt;
&lt;li&gt;면책&amp;nbsp;조항:&amp;nbsp;아무래도&amp;nbsp;글또&amp;nbsp;커뮤니티를&amp;nbsp;통해서&amp;nbsp;기회를&amp;nbsp;받았으므로&amp;nbsp;일종의&amp;nbsp;'광고'로&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;점을&amp;nbsp;글을&amp;nbsp;읽는&amp;nbsp;사람들이&amp;nbsp;고려했으면&amp;nbsp;함.&amp;nbsp;다만,&amp;nbsp;작성자&amp;nbsp;나름의&amp;nbsp;객관성을&amp;nbsp;유지하려고&amp;nbsp;하며&amp;nbsp;아쉬운&amp;nbsp;부분은&amp;nbsp;솔직하게&amp;nbsp;얘기할&amp;nbsp;것임&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체적인 인터페이스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 코드트리의 &lt;a href=&quot;https://www.codetree.ai/trail-info&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;메인 페이지&lt;/a&gt;로 접속하면 아래 그림처럼 크게 6개의 단계별 섹션 (코드트리 내에서는 이것을 Trail이라고 하는 것 같음)이 존재한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs2Frx/btsL4HmqJnz/O2uv9d12UMh4PwFL5NYbxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs2Frx/btsL4HmqJnz/O2uv9d12UMh4PwFL5NYbxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs2Frx/btsL4HmqJnz/O2uv9d12UMh4PwFL5NYbxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs2Frx%2FbtsL4HmqJnz%2FO2uv9d12UMh4PwFL5NYbxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1050&quot; height=&quot;777&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부문별로&amp;nbsp;다루는&amp;nbsp;내용과&amp;nbsp;난이도에&amp;nbsp;대해서&amp;nbsp;간략한&amp;nbsp;설명이&amp;nbsp;있기&amp;nbsp;때문에,&amp;nbsp;본인의&amp;nbsp;현재&amp;nbsp;수준에&amp;nbsp;대해서&amp;nbsp;잘&amp;nbsp;알고&amp;nbsp;있다면&amp;nbsp;해당&amp;nbsp;트레일로&amp;nbsp;바로&amp;nbsp;시작할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;잘&amp;nbsp;분리가&amp;nbsp;되어있는&amp;nbsp;점이&amp;nbsp;눈에&amp;nbsp;띄었다.&amp;nbsp;하지만,&amp;nbsp;객관적인&amp;nbsp;수준에&amp;nbsp;대해서&amp;nbsp;정확히&amp;nbsp;잘&amp;nbsp;모르는&amp;nbsp;경우&amp;nbsp;코드트리&amp;nbsp;내에서&amp;nbsp;실력&amp;nbsp;진단&amp;nbsp;테스트를&amp;nbsp;제공하고&amp;nbsp;있고,&amp;nbsp;이때&amp;nbsp;본인의&amp;nbsp;목표&amp;nbsp;기업도&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;것으로&amp;nbsp;보아&amp;nbsp;특정&amp;nbsp;회사에서&amp;nbsp;빈출&amp;nbsp;되는&amp;nbsp;유형에&amp;nbsp;대해서&amp;nbsp;더&amp;nbsp;효율적으로&amp;nbsp;학습할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;경로를&amp;nbsp;제공하는&amp;nbsp;것으로&amp;nbsp;보인다.&amp;nbsp;다만,&amp;nbsp;본인은&amp;nbsp;아쉽게도&amp;nbsp;해당&amp;nbsp;테스트가&amp;nbsp;약&amp;nbsp;3시간&amp;nbsp;정도&amp;nbsp;걸린다고&amp;nbsp;하여&amp;nbsp;테스트까지는&amp;nbsp;진행하지&amp;nbsp;않았고,&amp;nbsp;이번&amp;nbsp;한&amp;nbsp;달은&amp;nbsp;코드트리&amp;nbsp;플랫폼에&amp;nbsp;익숙해지기&amp;nbsp;위해서&amp;nbsp;가장&amp;nbsp;낮은&amp;nbsp;난도부터&amp;nbsp;차례대로&amp;nbsp;풀되,&amp;nbsp;너무&amp;nbsp;지루할&amp;nbsp;때는&amp;nbsp;그래도&amp;nbsp;잘&amp;nbsp;알고&amp;nbsp;있는&amp;nbsp;유형&amp;nbsp;(완전&amp;nbsp;탐색&amp;nbsp;등)에&amp;nbsp;대해서&amp;nbsp;몇&amp;nbsp;문제만&amp;nbsp;골라&amp;nbsp;풀기로&amp;nbsp;계획을&amp;nbsp;세웠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uETv3/btsL2SQdwcd/PPfuN7oLi0JK3JH6852wR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uETv3/btsL2SQdwcd/PPfuN7oLi0JK3JH6852wR1/img.png&quot; data-alt=&quot;실력 진단을 누르면 난이도 테스트를 시작할 수 있음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uETv3/btsL2SQdwcd/PPfuN7oLi0JK3JH6852wR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuETv3%2FbtsL2SQdwcd%2FPPfuN7oLi0JK3JH6852wR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;592&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실력 진단을 누르면 난이도 테스트를 시작할 수 있음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/28fLY/btsL3jGU4zk/Lmj4OBucbhHyshauxpogR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/28fLY/btsL3jGU4zk/Lmj4OBucbhHyshauxpogR0/img.png&quot; data-alt=&quot;난이도 테스트는 약 3시간이 걸린다고..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/28fLY/btsL3jGU4zk/Lmj4OBucbhHyshauxpogR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F28fLY%2FbtsL3jGU4zk%2FLmj4OBucbhHyshauxpogR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1050&quot; height=&quot;560&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;난이도 테스트는 약 3시간이 걸린다고..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제&amp;nbsp;문제&amp;nbsp;풀이를&amp;nbsp;진행하는&amp;nbsp;인터페이스는&amp;nbsp;아래와&amp;nbsp;같은데,&amp;nbsp;사실&amp;nbsp;해당&amp;nbsp;인터페이스는&amp;nbsp;기존에&amp;nbsp;LeetCode나&amp;nbsp;프로그래머스를&amp;nbsp;사용했던&amp;nbsp;사람들이라면&amp;nbsp;금방&amp;nbsp;익숙해질&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;만큼&amp;nbsp;유사하다.&amp;nbsp;좌측에는&amp;nbsp;문제에&amp;nbsp;대한&amp;nbsp;설명이&amp;nbsp;있고&amp;nbsp;우측에는&amp;nbsp;코드&amp;nbsp;작성란과&amp;nbsp;사용자가&amp;nbsp;지정해서&amp;nbsp;등록할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;테스트&amp;nbsp;케이스,&amp;nbsp;코드&amp;nbsp;실행&amp;nbsp;및&amp;nbsp;채점&amp;nbsp;메뉴들이&amp;nbsp;존재하여&amp;nbsp;직관적으로&amp;nbsp;이해할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1699&quot; data-origin-height=&quot;908&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7rVsw/btsL3scEpui/fZNskzpTtUNEeyNZQGeG3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7rVsw/btsL3scEpui/fZNskzpTtUNEeyNZQGeG3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7rVsw/btsL3scEpui/fZNskzpTtUNEeyNZQGeG3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7rVsw%2FbtsL3scEpui%2FfZNskzpTtUNEeyNZQGeG3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1699&quot; height=&quot;908&quot; data-origin-width=&quot;1699&quot; data-origin-height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실&amp;nbsp;여기까지만&amp;nbsp;보면&amp;nbsp;기존&amp;nbsp;플랫폼들과&amp;nbsp;특별히&amp;nbsp;다른&amp;nbsp;점이&amp;nbsp;있냐는&amp;nbsp;생각이&amp;nbsp;들&amp;nbsp;수&amp;nbsp;있는데,&amp;nbsp;세세한&amp;nbsp;부분에서&amp;nbsp;실제&amp;nbsp;사용자를&amp;nbsp;배려하고&amp;nbsp;동기를&amp;nbsp;유발하는&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;추가&amp;nbsp;기능들이&amp;nbsp;있어서&amp;nbsp;아래에서&amp;nbsp;자세히&amp;nbsp;소개해&amp;nbsp;본다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;학습 업적을 활용한 동기부여&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매일&amp;nbsp;첫&amp;nbsp;코드트리&amp;nbsp;접속&amp;nbsp;시&amp;nbsp;뜨는&amp;nbsp;모달&amp;nbsp;또는&amp;nbsp;오른쪽&amp;nbsp;위의&amp;nbsp;경험치&amp;nbsp;목표를&amp;nbsp;사용자가&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있고,&amp;nbsp;연속&amp;nbsp;학습에&amp;nbsp;따라&amp;nbsp;업적을&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;부여하는&amp;nbsp;것을&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;아마도&amp;nbsp;연속&amp;nbsp;학습에&amp;nbsp;대한&amp;nbsp;트래킹은&amp;nbsp;유사&amp;nbsp;서비스에서도&amp;nbsp;제공하나,&amp;nbsp;당일&amp;nbsp;업적을&amp;nbsp;쌓기&amp;nbsp;위해서,&amp;nbsp;필요한&amp;nbsp;경험치(XP)를&amp;nbsp;사용자가&amp;nbsp;직접&amp;nbsp;지정할&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문에&amp;nbsp;조금&amp;nbsp;더&amp;nbsp;유연하게&amp;nbsp;동기부여를&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;점이&amp;nbsp;마음에&amp;nbsp;들었다.&amp;nbsp;내&amp;nbsp;경우&amp;nbsp;주말이나&amp;nbsp;퇴근&amp;nbsp;후에&amp;nbsp;컨디션이&amp;nbsp;괜찮은&amp;nbsp;경우&amp;nbsp;100XP&amp;nbsp;정도로&amp;nbsp;설정했고,&amp;nbsp;바쁘거나&amp;nbsp;컨디션이&amp;nbsp;좋지&amp;nbsp;않으면&amp;nbsp;최소&amp;nbsp;경험치&amp;nbsp;값인&amp;nbsp;25XP를&amp;nbsp;설정하여&amp;nbsp;부담&amp;nbsp;없이&amp;nbsp;스트릭을&amp;nbsp;유지할&amp;nbsp;수&amp;nbsp;있었고&amp;nbsp;2월&amp;nbsp;초&amp;nbsp;기준&amp;nbsp;28일&amp;nbsp;연속&amp;nbsp;학습으로&amp;nbsp;Tree&amp;nbsp;업적&amp;nbsp;(30일)&amp;nbsp;까지는&amp;nbsp;2일이&amp;nbsp;남은&amp;nbsp;상태다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1031&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjn9gK/btsL4zB5ASR/l4asUV03KSbZGoTciyPz4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjn9gK/btsL4zB5ASR/l4asUV03KSbZGoTciyPz4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjn9gK/btsL4zB5ASR/l4asUV03KSbZGoTciyPz4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcjn9gK%2FbtsL4zB5ASR%2Fl4asUV03KSbZGoTciyPz4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1919&quot; height=&quot;1031&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;1031&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gang2/btsL4XJgHb0/tk1RlWovO7aSsTd28BSok0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gang2/btsL4XJgHb0/tk1RlWovO7aSsTd28BSok0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gang2/btsL4XJgHb0/tk1RlWovO7aSsTd28BSok0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGang2%2FbtsL4XJgHb0%2Ftk1RlWovO7aSsTd28BSok0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;438&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GitHub 연동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서&amp;nbsp;얘기한&amp;nbsp;서비스&amp;nbsp;내에서의&amp;nbsp;업적&amp;nbsp;외에도&amp;nbsp;코드트리는&amp;nbsp;자체적으로&amp;nbsp;GitHub&amp;nbsp;연동을&amp;nbsp;지원하는데,&amp;nbsp;무슨&amp;nbsp;말인가&amp;nbsp;하니&amp;nbsp;본인이&amp;nbsp;제출한&amp;nbsp;코드에&amp;nbsp;대해서&amp;nbsp;자동으로&amp;nbsp;연결된&amp;nbsp;GitHub&amp;nbsp;저장소에&amp;nbsp;연동이&amp;nbsp;된다.&amp;nbsp;연동에&amp;nbsp;대한&amp;nbsp;메뉴는&amp;nbsp;코드트리&amp;nbsp;오른쪽&amp;nbsp;아래의&amp;nbsp;본인&amp;nbsp;아이디를&amp;nbsp;누른&amp;nbsp;후&amp;nbsp;GitHub에&amp;nbsp;학습&amp;nbsp;기록&amp;nbsp;남기기&amp;nbsp;메뉴를&amp;nbsp;통해&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;진행된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;909&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RXkmU/btsL5CEBGQM/xpXu2k6APpTZcbn0SL8aPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RXkmU/btsL5CEBGQM/xpXu2k6APpTZcbn0SL8aPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RXkmU/btsL5CEBGQM/xpXu2k6APpTZcbn0SL8aPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRXkmU%2FbtsL5CEBGQM%2FxpXu2k6APpTZcbn0SL8aPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1050&quot; height=&quot;909&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;909&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;941&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVD8YK/btsL3gi9snI/R2rkZGRVXTUlJMU1BVv1E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVD8YK/btsL3gi9snI/R2rkZGRVXTUlJMU1BVv1E1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVD8YK/btsL3gi9snI/R2rkZGRVXTUlJMU1BVv1E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVD8YK%2FbtsL3gi9snI%2FR2rkZGRVXTUlJMU1BVv1E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1919&quot; height=&quot;941&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;941&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Wq9m/btsL4xqGR6F/PKmzI2fWig4GfKStKPzBlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Wq9m/btsL4xqGR6F/PKmzI2fWig4GfKStKPzBlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Wq9m/btsL4xqGR6F/PKmzI2fWig4GfKStKPzBlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Wq9m%2FbtsL4xqGR6F%2FPKmzI2fWig4GfKStKPzBlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1919&quot; height=&quot;942&quot; data-origin-width=&quot;1919&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어서 나는 &lt;a href=&quot;https://github.com/gamamoe/Codetree-TILs&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/gamamoe/Codetree-TILs&lt;/a&gt; 저장소를 설정했고, 아래처럼 1월 6일부터 제출한 코드들이 차곡차곡 쌓여있는 것을 확인할 수 있다. 날짜별 디렉터리를 들어가게 되면 푼 문제에 대한 요약도 같이 생성되어 있어 나중에 특정 자료구조나 알고리즘에 대한 코드가 필요할 경우 간단하게 검색을 통해 찾기도 쉬울 것으로 보인다. 이 기능이 마음에 드는 이유는 특히 경력이 없는 신입 개발자 지원자의 경우 면접관에게 어필할 수 있는 수단이 많지 않은데, 객관적으로 본인의 공부 내역을 보여줄 수 있기 때문에 얼마나 꾸준히 공부했고 어떤 자료구조/알고리즘을 공부했는지 파악할 수 있어 나중에 하나의 포트폴리오처럼 활용해도 좋을 것으로 보인다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;509&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwPQ4A/btsL4XboIG0/G8PchMExLOOJvs8YBCh270/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwPQ4A/btsL4XboIG0/G8PchMExLOOJvs8YBCh270/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwPQ4A/btsL4XboIG0/G8PchMExLOOJvs8YBCh270/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwPQ4A%2FbtsL4XboIG0%2FG8PchMExLOOJvs8YBCh270%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;647&quot; height=&quot;509&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;509&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ticFR/btsL3rx3tp5/xiY63Sq0WkypxqAw11SMA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ticFR/btsL3rx3tp5/xiY63Sq0WkypxqAw11SMA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ticFR/btsL3rx3tp5/xiY63Sq0WkypxqAw11SMA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FticFR%2FbtsL3rx3tp5%2FxiY63Sq0WkypxqAw11SMA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;791&quot; height=&quot;748&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디스코드 커뮤니티 운영&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실&amp;nbsp;위&amp;nbsp;2개의&amp;nbsp;수단만&amp;nbsp;해도&amp;nbsp;게이미피케이션&amp;nbsp;및&amp;nbsp;동기부여&amp;nbsp;기능으로는&amp;nbsp;충분한&amp;nbsp;것&amp;nbsp;같은데,&amp;nbsp;거기에&amp;nbsp;더해&amp;nbsp;추가로&amp;nbsp;디스코드&amp;nbsp;커뮤니티를&amp;nbsp;운영하고&amp;nbsp;있다.&amp;nbsp;다만,&amp;nbsp;글또X코드트리&amp;nbsp;챌린지&amp;nbsp;동안만&amp;nbsp;한시적으로&amp;nbsp;운영하는&amp;nbsp;것인지&amp;nbsp;아니면&amp;nbsp;이후에도&amp;nbsp;계속&amp;nbsp;운영할&amp;nbsp;것인지는&amp;nbsp;조금&amp;nbsp;불분명하나&amp;nbsp;관리자분들이&amp;nbsp;적절하게&amp;nbsp;설치한&amp;nbsp;봇을&amp;nbsp;통해서&amp;nbsp;매일매일의&amp;nbsp;목표를&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있고,&amp;nbsp;다른&amp;nbsp;사람들의&amp;nbsp;진행도를&amp;nbsp;보면서&amp;nbsp;좋은&amp;nbsp;자극과&amp;nbsp;동기부여를&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;점이&amp;nbsp;장점으로&amp;nbsp;보인다.&amp;nbsp;꼭,&amp;nbsp;디스코드가&amp;nbsp;아니더라도&amp;nbsp;플랫폼&amp;nbsp;내에&amp;nbsp;비슷한&amp;nbsp;기능을&amp;nbsp;구현하거나&amp;nbsp;앞으로도&amp;nbsp;디스코드&amp;nbsp;커뮤니티를&amp;nbsp;계속&amp;nbsp;운영하면&amp;nbsp;좋겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcA2kH/btsL4KDlf49/1DyxF2ZDSsOHTmyWSVSVK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcA2kH/btsL4KDlf49/1DyxF2ZDSsOHTmyWSVSVK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcA2kH/btsL4KDlf49/1DyxF2ZDSsOHTmyWSVSVK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcA2kH%2FbtsL4KDlf49%2F1DyxF2ZDSsOHTmyWSVSVK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;686&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 구성, 난이도 및 지원 프로그래밍 언어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나 특이한 점은 단순히 입력을 받아 출력을 계산하는 코드 작성 문제만 존재하지 않고, 다지선다 문제가 존재하는데 이는 처음 코딩테스트를 준비하는 사용자에게 단순히 코드만 작성하는 것이 아니라, 손과 머리를 활용하여 직접 다른 형태의 자극으로 공부에 도움이 될 것으로 보인다 (다만 코드를 복사해서 실행 후 답을 내면 의미가 없어지니, 펜과 종이를 활용하여 직접 풀어보자!)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1859&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KHllw/btsL5jFgzKc/1TacD5GgGKivNKDVO7dSQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KHllw/btsL5jFgzKc/1TacD5GgGKivNKDVO7dSQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KHllw/btsL5jFgzKc/1TacD5GgGKivNKDVO7dSQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKHllw%2FbtsL5jFgzKc%2F1TacD5GgGKivNKDVO7dSQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1859&quot; height=&quot;619&quot; data-origin-width=&quot;1859&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 25년 2월 기준으로 대부분의 메이저 프로그래밍 언어 (C/C++, Java, Python, JavaScript)는 지원하고 있으며, Go와 Rust 등의 언어도 지원하는 것으로 보인다. 다만 해설의 경우 대부분 많이 사용되는 프로그래밍 언어로만 작성되어 있다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아쉬운 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1월&amp;nbsp;초까지는&amp;nbsp;제출&amp;nbsp;시&amp;nbsp;채점&amp;nbsp;속도가&amp;nbsp;느리거나,&amp;nbsp;간혹&amp;nbsp;페이지가&amp;nbsp;멈추는&amp;nbsp;현상이&amp;nbsp;있었으나&amp;nbsp;아마도&amp;nbsp;개발자분들의&amp;nbsp;노력으로&amp;nbsp;25년&amp;nbsp;2월&amp;nbsp;기준으로는&amp;nbsp;쾌적하게&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있었다.&amp;nbsp;다만,&amp;nbsp;아래처럼&amp;nbsp;웹브라우저&amp;nbsp;크기를&amp;nbsp;줄이는&amp;nbsp;경우&amp;nbsp;데스크탑&amp;nbsp;환경인데도&amp;nbsp;아래와&amp;nbsp;같은&amp;nbsp;메시지가&amp;nbsp;뜬&amp;nbsp;거는&amp;nbsp;문제가&amp;nbsp;아직&amp;nbsp;있는&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;추가로&amp;nbsp;매일매일의&amp;nbsp;업적을&amp;nbsp;위해서&amp;nbsp;설정하는&amp;nbsp;경험치를&amp;nbsp;모아서&amp;nbsp;무언가를&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있으면&amp;nbsp;좋겠다는&amp;nbsp;생각이&amp;nbsp;드는데&amp;nbsp;그런&amp;nbsp;콘텐츠는&amp;nbsp;아직&amp;nbsp;없는&amp;nbsp;것으로&amp;nbsp;보인다.&amp;nbsp;동기부여가&amp;nbsp;떨어지면&amp;nbsp;25XP만&amp;nbsp;매일&amp;nbsp;설정하는&amp;nbsp;때도&amp;nbsp;생길&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;것&amp;nbsp;같아&amp;nbsp;뭔가&amp;nbsp;보상이&amp;nbsp;있으면&amp;nbsp;더&amp;nbsp;좋을&amp;nbsp;것&amp;nbsp;같다는&amp;nbsp;생각이&amp;nbsp;든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;1029&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n6aU4/btsL4buErGt/QVNDhKB5VftZVf2Gj63vl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n6aU4/btsL4buErGt/QVNDhKB5VftZVf2Gj63vl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n6aU4/btsL4buErGt/QVNDhKB5VftZVf2Gj63vl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn6aU4%2FbtsL4buErGt%2FQVNDhKB5VftZVf2Gj63vl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;958&quot; height=&quot;1029&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;1029&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;총평&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적으로 기존 코딩테스트 플랫폼과 유사한 인터페이스를 가져서 새로 시작하려는 사용자에게 거부감을 최대한 덜고, 삼중으로 무장한 동기부여 수단 (업적, GitHub 연동, 디스코드 커뮤니티)를 지원해 학습자가 꾸준히 진행할 수 있도록 도와줄 수 있다는 점이 장점으로 보인다. 코딩테스트는 결국 평소에 꾸준히 푸는 것이 중요하다고 생각되므로 이런 부분이 큰 도움이 될 수 있을 것 같다고 생각한다. 특히, 학생의 경우 할인이 추가로 있으니 이런 부분도 고려하여 코딩 테스트 준비에 고려하면 좋겠다. 그럼, 후기 끝!&lt;/p&gt;</description>
      <category>개발 이야기/Problem Solving</category>
      <category>codeTree</category>
      <category>알고리즘</category>
      <category>자료구조</category>
      <category>코드트리</category>
      <category>코딩테스트</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/188</guid>
      <comments>https://iostream.tistory.com/188#entry188comment</comments>
      <pubDate>Sun, 2 Feb 2025 15:32:43 +0900</pubDate>
    </item>
    <item>
      <title>문화체육관광부 추천 도서 (성인과 유아/청소년)</title>
      <link>https://iostream.tistory.com/187</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;설을 지내고 나니 벌써 1월의 마지막에 가까워졌고, 다시 말해서 25년도의 1/12가 지나간 셈이다. 나를 포함해 신년 목표로 독서를 계획한 사람들이 많을 것으로 생각한다. 본인만의 독서 계획이 있는 사람도 있겠지만, 이제 독서를 막 시작하는 사람이라면 어떤 책을 읽을지부터가 난관일 것 같다. 다행히도 문화체육관광부의 국립중앙도서관과 국립어린이청소년도서관에서 사서 추천 도서를 공개하고 있으니, 본인과 자녀들이 있다면 해당 추천 도서 리스트를 참고하면 좋은 시작점이 될 것 같다. 자세한 내용은 아래에서 서술한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;국립중앙도서관 추천 도서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문화체육관광부 국립중앙도서관 홈페이지 또는 다음 &lt;a href=&quot;https://www.nl.go.kr/NL/contents/N20500000000.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;를 통해서 여러 주제 (문학, 인문과학, 사회과학, 자연과학) 및 테마별로 정리한 추천 도서를 찾아볼 수 있다. 등록순으로 결과를 정렬해서 봤을 때 대략 2009년 혹은 2010년부터 목록을 만들기 시작한 것 같으며, 25년 1월 말 기준으로 총 1,371개의 추천 도서가 존재한다. 모든 목록을 확인한 것은 아니지만 대체로 성인을 위한 책들이라고 생각된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfG28a/btsL24ozmpQ/Bw6TdBlTjKldVPAjJsqtqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfG28a/btsL24ozmpQ/Bw6TdBlTjKldVPAjJsqtqK/img.png&quot; data-alt=&quot;국립중앙도서관 사서 추천 도서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfG28a/btsL24ozmpQ/Bw6TdBlTjKldVPAjJsqtqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfG28a%2FbtsL24ozmpQ%2FBw6TdBlTjKldVPAjJsqtqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;976&quot; height=&quot;872&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;국립중앙도서관 사서 추천 도서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;국립어린이청소년도서관 추천 도서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국립중앙도서관과 비슷하게 국립어린이청소년도서관에서는 유아부터 시작해 초등학생, 그리고 청소년을 위한 추천 도서를 정리해서 공개하고 있다. 문화체육관광부 국립어린이청소년도서관 홈페이지 또는 다음 &lt;a href=&quot;https://www.nlcy.go.kr/NLCY/contents/C10600000000.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;를 통해서 나이별로 그리고 주제별로 추천 도서를 아래 그림처럼 확인할 수 있다. 25년 1월 말 기준으로 총 2,440개의 추천 도서가 존재한다. 간단한 책 소개도 같이 수록되어 있으니, 구매나 도서 대출 전 자녀와 함께 읽어보고 흥미에 맞는 책을 고르는 데 한결 도움이 되지 않을까 싶다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boN788/btsL2bu61j9/OQ0G3RZuPkogVgskMuQumk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boN788/btsL2bu61j9/OQ0G3RZuPkogVgskMuQumk/img.png&quot; data-alt=&quot;국립어린이청소년도서관 사서 추천 도서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boN788/btsL2bu61j9/OQ0G3RZuPkogVgskMuQumk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboN788%2FbtsL2bu61j9%2FOQ0G3RZuPkogVgskMuQumk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;846&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;846&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;국립어린이청소년도서관 사서 추천 도서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우 하루에 30분 정도 독서를 꼭 하려고 노력하는데, 책의 주제나 내 배경지식의 유무에 따라 조금씩 차이는 있지만 30분에 30페이지 정도를 읽을 수 있다. 그렇다면 단순히 계산했을 때 300페이지의 책을 한 번 읽는 데 10일 정도가 걸리고, 이것이 쌓이면 1년 기준으로 꽤 많은 책을 읽을 수 있을 것이다. 완독한 책의 수를 세는 것이 누군가는 지적 허영심이다 또는 의미 없는 짓이라고 얘기하겠지만, 유튜브나 각종 SNS에 노출된 현대인을 생각하면 그것이 지적 허영심일지라도 책을 읽는다는 행위에 익숙해질 필요는 있다고 본다. 어느 정도 익숙해지고 나면 서평도 작성하고, 책에 대해서 비판적인 시선도 생길 것이며 그 후의 또 다른 과정은 미래의 나에게 맡겨두면 되니 너무 걱정하지 말고, 다 같이 독서의 즐거움을 알아가면 좋겠다. 추가로 모든 책을 구매하는 것은 생각보다 부담스러운 일이니, 근처 도서관을 활용해 빌려보다가 정말 마음에 드는 책이 있다면 그때 구매하는 것도 하나의 방법이겠다. 너무 큰 목표로 시작하기보다는 작년보다는 조금 더 책을 읽어보는 한 해가 되면 최고 아닐까?&lt;/p&gt;</description>
      <category>독서 이야기</category>
      <category>국립어린이청소년도서관</category>
      <category>국립중앙도서관</category>
      <category>문체부</category>
      <category>문화체육관광부</category>
      <category>추천 도서</category>
      <category>추천도서</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/187</guid>
      <comments>https://iostream.tistory.com/187#entry187comment</comments>
      <pubDate>Thu, 30 Jan 2025 22:58:01 +0900</pubDate>
    </item>
    <item>
      <title>머신러닝 엔지니어의 2024년 회고</title>
      <link>https://iostream.tistory.com/186</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;연차가 쌓이면서 하루하루는 더디게 느껴지지만 한 주, 한 달, 그리고 한 해는 눈 깜짝할 새 지나는 것 같다. &lt;a href=&quot;https://iostream.tistory.com/167&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023년 회고&lt;/a&gt;를 작성한 것이 얼마 되지 않은 것 같은데 벌써 2024년의 막바지에 기록을 남겨본다. 글을 작성하기 전 2023년 회고를 읽어봤는데, 나란 사람 자체가 변화를 크게 좋아하지 않고 루틴을 지키려고 하는 편이라 그런지 크게 변함없는 한 해를 보낸 것 같다. 조금 미리 작성하면 더 좋을 텐데 올해도 12월 31일 딱 마지막 날에 글을 작성하는 것도 작년과 똑같은 모습에 조금은 반성하게 된다. 그런데도 올 한 해 성취한 내용과 잘했던 점, 아쉬운 점 그리고 미약하지만 2025년도에 이루고 싶은 목표를 작성해 보고자 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;잘했던 점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Staff Engineer 승진&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;올해 9월로 Qualcomm에서 만으로 3년을 꽉 채우는 해였고 물 밑에서 어느 정도 승진에 관한 얘기가 있었지만, 주위 사례를 봤을 때 확신할 수는 없었다. 다행히 운이 좋게도 헌신적인 조직장과 훌륭한 동료들 덕분에 Staff Engineer로 승진할 수 있었다고 생각한다. 승진은 회사에서 나라는 엔지니어의 가치를 어느 정도 인정해 줬다는 것으로 생각하고, 실제로 그에 걸맞은 금전적인 보상이 있었다. 승진 자체는 매우 기쁘고 행복한 일이지만, 주위에서 보았던 동료 Staff Engineer들이 얼마나 열심히 일하고 업무에 헌신적인지를 봤을 때 내가 그들만큼 잘할 수 있을까에 대한 걱정은 여전히 가지고 있다. 다만 걱정만 하는 것은 회사도 나도 원하지 않는 방향이기 때문에 어떻게든 부딪혀가면서 해내 보려고 한다. 새로운 직급에 대해서 정확한 역할이 정해져 있는 것은 아니지만 역시나 기술적으로는 주니어 엔지니어들을 리드할 수 있어야 할 것이며, 팀 자체로는 좋은 멘토 및 동기부여를 줄 수 있는 사람이 되길 기원한다. 리더십이나 팀 매니징 관련해서는 선배들의 도움을 간접적으로나마 받고 싶어 &lt;a href=&quot;https://iostream.tistory.com/183&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;혼돈의 시대 리더의 탄생&amp;gt;&lt;/a&gt;과 &lt;a href=&quot;https://www.yes24.com/Product/Goods/139780268&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&amp;lt;무엇이 1등 팀을 만드는가?&amp;gt;&lt;/a&gt;와 같은 책을 읽어보면서 내 상황에 활용해보려고 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;독서&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;작년에&amp;nbsp;이어서&amp;nbsp;올해도&amp;nbsp;매달&amp;nbsp;진행하는&amp;nbsp;독서&amp;nbsp;모임을&amp;nbsp;계기로&amp;nbsp;꾸준히&amp;nbsp;책을&amp;nbsp;읽은&amp;nbsp;것은&amp;nbsp;잘한&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;이런&amp;nbsp;외적&amp;nbsp;동기부여가&amp;nbsp;없으면&amp;nbsp;소설이나&amp;nbsp;문학&amp;nbsp;작품은&amp;nbsp;우선순위에서&amp;nbsp;항상&amp;nbsp;밀리는&amp;nbsp;내&amp;nbsp;성격을&amp;nbsp;고려했을&amp;nbsp;때&amp;nbsp;올해도&amp;nbsp;아래와&amp;nbsp;같은&amp;nbsp;책들을&amp;nbsp;읽은&amp;nbsp;것은&amp;nbsp;매우&amp;nbsp;뿌듯한&amp;nbsp;일이라고&amp;nbsp;생각한다.&amp;nbsp;특히&amp;nbsp;좋았던&amp;nbsp;책은&amp;nbsp;굵은&amp;nbsp;글씨로&amp;nbsp;표기해&amp;nbsp;본다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라이프 타임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;아주 희미한 빛으로도&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;두 사람의 인터내셔널&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간을 잃어버린 사람들&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;한강 디 에센셜&lt;/li&gt;
&lt;li&gt;도시와 그 불확실한 벽&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;최은영&amp;nbsp;작가의&amp;nbsp;&amp;lt;아주&amp;nbsp;희미한&amp;nbsp;빛으로도&amp;gt;나&amp;nbsp;&amp;lt;두&amp;nbsp;사람의&amp;nbsp;인터내셔널&amp;gt;&amp;nbsp;같은&amp;nbsp;소설은&amp;nbsp;굉장히&amp;nbsp;재밌어서&amp;nbsp;주위&amp;nbsp;동료나&amp;nbsp;친구들에게도&amp;nbsp;선물했던&amp;nbsp;책이다.&amp;nbsp;다만&amp;nbsp;책을&amp;nbsp;읽은&amp;nbsp;것과는&amp;nbsp;별개로&amp;nbsp;개인&amp;nbsp;사정으로&amp;nbsp;작년만큼은&amp;nbsp;모임에&amp;nbsp;참석을&amp;nbsp;못&amp;nbsp;해서&amp;nbsp;좀&amp;nbsp;아쉬운&amp;nbsp;부분과&amp;nbsp;모임장에게&amp;nbsp;미안한&amp;nbsp;마음이&amp;nbsp;있다.&amp;nbsp;불가피한&amp;nbsp;사정이&amp;nbsp;아니라면&amp;nbsp;2025년에는&amp;nbsp;올해보다는&amp;nbsp;더&amp;nbsp;많이&amp;nbsp;참석하여&amp;nbsp;여러&amp;nbsp;사람과&amp;nbsp;읽은&amp;nbsp;책에&amp;nbsp;대해서&amp;nbsp;나눌&amp;nbsp;수&amp;nbsp;있기를&amp;nbsp;바란다.&amp;nbsp;추가로&amp;nbsp;글또&amp;nbsp;내의&amp;nbsp;소모임&amp;nbsp;중&amp;nbsp;하나인&amp;nbsp;&lt;b&gt;책읽었또&lt;/b&gt;&amp;nbsp;덕분에&amp;nbsp;몰아&amp;nbsp;읽기가&amp;nbsp;아니라&amp;nbsp;매일매일&amp;nbsp;조금이라도&amp;nbsp;읽을&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;루틴을&amp;nbsp;만들&amp;nbsp;수&amp;nbsp;있어서&amp;nbsp;큰&amp;nbsp;도움을&amp;nbsp;받았다.&amp;nbsp;내년에도&amp;nbsp;해당&amp;nbsp;소모임을&amp;nbsp;통해서&amp;nbsp;꾸준히&amp;nbsp;책을&amp;nbsp;읽는&amp;nbsp;습관을&amp;nbsp;지니려고&amp;nbsp;한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;조깅&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;독서와&amp;nbsp;마찬가지로&amp;nbsp;조깅&amp;nbsp;역시&amp;nbsp;올해도&amp;nbsp;꾸준히&amp;nbsp;한&amp;nbsp;것이&amp;nbsp;잘한&amp;nbsp;점이라고&amp;nbsp;생각한다.&amp;nbsp;재택근무를&amp;nbsp;주로&amp;nbsp;하므로&amp;nbsp;조깅하지&amp;nbsp;않으면&amp;nbsp;하루&amp;nbsp;종일&amp;nbsp;집에만&amp;nbsp;있게&amp;nbsp;되는&amp;nbsp;경우가&amp;nbsp;많았는데,&amp;nbsp;어떻게든&amp;nbsp;업무&amp;nbsp;시작&amp;nbsp;전이나&amp;nbsp;업무&amp;nbsp;마감&amp;nbsp;후에&amp;nbsp;뛰려고&amp;nbsp;했고&amp;nbsp;런데이&amp;nbsp;앱과&amp;nbsp;글또의&amp;nbsp;&lt;b&gt;달리또&lt;/b&gt;&amp;nbsp;소모임의&amp;nbsp;도움을&amp;nbsp;많이&amp;nbsp;받았다.&amp;nbsp;가능하면&amp;nbsp;격일로&amp;nbsp;30분&amp;nbsp;정도&amp;nbsp;뛰고,&amp;nbsp;뛰지&amp;nbsp;않는&amp;nbsp;날은&amp;nbsp;걷기라도&amp;nbsp;하려고&amp;nbsp;했으며&amp;nbsp;꾸준히&amp;nbsp;뛰었을&amp;nbsp;때&amp;nbsp;확실히&amp;nbsp;육체적/정신적으로&amp;nbsp;굉장히&amp;nbsp;긍정적인&amp;nbsp;효과가&amp;nbsp;있었다고&amp;nbsp;생각한다.&amp;nbsp;작년&amp;nbsp;회고에서&amp;nbsp;단거리&amp;nbsp;마라톤을&amp;nbsp;도전해&amp;nbsp;볼까&amp;nbsp;하는&amp;nbsp;얘기를&amp;nbsp;했었는데,&amp;nbsp;아쉽게도&amp;nbsp;특별히&amp;nbsp;대회에&amp;nbsp;참가하지는&amp;nbsp;않았다.&amp;nbsp;성향상&amp;nbsp;역시&amp;nbsp;부대끼지&amp;nbsp;않고&amp;nbsp;조용히&amp;nbsp;내&amp;nbsp;페이스대로&amp;nbsp;혼자&amp;nbsp;뛰는&amp;nbsp;것이&amp;nbsp;마음이&amp;nbsp;편한&amp;nbsp;것&amp;nbsp;같다.&amp;nbsp;올해&amp;nbsp;열심히&amp;nbsp;뛰어&amp;nbsp;수명이&amp;nbsp;다한&amp;nbsp;신발도&amp;nbsp;교체했고,&amp;nbsp;욕심을&amp;nbsp;조금&amp;nbsp;더&amp;nbsp;내어&amp;nbsp;2025년에는&amp;nbsp;올해보다&amp;nbsp;더&amp;nbsp;꾸준히&amp;nbsp;그리고&amp;nbsp;50분&amp;nbsp;달리기까지&amp;nbsp;도전해&amp;nbsp;보려고&amp;nbsp;한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zlzPk/btsLz6ag2C8/S3YlkQPPolEMrB20WEaGx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zlzPk/btsLz6ag2C8/S3YlkQPPolEMrB20WEaGx0/img.png&quot; data-alt=&quot;올해 가장 열심히 뛴 10월&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zlzPk/btsLz6ag2C8/S3YlkQPPolEMrB20WEaGx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzlzPk%2FbtsLz6ag2C8%2FS3YlkQPPolEMrB20WEaGx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;303&quot; height=&quot;242&quot; data-origin-width=&quot;303&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;올해 가장 열심히 뛴 10월&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아쉬운 점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;영어&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;가장&amp;nbsp;먼저&amp;nbsp;생각나는&amp;nbsp;항목은&amp;nbsp;역시&amp;nbsp;영어라고&amp;nbsp;본다.&amp;nbsp;기술적인&amp;nbsp;대화는&amp;nbsp;어휘나&amp;nbsp;표현이&amp;nbsp;그렇게&amp;nbsp;어렵지&amp;nbsp;않고,&amp;nbsp;상대의&amp;nbsp;눈빛과&amp;nbsp;같은&amp;nbsp;비언어적&amp;nbsp;반응을&amp;nbsp;통해서&amp;nbsp;이해&amp;nbsp;유무를&amp;nbsp;다시&amp;nbsp;한번&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문에&amp;nbsp;그동안&amp;nbsp;의사소통에&amp;nbsp;대해서&amp;nbsp;아주&amp;nbsp;심각하게&amp;nbsp;생각하진&amp;nbsp;않았었다.&amp;nbsp;그래서&amp;nbsp;특별히&amp;nbsp;영어&amp;nbsp;공부를&amp;nbsp;한다는&amp;nbsp;느낌보다는&amp;nbsp;작년&amp;nbsp;회고와&amp;nbsp;마찬가지로&amp;nbsp;유튜브&amp;nbsp;영상&amp;nbsp;(e.g.,&amp;nbsp;라이브&amp;nbsp;아카데미)&amp;nbsp;중&amp;nbsp;눈에&amp;nbsp;띄는&amp;nbsp;영어&amp;nbsp;관련&amp;nbsp;영상이&amp;nbsp;있으면&amp;nbsp;챙겨보는&amp;nbsp;정도였다.&amp;nbsp;다만&amp;nbsp;업무&amp;nbsp;분담이&amp;nbsp;늘어났고,&amp;nbsp;커리어&amp;nbsp;래더가&amp;nbsp;늘어났기&amp;nbsp;때문에&amp;nbsp;속된&amp;nbsp;말로&amp;nbsp;틀에&amp;nbsp;박힌&amp;nbsp;영어&amp;nbsp;구사력은&amp;nbsp;결국&amp;nbsp;내&amp;nbsp;발목을&amp;nbsp;잡을&amp;nbsp;것&amp;nbsp;같다는&amp;nbsp;생각이&amp;nbsp;꽤&amp;nbsp;많이&amp;nbsp;든&amp;nbsp;한해였다.&amp;nbsp;조금&amp;nbsp;유식하게&amp;nbsp;표현했을&amp;nbsp;때&amp;nbsp;현재&amp;nbsp;내가&amp;nbsp;모국어&amp;nbsp;간섭이&amp;nbsp;매우&amp;nbsp;많은&amp;nbsp;영어&amp;nbsp;구사를&amp;nbsp;하는&amp;nbsp;상태라는&amp;nbsp;것을&amp;nbsp;시간&amp;nbsp;내어&amp;nbsp;공부하고&amp;nbsp;있는&amp;nbsp;강의를&amp;nbsp;통해&amp;nbsp;이해하게&amp;nbsp;됐으며&amp;nbsp;이것을&amp;nbsp;적극적으로&amp;nbsp;개선해&amp;nbsp;보려고&amp;nbsp;노력&amp;nbsp;중이다.&amp;nbsp;확실히&amp;nbsp;유튜브를&amp;nbsp;통해서&amp;nbsp;내가&amp;nbsp;하고&amp;nbsp;싶을&amp;nbsp;때만&amp;nbsp;골라&amp;nbsp;듣는&amp;nbsp;것이&amp;nbsp;아니라&amp;nbsp;강의&amp;nbsp;형태로&amp;nbsp;어느&amp;nbsp;정도의&amp;nbsp;커리큘럼이&amp;nbsp;있다&amp;nbsp;보니&amp;nbsp;더&amp;nbsp;체계적이고&amp;nbsp;나도&amp;nbsp;무조건&amp;nbsp;영어&amp;nbsp;공부를&amp;nbsp;위한&amp;nbsp;시간을&amp;nbsp;따로&amp;nbsp;내고&amp;nbsp;있다&amp;nbsp;보니&amp;nbsp;조금씩&amp;nbsp;실력이&amp;nbsp;늘어나는&amp;nbsp;것이&amp;nbsp;느껴지고&amp;nbsp;있다.&amp;nbsp;2025년에도&amp;nbsp;매일&amp;nbsp;조금씩이라도&amp;nbsp;해당&amp;nbsp;강의와&amp;nbsp;함께&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;고급&amp;nbsp;영어를&amp;nbsp;내뱉을&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;노력해&amp;nbsp;보려고&amp;nbsp;한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Quantization 연구에 대한 뒤처짐&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Qualcomm에 입사한 2021년과 비교했을 때 2024년 기준 모델 경량화에 대한 수요와 연구는 폭발적으로 성장했다고 생각한다. 가장 정량적인 바로미터가 결국 연구 논문의 수라고 생각할 수 있는데, 입사할 때만 해도 per-tensor W8A16 정도를 기준으로 생각했던 것과 비교해 요즘은 per-group W4A8과 같이 굉장히 공격적인 경량화까지 시도하는 것을 보면 격세지감이라고 할 것 같다. 입사 후 1~2년은 크게 따라가야 할 연구 논문의 수가 부담스럽지 않았고 (그리고 꼭 봐야 했던 논문은 대부분 Qualcomm에서 출간한 논문이었다) 업무 자체가 소프트웨어 엔지니어링에 조금 더 힘을 주는 것이었기 때문에 큰 부담이 없었다. 다만 올해 직접적으로 구현에 참여했던 GPTVQ나 옆에서 지켜봤던 Group Quantization 그리고 논문 세미나에서 들은 연구 내용 (OmniQuant, SmoothQuant 등)들을 고려했을 때 최신 추세에도 리서치 엔지니어만큼은 아니라도 어느 정도 이해를 해야 한다는 결론에 이르렀다. 엔지니어링과 리서치 두 마리 토끼를 잡아야 하는 것 같아 조금은 부담스럽지만 그래도 공부하지 않고 걱정하는 것보다는 낫지 않을까 싶다. 모든 연구 논문을 따라가는 것은 현실적으로 불가능할 것 같고, 주위 리서치 엔지니어 동료의 도움을 받아서 그럼에도 꼭 읽어봐야 하는 논문 몇 편을 골라볼 예정이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2025년 목표&lt;/h3&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;올해 했던 내용들에서 특별한 무엇을 더하기보다는 올해 했던 것을 발전시켜 조금 더 나은 성취가 있기를 바라면서 정량적인 목표를 세워봤다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;15권 독서 및 그중 7권 서평 작성하기: 기술 서적 외에 올해는 10권 독서했으므로 내년에는 15권 그리고 기록으로 남길 수 있도록 7권은 서평까지 작성해 보려고 한다&lt;/li&gt;
&lt;li&gt;영어 강의 완강 및 후속 강의 수강: 현재 수강 중인 강의 완강과 후속 강의가 있어서 해당 강의까지 수강하는 것을 목표로 한다&lt;/li&gt;
&lt;li&gt;주 3회 50분 조깅: 올해는 주 3회 30분 조깅으로 무리 없이 뛸 수 있었다면 내년에는 50분으로 조금 더 운동 부하를 늘려서 뛰어보는 것을 목표로 한다&lt;/li&gt;
&lt;li&gt;Quantization 논문 2편 리뷰: 욕심내지 않고 2편 리뷰로 우선 목표를 잡아봤다. 아마 2편을 리뷰하려면 참조한 논문들까지 포함하여 꽤 많은 연구 논문을 봐야 할 것으로 생각한다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>일상 이야기/회고</category>
      <category>2024</category>
      <category>머신러닝 엔지니어</category>
      <category>회고</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/186</guid>
      <comments>https://iostream.tistory.com/186#entry186comment</comments>
      <pubDate>Tue, 31 Dec 2024 19:02:42 +0900</pubDate>
    </item>
    <item>
      <title>PyTorch Custom Op to ONNX</title>
      <link>https://iostream.tistory.com/185</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 포스트에서 몇 번 언급했던 것처럼 최근 머신러닝 애플리케이션은 연구자 (조직마다 다르지만 보통 Researcher, Data Scientist, Applied Scientist 등으로 표현하는 포지션)가 PyTorch 환경에서 모델 학습 및 실험으로 성능을 검증한 후 해당 모델을 배포할 환경에 따라 TFLite, ONNX 등으로 모델 변환을 하는 것이 일반적인데요. 특히 ONNX는 여러 최적화 기법을 공짜 점심으로 변환 시 제공하고 있어서 많이 활용합니다. 다만 우리가 만든 PyTorch 모델의 연산들이 항상 ONNX가 지원하는 Operator라는 보장이 없을 수 있는데요. 우선 ONNX에서 지원하는 &lt;a href=&quot;https://github.com/onnx/onnx/blob/main/docs/Operators.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Operator 목록&lt;/a&gt;은 링크를 통해 확인하실 수 있습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMcVlP/btsLtUlsPXH/RvchKjXDAKNaU57cDAaxm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMcVlP/btsLtUlsPXH/RvchKjXDAKNaU57cDAaxm0/img.png&quot; data-alt=&quot;ONNX Operator Schemas&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMcVlP/btsLtUlsPXH/RvchKjXDAKNaU57cDAaxm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMcVlP%2FbtsLtUlsPXH%2FRvchKjXDAKNaU57cDAaxm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;745&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;745&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ONNX Operator Schemas&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목록을 한 번 살펴보시면 눈치채셨겠지만, 최근 LLM 계열에서 많이 활용하는 RMSNorm이나 RotaryEmbedding 같은 연산들은 아직 ONNX에서 지원하지 않는 것을 확인하실 수 있는데요. 사실 이런 사용자 정의 연산자를 ONNX에서 매번 제공하는 것도 좋은 방향은 아닐 것 같습니다. 해당 연산이 정말로 많이 사용되고 이후에도 계속 사용된다면 괜찮겠지만, 특정 시점에 잠깐 유행하고 대체제가 나온다면 또 해당 연산을 지원해 줘야 하니까요. 우선은 이렇게 지원되지 않는 PyTorch 연산자를 ONNX로 export 하면 어떻게 결과물이 나오는지부터 확인해 보는 것이 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HuggingFace 저장소에 공개되어 있는 GemmaRMSNorm을 export 해보겠습니다. PyTorch에서의 구현체는 다음과 같습니다&lt;/p&gt;
&lt;pre id=&quot;code_1734867588706&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class GemmaRMSNorm(nn.Module):
    def __init__(self, dim: int, eps: float = 1e-6):
        super().__init__()
        self.eps = eps
        self.weight = nn.Parameter(torch.zeros(dim))

    def _norm(self, x):
        return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)

    def forward(self, x):
        output = self._norm(x.float())
        # Llama does x.to(float16) * w whilst Gemma is (x * w).to(float16)
        # See https://github.com/huggingface/transformers/pull/29402
        output = output * (1.0 + self.weight.float())
        return output.type_as(x)

    def extra_repr(self):
        return f&quot;{tuple(self.weight.shape)}, eps={self.eps}&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rsqrt나 pow, mean과 같은 연산의 조합으로 norm을 처리하는 것을 확인할 수 있습니다. 저희의 기대대로라면 RMSNorm이 ONNX 그래프에서도 같이 RMSNorm으로 표현이 된다면 좋겠지만, 아마도 Operator Schemas의 지원 목록에 없었기 때문에 그렇지 않을 것이란 것은 이미 어느 정도 짐작할 수 있는데요. 실제로 ONNX로 export 후 그래프 형태를 Netron으로 시각화해 보면 아래와 같이 나타납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buRT2B/btsLsz99MGd/1XCpF21Zb8wa96ZDo55nr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buRT2B/btsLsz99MGd/1XCpF21Zb8wa96ZDo55nr1/img.png&quot; data-alt=&quot;RMSNorm on ONNX&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buRT2B/btsLsz99MGd/1XCpF21Zb8wa96ZDo55nr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuRT2B%2FbtsLsz99MGd%2F1XCpF21Zb8wa96ZDo55nr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;237&quot; height=&quot;802&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;RMSNorm on ONNX&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원하지 않는 RMSNorm 대신 ONNX에서 현재 지원하는 Unit 연산들, 다시 말해서 Add, ReduceMean, Sqrt, Div와 같은 연산의 조합으로 그래프가 표현되고 있는 것을 확인할 수 있습니다. 이렇게 원본 PyTorch 그래프와 export 된 ONNX 그래프의 개형 차이가 발생하는 경우가 사용자 정의 연산으로 인해 꽤 빈번할 텐데요. 일반적인 Inference 환경에서라면 대부분 큰 문제는 없을 것입니다. Export 과정에서 Graph tracing이 제대로 되었다면 수학적으로 만들어지는 결과는 PyTorch와 ONNX 양쪽 모두에서 같거나 약간의 오차만 있어야 하기 때문입니다. 다만, 우리가 이런 그래프를 Quantization, 특히 Activation Quantization을 진행한다면 생각해야 하는 부분이 꽤 생기는데요. PyTorch에서는 한 개의 연산으로 표현되는 RMSNorm이므로 한 개의 Activation Quantization만을 고려하면 되지만, ONNX에서는 여러 Unit 연산으로 쪼개지므로 예외 처리를 하지 않는 이상 여러 개의 Activation Quantization이 발생하게 되며 이는 아마도 우리가 기대하는 결과와는 꽤 많은 차이를 발생시킬 것 같습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 유스케이스 때문에 PyTorch와 ONNX에서는 사용자 정의 연산을 원하는 형태로 Export 할 수 있는 기능을 제공하는데요. 요약하면 사용자 정의 연산을 torch.autograd.Function을 상속 후 symbolic 함수를 구현해주면 됩니다. PyTorch 문서에서 제공하는 &lt;a href=&quot;https://pytorch.org/docs/stable/onnx_torchscript.html#static-symbolic-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;예제 링크&lt;/a&gt;는 간단한 연산인 ReLU를 예제로 사용하고 있는데요. 이번 포스트에서도 비슷하게 ReLU로 진행해보겠습니다. 우선 다음과 같이 사용자 정의 ReLU를 정의하고 시작하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1734868512144&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ReluFunc(torch.autograd.Function):
    @staticmethod
    def forward(ctx: Any, *args: Any, **kwargs: Any) -&amp;gt; Any:
        inputs = args[0]
        ctx.save_for_backward(inputs)
        return inputs.clamp(min=0)

    @staticmethod
    def symbolic(g: GraphContext, *args: Any) -&amp;gt; torch.Value:
        inputs = args[0]
        return g.op('my_domain::CustomReLU', inputs).setType(inputs.type())


class UserDefinedReLU(nn.Module):
    def forward(self, x: torch.Tensor) -&amp;gt; torch.Tensor:
        return ReluFunc.apply(x)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;torch.autograd.Function을 상속한 ReluFunc를 정의하고 forward 함수와 symbolic을 구현한 것을 볼 수 있습니다. 이 때 symbolic 함수의 시그니처는 &lt;a href=&quot;https://github.com/onnx/tutorials/blob/main/tutorials/PytorchAddExportSupport.md#-export-related-apis-in-pytorch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다음 문서&lt;/a&gt;를 보시면 도움이 될 것 같은데요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sQtXY/btsLriPa4n1/mbNPyaux3tDI7IyANe4hu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sQtXY/btsLriPa4n1/mbNPyaux3tDI7IyANe4hu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sQtXY/btsLriPa4n1/mbNPyaux3tDI7IyANe4hu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsQtXY%2FbtsLriPa4n1%2FmbNPyaux3tDI7IyANe4hu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;611&quot; height=&quot;231&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;symbolic의 첫 번째 인자는 GraphContext이며 그 뒤는 positional arguments를 받습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccE3Pt/btsLsfKUGcB/PKD3b59p4BnufM3ZKxoSnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccE3Pt/btsLsfKUGcB/PKD3b59p4BnufM3ZKxoSnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccE3Pt/btsLsfKUGcB/PKD3b59p4BnufM3ZKxoSnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccE3Pt%2FbtsLsfKUGcB%2FPKD3b59p4BnufM3ZKxoSnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;601&quot; height=&quot;564&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 GraphContext의 op를 정의해서 반환을 해야하는데요. 순서대로 연산자의 이름 (이 때 domain::type_name 형태로 정의할 수 있음)과 positional arguments와 keyword arguments등을 g.op(...)에 채워넣을 수 있습니다. 위 예제에서 저는 우선 도메인은 my_domain 그리고 연산자의 이름은 CustomReLU로 정의했고 ReLU는 간단한 연산이므로 argument는 입력값만 넘겨주면 되겠네요! 뒤의 setType 설정은 쉽게 빠뜨리기 쉬운 부분인데요. &lt;a href=&quot;https://pytorch.org/docs/stable/onnx_torchscript.html#torch.onnx.register_custom_op_symbolic&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyTorch 문서&lt;/a&gt;를 확인하시면 Shape inference를 위해 setType을 설정하기를 권장하고 있는 내용이 나옵니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;When the user registers symbolic for custom/contrib ops, it is highly recommended to add shape inference for that operator via setType API, otherwise the exported graph may have incorrect shape inference in some extreme cases. An example of setType is test_aten_embedding_2 in test_operators.py.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NxMyd/btsLt4BxeBY/nLMbA1HQyDxbhDfenneB80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NxMyd/btsLt4BxeBY/nLMbA1HQyDxbhDfenneB80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NxMyd/btsLt4BxeBY/nLMbA1HQyDxbhDfenneB80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNxMyd%2FbtsLt4BxeBY%2FnLMbA1HQyDxbhDfenneB80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;874&quot; height=&quot;383&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 이제 필요한 작업은 다 한 것 같으니 실제로 export된 CustomReLU의 그래프 형태를 한 번 살펴보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEfLTl/btsLrkGd2ak/t8ihmkhcZQcoNcKKKSuAe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEfLTl/btsLrkGd2ak/t8ihmkhcZQcoNcKKKSuAe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEfLTl/btsLrkGd2ak/t8ihmkhcZQcoNcKKKSuAe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEfLTl%2FbtsLrkGd2ak%2Ft8ihmkhcZQcoNcKKKSuAe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;829&quot; height=&quot;548&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 PyTorch 코드에서 정의한 domain과 type이 잘 설정된 것을 확인할 수 있네요 :) 만약에 symboilc 함수를 정의하지 않고 export하면 어떻게 나오는 지도 한 번 확인해봐야겠죠? 결과는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;561&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhCyf/btsLscUYGw5/p25WXayfR0Z2SpSey3EDt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhCyf/btsLscUYGw5/p25WXayfR0Z2SpSey3EDt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhCyf/btsLscUYGw5/p25WXayfR0Z2SpSey3EDt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhCyf%2FbtsLscUYGw5%2Fp25WXayfR0Z2SpSey3EDt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;825&quot; height=&quot;561&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;561&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 symbolic 함수를 정의하지 않은 CustomReLU에 대해서는 ONNX가 기존에 지원하는 Unit 연산 중 하나인 Clip으로 그래프가 표현되고 있는 것을 확인할 수 있습니다. 포스트에서는 간단한 ReLU에 대해서만 진행해봤지만, 필요하다면 더 복잡한 연산에 대해서도 당연히 symbolic을 정의 후 ONNX export 할 수 있습니다. 본문의 RMSNorm과 같은 연산을 하나의 연산으로 export 하는 것은 과제로 남겨두겠습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 다음과 같은 내용을 다뤘습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ONNX에서 지원하는 Operator 목록&lt;/li&gt;
&lt;li&gt;PyTorch의 사용자 정의 연산을 export할 때 ONNX 그래프의 개형&lt;/li&gt;
&lt;li&gt;PyTorch 사용자 정의 연산을 원하는 형태로 export 하기 위한 symbolic 정의&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발 이야기/Machine learning</category>
      <category>onnx</category>
      <category>pytorch</category>
      <category>symbolic</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/185</guid>
      <comments>https://iostream.tistory.com/185#entry185comment</comments>
      <pubDate>Sun, 22 Dec 2024 20:31:07 +0900</pubDate>
    </item>
    <item>
      <title>Stable Diffusion 3 ONNX Export 트러블 슈팅</title>
      <link>https://iostream.tistory.com/184</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 업무 중 발생했던 Stable Diffusion 3 모델의 ONNX Export 과정에서 발생했던 이슈와 해결 방법에 대해서 공유해보려고 합니다. Qualcomm의 하드웨어에 AI/ML 모델을 배포하기 위해서 &lt;a href=&quot;https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-2/introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Qualcomm&amp;reg; Neural Processing SDK&lt;/a&gt;를 활용하는데요. 해당 SDK에서 제공하는 도구 중 Converter는 여러 가지 프레임워크 (e.g., ONNX, TensorFlow, ...) 를 지원하지만, 대체로 ONNX를 많이 활용하고 있습니다. 아마도 요즘 대부분의 Researcher들이 익숙한 딥러닝 프레임워크가 PyTorch고 PyTorch에서 ONNX Export는 간편하게 지원하는 것이 첫 번째 이유일 것이라고 짐작하며, 두 번째로는 ONNX를 활용함으로써 얻을 수 있는 공짜 점심들이 있기 때문일 것입니다. ONNX 자체적으로 지원하는 &lt;a href=&quot;https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;최적화&lt;/a&gt; (Constant Folding, Graph Fusion, ...) 외에도 &lt;a href=&quot;https://github.com/daquexian/onnx-simplifier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;onnx-simplifier&lt;/a&gt; 같은 도구를 통해서도 여러 가지 검증된 최적화를 수행할 수 있기 때문입니다. 즉, ONNX를 사용하지 않을 이유는 그렇게 많지 않다고 생각되고, 이런 최적화에 관한 내용은 이번 글의 주제를 조금 벗어나기 때문에 앞으로 따로 글을 써보도록 하겠습니다. 여하튼 이러한 이유로 오픈 소스로 제공되는 모델 자체 또는 그것을 어느 정도 Fine-tuning 한 모델을 ONNX로 먼저 Export 하는 것이 최우선 단계일 텐데요. 해당 과정부터 무언가 문제가 있다는 얘기를 다른 팀 엔지니어로부터 전해 들었고 그 원인을 파악해 보았습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stable Diffusion 3 모델 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Stable Diffusion 3의 모델 구조에 대해서 간략하게 설명하고 넘어가야할 것 같은데요. Stable Diffusion에 익숙하신 분들이라면 대부분 이 모델의 구조가 Text Encoder, UNet, 그리고 VAE의 조합으로 구성된 것을 어느 정도 잘 알고 계실 것 같습니다. Stable Diffusion 3도 큰 틀에서의 구조는 변함은 없지만 세세한 부분에서 변경사항이 좀 있는데요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ruaqM/btsKTZhOgJr/3AUk63tKvviT8t3KcaRfZ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ruaqM/btsKTZhOgJr/3AUk63tKvviT8t3KcaRfZ0/img.jpg&quot; data-alt=&quot;https://encord.com/blog/stable-diffusion-3-text-to-image-model/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ruaqM/btsKTZhOgJr/3AUk63tKvviT8t3KcaRfZ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FruaqM%2FbtsKTZhOgJr%2F3AUk63tKvviT8t3KcaRfZ0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;607&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://encord.com/blog/stable-diffusion-3-text-to-image-model/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림과 같이 3 종류의 Text Encoder를 사용하고 있으며, UNet 대신 MM-DiT를 활용하는 점이 이전 Stable Diffusion의 모델 구조와의 차이점이라고 볼 수 있을 것 같습니다. HuggingFace의 아래 모델 Definition을 보면 조금 더 이해에 도움이 될 것 같네요!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tm6hL/btsKTnXVacO/mHkSyKOKIpCJpXVHn23el1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tm6hL/btsKTnXVacO/mHkSyKOKIpCJpXVHn23el1/img.png&quot; data-alt=&quot;https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion_3/pipeline_stable_diffusion_3.py#L131&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tm6hL/btsKTnXVacO/mHkSyKOKIpCJpXVHn23el1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTm6hL%2FbtsKTnXVacO%2FmHkSyKOKIpCJpXVHn23el1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;453&quot; data-origin-width=&quot;821&quot; data-origin-height=&quot;656&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/stable_diffusion_3/pipeline_stable_diffusion_3.py#L131&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stable Diffusion 3 그 자체에 대해서는 또 글이 너무 길어질 것 같아서 이번 글에서는 모델 구조에 대해서만 간략하게 얘기하고 넘어가겠습니다. 좀 더 자세한 내용이 필요하신 분들은 stability.ai의 &lt;a href=&quot;https://stability.ai/news/stable-diffusion-3-research-paper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;research paper&lt;/a&gt;와 위 그림의 출처인 &lt;a href=&quot;https://encord.com/blog/stable-diffusion-3-text-to-image-model&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://encord.com/blog/stable-diffusion-3-text-to-image-model&lt;/a&gt; 링크를 참고하세요. 문제가 되는 컴포넌트는 MM-DiT였는데요. 어떤 Error가 발생했는지 밑에서 좀 더 자세히 설명하도록 하겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Error 내용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전달 받은 Error는 그래프 내부에 특정 Tensor의 이름이 비어있고, 그것이 Graph Compile 과정에서 에러를 발생시킨다는 내용이었는데요. AI/ML 모델 시각화로 많이 사용하는 &lt;a href=&quot;https://github.com/lutzroeder/netron&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Netron&lt;/a&gt; 을 활용해서 정말로 그런 노드가 존재하는 지 확인을 해보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eb77A0/btsKTX5ofpY/l7ckiWnpg21UdhfkS703FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eb77A0/btsKTX5ofpY/l7ckiWnpg21UdhfkS703FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eb77A0/btsKTX5ofpY/l7ckiWnpg21UdhfkS703FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feb77A0%2FbtsKTX5ofpY%2Fl7ckiWnpg21UdhfkS703FK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;346&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 Tensor부터 거슬러가다보니 생각보다 빠르게 수상한 노드를 찾을 수 있었는데요. 다름 아닌 LayerNormalization 노드였습니다. 이제 수상한 노드를 찾았으니 실제 코드가 어떤식으로 구성되어있는지 찾아보면 문제를 해결할 수 있을 것 같네요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MM-DiT의 모델의 &lt;a href=&quot;https://github.com/huggingface/diffusers/blob/7ac6e286ee994270e737b70c904ea50049d53567/src/diffusers/models/transformers/transformer_sd3.py#L263&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;forward pass&lt;/a&gt;를 보니 JointTransformerBlock 를 순회하고 있고, JointTransformerBlock은 아래와 같이 self.norm1을 가장 먼저 통과하게 되는데 이번 경우는 AdaLayerNormZero를 사용하고 있습니다. 거의 다 온 것 같은데요!&lt;/p&gt;
&lt;pre id=&quot;code_1732438263401&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class JointTransformerBlock(nn.Module):
    r&quot;&quot;&quot;
    A Transformer block following the MMDiT architecture, introduced in Stable Diffusion 3.

    Reference: https://arxiv.org/abs/2403.03206
    이하 중략
    &quot;&quot;&quot;

    def __init__(
        self,
        dim: int,
        num_attention_heads: int,
        attention_head_dim: int,
        context_pre_only: bool = False,
        qk_norm: Optional[str] = None,
        use_dual_attention: bool = False,
    ):
        super().__init__()

        self.use_dual_attention = use_dual_attention
        self.context_pre_only = context_pre_only
        context_norm_type = &quot;ada_norm_continous&quot; if context_pre_only else &quot;ada_norm_zero&quot;

        if use_dual_attention:
            self.norm1 = SD35AdaLayerNormZeroX(dim)
        else:
            self.norm1 = AdaLayerNormZero(dim)
        # ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 레이어의 Definition이 눈에 띄네요. 아래와 같이 elementwise_affine=False로 주고 있고 이는 일반적인 LayerNormalization layer의 인자와 다른 값입니다. 기본값은 elementwise_affine=True죠. 이제 원인을 거의 다 찾은 것 같습니다. 아마도 LayerNorm에 대한 PyTorch 문서만 확인해보면 될 것 같네요 :)&lt;/p&gt;
&lt;pre id=&quot;code_1732438336513&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class AdaLayerNormZero(nn.Module):
    r&quot;&quot;&quot;
    Norm layer adaptive layer norm zero (adaLN-Zero).

    Parameters:
        embedding_dim (`int`): The size of each embedding vector.
        num_embeddings (`int`): The size of the embeddings dictionary.
    &quot;&quot;&quot;

    def __init__(self, embedding_dim: int, num_embeddings: Optional[int] = None, norm_type=&quot;layer_norm&quot;, bias=True):
        super().__init__()
        if num_embeddings is not None:
            self.emb = CombinedTimestepLabelEmbeddings(num_embeddings, embedding_dim)
        else:
            self.emb = None

        self.silu = nn.SiLU()
        self.linear = nn.Linear(embedding_dim, 6 * embedding_dim, bias=bias)
        if norm_type == &quot;layer_norm&quot;:
            self.norm = nn.LayerNorm(embedding_dim, elementwise_affine=False, eps=1e-6)
        elif norm_type == &quot;fp32_layer_norm&quot;:
            self.norm = FP32LayerNorm(embedding_dim, elementwise_affine=False, bias=False)
        else:
            raise ValueError(
                f&quot;Unsupported `norm_type` ({norm_type}) provided. Supported ones are: 'layer_norm', 'fp32_layer_norm'.&quot;
            )
		# 중략&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyTorch 공식 문서의 LayerNorm Parameter에 대한 설명은 아래와 같습니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9O8v1/btsKTYJYXhx/i2dzckBgB7oIXTUYIPaFXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9O8v1/btsKTYJYXhx/i2dzckBgB7oIXTUYIPaFXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9O8v1/btsKTYJYXhx/i2dzckBgB7oIXTUYIPaFXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9O8v1%2FbtsKTYJYXhx%2Fi2dzckBgB7oIXTUYIPaFXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;785&quot; height=&quot;381&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;elementwise_affine은 기본값이 True이며 이는 scale과 zero_point를 각각 learnable parameter로 초기화한다고 되어있습니다. 따라서 해당 값을 False로 주게되면 scale과 zero_point에 대한 Tensor의 이름이 제대로 채워지지 않았을 것이라고 추측할 수 있었습니다. 이에 대한 부분은 사실 ONNX Export의 책임이므로 저희가 어떻게 해결하기는 어려운 문제였는데요. 다만 저희는 pre-trained 모델을 사용하고 향후에 QAT와 같은 fine-tuning의 요구사항이 없었기 때문에 아래와 같은 Workaround를 적용해서 문제를 해결했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Workaround&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 해결은 심플했는데요. PyTorch 모델을 순회하면서 nn.Module 중 LayerNorm이면서 elementwise_affine이 False로 설정되어있는 경우 해당 Flag를 변경하고, scale와 zero_point를 적절히 채워주었습니다. 코드 스니펫은 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732438741579&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for name, module in model.named_modules():
    if isinstance(module, nn.LayerNorm) and not module.elementwise_affine:
        module.weight = nn.Parameter(torch.ones(module.normalized_shape))
        module.bias = nn.Parameter(torch.zeros(module.normalized_shape))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식 상 weight * inputs + bias이므로 weight과 bias를 각각 1과 0으로 명시적 초기화하면 math invariant하기 때문에 문제가 발생하지 않습니다! 위와 같은 임시 해결책을 이슈를 공유한 엔지니어에게 전달하고 무사히 ONNX Export 및 Graph compile을 완료할 수 있었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Key takeaways&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결&amp;nbsp;방법이&amp;nbsp;생각보다&amp;nbsp;쉬워서&amp;nbsp;김이&amp;nbsp;좀&amp;nbsp;빠지셨나요?&amp;nbsp;실제로&amp;nbsp;위와&amp;nbsp;같은&amp;nbsp;이슈는&amp;nbsp;최신&amp;nbsp;PyTorch&amp;nbsp;및&amp;nbsp;ONNX&amp;nbsp;환경에서는&amp;nbsp;발생하지&amp;nbsp;않는&amp;nbsp;것으로&amp;nbsp;보입니다.&amp;nbsp;다만,&amp;nbsp;우리가&amp;nbsp;작업하는&amp;nbsp;환경이&amp;nbsp;항상&amp;nbsp;최신&amp;nbsp;버전을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없으므로&amp;nbsp;필요하다면&amp;nbsp;직접&amp;nbsp;소스&amp;nbsp;코드를&amp;nbsp;백포팅하거나&amp;nbsp;위와&amp;nbsp;같은&amp;nbsp;Workaround를&amp;nbsp;활용해야&amp;nbsp;할&amp;nbsp;때가&amp;nbsp;있음을&amp;nbsp;인지하고&amp;nbsp;있으면&amp;nbsp;좋겠죠?&amp;nbsp;이번&amp;nbsp;이슈&amp;nbsp;트러블슈팅에서의&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;Key&amp;nbsp;takeaway는&amp;nbsp;아래와&amp;nbsp;같았습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그를 잘 확인하자. 로그를 통해서 Tensor 이름이 비어 있는 값임을 알 수 있었다&lt;/li&gt;
&lt;li&gt;시각화 도구 (e.g., Netron 등)를 잘 활용하면 가시적으로 문제를 파악하는 데 도움이 된다&lt;/li&gt;
&lt;li&gt;상황에 따라 우리가 의존하는 패키지를 직접 수정하기 어려운 때도 있다. 이럴 때는 요구 사항을 잘 확인한 후 적절한 Workaround를 제공하는 유연함이 필요하다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발 이야기/Machine learning</category>
      <category>onnx</category>
      <author>가마뫼</author>
      <guid isPermaLink="true">https://iostream.tistory.com/184</guid>
      <comments>https://iostream.tistory.com/184#entry184comment</comments>
      <pubDate>Sun, 24 Nov 2024 17:06:47 +0900</pubDate>
    </item>
  </channel>
</rss>