<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_halo.log</title>
        <link>https://velog.io/</link>
        <description>일단 해보자 !</description>
        <lastBuildDate>Mon, 09 Sep 2024 01:24:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dev_halo.log</title>
            <url>https://images.velog.io/images/dev_halo/profile/c6bb192d-0d06-4bd4-84bb-f356f84c2a4e/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dev_halo.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_halo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Ngrok]]></title>
            <link>https://velog.io/@dev_halo/Ngrok</link>
            <guid>https://velog.io/@dev_halo/Ngrok</guid>
            <pubDate>Mon, 09 Sep 2024 01:24:24 GMT</pubDate>
            <description><![CDATA[<pre><code>curl -sSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \
    | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc &gt;/dev/null \
    &amp;&amp; echo &quot;deb https://ngrok-agent.s3.amazonaws.com buster main&quot; \
    | sudo tee /etc/apt/sources.list.d/ngrok.list \
    &amp;&amp; sudo apt update \
    &amp;&amp; sudo apt install ngrok</code></pre><pre><code>ngrok config add-authtoken $YOUR_AUTHTOKEN</code></pre><pre><code>ngrok start --config &quot;/root/.config/ngrok/ngrok.yml&quot; --all</code></pre><pre><code>authtoken: ${PERSONAL_AUTH_TOKEN}
tunnels:
  jupyter:
    proto: http
    addr: 8888
  test1:
    proto: http
    addr: 7474
  test2:
    proto: http
    addr: 7687</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[deepspeed Learning Rate Scheduler list]]></title>
            <link>https://velog.io/@dev_halo/deepspeed-Learning-Rate-Scheduler-list</link>
            <guid>https://velog.io/@dev_halo/deepspeed-Learning-Rate-Scheduler-list</guid>
            <pubDate>Fri, 05 Jul 2024 00:18:25 GMT</pubDate>
            <description><![CDATA[<p><a href="https://deepspeed.readthedocs.io/en/latest/schedulers.html">LR Scheduler</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[jupyter kernel]]></title>
            <link>https://velog.io/@dev_halo/jupyter-kernel</link>
            <guid>https://velog.io/@dev_halo/jupyter-kernel</guid>
            <pubDate>Thu, 23 Nov 2023 00:54:41 GMT</pubDate>
            <description><![CDATA[<p>ipykernel 설치</p>
<pre><code>pip install ipykernel</code></pre><p>가상환경 생성</p>
<pre><code>python -m venv 가상환경이름</code></pre><p>가상환경 시작</p>
<pre><code>source 가상환경이름/bin/activate</code></pre><p>가상환경 종료</p>
<pre><code>deactivate</code></pre><p>커널 추가</p>
<pre><code>python -m ipykernel install --user --name 가상환경이름 --display-name &quot;화면에보여질가상환경이름&quot;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[CLOVA X 리뷰]]></title>
            <link>https://velog.io/@dev_halo/CLOVA-X-%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@dev_halo/CLOVA-X-%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Tue, 29 Aug 2023 01:58:39 GMT</pubDate>
            <description><![CDATA[<h1 id="clova-x-리뷰">CLOVA X 리뷰</h1>
<p>3일을 기다려 CLOVA X의 대기가 끝났습니다.</p>
<p>리뷰 해봅시다.</p>
<h1 id="1-main">1. main</h1>
<h3 id="middle">middle</h3>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/f61e782d-6936-4c00-8389-05314110e38f/image.png" alt=""></p>
<h3 id="side">side</h3>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/2667474f-060f-44f9-ac05-82379b491677/image.png" alt=""></p>
<p>전형적인 요즘 chat 사이트 모습입니다.</p>
<h1 id="2-chat">2. chat</h1>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/cd0b63b8-2642-4104-84b1-acfd775a31a8/image.png" alt=""></p>
<p>무난합니다.</p>
<h2 id="할루시네이션">할루시네이션</h2>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/af4eeb07-dd06-4bdc-b41c-dd62ab864cf8/image.png" alt=""></p>
<p>P의 거짓이란 게임이 있는데 할루시네이션이 벌써 보입니다.</p>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/bbd87b1e-9e62-4b01-918e-9cbf48137cd3/image.png" alt=""></p>
<p>다시 올바른 질문을 하니 링크도 제대로 주고 그럴듯 합니다.</p>
<h2 id="최신-정보">최신 정보</h2>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/cf082f87-6391-4a95-bc3e-fb7e0d37fc2d/image.png" alt=""></p>
<p>최근 공개된 마스크걸에 대한 최신 정보도 제공합니다. chatgpt와 다르게 검색기능을 포함했기 때문에 최신 정보를 빠르게 제공해주는 강점을 갖고 있습니다.</p>
<h1 id="in-context-learning">In-Context Learning</h1>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/c89839a2-f45e-42b4-87ae-45ec22bce28a/image.png" alt=""></p>
<p>유저와의 상호작용이 불가능합니다. </p>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/d4261b31-1e49-4a22-bbea-4bce560acae9/image.png" alt=""></p>
<p>chatGPT의 경우 In-Context Learning이 가능하지만 CLOVA X는 불가능한 모습입니다.</p>
<h3 id="data-augmentation">Data Augmentation</h3>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/7061e09c-b497-4a1f-b95d-487d91a67841/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/e6638786-ac65-44f1-9e3a-c7b86012c75c/image.png" alt=""></p>
<p>데이터 증강을 요청했지만 chatGPT는 잘 생성해주는 것에 비해 CLOVA X는 전혀 못하고 있습니다.</p>
<h1 id="clova-x-skill">CLOVA X Skill</h1>
<p>CLOVA X 에선 네이버의 플랫폼을 chat과 연동하여 검색하는 기술을 SKILL 이라고 부르고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/476c0e8c-92fe-44d3-9b16-2d8a9bb1d390/image.png" alt=""></p>
<h1 id="결론">결론</h1>
<p>생성형 모델 자체로만 보면 chatGPT가 우월합니다. 하지만 정보의 출처를 제공하고, 본인들의 서비스에 녹여낸 상태를 보면 역시 네이버라고 생각됩니다. 아직 베타이기에 완전히 공개된게 아닐 것이라 생각됩니다. </p>
<p>CLOVA 화이팅</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[git bash conda activate]]></title>
            <link>https://velog.io/@dev_halo/git-bash-conda-activate</link>
            <guid>https://velog.io/@dev_halo/git-bash-conda-activate</guid>
            <pubDate>Wed, 09 Aug 2023 04:31:13 GMT</pubDate>
            <description><![CDATA[<h1 id="miniconda">miniconda</h1>
<pre><code>source ~/miniconda3/etc/profile.d/conda.sh</code></pre><h1 id="anaconda">anaconda</h1>
<pre><code>source ~/anaconda3/etc/profile.d/conda.sh</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[문서 생성요약기를 만들어보자(with BART Huggingface)]]></title>
            <link>https://velog.io/@dev_halo/%EC%83%9D%EC%84%B1%EC%9A%94%EC%95%BD%EA%B8%B0</link>
            <guid>https://velog.io/@dev_halo/%EC%83%9D%EC%84%B1%EC%9A%94%EC%95%BD%EA%B8%B0</guid>
            <pubDate>Tue, 07 Feb 2023 04:03:19 GMT</pubDate>
            <description><![CDATA[<h1 id="kobart">KoBART</h1>
<p>Huggingface🤗 Trainer를 활용하여 BART 한글 문서 생성 요약 Finetune 해보기</p>
<p>최대한 default 값 없이 재현하고 싶어서 작성한 BART Huggingface Fine tuning 코드</p>
<h1 id="data">Data</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/216853537-442e05eb-1ad5-4cff-92da-5e1f36cebf58.png" alt="image"></p>
<h1 id="결과물">결과물</h1>
<pre><code class="language-python">def infer(text):
    if type(text) == int:
        out = model.generate(input_ids = torch.tensor(train_dataset[text][&#39;input_ids&#39;])[None,:].to(device)).logits.argmax(2)
        result = tokenizer.decode(out[0])
    else:
        tmp = [tokenizer.bos_token_id] + tokenizer.encode(text) + [tokenizer.eos_token_id]
        out = model.generate(input_ids = torch.tensor(tmp)[None,:].to(device))
        result = tokenizer.decode(out[0])
    return print(result)
text = &quot;&quot;&quot;1일 오후 9시까지 최소 20만3220명이 코로나19에 신규 확진됐다. 
또다시 동시간대 최다 기록으로, 사상 처음 20만명대에 진입했다. 
방역 당국과 서울시 등 각 지방자치단체에 따르면 이날 0시부터 오후 9시까지 전국 신규 확진자는 총 20만3220명으로 집계됐다. 
국내 신규 확진자 수가 20만명대를 넘어선 것은 이번이 처음이다. 
동시간대 최다 기록은 지난 23일 오후 9시 기준 16만1389명이었는데, 이를 무려 4만1831명이나 웃돌았다. 
전날 같은 시간 기록한 13만3481명보다도 6만9739명 많다. 
확진자 폭증은 3시간 전인 오후 6시 집계에서도 예견됐다. 
오후 6시까지 최소 17만8603명이 신규 확진돼 동시간대 최다 기록(24일 13만8419명)을 갈아치운 데 이어 이미 직전 0시 기준 역대 최다 기록도 넘어섰다. 
역대 최다 기록은 지난 23일 0시 기준 17만1451명이었다. 
17개 지자체별로 보면 서울 4만6938명, 경기 6만7322명, 인천 1만985명 등 수도권이 12만5245명으로 전체의 61.6%를 차지했다. 
서울과 경기는 모두 동시간대 기준 최다로, 처음으로 각각 4만명과 6만명을 넘어섰다. 
비수도권에서는 7만7975명(38.3%)이 발생했다. 
제주를 제외한 나머지 지역에서 모두 동시간대 최다를 새로 썼다. 
부산 1만890명, 경남 9909명, 대구 6900명, 경북 6977명, 충남 5900명, 대전 5292명, 전북 5150명, 울산 5141명, 광주 5130명, 전남 4996명, 강원 4932명, 충북 3845명, 제주 1513명, 세종 1400명이다. 
집계를 마감하는 자정까지 시간이 남아있는 만큼 2일 0시 기준으로 발표될 신규 확진자 수는 이보다 더 늘어날 수 있다. 이에 따라 최종 집계되는 확진자 수는 21만명 안팎을 기록할 수 있을 전망이다. 
한편 전날 하루 선별진료소에서 이뤄진 검사는 70만8763건으로 검사 양성률은 40.5%다. 
양성률이 40%를 넘은 것은 이번이 처음이다. 
확산세가 계속 거세질 수 있다는 얘기다. 
이날 0시 기준 신규 확진자는 13만8993명이었다. 이틀 연속 13만명대를 이어갔다.&quot;&quot;&quot;
infer(text)
&lt;/s&gt;&lt;s&gt; 코로나19 사상 처음 20만 이상 인구가 신규 확진되었다.&lt;/s&gt;</code></pre>
<h1 id="score">Score</h1>
<p>2 rows val_dataset으로 측정했기 때문에 완전한 score가 아닙니다 !</p>
<table>
<thead>
<tr>
<th>Score</th>
<th>Rouge-1</th>
<th>Rouge-2</th>
<th>Rouge-L</th>
</tr>
</thead>
<tbody><tr>
<td>Recall</td>
<td>1.0</td>
<td>1.0</td>
<td>1.0</td>
</tr>
<tr>
<td>Precision</td>
<td>1.0</td>
<td>1.0</td>
<td>1.0</td>
</tr>
<tr>
<td>F1_score</td>
<td>0.99</td>
<td>0.99</td>
<td>0.99</td>
</tr>
</tbody></table>
<h1 id="깨달은점">깨달은점</h1>
<ul>
<li>초기 lr 1e-3 no scheduler 환경에서 학습이 전혀 진행되지 않아 모델 자체의 문제라고 생각했지만, lr과 scheduler warmup을 작성해주니 학습이 잘된점에서 깨달음을 얻음</li>
</ul>
<p>초기</p>
<p><img src="https://user-images.githubusercontent.com/44603549/216854384-ab1d76e8-ecf8-4561-bcd9-1b535e2ad80b.PNG" alt="캡처"></p>
<p>lr, scheduler 적용 후</p>
<p><img src="https://user-images.githubusercontent.com/44603549/216854421-b6cf89eb-53c0-4ff2-8f43-0d5bfbbed854.png" alt="image"></p>
<ul>
<li>당연하지만 인풋의 길이가 모델의 길이와 다르면 이상한 결과가 나옴</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/44603549/216854469-09498c67-6328-4c26-93ef-ddcd81dd2883.png" alt="image"></p>
<h1 id="reference">Reference</h1>
<p><a href="https://github.com/HaloKim/KorBARTSum">Github</a></p>
<p><a href="https://github.com/seujung/KoBART-summarization/tree/main/data">학습에 사용한 데이터</a></p>
<p><a href="https://huggingface.co/gogamza/kobart-base-v1">gogamza/kobart-base-v1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dacon 성균관대 문장 유형 분류 AI 경진대회 1등]]></title>
            <link>https://velog.io/@dev_halo/Dacon-%EC%84%B1%EA%B7%A0%EA%B4%80%EB%8C%80-%EB%AC%B8%EC%9E%A5-%EC%9C%A0%ED%98%95-%EB%B6%84%EB%A5%98-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-1%EB%93%B1</link>
            <guid>https://velog.io/@dev_halo/Dacon-%EC%84%B1%EA%B7%A0%EA%B4%80%EB%8C%80-%EB%AC%B8%EC%9E%A5-%EC%9C%A0%ED%98%95-%EB%B6%84%EB%A5%98-AI-%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C-1%EB%93%B1</guid>
            <pubDate>Wed, 18 Jan 2023 12:58:10 GMT</pubDate>
            <description><![CDATA[<h1 id="문장-유형-분류-ai-경진대회"><a href="https://dacon.io/competitions/official/236037/overview/description">문장 유형 분류 AI 경진대회</a></h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213177200-5193d1d7-3801-41ac-9255-4e4280836b6c.png" alt="image"></p>
<h1 id="대회정보">대회정보</h1>
<h2 id="주제">주제</h2>
<p>문장 유형 분류 AI 모델 개발</p>
<h2 id="설명">설명</h2>
<p>언어가 사용되는 모든 영역에서 폭넓게 활용될 수 있는 문장 유형 분류 AI 모델을 개발해 주세요.</p>
<ul>
<li>문장을 입력으로 받아 문장의 &#39;유형&#39;, &#39;시제&#39;, &#39;극성&#39;, &#39;확실성&#39;을 AI 분류 모델 생성</li>
</ul>
<h2 id="주최주관">주최/주관</h2>
<ul>
<li>주최: 성균관대학교</li>
<li>주관: 데이콘</li>
</ul>
<h2 id="참가-자격">참가 자격</h2>
<ul>
<li>일반인, 학생 등 누구나</li>
</ul>
<h1 id="데이터">데이터</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166135-04d3de9d-5920-4f00-8868-0c72f8a89504.png" alt="image"></p>
<p><img src="https://user-images.githubusercontent.com/44603549/213166217-ef1d882d-fb04-4595-bbe3-9f53aafab0fe.png" alt="image"></p>
<h1 id="성능-개선을-위한-시도">성능 개선을 위한 시도</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166340-ca2db899-bbc8-427e-82fd-a4e8eaabfb86.png" alt="image"></p>
<h1 id="전처리">전처리</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166411-d47b1a5f-a45b-48d0-bbe1-574a7ad42b3c.png" alt="image"></p>
<h1 id="text-augmentation">Text Augmentation</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166443-d839aa67-898f-46e4-8711-f9e82f030317.png" alt="image"></p>
<h1 id="loss">Loss</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213177405-d56843ae-1757-405a-a8e7-9ef1c71ba027.png" alt="image"></p>
<p><img src="https://user-images.githubusercontent.com/44603549/213177415-4f90c74e-47e0-48fc-a31f-592c7e0994f9.png" alt="image"></p>
<p><img src="https://user-images.githubusercontent.com/44603549/213177425-1a574a65-c567-4732-aa05-7f12ef9cc3bb.png" alt="image"></p>
<h1 id="custom-model">Custom Model</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166509-5c368d8b-8c32-43f1-96d7-afc27545bfce.png" alt="image"></p>
<h1 id="사용한-사전학습모델과-출처">사용한 사전학습모델과 출처</h1>
<p><img src="https://user-images.githubusercontent.com/44603549/213166597-7b8efb71-5f26-4f09-b2a7-787b919c7ed2.png" alt="image"></p>
<h1 id="code">Code</h1>
<p><a href="https://github.com/HaloKim/Competitions/tree/main/%5BDacon%5D%EB%AC%B8%EC%9E%A5%EC%9C%A0%ED%98%95%EB%B6%84%EB%A5%98AI%EA%B2%BD%EC%A7%84%EB%8C%80%ED%9A%8C">Github</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[For HuggingFace Custom CosineAnnealingWarmUpRestarts]]></title>
            <link>https://velog.io/@dev_halo/For-HuggingFace-Custom-CosineAnnealingWarmUpRestarts</link>
            <guid>https://velog.io/@dev_halo/For-HuggingFace-Custom-CosineAnnealingWarmUpRestarts</guid>
            <pubDate>Fri, 16 Dec 2022 04:54:31 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>Huggingface Custom Trainer 작성중에 lr을 정하기 위해 scheduler를 확인 중이었는데 좋은 블로그가 나와서 사용해보았습니다. 그런데 추천하신 스케쥴러가 custom으로 작성하신 코드였는데 Huggingfcace에 적용해보니 에러가 나와서 수정하였습니다.</p>
<h1 id="본론">본론</h1>
<pre><code class="language-python">class CosineAnnealingWarmUpRestarts(_LRScheduler):
    def __init__(self, optimizer, T_0, T_mult=1, eta_max=0.1, T_up=0, gamma=1., last_epoch=-1):
        if T_0 &lt;= 0 or not isinstance(T_0, int):
            raise ValueError(&quot;Expected positive integer T_0, but got {}&quot;.format(T_0))
        if T_mult &lt; 1 or not isinstance(T_mult, int):
            raise ValueError(&quot;Expected integer T_mult &gt;= 1, but got {}&quot;.format(T_mult))
        if T_up &lt; 0 or not isinstance(T_up, int):
            raise ValueError(&quot;Expected positive integer T_up, but got {}&quot;.format(T_up))
        self.T_0 = T_0
        self.T_mult = T_mult
        self.base_eta_max = eta_max
        self.eta_max = eta_max
        self.T_up = T_up
        self.T_i = T_0
        self.gamma = gamma
        self.cycle = 0
        self.T_cur = last_epoch
        super(CosineAnnealingWarmUpRestarts, self).__init__(optimizer, last_epoch)

    def get_lr(self):
        if self.T_cur == -1:
            return self.base_lrs
        elif self.T_cur &lt; self.T_up:
            return [(self.eta_max - base_lr)*self.T_cur / self.T_up + base_lr for base_lr in self.base_lrs]
        else:
            return [base_lr + (self.eta_max - base_lr) * (1 + math.cos(math.pi * (self.T_cur-self.T_up) / (self.T_i - self.T_up))) / 2
                    for base_lr in self.base_lrs]

    def step(self, epoch=None):
        if epoch is None:
            epoch = self.last_epoch + 1
            self.T_cur = self.T_cur + 1
            if self.T_cur &gt;= self.T_i:
                self.cycle += 1
                self.T_cur = self.T_cur - self.T_i
                self.T_i = (self.T_i - self.T_up) * self.T_mult + self.T_up
        else:
            if epoch &gt;= self.T_0:
                if self.T_mult == 1:
                    self.T_cur = epoch % self.T_0
                    self.cycle = epoch // self.T_0
                else:
                    n = int(math.log((epoch / self.T_0 * (self.T_mult - 1) + 1), self.T_mult))
                    self.cycle = n
                    self.T_cur = epoch - self.T_0 * (self.T_mult ** n - 1) / (self.T_mult - 1)
                    self.T_i = self.T_0 * self.T_mult ** (n)
            else:
                self.T_i = self.T_0
                self.T_cur = epoch

        self.eta_max = self.base_eta_max * (self.gamma**self.cycle)
        self.last_epoch = math.floor(epoch)
        for param_group, lr in zip(self.optimizer.param_groups, self.get_lr()):
            param_group[&#39;lr&#39;] = lr</code></pre>
<h1 id="결론">결론</h1>
<p>잘 돌아갑니다.</p>
<h1 id="출처">출처</h1>
<p><a href="https://gaussian37.github.io/dl-pytorch-lr_scheduler/">Pytorch Learning Rate Scheduler</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[청와대 국민청원(청무위키) 데이터 덤프를 떠보자]]></title>
            <link>https://velog.io/@dev_halo/%EC%B2%AD%EC%99%80%EB%8C%80-%EA%B5%AD%EB%AF%BC%EC%B2%AD%EC%9B%90%EC%B2%AD%EB%AC%B4%EC%9C%84%ED%82%A4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8D%A4%ED%94%84%EB%A5%BC-%EB%96%A0%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/%EC%B2%AD%EC%99%80%EB%8C%80-%EA%B5%AD%EB%AF%BC%EC%B2%AD%EC%9B%90%EC%B2%AD%EB%AC%B4%EC%9C%84%ED%82%A4-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8D%A4%ED%94%84%EB%A5%BC-%EB%96%A0%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 07 Dec 2022 05:19:15 GMT</pubDate>
            <description><![CDATA[<h1 id="bluehouse_petitions">bluehouse_petitions</h1>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/91fb3f31-0cdf-4c31-92cd-50058e117e95/image.png" alt=""></p>
<p>문재인 전 대통령 청와대 국민청원 데이터 청와대 기록실을 통한 덤프</p>
<p>python lxml 기반으로 작성하였으며, 병렬 크롤링을 위해 ray를 활용하여 데이터를 수집하였습니다.</p>
<p>본인의 컴퓨터 스펙에 맞게 파라미터를 수정해주세요.</p>
<p>데이터 분석을 위해 전처리는 최소로 작성하였습니다.</p>
<pre><code>worker = 16
size = 3000</code></pre><h1 id="requirements">Requirements</h1>
<pre><code class="language-python">pip install ray requests</code></pre>
<h1 id="data-shape">Data Shape</h1>
<table>
<thead>
<tr>
<th>number</th>
<th>제목</th>
<th>답변상태</th>
<th>참여인원</th>
<th>카테고리</th>
<th>청원시작</th>
<th>청원마감</th>
<th>청원내용</th>
<th>답변원고</th>
</tr>
</thead>
</table>
<p>[451513 rows x 9 columns]</p>
<h1 id="ray-process">RAY Process</h1>
<pre><code class="language-python">import pandas as pd
import requests
from lxml.html import fromstring
from tqdm import tqdm
import gc
import ray
ray.init()


@ray.remote
def main(data, h, ram, iteration):
    if ram == 0 &amp; h &gt; iteration: # 처음위치
        s = h
        e = s-iteration
    elif 0 &lt;= h-iteration*ram &lt;= iteration: # 마지막 위치
        s = h-iteration*ram
        e = -1
    elif h-iteration*ram &lt; 0: # 이전에 마지막 위치를 도달 했으면 빈 df 리턴
        return data.append(pd.Series([None for _ in range(len(columns))]), ignore_index=True)
    else:
        s = h-iteration*ram
        e = s-iteration
    for code in tqdm(range(s, e, -1)):
        try:
            url = &quot;http://19president.pa.go.kr/petitions/{}&quot;.format(code)
            res = requests.get(url)
            parser = fromstring(res.text)

            title = parser.xpath(&quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/h3/text()&quot;)
            status = parser.xpath(
                &quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[1]/h4/text()&quot;)
            personnel = parser.xpath(
                &quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/h2/span/text()&quot;)
            category = parser.xpath(
                &quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[2]/ul/li[1]/text()&quot;)
            start = parser.xpath(
                &quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[2]/ul/li[2]/text()&quot;)
            end = parser.xpath(
                &quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[2]/ul/li[3]/text()&quot;)
            q = parser.xpath(&quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[4]/div[2]/text()&quot;)
            a = parser.xpath(&quot;/html/body/div[3]/div[2]/section[2]/div[2]/div[1]/div[2]/div[1]/div/div[5]/div/text()&quot;)
            data = data.append(pd.Series([code, *title, &#39; &#39;.join(status), *personnel, *category, *start, *end,
                                          &#39; &#39;.join(q),
                                          &#39; &#39;.join(a)]), ignore_index=True)
        except:
            if len(data) &gt; 2:
                return data
            else:
                return data.append(pd.Series([None for _ in range(len(columns))]), ignore_index=True)
    return data


worker = 16
size = 3000
total = round(605368/(size*worker))
columns = [&#39;number&#39;, &#39;제목&#39;, &#39;답변상태&#39;, &#39;참여인원&#39;, &#39;카테고리&#39;, &#39;청원시작&#39;, &#39;청원마감&#39;, &#39;청원내용&#39;, &#39;답변원고&#39;]
for i in range(total):
    df = pd.DataFrame()
    df = ray.put(df)
    starting = 605368 - (size*worker*i)
    ans = [main.remote(data=df, h=starting, ram=n, iteration=size) for n in range(worker)]
    ans = ray.get(ans)
    ans = pd.concat(ans, ignore_index=True)

    ans.columns = columns
    ans = ans.dropna(subset=[&#39;청원시작&#39;]).reset_index(drop=True)

    ans.to_parquet(f&#39;Bluehouse{i}.parquet&#39;, engine=&#39;pyarrow&#39;, compression=&#39;gzip&#39;, index=False)
    print(f&quot;{i}th FIN&quot;)
    del df
    del ans
    gc.collect()
ray.shutdown()
</code></pre>
<h1 id="preprocess">Preprocess</h1>
<pre><code class="language-python">import pandas as pd

df = pd.read_parquet(&#39;Bluehouse.parquet&#39;)
df.청원내용 = df.청원내용.str.replace(&#39;\t&#39;, &#39;&#39;, regex=True)
df.청원내용 = df.청원내용.str.replace(&#39;\r&#39;, &#39;&#39;, regex=True)
df.청원내용 = df.청원내용.str.replace(&#39;\n&#39;, &#39; &#39;, regex=True)
df.청원내용 = df.청원내용.str.replace(&#39;\s+&#39;, &#39; &#39;, regex=True)
df.청원내용 = df.청원내용.str.strip()

df.답변원고 = df.답변원고.str.replace(&#39;\t&#39;, &#39;&#39;, regex=True)
df.답변원고 = df.답변원고.str.replace(&#39;\r&#39;, &#39; &#39;, regex=True)
df.답변원고 = df.답변원고.str.replace(&#39;\n&#39;, &#39;&#39;, regex=True)
df.답변원고 = df.답변원고.str.replace(&#39;\s+&#39;, &#39; &#39;, regex=True)
df.답변원고 = df.답변원고.str.strip()

df.number = df.number.astype(int)

df.to_parquet(&#39;Bluehouse_dump.parquet&#39;)</code></pre>
<h1 id="reference">reference</h1>
<p><a href="http://19president.pa.go.kr/petitions">대통령기록관</a></p>
<p><a href="https://www.ray.io/">RAY</a></p>
<p><a href="https://github.com/HaloKim/bluehouse_petitions">github</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sagemaker 빌트인 모델 서빙 패턴]]></title>
            <link>https://velog.io/@dev_halo/Sagemaker-%EB%B9%8C%ED%8A%B8%EC%9D%B8-%EB%AA%A8%EB%8D%B8-%EC%84%9C%EB%B9%99-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dev_halo/Sagemaker-%EB%B9%8C%ED%8A%B8%EC%9D%B8-%EB%AA%A8%EB%8D%B8-%EC%84%9C%EB%B9%99-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Mon, 17 Oct 2022 17:14:56 GMT</pubDate>
            <description><![CDATA[<h1 id="amazone-sagemaker의-빌트인-모델-서빙-패턴-4가지">Amazone SageMaker의 빌트인 모델 서빙 패턴 4가지</h1>
<p>딥러닝 모델을 만들고 효율적인 AI/ML 프로세스를 위해 Sagemaker로 Pipeline을 작성했다면 만들어진 모델을 이용해 실제 서비스에 적용해야 합니다. 이때, Sagemaker에서 크게 4가지의 빌트인 모델 서빙 패턴을 제공해주는데 프로젝트에 맞는 서빙 패턴을 고려해서 적용해야 합니다.</p>
<p>현재 작업을 완료한 실제 패턴은 특정시간을 기준으로 모인 데이터를 작성한 모델을 거쳐 고객 분석팀의 대시보드에 추론값을 parquet 방식으로 확률값과 라벨값을 뽑아줍니다.</p>
<p>처음 서빙패턴은 리얼타임 추론을 적용하였는데, 위 특성을 고려할 때 특정시간까지 모인 데이터셋의 크기가 일정하지 않고 매우 큰 데이터셋이 들어왔을때 최대 페이로드를 넘는 문제점이 존재했습니다. 따라서 배치 변환을 통한 서빙 패턴을 적용하기로 했습니다.</p>
<h1 id="1-배치-변환">1. 배치 변환</h1>
<p>전체 데이터셋에 대해 추론
대용량 데이터의 주기적 추론에 적합
임시 리소스(프로비저닝된 인스턴스는 작업 완료 후 곧바로 종료) -&gt; 사용한 만큼 과금</p>
<h1 id="2-비동기-추론-인터페이스">2. 비동기 추론 인터페이스</h1>
<p>최대 1GB의 대용량 페이로드에 적합
최대 15분의 타임아웃
오토스케일링
CV/NLP에 적합</p>
<h1 id="3-리얼타임-추론">3. 리얼타임 추론</h1>
<p>모델 추론에 필요한 모든 아티팩트를 웹 서버에 저장
최대 6MB 페이로드에 대한 즉각적인 응답
60초 타임아웃
오토스케일링</p>
<h1 id="4-서버리스-추론">4. 서버리스 추론</h1>
<h2 id="41-람다-서버리스-추론">4.1. 람다 서버리스 추론</h2>
<p>도커 이미지 빌드 및 람다 함수 구현 필요</p>
<h2 id="42-sagemaker-서버리스-추론">4.2. Sagemaker 서버리스 추론</h2>
<p>모델 생성 -&gt; 엔드포인트 구성 생성 -&gt; 엔드포인트생성 -&gt; Sagemaker 서버리스 엔드포인트
사용 가능한 메모리 크기 1/2/3/4/5/6GB</p>
<h1 id="요약">요약</h1>
<table>
<thead>
<tr>
<th>-</th>
<th>리얼타임</th>
<th>배치</th>
<th>비동기</th>
<th>서버리스</th>
</tr>
</thead>
<tbody><tr>
<td>GPU지원</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>오토스케일링</td>
<td>O</td>
<td>-</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>Scale to Zero</td>
<td>X</td>
<td>-</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>멀티컨테이너</td>
<td>O</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td>멀티모델</td>
<td>O</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td>페이로드 크기</td>
<td>6MB</td>
<td>-</td>
<td>1GB</td>
<td>4MB</td>
</tr>
<tr>
<td>타임아웃</td>
<td>60s</td>
<td>-</td>
<td>15M</td>
<td>60s</td>
</tr>
<tr>
<td>블루그린 가드레일</td>
<td>O</td>
<td>X</td>
<td>X</td>
<td>1step</td>
</tr>
<tr>
<td>PrivateLnk 지원</td>
<td>O</td>
<td>O</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>AB테스트</td>
<td>O</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
</tbody></table>
<h1 id="출처">출처</h1>
<p><a href="https://www.slideshare.net/awskorea/amazon-sagemaker-session2">AWS 슬라이드쉐어</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Yolov5 모델을 BentoML을 이용해 Serving 해보자]]></title>
            <link>https://velog.io/@dev_halo/Yolov5-BentoML%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-Serving-%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/Yolov5-BentoML%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-Serving-%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 07 Sep 2022 07:14:23 GMT</pubDate>
            <description><![CDATA[<h1 id="bentoml_serving">BentoML_Serving</h1>
<p>사내에서 병원의 마약 이미지를 이용하여 마약을 분류하는 모델을 개발하였습니다.
이 모델은 Yolov5를 이용해 개발하였고 pytorch 기반으로 작성하였습니다.
실제 배포방식을 고민하며 flask보다 API Serving이 좋다고 소문나있는 BentoML에 얹는 방법을 공유하겠습니다.</p>
<h1 id="1-init-wrappermodel-then-save-model-as-bentoml-model">1. Init WrapperModel then save model as bentoml model</h1>
<pre><code class="language-python">import torch
from models.common import DetectMultiBackend
from utils.torch_utils import select_device, time_sync
from pathlib import Path
from utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages
from utils.general import check_file, check_img_size, non_max_suppression, scale_coords
import bentoml

# Model
device = select_device(&#39;&#39;)
original_model = DetectMultiBackend(&#39;best.pt&#39;, device=device, dnn=False)


class WrapperModel(torch.nn.Module):
    def __init__(self, model):
        super().__init__()
        self.model = model

    def forward(self, imgs):
        source = str(imgs)
        is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
        is_url = source.lower().startswith((&#39;rtsp://&#39;, &#39;rtmp://&#39;, &#39;http://&#39;, &#39;https://&#39;))
        if is_url and is_file:
            source = check_file(source)  # download

        # Load model
        device = select_device(&#39;&#39;)
        stride, names, pt, jit, onnx, engine = self.model.stride, self.model.names, self.model.pt, self.model.jit, self.model.onnx, self.model.engine
        imgsz = check_img_size((448, 448), s=stride)  # check image size

        half = False
        if pt or jit:
            self.model.model.half() if half else model.model.float()

        # Dataloader
        dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt)
        bs = 1  # batch_size
        vid_path, vid_writer = [None] * bs, [None] * bs

        # Run inference
        dt, seen = [0.0, 0.0, 0.0], 0
        for path, im, im0s, vid_cap, s in dataset:
            t1 = time_sync()
            im = torch.from_numpy(im).to(device)
            im = im.half() if half else im.float()  # uint8 to fp16/32
            im /= 255  # 0 - 255 to 0.0 - 1.0
            if len(im.shape) == 3:
                im = im[None]  # expand for batch dim
            t2 = time_sync()
            dt[0] += t2 - t1

            # Inference
            pred = self.model(im)
            t3 = time_sync()
            dt[1] += t3 - t2

            # NMS
            pred = non_max_suppression(prediction=pred, conf_thres=torch.tensor(0.25).cuda(),
                                       iou_thres=torch.tensor(0.45).cuda(), classes=None, agnostic=False, max_det=1000)
            dt[2] += time_sync() - t3

            # Process predictions
            for i, det in enumerate(pred):  # per image
                seen += 1
                p, im0, frame = path, im0s.copy(), getattr(dataset, &#39;frame&#39;, 0)

                s += &#39;%gx%g &#39; % im.shape[2:]  # print string
                if len(det):
                    # Rescale boxes from img_size to im0 size
                    det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()

                    # Print results
                    for c in det[:, -1].unique():
                        n = (det[:, -1] == c).sum()  # detections per class
                        s += f&quot;{n} {names[int(c)]}{&#39;s&#39; * (n &gt; 1)}, &quot;  # add to string
        return s


model = WrapperModel(original_model)</code></pre>
<h1 id="2-write-servicepy">2. Write service.py</h1>
<pre><code class="language-python">import bentoml
from bentoml.io import Text

yolo_runner = bentoml.pytorch.get(&quot;pytorch_yolov5&quot;).to_runner()

svc = bentoml.Service(
    name=&quot;pytorch_yolo_demo&quot;,
    runners=[yolo_runner],
)


@svc.api(input=Text(), output=Text())
async def predict(img: str) -&gt; str:
    assert isinstance(img, str)
    return await yolo_runner.async_run(img)</code></pre>
<h1 id="3-run-service">3. Run service</h1>
<pre><code class="language-bash">bentoml serve service.py:svc</code></pre>
<h1 id="4-send-api">4. Send API</h1>
<pre><code class="language-bash">curl -X POST -H &quot;Content-Type: text/plain&quot; --data &#39;SAMPLE IMG URI&#39; http://localhost:3000/predict</code></pre>
<p>return &#39;image 1/1 /home/halo/PycharmProjects/bentoml/202106180043369591_0.jpg: 352x448 1 F_Duro_50mcg,&#39;</p>
<h1 id="5-docker-build">5. Docker build</h1>
<h3 id="write-bentomlfileyaml">Write bentomlfile.yaml</h3>
<pre><code class="language-yaml">service: &quot;service:svc&quot;  # where the bentoml.Service instance is defined
include:
- &quot;*.py&quot;
- &quot;*.pt&quot;
docker:
    base_image: &quot;my_custom_image:latest&quot;</code></pre>
<h3 id="build">Build</h3>
<pre><code class="language-bash">bentoml build</code></pre>
<h3 id="deploying-the-bento">Deploying the Bento</h3>
<pre><code class="language-bash">bentoml containerize pytorch_yolo_demo:uk3q6lq7rsmkw3lr

# Successfully built docker image &quot;pytorch_yolo_demo:uk3q6lq7rsmkw3lr&quot;

docker run --gpus all -p 3000:3000 pytorch_yolo_demo:uk3q6lq7rsmkw3lr</code></pre>
<h1 id="options">Options</h1>
<pre><code class="language-bash"># Production
bentoml serve --production --host 0.0.0.0 service.py:svc</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sagemaker MLOps Pipeline with HuggingFace]]></title>
            <link>https://velog.io/@dev_halo/Sagemaker-MLOps-Pipeline-with-HuggingFace</link>
            <guid>https://velog.io/@dev_halo/Sagemaker-MLOps-Pipeline-with-HuggingFace</guid>
            <pubDate>Wed, 07 Sep 2022 07:02:15 GMT</pubDate>
            <description><![CDATA[<h1 id="huggingface_sagemaker_pipeline">huggingface_sagemaker_pipeline</h1>
<p>K-항공사의 고객 설문 데이터를 이용하여 감정분석 모델을 HuggingFace를 이용해 개발했습니다.
MLOps가 다들 좋다고 얘기하지만 정작 이를 실제 서비스에 배포하려면 정보가 매우 적습니다.
이 모델을 이용하여 MLOps Pipeline을 구축하였고 이 과정에서 겪은 시행착오를 공유하겠습니다.
현재 구축한 상태는 크게 전처리-학습-모델 업로드이며 실제 모델을 Serving 하는 방법은 추후에 공유하겠습니다.</p>
<h1 id="overview">Overview</h1>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/1e66bfbc-ad82-48ad-8175-70c389c48a60/image.png" alt=""></p>
<h1 id="pipeline">Pipeline</h1>
<p><img src="https://velog.velcdn.com/images/dev_halo/post/80ed0771-757d-42a4-a915-28095f92d28b/image.png" alt=""></p>
<h1 id="prepare">Prepare</h1>
<ol>
<li>Preprocess dockerfile</li>
<li>Inference dockerfile(cpu or cuda) <a href="https://github.com/aws/sagemaker-pytorch-inference-toolkit">sagemaker-pytorch-inference-toolkit</a></li>
<li>Python Script (train.py, evaluation.py, inference.py)</li>
</ol>
<h1 id="sagemaker-notebook">Sagemaker Notebook</h1>
<p><a href="https://github.com/philschmid/huggingface-sagemaker-workshop-series/blob/main/workshop_3_mlops/lab_1_sagemaker_pipeline.ipynb">Sagemaker_pipeline</a></p>
<h1 id="sagemaker-environment-variables">Sagemaker Environment variables</h1>
<p><a href="https://github.com/aws/sagemaker-training-toolkit/blob/master/ENVIRONMENT_VARIABLES.md">Environment variables</a></p>
<h1 id="some-tips-to-understand-the-path">Some tips (To understand the path)</h1>
<h2 id="in-processingstep">in ProcessingStep</h2>
<ul>
<li><p>inputs (List type)</p>
<pre><code>source(S3) -&gt; destination(container instance)</code></pre></li>
<li><p>outputs (List type)</p>
<pre><code>source(container instance) -&gt; destination(S3)</code></pre><h2 id="in-trainingstep">in TrainingStep</h2>
</li>
<li><p>inputs (Dict type)</p>
</li>
</ul>
<p>Only suport train, test variables</p>
<pre><code>source(Your sagemaker S3 URI, made at the processing step) -&gt; destination(container instance)</code></pre><p>Also, When the save the model, Use it trainer.save_model(os.environ[&quot;SM_MODEL_DIR&quot;])</p>
<p>then you can check the model saved at sagemaker s3</p>
<h1 id="custom-script-processing-step">Custom script processing step</h1>
<pre><code class="language-python">from sagemaker.processing import ScriptProcessor

processing_output_destination = &#39;YOUR S3 PATH&#39;

custom_processor = ScriptProcessor(
    image_uri=&#39;YOUR ECR URI&#39;,
    instance_type=&#39;ml.c5.2xlarge&#39;,
    instance_count=1,
    base_job_name=base_job_prefix + &quot;/preprocessing&quot;,
    sagemaker_session=sagemaker_session,
    role=role,
    command = [&quot;python3&quot;])

step_process = ProcessingStep(
    name=&quot;ProcessDataForTraining&quot;,
    cache_config=cache_config,
    processor=custom_processor,
    job_arguments=[&quot;--bucket&quot;,&#39;hg.sage&#39;,
                   &quot;--file_name&quot;, &#39;train/train.csv&#39;],
    inputs=[
        ProcessingInput(
            input_name=&quot;train.csv&quot;,
            source=f&quot;{processing_output_destination}/train&quot;,
            destination=&quot;/opt/ml/processing/input/train&quot;
        ),
        ProcessingInput(
            input_name=&quot;test.csv&quot;,
            source=f&quot;{processing_output_destination}/test&quot;,
            destination=&quot;/opt/ml/processing/input/test&quot;
        ),
    ],

    outputs=[
        ProcessingOutput(
            output_name=&quot;train&quot;,
            destination=f&quot;{processing_output_destination}/train&quot;,
            source=&quot;/opt/ml/processing/train&quot;,
        ),
        ProcessingOutput(
            output_name=&quot;test&quot;,
            destination=f&quot;{processing_output_destination}/test&quot;,
            source=&quot;/opt/ml/processing/test&quot;,
        ),
    ],
    code=f&#39;{YOUR SOURCE PATH}/Preprocess.py&#39;,
)</code></pre>
<h1 id="custom-script-inference-step">Custom script inference step</h1>
<p>To use the custom inference, You must follow the rules.</p>
<p>Sagemaker inference follow the model.tar.gz</p>
<pre><code>model.tar.gz
├── /code
│   └── inference.py
├── tokenizer.json
├── tokenizer_config.json
├── config.json
├── vocab.txt
└── pytorch_model.bin</code></pre><p><a href="https://github.com/huggingface/notebooks/blob/main/sagemaker/17_custom_inference_script/sagemaker-notebook.ipynb">custom_inference_script</a></p>
<h1 id="s3-directory">S3 Directory</h1>
<pre><code>S3
├── /code
│   └── inference.py
├── /train
│   ├── train.csv
│   ├── model.bin(optional)
│   ├── vocab.txt(optional)
│   └── config(optional)
└── /test
    └── test.csv</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[아무도 안알려주는 on-premise Kubeflow 구축해보자(with cuda)]]></title>
            <link>https://velog.io/@dev_halo/%EC%95%84%EB%AC%B4%EB%8F%84-%EC%95%88%EC%95%8C%EB%A0%A4%EC%A3%BC%EB%8A%94-on-premise-Kubeflow-%EA%B5%AC%EC%B6%95%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/%EC%95%84%EB%AC%B4%EB%8F%84-%EC%95%88%EC%95%8C%EB%A0%A4%EC%A3%BC%EB%8A%94-on-premise-Kubeflow-%EA%B5%AC%EC%B6%95%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 26 Jul 2022 11:54:19 GMT</pubDate>
            <description><![CDATA[<p>회사에서 모델을 개발하니 Production을 해야하고 이를 실제 배포까지 진행한다면 많은 단계를 거쳐야하고 모니터링 및 복구가 가능해야 합니다.</p>
<p>이에따라 MLOps가 필요해졌고 고객요구에 따라 Sagemaker를 활용하여 MLOps를 구축하게 되었습니다.</p>
<p>사실 MLOps에 대한 개념도 없이 Sagemaker로 구축을하니 너무 불편하고 번거로운 작업을 초반에 진행해야하는 문제가 있었고 이게 좋은게 맞나 ? 라는 생각이 들어 on-premise mlops를 구축하여 모르고 욕하는 것보다 알고 욕하고 싶었고 그 결과는 Sagemaker가 맞구나 라는 결론이었습니다.</p>
<p>on-premise로 Kubeflow를 구축하며 많은 자료가 있었지만 너무나 구버전이고 GPU 자원 활용에 대한 정보가 부족하여 누군가에게 도움되길 바라며 공유합니다.</p>
<p>업데이트는 첫번째 출처 깃허브에서 진행됩니다
<a href="https://github.com/z1z0nhist/kubeflow_ubuntu">원본 깃허브</a></p>
<h1 id="set-env">Set env</h1>
<h3 id="prerequirement">prerequirement</h3>
<ul>
<li>nvidia docker</li>
<li>docker default runtime</li>
</ul>
<p><a href="https://docs.docker.com/desktop/install/ubuntu/">docker</a></p>
<h4 id="optionalgpu-docker">(optional)gpu docker</h4>
<pre><code># /etc/docker/daemon.json
{
  &quot;default-runtime&quot;: &quot;nvidia&quot;,
  &quot;runtimes&quot;: {
      &quot;nvidia&quot;: {
          &quot;path&quot;: &quot;nvidia-container-runtime&quot;,
          &quot;runtimeArgs&quot;: []
   }
  }
}</code></pre><p><a href="https://minikube.sigs.k8s.io/docs/start/">minikube</a></p>
<pre><code>curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

minikube start --driver=docker --disk-size=100g --kubernetes-version=1.21.0 --memory=4g --cpus=4
(optional)minikube config set profile test</code></pre><h4 id="optionalminikube-cuda">(optional)minikube cuda</h4>
<p>kubeflow가 kubernetes 위에서 작동하므로 minikube에 cuda 환경이 배포되어야 사용 가능</p>
<pre><code>sudo apt install conntrack
sudo apt install socat
minikube start --driver=none --kubernetes-version=1.21.0
kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/master/nvidia-device-plugin.yml
kubectl get pod -A | grep nvidia
kubectl get nodes &quot;-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu&quot;

vim gpu.yaml
# in gpu.yaml
# caution cuda version
# 이미지가 본인의 환경에 맞는 cuda 환경을 설정해 주어야 합니다.
apiVersion: v1
kind: Pod
metadata:
  name: gpu
spec:
  containers:
  - name: gpu-container
    image: nvidia/cuda:11.4.2-runtime-ubuntu18.04
    command:
      - &quot;/bin/sh&quot;
      - &quot;-c&quot;
    args:
      - nvidia-smi &amp;&amp; tail -f /dev/null
    resources:
      requests:
        nvidia.com/gpu: 1
      limits:
        nvidia.com/gpu: 1
#
kubectl create -f gpu.yaml
kubectl logs gpu</code></pre><p><a href="https://kubernetes.io/ko/docs/tasks/tools/install-kubectl-linux/">kubectl</a></p>
<pre><code>curl -LO &quot;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl&quot;
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client</code></pre><p><a href="https://kubectl.docs.kubernetes.io/guides/introduction/kustomize/">kustomize</a></p>
<pre><code>wget https://github.com/kubernetes-sigs/kustomize/releases/download/v3.2.0/kustomize_3.2.0_linux_amd64
chmod +x kustomize_3.2.0_linux_amd64
sudo mv kustomize_3.2.0_linux_amd64 /usr/local/bin/kustomize</code></pre><pre><code>manifests/common/user-namespace/base/params.env
manifests/common/dex/base/config-map.yaml
kubectl -n auth rollout restart deployment dex </code></pre><p><a href="https://github.com/kubeflow/manifests">kubeflow/manifests</a></p>
<pre><code>git clone https://github.com/kubeflow/manifests.git
cd manifests
git checkout v1.4-branch(kubeflow 버전 변경)

# 아래 명령어는 작동 순서에 예민하므로 성공할 때까지 기다린다
while ! kustomize build example | kubectl apply -f -; do echo &quot;Retrying to apply resources&quot;; sleep 10; done
# 이유를 모르겠으나 이렇게 설치하면 파드가 잘 생성이 안됩니다.
# 아래 참조처럼 한개씩 설치합시다 
# (참조)[https://mlops-for-all.github.io/docs/setup-components/install-components-kf/#cert-manager]</code></pre><h4 id="optionalkubeflow-local-host">(optional)Kubeflow local host</h4>
<pre><code>kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80

# Login
user@example.com
12341234</code></pre><h4 id="optionaladd-user">(optional)add user</h4>
<pre><code># manifests/common/dex/base/comnfig-map.yaml
# hash는 접속시 비밀번호인데 Bcrypt를 통해 암호화 시킨 값을 넣어야 한다.
apiVersion: v1
kind: ConfigMap
metadata:
  name: dex
data:
  config.yaml: |
    issuer: http://dex.auth.svc.cluster.local:5556/dex
    storage:
      type: kubernetes
      config:
        inCluster: true
    web:
      http: 0.0.0.0:5556
    logger:
      level: &quot;debug&quot;
      format: text
    oauth2:
      skipApprovalScreen: true
    enablePasswordDB: true
    staticPasswords:
    - email: user@example.com
      hash: $2y$12$4K/VkmDd1q1Orb3xAt82zu8gk7Ad6ReFR4LCP9UeYE90NLiN9Df72
      # https://github.com/dexidp/dex/pull/1601/commits
      # FIXME: Use hashFromEnv instead
      username: user
      userID: &quot;15841185641784&quot;
    - email: dev7halo@gmail.com
      hash: $2a$12$pnfKk2PSRTyM8Wm3jrEkKuM339fgBqWcFPrHbcsEHGhzDmH/pm/Uy
      username: krkim
      userID: krkim
    staticClients:
    # https://github.com/dexidp/dex/pull/1664
    - idEnv: OIDC_CLIENT_ID
      redirectURIs: [&quot;/login/oidc&quot;]
      name: &#39;Dex Login Application&#39;
      secretEnv: OIDC_CLIENT_SECRET</code></pre><h4 id="optionalnamespace-설정">(optional)namespace 설정</h4>
<pre><code># manifests/common/user-namespace/base/params.env

user=dev7halo@gmail.com
profile-name=krkim</code></pre><h1 id="kfp-사용하기">kfp 사용하기</h1>
<pre><code>import kfp
import requests

USERNAME = &quot;dev7halo@gmail.com&quot;
PASSWORD = &quot;    &quot;
NAMESPACE = &quot;krkim&quot;
HOST = &quot;http://10.23.13.113:31265&quot; # istio-ingressgateway&#39;s external-ip created by the load balancer.

session = requests.Session()
response = session.get(HOST)

headers = {
    &quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;,
}

data = {&quot;login&quot;: USERNAME, &quot;password&quot;: PASSWORD}
session.post(response.url, headers=headers, data=data)
session_cookie = session.cookies.get_dict()[&quot;authservice_session&quot;]

client = kfp.Client(
    host=f&quot;{HOST}/pipeline&quot;,
    namespace=f&quot;{NAMESPACE}&quot;,
    cookies=f&quot;authservice_session={session_cookie}&quot;,
)
print(client.list_pipelines())</code></pre><h1 id="명령어">명령어</h1>
<pre><code># 쿠버네티스 파드 확인
kubectl get pods -A
watch kubectl get pods -A 
kubectl get po -A -w

# namespace별 pod 확인
kubectl get po -n {namespace}

# pod 재생성
kubectl get pod &lt;pod_name&gt; -n &lt;namespace&gt; -o yaml | kubectl replace --force -f-

# pod 삭제
kubectl delete pod &lt;pod_name&gt; -n &lt;namespace&gt;

# 강제종료
kubectl delete pod &lt;pod_name&gt; -n &lt;namespace&gt; --grace-period 0 --force

# namespace 삭제
kubectl delete namespace {삭제할 namespace}

# minikube service list
minikube service list -n istio-system</code></pre><h1 id="info">Info</h1>
<table>
<thead>
<tr>
<th>Tool</th>
<th>Version</th>
</tr>
</thead>
<tbody><tr>
<td>Ubuntu</td>
<td>22.04</td>
</tr>
<tr>
<td>minikube</td>
<td>v1.26.0</td>
</tr>
<tr>
<td>kubernetes</td>
<td>v1.21.0</td>
</tr>
<tr>
<td>kustomize</td>
<td>v3.2.0</td>
</tr>
<tr>
<td>cuda</td>
<td>11.4</td>
</tr>
</tbody></table>
<h1 id="겪었던-문제">겪었던 문제</h1>
<ul>
<li>회사 이메일에 . 이 들어가는데 yaml 파일에서 .이 들어가면 문제가 생겨서 삽질</li>
<li>on-premise로 구축하려니 쿠버네티스 생태계에 이해를 못해서 gpu 자원 활용에 문제</li>
<li>on-premise로 구축하고 localhost에서 jupyter notebook에서 kubeflow pipe라인을 작성하니 토큰 문제(client에 localhost:port를 넣어서 해결)</li>
<li>Could not find CSRF cookie XSRF-TOKEN in the request(참조3)</li>
</ul>
<h1 id="reference">Reference</h1>
<p><a href="https://github.com/z1z0nhist/kubeflow_ubuntu">원본 깃허브</a></p>
<p><a href="https://github.com/kubeflow/manifests">https://github.com/kubeflow/manifests</a></p>
<p><a href="https://velog.io/@moey920/Minikube-Nvidia-GPU-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0">https://velog.io/@moey920/Minikube-Nvidia-GPU-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</a></p>
<p><a href="https://otzslayer.github.io/kubeflow/2022/06/11/could-not-find-csrf-cookie-xsrf-token-in-the-request.html">https://otzslayer.github.io/kubeflow/2022/06/11/could-not-find-csrf-cookie-xsrf-token-in-the-request.html</a></p>
<p><a href="https://mlops-for-all.github.io/docs/setup-components/install-components-kf/">모두의 MLOps</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[UnicodeDecodeError (Sagemaker, HuggingFace)]]></title>
            <link>https://velog.io/@dev_halo/UnicodeDecodeError-Sagemaker-HuggingFace</link>
            <guid>https://velog.io/@dev_halo/UnicodeDecodeError-Sagemaker-HuggingFace</guid>
            <pubDate>Wed, 25 May 2022 01:29:12 GMT</pubDate>
            <description><![CDATA[<p>This error occur, When the load the checkpoint in Sagemaker that maked in huggingface(transformer) of other os(windows, ubuntu).</p>
<p>Maybe Sagemaker file system is configured as S3, So is not normal file system.</p>
<p>Thus, Can&#39;t use checkpoint file.</p>
<p>It is easy to solve this problem.</p>
<p>When the careate the model file, You just use torch.save</p>
<pre><code>---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/transformers/modeling_utils.py in load_state_dict(checkpoint_file)
    348     try:
--&gt; 349         return torch.load(checkpoint_file, map_location=&quot;cpu&quot;)
    350     except Exception as e:

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/serialization.py in load(f, map_location, pickle_module, **pickle_load_args)
    586             orig_position = opened_file.tell()
--&gt; 587             with _open_zipfile_reader(opened_file) as opened_zipfile:
    588                 if _is_torchscript_zip(opened_zipfile):

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/serialization.py in __init__(self, name_or_buffer)
    241     def __init__(self, name_or_buffer) -&gt; None:
--&gt; 242         super(_open_zipfile_reader, self).__init__(torch._C.PyTorchFileReader(name_or_buffer))
    243 

RuntimeError: [enforce fail at inline_container.cc:145] . PytorchStreamReader failed reading zip archive: failed finding central directory

During handling of the above exception, another exception occurred:

UnicodeDecodeError                        Traceback (most recent call last)
~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/transformers/modeling_utils.py in load_state_dict(checkpoint_file)
    352             with open(checkpoint_file) as f:
--&gt; 353                 if f.read().startswith(&quot;version&quot;):
    354                     raise OSError(

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/codecs.py in decode(self, input, final)
    320         data = self.buffer + input
--&gt; 321         (result, consumed) = self._buffer_decode(data, self.errors, final)
    322         # keep undecoded input until the next call

UnicodeDecodeError: &#39;utf-8&#39; codec can&#39;t decode byte 0x80 in position 64: invalid start byte

During handling of the above exception, another exception occurred:

OSError                                   Traceback (most recent call last)
&lt;ipython-input-7-33d79adeebc4&gt; in &lt;module&gt;
      1 # 사용할 모델과 토크나이저 로드
----&gt; 2 model = AutoModelForSequenceClassification.from_pretrained(&#39;trained&#39;, num_labels=3)
      3 tokenizer = AutoTokenizer.from_pretrained(&#39;koelectra-base-v3-discriminator&#39;)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/transformers/models/auto/auto_factory.py in from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs)
    444         elif type(config) in cls._model_mapping.keys():
    445             model_class = _get_model_class(config, cls._model_mapping)
--&gt; 446             return model_class.from_pretrained(pretrained_model_name_or_path, *model_args, config=config, **kwargs)
    447         raise ValueError(
    448             f&quot;Unrecognized configuration class {config.__class__} for this kind of AutoModel: {cls.__name__}.\n&quot;

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/transformers/modeling_utils.py in from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs)
   1795             if not is_sharded:
   1796                 # Time to load the checkpoint
-&gt; 1797                 state_dict = load_state_dict(resolved_archive_file)
   1798             # set dtype to instantiate the model under:
   1799             # 1. If torch_dtype is not None, we use that dtype

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/transformers/modeling_utils.py in load_state_dict(checkpoint_file)
    364         except (UnicodeDecodeError, ValueError):
    365             raise OSError(
--&gt; 366                 f&quot;Unable to load weights from pytorch checkpoint file for &#39;{checkpoint_file}&#39; &quot;
    367                 f&quot;at &#39;{checkpoint_file}&#39;. &quot;
    368                 &quot;If you tried to load a PyTorch model from a TF 2.0 checkpoint, please set from_tf=True.&quot;

OSError: Unable to load weights from pytorch checkpoint file for &#39;trained/pytorch_model.bin&#39; at &#39;trained/pytorch_model.bin&#39;. If you tried to load a PyTorch model from a TF 2.0 checkpoint, please set from_tf=True.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Mount S3 at Local Docker Container]]></title>
            <link>https://velog.io/@dev_halo/Mount-S3-at-Local-Docker-Container</link>
            <guid>https://velog.io/@dev_halo/Mount-S3-at-Local-Docker-Container</guid>
            <pubDate>Mon, 23 May 2022 12:51:15 GMT</pubDate>
            <description><![CDATA[<pre><code># Dockerfile
FROM ubuntu:18.04 

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y wget curl fuse awscli

# Goofys for s3

RUN curl -O https://storage.googleapis.com/golang/go1.18.2.linux-amd64.tar.gz &amp;&amp; \
    tar -xvf go1.18.2.linux-amd64.tar.gz &amp;&amp; \
    mv go /usr/local &amp;&amp; \
    ln -s /usr/local/go/bin/go /usr/bin/go &amp;&amp; \
    wget http://bit.ly/goofys-latest -O /usr/local/bin/goofys &amp;&amp; \
    chmod 755 /usr/local/bin/goofys

# 실행
# docker run -it --privileged IMAGE_NAME 
# docker start CONTINER_NAME 
# docker exec -it CONTINER_NAME bash
# aws configure
# goofys -f S3_BUCKET YOURDIR</code></pre><pre><code># aws configure
AWS Access Key ID : 
AWS Secret Access Key :
Default region name : 
Default output format : </code></pre><p>AWS의 EC2 Docker에 S3를 붙이는 방식과 Local Container에 마운트하는 방식이 좀 달라서 하루종일 삽질..</p>
<p>그중 가장 빠르다는 goofys를 이용해 붙이는 방식을 이용하기로 했다..</p>
<p><a href="https://hub.docker.com/repository/docker/dev7halo/ko-nlp">Docker Hub</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[One Shot 한글 NLP Docker 이미지를 구워보자]]></title>
            <link>https://velog.io/@dev_halo/%ED%95%9C%EA%B8%80-NLP-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A5%BC-%EA%B5%AC%EC%9B%8C%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/%ED%95%9C%EA%B8%80-NLP-Docker-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A5%BC-%EA%B5%AC%EC%9B%8C%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Thu, 19 May 2022 06:15:43 GMT</pubDate>
            <description><![CDATA[<h1 id="1-구성요소">1. 구성요소</h1>
<p>pytorch/pytorch, konlpy, mecab, transformers, sklearn, jupyter lab, matplotlib, kiwi</p>
<h1 id="2-docker-pull">2. Docker pull</h1>
<pre><code>docker pull dev7halo/ko-nlp</code></pre><h1 id="3-docker-run">3. Docker run</h1>
<pre><code>sudo docker run -it -p 8888:8888 --name nlp --gpus all -v /home/halo/NLP:/root/.jupyter/NLP 6960dfd63b94 jupyter lab
</code></pre><p>jupyter port 8888
name nlp
num_gpu all
mount /home/halo/NLP to /root/.jupyter/NLP
run jupyter lab</p>
<p><a href="https://github.com/HaloKim/ko-nlp-docker">관리깃</a>
<a href="https://hub.docker.com/repository/docker/dev7halo/ko-nlp">Dockerhub</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sagemaker에서 Mecab을 설치해보자]]></title>
            <link>https://velog.io/@dev_halo/Sagemaker%EC%97%90%EC%84%9C-Mecab%EC%9D%84-%EC%84%A4%EC%B9%98%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/Sagemaker%EC%97%90%EC%84%9C-Mecab%EC%9D%84-%EC%84%A4%EC%B9%98%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 10 May 2022 07:48:52 GMT</pubDate>
            <description><![CDATA[<pre><code>pip install konlpy</code></pre><h1 id="sagemaker-terminal에서-진행">Sagemaker Terminal에서 진행</h1>
<pre><code>wget https://bitbucket.org/eunjeon/mecab-ko/downloads/mecab-0.996-ko-0.9.2.tar.gz
tar xvfz mecab-0.996-ko-0.9.2.tar.gz
cd mecab-0.996-ko-0.9.2
./configure
make
make check
sudo make install
sudo ldconfig
mecab --version
---
mecab of 0.996/ko-0.9.2</code></pre><pre><code>wget https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-2.1.1-20180720.tar.gz
tar xvfz mecab-ko-dic-2.1.1-20180720.tar.gz
cd mecab-ko-dic-2.1.1-20180720
autoreconf
./configure
make
sudo make install</code></pre><pre><code>pip install mecab-python</code></pre><p><a href="https://vhrehfdl.tistory.com/m/129">참조1</a>
<a href="https://m.blog.naver.com/varkiry05/221682219392">참조2</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nvidia driver, cuda, cudnn]]></title>
            <link>https://velog.io/@dev_halo/Nvidia-driver-cuda-cudnn</link>
            <guid>https://velog.io/@dev_halo/Nvidia-driver-cuda-cudnn</guid>
            <pubDate>Fri, 06 May 2022 07:42:12 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.nvidia.co.kr/download/Find.aspx?lang=kr">nvidia 드라이버 고급 검색</a></p>
<pre><code># 설치확인
nvidia-smi</code></pre><pre><code># 드라이버제거
sudo apt-get --purge -y remove &#39;cuda*&#39;
sudo apt-get --purge -y remove &#39;nvidia*&#39;
sudo apt-get --purge -y remove &quot;*nvidia*&quot;
sudo apt-get autoremove --purge cuda
sudo rm -rf /usr/local/cuda*

sudo /usr/local/cuda-11.2/bin
sudo /usr/bin/nvidia-uninstall</code></pre><p>drm error
<a href="https://unix.stackexchange.com/questions/440840/how-to-unload-kernel-module-nvidia-drm">stackoverflow</a></p>
<p><a href="https://developer.nvidia.com/cuda-toolkit-archive">cuda toolkit achive</a></p>
<pre><code># 설치확인
nvcc -V</code></pre><p><img src="https://velog.velcdn.com/images/dev_halo/post/488a0cd4-01d2-410f-a5db-6a41f165df20/image.png" alt=""></p>
<pre><code># cuda 경로 설정
# 1
vi /etc/profile

# 열린 파일안 하단에 작성
export PATH=$PATH:/usr/local/cuda-11.3/bin 
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-11.3/lib64 
export CUDADIR=/usr/local/cuda-11.3

# 2
gedit ~/.bashrc

export PATH=/usr/local/cuda-11.1/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64:$LD_LIBRARY_PATH

source ~/.bashrc</code></pre><p><a href="https://developer.nvidia.com/rdp/cudnn-archive">cudnn achive</a></p>
<pre><code># 설치
tar xvzf cudnn-11.3-linux-x64-v8.2.1.32.tgz
sudo cp cuda/include/cudnn* /usr/local/cuda-11.3/include 
sudo cp cuda/lib64/libcudnn* /usr/local/cuda-11.3/lib64 
sudo chmod a+r /usr/local/cuda-11.3/include/cudnn.h /usr/local/cuda-11.3/lib64/libcudnn*

# 하단을 실행하는 이유
# cudnn을 카피시 심볼릭 링크가 사라져서 다시 잡아주기 위함
sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_adv_train.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_adv_train.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_ops_infer.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_ops_infer.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_cnn_train.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_cnn_train.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_adv_infer.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_adv_infer.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_ops_train.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_ops_train.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_cnn_infer.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn_cnn_infer.so.8 

sudo ln -sf /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn.so.8.2.1.32 /usr/local/cuda-11.3/targets/x86_64-linux/lib/libcudnn.so.8

# 설치확인 1
ldconfig -N -v $(sed &#39;s/:/ /&#39; &lt;&lt;&lt; $LD_LIBRARY_PATH) 2&gt;/dev/null | grep libcudnn

# 설치확인 2
sudo ldconfig

# 설치확인 3
cat /usr/local/cuda/include/cudnn_version.h | grep CUDNN_MAJOR -A 2</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Correlation loss / metric 구현해보자(with Pytorch)]]></title>
            <link>https://velog.io/@dev_halo/correlation-loss-correlation-metricPytorch</link>
            <guid>https://velog.io/@dev_halo/correlation-loss-correlation-metricPytorch</guid>
            <pubDate>Wed, 06 Apr 2022 03:48:55 GMT</pubDate>
            <description><![CDATA[<h1 id="loss">Loss</h1>
<pre><code>def correlation_loss(y_pred, y_true):
    x = y_pred.clone()
    y = y_true.clone()
    vx = x - torch.mean(x)
    vy = y - torch.mean(y)
    cov = torch.sum(vx * vy)
    corr = cov / (torch.sqrt(torch.sum(vx ** 2)) * torch.sqrt(torch.sum(vy ** 2)) + 1e-12)
    corr = torch.maximum(torch.minimum(corr,torch.tensor(1)), torch.tensor(-1))
    return torch.sub(torch.tensor(1), corr ** 2)</code></pre><h1 id="metric">Metric</h1>
<pre><code>def correlation_metric(y_pred, y_true):
        x = torch.Tensor(y_pred)
        y = torch.Tensor(y_true)
        vx = x - torch.mean(x)
        vy = y - torch.mean(y)
        cov = torch.sum(vx * vy)
        corr = cov / (torch.sqrt(torch.sum(vx ** 2)) * torch.sqrt(torch.sum(vy ** 2)) + 1e-12)
        return corr</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[세금안낸놈들 명단을 분석해보자]]></title>
            <link>https://velog.io/@dev_halo/%EC%84%B8%EA%B8%88%EC%95%88%EB%82%B8%EB%86%88%EB%93%A4-%EB%AA%85%EB%8B%A8%EC%9D%84-%EB%B6%84%EC%84%9D%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dev_halo/%EC%84%B8%EA%B8%88%EC%95%88%EB%82%B8%EB%86%88%EB%93%A4-%EB%AA%85%EB%8B%A8%EC%9D%84-%EB%B6%84%EC%84%9D%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 27 Mar 2022 04:29:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/dev_halo/post/8df91450-acf1-49a4-9a53-eaa49c643cb7/image.png" alt=""></p>
<ul>
<li>명단공개자의 일부 또는 전부를 사용하여 특정인의 명예를 훼손할 경우에는 형사상 명예훼손죄로 처벌을 받거나 민사상 손해배상 책임을 질 수 있습니다.</li>
</ul>
<p><a href="https://www.nts.go.kr/nts/cm/cntnts/cntntsView.do?mi=6685&amp;cntntsId=8097">고액 상습체납자 명단 공개</a></p>
<p>국세청은 고액 상습체납자 명단을 홈페이지에 게시하여 공개하고 있습니다. 다만, 개인이 이 정보를 통해 체납자의 명예를 훼손시키는 경우 문제가 발생하니 조심하세요 !</p>
<p>밤에 잠이안와서 심심해서 해본 데이터 수집과 분석</p>
<h1 id="1장-크롤링">1장. 크롤링</h1>
<p><a href="https://www.nts.go.kr/nts/ad/openInfo/selectList.do?tcd=2">개인체납자</a></p>
<p>위 링크를 접속하면 개인 고액 체납자의 목록을 확인할 수 있는데,</p>
<p><img src="https://images.velog.io/images/dev_halo/post/ff698584-86cb-4f29-a034-ebdc687c6a4a/image.png" alt=""></p>
<p>무려 20개씩 1658페이지 까지 구성되어 있어 도구의 힘을 빌려야 수집할 수 있는 정보였습니다.</p>
<p>사실 BS4를 활용해서 크롤링을 진행하려 했는데, 페이지 이동이 자유롭지 못하여 Selenium을 통해 클릭 이벤트를 활용하여 수집하는 방식을 활용했습니다.</p>
<pre><code>df = pd.DataFrame(columns = [&#39;No&#39;,&#39;공개년도&#39;,&#39;성명&#39;,&#39;연령&#39;,
                             &#39;상호&#39;,&#39;직업(업종)&#39;,&#39;체납자 주소&#39;,
                             &#39;총 체납액&#39;,&#39;세목&#39;,&#39;납기&#39;,&#39;체납건수&#39;,&#39;체납요지&#39;])</code></pre><p>테이블의 컬럼은 총 12개로 구성되어 있어 위와 같이 데이터프레임을 할당했습니다.</p>
<pre><code>for click in range(1, 1659):
    for i in range(1, 20+1):
        inputs = []
        for j in range(1, 12+1):
            inputs.append(driver.find_element_by_xpath(f&#39;//*[@id=&quot;wrap&quot;]/div/div[2]/table/tbody/tr[{i}]/td[{j}]&#39;).text)
        df = df.append(pd.DataFrame([inputs], columns = df.columns.to_list()))
    if click == 10:
        driver.find_element_by_xpath(f&#39;//*[@id=&quot;wrap&quot;]/div/div[2]/form/div/a[4]&#39;).click()
    elif click%10 == 0:
        driver.find_element_by_xpath(f&#39;//*[@id=&quot;wrap&quot;]/div/div[2]/form/div/a[5]&#39;).click()
    else:
        driver.find_element_by_xpath(f&#39;//*[@id=&quot;wrap&quot;]/div/div[2]/form/div/div/a[{click%10}]&#39;).click()</code></pre><p>크롤링을 진행하며 불편했던 사항은 10페이지에서 다음페이지를 이동하기 위해 버튼의 클릭이벤트를 할당해야하는데 1-10번대의 클릭 이벤트 xpath와 20페이지 이상의 클릭버튼 xpath가 상이하여 문제가 발생했는데 다행히 처음 10페이지만 달랐기에 무난히 클릭이벤트를 사용했습니다. </p>
<h1 id="2장-분석">2장. 분석</h1>
<p>분석 내용은 사실 별거 없었습니다..</p>
<pre><code>df.dtypes
---
No          int64
공개년도        int64
성명         object
연령        float64
상호         object
직업(업종)     object
체납자 주소     object
총 체납액      object
세목         object
납기         object
체납건수      float64
체납요지       object
dtype: object</code></pre><p>데이터 타입에서 총 체납액 부분이 연속형 변수인데 &#39;1,000&#39;과 같이 구분자가 포함되어 Object로 인식되어 삭제하여 int타입으로 변환해주었습니다.</p>
<pre><code>df[&#39;총 체납액&#39;].replace(&#39;[^0-9]&#39;,&#39;&#39;, regex=True, inplace=True)
df = df.astype({&#39;총 체납액&#39; : &#39;int&#39;})
df.info()
---
&lt;class &#39;pandas.core.frame.DataFrame&#39;&gt;
RangeIndex: 33150 entries, 0 to 33149
Data columns (total 12 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   No      33150 non-null  int64  
 1   공개년도    33150 non-null  int64  
 2   성명      33150 non-null  object 
 3   연령      33099 non-null  float64
 4   상호      22791 non-null  object 
 5   직업(업종)  26200 non-null  object 
 6   체납자 주소  33150 non-null  object 
 7   총 체납액   33150 non-null  int64  
 8   세목      33150 non-null  object 
 9   납기      33150 non-null  object 
 10  체납건수    33145 non-null  float64
 11  체납요지    33150 non-null  object 
dtypes: float64(2), int64(3), object(7)
memory usage: 3.0+ MB</code></pre><p><img src="https://images.velog.io/images/dev_halo/post/108cbc0d-ba07-4207-ba12-901643a8a9e0/image.png" alt="">
공개년도는 2004년부터, 총 체납액은 최소 205 최대 163299인데 단위가 백만원입니다.. 엄청난 체납자 놈들이라 할 수 있습니다 ..</p>
<p>위 자료에서 확인해보면 연령에서의 최소값이 12인데 궁금해서 확인해보았습니다</p>
<pre><code>df[df.연령 &lt; 20]</code></pre><p><img src="https://images.velog.io/images/dev_halo/post/9830de32-3e74-41ad-8863-6e0ec1d0ffab/image.png" alt="">
상속, 양도소득세 등이 있네요
이제 결측값을 확인합시다.</p>
<pre><code>df.isna().sum()
---
No            0
공개년도          0
성명            0
연령           51
상호        10359
직업(업종)     6950
체납자 주소        0
총 체납액         0
세목            0
납기            0
체납건수          5
체납요지          0
dtype: int64</code></pre><p>상호와 직업란이 많이 비어있는데 큰 문제는 없을 것 같습니다.(개인체납자니까요)</p>
<p>주로 어떤 직업/직종이 많은지 확인해보겠습니다.</p>
<pre><code>sorted_dict = sorted(dict.items(), key = lambda item: item[1], reverse = True)
print(sorted_dict[:20])
---
[(nan, 6950), (&#39;건설업&#39;, 1737), (&#39;제조업&#39;, 1611), 
(&#39;서비스&#39;, 1582), (&#39;도소매&#39;, 1536), (&#39;제조&#39;, 1220), 
(&#39;부동산&#39;, 1117), (&#39;부동산업&#39;, 947), (&#39;무직&#39;, 796), 
(&#39;건설&#39;, 723), (&#39;도매&#39;, 720), (&#39;음식&#39;, 637), 
(&#39;소매&#39;, 569), (&#39;소매업&#39;, 450), (&#39;서비스업&#39;, 369), 
(&#39;도소매업&#39;, 323), (&#39;도매업&#39;, 306), (&#39;도매 및 소매업&#39;, 304), 
(&#39;음식점업&#39;, 198), (&#39;임대&#39;, 160)]</code></pre><p>상위 20개를 뽑아봤는데 nan이 6950으로 1위 주로 제조, 부동산, 도소매 등이 상위에 있습니다. 
이중 nan값과 무직이 궁금하니 한번 20개정도씩 확인해 보겠습니다.</p>
<pre><code>df[df[&#39;직업(업종)&#39;].isna()]
df[df[&#39;직업(업종)&#39;] == &#39;무직&#39;][:20]</code></pre><p><img src="https://images.velog.io/images/dev_halo/post/1af7f51c-4ea9-45f1-aaa0-d5f2840409a2/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/dev_halo/post/5dc361a3-f3b5-4a38-ade7-7abe956b0f12/image.png" alt=""></p>
<p>네.. 대부분 소득세, 상속세입니다 개킹받네요</p>
<p>자 이제 어느 지역에 가장 많은 체납자 놈들이 거주중일지 확인해봅니다.</p>
<pre><code>dict = {}
for i in df[&#39;지역&#39;]:
    dict[i] = dict.get(i, 0) + 1
sorted_dict = sorted(dict.items(), key = lambda item: item[1], reverse = True)
---
[(&#39;경기&#39;, 6817),
 (&#39;서울&#39;, 4653),
 (&#39;경기도&#39;, 4309),
 (&#39;서울특별시&#39;, 2359),
 (&#39;경남&#39;, 1516),
 (&#39;인천&#39;, 1417),
 (&#39;충남&#39;, 1314),
 (&#39;부산&#39;, 1033),
 (&#39;경북&#39;, 948),
 (&#39;인천광역시&#39;, 935),
 (&#39;충북&#39;, 784),
 (&#39;부산광역시&#39;, 736),
 (&#39;전북&#39;, 577),
 (&#39;전남&#39;, 574),
 (&#39;강원&#39;, 560),
 (&#39;대구광역시&#39;, 467),
 (&#39;대구&#39;, 466),
 (&#39;대전&#39;, 400),
 (&#39;대전광역시&#39;, 320),
 (&#39;경상남도&#39;, 306),
 (&#39;강원도&#39;, 294),
 (&#39;광주&#39;, 285),
 (&#39;광주광역시&#39;, 267),
 (&#39;울산&#39;, 259),
 (&#39;울산광역시&#39;, 250),
 (&#39;제주특별자치도&#39;, 215),
 (&#39;경상북도&#39;, 200),
 (&#39;충청남도&#39;, 198),
 (&#39;제주&#39;, 188),
 (&#39;전라북도&#39;, 121),
 (&#39;전라남도&#39;, 115),
 (&#39;충청북도&#39;, 110),
 (&#39;세종&#39;, 80),
 (&#39;세종특별자치시&#39;, 69),
 (&#39;서울시&#39;, 5),
 (&#39;제주도&#39;, 2),
 (&#39;대구역시&#39;, 1)]</code></pre><p>데이터에서 경기, 경기도, 서울, 서울특별시등 일관성이 없어 보이지만
사람눈에 확인 가능한 수준으로 경기가 압도적으로 1위 서울이 2위입니다.</p>
<p>이제 졸리니까 자러가겠습니다.</p>
]]></description>
        </item>
    </channel>
</rss>