<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>-</title>
        <link>https://velog.io/</link>
        <description>살아남은 자가 강한 것</description>
        <lastBuildDate>Sun, 04 Jan 2026 12:17:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>-</title>
            <url>https://velog.velcdn.com/images/ma-kjh/profile/b99d54bc-3f49-4e0b-943e-6ef6d16e29da/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. -. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ma-kjh" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[git] subbranch]]></title>
            <link>https://velog.io/@ma-kjh/git-subbranch</link>
            <guid>https://velog.io/@ma-kjh/git-subbranch</guid>
            <pubDate>Sun, 04 Jan 2026 12:17:01 GMT</pubDate>
            <description><![CDATA[<h3 id="1-일반적인-흐름">1. 일반적인 흐름</h3>
<pre><code>[Root] -&gt; main
         |
         +-- [main에서 딴 브랜치] feat/new_feature
              |
              +-- [feat/new_feature에서 딴 브랜치] feat/new_feature_subtask_1
                   |
                   +-- [feat/new_feature_subtask_1에서 딴 브랜치] feat/new_feature_subtask_1_refactor</code></pre><ul>
<li><strong><code>main</code></strong>: 프로젝트의 기본 줄기.</li>
<li><strong><code>feat/new_feature</code></strong>: <code>main</code>에서 새로운 기능을 만들기 위해 딴 브랜치.</li>
<li><strong><code>feat/new_feature_subtask_1</code></strong>: <code>feat/new_feature</code> 브랜치에서 작업하던 중, 더 작은 단위의 작업(<code>subtask_1</code>)을 위해 다시 딴 브랜치.</li>
<li><strong><code>feat/new_feature_subtask_1_refactor</code></strong>: <code>feat/new_feature_subtask_1</code> 브랜치의 코드를 리팩토링(개선)하기 위해 또 딴 브랜치.</li>
</ul>
<h3 id="2-왜-이렇게-할까">2. 왜 이렇게 할까?</h3>
<ol>
<li><strong>작업 분담 및 집중:</strong><ul>
<li>큰 기능(<code>feat/new_feature</code>)을 여러 사람이 나눠서 작업할 때, 각자 <strong>서브 브랜치</strong>를 따서 맡은 부분만 집중해서 작업할 수 있음.</li>
</ul>
</li>
<li><strong>단계별 관리:</strong><ul>
<li>어떤 작업은 <strong>&quot;아이디어 구상&quot;</strong> 단계, <strong>&quot;기본 코드 작성&quot;</strong> 단계, <strong>&quot;테스트 코드 작성&quot;</strong> 단계 등으로 나눌 수 있습니다. 각 단계를 브랜치로 관리하면 진행 상황을 명확히 파악하기 좋음.</li>
</ul>
</li>
<li><strong>실험 및 위험 작업:</strong><ul>
<li>매우 실험적인 기능이나, 코드를 크게 변경해야 하는 작업은 <code>main</code>이나 다른 중요한 브랜치에서 직접 하기 위험합니다. 이때는 <strong>독립적인 브랜치</strong>를 따서 마음껏 실험해볼 수 있음. 실패하면 그냥 버리면 그만.</li>
</ul>
</li>
<li><strong>코드 리뷰 효율화:</strong><ul>
<li>PR(Pull Request)을 올릴 때, 너무 길고 복잡한 PR보다는 <strong>작고 명확한 단위의 PR</strong>이 검토하기 훨씬 쉬움. 서브 브랜치를 통해 작업을 나누면 PR도 작게 만들 수 있음.</li>
</ul>
</li>
</ol>
<h3 id="3-따는-방법">3. 따는 방법</h3>
<p>기존 브랜치에서 브랜치를 따는 방법은 동일.</p>
<pre><code class="language-bash"># 현재 브랜치가 &#39;feat/new_feature&#39; 라고 가정

# 1. 새 브랜치 생성 및 이동
git checkout -b feat/new_feature_subtask_1

# 또는, 이미 다른 브랜치에 있어도 기준이 되는 브랜치에서 딸 수 있음.
# git checkout feat/new_feature (기준이 되는 브랜치로 이동)
# git checkout -b feat/new_feature_subtask_1 (거기서 따기)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[git] log / reset / revert]]></title>
            <link>https://velog.io/@ma-kjh/git-log-reset-revert</link>
            <guid>https://velog.io/@ma-kjh/git-log-reset-revert</guid>
            <pubDate>Sun, 04 Jan 2026 11:58:10 GMT</pubDate>
            <description><![CDATA[<p>커밋을 잘못했을 때 <strong>확인하고, 취소(삭제)하는 방법</strong></p>
<hr>
<h3 id="1-커밋-내역-확인하는-방법-로그-보기">1. 커밋 내역 확인하는 방법 (로그 보기)</h3>
<p>내가 뭘 잘못했는지, 돌아갈 지점이 어디인지 확인.</p>
<pre><code class="language-bash">git log --oneline</code></pre>
<ul>
<li><code>--oneline</code>: 복잡한 정보 빼고 <strong>&quot;커밋ID + 메시지&quot;</strong>만 한 줄로 깔끔하게 보여줍니다.</li>
</ul>
<p><strong>[출력 예시]</strong></p>
<pre><code class="language-text">a1b2c3d (HEAD -&gt; main) 실수로 비밀번호 올림  &lt;-- 방금 한 실수 (삭제하고 싶음)
e5f6g7h 기능 A 구현 완료                    &lt;-- 여기로 돌아가고 싶음
i9j0k1l 초기 세팅</code></pre>
<ul>
<li>맨 위에 있는 게 가장 최신 커밋.</li>
</ul>
<hr>
<h3 id="2-커밋-삭제취소하는-방법">2. 커밋 삭제(취소)하는 방법</h3>
<p>상황에 따라 <strong>두 가지 방법</strong> 중 하나를 골라 쓰면 됨.</p>
<h4 id="상황-a-방금-내-컴퓨터에서만-커밋했고-아직-github엔-안-올렸어-reset">상황 A: &quot;방금 내 컴퓨터에서만 커밋했고, 아직 GitHub엔 안 올렸어&quot; (Reset)</h4>
<ul>
<li>가장 흔한 경우. </li>
<li><code>reset</code>을 씁니다.</li>
</ul>
<ol>
<li><p><strong>파일은 살려두기 (추천):</strong> &quot;커밋만 취소하고, 작성한 코드는 수정해서 다시 쓰고 싶어.&quot;</p>
<pre><code class="language-bash">git reset --soft HEAD~1</code></pre>
<ul>
<li><code>HEAD~1</code>: 현재(HEAD)에서 <strong>1칸 뒤로</strong> 가겠다.</li>
<li><code>--soft</code>: 커밋 기록은 지우지만, <strong>파일 내용은 지우지 않고</strong> 장바구니(Staging) 상태로 둠. (오타 수정 후 다시 커밋할 때 사용)</li>
</ul>
</li>
<li><p><strong>완전 삭제 (주의⚠️):</strong> &quot;그냥 방금 짠 코드 꼴도 보기 싫어. 싹 다 날려줘.&quot;</p>
<pre><code class="language-bash">git reset --hard HEAD~1</code></pre>
<ul>
<li><code>--hard</code>: 커밋 기록도 지우고, <strong>작성했던 코드 파일도 깨끗하게 지워버림.</strong> (복구 불가능하니 주의!)</li>
</ul>
</li>
</ol>
<hr>
<h4 id="상황-b-이미-githuborigin에도-push-해버렸어-revert">상황 B: &quot;이미 GitHub(Origin)에도 Push 해버렸어&quot; (Revert)</h4>
<p>이미 <code>push</code>를 해서 팀원들도 볼 수 있는 상태라면, <code>reset</code>으로 몰래 기록을 지우면 족보가 꼬여서 큰일 남.</p>
<p>이때는 <strong>&quot;실수를 인정하는 새로운 커밋&quot;</strong>을 덮어씌워서 해결. </p>
<ul>
<li>이것을 <code>revert</code>라고 함.</li>
</ul>
<pre><code class="language-bash"># 1. 취소하고 싶은 커밋 ID를 확인 (git log --oneline)
# 예: a1b2c3d

# 2. 해당 커밋의 정반대 행동을 하는 커밋 생성
git revert a1b2c3d</code></pre>
<ul>
<li>이 명령어를 치면 에디터가 뜨는데, 그냥 저장하고 나오면(<code>:wq</code>) 됨.</li>
<li><strong>결과:</strong> &quot;실수로 비밀번호 올림&quot; 커밋은 그대로 남지만, 그 위에 <strong>&quot;Revert &#39;실수로 비밀번호 올림&#39;&quot;</strong>이라는 새 커밋이 생기면서 코드는 원상 복구됩니다.</li>
<li>그 후 <code>git push origin [브랜치명]</code> 하시면 됩니다.</li>
</ul>
<hr>
<h3 id="3-요약">3. 요약</h3>
<ol>
<li><strong>확인한다:</strong>
<code>git log --oneline</code></li>
<li><strong>아직 안 올렸으면 (내 컴퓨터):</strong>
<code>git reset --soft HEAD~1</code> (코드 살림)</li>
<li><strong>이미 올렸으면 (GitHub):</strong>
<code>git revert [커밋ID]</code> (취소 커밋 생성)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[git] branch]]></title>
            <link>https://velog.io/@ma-kjh/git-branch</link>
            <guid>https://velog.io/@ma-kjh/git-branch</guid>
            <pubDate>Sun, 04 Jan 2026 11:51:58 GMT</pubDate>
            <description><![CDATA[<h3 id="1단계-내-컴퓨터에서-만들기">1단계: 내 컴퓨터에서 만들기</h3>
<p>GitHub에는 아직 없고, <strong>오직 내 컴퓨터(서버)</strong>에서만 존재하는 방을 먼저 만들어야 함.</p>
<pre><code class="language-bash"># &#39;브랜치를 만드는&#39; 명령어입니다.
git checkout -b feat/dataloader</code></pre>
<p>👉 이 시점에서는 <strong>나만</strong> <code>feat/dataloader</code>라는 브랜치를 가지고 있고, GitHub는 이 존재를 전혀 모릅니다.</p>
<hr>
<h3 id="2단계-github에도-똑같이-만들기-나중에-함">2단계: GitHub에도 똑같이 만들기 (나중에 함)</h3>
<p>이제 내가 만든 방을 GitHub에도 똑같이 만들어달라고 요청하는 것이 <code>push</code>입니다.</p>
<pre><code class="language-bash"># 이 명령어가 &#39;GitHub에 등록하는&#39; 명령어입니다.
git push origin feat/dataloader</code></pre>
<p>👉 여기서 브랜치 이름을 적어주는 이유가 바로 이것입니다.
<strong>&quot;내 컴퓨터에는 <code>feat/dataloader</code>라는 게 이미 만들어져 있으니, GitHub 너도 똑같은 이름으로 방을 하나 새로 파라!&quot;</strong> 라고 명령하는 것입니다.</p>
<hr>
<h3 id="순서">순서</h3>
<ol>
<li>Local : <code>git checkout -b 이름</code></li>
<li>Work : 작업을 하고 커밋</li>
<li>Remote (GitHub) : <code>git push origin 이름</code>으로 GitHub에도 그 브랜치를 생성시킴.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[git] push]]></title>
            <link>https://velog.io/@ma-kjh/git-push</link>
            <guid>https://velog.io/@ma-kjh/git-push</guid>
            <pubDate>Sun, 04 Jan 2026 11:47:17 GMT</pubDate>
            <description><![CDATA[<p><strong>⚠️직접 터미널에서 git push origin main을 입력하는 것은 절대 금지!!!</strong></p>
<p><code>git push origin [브랜치이름]</code> 명령어는 &quot;어디로(origin), 무엇을(branch) 보낼지&quot; 명확하게 지정</p>
<ol>
<li>GitHub에는 아직 브랜치가 없다.</li>
</ol>
<ul>
<li>본인의 컴퓨터에서 <code>feat/dataloader</code> 라는 브랜치를 새로 만듦</li>
<li>하지만 GitHub(원격)에는 아직 <code>main</code> 방밖에 없고, <code>feat/dataloaer</code> 라는 방은 없는 상태.</li>
</ul>
<p>이때 <code>git push origin feat/dataloader</code> 라고 딱 짚어서 말해줘야, GitHub가 <code>feat/dataloader</code>라는 방을 새로 만들고 거기에 코드를 넣으라는 구나 알아들음</p>
<ol start="2">
<li>실수 방지</li>
</ol>
<ul>
<li>개발자의 컴퓨터에는 보통 수많은 브랜치가 지저분하게 깔림</li>
<li>그냥 git push라고만 하면, 설정에 따라 원치 않는 쓰레기 코드나 테스트용 브랜치까지 몽땅 올라갈 위험.</li>
</ul>
<ol start="3">
<li>다른 이름으로 보낼 수도 있음</li>
</ol>
<p><code>git push origin feat/A:feat/B</code> 라고 하면 <code>feat/A</code>라고 나 컴퓨터에 있는 브랜치를 <code>feat/B</code>라는 이름으로 올릴 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[git] Pull Request (PR)]]></title>
            <link>https://velog.io/@ma-kjh/git-2.-Pull-Request</link>
            <guid>https://velog.io/@ma-kjh/git-2.-Pull-Request</guid>
            <pubDate>Sun, 04 Jan 2026 08:45:33 GMT</pubDate>
            <description><![CDATA[<p>팀 프로젝트에서는 main 브랜치를 신성한 곳으로 취급하여 절대 바로 수정하지 않습니다.</p>
<p>핵심 흐름:</p>
<ol>
<li>작업 공간(Branch) 따로 만들기</li>
<li>작업 후 내 공간만 GitHub에 올리기</li>
<li>&quot;내 거 합쳐줘&quot;라고 요청서(PR) 보내기</li>
<li>승인되면 합치기(Merge)</li>
</ol>
<p><strong>1단계 : 작업 공간(Branch) 만들기 (서버 터미널)</strong></p>
<p>가상의 상황을 만들어보죠. <strong>&quot;새로운 기능인 데이터 로더(dataloader)를 만든다&quot;</strong>고 가정합시다.</p>
<pre><code class="language-bash"># 1. 현재 내가 main 브랜치에 있는지 확인
git checkout main

# 2. 최신 상태로 업데이트 (습관적으로 해야 함)
git pull origin main

# 3. 새로운 브랜치 생성 및 이동 (이름은 보통 feat/기능명, fix/버그명)
git checkout -b feat/dataloader</code></pre>
<ul>
<li>git checkout -b는 &quot;브랜치를 만들고(-b) 거기로 이동해라&quot;라는 명령어입니다.</li>
<li>이제 터미널 프롬프트가 (feat/dataloader)로 바뀌었을 겁니다.</li>
</ul>
<p><strong>2단계: 작업하고 커밋하기 (서버 터미널)</strong></p>
<p>이제 안심하고 코드를 막 수정하세요. 여기서 망쳐도 main은 멀쩡합니다.</p>
<pre><code class="language-bash"># 1. 파일 생성 또는 수정
echo &quot;print(&#39;Data Loading...&#39;)&quot; &gt; dataloader.py

# 2. 장바구니 담기
git add .

# 3. 커밋 (작업 저장)
git commit -m &quot;Add dataloader base code&quot;</code></pre>
<p><strong>3단계: 내 브랜치 업로드 (서버 터미널)</strong></p>
<p>이제 중요한 점은 git push origin main이 아닙니다. 내가 만든 브랜치 이름으로 올려야 합니다.</p>
<pre><code class="language-bash">git push origin feat/dataloader</code></pre>
<ul>
<li>이러면 GitHub에 main 말고 feat/dataloader라는 줄기가 하나 더 생깁니다.</li>
</ul>
<p><strong>4단계: Pull Request(PR) 만들기 (GitHub 웹사이트)</strong></p>
<ul>
<li>이제 서버 할 일은 끝났고, GitHub 웹페이지로 가세요.</li>
</ul>
<ol>
<li>저장소(Repository) 메인 페이지에 들어가면, 방금 올린 브랜치 때문에 노란색 박스와 함께 <strong>&quot;Compare &amp; pull request&quot;</strong>라는 초록색 버튼이 생겼을 겁니다. 클릭하세요.<ul>
<li>(만약 안 보이면 &#39;Pull requests&#39; 탭 -&gt; &#39;New pull request&#39; -&gt; &#39;feat/dataloader&#39; 선택)</li>
</ul>
</li>
<li>Open a pull request 화면이 나옵니다.<ul>
<li>Title: &quot;데이터 로더 기능 추가 구현&quot;</li>
<li>Description: &quot;어떤 기능을 만들었고, 어떻게 테스트했는지 적습니다.&quot;</li>
<li>Reviewers: (팀원이 있다면) 여기서 동료를 지정합니다.</li>
</ul>
</li>
<li>Create pull request 버튼 클릭.</li>
</ol>
<p>👉 이 상태가 바로 &quot;검토 대기 중&quot;인 상태입니다.
실제 회사라면 여기서 동료들이 코드를 보고 댓글(Review)을 달아줍니다.</p>
<p><strong>5단계: 합치기 (Merge) (GitHub 웹사이트)</strong></p>
<p>팀원이 검토를 끝냈다고 가정하고, 본인이 직접 합쳐보겠습니다.</p>
<ol>
<li>PR 화면 하단의 &quot;Merge pull request&quot; 초록색 버튼 클릭.</li>
<li>&quot;Confirm merge&quot; 클릭.</li>
<li>상태가 <strong>Merged(보라색)</strong>로 바뀌면 성공입니다.</li>
<li>옆에 &quot;Delete branch&quot; 버튼이 나오면 눌러주세요. (이미 합쳤으니 GitHub에 있는 찌꺼기 브랜치는 지우는 게 깔끔합니다.)</li>
</ol>
<p><strong>6단계: 내 컴퓨터(서버) 동기화 (서버 터미널)</strong></p>
<p>GitHub(원격)의 main은 이제 코드가 합쳐져서 최신이 되었지만, 내 서버의 main은 아직 옛날 상태입니다. 업데이트를 해줘야 사이클이 끝납니다.</p>
<pre><code class="language-bash"># 1. 다시 main 브랜치로 돌아오기
git checkout main

# 2. GitHub에서 최신 변경 사항(합쳐진 코드) 가져오기
git pull origin main
# (이제 dataloader.py 파일이 main에도 생겼을 겁니다)

# 3. 다 쓴 작업 브랜치 삭제하기 (청소)
git branch -d feat/dataloader</code></pre>
<hr>
<p>요약 (이 사이클만 반복하세요)</p>
<ol>
<li>git checkout -b feat/기능이름 (작업방 만들기)</li>
<li>git add . -&gt; git commit (작업하기)</li>
<li>git push origin feat/기능이름 (GitHub에 올리기)</li>
<li>웹에서 PR 작성 &amp; Merge (합치기)</li>
<li>git checkout main -&gt; git pull origin main (내 컴퓨터 업데이트)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[git] 시작 ]]></title>
            <link>https://velog.io/@ma-kjh/git</link>
            <guid>https://velog.io/@ma-kjh/git</guid>
            <pubDate>Sun, 04 Jan 2026 08:39:15 GMT</pubDate>
            <description><![CDATA[<p>Google, Meta, Amazon 등은 각자 자체적인 도구를 쓰기도 하지만, 기본 철학은 &quot;Git Flow&quot; 또는 <strong>&quot;Trunk-Based Development&quot;</strong>와 유사하며 GitHub의 Pull Request(PR) 시스템을 핵심으로 사용합니다.</p>
<p>핵심 프로세스는 다음과 같습니다:</p>
<ul>
<li>Issue(티켓) 생성: &quot;로그인 버튼 버그 수정&quot; 같은 작업 단위를 정의합니다 (Jira나 GitHub Issues 사용).</li>
<li>Branch 생성: 메인 코드(main 또는 master)를 직접 건드리지 않습니다. feat/login-fix 같은 새로운 가지(Branch)를 따서 작업합니다.</li>
<li>Code &amp; Commit: 코드를 수정하고 의미 있는 단위로 커밋(Commit)합니다.</li>
<li>Pull Request (PR) 작성: &quot;내 코드를 메인 코드에 합쳐줘&quot;라고 요청서를 보냅니다.</li>
<li>Code Review (가장 중요): 동료들이 코드를 라인 단위로 뜯어보고 피드백을 줍니다. (변수명, 로직, 보안 문제 등). 승인(Approve)이 없으면 절대 합쳐지지 않습니다.</li>
<li>CI (Continuous Integration): PR을 올리는 순간 자동화된 서버가 돌면서 테스트 코드(Test Case) 수천 개를 실행합니다. 여기서 에러가 나면 수정해야 합니다.</li>
<li>Merge: 리뷰 승인 + 테스트 통과가 되면 메인 코드에 합쳐집니다(Merge).</li>
</ul>
<p>개인 서버(Linux/Ubuntu 등)에서 GitHub에 안전하게 접속하고 코드를 올리는 가장 정석적인 방법은 SSH Key를 사용하는 것입니다.</p>
<p><strong>1단계: Git 설치 및 기본 설정 (서버 터미널)</strong>
서버에 git이 없다면 설치하고, 본인의 정보를 등록합니다.</p>
<pre><code class="language-bash"># 1. git 설치
sudo apt-get update
sudo apt-get install git -y

# 2. 유저 이름과 이메일 등록 (GitHub에 가입한 이메일 권장)
git config --global user.name &quot;Your Name&quot;
git config --global user.email &quot;your_email@example.com&quot;</code></pre>
<p><strong>2단계: SSH 키 생성 (서버 터미널)</strong>
서버가 GitHub에 &quot;내가 주인이다&quot;라고 증명할 열쇠를 만듭니다.</p>
<pre><code class="language-bash"># 이메일 주소는 본인 GitHub 이메일로 변경하세요
ssh-keygen -t ed25519 -C &quot;your_email@example.com&quot;</code></pre>
<ul>
<li>명령어를 치면 Enter file in which to save the key... 등이 나오는데 그냥 Enter를 3번 연속 누르세요 (기본 경로 저장, 암호 없음).</li>
</ul>
<p><strong>3단계: 공개키(Public Key) 복사 (서버 터미널)</strong>
만들어진 열쇠 중 &quot;공개된 열쇠&quot; 내용을 확인하고 복사합니다.</p>
<pre><code class="language-bash">cat ~/.ssh/id_ed25519.pub</code></pre>
<ul>
<li>ssh-ed25519 AAA... 로 시작하는 긴 문자열이 나옵니다. 이 전체를 마우스로 드래그해서 복사하세요.</li>
</ul>
<p><strong>4단계: GitHub에 키 등록 (웹 브라우저)</strong></p>
<ol>
<li>GitHub에 로그인합니다.</li>
<li>우측 상단 프로필 아이콘 클릭 -&gt; Settings 클릭.</li>
<li>좌측 메뉴에서 SSH and GPG keys 클릭.</li>
<li>New SSH key 초록색 버튼 클릭.<ul>
<li>Title: 내 서버 이름 (예: My Private Server)</li>
<li>Key: 아까 복사한 ssh-ed25519... 내용을 붙여넣기.</li>
</ul>
</li>
<li>Add SSH key 클릭.</li>
</ol>
<p><strong>5단계: 연결 테스트 (서버 터미널)</strong>
서버로 돌아와서 잘 연결됐는지 확인합니다.</p>
<pre><code class="language-bash">ssh -T git@github.com</code></pre>
<ul>
<li>처음에 Are you sure you want to continue connecting? 라고 물으면 yes 입력.</li>
<li>Hi [username]! You&#39;ve successfully authenticated... 라는 메시지가 나오면 성공입니다.</li>
</ul>
<p><strong>6단계: GitHub에 새 프로젝트(Repository) 만들기 (웹 브라우저)</strong></p>
<ol>
<li>GitHub 메인 페이지 우측 상단의 + 버튼 -&gt; New repository.</li>
<li>Repository name 입력 (예: my-server-project).</li>
<li>Public/Private 선택 (비공개로 하려면 Private).</li>
<li>Create repository 클릭.</li>
<li>화면에 나오는 주소 중 SSH 버튼을 클릭해서 주소를 복사해둡니다. (예: <a href="mailto:git@github.com">git@github.com</a>:User/my-server-project.git)</li>
</ol>
<p><strong>7단계: 서버에서 프로젝트 시작 및 업로드 (서버 터미널)</strong>
이제 서버에서 폴더를 만들고 GitHub에 코드를 올려봅시다.</p>
<pre><code class="language-bash"># 1. 프로젝트 폴더 생성 및 진입
mkdir my-server-project
cd my-server-project

# 2. git 초기화 (이 폴더를 git으로 관리하겠다)
git init

# 3. 방금 만든 GitHub 저장소와 연결 (아까 복사한 SSH 주소 사용)
# git remote add origin [복사한 SSH 주소]
git remote add origin git@github.com:YourID/my-server-project.git

# 4. 테스트 파일 생성
echo &quot;# My First Project&quot; &gt; README.md

# 5. 파일을 장바구니에 담기 (Staging)
git add .

# 6. 버전을 확정짓기 (Commit)
git commit -m &quot;First commit from server&quot;

# 7. GitHub로 쏘아 올리기 (Push)
# 처음 올릴 때는 -u 옵션을 써서 기본 업로드 경로를 지정해줍니다.
git push -u origin main</code></pre>
<p>(참고: 만약 브랜치 이름이 master로 되어 있다면 git branch -M main 명령어로 main으로 바꿔주는 것이 요즘 추세입니다.)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]Resize]]></title>
            <link>https://velog.io/@ma-kjh/PytorchResize</link>
            <guid>https://velog.io/@ma-kjh/PytorchResize</guid>
            <pubDate>Thu, 23 Oct 2025 12:07:13 GMT</pubDate>
            <description><![CDATA[<p>Pytorch의 Resize에 대해서 알아보자.</p>
<h1 id="resize">Resize</h1>
<hr>
<p><code>CLASS torchvision.transforms.Resize(size, interpolation=InterpolationMode.BILINEAR, max_size=None, antialias=True)</code></p>
<p>Resize the input image to the given size. If the image is torch Tensor, it is expected to have [..., H, W] shape, where ... means a maximum of two leading dimensions</p>
<h3 id="parameters">Parameters:</h3>
<ul>
<li><p><strong>size</strong> (sequence or <code>int</code>)-
<code>Desired output size. If size is a sequence like (h,w), output size will be matched to this. if size is an int, smaller edge of the image will be matched to this number. i.e, if height &gt; width, then image will be rescaled to (height * size / width, size).</code></p>
</li>
<li><p>🔥[주의]🔥 <strong>size</strong> 입력 시에 <code>int</code>로 입력하면 <code>h, w</code> 중 작은 값이 해당 size에 맞춰지고 다른 쪽은 기존 ratio에 맞게 resize됨. </p>
</li>
</ul>
<blockquote>
<p>Note</p>
</blockquote>
<ul>
<li><p>In torchscript mode size as single int is not supported, use a sequence of length 1: <code>[size, ]</code>.</p>
</li>
<li><p><strong>Interpolation</strong> (InterploationMode) - Desired interpolation enum defined by <code>torchvision.transforms.InterpolationMode</code>. Default is <code>InterpolationMode.BILINEAR</code>. If input is Tensor, only <code>InterpolationMode.NEAREST,InterpolationMode.NEAREST_EXACT,InterpolationMode.BILINEAR</code> and <code>InterpolationMode.BICUBIC</code> are supported. The corresponding Pillow integer constants, e.g. <code>PIL.Image.BILINEAR</code> are accepted as well.</p>
</li>
<li><p>🔥[주의]🔥 <code>torchvision.transforms.InterpolationMode</code> 는 이미지의 크기를 변경할 때, 새로운 픽셀의 값을 어떻게 채워 넣을지 결정하는 수학적인 방법임; 이미지를 늘리거나 줄이면 기존 픽셀 정보만으로는 부족해서 주변 픽셀을 참고해서 새 픽셀을 <code>추정</code> 해야하는데 이 방식을 <code>보간(Interpolation)</code> 이라고 한다. </p>
<ul>
<li>NEAREST : 가장 가까운 원본 픽셀의 값을 그대로 복사하여 사용함; 가장 빠르지만, 결과 이미지의 경계선이 거칠고 계단 현상(aliasing)이 뚜렷하게 나타남.</li>
<li>NEAREST_EXACT : NEAREST와 유사한데, 좌표 정렬 방식에서 약간의 기술적 정밀도를 높인 버전; 일반적인 NEAREST보다 약간 더 정확한 픽셀 매핑이 필요할 때 사용됨.</li>
<li>BILINEAR : 새로운 픽셀 주변의 4개 픽셀을 사용하여 가중 평균을 계산; 속도와 결과 품질의 균형이 가장 좋아서 이미지 모델 훈련에서 가장 일반적으로 사용되는 기본값.</li>
<li>BICUBIC : 새로운 픽셀 주변의 16개 픽셀 (4x4격자)를 사용하여 훨씬 더 복잡한 곡선 방정식을 적용; 가장 부드럽고 고화질의 결과물을 제공하지만, 계산량이 많아 가장 느림.</li>
</ul>
</li>
<li><p><strong>max_size</strong> (<code>int,optional</code>) - The maximum allowed for the longer edge of the resized image. If the longer edge of the image is greater than <code>max_size</code> after being resized according to <code>size</code>, <code>size</code> will be overruled so that the longer edge is equal to <code>max_size</code>. As a result, the smaller edge may be shorter than <code>size</code>. This is only supported if <code>size</code> is an int (or a sequence of length 1 in torchscript mode).</p>
</li>
<li><p><strong>antialias</strong> (<code>bool,optional</code>) - Whether to apply antialiasing. It only affects tensors with bilinear of bicubic modes and it is ignored otherwise: on PIL images, antialiasing is always applied on bilinear or bicubic modes; on ther modes (for PIL images and tensors), antialiasing makes no sense and this parameter is ignored. Possible values are:</p>
<ul>
<li>True (default) : will apply antialiasing for bilinear or bicubic modes. Other mode aren&#39;t affected. This is probably what you want to use.</li>
<li>False : will not apply antialiasing for tensors on any model. PIL images are still antialiased on bilinear or bicubic modes, because PIL doesn&#39;t support no antialias.</li>
<li>None : equivalent to False for tensors and True for PIL images. This Value exists for legacy reasons and you probably don&#39;t want to use it unless you really know what you are doing.</li>
<li>The default value changed from None to True in v0.17, for the PIL and Tensor backends to be consistent.</li>
</ul>
</li>
<li><p>🔥[주의]🔥  Antialias은 이미지를 resize할 때 발생하는 jagged edges 를 부드럽게 처리하여 이미지 품질을 개선하는 기술</p>
</li>
<li><ul>
<li>문제 : 이미지를 Downsampling할 때, 대각선이나 곡선의 날카로운 경계선에 있던 픽셀들이 뭉쳐지면서 깨진 것처럼 보이거나 계단 모양으로 거칠게 변화함.</li>
</ul>
</li>
<li><ul>
<li>해결책 (Antialiasing) : 안티 얼라이어싱을 적용하면, 경계선 주변 픽셀들의 색상과 배경색을 미세하게 섞어서 (약간의 블러) 픽셀 경계를 부드럽게 만들고 시각적인 거슬림을 줄인다. 결과적으로 모델이 더 자연스로운 입력을받음.</li>
</ul>
</li>
<li><ul>
<li>지원되는 보간모드는 <code>BILINEAR</code> and <code>BICUBIC</code> : 이 모드들은 이미 주변 픽셀들을 Blending 방식으로 새로운 픽셀을 추정. 안티앨리어싱은 이 블렌딩 과정을 경계선에서 더 정교하게 만들어서 화질을 높임.</li>
</ul>
</li>
<li><ul>
<li><code>NEAREST</code> : 이 모드는 주변 픽셀 중 하나를 선택만하고 섞지 않아서, 안티앨리어싱을 적용하는 것이 무의미하거나 지원이 안됨.</li>
</ul>
</li>
</ul>
<hr>
<h1 id="reference">Reference</h1>
<p><a href="https://docs.pytorch.org/vision/main/generated/torchvision.transforms.Resize.html">https://docs.pytorch.org/vision/main/generated/torchvision.transforms.Resize.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[LLM sampling] token prediction]]></title>
            <link>https://velog.io/@ma-kjh/LLM-sampling-token-prediction</link>
            <guid>https://velog.io/@ma-kjh/LLM-sampling-token-prediction</guid>
            <pubDate>Mon, 20 Jan 2025 05:57:03 GMT</pubDate>
            <description><![CDATA[<p>LLM(대규모 언어 모델)에서 마지막 토큰의 출력을 생성할 때, 다양한 샘플링 기법이 사용됩니다. 이러한 기법은 모델의 출력을 제어하여 보다 자연스럽거나 특정한 특징을 가지는 텍스트를 생성하도록 돕습니다. 아래는 주요 샘플링 기법과 그 예시에 대한 구체적인 설명입니다.</p>
<hr>
<h3 id="1-greedy-search-탐욕적-탐색"><strong>1. Greedy Search (탐욕적 탐색)</strong></h3>
<ul>
<li><p><strong>설명</strong>: 확률이 가장 높은 토큰을 반복적으로 선택하는 방법입니다.</p>
</li>
<li><p><strong>특징</strong>: 단순하고 빠르지만, 항상 동일한 결과를 생성하고 다양성이 부족할 수 있습니다. 로컬 최적화로 인해 비문법적이거나 의미가 없는 문장이 나올 가능성도 있습니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<pre><code class="language-python">logits = [0.1, 0.3, 0.6]  # 토큰 확률
selected_token = argmax(logits)  # 확률이 가장 높은 토큰 선택 (2번째 토큰)</code></pre>
<ul>
<li>토큰 3((0.6))이 선택됩니다.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-beam-search"><strong>2. Beam Search</strong></h3>
<ul>
<li><p><strong>설명</strong>: 여러 개의 후보 시퀀스(빔)를 유지하며 확장하는 방법입니다. 각 단계에서 가장 높은 확률을 가진 ( k )개의 시퀀스를 선택하여 다음 단계로 이어갑니다.</p>
</li>
<li><p><strong>특징</strong>: 보다 최적화된 시퀀스를 생성하지만, 다양성이 부족하고 계산 비용이 큽니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<ul>
<li>( k = 2 ) (빔 크기 2)</li>
<li>단계 1: &quot;The cat&quot; (( P = 0.7 )), &quot;The dog&quot; (( P = 0.6 ))</li>
<li>단계 2: &quot;The cat sat&quot; (( P = 0.7 \times 0.8 )), &quot;The cat jumped&quot; (( P = 0.7 \times 0.5 )) 등</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3-top-k-샘플링"><strong>3. Top-k 샘플링</strong></h3>
<ul>
<li><p><strong>설명</strong>: 확률이 상위 ( k )개에 해당하는 토큰만 고려하고, 나머지는 확률을 0으로 만들어 샘플링합니다.</p>
</li>
<li><p><strong>특징</strong>: 낮은 확률 토큰을 제거하여 비문법적인 출력을 줄이고, 높은 확률 토큰 내에서 무작위성을 유지합니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<pre><code class="language-python">logits = [0.1, 0.3, 0.6]  # 토큰 확률
k = 2
top_k_logits = [0.0, 0.3, 0.6]  # 상위 2개의 확률만 남김
selected_token = sample(top_k_logits)</code></pre>
<ul>
<li>토큰 2((0.3)) 또는 3((0.6))이 선택될 수 있음.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="4-top-p-샘플링-nucleus-sampling"><strong>4. Top-p 샘플링 (Nucleus Sampling)</strong></h3>
<ul>
<li><p><strong>설명</strong>: 누적 확률이 ( p ) (예: 0.9)를 넘을 때까지의 토큰만 고려합니다. 즉, 가장 중요한 확률 질량을 유지하며 나머지는 제거합니다.</p>
</li>
<li><p><strong>특징</strong>: 동적으로 토큰을 선택하므로, 텍스트의 다양성과 품질 간 균형을 맞출 수 있습니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<pre><code class="language-python">logits = [0.1, 0.2, 0.3, 0.4]  # 토큰 확률
p = 0.8
sorted_logits = [0.4, 0.3, 0.2, 0.1]
cumulative_probs = [0.4, 0.7, 0.9, 1.0]
selected_tokens = [0.4, 0.3]  # 누적 확률 0.8 이하인 토큰만 선택</code></pre>
<ul>
<li>토큰 4((0.4)) 또는 3((0.3))이 선택될 수 있음.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="5-temperature-샘플링"><strong>5. Temperature 샘플링</strong></h3>
<ul>
<li><p><strong>설명</strong>: 확률 분포를 조정하여 출력을 더 창의적이거나 더 결정적으로 만듭니다. 온도 ( T )를 사용하여 확률 분포를 다음과 같이 변환합니다:
[
P_i = \frac{\exp\left(\frac{\log P_i}{T}\right)}{\sum_j \exp\left(\frac{\log P_j}{T}\right)}
]</p>
<ul>
<li>( T &gt; 1 ): 확률 분포가 평탄해져 무작위성이 증가합니다.</li>
<li>( T &lt; 1 ): 확률 분포가 뾰족해져 탐욕적 선택에 가까워집니다.</li>
</ul>
</li>
<li><p><strong>특징</strong>: 모델의 출력 스타일을 제어할 수 있습니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<pre><code class="language-python">logits = [0.1, 0.3, 0.6]  # 토큰 확률
T = 0.5
adjusted_logits = [0.1**(1/0.5), 0.3**(1/0.5), 0.6**(1/0.5)]
selected_token = sample(adjusted_logits)</code></pre>
<ul>
<li>( T ) 값에 따라 높은 확률 토큰이 더 자주 선택됨.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="6-혼합-기법"><strong>6. 혼합 기법</strong></h3>
<p>현대의 LLM에서는 Top-k, Top-p, Temperature 등을 결합하여 최적의 출력을 생성합니다.</p>
<ul>
<li><strong>예시</strong>:<ul>
<li>Top-p로 중요한 확률 질량을 제한한 후, Temperature를 조정하여 무작위성을 추가.<pre><code class="language-python">logits = [0.1, 0.3, 0.6]  # 원래 확률
p = 0.8
T = 0.7
filtered_logits = apply_top_p(logits, p)
adjusted_logits = adjust_temperature(filtered_logits, T)
selected_token = sample(adjusted_logits)</code></pre>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="샘플링-기법-선택-기준"><strong>샘플링 기법 선택 기준</strong></h3>
<ol>
<li><strong>창의적 응답</strong>: Top-p + Temperature 샘플링</li>
<li><strong>결정적 응답</strong>: Greedy 또는 Beam Search</li>
<li><strong>다양성 확보</strong>: Top-k 또는 Nucleus Sampling</li>
</ol>
<p>이런 다양한 기법은 모델의 목적, 응용 사례, 요구 사항에 따라 유연하게 선택됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[metric] LLM evaluation metrics]]></title>
            <link>https://velog.io/@ma-kjh/metric-LLM-evaluation-metrics</link>
            <guid>https://velog.io/@ma-kjh/metric-LLM-evaluation-metrics</guid>
            <pubDate>Mon, 13 Jan 2025 07:04:25 GMT</pubDate>
            <description><![CDATA[<hr>
<ol>
<li>ROUGE</li>
<li>BLUE</li>
</ol>
<hr>
<h1 id="1-rouge">1. ROUGE</h1>
<p><strong>ROUGE (Recall-Oriented Understudy for Gisting Evaluation)</strong>는 자동 요약이나 기계 번역 등의 자연어 생성 품질을 평가하기 위한 지표. ROUGE는 주로 <strong>생성된 텍스트와 기준(참조) 텍스트 사이에 얼마나 많은 n-gram, 단어, 혹은 연속된 단어(문장)를 공유하는지를 측정</strong>하는 방식. 대표적으로 사용되는 ROUGE 지표들에는 ROUGE-N, ROUGE-L 등이 있다.</p>
<hr>
<h2 id="1-rouge-n">1. ROUGE-N</h2>
<h3 id="개념"><strong>개념</strong></h3>
<ul>
<li><strong>ROUGE-N</strong>은 n-gram 기준의 겹치는 항목을 계산한다.</li>
<li><strong>n-gram</strong>은 텍스트에서 연속된 n개의 단어 집합을 의미한다.<ul>
<li><strong>ROUGE-1</strong>: 단일 단어(유니그램) 기준</li>
<li><strong>ROUGE-2</strong>: 두 단어(바이그램) 기준 등</li>
</ul>
</li>
</ul>
<h3 id="계산-방법"><strong>계산 방법</strong></h3>
<ol>
<li><strong>n-gram 추출</strong>  <ul>
<li>기준 텍스트(참조 요약)와 생성된 텍스트에서 각각의 n-gram을 추출.</li>
</ul>
</li>
<li><strong>겹치는 항목 수 계산</strong>  <ul>
<li>두 텍스트 간에 겹치는(n-gram) 개수를 센다. 이를 <strong>매치된 n-gram의 수 (overlap count)</strong>라고 한다.</li>
</ul>
</li>
<li><strong>정밀도(Precision), 재현율(Recall), F1 스코어 계산</strong>  <ul>
<li><strong>재현율 (Recall)</strong>:  
$$ 
\text{Recall} = \frac{\text{매치된 n-gram 수}}{\text{기준 텍스트의 총 n-gram 수}} $$</li>
<li><strong>정밀도 (Precision)</strong>:  
$$
\text{Precision} = \frac{\text{매치된 n-gram 수}}{\text{생성된 텍스트의 총 n-gram 수}}
$$</li>
<li><strong>F1 스코어 (F1 score)</strong>:  
재현율과 정밀도의 조화평균.<br>$$
\text{F1} = \frac{2 \times \text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}} 
$$</li>
</ul>
</li>
</ol>
<hr>
<h2 id="2-rouge-l">2. ROUGE-L</h2>
<h3 id="개념-1"><strong>개념</strong></h3>
<ul>
<li><strong>ROUGE-L</strong>은 두 텍스트 간의 <strong>최장 공통 부분 수열(Longest Common Subsequence, LCS)</strong>을 기반으로 함.</li>
<li>LCS는 두 시퀀스에서 순서를 유지하면서 일치하는 가장 긴 공통 부분을 의미한다.</li>
<li>ROUGE-L은 텍스트의 유창성과 문맥 구조를 평가하는 데 도움을 준다.</li>
</ul>
<h3 id="계산-방법-1"><strong>계산 방법</strong></h3>
<ol>
<li><strong>LCS 길이 계산</strong>  <ul>
<li>기준 텍스트와 생성된 텍스트 간의 최장 공통 부분 수열의 길이를 구합니다.</li>
</ul>
</li>
<li><strong>재현율, 정밀도, F1 스코어 계산</strong>  <ul>
<li><strong>재현율 (Recall)</strong>:  
$$ 
\text{Recall} = \frac{\text{LCS 길이}}{\text{기준 텍스트의 단어 수}} 
$$</li>
<li><strong>정밀도 (Precision)</strong>:  
$$ 
\text{Precision} = \frac{\text{LCS 길이}}{\text{생성된 텍스트의 단어 수}} 
$$</li>
<li><strong>F1 스코어 (F1 score)</strong>:  
두 값의 조화 평균으로 계산합니다.<br>$$ 
\text{F1} = \frac{2 \times \text{Precision} \times \text{Recall}}{\text{Precision} + \text{Recall}} 
$$</li>
</ul>
</li>
</ol>
<hr>
<h2 id="간단한-설명">간단한 설명</h2>
<ul>
<li><strong>목적</strong>: ROUGE는 자동 요약, 번역, 혹은 생성된 텍스트가 기준 텍스트와 어느 정도 일치하는지를 평가하는 데 사용.</li>
<li><strong>주요 아이디어</strong>:  <ul>
<li><strong>ROUGE-N</strong>은 n-gram의 중복률을 측정하여 <strong>텍스트의 정확성</strong>을 평가.</li>
<li><strong>ROUGE-L</strong>은 텍스트 간의 <strong>연속된 일치 패턴(최장 공통 부분 수열)</strong>을 기반으로 <strong>문맥 및 유창성</strong>을 측정합니다.</li>
</ul>
</li>
<li><strong>응용분야</strong>:  <ul>
<li>텍스트 요약 평가</li>
<li>기계 번역 품질 평가</li>
<li>기타 자연어 생성 시스템의 출력 평가</li>
</ul>
</li>
</ul>
<p>ROUGE 스코어는 생성된 텍스트가 얼마나 원본(참조) 텍스트의 중요한 내용을 잘 담고 있는지를 수치화하는 지표로 많이 활용됩니다.</p>
<hr>
<h1 id="2-blue">2. BLUE</h1>
<p><strong>BLEU (Bilingual Evaluation Understudy) score</strong>는 기계 번역 결과와 참조(reference) 번역 사이의 <strong>유사도를 평가하는 대표적인 자동 평가 지표</strong>. BLEU 스코어는 주로 후보 번역이 참조 번역의 n-gram을 얼마나 잘 포함하는지를 기반으로 계산하며, <strong>수정된 n-gram precision</strong>과 <strong>brevity penalty (길이 패널티)</strong>를 함께 고려.</p>
<hr>
<h2 id="bleu-score-계산-방법">BLEU Score 계산 방법</h2>
<h3 id="1-n-gram-추출-및-수정된-n-gram-precision-계산">1. <strong>n-gram 추출 및 수정된 n-gram Precision 계산</strong></h3>
<ol>
<li><p><strong>n-gram 추출</strong>:  
후보 번역과 하나 이상의 참조 번역에서 n-gram (예: unigram, bigram, trigram, ... 등)을 추출.</p>
</li>
<li><p><strong>클리핑(clip) 카운트</strong>:  </p>
<ul>
<li>각 후보 번역의 n-gram에 대해, 해당 n-gram이 참조 번역에서 나타나는 최대 빈도수를 구함.</li>
<li>후보 번역에서 해당 n-gram의 등장 횟수를 참조 번역에서의 최대 등장 횟수와 비교하여, 후보에서의 n-gram 카운트를 <strong>클리핑</strong> 한다.<br>예를 들어, 후보 번역에서 &quot;the cat&quot;이 3번 나타나는데 참조에서는 최대 2번만 등장한다면, &quot;the cat&quot;의 클리핑 카운트는 2가 된다.</li>
</ul>
</li>
<li><p><strong>수정된 n-gram Precision 계산</strong>:  
모든 n-gram에 대해, 클리핑된 카운트의 총합을 후보 번역 전체의 n-gram 총개수로 나눈다.
$$
p_n = \frac{\sum_{\text{n-gram} \in \text{candidate}} \min(\text{count in candidate}, \text{max count in references})}{\text{총 후보 n-gram 개수}}
$$</p>
</li>
</ol>
<h3 id="2-geometric-mean-계산">2. <strong>Geometric Mean 계산</strong></h3>
<ul>
<li>여러 n-gram (보통 1-gram부터 4-gram까지)에 대해 수정된 precision $p_n$의 <strong>기하평균(geometric mean)</strong>을 구한다.</li>
<li>보통 등가의 가중치 $w_n$ (대개 $w_n = \frac{1}{N}$, 여기서 $N$은 사용한 n-gram의 최대 크기)를 부여한다.</li>
<li>기하평균은 다음과 같이 계산된다.
$$
\text{Precision}<em>{\text{geom}} = \exp\left(\sum</em>{n=1}^{N} w_n \cdot \ln(p_n)\right)
$$</li>
</ul>
<h3 id="3-brevity-penalty-길이-패널티-적용">3. <strong>Brevity Penalty (길이 패널티) 적용</strong></h3>
<ul>
<li>후보 번역이 참조 번역보다 지나치게 짧으면 높은 precision을 갖더라도 과도한 스코어가 나오는 것을 방지하기 위해 <strong>Brevity Penalty (BP)</strong>를 적용합니다.</li>
<li>후보 번역 길이 $c$와 참조 번역 길이 $r$에 기반하여 다음과 같이 계산합니다.
$$
BP =
\begin{cases}
1 &amp; \text{if } c &gt; r, \
\exp\left(1 - \frac{r}{c}\right) &amp; \text{if } c \le r.
\end{cases}
$$</li>
</ul>
<h3 id="4-최종-bleu-score-계산">4. <strong>최종 BLEU Score 계산</strong></h3>
<ul>
<li>최종 BLEU 스코어는 기하평균과 Brevity Penalty를 곱하여 얻습니다.
$$
\text{BLEU} = BP \cdot \exp\left(\sum_{n=1}^{N} w_n \cdot \ln(p_n)\right)
$$</li>
</ul>
<hr>
<h2 id="간단한-설명-1">간단한 설명</h2>
<ul>
<li><p><strong>목적</strong>: 후보 번역과 참조 번역 간의 n-gram 매칭을 기반으로 번역의 질을 평가하는 지표.</p>
</li>
<li><p><strong>핵심 아이디어</strong>:  </p>
<ol>
<li>후보 번역에 포함된 n-gram이 참조 번역에도 동일하게 등장하는지 확인한다.</li>
<li>각 n-gram의 중복 횟수를 참조에서의 최대 빈도로 클리핑하여 과도한 중복을 방지한다.</li>
<li>여러 n-gram 순서에 대해 수정된 precision의 기하평균을 계산한다.</li>
<li>후보 번역이 참조 번역보다 너무 짧으면 벌점을 주어 스코어를 낮춘다.</li>
</ol>
</li>
<li><p><strong>특징</strong>: BLEU는 <strong>자동 평가 지표</strong>로 널리 사용되지만, 문맥의 유창성이나 문법적 정확성 등을 직접 평가하지는 않으므로, 인간 평가와 함께 고려하는 것이 일반적이다.</p>
</li>
</ul>
<p>이와 같은 과정으로 BLEU 스코어를 계산하며, 번역 시스템 및 자연어 생성 모델의 성능을 비교 평가할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[metric] Expected Calibration Error (ECE)]]></title>
            <link>https://velog.io/@ma-kjh/Expected-Calibration-Error-ECE</link>
            <guid>https://velog.io/@ma-kjh/Expected-Calibration-Error-ECE</guid>
            <pubDate>Sat, 04 Jan 2025 07:56:55 GMT</pubDate>
            <description><![CDATA[<h2 id="ece란">ECE란?</h2>
<ul>
<li>Expected Calibration Error (ECE)는 모델이 예측한 확률과 실제 정확도 간의 차이를 측정하는 지표.</li>
<li>모델이 &quot;0.8의 확률로 맞다&quot;라고 예측할 때 실제로 약 80%의 정확도로 맞는지를 확인하여, <strong>모델의 신뢰도(Confidence)</strong>를 평가.</li>
</ul>
<h3 id="expected-calibration-error-ece-계산-방법"><strong>Expected Calibration Error (ECE) 계산 방법</strong></h3>
<h4 id="ece-계산-공식"><strong>ECE 계산 공식</strong></h4>
<p>$$
ECE = \sum_{m=1}^{M} \frac{|B_m|}{n} \cdot \left| \text{acc}(B_m) - \text{conf}(B_m) \right|
$$</p>
<ul>
<li>$M$: 총 bin의 개수 (일반적으로 10개)</li>
<li>$B_m$: m번째 bin에 속하는 샘플들의 집합</li>
<li>$n$: 전체 샘플 수</li>
<li>$\text{acc}(B_m)$: 해당 bin에서의 정확도<br>$$
\text{acc}(B_m) = \frac{1}{|B_m|} \sum_{i \in B_m} \mathbf{1}(\hat{y_i} = y_i)
$$</li>
<li>$\text{conf}(B_m)$: 해당 bin에서의 평균 confidence<br>$$
\text{conf}(B_m) = \frac{1}{|B_m|} \sum_{i \in B_m} p_i
$$</li>
</ul>
<hr>
<h4 id="ece-계산-과정-예시"><strong>ECE 계산 과정 예시</strong></h4>
<ul>
<li><strong>모델의 예측 값</strong>: [0.92, 0.75, 0.55, 0.87, 0.66, 0.33]  </li>
<li><strong>실제 라벨</strong>: [1, 1, 0, 1, 0, 0]  </li>
<li><strong>bin의 개수 (M)</strong>: 3개로 설정 ([0.0-0.3], [0.3-0.6], [0.6-1.0])  </li>
</ul>
<p><strong>Step 1: bin별 분류</strong></p>
<ul>
<li><strong>Bin 1 (0.0~0.3)</strong>: 해당하는 데이터 없음 → 무시  </li>
<li><strong>Bin 2 (0.3~0.6)</strong>: [0.33] → 평균 confidence: 0.33, 정확도: 1.0  </li>
<li><strong>Bin 3 (0.6~1.0)</strong>: [0.92, 0.75, 0.55, 0.87, 0.66] → 평균 confidence: 0.75, 정확도: 0.6  </li>
</ul>
<p><strong>Step 2: ECE 계산</strong>
$$
ECE = \frac{1}{6} \left( |1.0 - 0.33| + 5 \cdot |0.75 - 0.6| \right) \approx 0.125
$$</p>
<hr>
<p>ECE는 <strong>딥러닝 모델의 calibration 성능</strong>을 평가할 수 있는 중요한 지표로, 특히 <strong>불확실성 기반 모델 평가 및 안전성</strong>을 요하는 분야에서 자주 사용.<br>이를 통해 모델이 지나치게 과신하거나 보수적인 예측을 하는지 판단할 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]args, kwargs]]></title>
            <link>https://velog.io/@ma-kjh/Pytorchargs-kwargs</link>
            <guid>https://velog.io/@ma-kjh/Pytorchargs-kwargs</guid>
            <pubDate>Mon, 23 Dec 2024 08:08:05 GMT</pubDate>
            <description><![CDATA[<p>파이썬에서 <strong><code>args</code></strong>와 <strong><code>kwwargs</code></strong>는 함수를 정의할 때 <strong>가변 인자</strong>(Variable-length arguments)를 받아들이기 위한 문법적 장치.</p>
<hr>
<h2 id="1-args-가변-위치-인자">1. <code>args</code> (가변 위치 인자)</h2>
<ul>
<li>여러 개의 <strong>위치 기반 인자</strong>를 <strong>튜플</strong> 형태로 전달받는다.</li>
<li>함수나 메서드를 호출할 때, 인자의 개수가 가변적일 수 있도록 유연성을 제공.</li>
</ul>
<pre><code class="language-python">def example_func(*args):
    for i, arg in enumerate(args):
        print(f&quot;args[{i}] = {arg}&quot;)

example_func(1, &quot;hello&quot;, 3.14)
# args[0] = 1
# args[1] = hello
# args[2] = 3.14</code></pre>
<hr>
<h2 id="2-kwargs-가변-키워드-인자">2. <code>kwargs</code> (가변 키워드 인자)</h2>
<ul>
<li>여러 개의 <strong>키워드 기반 인자</strong>를 <strong>딕셔너리</strong> 형태로 전달받는다.</li>
<li>딕셔너리의 키(문자열)는 해당 인수의 변수 이름이 되고, 값이 인수 값으로 할당됨.</li>
</ul>
<pre><code class="language-python">def example_func(**kwargs):
    for key, value in kwargs.items():
        print(f&quot;{key} = {value}&quot;)

example_func(name=&quot;Alice&quot;, age=30, job=&quot;Engineer&quot;)
# name = Alice
# age = 30
# job = Engineer</code></pre>
<hr>
<h2 id="3-클래스-__init__에서-사용되는-이유">3. 클래스 <code>__init__</code>에서 사용되는 이유</h2>
<h3 id="1-상위-클래스부모-클래스와-호환성">(1) 상위 클래스(부모 클래스)와 호환성</h3>
<ul>
<li><strong>상속</strong>을 사용할 때, 부모 클래스의 <code>__init__</code> 메서드가 받는 인자 형태를 그대로 자식 클래스에서도 받고 싶을 수 있음.</li>
<li>이때 자식 클래스의 <code>__init__</code>에서 <code>*args, **kwargs</code>를 통해 모든 인자를 받아 두었다가, 부모 클래스의 <code>__init__</code>에 넘길 수 있음.</li>
</ul>
<pre><code class="language-python">class Parent:
    def __init__(self, x, y, **kwargs):
        self.x = x
        self.y = y

class Child(Parent):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Child-specific initialization</code></pre>
<h3 id="2-유연성">(2) 유연성</h3>
<ul>
<li>클래스나 함수가 받을 <strong>매개변수의 수나 종류가 자주 변할 수 있는 상황</strong>에서, <code>*args</code>, <code>**kwargs</code>는 코드를 자주 수정할 필요 없이 유연하게 대응할 수 있다.</li>
</ul>
<hr>
<h2 id="4-요약">4. 요약</h2>
<ul>
<li><code>*args</code>: 여러 개의 <strong>위치 인자</strong>를 하나의 튜플로 받아옴.</li>
<li><code>**kwargs</code>: 여러 개의 <strong>키워드 인자</strong>를 하나의 딕셔너리로 받아옴.</li>
<li>클래스의 <code>__init__</code>에서 <code>*args</code>와 <code>**kwargs</code>를 사용하는 주된 이유는 <strong>상속 구조</strong>에서 인자를 <strong>유연하게 전달</strong>하기 위함이며, 다양한 함수 시그니처(매개변수 형태)에 대응하기 위한 편의성도 제공.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]CrossEntropyLoss(weight)]]></title>
            <link>https://velog.io/@ma-kjh/PytorchCrossEntropyLossweight</link>
            <guid>https://velog.io/@ma-kjh/PytorchCrossEntropyLossweight</guid>
            <pubDate>Mon, 23 Dec 2024 08:02:23 GMT</pubDate>
            <description><![CDATA[<p><code>CrossEntropyLoss</code>에서 <strong>가중치(weight)</strong>는 <strong>softmax를 적용한 확률</strong>이 아니라, <strong>최종 손실 값</strong>에 곱해짐. 따라서 가중치는 <strong>로그 확률에 곱해서 손실을 조정하는 역할</strong>.</p>
<hr>
<h3 id="1-crossentropyloss-공식">1. <strong>CrossEntropyLoss 공식</strong></h3>
<p>$$
\text{Loss} = -\frac{1}{N} \sum_{i=1}^N \text{weight}[y_i] \cdot \log(\hat{p}_{i,y_i})
$$
여기서:</p>
<ul>
<li>$N$: 배치 내 샘플 수.</li>
<li>$y_i$: 샘플 $i$의 정답 클래스.</li>
<li>$\hat{p}_{i,y_i}$: 모델이 예측한 샘플 $i$의 정답 클래스 확률 (softmax 값).</li>
<li>$\text{weight}[y_i]$: 정답 클래스 $y_i$에 대응하는 가중치.</li>
</ul>
<hr>
<h3 id="2-softmax-계산">2. <strong>Softmax 계산</strong></h3>
<p><code>logits</code>를 사용하여 <strong>softmax</strong>를 계산합니다. Softmax는 모델이 출력한 raw logits를 <strong>확률 분포</strong>로 변환.</p>
<h4 id="softmax-공식">Softmax 공식:</h4>
<p>$$
\hat{p}<em>{i,j} = \frac{\exp(\text{logit}</em>{i,j})}{\sum_k \exp(\text{logit}_{i,k})}
$$</p>
<h4 id="예시-주어진-logits">예시: 주어진 <code>logits</code></h4>
<pre><code class="language-python">logits = torch.tensor([[2.0, 1.0, 0.1], [0.5, 2.5, 0.3]])
labels = torch.tensor([0, 2])  # 샘플 1: 클래스 0, 샘플 2: 클래스 2
weights = torch.tensor([1.0, 2.0, 3.0])  # 클래스별 가중치</code></pre>
<h5 id="softmax-계산">Softmax 계산:</h5>
<ul>
<li><p>샘플 1의 logits: <code>[2.0, 1.0, 0.1]</code>
$$
\hat{p}<em>{1,0} = \frac{\exp(2.0)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} = \frac{e^2}{e^2 + e^1 + e^{0.1}} \approx 0.659
$$
$$
\hat{p}</em>{1,1} = \frac{\exp(1.0)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} \approx 0.242
$$
$$
\hat{p}_{1,2} = \frac{\exp(0.1)}{\exp(2.0) + \exp(1.0) + \exp(0.1)} \approx 0.099
$$</p>
</li>
<li><p>샘플 2의 logits: <code>[0.5, 2.5, 0.3]</code>
$$
\hat{p}<em>{2,0} = \frac{\exp(0.5)}{\exp(0.5) + \exp(2.5) + \exp(0.3)} \approx 0.095
$$
$$
\hat{p}</em>{2,1} = \frac{\exp(2.5)}{\exp(0.5) + \exp(2.5) + \exp(0.3)} \approx 0.843
$$
$$
\hat{p}_{2,2} = \frac{\exp(0.3)}{\exp(0.5) + \exp(2.5) + \exp(0.3)} \approx 0.062
$$</p>
</li>
</ul>
<hr>
<h3 id="3-손실-계산">3. <strong>손실 계산</strong></h3>
<p>모델의 출력 확률(softmax 값)을 정답 레이블과 비교하여 CrossEntropyLoss를 계산합니다.</p>
<h4 id="31-로그-확률-계산">3.1 로그 확률 계산:</h4>
<ul>
<li>샘플 1의 정답은 클래스 0:
$$
-\log(\hat{p}_{1,0}) = -\log(0.659) \approx 0.417
$$</li>
<li>샘플 2의 정답은 클래스 2:
$$
-\log(\hat{p}_{2,2}) = -\log(0.062) \approx 2.785
$$</li>
</ul>
<h4 id="32-클래스별-가중치-적용">3.2 클래스별 가중치 적용:</h4>
<ul>
<li>샘플 1의 정답 클래스 0의 가중치: (1.0)
$$
\text{가중치 적용 손실} = 1.0 \cdot 0.417 = 0.417
$$</li>
<li>샘플 2의 정답 클래스 2의 가중치: (3.0)
$$
\text{가중치 적용 손실} = 3.0 \cdot 2.785 = 8.355
$$</li>
</ul>
<hr>
<h3 id="4-최종-손실-계산">4. <strong>최종 손실 계산</strong></h3>
<p>배치의 평균 손실을 계산합니다:
$$
\text{최종 손실} = \frac{\text{샘플 1 손실} + \text{샘플 2 손실}}{2} = \frac{0.417 + 8.355}{2} \approx 4.386
$$</p>
<hr>
<h3 id="5-요약">5. <strong>요약</strong></h3>
<ol>
<li><code>CrossEntropyLoss</code>의 <code>weight</code>는 클래스별 가중치를 조정하여, 특정 클래스가 손실에 더 큰 영향을 미치도록 설계됨.</li>
<li>Softmax 확률 계산 후 로그 확률을 손실로 변환하며, 이 손실에 클래스별 가중치가 곱해짐.</li>
<li>배치의 평균 손실이 최종 결과로 반환됨. </li>
</ol>
<p><code>weight</code>를 적절히 설정하면 클래스 불균형 문제를 완화하거나, 특정 클래스의 중요도를 조정할 수 있음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]torch.contiguous()]]></title>
            <link>https://velog.io/@ma-kjh/Pytorchtorch.contiguous</link>
            <guid>https://velog.io/@ma-kjh/Pytorchtorch.contiguous</guid>
            <pubDate>Mon, 23 Dec 2024 07:45:00 GMT</pubDate>
            <description><![CDATA[<p><code>contiguous()</code>는 PyTorch에서 <strong>텐서의 메모리 레이아웃을 연속적(contiguous)</strong>으로 변환하는 역할을 함. 이 함수는 텐서가 연속적인 메모리 레이아웃을 가지지 않는 경우 이를 새로운 텐서로 만들어 반환하는 역할. </p>
<h3 id="1-연속적-메모리contiguous-memory란">1. <strong>연속적 메모리(contiguous memory)란?</strong></h3>
<p>PyTorch 텐서는 기본적으로 데이터를 <strong>행우선(row-major)</strong> 순서로 저장합니다. 하지만, <strong>슬라이싱, 전치(transpose)</strong> 등의 연산은 텐서의 메모리 레이아웃을 변경하여, 원래의 연속적 메모리에서 <strong>비연속적(non-contiguous)</strong>인 상태로 만들 수 있다.</p>
<ul>
<li><strong>연속적 텐서</strong>: 메모리 상에서 값들이 순차적으로 저장됨.</li>
<li><strong>비연속적 텐서</strong>: 메모리 상에서 값들이 순차적이지 않고, 내부적으로 인덱싱을 통해 접근.</li>
</ul>
<h4 id="예시">예시:</h4>
<pre><code class="language-python">import torch

# 연속적 텐서
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(x.is_contiguous())  # True

# 전치 연산 후 비연속적 텐서
x_t = x.transpose(0, 1)
print(x_t.is_contiguous())  # False</code></pre>
<hr>
<h3 id="2-왜-contiguous를-사용하는가">2. <strong>왜 <code>contiguous()</code>를 사용하는가?</strong></h3>
<p>PyTorch의 대부분의 연산(특히 C/C++로 구현된 저수준 연산)은 텐서가 <strong>연속적 메모리 레이아웃</strong>을 가질 때만 효율적으로 작동. </p>
<ul>
<li>비연속적인 텐서를 사용할 경우, <strong><code>contiguous()</code></strong>를 호출하여 연속적인 메모리 레이아웃으로 변환해야 한다.</li>
<li>변환하지 않으면 연산 중에 <strong>RuntimeError</strong>가 발생하거나 성능이 저하될 수 있음.</li>
</ul>
<h4 id="예제-비연속적-텐서의-문제와-해결">예제: 비연속적 텐서의 문제와 해결</h4>
<pre><code class="language-python">import torch
import torch.nn.functional as F

# 비연속적 텐서 생성
x = torch.randn(2, 3, 4)
x_t = x.transpose(1, 2)  # 메모리 레이아웃 변경
print(x_t.is_contiguous())  # False

# 연산 시 문제 발생
try:
    F.softmax(x_t, dim=-1)
except RuntimeError as e:
    print(e)

# contiguous로 해결
x_t_contig = x_t.contiguous()
F.softmax(x_t_contig, dim=-1)  # 정상 작동</code></pre>
<hr>
<h3 id="3-get_batch_loss-함수에서의-역할">3. <strong><code>get_batch_loss</code> 함수에서의 역할</strong></h3>
<p><code>contiguous()</code>가 <code>get_batch_loss</code> 함수에서 사용된 이유는, 슬라이싱(<code>labels[..., 1:]</code>, <code>output[..., :-1, :]</code>) 이후 텐서가 <strong>비연속적</strong>일 가능성이 있기 때문임. 이를 보장하지 않으면 아래 연산에서 문제가 발생할 수 있음:</p>
<h4 id="1-shifted_labels">(1) <strong><code>shifted_labels</code></strong></h4>
<pre><code class="language-python">shifted_labels = labels[..., 1:].contiguous()</code></pre>
<ul>
<li>슬라이싱(<code>labels[..., 1:]</code>)으로 인해 텐서가 비연속적으로 변환될 가능성이 있음.</li>
<li><code>contiguous()</code>를 호출하여, 슬라이싱 이후의 텐서를 연속적인 메모리 레이아웃으로 변환.</li>
</ul>
<h4 id="2-output">(2) <strong><code>output</code></strong></h4>
<pre><code class="language-python">output = output[..., :-1, :].contiguous()</code></pre>
<ul>
<li>출력 텐서도 슬라이싱(<code>output[..., :-1, :]</code>)으로 인해 비연속적일 가능성이 있음.</li>
<li><code>contiguous()</code>를 호출하여, 이후의 연산(CrossEntropyLoss)에서 문제가 발생하지 않도록 함.</li>
</ul>
<hr>
<h3 id="4-왜-슬라이싱이-비연속적일-가능성이-있는가">4. <strong>왜 슬라이싱이 비연속적일 가능성이 있는가?</strong></h3>
<p>슬라이싱 연산은 텐서를 복사하지 않고, 원래의 텐서에서 <strong>뷰(view)</strong>를 생성. 이 과정에서 메모리 레이아웃이 변경될 수 있어, 비연속적 상태가 될 가능성이 높습니다.</p>
<h4 id="예시-1">예시:</h4>
<pre><code class="language-python">x = torch.tensor([[1, 2, 3], [4, 5, 6]])
y = x[:, 1:]  # 슬라이싱
print(y.is_contiguous())  # False</code></pre>
<hr>
<h3 id="5-요약">5. <strong>요약</strong></h3>
<ul>
<li><strong><code>contiguous()</code></strong>는 텐서의 메모리 레이아웃을 연속적으로 만들어, PyTorch 연산이 정상적으로 작동하도록 보장한다.</li>
<li>슬라이싱(<code>[..., :-1]</code>, <code>[..., 1:]</code>)이나 전치(<code>transpose</code>) 이후 텐서는 비연속적일 가능성이 있으므로, 이를 해결하기 위해 <code>contiguous()</code>를 사용.</li>
<li><code>get_batch_loss</code> 함수에서는 <strong>CrossEntropyLoss</strong> 연산에서 메모리 레이아웃 문제를 방지하기 위해 사용됨.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]torch.stack]]></title>
            <link>https://velog.io/@ma-kjh/Pytorchtorch.stack</link>
            <guid>https://velog.io/@ma-kjh/Pytorchtorch.stack</guid>
            <pubDate>Mon, 23 Dec 2024 07:34:28 GMT</pubDate>
            <description><![CDATA[<p><strong><code>torch.stack</code></strong>은 <strong>리스트</strong> 또는 <strong>배열 형태의 텐서들</strong>을 하나의 <strong><code>torch.Tensor</code></strong>로 결합해주는 함수. <strong>입력 텐서들을 새로운 차원으로 쌓는 역할</strong>.</p>
<hr>
<h3 id="1-torchstack">1. <strong><code>torch.stack</code></strong></h3>
<ul>
<li><code>torch.stack</code>은 <strong>여러 텐서</strong>를 주어진 <strong>새 축(dim)</strong>을 따라 연결. </li>
<li>즉, 입력 텐서 리스트의 요소들은 <strong>동일한 크기</strong>를 가져야 하며, 이를 새로운 차원으로 쌓아서 하나의 텐서로 만든다.</li>
</ul>
<h4 id="기본-예제">기본 예제:</h4>
<pre><code class="language-python">import torch

# 텐서 리스트
tensor_list = [torch.tensor([1, 2]), torch.tensor([3, 4]), torch.tensor([5, 6])]

# torch.stack으로 쌓기
result = torch.stack(tensor_list)

print(result)
# 출력:
# tensor([[1, 2],
#         [3, 4],
#         [5, 6]])

print(result.shape)
# 출력: torch.Size([3, 2])  # (새로운 축, 기존 차원)</code></pre>
<h4 id="설명">설명:</h4>
<ul>
<li><code>tensor_list</code>는 크기 <code>[2]</code>를 가진 텐서 3개로 구성됨.</li>
<li><code>torch.stack</code>은 리스트의 요소를 새로운 첫 번째 차원(디폴트 <code>dim=0</code>)으로 쌓아 크기 <code>[3, 2]</code>의 텐서를 생성함.</li>
</ul>
<hr>
<h3 id="2-torchstack-vs-torchcat">2. <strong><code>torch.stack</code> vs <code>torch.cat</code></strong></h3>
<p>둘 다 텐서를 연결하지만, 동작 방식이 다르다.</p>
<ul>
<li><strong><code>torch.stack</code></strong>: 새로운 차원을 생성해서 텐서를 쌓음.</li>
<li><strong><code>torch.cat</code></strong>: 기존 차원에서 텐서를 이어붙임.</li>
</ul>
<h4 id="비교-예제">비교 예제:</h4>
<pre><code class="language-python">import torch

tensor_list = [torch.tensor([1, 2]), torch.tensor([3, 4]), torch.tensor([5, 6])]

# torch.stack
stacked = torch.stack(tensor_list)
print(stacked)
# tensor([[1, 2],
#         [3, 4],
#         [5, 6]])

# torch.cat
concatenated = torch.cat(tensor_list)
print(concatenated)
# tensor([1, 2, 3, 4, 5, 6])</code></pre>
<ul>
<li><code>torch.stack</code>: 차원이 추가되어 <code>[3, 2]</code>.</li>
<li><code>torch.cat</code>: 차원이 추가되지 않고, 결과 크기가 <code>[6]</code>.</li>
</ul>
<hr>
<h3 id="3-torchstack의-축-변경">3. <strong><code>torch.stack</code>의 축 변경</strong></h3>
<p>새로운 축(<code>dim</code>)의 위치를 지정할 수 있습니다.</p>
<h4 id="예제">예제:</h4>
<pre><code class="language-python">tensor_list = [torch.tensor([1, 2]), torch.tensor([3, 4]), torch.tensor([5, 6])]

# Default (dim=0)
result1 = torch.stack(tensor_list, dim=0)
print(result1.shape)  # torch.Size([3, 2])

# dim=1
result2 = torch.stack(tensor_list, dim=1)
print(result2)
# tensor([[1, 3, 5],
#         [2, 4, 6]])
print(result2.shape)  # torch.Size([2, 3])</code></pre>
<hr>
<h3 id="4-주의-사항">4. <strong>주의 사항</strong></h3>
<ol>
<li><p><strong>모든 텐서의 크기가 같아야 함</strong>:</p>
<ul>
<li><code>torch.stack</code>은 새로운 차원을 생성하므로, 리스트의 모든 텐서가 같은 크기를 가져야 함.<pre><code class="language-python">tensors = [torch.tensor([1, 2]), torch.tensor([3, 4, 5])]
torch.stack(tensors)  # 오류 발생: RuntimeError</code></pre>
</li>
</ul>
</li>
<li><p><strong>데이터 타입도 동일해야 함</strong>:</p>
<ul>
<li>리스트의 텐서가 다른 데이터 타입을 가지면 오류가 발생.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="5-단순히-list를-torchtensor로-바꾸는-경우">5. <strong>단순히 <code>list</code>를 <code>torch.Tensor</code>로 바꾸는 경우</strong></h3>
<p><code>torch.tensor</code>를 사용하면 간단히 리스트를 텐서로 변환할 수 있습니다.</p>
<h4 id="예제-1">예제:</h4>
<pre><code class="language-python"># 리스트를 텐서로 변환
my_list = [[1, 2], [3, 4]]
tensor = torch.tensor(my_list)

print(tensor)
# tensor([[1, 2],
#         [3, 4]])</code></pre>
<h4 id="차이점">차이점:</h4>
<ul>
<li><strong><code>torch.tensor</code></strong>는 리스트를 텐서로 직접 변환.</li>
<li><strong><code>torch.stack</code></strong>은 텐서 리스트를 새로운 차원으로 쌓아서 하나의 텐서를 만듦.</li>
</ul>
<hr>
<h3 id="요약">요약</h3>
<ul>
<li><strong><code>torch.stack</code></strong>은 텐서 리스트를 새로운 축(dim)으로 쌓아주는 역할.</li>
<li>입력 텐서들은 크기와 데이터 타입이 동일해야 함.</li>
<li>단순히 리스트를 텐서로 변환하려면 <code>torch.tensor</code>를 사용하고, 여러 텐서를 하나로 합칠 때는 <code>torch.stack</code> 또는 <code>torch.cat</code>을 적절히 선택.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Tokenizer]token_embedding]]></title>
            <link>https://velog.io/@ma-kjh/Tokenizertokenembedding</link>
            <guid>https://velog.io/@ma-kjh/Tokenizertokenembedding</guid>
            <pubDate>Mon, 23 Dec 2024 06:07:23 GMT</pubDate>
            <description><![CDATA[<p>NLP 모델을 학습할 때 tokenizer의 output은 tokenized된 text 꾸러미들이다. (text_embedding이 아님)</p>
<p>LLM(대규모 언어 모델)의 가장 앞단에서는 <strong>토크나이저의 출력(Token IDs)</strong>이 입력으로 사용되며, 이를 <strong>임베딩(Embedding)</strong>으로 변환하는 과정을 거치게됨. 이를 단계적으로 살펴보면 다음을 따름:</p>
<hr>
<h3 id="1-tokenizer의-역할">1. <strong>Tokenizer의 역할</strong></h3>
<ul>
<li><p><strong>입력 텍스트 → Token IDs 변환</strong>  </p>
<ul>
<li>토크나이저는 입력 텍스트를 <strong>토큰화</strong>하여 모델의 vocabulary Size에 해당하는 정수 ID로 변환.</li>
<li>예를 들어, &quot;Hello, world!&quot;라는 텍스트가 주어졌을 때, 이를 아래와 같이 변환한다고 가정:<pre><code class="language-python">tokenizer(&quot;Hello, world!&quot;)
# 출력: [15496, 11, 995]</code></pre>
여기서 각 숫자는 해당 토큰의 ID입니다.</li>
</ul>
</li>
<li><p><strong>출력: Vocabulary Size의 정수값 (Token IDs)</strong>  </p>
<ul>
<li>토큰 ID의 범위는 <code>[0, vocab_size-1]</code>.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-embedding-layer의-역할">2. <strong>Embedding Layer의 역할</strong></h3>
<ul>
<li><strong>Token IDs → Dense Embedding Vector 변환</strong>  <ul>
<li>토크나이저의 출력(Token IDs)은 정수 리스트이므로, 이를 학습 가능한 실수 벡터로 변환해야 함.</li>
<li>각 Token ID는 <code>Embedding Layer</code>에서 <strong>Dense Vector</strong>로 매핑됨.</li>
<li>임베딩 벡터의 차원은 모델에서 정의된 <code>embedding_dim</code>(예: 768, 1024 등).</li>
</ul>
</li>
</ul>
<h4 id="임베딩-프로세스">임베딩 프로세스:</h4>
<ul>
<li>토큰 ID가 <code>vocab_size</code>(어휘 크기)의 one-hot vector로 변환된 뒤, <strong>Embedding Matrix</strong>와 곱해져 Dense Embedding을 만듬.</li>
<li>임베딩 행렬 크기: <code>[vocab_size, embedding_dim]</code>  <ul>
<li>예: <code>vocab_size=50,000</code>, <code>embedding_dim=768</code> → <code>[50,000, 768]</code></li>
</ul>
</li>
</ul>
<h4 id="예시">예시:</h4>
<pre><code class="language-python">token_ids = [15496, 11, 995]  # 토크나이저 출력
# 임베딩 벡터로 변환
embedding = Embedding(vocab_size, embedding_dim)
output = embedding(token_ids)
# 출력: Tensor of shape [3, embedding_dim]</code></pre>
<hr>
<h3 id="3-llm-모델의-가장-앞단에서-작동">3. <strong>LLM 모델의 가장 앞단에서 작동</strong></h3>
<ul>
<li><strong>Embedding Layer</strong>는 입력 데이터의 첫 번째 단계로 작동합니다.</li>
<li>변환 과정:<ol>
<li>텍스트 → Token IDs (<code>tokenizer</code>)</li>
<li>Token IDs → Embedding Vectors (<code>Embedding Layer</code>)</li>
<li>Embedding Vectors → 모델의 첫 번째 레이어(Transformer 블록)로 전달</li>
</ol>
</li>
</ul>
<h4 id="transformer-블록의-입력">Transformer 블록의 입력:</h4>
<ul>
<li>일반적으로, 각 토큰의 Dense Embedding + Position Embedding의 합.</li>
<li>입력 텐서 크기: <code>[batch_size, seq_len, embedding_dim]</code></li>
</ul>
<hr>
<p>LLM의 입력 단계:</p>
<ol>
<li><strong>Tokenizer</strong>가 텍스트를 <strong>Token IDs</strong>로 변환 (범위: <code>[0, vocab_size-1]</code>).</li>
<li><strong>Embedding Layer</strong>가 각 Token ID를 <strong>Dense Embedding Vector</strong>로 변환.</li>
<li>변환된 임베딩 벡터와 <strong>Position Embedding</strong>을 더하여(일반적인 경우) 모델의 첫 번째 Transformer 블록에 입력.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch]super(class, self).__init__()]]></title>
            <link>https://velog.io/@ma-kjh/Pytorchsuperclass-self.init</link>
            <guid>https://velog.io/@ma-kjh/Pytorchsuperclass-self.init</guid>
            <pubDate>Mon, 23 Dec 2024 06:01:30 GMT</pubDate>
            <description><![CDATA[<p>코드 보다보면, class를 정의할 때, super(class_name, self)._<em>init_</em>()을 를 사용하는 경우가 있는데 이게 왜 필요할까 .. ?</p>
<ul>
<li>부모 클래스에 이미 구현된 초기화 로직을 재사용할 수 있다. </li>
<li>이를 통해 코드의 중복을 줄이고 유지보수를 용이하게 함. </li>
<li>부모 클래스가 복잡한 초기화 과정을 갖고 있다면 이를 자식 클래스에서 다시 구현할 필요가 없게됨.</li>
</ul>
<pre><code class="language-python">class Parent:
    def __init__(self, value):
        self.value = value
        print(f&quot;Parent initialized with value {value}&quot;)

class Child(Parent):
    def __init__(self, value, extra):
        super().__init__(value)  # Parent의 초기화 로직 재사용
        self.extra = extra
        print(f&quot;Child initialized with extra {extra}&quot;)

c = Child(10, &quot;extra_value&quot;)
# 출력:
# Parent initialized with value 10
# Child initialized with extra extra_value</code></pre>
<pre><code class="language-python">class TextForgetDatasetQA(Dataset):
    def __init__(self, data_path, tokenizer, model_family, max_length=512, split=&#39;forget10&#39;, loss_type=&quot;idk&quot;):
        super(TextForgetDatasetQA, self).__init__()</code></pre>
<ul>
<li>TextForgetDatasetQA 클래스에서 Dataset 클래스를 상속받고 있기 때문에, Dataset 클래스의 초기화 로직을 실행하기 위해 super()를 사용하여 부모 클래스의 _<em>init_</em>()을 호출.</li>
<li>Dataset 클래스 초기화: PyTorch의 Dataset 클래스가 이미 정의한 초기화 로직을 실행하여 필요한 속성이나 메서드가 정상적으로 동작하도록 보장.</li>
<li>확장 가능성: 만약 Dataset 클래스가 업데이트되어 초기화 과정이 변경되더라도, super()를 사용하면 이를 자동으로 상속받을 수 있음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nobel Prize in Physics 2024 Interview]]></title>
            <link>https://velog.io/@ma-kjh/Nobel-Prize-in-Physics-2024-Interview</link>
            <guid>https://velog.io/@ma-kjh/Nobel-Prize-in-Physics-2024-Interview</guid>
            <pubDate>Sun, 13 Oct 2024 05:15:50 GMT</pubDate>
            <description><![CDATA[<p>GPT가 해석해줌.</p>
<p>“그게 장난 전화가 아니라는 걸 어떻게 확신할 수 있었을까요?”</p>
<p>2024년 물리학 노벨상 수상자 제프리 힌튼은 캘리포니아의 한 호텔 방에서 이른 아침 스톡홀름으로부터 전화를 받았고, 여러 스웨덴 억양의 목소리가 그의 노벨 물리학상 수상이 실제임을 확신하게 도와주었습니다. 상 수상 사실을 알게 된 직후에 녹음된 이 인터뷰에서 그는 머신러닝의 현 상태, 안전 연구의 긴급한 필요성, 그리고 그가 제기하는 우려를 사람들이 더 진지하게 받아들이기를 바라는 마음에 대해 이야기합니다.</p>
<p><strong>인터뷰 전문</strong></p>
<p><strong>제프리 힌튼(GH):</strong> 여보세요?</p>
<p><strong>아담 스미스(AS):</strong> 안녕하세요, 제프리 힌튼과 통화 중인가요?</p>
<p><strong>GH:</strong> 그렇습니다.</p>
<p><strong>AS:</strong> 저는 노벨상 웹사이트의 아담 스미스입니다.</p>
<p><strong>GH:</strong> 아, 예. 오래 전에 누군가가 수상자들의 반응을 듣기 위해 전화를 한다는 것을 알게 되었습니다.</p>
<p><strong>AS:</strong> 맞습니다. 몇 분만 이야기 나눌 수 있을까요?</p>
<p><strong>GH:</strong> 네.</p>
<p><strong>AS:</strong> 정말 감사합니다. 우선, 진심으로 축하드립니다.</p>
<p><strong>GH:</strong> 감사합니다.</p>
<p><strong>AS:</strong> 어디에 계셨나요? 소식을 어디서 들으셨나요?</p>
<p><strong>GH:</strong> 저는 인터넷 연결이 되지 않는 캘리포니아의 저렴한 호텔에 있고, 전화 연결도 좋지 않습니다. 오늘 MRI 스캔을 받을 예정이었지만, 취소해야 할 것 같네요. 제가 물리학 노벨상 후보에 올랐다는 사실조차 전혀 몰랐습니다. 매우 놀랐습니다.</p>
<p><strong>AS:</strong> 어떻게 보면 소식을 받기에 꽤 적절한 장소인 것 같네요. 조금은 고립되어서 하루의 폭풍우 전에 생각을 정리할 수 있으니까요.</p>
<p><strong>GH:</strong> 네. 하지만 지금 새벽 2시입니다.</p>
<p><strong>AS:</strong> 아, 그렇군요. 죄송합니다. 아, 이런.</p>
<p><strong>GH:</strong> 지금은 아마 새벽 3시일 거예요.</p>
<p><strong>AS:</strong> 이 상황에서 다시 잠자리에 들 수 있을지, 아니면 긴 하루를 받아들여야 할지 모르겠네요.</p>
<p><strong>GH:</strong> 네, 그렇게 침착하지는 못한 것 같아요.</p>
<p><strong>AS:</strong> 완전히 놀라셨겠네요. 처음에는 어떤 생각이 드셨나요?</p>
<p><strong>GH:</strong> 가장 먼저 든 생각은 이게 장난 전화가 아니라는 것을 어떻게 확신할 수 있을까 하는 것이었어요.</p>
<p><strong>AS:</strong> 그리고 어떻게 확신하셨나요?</p>
<p><strong>GH:</strong> 전화가 스웨덴에서 걸려왔고, 상대방이 강한 스웨덴 억양을 가지고 있었으며, 여러 명이 있었습니다.</p>
<p><strong>AS:</strong> 그렇군요. 그렇다면 여러 명이 함께 장난을 치는 것은 아닐 테니, 그럴 가능성은 낮겠네요.</p>
<p><strong>GH:</strong> 네.</p>
<p><strong>AS:</strong> 자신을 어떻게 설명하시겠어요? 컴퓨터 과학자라고 하시겠어요, 아니면 이 작업을 할 때 생물학을 이해하려는 물리학자였다고 하시겠어요?</p>
<p><strong>GH:</strong> 저는 자신이 어떤 분야에 있는지 정확히 모르는 사람이지만, 뇌가 어떻게 작동하는지 이해하고 싶어하는 사람이라고 말하고 싶습니다. 뇌의 작동 방식을 이해하려는 시도에서, 저는 놀랍도록 잘 작동하는 기술을 만들어내는 데 기여했습니다.</p>
<p><strong>AS:</strong> 당신이 이 기술이 가져올 수 있는 것에 대해 공개적으로 우려를 표명하신 것은 주목할 만합니다. 당신과 다른 사람들이 표현하는 우려를 해소하기 위해 무엇이 필요하다고 생각하시나요?</p>
<p><strong>GH:</strong> 저는 이것이 기후 변화와는 다르다고 생각합니다. 기후 변화의 경우, 모두가 무엇을 해야 하는지 알고 있습니다. 우리는 탄소 배출을 멈춰야 합니다. 그것을 실행할 정치적 의지와 큰 이익을 내는 대기업들이 그것을 원하지 않는 것이 문제입니다. 그러나 무엇을 해야 하는지는 분명합니다. 여기서는 앞으로 무엇이 일어날지, 그리고 그것에 대해 무엇을 해야 할지에 대해 훨씬 더 적은 아이디어를 가지고 있습니다. 만약 여러분이 이렇게 하면 모든 것이 괜찮아질 거라는 간단한 레시피가 있으면 좋겠지만, 저는 가지고 있지 않습니다. 특히 이러한 것들이 통제를 벗어나 지배하게 될 수 있는 존재적 위협과 관련하여, 저는 우리가 역사적인 분기점에 있다고 생각합니다. 앞으로 몇 년 동안 우리가 그 위협을 다룰 방법을 찾아내야 합니다. 지금이 바로 우리가 통제를 유지하는 방법에 대해 많은 사람들이 작업해야 하는 중요한 시기라고 생각합니다. 우리는 여기에 많은 연구 노력을 기울여야 합니다. 정부가 할 수 있는 한 가지는 대기업들이 안전 연구에 더 많은 자원을 투입하도록 강제하는 것입니다. 예를 들어, OpenAI와 같은 회사들이 안전 연구를 뒷전으로 미룰 수 없도록 하는 것입니다.</p>
<p><strong>AS:</strong> 생명공학 혁명과의 유사점이 있나요? 그 당시 생명공학자들이 아실로마 회의에서 모여 잠재적인 위험이 있으니 우리가 스스로 이를 관리해야 한다고 말한 것처럼요.</p>
<p><strong>GH:</strong> 네, 그와 유사한 점이 있다고 생각합니다. 그리고 그들이 한 일은 매우 훌륭했다고 생각합니다. 불행히도, AI의 실용적인 응용 분야가 생물학자들이 통제하려던 클로닝과 같은 것들보다 훨씬 더 많습니다. 그래서 훨씬 더 어려울 것이라고 생각합니다. 하지만 생물학자들이 한 일은 좋은 모델이라고 생각합니다. 그들이 합의를 이끌어냈다는 것은 인상적이며, 과학자들이 그것을 해냈습니다.</p>
<p><strong>AS:</strong> 예를 들어, 대형 언어 모델의 경우, 사람들이 생각하는 것보다 이 모델들이 이해에 훨씬 더 가깝다고 생각하시는 것이 당신의 우려에 기여하는 것 같습니다. 이 분야에서 노벨상의 영향에 대해 어떻게 생각하시나요? 차이를 만들 것이라고 생각하시나요?</p>
<p><strong>GH:</strong> 네, 차이를 만들 것이라고 생각합니다. 희망컨대, 이것이 사람들이 제가 말하는 것들을 더 신뢰하게 만들어, 이 모델들이 정말로 자신이 말하는 것을 이해하고 있다는 것을 믿게 되길 바랍니다.</p>
<p><strong>AS:</strong> 사람들이 당신을 진지하게 받아들이지 않는다고 걱정하시나요?</p>
<p><strong>GH:</strong> 촘스키에서 비롯된 언어학의 한 학파가 있는데, 이 모델들이 이해한다는 것은 완전히 터무니없으며, 우리가 언어를 처리하는 방식과 전혀 다르게 언어를 처리한다고 생각합니다. 저는 그 학파가 틀렸다고 생각합니다. 이제 신경망이 촘스키 언어학 학파가 만들어낸 어떤 것보다 언어를 훨씬 더 잘 처리한다는 것이 분명하다고 생각합니다. 그러나 특히 언어학자들 사이에서는 여전히 많은 논쟁이 있습니다.</p>
<p><strong>AS:</strong> 다시 당신이 이 소식을 받은 상황으로 돌아가고 싶습니다. 한밤중의 호텔 방에서 이 소식을 들으셨네요. 어떤 면에서는 소식을 듣기에 다소 외로운 장소입니다. 함께 껴안고 축하할 사람도 없고요.</p>
<p><strong>GH:</strong> 아뇨, 제 파트너와 함께 있습니다. 그녀는 매우 흥분하고 있습니다.</p>
<p><strong>AS:</strong> 아, 그렇군요. 네, 그렇습니다. 그럼, 다시 한 번 진심으로 축하드립니다.</p>
<p><strong>GH:</strong> 감사합니다.</p>
<p><strong>AS:</strong> 안녕히 계세요.</p>
<p><strong>GH:</strong> 안녕히 계세요.</p>
<hr>
<p>“아직도 약간은 충격 상태입니다”</p>
<p>“아래에서부터 쌓아올려야 합니다.” 발표 직후 이 인터뷰에서, 존 홉필드는 이메일을 확인하던 중 상을 받았다는 소식을 어떻게 알게 되었는지 이야기합니다. &quot;네 번째 이메일에 도달할 때까지 실감이 나지 않았습니다!&quot; 영국의 셀번 마을에 있는 그의 오두막에서, 존 홉필드는 마음이 어떻게 뇌의 배선에서 비롯되는지와 같은 큰 질문을 다루는 방법에 대해 회고합니다. 그는 좋은 문제를 선택하는 방법, 머신러닝의 미래에 대한 그의 두려움, 그리고 학제 간 접근의 필요성에 대해 이야기합니다.</p>
<hr>
<p><strong>인터뷰 전문</strong></p>
<p><strong>존 홉필드(JH):</strong> 여보세요?</p>
<p><strong>아담 스미스(AS):</strong> 아, 안녕하세요. 존 홉필드와 통화 중인가요?</p>
<p><strong>JH:</strong> 네, 존 홉필드입니다.</p>
<p><strong>AS:</strong> 아, 안녕하세요. 저는 노벨상 웹사이트의 아담 스미스입니다. 메리가 친절하게도 이 시간에 통화할 수 있도록 설정해 주셨습니다. 괜찮으신가요?</p>
<p><strong>JH:</strong> 네.</p>
<p><strong>AS:</strong> 지금 스피커폰을 사용하고 계신가요?</p>
<p><strong>JH:</strong> 제 쪽에서는 어떠신가요?</p>
<p><strong>AS:</strong> 아주 완벽합니다. 정말 좋습니다. 정말 감사합니다. 우선, 노벨상 수상을 진심으로 축하드립니다.</p>
<p><strong>JH:</strong> 아, 감사합니다. 감사합니다.</p>
<p><strong>AS:</strong> 메리가 오늘 당신이 햄프셔에 계시다고 말씀해 주셨습니다.</p>
<p><strong>JH:</strong> 맞습니다.</p>
<p><strong>AS:</strong> 노벨상 소식을 듣기에 꽤 좋은 장소인 것 같네요. 약간 숨겨져 있으니까요.</p>
<p><strong>JH:</strong> 우리는 말하자면, 인구 천 명도 안 되는 작은 마을에 따로 떨어져 있습니다.</p>
<p><strong>AS:</strong> 이런 바쁜 날에 고독을 즐길 수 있겠네요.</p>
<p><strong>JH:</strong> 셀번 마을에는 다른 물리학자가 없는 것 같아서, 소식이 천천히 퍼져나가고 있습니다. 하지만 여기에는 거리 행진은 없습니다.</p>
<p><strong>AS:</strong> 노벨상을 수상하셨다는 소식을 실제로 어떻게 알게 되셨나요?</p>
<p><strong>JH:</strong> 아내와 함께 독감 예방 주사를 맞고, 어딘가에서 커피 한 잔을 하고 돌아왔는데, 컴퓨터에 전혀 예상치 못한 엄청난 이메일 목록이 있었습니다. 첫 두세 개의 이메일을 읽으면서, 노벨상이 있다는 것을 깨달았습니다. 정말 놀라웠습니다. 처음에는 노벨상을 발표했다는 것이었는데, 그가 노벨상과 저를 같은 문장에 연결하지 않았습니다. 그래서 누군가에게 수여된 노벨상에 대한 이메일이라고 생각했습니다. 세 번째 이메일쯤에 이르러서야 그게 저에게 온 것이고, 맨 위의 이메일들은 그냥 예고편이었다는 것을 깨달았습니다. 네 번째 이메일에 도달할 때까지 실감이 나지 않았습니다.</p>
<p><strong>AS:</strong> 그런 티저들이 마음에 드네요. 상은 머신러닝과 인공 신경망을 가능하게 한 것에 대해 수여되었지만, 이 도구들을 만들기 위해 이 작업을 시작한 것이 아니라, 뇌의 배선으로부터 마음이 어떻게 발생하는지를 이해하기 위해 시작하셨다고 알고 있습니다.</p>
<p><strong>JH:</strong> 맞습니다. 제 동기는 실제로 뇌가 작동한다는 것을 보고, 생각이나 의식 등을 이해하려면 뇌가 어떻게 작동하는지를 더 이해해야 한다는 것이었습니다. 그리고 그것이 어떤 식으로든 네트워크의 집합적 현상과 관련되어 있다는 것이었습니다. 그래서 저는 뇌의 기능에 대한 관심에서 하드웨어나 소프트웨어, 또는 웻웨어(wetware)가 어떻게 그런 것을 만들어낼 수 있을까 하는 질문으로 천천히 나아갔습니다. 저의 지식과 이해의 중심은 점차 물리학 중심에서 신경생물학적인 것으로 이동했습니다. 그리고 그 과정에서 AI, 네트워크, 신경망과 물리학 사이의 연결이 발전했습니다.</p>
<p><strong>AS:</strong> 수년간 물리학의 렌즈를 사용하여 생물학의 여러 다른 질문들을 다루셨습니다. 어떤 것이 당신을 끌어들이고, 물리학자로서 어떤 것이 좋은 문제를 만드는지 궁금합니다.</p>
<p><strong>JH:</strong> 네. 좋은 물리학 문제에서는, 잘 정의된 시스템이 있고, 개별적인 작은 부분들보다 더 견고한 방식으로 집합적으로 어떻게 작동할 수 있는지 이해할 수 있습니다. 처음부터 문제에 뛰어들어 &quot;마음이 어떻게 작동하는지 이해하고 싶다&quot;고 말하는 것은 아닙니다. 아래에서부터 쌓아올려야 합니다. 날씨를 연구한다면, 상호 작용하는 질소 분자들로 돌아가지 않고도 폭풍이 무엇인지 이해하고 싶다고 말할 것입니다.</p>
<p>적절한 수준의 질문을 가져야 합니다. 그리고 그 수준의 질문이 무엇이어야 하는지는 명확하지 않습니다. 여러 가지 작업을 시도하면서 손을 더럽히게 되고, 그것들이 성과를 내지 못할 수도 있습니다.</p>
<p><strong>AS:</strong> 그렇군요. 물리학자들이 뇌나 의식에 관심을 돌린 긴 역사가 있다고 생각합니다. 프랜시스 크릭이나 돈 글레이저 같은 사람들 말이죠. 질문의 수준을 정확히 맞추는 것이 중요하지 않나요?</p>
<p><strong>JH:</strong> 저는 예를 들어 돈 글레이저가 쓴 것들을 읽었는데, 그것들은 상상력 있는 물리학이지만, 생물학으로서는 그다지 훌륭하지 않습니다. 물리학에서 손을 뻗어 다다르고 싶은 것들에 도달할 수 있어야 한다는 합의가 있었지만, 그럼에도 불구하고 전체가 말이 되도록 충분한 생물학을 알아야 합니다. 그리고 실제로 공동체가 형성되도록 것들을 제시해야 합니다. 그 당시에는 그것을 깨닫지 못했지만, 제가 한 일의 중요한 것 중 하나는 물리학에서 온 사람들이나 생물학에서 온 사람들이 한 가지 작은 문제나 조각이 아니라, 어떻게든 함께 일하면서 이해를 얻기 위해 노력하는 공동체를 형성하도록 한 것이었습니다.</p>
<p><strong>AS:</strong> 그렇습니다. 그것은 공동체를 촉진시켰고, 홉필드 네트워크는 사람들이 붙잡고 발전시킬 수 있는 엄청난 진전이었습니다. 공동 수상자인 제프리 힌튼은 머신러닝과 그 잠재력에 대한 그의 우려를 매우 공개적으로 표현하고 있습니다. 그의 우려에 동의하시나요?</p>
<p><strong>JH:</strong> 네, 그의 우려에 동의합니다. 무언가가 매우 강력해 보이고 왜 그런지 이해하지 못할 때 항상 걱정하게 됩니다. 즉, 그것들을 어떻게 통제해야 하는지, 통제가 문제가 되는지, 또는 그들의 잠재력이 무엇인지 이해하지 못한다는 것입니다. 깊이 있는 수학으로 들어가면 작동할 것이라고 말하지 않고는 그것들이 어떻게 작동하는지 이해하고 설명할 수 없다면, 그것은 만족스러운 답이 아닙니다. 미시적인 물리학이 어떻게 더 큰 시스템의 흥미로운 특성을 발생시키는지에 대한 더 많은 이해를 하고 싶습니다.</p>
<p><strong>AS:</strong> 이번 노벨상이 어떤 메시지를 전하기를 바라시나요? 말하자면 인공지능 분야에서의 첫 번째 상입니다.</p>
<p><strong>JH:</strong> 저는 이 상이 부분적으로 마음과 같은 깊은 문제를 이해하는 것이 뉴턴 역학과 같은 간단한 방식으로 나오지 않을 것이라는 사실을 인정하고 있다고 생각합니다. 그것은 실제로 구조와 특성, 구조 역학과 특성 사이의 관계에 대한 훨씬 더 많은 이해를 필요로 합니다. 그리고 그것은 물리학의 일부, 화학의 일부, 생물학의 일부가 함께 모여 하나의 연구 분야를 이해하고 만들어내는 것입니다.</p>
<p><strong>AS:</strong> 감사합니다. 아주 잘 말씀해 주셨습니다. 마무리하면서, 당신이 이 소식을 셀번에서 듣고 있다는 것을 깨달았습니다. 길버트 화이트의 &quot;셀번의 자연사&quot;의 주제였죠.</p>
<p><strong>JH:</strong> 아, 당신이 길버트 화이트를 발견하셨군요! 잘하셨습니다.</p>
<p><strong>AS:</strong> 하지만 셀번에게 노벨상이 그 중심에서 발표되는 것은 멋진 일입니다. 자연과학과 깊고 오래된 연관성이 있으니까요.</p>
<p><strong>JH:</strong> 길버트 화이트는 예리한 관찰자였습니다.</p>
<p><strong>AS:</strong> 네. 당신과 이야기하게 되어 정말 큰 기쁨이었습니다. 정말 감사드립니다. 다시 한 번 오늘의 소식에 대해 축하드립니다.</p>
<p><strong>JH:</strong> 감사합니다. 아직도 약간은 충격 상태여서 저를 인터뷰하려는 것이 간단하지 않다는 것을 알고 있습니다.</p>
<p><strong>AS:</strong> 충분히 이해합니다. 정말 흥미로웠고, 앞으로 모든 것이 정리되면 더 긴 대화를 나누기를 기대합니다. 감사합니다.</p>
<p><strong>JH:</strong> 네, 안녕히 계세요.</p>
<p><strong>AS:</strong> 안녕히 계세요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[vLLM] GPU utilization]]></title>
            <link>https://velog.io/@ma-kjh/vLLM-GPU-utilization</link>
            <guid>https://velog.io/@ma-kjh/vLLM-GPU-utilization</guid>
            <pubDate>Thu, 10 Oct 2024 07:15:17 GMT</pubDate>
            <description><![CDATA[<p>ref : <a href="https://sjkoding.tistory.com/91">https://sjkoding.tistory.com/91</a> ( 압도적 감사.)</p>
<p>위 링크 들어가면 자세히 설명되어 있습니다.</p>
<p>vllm은 대규모 언어 모델의 효율적인 추론을 위해 설계된 library이다. </p>
<ul>
<li>모델 추론 중에 반복적으로 참조되는 데이터의 캐싱을 위해 키-값 캐시(KV Cache)를 사용. </li>
<li>KV Cache는 트랜스포머 모델의 각 레이어에서 생성된 Key, Value 텐서를 저장하여, 동일한 입력에 대해 반복적인 계산을 피하고 성능을 최적화.</li>
</ul>
<p>KV Cache는 다음과 같은 장점을 제공한다:</p>
<ul>
<li>추론 속도 향상: KV Chache.</li>
<li>메모리 사용 최적화: 캐싱을 통해 필요한 메모리 용량을 줄이고, 효율적인 메모리 관리를 가능하게 한다.</li>
<li>메모리를 많이 소모할 수 있d음: 특히, 전체 GPU 메모리의 90%를 할당하여 모델 추론과 KV Cache를 처리함. 이는 빠른 추론이 가능하지만, GPU 메모리 부족을 초래할 수 있음.</li>
</ul>
<p>해결</p>
<pre><code class="language-python">gpu_memory_utilization=0.8 % 약간 작게 설정
model = LLM(model_id, gpu_memory_utilization=gpu_memory_utilization)

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[conda] Jupyter kernel]]></title>
            <link>https://velog.io/@ma-kjh/conda-Jupyter-kernel</link>
            <guid>https://velog.io/@ma-kjh/conda-Jupyter-kernel</guid>
            <pubDate>Thu, 10 Oct 2024 04:06:23 GMT</pubDate>
            <description><![CDATA[<p><code>python -m ipykernel install --user --name 가상환경이름 --display-name &quot;커널출력이름&quot;</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[llama3/llama/generation.py][class Llama] def sample_top_p]]></title>
            <link>https://velog.io/@ma-kjh/llama3llamageneration.pyclass-Llama-def-sampletopp</link>
            <guid>https://velog.io/@ma-kjh/llama3llamageneration.pyclass-Llama-def-sampletopp</guid>
            <pubDate>Fri, 30 Aug 2024 05:11:38 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">def sample_top_p(probs, p):
    &quot;&quot;&quot;
    Perform top-p (nucleus) sampling on a probability distribution.

    Args:
        probs (torch.Tensor): Probability distribution tensor.
        p (float): Probability threshold for top-p sampling.

    Returns:
        torch.Tensor: Sampled token indices.

    Note:
        Top-p sampling selects the smallest set of tokens whose cumulative probability mass exceeds the threshold p. The distribution is renormalized based on the selected tokens.
    &quot;&quot;&quot;
    probs_sort, probs_idx = torch.sort(probs, dim=-1, descending=True)
    probs_sum = torch.cumsum(probs_sort, dim=-1)
    mask = probs_sum - probs_sort &gt; p # probs sum에서 해당 prob값을 뺏을 때, 나머지. 한마디로 높은애들 중에서 자기자신 뺀 건데, 그 값이 0.95(threshold)보다 크면,(자기자신이 차지하는 비율이 작다는 얘기인듯.) masking한다는거.(True)
    probs_sort[mask] = 0.0
    probs_sort.div_(probs_sort.sum(dim=-1, keepdim=True))
    next_token = torch.multinomial(probs_sort, num_samples=1)
    next_token = torch.gather(probs_idx, -1, next_token)
     return next_token

</code></pre>
<hr>
<p>LLM의 최종 output (next token)은 결국 sampling을 통해서 결정된다.
이 때 LLaMA3.1에서 사용되는 method는 sample_top_p이다.</p>
<p>해당 함수는 <code>probs</code>와 <code>p</code>를 입력으로 받는데 각각은 다음을 의미한다.</p>
<p><code>probs (torch.Tensor)</code> : Linear Layer를 통과한 logits값들 주에서 마지막 위치(바로 다음을 예측)에 해당되는 token의 softmax probability. 이 때 temperature가 반영되어 계산된다(llama generate.py).</p>
<p><code>probs = torch.softmax(logits[:, -1]/ temperature, dim=-1)</code></p>
<p>그리고 <code>p</code> 같은 경우는 threshold를 의미하는데 상위 logit에 해당되는 token들 중에서 하나를 선택하겠다는 의미로 받아들일 수 있다.</p>
<p>-&gt; 여기서 만약에 temperature가 높은(1.0에 가까운) 경우, logit값들은 12만개의 골고루 뿌려진 형태의 distribution을 형성할 것이다. 반면에 temperature가 낮은(0.0에 가까운 경우) 하나의 logit값이 매우 크게 반영이 되겠고, 샘플링을 진행할 때 가장 높은 토큰만을 선택하게 될 것임.</p>
<p>In the context of the <code>sample_top_p</code> function you&#39;ve provided, &quot;cumulative probability mass&quot; refers to the sum of probabilities for a sequence of tokens when sorted in descending order of their individual probabilities.</p>
<h3 id="explanation-of-cumulative-probability-mass">Explanation of Cumulative Probability Mass:</h3>
<ol>
<li><p><strong>Probability Distribution (<code>probs</code>)</strong>:</p>
<ul>
<li>This is a tensor representing the probabilities of different tokens in a vocabulary. Each entry in the tensor corresponds to the likelihood that the token appears as the next token in the generated sequence.</li>
</ul>
</li>
<li><p><strong>Sorting the Probabilities</strong>:</p>
<ul>
<li><code>probs_sort, probs_idx = torch.sort(probs, dim=-1, descending=True)</code></li>
<li>The probabilities are sorted in descending order (<code>probs_sort</code>), and <code>probs_idx</code> holds the corresponding indices of the tokens after sorting.</li>
</ul>
</li>
<li><p><strong>Calculating Cumulative Probability Mass</strong>:</p>
<ul>
<li><code>probs_sum = torch.cumsum(probs_sort, dim=-1)</code></li>
<li>Here, <code>torch.cumsum</code> computes the cumulative sum of the sorted probabilities. This means each entry in <code>probs_sum</code> contains the sum of all previous probabilities up to that point in the sorted list.</li>
</ul>
<p>For example, if <code>probs_sort = [0.4, 0.3, 0.2, 0.1]</code>, then <code>probs_sum</code> would be <code>[0.4, 0.7, 0.9, 1.0]</code>.</p>
</li>
<li><p><strong>Top-p Sampling</strong>:</p>
<ul>
<li>The function aims to select the smallest set of tokens whose cumulative probability mass (sum) exceeds a threshold <code>p</code>.</li>
<li>The mask <code>mask = probs_sum - probs_sort &gt; p</code> identifies tokens where the cumulative probability exceeds <code>p</code> after subtracting the current token&#39;s probability. These tokens will be excluded from sampling.</li>
</ul>
</li>
<li><p><strong>Renormalization and Sampling</strong>:</p>
<ul>
<li>The probabilities of tokens not excluded by the mask are renormalized to sum to 1.</li>
<li><code>next_token = torch.multinomial(probs_sort, num_samples=1)</code> samples from the renormalized distribution.</li>
</ul>
</li>
</ol>
<h3 id="cumulative-probability-mass-in-this-context">Cumulative Probability Mass in This Context:</h3>
<ul>
<li>The cumulative probability mass is essentially the running total of the sorted probabilities as you iterate over the list.</li>
<li>For a given threshold <code>p</code>, top-p sampling involves including tokens until this cumulative mass exceeds <code>p</code>. The intuition is that you only sample from the most probable tokens that together cover at least <code>p</code> percent of the total probability distribution, making the sampling process focus on the most likely tokens while still allowing for some diversity.</li>
</ul>
<p>In summary, cumulative probability mass in this situation refers to the sum of probabilities up to a certain point in the sorted list, and it is used to decide which tokens are eligible for sampling in the top-p (nucleus) sampling method.</p>
<p><code>python
probs_sort = [0.4/0.9, 0.3/0.9, 0.2/0.9, 0.0]
         ≈ [0.444, 0.333, 0.222, 0.0]</code></p>
]]></description>
        </item>
    </channel>
</rss>