<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>SJ_Koding</title>
    <link>https://sjkoding.tistory.com/</link>
    <description> 안녕하세요. </description>
    <language>ko</language>
    <pubDate>Mon, 29 Jun 2026 12:17:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>성지코딩</managingEditor>
    <image>
      <title>SJ_Koding</title>
      <url>https://tistory1.daumcdn.net/tistory/5130613/attach/1f1b3cfef8344306b22dce8ec5c46002</url>
      <link>https://sjkoding.tistory.com</link>
    </image>
    <item>
      <title>[LLM] Surrogate pairs란? ('utf-8' codec can't encode character: surrogates not allowed 해결방법)</title>
      <link>https://sjkoding.tistory.com/103</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Llama-4 모델을 테스트하던 중 자꾸 surrogates not allowed 에러가 발생했다. 이모티콘을 내뱉으려고 하는건지, 가끔씩 한글이 크게 왜곡되면서 이상하게 답변이 오거나 이 에러가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Surrogates라는 개념을 처음 접하는데 이를 이해하기 쉽게 아래 차근차근 풀어서 정리한다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;우선 UTF-16과 UTF-8의 차이를 알아봐야한다. 아주 쉽게.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTF-16은 16비트의 고정 길이를 가진다. 따라서 0x10000이상의 코드포인트를 하나의 16비트 단위로 표현할 수 없어서, 이를 해결하기 위해 Surrogate Pair라는 개념을 사용한다. 간단히 말해 2개의 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;UTF-16의 &lt;b&gt;surrogate 코드유닛&lt;/b&gt; 2개를 이용해 20비트의 코드포인트를 표현한다. *기억&lt;/span&gt;&amp;nbsp;(이는 하단에 자세히 서술한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 UTF-8은 가변 길이 인코딩 방식이다. 즉 한 문자에 8비트, 16비트, 24비트, 32비트를 사용하여 유니코드의 모든 코드포인트를 표현할 수 있다. 이 때문에 별도의 surrogate를 필요로 하지 않으며 실제로 유효한 문자로 간주하지 않는다. 그래서, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Surrogate의 코드유닛 범위를 UTF-8로 인코딩하면 에러가 발생하는 것이다. &lt;s&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;에러 해결 보러오신분은 아래로 쭈우욱&lt;/span&gt;&lt;/s&gt; &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745933624772&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UnicodeEncodeError: 'utf-8' codec can't encode character '\ud83d': surrogates not allowed&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Surrogates Pair&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rbXZ0/btsNF8V6qaj/6DxcfRHZc7klkZeTtXuHz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rbXZ0/btsNF8V6qaj/6DxcfRHZc7klkZeTtXuHz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rbXZ0/btsNF8V6qaj/6DxcfRHZc7klkZeTtXuHz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrbXZ0%2FbtsNF8V6qaj%2F6DxcfRHZc7klkZeTtXuHz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;480&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 코딩적으로 Surrogates는 Surrogates pair가 정확한 명칭이다. surrogate는 대신하다는 의미의 '대리'의 의미를 가지고있는데, Unicode를 대신하여 두 개의 UTF-16 인코딩으로 대신 표현한다 하여 붙여진 이름으로 추정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Surrogate pair는 High Surrogate와 Low Surrogate로 쌍을 이룬다. &lt;/b&gt;각 Surrogate의 코드유닛 범위는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1745933866378&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{'High Surrogate' : &quot;0xD800&quot; ~ &quot;0xDBFF&quot;}
{'Low Surrogate' : &quot;0xDC00&quot; ~ &quot;0xDFFF&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;High&amp;nbsp;Surrogate와&amp;nbsp;Low&amp;nbsp;Surrogate는&amp;nbsp;상위&amp;nbsp;6비트를&amp;nbsp;고정된&amp;nbsp;식별&amp;nbsp;패턴으로&amp;nbsp;사용하여,&amp;nbsp;어떤&amp;nbsp;코드&amp;nbsp;유닛이&amp;nbsp;High인지&amp;nbsp;Low인지&amp;nbsp;구분&amp;nbsp;가능하게&amp;nbsp;만든다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;High Surrogate의 0xD800 ~ 0xDBFF범위는 이진표현으로 `1101 10xx xxxx xxxx`(16bit)&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;즉, &quot;110110&quot;의 상위 6bit가 고정되어있을 때 가질 수 있는 범위이며&lt;/span&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Low Surrogate의 0xDC00 ~ 0xDFFF범위는 이진표현으로 `1101 11yy yyyy yyyy`(16bit)&lt;/span&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;즉, &quot;110111&quot;의 상위&amp;nbsp; 6bit가 고정되어있을 때 가질 수 있는 범위이다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간 글씨들을 이해했다면 글 상단부에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;UTF-16의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;surrogate 코드유닛&lt;/b&gt; 2개를 이용해 20비트의 코드포인트를 표현한다.&lt;/span&gt; 에서 왜 20bit를 표현할 수 있는지 느낌이 온다. 위의 x와 y부분만 사용하여 xxxx xxxx xxyy yyyy yyyy(20bit, xy순서 중요)로 코드포인트를 생성하게된다. high surrogate 하위 10개 bit가 먼저오고 뒤이어 low surrogate 하위 10개 bit가 온다.&lt;br /&gt;&lt;br /&gt;따라서, (high unit, 10it) + (low unit, 10bit) == unicode codepoint (20bit) 가 성립된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 코드로는 아래와 같이 구현된다.&lt;/p&gt;
&lt;pre id=&quot;code_1745934477704&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CodePoint = chr(0x10000 + ((hi - 0xD800) &amp;lt;&amp;lt; 10) + (lo - 0xDC00))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;어려워 보이지만 굉장히 쉬운 수식인데, 아래 비트단위로 보면 이해가 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;chr&amp;nbsp;&lt;/b&gt;&lt;br /&gt;== Unicode to str&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;0x10000&lt;br /&gt;&lt;/b&gt;== 0001 0000 0000 0000 0000&lt;br /&gt;== 20bit codepoint 시작지점&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;((hi - 0xD800)&lt;/b&gt;&lt;br /&gt;== 1101 10xx xxxx xxxx &lt;br /&gt;&amp;nbsp; &amp;nbsp;- 1101 1000 0000 0000 &lt;br /&gt;== 0000 00xx xxxx xxxx &lt;br /&gt;== xx xxxx xxxx (10bit)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;lt;&amp;lt;10)&lt;/b&gt;&lt;br /&gt;xx xxxx xxxx &amp;lt;&amp;lt; 10&lt;br /&gt;== xxxx xxxx xx00 0000 0000 (A)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(lo - 0xDC00))&lt;br /&gt;&lt;/b&gt;== 1101 11yy yyyy yyyy &lt;br /&gt;&amp;nbsp; &amp;nbsp;- 1101 1100 0000 0000&lt;br /&gt;== 0000 00yy yyyy yyyy&lt;br /&gt;== yy yyyy yyyy (B)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;0x10000&lt;/b&gt; + (A) + (B) = &lt;br /&gt;= 0001 0000 0000 0000 0000 &lt;br /&gt;+ xxxx xxxx xx00 0000 0000 &lt;br /&gt;+&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; yy yyyy yyyy&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;== 20bit의 완성된 코드포인트 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 코드포인트가 완성되었으면, 해당 값은 표준 Unicode 문자 영역에 속하는 실제 문자로 인식됩니다.&lt;br /&gt;예를 들어  (U+1F600)&amp;nbsp;이모지는&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;계산됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;High Surrogate: 0xD83D&lt;/li&gt;
&lt;li&gt;Low Surrogate: 0xDE00&lt;br /&gt;이를 수식에 대입하면&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745943710733&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;codepoint = 0x10000 + ((0xD83D - 0xD800) &amp;lt;&amp;lt; 10) + (0xDE00 - 0xDC00)
          = 0x10000 + (0x03D &amp;lt;&amp;lt; 10) + (0x200)
          = 0x10000 + 0xF400 + 0x200
          = 0x1F600&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chr(0x1F600)을&amp;nbsp;호출하면&amp;nbsp;바로&amp;nbsp; 가&amp;nbsp;생성됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; color: #000000;&quot;&gt;바쁘신분은 여기만! 'utf-8' codec can't encode character: surrogates not allowed&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설명과 같이 utf-8에서 surrogate범위의 코드유닛을 인코딩할 수 없다. 한글이 덜 학습된 LLM의 response문제로 surrogate문제가 발생했을 가능성이 있다. 그리고 surrogate가 pair를 이루지 않은 경우(Unpaired surrogate)도 문제가 되는데, 해결방법은 아래와 같다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 정규표현식 사용하여 surrogates pair대응 및 unpair surrogates제거(복잡하지만, O(n)으로 가장 확실한 방법)&lt;/h2&gt;
&lt;pre id=&quot;code_1745942111933&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re

def __normalize(s: str) -&amp;gt; str:
    &quot;&quot;&quot;
    '\\\\uXXXX' --&amp;gt; '\\uXXXX'
    다 될때 까지 반복
    &quot;&quot;&quot;
    while True:
        # '\\\\uXXXX' &amp;rarr; '\\uXXXX'
        n = re.sub(r'\\\\u([0-9a-fA-F]{4})', r'\\u\1', s)

        if n == s:
            return s

        s = n

def __decode_unicode_escapes(t: str) -&amp;gt; str:
    &quot;&quot;&quot;
    utf-8 인코딩을 사용하기 전에 서러게이트 쌍(high/low surrogate)이 존재할 경우 
    이를 합쳐 20비트 코드포인트로 변환
    이때 유효하지 않은 서러게이트는 U+FFFD(�)로 대체
    &quot;&quot;&quot;

    _HI_MIN, _HI_MAX = 0xD800, 0xDBFF  # High surrogate 범위
    _LO_MIN, _LO_MAX = 0xDC00, 0xDFFF  # Low surrogate 범위
    
    # '\\uXXXX' 추출
    _RE_U4 = re.compile(r'\\u([0-9a-fA-F]{4})')

    # 이스케이프 처리
    t = __normalize(t)

    i = 0        # 현재 처리 위치 인덱스
    out = []     # 변환된 문자들을 담을 리스트

    # 문자열 끝까지 순회
    while i &amp;lt; len(t):
        m = _RE_U4.match(t, i)
        # '\\u' 패턴이 아니면 그대로 추가
        if not m:
            out.append(t[i])
            i += 1
            continue

        # '\\uXXXX' &amp;rarr; 16진수 숫자로 변환
        hi = int(m.group(1), 16)
        i += 6  # '\\u' + 4자리 코드포인트 길이만큼 인덱스 이동

        # High surrogate일 경우 뒤에 Low surrogate가 이어지는지 확인
        if _HI_MIN &amp;lt;= hi &amp;lt;= _HI_MAX and _RE_U4.match(t, i):
            lo = int(_RE_U4.match(t, i).group(1), 16)
            # Low surrogate 범위가 유효하면 둘을 합쳐 실제 코드포인트로 변환
            if _LO_MIN &amp;lt;= lo &amp;lt;= _LO_MAX:
                # 0x10000 + (high_offset &amp;lt;&amp;lt; 10) + low_offset (블로그 상단 수식 참고)
                codepoint = 0x10000 + ((hi - _HI_MIN) &amp;lt;&amp;lt; 10) + (lo - _LO_MIN)
                out.append(chr(codepoint))
                i += 6  # Low surrogate 길이만큼 추가 이동
                continue

        # High/Low surrogate 범위를 벗어나면 U+FFFD로 대체하거나 단일 코드포인트로 처리
        if _HI_MIN &amp;lt;= hi &amp;lt;= _LO_MAX:
            # 서러게이트 범위지만 짝이 맞지 않는 경우
            out.append('\uFFFD')
        else:
            out.append(chr(hi))

    # 리스트를 합쳐 최종 문자열 반환
    return ''.join(out)
    
    if __name__ == '__main__': # 테스트 해보세요!!
        examples = {
            &quot;BMP 문자열 (가나다)&quot;: r&quot;\uAC00\uB098\uB2E4&quot;,
            &quot;이모지 ( )&quot;:        r&quot;\uD83D\uDE00&quot;,
            &quot;유효하지 않은 서러게이트&quot;: r&quot;\uD800\u0041&quot;,
        }

        for desc, esc in examples.items():
            decoded = __decode_unicode_escapes(esc)
            print(f&quot;{desc})
            print(f&quot;원본: {esc}
            print(f&quot;변환: {decoded}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;주의&lt;/span&gt;&lt;/b&gt;: streaming response으로 진행할 경우, 처음 surrogate가 나왔을 때 이후 low surrogate가 나올때 까지 대기하고, 확인이 되고 나서 변환하는 별도의 로직이 필요합니다. LLM의 토크나이저는&lt;b&gt;&amp;nbsp;surrogate pair를 대부분 하나의 토큰으로 두지 않습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. .encode함수의 replace 기능 사용&lt;/h2&gt;
&lt;pre id=&quot;code_1745943578749&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;text = text.encode('utf-8', errors='replace').decode('utf-8')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 함수는 surrogate를 pair가 존재하던 말던 무조건 '�'로 대체한다. 임시적으로 에러는 해결 되겠지만, &lt;br /&gt;이모지와 같은 surrogates쌍으로 이루어진 문자는 utf-8에서 나타낼 수 없게된다.&amp;nbsp;&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/103</guid>
      <comments>https://sjkoding.tistory.com/103#entry103comment</comments>
      <pubDate>Wed, 30 Apr 2025 01:24:54 +0900</pubDate>
    </item>
    <item>
      <title>[LLM] Text Embedding모델 파인튜닝을 위한 Hard Negative Mining 방법론 핵심 정리</title>
      <link>https://sjkoding.tistory.com/102</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;마지막 포스팅 이후 어느덧 5개월의 시간이 흘렀는데, 사실 이 사이에 회사 이직과 적응을 하느랴 블로그를 신경쓰지 못했습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;기존에는 LLM 챗봇 구축을 위한 서비스를 개발했다면, 현재는 RAG성능을 극대화 할 수 있는 Backbone모델의 성능을 높이는 업무를 담당하고있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;정확한 업무는 말할 수 없으나, &lt;span style=&quot;text-align: start;&quot;&gt;다행스럽게도 &lt;/span&gt;특정 도메인에서 동료와 함께 기존 foundation모델 보다 좋은 성능을 달성할 수 있었고, 지금은 이보다 더 높은 성능을 달성하기 위해 다양한 기법을 적용하며 실험하고있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;개인 공부 겸 hard negative mining을 간단히 정리합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EuhGZ/btsNafpRw8t/rPhkEo23i0WpFjisekimXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EuhGZ/btsNafpRw8t/rPhkEo23i0WpFjisekimXK/img.png&quot; data-alt=&quot;gpt-4o image generator사용 이미지, 지브리 풍으로 만들까 하다가 너무 흔해져서 철회함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EuhGZ/btsNafpRw8t/rPhkEo23i0WpFjisekimXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEuhGZ%2FbtsNafpRw8t%2FrPhkEo23i0WpFjisekimXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;1024&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;gpt-4o image generator사용 이미지, 지브리 풍으로 만들까 하다가 너무 흔해져서 철회함&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Hard Negative란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Text Embedding모델을 파인튜닝 할 때, MLM(Masked Language Modeling), NLI(Natural Language Inferencing), 그리고 가장 많이 쓰이는 contrastive learning을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;contrastive learning을 진행할 때 가장 중요한 것이 데이터셋인데, query - positive - negative 쌍으로 구성되어있다. 이때 주로 negative의 데이터가 없어서 곤란을 겪는다.  따라서 negative를 기존 데이터로부터 발굴한다라는 뜻으로 negative mining이라는 기법이 제시되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 query-positive쌍이 있을 때, negative가 없다면, 다른 query의 positive를 negative로 사용할 수 있다. 이 때 무작정 랜덤 샘플링으로 negative를 샘플링하게 되면 아래와 같은 문제가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. False-negative문제&lt;/b&gt; &lt;br /&gt;- 다른 query의 positive가 현재 query의 positive로도 성립하는 경우. 즉, negative데이터로 매핑됐지만 실제로는 positive내용인 경우를 의미)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Soft-negative문제&lt;/b&gt;&lt;br /&gt;- 랜덤 샘플링으로 만들어진 negative데이터가 &lt;b&gt;너무 쉬워서&lt;/b&gt; 헷갈리는 문장에 대해 잘 학습하지 못하는 경우.&lt;br /&gt;예를 들어, &quot;대한민국의 수도는 서울이다&quot;-&quot;오늘 날씨는 비가 많이 쏟아졌다&quot; 처럼 negative가 명확한 경우를 &lt;b&gt;soft-negative&lt;/b&gt;(딱히 구분짓지는 않고 그냥 negative라고 표현할 때가 많음)라고 하며 반대로 &quot;대한민국의 수도는 서울이다&quot;-&quot;서울은 대한민국에서 가장 큰 도시 중 하나다&quot; 처럼 유사해 보이지만, &quot;수도&quot;라는 핵심 정보가 다른 것 처럼 실제로는 같은 의미가 아닌 데이터를 &lt;b&gt;hard-negative&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hard negative가 거의 필수시 되는게, 유사하지만 의미가 다른 문장임을 명확히 구분해야할 필요가 있어서 Text Embedding모델에서 Sentence Similiarity 테스크를 다룰 경우, hard negative mining이 대체로 필수적이다. 이는 랜덤 샘플링이 아닌 특정 기준과 필터링을 통해 걸러진 유의미하고 품질이 높은 negative를 만드는 것에 목적이 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Naive한 Hard Negative Mining&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기초적으로 마이닝 하는 방법은 임베딩 벡터간의 유사도 혹은 통계 기반(BM25등)으로 유사한 문장으로 hard negative를 찾는 방법이다. 임베딩 벡터간의 유사도를 기반으로 하는 마이닝 기법은 아래 단계로 이루어진다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 기존 foundation모델 (ko-sroberta, bge-m3 등등 목적에 맞게)이나 외부 API(upstage, openAI)를 사용하여 VectorDB를 구축&lt;br /&gt;2. 데이터셋을 순회하며, query와 유사한 문장 k개 추출&lt;br /&gt;3. 추출된 문장들을 negative로 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 단순하지만 아래와 같은 문제점이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. False-negative문제&lt;/b&gt;&lt;br /&gt;이 문제는 사실 완벽히 해결하는게 어렵다. 어느 곳에서나 발생할 수 있는 문제인데 위 방법론에서 특히나 많이 발생한다. 유사도를 기준으로 negative를 추출하기 때문에, 문장은 유사하나 의미가 다른 문장을 구분짓기 어렵다. foundation 모델이나 외부 API모델이라고 한들, 모든 경우의 false-negative를 완벽히 필터링 할 수 없다. 그냥 문장이 유사하면 유사도가 높을 가능성이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 학습이 너무 어려워요ㅠㅠ&lt;/b&gt;&lt;br /&gt;랜덤 샘플링 기법과 반대로, 모든 negative데이터셋이 'hard'하다 보니, 모델 입장에서 positive와 negative를 명확히 구분짓는데 어려움을 겪어 underfitting현상이 발생할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고도화된 Hard Negative Mining&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 아래 두 가지 논문을 보면 자주 쓰이는 hard negative mining을 이해할 수 있다. 이를 아주 간단히 요약한건데, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;아래 아이디어들을 결합하여 개인만의 마이닝 방식을 설계해보자!&lt;/span&gt; 관련 논문은 [n]으로 표기하였으며, 특히 [1]의 논문(NV-Retriever)에서 기존 mining기법을 모두 인용하여 흐름을 파악하기 매우 좋은 논문.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[1] 2024 NVIDIA 발표, &lt;a href=&quot;https://arxiv.org/pdf/2407.15831&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NV-Retriever: Improving text embedding models with effective hard-negative mining&lt;/a&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;[2] 2024 CMTEB 1위 달성모델, &lt;a href=&quot;https://arxiv.org/pdf/2408.15710&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Conan-embedding: General Text Embedding with More and Better Negative Samples&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* Query-Positive Similarity : pos_score = $S_{pos}$&lt;br /&gt;* Query-Negative Similarity : pos_score = $S_{neg}$&lt;br /&gt;* Posistive-Negative Similarity : pos_score = $S_{pn}$&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Hybrid mining (BM25 + embedding model&lt;/b&gt;)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;BM25로 Top-30개의 청크 추출&lt;/li&gt;
&lt;li&gt;추출된 top-30에서 top-10을 embedding similarity로 추출.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Top-K with absolute threshold [1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;$S_neg$가 유사도가 threshold를 넘으면 후보군에서 제외&lt;/li&gt;
&lt;li&gt;쿼리와 유사도가 높으면 false negative일 경우가 있으므로.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Top-K shifted by N [1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;N이 5이면 top-1 부터 top-5까지 drop.&lt;/li&gt;
&lt;li&gt;false negative 방지&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TopK-MarginPos negatives filter [1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;$S_{neg} &amp;gt; S_{pos}$ 즉, negative가 query와 더 가깝다고 판단되면 후보군에서 제외&amp;nbsp;&lt;/li&gt;
&lt;li&gt;상수 margin 주어 필터정도 조절 가능 ($S_{neg} &amp;gt; S_{pos} + \sigma$)&lt;/li&gt;
&lt;li&gt;overlap청크, positive와 너무 유사한 negative방지(false-negative 위험)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TopK-PercPos negatives filter [1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;4번 방법에서, $S_{pos}$에 margin_rate($\sigma_{rate}$)를 주어 S_{neg} &amp;gt; S_{pos}*$\sigma_{rate}$ 일 경우 후보군에서 제외&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;$\sigma_{rate}$&lt;/b&gt; &amp;gt; 1 일 경우 조금 더 후한 필터링, &lt;b&gt;$\sigma_{rate}$ &lt;/b&gt;&amp;lt; 1일 경우 하드 필터링(더 많이 걸러진다는 뜻)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Jaccard 유사도(토큰 겹침정도(like비교)) 필터링[1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;$S_{pos}$와 $S_{neg}$ 간의 Jaccard Similarity 계산
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Jaccard Similarity: $J(A,B)&amp;nbsp;=&amp;nbsp;\frac{|A&amp;nbsp;\cap&amp;nbsp;B|}{|A&amp;nbsp;\cup&amp;nbsp;B|}$&lt;/li&gt;
&lt;li&gt;' ' 공백 단위로 split하여 단어들의 Set으로 구성하면 구현이 매우 쉬움&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;4-2번과 마찬가지로 overlap청크 방지&lt;/li&gt;
&lt;li&gt;논문에서는 0.3을 기준으로 잡음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LLM사용하여 false negative필터링 [1]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;LLM에 청크를 하나씩 제공하여 query의 negative인지 판단을 맡김.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Dynamic Hard Negative Mining(DHNM) [2]&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기존 HNM은 전처리 단계에서만 수행되어 모델이 학습되는 동안 negative sample의 난이도가 변하는 것을 고려하지 못함&lt;/li&gt;
&lt;li&gt;DHNM은 학습 과정에서 반복적으로 hard Negative를 마이닝하여 모델이 변화하는 학습데이터에 동적으로 적응하도록 함&lt;/li&gt;
&lt;li&gt;각 데이터 포인트에 대해 query에 대한 hard negative의 평균 score를 기록하고, 일정 iteration마다 score가 아래의 조건을 만족하는 경우 더 이상 어렵지 않은 데이터라고 판단하여, 새로운 hard negative mining을 진행
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;초기 score의 1.15배 미만일 경우&lt;/li&gt;
&lt;li&gt;절대값이 0.8 미만일 경우&lt;/li&gt;
&lt;li&gt;위 수치는 하이퍼파라메터임. 조절가능&lt;/li&gt;
&lt;li&gt;conan-embedding은 아래 그림처럼 쉬워진 데이터는 더 이상 학습하지 않고, 새로 어려운 데이터를 새롭게 마이닝 함으로써 다양한 negative데이터와 다양한 hard난이도 데이터를 볼 수 있다.&lt;/li&gt;
&lt;li&gt;이렇게 되면 이미 negative로 학습된 데이터를 다시 학습하지 않는 다는 것이 되어서 효율적인 학습이 가능하다고도 볼 수 있다. 즉, 시험 직전 수학공부를 할 때, 챕터1의 1번문제를 보면 (일명 처음병) 너무 많이 본 문제이기 때문에 굳이 다시 공부할 필요가 없는 것 처럼, 이미 학습된 데이터는 다시 보지 않게된다. 매력적인 방법.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEzARI/btsNcirPvMo/ZYMK6YJcc5hmLK5kuPFuG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEzARI/btsNcirPvMo/ZYMK6YJcc5hmLK5kuPFuG1/img.png&quot; data-alt=&quot;Re-HNM을 진행할 때, 평균적인 negative셋의 스코어를 시각화함. 100step단위로 검증하여 조건을 만족하면 다시 HNM을 진행. 데이터에 따라 Re-HNM조건 튜닝 필수.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEzARI/btsNcirPvMo/ZYMK6YJcc5hmLK5kuPFuG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEzARI%2FbtsNcirPvMo%2FZYMK6YJcc5hmLK5kuPFuG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;706&quot; height=&quot;640&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Re-HNM을 진행할 때, 평균적인 negative셋의 스코어를 시각화함. 100step단위로 검증하여 조건을 만족하면 다시 HNM을 진행. 데이터에 따라 Re-HNM조건 튜닝 필수.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9.&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://arxiv.org/pdf/2402.16829&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GISTEmbedLoss&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;갑자기 Loss가 나왔는데, Hard Negative가 잘 진행되어 있다한들, InfoNCE기반의 Loss(MultipleNegativeRankingLoss등)는 다른 쿼리의 negative후보군들을 모두 negative데이터로 가짐으로써 따라오는 false-negative현상을 해결할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 해당 Loss는 Guide model을 활용하여 필터링 조건을 train time에서 배치단위로 진행하면서, 다른 query의 negative를 효과적으로 필터링 할 수 있는 Loss여서 기입하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVoEeo/btsNbJKLY5i/I8vQkN9aK9pgg7UoSJ1Y30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVoEeo/btsNbJKLY5i/I8vQkN9aK9pgg7UoSJ1Y30/img.png&quot; data-alt=&quot;GISTEmbed: Guided In-sample Selection of Training Negatives for Text Embedding Fine-tuning의 Figure 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVoEeo/btsNbJKLY5i/I8vQkN9aK9pgg7UoSJ1Y30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVoEeo%2FbtsNbJKLY5i%2FI8vQkN9aK9pgg7UoSJ1Y30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1444&quot; height=&quot;1654&quot; data-origin-width=&quot;1444&quot; data-origin-height=&quot;1654&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GISTEmbed: Guided In-sample Selection of Training Negatives for Text Embedding Fine-tuning의 Figure 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인은 위의 mining기법들을 적절히 커스터마이징 하여 성능을 향상시킬 수 있었다. 다양하게 조합하고 비교실험을 진행하여 새로운 마이닝 기법도 도출해보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;잘못된 정보, 보충사항, 조언사항 댓글로 언제든 남겨주세요! 공부하겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/102</guid>
      <comments>https://sjkoding.tistory.com/102#entry102comment</comments>
      <pubDate>Mon, 7 Apr 2025 16:50:10 +0900</pubDate>
    </item>
    <item>
      <title>[LLM] Docker compose를 활용한 sLLM 파인튜닝 및 추론 자동화하기 下편 - Docker compose</title>
      <link>https://sjkoding.tistory.com/100</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여러분의 소스코드가 담겨있는 Docker Image를 성공적으로 빌드했습니다. ipynb가 아닌 이상 학습을 실행하는 코드와 추론을 진행하는 코드가 별도로 존재하고, 특정 명령을 통해 수행될 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1731888431981&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[LLM] Docker compose를 활용한 sLLM 파인튜닝 및 추론 자동화하기 上편 - Docker Image 빌드&quot; data-og-description=&quot;대학생때 부터 AI만 전공해오다보니 백엔드 지식이 턱없이 부족한 것을 깨닫게 해준 프로젝트를 진행해왔습니다.그 중 Docker를 활용하여 LLM파인튜닝 및 추론단계를 자동화 할 수 있도록 만들어&quot; data-og-host=&quot;sjkoding.tistory.com&quot; data-og-source-url=&quot;https://sjkoding.tistory.com/98&quot; data-og-url=&quot;https://sjkoding.tistory.com/98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cIi3vD/hyXzUgnZQH/nWlrQEAaoluTzgcl2jGkh0/img.png?width=279&amp;amp;height=131&amp;amp;face=0_0_279_131,https://scrap.kakaocdn.net/dn/bbnuzA/hyXzKLB1rP/NN50MCREL7WMzkMGVH4DRK/img.png?width=279&amp;amp;height=131&amp;amp;face=0_0_279_131,https://scrap.kakaocdn.net/dn/GNVu4/hyXzPlQWO2/eBh5G0Dk8kz85MhM2V07kk/img.jpg?width=594&amp;amp;height=594&amp;amp;face=0_0_594_594&quot;&gt;&lt;a href=&quot;https://sjkoding.tistory.com/98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sjkoding.tistory.com/98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cIi3vD/hyXzUgnZQH/nWlrQEAaoluTzgcl2jGkh0/img.png?width=279&amp;amp;height=131&amp;amp;face=0_0_279_131,https://scrap.kakaocdn.net/dn/bbnuzA/hyXzKLB1rP/NN50MCREL7WMzkMGVH4DRK/img.png?width=279&amp;amp;height=131&amp;amp;face=0_0_279_131,https://scrap.kakaocdn.net/dn/GNVu4/hyXzPlQWO2/eBh5G0Dk8kz85MhM2V07kk/img.jpg?width=594&amp;amp;height=594&amp;amp;face=0_0_594_594');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[LLM] Docker compose를 활용한 sLLM 파인튜닝 및 추론 자동화하기 上편 - Docker Image 빌드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;대학생때 부터 AI만 전공해오다보니 백엔드 지식이 턱없이 부족한 것을 깨닫게 해준 프로젝트를 진행해왔습니다.그 중 Docker를 활용하여 LLM파인튜닝 및 추론단계를 자동화 할 수 있도록 만들어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sjkoding.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM파인튜닝 특성상 환경을 분할할 필요가 적습니다. train타입과 inference타입의 환경은 거의 동일하며 소스코드만 차이가 나기 때문에 이 때문에 이미지를 2개로 나누는 것이 어쩌면 공간적으로 비효율적일 수 있기 때문에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;하나의 이미지를 활용할 예정입니다.&lt;/span&gt; 물론 inference때 train코드가 필요 없겠지만, 일반적으로 큰 문제가 아닙니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;우선 Docker compose가 무엇인지 간략하게 살펴보겠습니다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker compose는 여러 컨테이너 정의를 docker-compose.yml파일로 정의하며, 이 파일에 담긴 모든 컨테이너의 정의 및 명령을 일괄적으로 빌드할 수 있게 해주는 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 trainable한 데이터셋으로 변환해주는 컨테이너, fine-tuning을 진행하는 컨테이너, inference를 진행하는 컨테이너를 빌드할 예정인데, 이를 간편하게 수행할 수 있게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 값으로는 네트워크, 볼륨, 환경 변수 등이 존재하며, 해당 파일로 어디에서나 동일한 환경을 재현할 수 있어 편리합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 명령은 아래 명령 으로 매우 간편하게 빌드할 수 있습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1731889480114&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker compose up # 최신버전 (2020년 12월 이후, 권장버전)
docker-compose up # 구버전&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 docker run과 다르게 이미 설정값이 docker-compose.yml에 삽입 되어있기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;컨테이너의 구성&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. dataset_generator: 예를 들어 db나 csv파일로 부터 가져온 데이터를 LLM이 파인튜닝할 수 있는 형태로 재 가공하는 컨테이너&lt;br /&gt;2. finetuner: LLM 모델을 fine-tuning하는 컨테이너 (LoRA or Full)&lt;br /&gt;3. inferrer: 학습된 LLM모델을 테스트하고 기능을 수행하는 컨테이너&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 컨테이너를 작성시키기 위해서는 각 컨테이너마다 필요한 소스코드를 Image 빌드시점에서 함께 빌드되어야합니다. 예를 들어, 여러분이 사용하시는 데이터셋을 여러분의 LLM모델 학습 포맷에 맞춰 재 가공하는 소스파일을 작성하셔야합니다. 저는 이전에 빌드했던 /app/train경로안에 fine-tuning소스와 dataset_generator소스파일이 함께 포함되어 있어 /app/train과 /app/inference 경로 두 개를 사용합니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Docker-compose.yml 작성하기&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) Docker volume 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서 저만의 규칙을 세웠고 해당 내용을 다시 복기하자면 &lt;b&gt;기존 모델파일은 /app/models에 저장될 것&lt;/b&gt;이며, &lt;b&gt;파인튜닝된 LoRA어뎁터, 생성된 데이터셋을 저장하는 경로는 /app/outputs&lt;/b&gt;에 저장될 예정이라고 했습니다. 그리고 저는 해당 경로를 local의 디스크를 빌린 volume을 활용하여 저장할 계획입니다. 이를 각각 다음과 같이 정의하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731890326285&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;volumes:
  output-volume:
    name: output-volume
    driver: local
  model-volume:
    name: model-volume
    driver: local&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 볼륨을 정의했으며&lt;b&gt; name: 값을 지정하지 않으면 docker compose를 실행하는 프로젝트 폴더명이 접미사로 붙게됩니다.&lt;/b&gt; 만약 docker_project/ 라는 폴더에서 지정하고 해당 볼륨을 name: 값 없이 생성하게 되면docker_project_output-volume 이라는 볼륨 명을 가질 것 입니다. 이는 추후 협업을 진행할 때 프로젝트 명에 따라 파일을 중복하여 저장할 수 있기 때문에 name을 지정하면 동일한 볼륨에서 협업이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;driver: local의 의미는 해당 docker compose를 실행하는 호스트 환경의 디스크를 사용한다는 의미입니다. Ubuntu환경 기준으로 /var/lib/docker/volume/~~~ 경로에 저장되게 되며 일반 권한으로 해당 경로를 접근할 수 없어 sudo권한을 이용해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) dataset_generator 컨테이너 설정&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731890888666&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'
services:
  dataset_generator:
    image: seongjiko/enssel_llm_env:latest
    container_name: dataset_generator
    command: [ &quot;/bin/bash&quot;, &quot;-c&quot;, &quot;set -e; python3 /app/train/datasets/trainable_dataset_generator.py;&quot; ]
    volumes:
      - output-volume:/app/outputs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너명은 dataset_generator로 지정했습니다. image는 이전에 빌드했던 이미지를 사용합니다. command는 해당 컨테이너가 빌드될 때 실행하는 명령들의 집합체입니다. 즉 trainable_dataset_generator.py를 실행한다는 뜻이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 output-volume의 /app/outputs경로를 마운트하여 해당 경로에 생성된 데이터셋을 저장합니다. 저장될 경로는 소스코드내에서 직접 /app/outputs로 지정해야합니다. 해당 볼륨에 저장하면 추후에 fine-tuning하는 시점에서 저장된 데이터셋을 같은 볼륨에 접근하여 불러올 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) llm_finetuner 컨테이너 설정&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731891215863&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; #  if test for inferrer
  llm_finetuner:
    image: seongjiko/enssel_llm_env:latest
    container_name: llm_finetuner
    command: |
      /bin/bash -c &quot;
      set -e
      echo 'Starting llm_finetuner...'
      git lfs install
      if [ ! -d /app/models/llama-3.2-3B-Instruct ]; then
        echo 'Cloning repository Llama-3.2-3B-Instruct...'
        sudo git clone https://huggingface.co/Enssel/Llama-3.2-3B-@@@ /app/models/llama-3.2-3B-Instruct
      else
        echo 'Repository Llama-3.2-3B-Instruct already cloned.'
      fi
      if [ ! -d /app/outputs/llama3.2-SFT-lora ]; then
        echo 'Running finetuning.py...'
        sudo git clone https://huggingface.co/@@@/llama3.2-3b-@@@ /app/outputs/llama3.2-SFT-lora
      else
        echo '/app/outputs/llama3.2-SFT-lora already exists. Skipping finetuning.'
      fi
      echo 'llm_finetuner completed.'
      &quot;
    networks:
      - sop-network

    volumes:
      - output-volume:/app/outputs
      - model-volumes:/app/models:rw
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [ gpu ]
    depends_on:
      dataset_generator:
        condition: service_completed_successfully&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 llama3.2를 사용합니다.&lt;br /&gt;git lfs install는 LFS(Large File Storage)를 활성화 하여 대형 모델 파일을 다운로드할 준비를 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 만약 모델이 다운로드된 적이 없다면(git clone을 통해 다운로드 받아진 모델은 model-volumes의 /app/models에 저장하게 되며 if문으로 이미 다운로드가 되어있는지 확인할 수 있습니다.) huggingface에서 모델을 clone해옵니다. 사실 Image를 빌드하는 시점에서 모델을 미리 삽입해도 되나, 그렇게 되면 이미지의 용량이 터무니없이 커지게됩니다. (30~50GB 이상)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나서 파인튜닝된 모델이 저장되어있지 않은경우(최초로 튜닝을 시도할 경우) 파인튜닝 소스파일을 실행시켜 파인튜닝을 진행하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 output-volume의 /app/outputs경로를 마운트하며 이전에 저장했던 trainable dataset을 사용할 수 있게됩니다. 그러면 선행조건이 &lt;b&gt;dataset_generator&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;컨테이너가 실행이 되고 난 후에 해당 컨테이너를 실행해야한다는 점인데, 이를 depends_on으로 설정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;dataset_generator에 의존하는 컨테이너이며, 실행 조건은 &lt;b&gt;service_completed_successfully&lt;/b&gt; 즉, 의존하는 컨테이너가 성공적으로 종료되고 나서 실행한다는 의미입니다. 저는 해당 구조를 통해 자동화를 진행하였습니다. 나중에는 KubeFlow등에 비슷한 원리로 적용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파인튜닝된 모델은 dataset과 마찬가지로 output-volume의 /app/outputs에 저장되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 deploy.resources.reservations.devices를 통해 NVIDIA GPU 2개를 할당하여, GPU 리소스를 활용한 고성능 학습이 가능하도록 설정했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4) llm_inferrer 컨테이너 설정&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731891871542&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llm_inferrer:
    image: seongjiko/enssel_llm_env:latest
    container_name: llm_inferrer
    command: |
      /bin/bash -c &quot;
      set -e
      echo 'Starting llm_inferrer...'
      cd /app/inference
      uvicorn main:app --host 0.0.0.0 --port 8811
      &quot;
    networks:
      - sop-network
    volumes:
      - output-volume:/app/outputs
      - model-volumes:/app/models:rw
    ports:
      - &quot;8811:8811&quot;
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [ gpu ]
    depends_on:
      llm_finetuner:
        condition: service_completed_successfully&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 추론 컨테이너입니다. command를 보고 눈치를 채신분도 계시겠지만, 개인적으로는 FastAPI를 통해 추론 시스템을 개발했습니다(uvicorn명령).&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 대충 감이 오실텐데 지금까지 저장된 model과 outputs들을 모두 불러와서 단순히 추론 로직을 실행하는 구문입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 역시 llm_finetuner가 정상적으로 종료되는 것을 대기하고 있습니다. 데이터셋 생성 - 파인튜닝 - 추론이 순차적으로 자동화 되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전체코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731892264930&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'
services:
  dataset_generator:
    image: seongjiko/enssel_llm_env:latest
    container_name: dataset_generator
    command: [ &quot;/bin/bash&quot;, &quot;-c&quot;, &quot;set -e; echo 'Starting dataset generation...'; echo 'Generating dataset...'; python3 /app/train/datasets/trainable_dataset_generator.py; echo 'Dataset generation completed.'&quot; ]
    volumes:
      - output-volume:/app/outputs


  llm_finetuner:
    image: seongjiko/enssel_llm_env:latest
    container_name: llm_finetuner
    command: |
      /bin/bash -c &quot;
      set -e
      echo 'Starting llm_finetuner...'
      git lfs install
      if [ ! -d /app/models/llama-3.2-3B-Instruct ]; then
        echo 'Cloning repository Llama-3.2-3B-Instruct...'
        sudo git clone https://huggingface.co/@@@/Llama-3.2-3B-Instruct_@@@ /app/models/llama-3.2-3B-Instruct
      else
        echo 'Repository Llama-3.2-3B-Instruct already cloned.'
      fi
      if [ ! -d /app/outputs/llama3.2-SFT-lora ]; then
        echo 'Running finetuning.py...'
        sudo git clone https://huggingface.co/@@@/llama3.2@@@ /app/outputs/llama3.2-SFT-lora
      else
        echo '/app/outputs/llama3.2-SFT-lora already exists. Skipping finetuning.'
      fi
      echo 'llm_finetuner completed.'
      &quot;
    networks:
      - sop-network

    volumes:
      - output-volume:/app/outputs
      - model-volumes:/app/models:rw
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [ gpu ]
    depends_on:
      dataset_generator:
        condition: service_completed_successfully

  llm_inferrer:
    image: seongjiko/enssel_llm_env:latest
    container_name: llm_inferrer
    command: |
      /bin/bash -c &quot;
      set -e
      ls /app/outputs
      echo 'Starting llm_inferrer...'
      cd /app/inference
      uvicorn main:app --host 0.0.0.0 --port 8811
      &quot;
    networks:
      - sop-network
    volumes:
      - output-volume:/app/outputs
      - model-volumes:/app/models:rw
    ports:
      - &quot;8811:8811&quot;
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2
              capabilities: [ gpu ]
    depends_on:
      llm_finetuner:
        condition: service_completed_successfully

networks:
  sop-network:
    driver: bridge
    name: sop-network

volumes:
  output-volume:
    name: sop-output-volume
    driver: local
  model-volumes:
    name: sop-model-volumes
    driver: local&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번&amp;nbsp;글에서는&amp;nbsp;Docker&amp;nbsp;Compose를&amp;nbsp;활용해&amp;nbsp;LLM의&amp;nbsp;데이터셋&amp;nbsp;생성,&amp;nbsp;파인튜닝,&amp;nbsp;추론&amp;nbsp;과정을&amp;nbsp;자동화하는&amp;nbsp;방법을&amp;nbsp;다뤘습니다.&amp;nbsp;세&amp;nbsp;단계로&amp;nbsp;나뉜&amp;nbsp;컨테이너&amp;nbsp;구성(dataset_generator,&amp;nbsp;llm_finetuner,&amp;nbsp;llm_inferrer)을&amp;nbsp;통해&amp;nbsp;데이터&amp;nbsp;파이프라인을&amp;nbsp;체계적으로&amp;nbsp;관리하고,&amp;nbsp;GPU&amp;nbsp;리소스를&amp;nbsp;효율적으로&amp;nbsp;활용하며,&amp;nbsp;설정&amp;nbsp;파일을&amp;nbsp;통해&amp;nbsp;환경&amp;nbsp;재현성을&amp;nbsp;확보할&amp;nbsp;수&amp;nbsp;있었습니다. &lt;br /&gt;&lt;br /&gt;이러한 자동화 구조는 개발 및 운영의 효율성을 극대화하며, 향후 KubeFlow와 같은 더 큰 확장성 있는 플랫폼으로도 자연스럽게 연결될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/100</guid>
      <comments>https://sjkoding.tistory.com/100#entry100comment</comments>
      <pubDate>Mon, 18 Nov 2024 10:12:19 +0900</pubDate>
    </item>
    <item>
      <title>백준 12865: 배낭문제 (knapsack)(골드 V) - DP</title>
      <link>https://sjkoding.tistory.com/99</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMSuix/btsKLoWd4nx/zrKneKPT6wsobDOieXlIZk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMSuix/btsKLoWd4nx/zrKneKPT6wsobDOieXlIZk/img.webp&quot; data-alt=&quot;배낭 문제 (0-1)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMSuix/btsKLoWd4nx/zrKneKPT6wsobDOieXlIZk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMSuix%2FbtsKLoWd4nx%2FzrKneKPT6wsobDOieXlIZk%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;340&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배낭 문제 (0-1)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(독백체 글)&lt;br /&gt;오랜만에 알고리즘 연습을 하려고 한다. 배낭 문제는 DP를 입문할때 반드시 거치는 문제인데 제대로 연습해보고자 다시 한 번 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP가 어려운 이유는 점화식을 세우는 것이 대단히 어렵다고 느낀다. 배낭문제를 처음 접하면 이 역시 점화식을 세우기 쉽지 않고 어떻게 접근해야하는지도 막막하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/12865&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말하면 100개 이내의 물건은 각각 무게와 가치를 가지고 있고. 이를 K kg이내로 물건들을 최대로 담을 수 있을 때, 물건을 어떻게 담아야 최고의 가치를 얻을 수 있는지를 묻는다. 문제 이해 자체는 어렵지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 모든 경우의 수를 탐색하는 완전 탐색을 생각해 낼 수 있지만 물건들을 담냐 or 안담냐로 물건마다 2개의 경우의 수가 생긴다.&lt;br /&gt;&lt;br /&gt;예를 들어 물건이 4개가 있으면 2 * 2 * 2 * 2 = 16가지의 경우의 수가 생기며 이는 O(2^n)을 가진다. 컴퓨터가 일반적으로 1초당 1억번의 연산을 진행한다고 하면 최대로 시간내에 완전탐색으로 연산을 할 수 있는 물건 개수는 26개 $ &lt;span&gt;&lt;span&gt;2^26= &lt;span&gt;67,&lt;/span&gt;&lt;span&gt;108,&lt;/span&gt;&lt;span&gt;864 &lt;/span&gt;$&lt;/span&gt;&lt;/span&gt;이다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;하지만 물건의 최대 개수는 100개이기 때문에 경우의수가 100양 (억,조,경,해,자,양....ㅎ) 을 넘어 시간 제한 2초내에 절대 못푼다. (쓸데없는 연산을 진행했지만 그냥 궁금해서,,)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국엔 DP를 사용해야하는 문제인데, 이를 아주 쉽고 차근차근 이해하려고 글을 썼다. 왜 dp를 사용하는지, 어떻게 점화식을 만들어가는지에 대해 정리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 문제 관찰&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가치합의 최대값을 구하라는건 결국 최적화 문제이다. 현재 상황에서 최적의 상황을 고를 수 없기 때문에 그리디 알고리즘은 사용할 수 없다. 그렇다면 DP를 떠올릴 수 있다. DP의 조건을 떠올려보면 작은 문제로 나뉘어질 수 있다. 그리고 메모라이제이션이 가능하다.&lt;br /&gt;&lt;br /&gt;먼저 각 물건을 넣을지 말지 결정해야한다. DP는 이런 선택 문제를 단계적으로 해결하는데 강점이 있다. 또한 K라는 제한 조건이 있기 때문에 가능한 경우의 수를 나눠가며 해결한다.&lt;br /&gt;&lt;br /&gt;문제를 읽으면서 &lt;b&gt;&quot;최댓값&quot;&lt;/b&gt;, &lt;b&gt;&quot;최적화&quot;&lt;/b&gt;와 같은 단어들이 나오면 DP를 고려해볼 수 있다. 이 문제에서는 &lt;b&gt;가치의 합의 최댓값&lt;/b&gt;을 구하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 배낭 문제에는 0-1배낭문제와 무한 배낭 문제가 있는데, 이 문제는 물건을 &lt;b&gt;넣을지 말지&amp;nbsp;&lt;/b&gt;결정하는 것으로 이는 0-1배낭 문제이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) 문제 쪼개기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 작은 문제로 나뉘어질 수 있는지 확인해야한다. 문제를 가장 작게 쪼개면 다음과 같아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 무게 한도(K)에서, 1번째 물건만 고려했을 때의 가치는?&lt;br /&gt;--&amp;gt; 1~2 번째 물건을 고려했을 때의 최대 가치는?&lt;br /&gt;--&amp;gt; ...&lt;br /&gt;--&amp;gt; 1~N 번째 물건까지 고려했을 때, 무게 K를 넘지 않는 최대 가치는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 작은 문제를 해결하면서 점차 큰 문제로 확장해 나가는 방식이 DP의 핵심이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) DP 적용 가능성 확인&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 최적 부분 구조 (Optimal Substructure)&lt;br /&gt;- 큰 문제의 답을 작은 문제의 답으로 구성 가능한가?&lt;br /&gt;: &quot;N번째 물건까지 고려한 최댓값&quot;은 &quot;N-1번째 물건 까지의 최댓값&quot;을 이용해서 구할 수 있다.&lt;br /&gt;&lt;br /&gt;2. 중복되는 부분 문제&lt;br /&gt;- 동일한 부분 문제를 여러 번 계산이 필요한가?&lt;br /&gt;: 그렇다. N번째 물건을 고려할 때 N-1번째 고려된 물건의 경우를 다시 연산해야한다.&lt;br /&gt;--&amp;gt; 메모이제이션이 가능하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 DP를 써도 괜찮다는 결론이 나왔으므로 점화식을 도출해야한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 점화식 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;현재 상태를 이전 상태로부터 어떻게 계산할 것인가?&quot;&amp;nbsp;&lt;/b&gt;이 질문이 핵심이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP테이블 부터 정의하면 dp[i][k], i는 물건의 인덱스, k는 현재 배낭의 남은 무게를 의미하며&lt;br /&gt;&lt;b&gt;[i번째 물건까지 고려했을 때, 배낭의 남은 무게가 k일 때 얻을 수 있는 최대 가치]&lt;/b&gt;의 의미를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉 dp[0][k]는 물건이 하나도 없을 때, 배낭의 남은 무게가 k일 때의 최대 가치는 0이라는 초기 조건을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i번 째 물건을 넣을지 말지 결정해야하고 이에 따라 두 가지의 경우로 나뉘어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;i번째 물건을 넣지 않는 경우&lt;/span&gt;:&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우 dp[i][k] = &lt;span style=&quot;background-color: #f6e199;&quot;&gt;dp[i-1][k]&lt;/span&gt;&lt;br /&gt;즉, i번째 물건을 고려하지 않고 이전 상태를 그대로 유지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;i번째 물건을 넣는 경우&lt;/span&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i번째 물건의 무게가 k를 초과하지 않는다는 조건에서&lt;/li&gt;
&lt;li&gt;i번째의 물건의 무게와 가치를 반영하여 계산한다. 즉,&lt;/li&gt;
&lt;li&gt;dp[i][k] = &lt;span style=&quot;background-color: #99cefa;&quot;&gt;dp[i-1][k-W[i]] + V[i]&lt;/span&gt; (W: 무게, V: 가치)&lt;/li&gt;
&lt;li&gt;구체적으로 살펴보면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1. 이전 상태: dp[i-1][k-W[i]]
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i-1번째 물건까지 고려했을 때, 배낭의 남은 무게가 k-W[i]인 상황에서의 최대 가치이다.&lt;/li&gt;
&lt;li&gt;즉, i번째 물건을 배낭에 넣기 위해, 배낭의 남은 무게 k에서 i번째 물건의 W[i]를 뺀 상태를 고려한다.&lt;/li&gt;
&lt;li&gt;왜냐면 이 상태에서 물건을 다시 넣을 거니까.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2. i번째 물건의 가치 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;+ V[i]&lt;/li&gt;
&lt;li&gt;i번째 물건을 배낭에 넣었으므로, 그 물건의 가치를 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;3. 결과적으로&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;i번째 물건을 넣었을 때, 배낭의 무게 한도가 k일 때 얻을 수 있는 최대 가치는 &lt;b&gt;&quot;이전 상태에서 W[i]만큼의 무게를 소모하고, i번째 물건의 가치를 더한 값&quot;&lt;/b&gt; 이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) 다시. 직관적으로&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;i번째 물건을 넣는다.&lt;/span&gt;&lt;br /&gt;-&amp;nbsp;&lt;/b&gt;i번째 물건을 넣으면 배낭의 남은 무게가 줄어들고(-W[i]) 대신 i번째 물건의 가치가 추가된다. (+ V[i])&lt;br /&gt;- dp[i][k] = &lt;span style=&quot;background-color: #99cefa;&quot;&gt;dp[i-1][k-W[i]] + V[i]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; &lt;b&gt;i번째 물건을 넣지 않는다.&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;- i번째 물건을 넣지 않으면 i-1번째 상태 그대로 유지한다.&lt;br /&gt;- dp[i][k] = &lt;span style=&quot;background-color: #f6e199;&quot;&gt;dp[i-1][k]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그렇다면?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적의 경우는 이 두 가지 경우에 대해 더 큰 값을 가지는 것으로 매핑하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;b&gt;최종 점화식&lt;/b&gt;: d&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;dp[i&amp;minus;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1][k]&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;dp[i&amp;minus;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;1][k&amp;minus;W[i]]+&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;V[i&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;]&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;코드구현&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731681889097&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N, K = map(int, input().split())
items = []  # (무게, 가치)
for _ in range(N):
    W, V = map(int, input().split())
    items.append((W, V))

dp = [[0] * (K + 1) for _ in range(N + 1)]

for i in range(1, N + 1):
    W, V = items[i - 1]
    for k in range(K + 1):
        
        dp[i][k] = dp[i - 1][k]
       
        if k &amp;gt;= W:
            dp[i][k] = max(dp[i][k], dp[i - 1][k - W] + V)

print(dp[N][K])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DP를 1차원으로 사용할 경우&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731682636805&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N, K = map(int, input().split())
items = []
for _ in range(N):
    W, V = map(int, input().split())
    items.append((W, V))

dp = [0] * (K + 1)

for W, V in items:
    for k in range(K, W - 1, -1):  # 역순으로 순회
        dp[k] = max(dp[k], dp[k - W] + V)

print(dp[K])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간복잡도&lt;/b&gt;&lt;br /&gt;2차원 DP:&amp;nbsp; ( &amp;times; )&lt;br /&gt;1차원 DP:&amp;nbsp; ( &amp;times; )&lt;br /&gt;&lt;b&gt;공간복잡도&lt;/b&gt;&lt;br /&gt;2차원 DP:  ( &amp;times; )&lt;br /&gt;1차원 DP:  ( )&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/99</guid>
      <comments>https://sjkoding.tistory.com/99#entry99comment</comments>
      <pubDate>Fri, 15 Nov 2024 21:22:26 +0900</pubDate>
    </item>
    <item>
      <title>[LLM] Docker compose를 활용한 sLLM 파인튜닝 및 추론 자동화하기 上편 - Docker Image 빌드</title>
      <link>https://sjkoding.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;대학생때 부터 AI만 전공해오다보니 백엔드 지식이 턱없이 부족한 것을 깨닫게 해준 프로젝트를 진행해왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 Docker를 활용하여 LLM파인튜닝 및 추론단계를 자동화 할 수 있도록 만들어야했는데 제가 삽질하면서 얻은 내용들을 여기에 정리해보고자 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM특성상 GPU환경을 사용해야만 합니다. 저는 하나의 GPU환경과 모델에 필요한 라이브러리를 하나의 Image로 만들고, trainable data 생성, LLM Finetuning(LoRA), LLM Inference를 진행하는 3개의 컨테이너를 만들어 Docker compose를 활용해 순차적으로 실행되게끔 자동화를 시켜볼 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;준비물: Docker엔진 Docker compose(v2), 학습용 데이터 코드(json), LLM 파인튜닝 코드 및 추론 코드, requirement.txt, CUDA버전확인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각자 환경에 맞춰 진행하시면 됩니다. 바로 적용할 수 있도록 글을 잘 작성해보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Docker먼저 간략하게 소개하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9LKeY/btsKCoInnhM/K0LY8huLkyl8v1HU4OJYSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9LKeY/btsKCoInnhM/K0LY8huLkyl8v1HU4OJYSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9LKeY/btsKCoInnhM/K0LY8huLkyl8v1HU4OJYSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9LKeY%2FbtsKCoInnhM%2FK0LY8huLkyl8v1HU4OJYSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;279&quot; height=&quot;131&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 애플리케이션과 그 실행 환경을 하나의 패키지로 묶어주는 도구라고 설명합니다. 이를 통해 개발자는 동일한 환경에서 애플리케이션을 실행할 수 있어, 환경 차이로 인한 문제를 줄일 수 있습니다. 대표적인 의존성 문제, 성능 재현 문제를 한 번에 해결할 수 있는 강력한 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 쉽게 설명하면 &quot;데스크톱PC 자체를 통째로 줄게, 그냥 마우스 까딱만 해&quot;를 가능하게 하는 도구입니다. 예시는 예시일뿐 실제로는 '이미지 형태로 배포한다'로 이해하시면 편합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker Image&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 이미지가 모든 환경을 가지고있는 아이입니다. 즉, 컴퓨터입니다. 애플리케이션을 실행하기 위한 모든 파일과 설정, 코드, 라이브러리, 설정파일등을 모두 담고있습니다. 이를 기반으로 '컨테이너' 라는 것을 생성하게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker Container&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 컨테이너는 이미지를 기반으로 실제로 실행되는 독립된 환경입니다. AI 경험이 있으신분들은 익숙한 conda 가상환경과 유사한 개념입니다. 각각의 컨테이너는 독립적으로 이루어져있습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;Dockerfile&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;25&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KqeyI/btsKBLqEXKC/Krizf4kEvyk96AymPZLWY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KqeyI/btsKBLqEXKC/Krizf4kEvyk96AymPZLWY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KqeyI/btsKBLqEXKC/Krizf4kEvyk96AymPZLWY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKqeyI%2FbtsKBLqEXKC%2FKrizf4kEvyk96AymPZLWY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;90&quot; height=&quot;25&quot; data-origin-width=&quot;90&quot; data-origin-height=&quot;25&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Docker Image를 생성할 때 쓰이는 설정 및 명령 파일입니다.&lt;/span&gt; Visual Studio에서 Docker 확장프로그램을 설치하면 해당 파일명을 가지는 파일의 아이콘 모양이 바뀝니다. 만약 모양이 바뀌지 않았을 경우, Extention에서 Docker를 검색해 확장프로그램을 설치해주세요. Dockerfile에서는 FROM, ENV, RUN, COPY, CMD 명령이 주로 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FROM: 기반이 되는 이미지 설정으로, 새로운 이미지는 이 이미지에서 시작합니다.&lt;/li&gt;
&lt;li&gt;ENV: 환경 변수를 설정하여 실행 환경을 지정합니다.&lt;/li&gt;
&lt;li&gt;RUN: 이미지를 빌드할 때 실행될 명령을 지정하여, 패키지 설치나 파일 변경 등의 작업을 수행합니다.&lt;/li&gt;
&lt;li&gt;COPY: 로컬 파일이나 디렉터리를 이미지 내부로 복사합니다.&lt;/li&gt;
&lt;li&gt;CMD: 컨테이너가 시작될 때 실행할 기본 명령을 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 보면 Docker 시스템에 있어 가장 핵심이 되는 파일입니다. 이미지단위로 주로 움직이는 도커 시스템에서 이미지를 만들어내는 친구이기 때문입니다. 가장 먼저 LLM 학습과 추론이 가능한 환경을 구축해주는것이 우선입니다. 다음 단계들을 따릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) 베이스 이미지 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 파일에 Dockerfile이라는 이름으로 파일을 만들어주세요. 확장자는 필요없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM파인튜닝을 하기 위해서는 앞서 말씀드렸듯 GPU환경이 반드시 필요합니다. 대부분 cuda환경을 사용하므로 먼저 CUDA셋팅부터 해줄겁니다. 해보신분들은 알겠지만 GPU에 맞는 CUDA버전을 확인하고 또 이 CUDA버전에 맞는 cuDNN을 찾아 설치해줘야합니다. 조금 번거로울 수 있으나 다행히도&amp;nbsp;간단합니다. &lt;br /&gt;&lt;br /&gt;도커 시스템은 전세계적으로 정말 많이 사용되고있습니다. 다행히도 CUDA환경이 마련된 이미지파일 또한 이미 존재합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731049533468&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 구문은 NVIDIA에서 제공하는 CUDA 11.8 버전과 cuDNN 8이 포함된 Ubuntu 22.04 기반의 Docker 이미지를 사용하여 환경을 설정하는 것입니다. 즉 Ubuntu환경에서 GPU를 사용할 수 있게 마련된 환경이 준비되어있는것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(사용하시는 GPU에 맞는 cuda버전을 확인하고, 해당 이미지파일이 있는지 찾으신 후 변경바랍니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) 환경 변수 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 컨테이너 환경을 설정하는 환경 변수를 셋팅해야합니다. 이미지가 빌드되는 시점에서 사용자의 개입 없이 환경 셋팅이 마무리가 되어야합니다. 예를 들어 Y/n을 묻는 질문같은 경우를 생략해줍니다. (모두 Y)&lt;/p&gt;
&lt;pre id=&quot;code_1731050423585&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENV DEBIAN_FRONTEND=noninteractive \&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 추후 DB를 사용하실 분이라면 한국의 time format과 미국의 time format이 상이하고, container도 한국으로 셋팅되어있지 않을 가능성이 큽니다. 따라서 이를 한국을 기준으로 동일화해줍니다. 이참에 모두 한국환경에 맞춥니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731050440137&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    TZ=Asia/Seoul \
    LANG=ko_KR.UTF-8 \
    LANGUAGE=ko_KR:ko \
    LC_ALL=ko_KR.UTF-8 \&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 사용할 파이썬과 pip버전을 셋팅합니다. 파이썬은 3.10.14버전을 사용하고, PIP버전은 24.2를 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731050952520&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    PYTHON_VERSION=3.10.14 \
    PYTHON_PIP_VERSION=24.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 눈에&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731050964271&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENV DEBIAN_FRONTEND=noninteractive \
    TZ=Asia/Seoul \
    LANG=ko_KR.UTF-8 \
    LANGUAGE=ko_KR:ko \
    LC_ALL=ko_KR.UTF-8 \
    PYTHON_VERSION=3.10.14 \
    PYTHON_PIP_VERSION=24.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3) 필수 패키지 설치 및 환경 설정&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731309080830&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \
    build-essential \
    wget \
    zlib1g-dev \
    libncurses5-dev \
    libgdbm-dev \
    libnss3-dev \
    libssl-dev \
    libsqlite3-dev \
    libreadline-dev \
    libffi-dev \
    libbz2-dev \
    liblzma-dev \
    tk-dev \
    uuid-dev \
    git \
    unzip \
    sudo \
    locales &amp;amp;&amp;amp; \
    ln -fs /usr/share/zoneinfo/$TZ /etc/localtime &amp;amp;&amp;amp; \
    dpkg-reconfigure --frontend noninteractive tzdata &amp;amp;&amp;amp; \
    locale-gen ko_KR.UTF-8 &amp;amp;&amp;amp; \
    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build-essential, libncurses5-dev, libgdbm-dev, libnss3-dev, libssl-dev, libsqlite3-dev, libreadline-dev, libffi-dev, libbz2-dev, liblzma-dev, zlib1g-dev, uuid-dev, tk-dev 등은 Python과 다른 소프트웨어의 빌드 및 컴파일에 필요한 라이브러리입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외 기타 유틸리티 라이브러리는 다음과 같습니다:&lt;br /&gt;- wget: 파일 다운로드용 도구&lt;br /&gt;- git: 버전 관리 시스템, 소스 코드 다운로드 및 관리&lt;br /&gt;- unzip: 압축 해제 유틸리티&lt;br /&gt;- sudo: 사용자 권한 관리&lt;br /&gt;- locales: 로케일&amp;nbsp; 설정&lt;br /&gt;이외 등등&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ln -fs /usr/share/zoneinfo/$TZ /etc/localtime: &lt;br /&gt;$TZ로 설정된 시간대 (여기서는 Asia/Seoul)에 맞게 시스템 시간대를 설정&lt;/li&gt;
&lt;li&gt;dpkg-reconfigure --frontend noninteractive tzdata: &lt;br /&gt;시간대를 재설정하여 업데이트된 시간대가 적용되도록 합니다.&lt;/li&gt;
&lt;li&gt;locale-gen ko_KR.UTF-8: &lt;br /&gt;한국어 UTF-8 로케일을 생성하여 한국어 환경을 지원합니다.&lt;/li&gt;
&lt;li&gt;apt-get&amp;nbsp;clean&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;rm&amp;nbsp;-rf&amp;nbsp;/var/lib/apt/lists/*:&amp;nbsp;&lt;br /&gt;설치&amp;nbsp;후&amp;nbsp;불필요한&amp;nbsp;패키지&amp;nbsp;캐시를&amp;nbsp;삭제하여&amp;nbsp;이미지의&amp;nbsp;크기를&amp;nbsp;줄입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4) 3.10.14 설치 및 빌드 아티팩트 정리&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731309490242&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN cd /usr/src &amp;amp;&amp;amp; \
    wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz &amp;amp;&amp;amp; \
    tar xzf Python-${PYTHON_VERSION}.tgz &amp;amp;&amp;amp; \
    cd Python-${PYTHON_VERSION} &amp;amp;&amp;amp; \
    ./configure --enable-optimizations &amp;amp;&amp;amp; \
    make -j&quot;$(nproc)&quot; &amp;amp;&amp;amp; \
    make altinstall &amp;amp;&amp;amp; \
    ln -s /usr/local/bin/python3.10 /usr/bin/python3 &amp;amp;&amp;amp; \
    ln -s /usr/local/bin/pip3.10 /usr/bin/pip3 &amp;amp;&amp;amp; \
    cd / &amp;amp;&amp;amp; rm -rf /usr/src/Python-${PYTHON_VERSION}*&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이&amp;nbsp;구문은&amp;nbsp;Python&amp;nbsp;3.10.14를&amp;nbsp;소스에서&amp;nbsp;컴파일하여&amp;nbsp;설치하는&amp;nbsp;Dockerfile의&amp;nbsp;일부로,&amp;nbsp;Python&amp;nbsp;설치&amp;nbsp;및&amp;nbsp;최적화,&amp;nbsp;그리고&amp;nbsp;설치&amp;nbsp;후의&amp;nbsp;빌드&amp;nbsp;아티팩트&amp;nbsp;정리를&amp;nbsp;수행합니다.&lt;br /&gt;&lt;br /&gt;cd&amp;nbsp;/usr/src:&amp;nbsp;소스&amp;nbsp;파일을&amp;nbsp;다운로드할&amp;nbsp;디렉토리로&amp;nbsp;이동합니다.&lt;/li&gt;
&lt;li&gt;wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz: &lt;br /&gt;Python 소스 코드 압축 파일을 Python 공식 사이트에서 다운로드합니다. PYTHON_VERSION 환경 변수에 따라 지정된 버전을 가져옵니다 (여기서는 3.10.14).&lt;/li&gt;
&lt;li&gt;tar xzf Python-${PYTHON_VERSION}.tgz: &lt;br /&gt;다운로드한 파일을 압축 해제하여 소스 파일을 준비합니다.&lt;/li&gt;
&lt;li&gt;cd Python-${PYTHON_VERSION}: &lt;br /&gt;압축 해제된 Python 소스 디렉토리로 이동합니다.&lt;/li&gt;
&lt;li&gt;./configure --enable-optimizations: &lt;br /&gt;Python 설치를 최적화하여 컴파일하도록 설정합니다. 이 옵션은 Python 실행 속도를 높이기 위해 여러 컴파일 최적화 기법을 사용합니다.&lt;/li&gt;
&lt;li&gt;make -j&quot;$(nproc)&quot;: &lt;br /&gt;소스 코드를 컴파일합니다. -j&quot;$(nproc)&quot; 옵션은 시스템의 CPU 코어 수를 활용하여 병렬로 컴파일하여 설치 속도를 높입니다.&lt;/li&gt;
&lt;li&gt;make altinstall: &lt;br /&gt;Python을 설치합니다. altinstall 옵션은 기존 Python 버전과의 충돌을 방지하며, python3의 기본 버전을 바꾸지 않고 별도로 설치하게 합니다.&lt;/li&gt;
&lt;li&gt;ln -s /usr/local/bin/python3.10 /usr/bin/python3 및 ln -s /usr/local/bin/pip3.10 /usr/bin/pip3: &lt;br /&gt;Python과 pip 실행 파일에 대한 심볼릭 링크를 생성하여 /usr/bin에서 접근할 수 있도록 합니다. 이를 통해 python3와 pip3 명령어를 사용할 수 있게 됩니다.&lt;/li&gt;
&lt;li&gt;cd / &amp;amp;&amp;amp; rm -rf /usr/src/Python-${PYTHON_VERSION}*: &lt;br /&gt;빌드 후 남은 Python 소스 디렉토리와 압축 파일을 삭제하여 Docker 이미지 크기를 줄입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;과정은&amp;nbsp;Python&amp;nbsp;3.10.14을&amp;nbsp;Docker&amp;nbsp;컨테이너에&amp;nbsp;설치하기&amp;nbsp;위한&amp;nbsp;소스&amp;nbsp;컴파일&amp;nbsp;단계로,&amp;nbsp;필요한&amp;nbsp;최적화와&amp;nbsp;링크&amp;nbsp;설정을&amp;nbsp;완료한&amp;nbsp;후,&amp;nbsp;빌드&amp;nbsp;중간&amp;nbsp;파일을&amp;nbsp;제거해&amp;nbsp;최종&amp;nbsp;이미지&amp;nbsp;크기를&amp;nbsp;줄이는&amp;nbsp;데&amp;nbsp;목적이&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5) requirements.txt 및 torch 라이브러리 설치&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요! 기존 requirement파일과 소스파일들을 이미지환경에 구축시키기 위해서는 Dockerfile이 있는 경로 상에 있는것이 일반적입니다. 예를 들어 COPY명령을 실행할 때, requirement.txt와 Dockerfile이 동일 경로에 있다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;COPY requirements.txt /app/&lt;br /&gt;코드로 이미지 상에 업로드가 가능해집니다. 즉, 프로젝트 폴더안에 Dockerfile이 위치해있으면 편합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 셋팅이 되어있다고 가정합니다. requirements.txt를 준비해야하는데 준비하는 방법은 아래 제 이전 포스팅을 참고해주세요.&lt;/p&gt;
&lt;figure id=&quot;og_1731459582714&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;requirements.txt 오류 없이 만들기 (@, file:///를 버전으로 바꾸기)&quot; data-og-description=&quot;요약:문제 코드pip freeze &amp;gt; requirements.txt해결 코드pip list --format=freeze &amp;gt; requirements.txt파이썬을 사용한다면 다른 가상환경, 다른 PC, local --&amp;gt; server, 경진대회 검증소스코드등 환경 자체를 옮겨야하는 경&quot; data-og-host=&quot;sjkoding.tistory.com&quot; data-og-source-url=&quot;https://sjkoding.tistory.com/87&quot; data-og-url=&quot;https://sjkoding.tistory.com/87&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oKqyV/hyXwtqhuZN/kUNjyn2vJySWqsrkry0xkk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/c6AYTV/hyXwvuRWrT/A2tbatDpbldo7lOOfQ3ND1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bev3BZ/hyXwmLtVJD/BZ4ZonnOKCHnhY8YioWP90/img.jpg?width=594&amp;amp;height=594&amp;amp;face=0_0_594_594&quot;&gt;&lt;a href=&quot;https://sjkoding.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sjkoding.tistory.com/87&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oKqyV/hyXwtqhuZN/kUNjyn2vJySWqsrkry0xkk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/c6AYTV/hyXwvuRWrT/A2tbatDpbldo7lOOfQ3ND1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bev3BZ/hyXwmLtVJD/BZ4ZonnOKCHnhY8YioWP90/img.jpg?width=594&amp;amp;height=594&amp;amp;face=0_0_594_594');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;requirements.txt 오류 없이 만들기 (@, file:///를 버전으로 바꾸기)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;요약:문제 코드pip freeze &amp;gt; requirements.txt해결 코드pip list --format=freeze &amp;gt; requirements.txt파이썬을 사용한다면 다른 가상환경, 다른 PC, local --&amp;gt; server, 경진대회 검증소스코드등 환경 자체를 옮겨야하는 경&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sjkoding.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;가장 중요한 점은 requirements.txt에서 torch라이브러리를 제외시키는 것입니다. 이미지에서 새롭게 설치한 CUDA 11.8환경과 기존 11.8환경의 torch 라이브러리 의존성이 다른 에러가 종종 발생합니다. requirements 속 라이브러리를 모두 설치 한 후에 torch는 별도로 설치하는걸로 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;requirement환경을 실행하기 위해 아래의 명령을 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731457976083&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# pip 특정 버전으로 업그레이드
RUN pip3 install --no-cache-dir --upgrade pip==${PYTHON_PIP_VERSION}

# Docker 레이어 캐싱을 활용하기 위해 requirements.txt 복사
COPY requirements.txt /app/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 requirements.txt라이브러리와 torch설치를 순차적으로 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731460546308&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# PyTorch(CUDA 11.8 포함)를 비롯한 Python 의존성 설치
RUN pip3 install --no-cache-dir -r /app/requirements.txt &amp;amp;&amp;amp; \
    pip3 install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cu118&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6) git-lfs 설치 및 정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;huggingface의 오픈소스 LLM을 다운받기 위해서는 git-lfs가 필요하며 선행작업으로 git설치도 필요합니다(위 3번 에서 이미 진행함).&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731461900646&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git-lfs 설치 및 정리
RUN wget https://github.com/git-lfs/git-lfs/releases/download/v3.1.4/git-lfs-linux-amd64-v3.1.4.tar.gz &amp;amp;&amp;amp; \
    tar -xzf git-lfs-linux-amd64-v3.1.4.tar.gz &amp;amp;&amp;amp; \
    ./install.sh &amp;amp;&amp;amp; \
    rm -rf git-lfs-linux-amd64-v3.1.4.tar.gz install.sh README.md CHANGELOG.md LICENSE.md&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7) 필요 디렉토리 생성 및 코드 파일 및 데이터셋 복사&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저만의 규칙을 세웠는데, 여러분의 구조에 맞게 설정하셔도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 /app의 경로는 docker로 부터 생성되거나 사용될 소스코드, 모델파일 등 모든 일괄의 파일을 저장하는 경로이며 정해진 이름은 아니지만 일반적으로 자주 사용되는 경로명입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하단의 경로들은 제 소스파일에 맞춘 경로이므로 여러분의 환경에 맞게 적절하게 수정하시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/app/outputs : trainable한 데이터셋과 파인튜닝된 모델이 저장되는 경로&lt;br /&gt;/app/models: huggingface에서 다운로드 받아질 LLM모델 및 embedding(필요시) 모델 등&lt;br /&gt;위 두 개의 경로는 추후 docker volume시스템에 의해 관리되며, 불필요한 중복 실행을 막을 수도 있습니다.&lt;br /&gt;&lt;br /&gt;/app/train : train관련 코드&lt;br /&gt;/app/inference: inference관련 코드&lt;br /&gt;&lt;br /&gt;그리고 이를 복사하는 과정까지의 코드입니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1731462161316&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 필요한 디렉토리 생성
RUN mkdir -p /app/outputs /app/models /app/outputs/temp_lora /app/temp

# 코드 파일 및 데이터셋 복사
COPY train/ /app/train
COPY inference/ /app/inference

# 기본 명령어로 nvidia-smi 실행하여 GPU 확인
CMD [&quot;nvidia-smi&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;추후 업로드될 下편에서는 docker compose와 실제 구동 원리를 다룰 예정입니다. docker-compose.yml의 명령구조를 보면 손쉽게 각자 코드구조에 맞게 학습과 추론을 진행할 수 있다는 것을 알 수 있을 것입니다.&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;8) 전체 Dockerfile 코드&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1731462329606&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CUDA 11.8과 Ubuntu 22.04를 기반으로 한 베이스 이미지
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04

# 환경 변수 설정
ENV DEBIAN_FRONTEND=noninteractive \
    TZ=Asia/Seoul \
    PYTHON_VERSION=3.10.14 \
    PYTHON_PIP_VERSION=24.2 \
    LANG=ko_KR.UTF-8 \
    LANGUAGE=ko_KR:ko \
    LC_ALL=ko_KR.UTF-8

# 의존성 설치, 시간대 설정, 로케일 생성 및 정리
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \
    build-essential \
    wget \
    zlib1g-dev \
    libncurses5-dev \
    libgdbm-dev \
    libnss3-dev \
    libssl-dev \
    libsqlite3-dev \
    libreadline-dev \
    libffi-dev \
    libbz2-dev \
    liblzma-dev \
    tk-dev \
    uuid-dev \
    tzdata \
    git \
    libaio1 \
    unzip \
    sudo \
    locales &amp;amp;&amp;amp; \
    ln -fs /usr/share/zoneinfo/$TZ /etc/localtime &amp;amp;&amp;amp; \
    dpkg-reconfigure --frontend noninteractive tzdata &amp;amp;&amp;amp; \
    locale-gen ko_KR.UTF-8 &amp;amp;&amp;amp; \
    apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

# Python 3.10.14 소스에서 설치 및 빌드 아티팩트 정리
RUN cd /usr/src &amp;amp;&amp;amp; \
    wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz &amp;amp;&amp;amp; \
    tar xzf Python-${PYTHON_VERSION}.tgz &amp;amp;&amp;amp; \
    cd Python-${PYTHON_VERSION} &amp;amp;&amp;amp; \
    ./configure --enable-optimizations &amp;amp;&amp;amp; \
    make -j&quot;$(nproc)&quot; &amp;amp;&amp;amp; \
    make altinstall &amp;amp;&amp;amp; \
    ln -s /usr/local/bin/python3.10 /usr/bin/python3 &amp;amp;&amp;amp; \
    ln -s /usr/local/bin/pip3.10 /usr/bin/pip3 &amp;amp;&amp;amp; \
    cd / &amp;amp;&amp;amp; rm -rf /usr/src/Python-${PYTHON_VERSION} /usr/src/Python-${PYTHON_VERSION}.tgz

# pip 특정 버전으로 업그레이드
RUN pip3 install --no-cache-dir --upgrade pip==${PYTHON_PIP_VERSION}

# Docker 레이어 캐싱을 활용하기 위해 requirements.txt 복사
COPY requirements.txt /app/

# PyTorch(CUDA 11.8 포함)를 비롯한 Python 의존성 설치
RUN pip3 install --no-cache-dir -r /app/requirements.txt &amp;amp;&amp;amp; \
    pip3 install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cu118


# git-lfs 설치 및 정리
RUN wget https://github.com/git-lfs/git-lfs/releases/download/v3.1.4/git-lfs-linux-amd64-v3.1.4.tar.gz &amp;amp;&amp;amp; \
    tar -xzf git-lfs-linux-amd64-v3.1.4.tar.gz &amp;amp;&amp;amp; \
    ./install.sh &amp;amp;&amp;amp; \
    rm -rf git-lfs-linux-amd64-v3.1.4.tar.gz install.sh README.md CHANGELOG.md LICENSE.md

# 필요한 디렉토리 생성
RUN mkdir -p /app/outputs /app/models /app/trian /app/inference

# 코드 파일 및 데이터셋 복사
COPY train/ /app/train
COPY inference/ /app/inference

# 기본 명령어로 nvidia-smi 실행하여 GPU 확인
CMD [&quot;nvidia-smi&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드에 Oracle셋팅을 포함하면 18GB의 이미지가 완성됩니다. 아직 LLM모델은 다운받지 않았으며 컨테이너 빌드시점에서 volume에 저장되도록 다운로드 할 예정입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker image build&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;본 포스팅은 Docker 엔진이 설치되어있다고 가정합니다. 빌드하는 방법은 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Dockerfile이 있는 경로로 이동한 후&lt;/p&gt;
&lt;pre id=&quot;code_1731477175181&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t &amp;lt;이미지명&amp;gt;:&amp;lt;태그명&amp;gt; .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위&amp;nbsp; 명령을 기입하면 이미지&amp;nbsp; 빌드가 진행됩니다. 설치된 이미지의 내역을 보시려면 아래 명령을 실행해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1731477203089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker images&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;감사합니다.&lt;/h2&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/98</guid>
      <comments>https://sjkoding.tistory.com/98#entry98comment</comments>
      <pubDate>Wed, 13 Nov 2024 10:46:04 +0900</pubDate>
    </item>
    <item>
      <title>[LLM] ANTHROPIC에서 발표한 RAG성능 향상 꿀팁 정리(Contextual Retrieval)</title>
      <link>https://sjkoding.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2024년 9월 20일, Claude 제작사의 Anthropic사에서 RAG성능을 향상시키기 위한 기법을 공개했습니다.&lt;/span&gt; Claude에 사용된 프롬프트들을 공개하는 등, 본인들이 가지고있는 기술들을 공개하는 데에 꺼리지 않는 모습을 보이는 것 같습니다. (OpenAI는 이런 적이 있었나..)&lt;/p&gt;
&lt;figure id=&quot;og_1727142666372&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Introducing Contextual Retrieval&quot; data-og-description=&quot;Anthropic is an AI safety and research company that's working to build reliable, interpretable, and steerable AI systems.&quot; data-og-host=&quot;www.anthropic.com&quot; data-og-source-url=&quot;https://www.anthropic.com/news/contextual-retrieval&quot; data-og-url=&quot;https://www.anthropic.com/news/contextual-retrieval&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UaNhT/hyW6FEljux/7eZZxByRkZbhHmIHNaosOK/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620,https://scrap.kakaocdn.net/dn/GLGZC/hyW6BPvtm0/bkJ2PndJu137Sb7CSM64Xk/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620,https://scrap.kakaocdn.net/dn/baaF8F/hyW6DfrLon/i8rm5ZVN4KAVcuQ0VnpqG1/img.jpg?width=3840&amp;amp;height=2160&amp;amp;face=0_0_3840_2160&quot;&gt;&lt;a href=&quot;https://www.anthropic.com/news/contextual-retrieval&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.anthropic.com/news/contextual-retrieval&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UaNhT/hyW6FEljux/7eZZxByRkZbhHmIHNaosOK/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620,https://scrap.kakaocdn.net/dn/GLGZC/hyW6BPvtm0/bkJ2PndJu137Sb7CSM64Xk/img.png?width=2880&amp;amp;height=1620&amp;amp;face=0_0_2880_1620,https://scrap.kakaocdn.net/dn/baaF8F/hyW6DfrLon/i8rm5ZVN4KAVcuQ0VnpqG1/img.jpg?width=3840&amp;amp;height=2160&amp;amp;face=0_0_3840_2160');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Introducing Contextual Retrieval&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Anthropic is an AI safety and research company that's working to build reliable, interpretable, and steerable AI systems.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.anthropic.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 해당 포스팅은 통번역이 아닙니다. 제 경험과 주관이 내포되어있기 때문에 원문과 함께 구독하시면 효과적입니다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;RAG (Retrieval-Augmented Generation)기술의 필요성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 너무 유명한 기술이라고 생각이 듭니다. 왜 필요한지, 어떤 효과가 있는지 LLM에 조금이라도 관심이 있다면 알고 있을 것이며 적용도 해본 사람이 많을 것입니다. 대부분 기업들의 제한적인 자원 환경에서의 RAG기술은 가볍지만 아주 강한 기술입니다. 예를 들어 뉴스 기사를 찾아준다거나, 유사논문을 찾는다거나 많은 도메인에서 RAG기술이 사용됩니다. 저 또한 여러 프로젝트에서 RAG를 파인튜닝과 함께 필수적으로 사용하고있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Anthropic은 기존 RAG기술에 대해 정보를 encoding하는 과정에서 context를 제거하기 때문에 관련 정보를 검색하지 못하는 경우가 많다는 것을 문제점으로 삼았습니다. 따라서 이를 해결하기 위한 &quot;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Contextual Retrieval&lt;/span&gt;&quot;에 대해 소개합니다. 해당 기술은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Contextual Embedding와 &lt;/span&gt;BM25 하위 두 가지 기술로 나뉘게 되고 이를 모두 적용하면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;검색 실패횟수를 49%&lt;/b&gt;&lt;/span&gt;까지 줄일 수 있고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;rerank기술과 결합하면 최대 67%&lt;/b&gt;&lt;/span&gt;까지 줄일 수 있다고 설명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(물론 200K가 넘지 않은 knowledge bases에서는 Retreival를 사용하지 않고 그냥 프롬프트에 포함하는 것이 가장 간단하고 베스트일 수 있다는 antropic의 이야기와 RAG의 기본적인 개념설명을 넘어...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Embedding models &amp;amp; BM25 (Best matching 25)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Embedding 모델은 자연어를 하나의 벡터로 표시하고 문맥을 파악할 수 있으므로 &lt;b&gt;의미론적 관계를 포착하는데는 탁월&lt;/b&gt;합니다. 기존 룰 베이스에서 사과와 배는 유명한 조합의 과일입니다. 여기서 단순히 룰베이스 기반으로는 '사과'와 '배'는 다른 글자를 가지므로 완전히 다른 의미로 해석하지만 embedding모델에서는 사과와 배를 유사한 의미론적 관계를 갖는다는 것을 알 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 의미가 아닌 토큰(단어) 그 자체가 중요할 때가 있습니다. 대표적으로 사람 이름, 특정 코드와 같은 &lt;b&gt;고유 식별자를 찾아야할 경우&lt;/b&gt;입니다. 이때 BM25가 효과적인데 이는 토큰 매칭을 사용해서 정확한 단어 및 구문 일치를 찾아내어 순위를 매깁니다. 수식은 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$\text{BM25}(D, Q) = \sum_{i=1}^{n} IDF(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot \left(1 - b + b \cdot \frac{|D|}{\text{avgdl}}\right)}$&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;865&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nI0Tu/btsJKDfjevW/7zdsSJoXbx7IElU6GmKVY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nI0Tu/btsJKDfjevW/7zdsSJoXbx7IElU6GmKVY1/img.png&quot; data-alt=&quot;https://www.anthropic.com/news/contextual-retrieval&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nI0Tu/btsJKDfjevW/7zdsSJoXbx7IElU6GmKVY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnI0Tu%2FbtsJKDfjevW%2F7zdsSJoXbx7IElU6GmKVY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1532&quot; height=&quot;865&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;865&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.anthropic.com/news/contextual-retrieval&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BM25는 TF-IDF개념을 기반으로 작동하며 문서 길이와 용어 빈도에 포화함수를 적용하면서 일반적인 단어가 추출해야할 결과를 묻어버리는 것을 방지합니다. 따라서 다음 단계에 따라 embedding과 BM25기술을 결합하여 사용할 수 있다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Document를 수백 개의 토큰을 넘지 않는 작은 텍스트로 청크를 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 해당 청크에 대한 TF-IDF encoding 및 semantic embeddings를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. BM25를 사용하여 정확히 일치하는 chunks를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. embedding을 사용하여 의미적 유사성을 기반으로 chunks를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. rank fusion 기술을 이용하여 결과를 결합하고, 중복을 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. prompt에 상위-K개의 청크를 추가하여 응답을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6단계나 이루어져있지만, 결국엔 BM25로 chunk를 뽑아내고, embedding으로 chunk를 뽑아내어 이를 특정한 rank fusion기술을 활용하여 재정렬 한 후, 이를 프롬프트로 넘기는 방식입니다. 이로써 &lt;b&gt;정확한 용어 매칭과 의미론적 이해의 균형을 맞추며 보다 정확한 RAG시스템이 완성됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;But!!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 작은 청크들은 각각 충분한 문맥을 갖추지 못하면 문제가 발생할 수 있습니다. 만약에 knowledge bases에 국세청 자료를 가지고 있고, 다음과 같은 질문이 주어졌습니다(원문 예시 인용):&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;User: &quot;삼성전자의 2023년 2분기 매출 성장률은 어떻게 돼?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;related chunk: &quot;회사의 매출이 전 분기 대비 3% 성장했다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;해당 chunk를 보면 어느 회사의 매출인지, 그리고 전 분기가 언제인지 context를 파악할 수 없기 때문에 올바른 정보를 검색하거나, 그 정보를 효과적으로 사용하는 것이 어려울 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 이 이야기를 하고자 서론이 길었던 것 같습니다. 이를 해결하기 위한 방법으로 Contextual Retrieval기법을 소개하고있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;Introducing Contextual Retrieval★&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;knowledge bases에 있는 수천 수백만 개의 chunk에 수동으로 문맥을 기입하는것은 현실적으로 어려우므로 Cluade를 활용했다고 합니다. 전체 Document의 context를 사용하여 chunk를 설명하는 간결한 context를 제공하도록 프롬프트를 작성하였고 &lt;b&gt;해당 프롬프트는 다음과 같습니다&lt;/b&gt;:&lt;/p&gt;
&lt;pre id=&quot;code_1727162650471&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;document&amp;gt; 
    {{WHOLE_DOCUMENT}} 
&amp;lt;/document&amp;gt; 

Here is the chunk we want to situate within the whole document 

&amp;lt;chunk&amp;gt; 
    {{CHUNK_CONTENT}} 
&amp;lt;/chunk&amp;gt; 

Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else.

&quot;&quot;&quot;
&amp;lt;document&amp;gt; 
    {{WHOLE_DOCUMENT}} 
&amp;lt;/document&amp;gt;
전체 문서 내에 배치하려는 청크는 다음과 같습니다.
&amp;lt;chunk&amp;gt; 
    {{CHUNK_CONTENT}} 
&amp;lt;/chunk&amp;gt;
청크의 검색 검색을 개선하기 위해 전체 문서 내에서 이 청크의 위치를 파악할 수 있도록 짧고 간결한 문맥을 제공하세요. 간결한 문맥으로만 답변하고 다른 내용은 입력하지 마세요.
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 프롬프트를 활용해서 일반적으로 chunk당 50~100개의 token수를 가진 데이터가 완성되었다고 합니다. 그 후 flow는 하단 이미지와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/97um9/btsJJOhPdRh/KJOw3LxaCvuwlxKaLTfcR0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/97um9/btsJJOhPdRh/KJOw3LxaCvuwlxKaLTfcR0/img.webp&quot; data-alt=&quot;https://www.anthropic.com/news/contextual-retrieval&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/97um9/btsJJOhPdRh/KJOw3LxaCvuwlxKaLTfcR0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F97um9%2FbtsJJOhPdRh%2FKJOw3LxaCvuwlxKaLTfcR0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.anthropic.com/news/contextual-retrieval&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Anthropic은 독립적으로 코드베이스, 소설, ArXiv 논문, 과학 논문 등의 지식 영역, embedding 모델, 검색전략, 평가 등의 다양한 실험을 진행했습니다. 이때 몇 가지 질문/답변 쌍의 예시는 &lt;a title=&quot;해당 링크&quot; href=&quot;https://assets.anthropic.com/m/1632cded0a125333/original/Contextual-Retrieval-Appendix-2.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;해당 링크&lt;/a&gt;로 공유했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 앞서 설명한 기술들을 조합했을 때의 성능 지표를 다음과 같이 나타냈습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGe7g/btsJLhvRaka/WLGFhRHJ0CKmvP9ffDixl0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGe7g/btsJLhvRaka/WLGFhRHJ0CKmvP9ffDixl0/img.webp&quot; data-alt=&quot;https://www.anthropic.com/news/contextual-retrieval&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGe7g/btsJLhvRaka/WLGFhRHJ0CKmvP9ffDixl0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGe7g%2FbtsJLhvRaka%2FWLGFhRHJ0CKmvP9ffDixl0%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.anthropic.com/news/contextual-retrieval&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실히 Contextual Retrieval가 Standard Retrieval보다, embedding과 BM25의 결합이, embedding모델보다 우수한 성능을 보였습니다. 모든 기술을 적용한 스코어가 기존 임베딩만 사용했을 때보다 2배가량 우수해보입니다. (하지만 성능 향상 기술이 하나 더 남아있습니다. Rerank! 이후 나옵니다.)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Implementation considerations&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Antropic은 구현시 고려할 사항에 대해 팁아닌 팁을 공유했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. chunk: 당연한 말이지만 청크 길이, 분류 방법을 반드시 고려해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. embedding model: 결국 근본이 되는 임베딩모델이 좋아야하는 법. &lt;b&gt;Antropic은 Gemini와 Voyage의 embedding API사용을 추천하고 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 문맥 분석 프롬프트 사용자화: 제공하는 일반적인 프롬프트보다 특정 도메인이나 사용 사례에 맞는 프롬프트를 사용하면 더 나은 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 추출할 chunk 수: 추출된 chunk를 만약 상위 1개만 준다면, 많은 정보를 얻지 못해 엉뚱한 RAG를 수행할 수 있고 만약 상위 100개를 준다면 이 중 어느 것을 보고 답변해야할지 헷갈려하며 모델이 멀미할 수도 있습니다. Antropic은 5개, 10개, 20개를 제공해본 결과 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;20개의 chunk를 주는 것이 가장 성능이 좋았다고 합니다.&lt;/b&gt;&lt;/span&gt; 당연히 데이터에 따라 상이하므로 실험을 통해 결정해야 할 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Further boosting performance with Reranking&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rerank기법은 저희 팀에서도 시도해봤던 방법인데, 탐색 시간이 너무 오래걸려서 철회했었던 기술입니다. 다시 한 번 시도해보고 싶네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼, Rerank기법을 적용하면 성능이 향상된다고 합니다. 해당 기술은 예를 들어 Retrieval로 뽑힌 상위 150개의 chunk가 있고, 이를 사용자의 query와 함께 상위 N개의 chunk를 다시 rerank 모델에 전달하여 최종적으로 상위 K(=20)개의 chunk를 선택합니다. 다시 말해 1차적으로 뽑고, 그 중에서 유사한 chunk를 재선별하는 기술입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Antropic은 다양한 Rerank model중 Cohere reranker를 사용하여 테스트를 진행했다고 합니다. Voyage도 있지만 시간이 없었다고 하네요. 실험 결과 다양한 도메인에서 rerank를 수행하면 검색이 더욱 최적화 되는 것으로 나타났습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdNcrA/btsJK95WNf8/JbT6UvamODkyIzEBXL34mK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdNcrA/btsJK95WNf8/JbT6UvamODkyIzEBXL34mK/img.webp&quot; data-alt=&quot;기존: 5.7% 최종: 1.9% --&amp;amp;gt; 67%감소&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdNcrA/btsJK95WNf8/JbT6UvamODkyIzEBXL34mK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdNcrA%2FbtsJK95WNf8%2FJbT6UvamODkyIzEBXL34mK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기존: 5.7% 최종: 1.9% --&amp;gt; 67%감소&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 섹션의 첫 마디에 시간이 오래걸려서 철회했었다고 말씀드렸습니다. 이에 관련한 내용을 Antropic에서도 언급했습니다. rerank기법의 지연시간에 대한 문제를 강조하면서 이는 chunk수에 따라 점진적으로 증가합니다. 병렬적으로 처리해도 어쨋든 지연시간이 추가될 수 밖에 없다는 것을 강조하면서, 트레이드오프를 적절히 설정하는 것이 좋다고 하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Conclusiuon&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약하겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. embedding과 BM25를 결합한 방법이 embedding 단독 사용보다 더 효과적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Voyage와 Gemini가 테스트한 embedding모델 중에서 가장 우수하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 상위 20개의 chunk를 모델에 전달하는 것이 10개 혹은 5개만 전달하는 것 보다 더욱 효과적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. chunk에 문맥을 추가하면 검색 정확도가 크게 향상된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. rerank를 사용하는 것이 더욱 효과적이다. 단, 시간소요는 감안해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 위 내용들은 모두 결합할 수 있어 최종적으로 67%의 검색 성능 향상을 보였다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ4cJR/btsJKG4mEzz/2SirWjOEOwjfngAe0eQagK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ4cJR/btsJKG4mEzz/2SirWjOEOwjfngAe0eQagK/img.webp&quot; data-alt=&quot;최종 flow&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ4cJR/btsJKG4mEzz/2SirWjOEOwjfngAe0eQagK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ4cJR%2FbtsJKG4mEzz%2F2SirWjOEOwjfngAe0eQagK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최종 flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAG에 대해 글을 다루어보고 싶었는데, 리뷰느낌으로 Antropic의 게시글을 정리하였습니다. 주관이 담긴 글이어서 틀린 내용이 있을 수 있습니다. 자세한건 원문을 참고해주시고 언제든 지적해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다 :)&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/97</guid>
      <comments>https://sjkoding.tistory.com/97#entry97comment</comments>
      <pubDate>Tue, 24 Sep 2024 17:27:20 +0900</pubDate>
    </item>
    <item>
      <title>[LLM] Selective Reflection-Tuning 요약 및 정리 (feat. Reflection Llama-3.1 70B 논란)</title>
      <link>https://sjkoding.tistory.com/96</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6g8p9/btsJwqAU3lx/qVHCPP8DAsnWtOrwqWit90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6g8p9/btsJwqAU3lx/qVHCPP8DAsnWtOrwqWit90/img.png&quot; data-alt=&quot;2024.06.07 arXiv 출판 (https://arxiv.org/pdf/2402.10110)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6g8p9/btsJwqAU3lx/qVHCPP8DAsnWtOrwqWit90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6g8p9%2FbtsJwqAU3lx%2FqVHCPP8DAsnWtOrwqWit90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;131&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2024.06.07 arXiv 출판 (https://arxiv.org/pdf/2402.10110)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Selective Reflection Tuning&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Selective Reflection-Tuning: Student-Selected Data Recycling for LLM Instruction-Tuning (2024.06)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM Fine-tuning의 성능 향상을 위해 데이터 품질을 향상하려는 시도, 그리고 데이터 생성에 대한 다양한 방법론이 연구되어왔습니다. 하지만 이는 모두 학생모델(이하 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;, 주로 Llama-3.1 8B, Solar 10.8B 등등의 sLM급 모델)의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;호환성을 고려하지 않았다&lt;/b&gt;&lt;/span&gt;는 것을 핵심으로 이야기합니다. 이는 즉 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;의 제한된 성능때문에 GPT4o등이 만들어낸 고품질 프롬프트로 fine-tuning을 진행하더라도 이를 모방할 수 없다라는 의미로 받아들여집니다. 저는 현재 GPT4o-mini 로 생성해낸 데이터셋으로 fine-tuning을 진행하고 있으나, 해당 성능을 따라가진 못합니다. 어떻게 보면 당연하지만 이 현상을 크게 완화할 수 있는 기법으로 파악되어 추후 적용시켜볼 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 교사모델(이하 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Teacher&lt;/b&gt;&lt;/span&gt;, 주로 GPT-4o, Claude와 같은 고품질 초대형모델)이 데이터 개선을 위한 *&lt;b&gt;Reflection을&lt;/b&gt; 진행하고 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;는&lt;b&gt;&amp;nbsp;자신에게 맞는 데이터를 선택하는 기능&lt;/b&gt;을 통해 데이터를 자동으로 정제하는 기능을 &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;Selective Reflection Tuning&lt;/span&gt;의 이름으로 소개합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*Reflection: &lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델이&amp;nbsp;기존의&amp;nbsp;명령어와&amp;nbsp;응답을&amp;nbsp;검토하고&amp;nbsp;개선하는&amp;nbsp;과정을&amp;nbsp;의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Teacher&lt;/b&gt;&lt;/span&gt;은 주어진 데이터를 보고 명령어나 응답이 얼마나 복잡한지, 명확한지, 또는 더 나은 방식으로 제공될 수 있는지를 분석합니다.&lt;/li&gt;
&lt;li&gt;이 과정을 통해 모델은 데이터를 더 효과적이고 학습 가능한 형태로 &lt;b&gt;개선&lt;/b&gt;합니다. 예를 들어, 모호한 명령어를 더 구체적으로 수정하거나, 불충분한 응답을 더 자세하고 관련성 있게 바꿉니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;의 성능을 고려하고 잘 맞는, 즉 호환이 잘 되는 데이터를 만들 수 있으며 이는 데이터 추가 수집이 필요없으며 이로인해 fine-tuning 자체 성능을 개선할 수 있다는 점이 메리트입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HOW?&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bejBVz/btsJwKMq6F1/unkp6NnjWPVnDl5Kkgk9t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bejBVz/btsJwKMq6F1/unkp6NnjWPVnDl5Kkgk9t0/img.png&quot; data-alt=&quot;Figure 1: The overall pipeline of our method. The first Selective Instruction Reflection phase aims to obtain a better instruction for a data sample and the second Selective Response Reflection phase aims to obtain a better response for the sample. The reflection process is conducted by the well-trained teacher model and the selection process is conducted by the student model.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bejBVz/btsJwKMq6F1/unkp6NnjWPVnDl5Kkgk9t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbejBVz%2FbtsJwKMq6F1%2Funkp6NnjWPVnDl5Kkgk9t0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1051&quot; height=&quot;432&quot; data-origin-width=&quot;1051&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 1: The overall pipeline of our method. The first Selective Instruction Reflection phase aims to obtain a better instruction for a data sample and the second Selective Response Reflection phase aims to obtain a better response for the sample. The reflection process is conducted by the well-trained teacher model and the selection process is conducted by the student model.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면 크게 3단계로 구성되어있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Selective Instruction Reflection&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input 으로 가장 초기의 프롬프트 쌍($x_0, y_0$)이 주어집니다. 이를 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Teacher&lt;/b&gt;&lt;/span&gt;에 넣고 새로운 프롬프트를 생성합니다. 이때 새로운 프롬프트를 생성하기 위한 프롬프트는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vmy7X/btsJxjHp43H/tFKDY9hSnssZqdkfaeV3bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vmy7X/btsJxjHp43H/tFKDY9hSnssZqdkfaeV3bK/img.png&quot; data-alt=&quot;Figure 5: The prompt we used to modify the existing instruction&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vmy7X/btsJxjHp43H/tFKDY9hSnssZqdkfaeV3bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvmy7X%2FbtsJxjHp43H%2FtFKDY9hSnssZqdkfaeV3bK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;909&quot; height=&quot;692&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 5: The prompt we used to modify the existing instruction&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 프롬프트를 한글로 정리하면 아래 더보기와 같습니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는&amp;nbsp;주어진&amp;nbsp;명령어의&amp;nbsp;품질과&amp;nbsp;관련된&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;질문에&amp;nbsp;답해주길&amp;nbsp;원합니다.&lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;이&amp;nbsp;명령어가&amp;nbsp;왜&amp;nbsp;좋지&amp;nbsp;않은지&amp;nbsp;분석하세요.&amp;nbsp;먼저,&amp;nbsp;다음&amp;nbsp;기준에&amp;nbsp;따라&amp;nbsp;명령어를&amp;nbsp;분석하세요:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;주제의&amp;nbsp;복잡성&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;요구되는&amp;nbsp;세부&amp;nbsp;사항의&amp;nbsp;수준&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;필요한&amp;nbsp;지식&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;명령어의&amp;nbsp;모호성&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;논리적&amp;nbsp;추론&amp;nbsp;또는&amp;nbsp;문제&amp;nbsp;해결이&amp;nbsp;포함되는지&amp;nbsp;여부&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;그런&amp;nbsp;다음,&amp;nbsp;주어진&amp;nbsp;명령어에&amp;nbsp;대한&amp;nbsp;응답이&amp;nbsp;왜&amp;nbsp;좋지&amp;nbsp;않은지&amp;nbsp;다음&amp;nbsp;기준을&amp;nbsp;바탕으로&amp;nbsp;분석하세요:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;도움이&amp;nbsp;되는지&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;관련성&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;정확성&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;-&amp;nbsp;세부&amp;nbsp;사항의&amp;nbsp;수준&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;마지막으로,&amp;nbsp;이&amp;nbsp;나쁜&amp;nbsp;명령어가&amp;nbsp;어떻게&amp;nbsp;나쁜&amp;nbsp;답변으로&amp;nbsp;이어졌는지&amp;nbsp;분석하세요.&lt;br /&gt;&lt;br /&gt;2. 제공한 이유에 따라 새롭고 완전한 명령어를 생성하세요. 이 명령어는 복잡하고 직접적으로 답변하기 어려워야 하며, 원래의 명령어와 관련은 있지만 독립적이어야 합니다. 원래 명령어를 알지 않고도 답변할 수 있어야 하며, 다음 형식으로 작성하세요:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[New&amp;nbsp;Instruction]&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;새로운&amp;nbsp;명령어&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[End]&lt;br /&gt;&lt;br /&gt;3. 새롭게 생성된 명령어에 가능한 한 자세하게 답변하세요. 다음 형식으로 작성하세요:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[New&amp;nbsp;Answer]&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;새로운&amp;nbsp;답변&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[End]&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 프롬프트와 같이 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Teacher&lt;/b&gt;는&lt;/span&gt;&lt;/span&gt;&amp;nbsp;주어진 데이터를 Reflection하여 Instruction을 개선하고 개선된 데이터는 Ins-reflected Data로 표현되고있습니다. 그리고 새로운 Instruction와 Response는 각각 $x_ins, y_ins$로 표기되고 있네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;는 새로 만들어진 데이터를 IFD(Instruction-Following Difficulty)점수를 통해 평가하고, 난이도가 적합한지에 따라 데이터 ($x_1, y_1$)를 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IFD는 한 마디로 주어진 instruction이 얼마나 어려운지를 측정하는 평가지표입니다. &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Student&lt;/b&gt;&lt;/span&gt;모델의 output의 토큰의 확률분포로 구해집니다. 수식은 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$f_{\theta}(x) = \prod_{i=1}^{n} f(x[i] \mid x[1], \dots, x[i-1])$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 각 token ($x[i]$)을 차례대로 예측하며, 이전 token들의 정보를 조건으로 다음 token의 확률을 예측하는 수식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$L_{\theta}(y \mid x) = -\frac{1}{n} \sum_{i=1}^{n} \log f_{\theta}(y \mid x)$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: Log-Likelihood&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$\text{IFD}_{\theta}(y \mid x) = \frac{\text{ppl}(y \mid x)}{\text{ppl}(y)} = \exp \left( L_{\theta}(y \mid x) - L_{\theta}(y) \right)$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;IFD&lt;/b&gt;&lt;/span&gt;, instruction $x$가 response $y$에 미치는 영향을 측정, instruction이 있을 때의 난이도와 없을 때의 난이도를 비교합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$ppl(y|x)$는 주어진 instruction $x$에서 response $y$를 예측하는 모델의 perplexity입니다. 낮을 수록 더 잘 예측하고 있는 것을 의미합니다. 당연히 $ppl(y)$는 instruction이 없는 상태에서 response y를 예측하는 것이겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 perplexity를 비교하여 IFD점수를 구하는데, 이는 Log-Likelihood의 차이를 통해 계산됩니다. 해당 값이 높을 수록 instruction이 response을 잘 예측하는 데에 더 어려움을 겪는 것을 의미하며, 명령어의 난이도가 높다는 것을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, IFD가 높으면 instruction을 따르는 것이 어려운 것입니다. 해당 IFD의 score를 통해 앞서 말했듯 $x_1, y_1$을 선택합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이때, IFD가 가장 높은 데이터를 선택합니다.&lt;/span&gt; IFD가 높다는 것은 해당 instruction이 &lt;b&gt;S&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;tudent&lt;/b&gt;&lt;/span&gt;에게 response를 생성하는데 더 어려움을 준다는 것을 의미하며, 해당 instruction이 &lt;b&gt;Student&lt;/b&gt;에게 더 어렵다는 것을 시사한다라고 저자는 말했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이는 즉 Student에게 더 복잡하고 학습할 가치가 있는 데이터라고 해석할 수 있을 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Selective Response Reflection&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;앞서 구한 ($x_1, y_1$)가 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Teacher&lt;/b&gt;&lt;/span&gt;에 입력됩니다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이때 저자는 $x_1$이 &lt;b&gt;Student&lt;/b&gt;에게 어렵다고 IFD로써 보장되지만, 그에 따른 response $y_1$은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;여전히 최적화되지 않았을 수도 있다&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 문제를 제기합니다.&lt;/span&gt; 이를 위해 &lt;b&gt;Teacher&lt;/b&gt;은 response에 대한 reflection을 수행하여 개선된 응답 ($y_res$)을 생성합니다. 해당 데이터는 Res-reflected Data로 표기됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 단계에서 단순히 instruction의 난이도만 측정하는 IFD에서 더 나아가, r-IFD(Reversed Instruction-Following Difficulty)라는 새로운 지표를 추가합니다. 이는 response를 기반으로 instruction을 얼마나 쉽게 유추할 수 있는지 평가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낮은 r-IFD점수는 &lt;b&gt;Student&lt;/b&gt;가 response를 통해 instruction을 더욱 쉽게 유추할 수 있음을 나타내며, 이는 해당 데이터가 Student에게 학습하기 Feasibility하다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;Student&lt;/b&gt;는 r-IFD 점수를 사용하여 response가 학습 가능성이 있는지(Feasibility)를 평가합니다. 그 결과 최종적으로 선택된 데이터 ( $ x_2, y_2 $ )가 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 r-IFD가 낮을수록 더 학습에 적합한 샘플이라고 판단하였습니다. $(x_1, y_1)$은 IFD가 가장 높은, 어려운 것을 택했지만 r-IFD는 왜 가장 낮은것을 택할지 궁금했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유추한 바로는 어려운 instruction을 통해 instruction이해능력을 키우면서도 이를 잘 이해하고 쉽고 명확한 response를 생성하도록 하는 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Selective Response Reflection에 사용된 프롬프트는 아래와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B3XVv/btsJwNilZzx/eOzwK9hykncq3NlbBMtl60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B3XVv/btsJwNilZzx/eOzwK9hykncq3NlbBMtl60/img.png&quot; data-alt=&quot;Figure 6: The prompt we used to modify the existing response.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B3XVv/btsJwNilZzx/eOzwK9hykncq3NlbBMtl60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB3XVv%2FbtsJwNilZzx%2FeOzwK9hykncq3NlbBMtl60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;884&quot; height=&quot;514&quot; data-origin-width=&quot;884&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Figure 6: The prompt we used to modify the existing response.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 프롬프트를 한글로 정리하면 아래 더보기와 같습니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**시스템 프롬프트**&amp;nbsp;&amp;nbsp; &lt;br /&gt;당신은&amp;nbsp;주어진&amp;nbsp;명령어에&amp;nbsp;대한&amp;nbsp;응답의&amp;nbsp;품질을&amp;nbsp;확인하는&amp;nbsp;데&amp;nbsp;있어&amp;nbsp;도움이&amp;nbsp;되며,&amp;nbsp;정확하지만&amp;nbsp;까다로운&amp;nbsp;조력자입니다. &lt;br /&gt;&lt;br /&gt;**사용자&amp;nbsp;프롬프트** &lt;br /&gt;&lt;br /&gt;``` &lt;br /&gt;[Instruction]&amp;nbsp;&amp;nbsp; &lt;br /&gt;명령어&amp;nbsp;&amp;nbsp; &lt;br /&gt;[The&amp;nbsp;Start&amp;nbsp;of&amp;nbsp;Answer]&amp;nbsp;&amp;nbsp; &lt;br /&gt;응답의&amp;nbsp;시작&amp;nbsp;&amp;nbsp; &lt;br /&gt;[Answer]&amp;nbsp;&amp;nbsp; &lt;br /&gt;응답&amp;nbsp;&amp;nbsp; &lt;br /&gt;[The&amp;nbsp;End&amp;nbsp;of&amp;nbsp;Answer]&amp;nbsp;&amp;nbsp; &lt;br /&gt;응답의&amp;nbsp;끝 &lt;br /&gt;``` &lt;br /&gt;&lt;br /&gt;우리는&amp;nbsp;주어진&amp;nbsp;명령어에&amp;nbsp;대한&amp;nbsp;응답의&amp;nbsp;품질과&amp;nbsp;관련된&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;질문에&amp;nbsp;답해주길&amp;nbsp;원합니다: &lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;왜&amp;nbsp;이&amp;nbsp;응답이&amp;nbsp;주어진&amp;nbsp;명령어에&amp;nbsp;대해&amp;nbsp;좋지&amp;nbsp;않은가?&amp;nbsp;**도움이&amp;nbsp;되는지**,&amp;nbsp;**관련성이&amp;nbsp;있는지**,&amp;nbsp;**정확성**,&amp;nbsp;그리고&amp;nbsp;**세부&amp;nbsp;사항의&amp;nbsp;수준**을&amp;nbsp;기준으로&amp;nbsp;분석해&amp;nbsp;주세요. &lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;제공한&amp;nbsp;이유를&amp;nbsp;바탕으로,&amp;nbsp;더&amp;nbsp;나은&amp;nbsp;새로운&amp;nbsp;응답을&amp;nbsp;생성해&amp;nbsp;주세요.&amp;nbsp;새로운&amp;nbsp;응답은&amp;nbsp;완전하고&amp;nbsp;가능한&amp;nbsp;한&amp;nbsp;세부적으로&amp;nbsp;작성해야&amp;nbsp;하며,&amp;nbsp;다음&amp;nbsp;형식으로&amp;nbsp;작성해&amp;nbsp;주세요: &lt;br /&gt;&lt;br /&gt;``` &lt;br /&gt;[Better&amp;nbsp;Answer]&amp;nbsp;&amp;nbsp; &lt;br /&gt;더&amp;nbsp;나은&amp;nbsp;응답&amp;nbsp;&amp;nbsp; &lt;br /&gt;[End] &lt;br /&gt;```&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Instruction tuning&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 $(x_2, y_2)$를 통해 파인튜닝을 진행합니다. 여기서 볼 수 있듯이 별도의 데이터를 추가수집하지 않고 기존의 데이터를 변환하기만 해도 큰 성능 향상을 보였다는 점에서 인상깊었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Result 생략!)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Limitations&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자가 인정한 한계점은 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;Student&lt;/b&gt;가 바뀔 때 마다 새롭게 적용하여 데이터셋을 꾸며야 한다는 점입니다. 모델마다 선택되는 데이터가 달라지기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 새로운 모델마다 통계를 어쨋든 다시 계산해야 한다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 해당 방법론이 &lt;b&gt;Student&lt;/b&gt;에 맞는 데이터 생성을 가능하게 한다는 장점이 있지만, 모델이 달라질 때 마다 데이터를 다시 계산해야 하는 비효율성이 한계점으로 인정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파인튜닝을 지금껏 바닐라하게만 진행했던 것 같습니다. 이런 최신 기법들을 더욱 공부하고 프로젝트에 적용시킬 수 있는 능력을 키워야겠다고 느꼈습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;s&gt;&lt;b&gt;성능 미쳤다!&amp;nbsp;&lt;/b&gt;&lt;/s&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(수정 참고)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Hugging Face사이트의 Trending순위를 보던 중 갑자기 1위를 달성한 모델을 확인했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbqLql/btsJwYKaHyN/9y6ca1IW2doOG28bfrldK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbqLql/btsJwYKaHyN/9y6ca1IW2doOG28bfrldK0/img.png&quot; data-alt=&quot;2024.09.09기준 Hugging face의 trending 1위&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbqLql/btsJwYKaHyN/9y6ca1IW2doOG28bfrldK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbqLql%2FbtsJwYKaHyN%2F9y6ca1IW2doOG28bfrldK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;287&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2024.09.09기준 Hugging face의 trending 1위&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Meta 사의 Llama-3.1 모델 앞에 Reflection이라는 키워드를 보고 궁금증이 생겨 확인해보았더니&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;벤치마크 스코어가 말도 안되게 높았습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxV00/btsJuRzcpES/GGi1ob5KsI0krLK9NjzxkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxV00/btsJuRzcpES/GGi1ob5KsI0krLK9NjzxkK/img.png&quot; data-alt=&quot;70B짜리가 Claude, GPT, Gemini, Llama 3.1 405B를 넘어섰다고...??????&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxV00/btsJuRzcpES/GGi1ob5KsI0krLK9NjzxkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxV00%2FbtsJuRzcpES%2FGGi1ob5KsI0krLK9NjzxkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;317&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;70B짜리가 Claude, GPT, Gemini, Llama 3.1 405B를 넘어섰다고...??????&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;s&gt;엄청난 벤치마크 스코어를 보고, Reflection Tuning이 대체 뭐길래 라는 궁금증이 생겼습니다.&lt;/s&gt;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;+) 수정:&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://x.com/shinboson/status/1832933753837982024/photo/2&quot;&gt;https://x.com/shinboson/status/1832933753837982024/photo/2&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해당 포스트를 보면 위 벤치마크 결과는 잘못되었다고 비판하고있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Artificial Analysis라는 외국 업체에서 독립적으로 자체 평가를 한 결과 기존 Meta-Llama-3.1-70B보다 오히려 낮은 스코어를 기록했다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZsqYp/btsJw4RBeff/Ked9uhpuvh1oo7bgwbkfY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZsqYp/btsJw4RBeff/Ked9uhpuvh1oo7bgwbkfY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZsqYp/btsJw4RBeff/Ked9uhpuvh1oo7bgwbkfY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZsqYp%2FbtsJw4RBeff%2FKed9uhpuvh1oo7bgwbkfY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1870&quot; height=&quot;441&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2548&quot; data-origin-height=&quot;820&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IXwBf/btsJvXlOEAm/Nxg4ksI8gVWk66DPD8mja0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IXwBf/btsJvXlOEAm/Nxg4ksI8gVWk66DPD8mja0/img.jpg&quot; data-alt=&quot;자체적으로 실험한 벤치마크 스코어. 원본 모델보다 낮은 스코어를 보임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IXwBf/btsJvXlOEAm/Nxg4ksI8gVWk66DPD8mja0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIXwBf%2FbtsJvXlOEAm%2FNxg4ksI8gVWk66DPD8mja0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2548&quot; height=&quot;820&quot; data-origin-width=&quot;2548&quot; data-origin-height=&quot;820&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자체적으로 실험한 벤치마크 스코어. 원본 모델보다 낮은 스코어를 보임&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;결정적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;Reflection Llama-3.1 70B가 크게 부정적인 평가를 받는 이유&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xWcOF/btsJxjazIWN/ICyWvizDvLly0ylIIpYvNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xWcOF/btsJxjazIWN/ICyWvizDvLly0ylIIpYvNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xWcOF/btsJxjazIWN/ICyWvizDvLly0ylIIpYvNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxWcOF%2FbtsJxjazIWN%2FICyWvizDvLly0ylIIpYvNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1017&quot; height=&quot;257&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;제가 hugging face 커뮤니티에 직접 올린 문의글에 대한 답변입니다. 왜이렇게 부정적인지에 대한 글이었는데 위와 같은 행동을 벌였다고 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일단 직접 사용해보려고 GGUF버전을 다운로드 하여 원본 4Q-L모델과 비교하였습니다. 그 결과 성능이 확실히 높아진 것을 알 수 있는데, 추론 과정에서도 reflection 알고리즘을 수행합니다. 사용할때 주어진 system prompt사용을 권유했고 문장 끝에 Think carefully등과 같은 프롬프트도 포함시켰습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;성능 자체는 향상된 것으로 보이지만 위와같은 언행들로 부정적인 평가를 받고 있는 것 같습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;+&amp;nbsp;자료를 제공해주신 &lt;a style=&quot;background-color: #f6e199; color: #222222; text-align: left;&quot; href=&quot;https://heygeronimo.tistory.com/&quot;&gt;HEY, GERONIMO님&amp;nbsp; 감사드립니다.&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726133227751&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;'세계 최고 오픈 소스 모델' 제작자, 사기 논란에 &amp;quot;앞서나갔다&amp;quot;고 사과 - AI타임스&quot; data-og-description=&quot;\&amp;quot;세계 최고의 오픈 소스 모델\&amp;quot; 사기 논란에 휩싸였던 하이퍼라이트의 CEO가 \&amp;quot;너무 앞서나갔다\&amp;quot;라고 사과했다. 사실상 과장 홍보라는 것을 인정한 셈이다.맷 슈머 하이퍼라이트 CEO는 11...&quot; data-og-host=&quot;www.aitimes.com&quot; data-og-source-url=&quot;https://www.aitimes.com/news/articleView.html?idxno=163312&quot; data-og-url=&quot;https://www.aitimes.com/news/articleView.html?idxno=163312&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bARPW8/hyW23YUHZS/cM8VUuLmr6kNM5Tlg34NBk/img.jpg?width=400&amp;amp;height=400&amp;amp;face=127_109_260_254,https://scrap.kakaocdn.net/dn/owTq4/hyW2ZCcWck/5rCkKjjaDP0FkMOXlyh6S0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=127_109_260_254&quot;&gt;&lt;a href=&quot;https://www.aitimes.com/news/articleView.html?idxno=163312&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aitimes.com/news/articleView.html?idxno=163312&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bARPW8/hyW23YUHZS/cM8VUuLmr6kNM5Tlg34NBk/img.jpg?width=400&amp;amp;height=400&amp;amp;face=127_109_260_254,https://scrap.kakaocdn.net/dn/owTq4/hyW2ZCcWck/5rCkKjjaDP0FkMOXlyh6S0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=127_109_260_254');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'세계 최고 오픈 소스 모델' 제작자, 사기 논란에 &quot;앞서나갔다&quot;고 사과 - AI타임스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;\&quot;세계 최고의 오픈 소스 모델\&quot; 사기 논란에 휩싸였던 하이퍼라이트의 CEO가 \&quot;너무 앞서나갔다\&quot;라고 사과했다. 사실상 과장 홍보라는 것을 인정한 셈이다.맷 슈머 하이퍼라이트 CEO는 11...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aitimes.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 제작자도 잘못을 인정한 해프닝이 되었습니다. 역시나 보이는대로 모든것을 믿어버리면 안되는군요,, 저는 처음 GPT, Claude를 뛰어넘는 스코어를 보고 추론 해볼때까지 설레기만 했었습니다. (다들 그런가요?)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM 초보자 입니다. 틀린 내용이 있을 수 있으며 지적 사항과 의논할 부분 언제든 댓글 남겨주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/96</guid>
      <comments>https://sjkoding.tistory.com/96#entry96comment</comments>
      <pubDate>Tue, 10 Sep 2024 16:27:28 +0900</pubDate>
    </item>
    <item>
      <title>제3회 ETRI 휴먼이해 인공지능 논문경진대회 대상 리뷰 (ICTC2024 발표)</title>
      <link>https://sjkoding.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;+) 25.04.14: 제 4회 ETRI 휴먼이해 인공지능 논문경진대회가 개최됐네요! &lt;b&gt;이번에는 데이콘에서 대회 운영을 돕습니다.&amp;nbsp;&lt;/b&gt;&lt;br /&gt;해당 포스팅 내용이 좋은 참고가 되길 바랍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;해당 방법론이 유용하고 도움이 되었다고 판단되시면 아래의 인용정보를 기입해주시길 바랍니다.&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744794164712&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@inproceedings{na2024pixleepflow,
  title={PixleepFlow: A Pixel-Based Lifelog Framework for Predicting Sleep Quality and Stress Level},
  author={Na, Younghoon and Oh, Seunghun and Ko, Seongji and Lee, Hyunkyung},
  booktitle={2024 15th International Conference on Information and Communication Technology Convergence (ICTC)},
  pages={810--815},
  year={2024},
  organization={IEEE}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744615409754&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;제 4회 ETRI 휴먼이해 인공지능 논문경진대회 - DACON&quot; data-og-description=&quot;분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.&quot; data-og-host=&quot;dacon.io&quot; data-og-source-url=&quot;https://dacon.io/competitions/official/236468/overview/description?utm_source=DACON&amp;amp;utm_campaign=2b77ff0bda-EMAIL_CAMPAIGN_2022_10_05_06_21_COPY_01&amp;amp;utm_medium=email&amp;amp;utm_term=0_7485ff9d1e-2b77ff0bda-477658889&quot; data-og-url=&quot;https://dacon.io/competitions/official/236468/overview/description?utm_campaign=2b77ff0bda-EMAIL_CAMPAIGN_2022_10_05_06_21_COPY_01&amp;amp;utm_medium=email&amp;amp;utm_source=DACON&amp;amp;utm_term=0_7485ff9d1e-2b77ff0bda-477658889&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nQLHe/hyYFyv8LdB/OUb7ZDLt87y54whDCgjrjK/img.jpg?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810&quot;&gt;&lt;a href=&quot;https://dacon.io/competitions/official/236468/overview/description?utm_source=DACON&amp;amp;utm_campaign=2b77ff0bda-EMAIL_CAMPAIGN_2022_10_05_06_21_COPY_01&amp;amp;utm_medium=email&amp;amp;utm_term=0_7485ff9d1e-2b77ff0bda-477658889&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dacon.io/competitions/official/236468/overview/description?utm_source=DACON&amp;amp;utm_campaign=2b77ff0bda-EMAIL_CAMPAIGN_2022_10_05_06_21_COPY_01&amp;amp;utm_medium=email&amp;amp;utm_term=0_7485ff9d1e-2b77ff0bda-477658889&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nQLHe/hyYFyv8LdB/OUb7ZDLt87y54whDCgjrjK/img.jpg?width=1440&amp;amp;height=810&amp;amp;face=0_0_1440_810');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;제 4회 ETRI 휴먼이해 인공지능 논문경진대회 - DACON&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;분석시각화 대회 코드 공유 게시물은 내용 확인 후 좋아요(투표) 가능합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dacon.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;figure id=&quot;og_1719634548459&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;제3회 ETRI 휴먼이해 인공지능 논문경진대회&quot; data-og-description=&quot;본 대회는 한국전자통신연구원(ETRI)이 주최하고 과학기술정보통신부와 국가과학기술연구회(NST)가 후원합니다&quot; data-og-host=&quot;aifactory.space&quot; data-og-source-url=&quot;https://aifactory.space/task/2790/overview&quot; data-og-url=&quot;https://aifactory.space/task/2790/overview&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bj32Ee/hyWrOaYxMQ/LuYASftsLu2t76k7dsief0/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280,https://scrap.kakaocdn.net/dn/h4epo/hyWrRrZRzm/dRFTrkWmvBKnRUu6EwmY2K/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280,https://scrap.kakaocdn.net/dn/Q6xaa/hyWrKTXwcs/pcok6g6JswzkKjjXxtohD1/img.jpg?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675&quot;&gt;&lt;a href=&quot;https://aifactory.space/task/2790/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://aifactory.space/task/2790/overview&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bj32Ee/hyWrOaYxMQ/LuYASftsLu2t76k7dsief0/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280,https://scrap.kakaocdn.net/dn/h4epo/hyWrRrZRzm/dRFTrkWmvBKnRUu6EwmY2K/img.jpg?width=280&amp;amp;height=280&amp;amp;face=0_0_280_280,https://scrap.kakaocdn.net/dn/Q6xaa/hyWrKTXwcs/pcok6g6JswzkKjjXxtohD1/img.jpg?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;제3회 ETRI 휴먼이해 인공지능 논문경진대회&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;본 대회는 한국전자통신연구원(ETRI)이 주최하고 과학기술정보통신부와 국가과학기술연구회(NST)가 후원합니다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;aifactory.space&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #222222; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;주최 : 한국전자통신연구원 (ETRI)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;후원 : 과학정보기술통신부, 국가과학기술연구회 (NST)&lt;/li&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;운영 : 인공지능팩토리 (AIFactory)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 대회는 다양한 스마트폰, 스마트워치 센서 데이터가 주어졌을 때, 이를 활용하여 총 7가지의 라벨을 예측하는 모델을 개발하고 &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;The 15th International Conference on ICT Convergence(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;ICTC 2024)와 연계하여 논문 투고 및 엑셉까지 이루어져야합니다. 제 4회 대회에서도 유사한 방식으로 경진대회가 진행될 것으로 보입니다. 해당 포스팅이 대회 진행에 좋은 참고자료가 되었으면 좋겠습니다. (&lt;s&gt;출판할 논문내용은 출판이 되거나 arXiv에 업로드 되면 링크로 추가첨부하겠습니다.&lt;/s&gt;) --&amp;gt; &lt;a href=&quot;https://www.arxiv.org/abs/2502.17469&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.arxiv.org/abs/2502.17469&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1744615678001&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;PixleepFlow: A Pixel-Based Lifelog Framework for Predicting Sleep Quality and Stress Level&quot; data-og-description=&quot;The analysis of lifelogs can yield valuable insights into an individual's daily life, particularly with regard to their health and well-being. The accurate assessment of quality of life is necessitated by the use of diverse sensors and precise synchronizat&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://www.arxiv.org/abs/2502.17469&quot; data-og-url=&quot;https://arxiv.org/abs/2502.17469v2&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dFs1LN/hyYCjAAPYL/ajDBMbdxmEM4odtyVERnn0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/bnDcm3/hyYCkM1fCk/dqXfk4XpKqwSraH7OC6ejK/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://www.arxiv.org/abs/2502.17469&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.arxiv.org/abs/2502.17469&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dFs1LN/hyYCjAAPYL/ajDBMbdxmEM4odtyVERnn0/img.png?width=1200&amp;amp;height=700&amp;amp;face=0_0_1200_700,https://scrap.kakaocdn.net/dn/bnDcm3/hyYCkM1fCk/dqXfk4XpKqwSraH7OC6ejK/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;PixleepFlow: A Pixel-Based Lifelog Framework for Predicting Sleep Quality and Stress Level&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The analysis of lifelogs can yield valuable insights into an individual's daily life, particularly with regard to their health and well-being. The accurate assessment of quality of life is necessitated by the use of diverse sensors and precise synchronizat&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;| 논문 모집분야&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  라이프로그 데이터를 이용한 수면, 감정, 스트레스 인식 및 추론&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #222222; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&lt;b&gt;논문주제 : 라이프로그 데이터셋을 이용하여 일상 경험에서의 다양한 지표를 인식 및 추론하&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추론 대상 (labels)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하루 단위로 이루어진 multi binary classification label입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q1.&amp;nbsp; 전반적인 수면의 질&lt;br /&gt;Q2.&amp;nbsp; 감정 상태&lt;br /&gt;Q3.&amp;nbsp; 스트레스 상태&lt;br /&gt;S1.&amp;nbsp; 수면 시간&lt;br /&gt;S2.&amp;nbsp; 수면의 효율&lt;br /&gt;S3.&amp;nbsp; 잠에 드는 데 걸리는 시간(입면 잠복기, Sleep onset latency, SL)&lt;br /&gt;S4.&amp;nbsp; 입면 후 각성 시간(WASO, Wake after sleep onset)&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;주어진 데이터&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2023년도에 측정된 데이터 및 2021년도에 측정된 데이터가 주어집니다. 이 때, 2023년도와 2020년도에서 측정에 사용된 센서가 다르며, 피실험자도 상이합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 점은 2023년 데이터를 train셋, 2020년도의 8명의 실험자 중 4명은 validation셋, 나머지 4명은 실제 평가에 사용되는 test셋으로 지정되었다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;validation셋이라고 해서 학습에 사용할 수 없는 건 아닙니다. 따라서 validation셋이 비교적 test셋과 분포가 비슷할 것으로 예상되며, 측정된 센서들이 정확히 겹치기 때문에 test셋을 추론하는데 가장 큰 힌트가 되는 데이터인 반면, train셋은 측정 센서가 달라 test셋과는 거리가 먼 데이터셋입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train셋을 활용해보고자 train포함 학습, Domain Adaption등등 다양한 기법을 실험해보았지만 train셋을 사용하지 않았을 때가 성능이 훨씬 우수했습니다. 이는 test셋과 데이터 분포가 크게 상이하여 오히려 학습에 방해가되는 현상으로 추정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 총 아래 그림과 같이 18개의 센서를 가집니다(validation, test).&amp;nbsp; 각 센서는 주파수가 상이하고, 결측치 시간도 상이합니다. 즉 동기화 과정이 반드시 필요할 것입니다. (저희는 논문에 Channel이라는 용어를 사용했습니다. 이는 데이터에 포함된 센서의 개수를 의미합니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;990&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TkrRi/btsI1uJ4kkn/koFGwUQv1iKU6ODWGb4k1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TkrRi/btsI1uJ4kkn/koFGwUQv1iKU6ODWGb4k1k/img.png&quot; data-alt=&quot;사용된 데이터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TkrRi/btsI1uJ4kkn/koFGwUQv1iKU6ODWGb4k1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTkrRi%2FbtsI1uJ4kkn%2FkoFGwUQv1iKU6ODWGb4k1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;896&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;990&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;사용된 데이터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;외부데이터 사용이 허용되었음에도, 외부데이터를 활용하지 못한점이 아쉬운 점으로 남지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;validation셋만으로도 충분한 성능을 이끌어 낼 수 있었습니다.&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(실제 검증에만 사용되는 validation셋과 혼동하면 안됩니다. 주어진 데이터셋이 validation으로 쓰라고 주어졌지만, train에 사용한 데이터입니다. 규칙에 위반되지 않습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HOW?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논문을 작성하면서 저희 방법론을 &quot;PixleepFlow&quot;라고 지칭했습니다. 대충 감이 오시나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 스트레스 지표도 추론을 하지만, 수면과 큰 관련이 있는 대회이다보니 Pixel + sleep의 합성어로 이름을 명명했습니다. 여기서 Pixel은 흔히 말하는 이미지 데이터의 한 칸의 정보를 나타내는 단위를 의미합니다. 즉, &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;저희는 &lt;b&gt;이미지 변환&lt;/b&gt;을 적극 활용하여 성능향상을 도출했습니다.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pixleepflow의 프레임워크는 아래 그림과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUK6n3/btsI1cJBAtR/Mzl6ulMM8tFZ6vTFZATZik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUK6n3/btsI1cJBAtR/Mzl6ulMM8tFZ6vTFZATZik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUK6n3/btsI1cJBAtR/Mzl6ulMM8tFZ6vTFZATZik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUK6n3%2FbtsI1cJBAtR%2FMzl6ulMM8tFZ6vTFZATZik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;371&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data preprocessing과정에서 3가지의 과정을 거쳐 만들어진 Composite Image와 Spectrogram이미지 데이터셋, 그리고 기존 Raw데이터셋을 만들어냅니다. 3가지의 과정은 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Frequency Normalization&lt;/b&gt;&lt;br /&gt;다양한 센서들은 서로 다른 주파수(Hz)를 가집니다. 동기화를 위해 주파수를 정규화하는 과정이 필요했는데, 이를 위해 1Hz단위로 데이터를 집계하여 매 초마다 가장 가까운 데이터 포인트를 매핑하는 방식을 채택했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Synchronization&lt;br /&gt;&lt;/b&gt;데이터는 00:00:00부터 23:59:59까지 총 86,400(24시간)에 대한 값으로 하나의 데이터셋으로 동기화됩니다. 매 초의 데이터로 기록함으로써 동기화된 데이터는 다양한 형태로 변환이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Interpolation&lt;br /&gt;&lt;/b&gt;주파수가 1Hz이상인 경우에 결측치가 발생하며, 애초에 결측치인 경우도 존재합니다. 이를 위해 linear interpolation을 적용하였고 데이터의 시작이나 끝 부분에 데이터가 존재하지 않을 경우에는 데이터의 과도한 변형을 방지하기 위해 해당 부분은 보간하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 변환된 데이터는 하나의 이미지에 모든 동기화 및 정규화된 데이터로 표현됩니다. 하나의 이미지는, 하루 단위의 이미지입니다. medical field에서 수면의 질을 판단할 때 시각화 된 신호를 보고 파악하는 경우가 있는 것으로 알고있고, 사람이 할 수 있으면 딥러닝도 반드시 할 수 있다는 저희 가치관이 있었기 떄문에 시도할 수 있던 방법이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Raw데이터의 1D-CNN(resnet 매커니즘 사용), Spectrogram(Concat&amp;amp;Resnext), Image(seresnext)중에 Image데이터가 가장 성능이 우수하였습니다. Image데이터의 생김새는 아래와 같습니다. (확장실험의 11channel 데이터 예시)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;951&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1sHWX/btsI05KOdaX/u3uiDXrnIniLK9pIhsDZ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1sHWX/btsI05KOdaX/u3uiDXrnIniLK9pIhsDZ31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1sHWX/btsI05KOdaX/u3uiDXrnIniLK9pIhsDZ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1sHWX%2FbtsI05KOdaX%2Fu3uiDXrnIniLK9pIhsDZ31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;951&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;951&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Experiments Result&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 주로 timm라이브러리를 사용하여 seresnext101_32x4d와 resnext101_32x32d를 사용하였으며, 적절한 앙상블을 통해 성능을 향상시켰습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Test셋의 라벨은 알 수 없으므로, 자체적으로 K-fold validation score를 논문에 기입했는데, 일반적인 k-fold validation과 달리 각 fold별 최고 f1-score(macro)를 가진 모델들의 추론값을 평균내어 스코어를 기입했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실험 결과는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VXpXc/btsI04lb9Eg/tkKcHpgFgtrtXVAoFBvDNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VXpXc/btsI04lb9Eg/tkKcHpgFgtrtXVAoFBvDNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VXpXc/btsI04lb9Eg/tkKcHpgFgtrtXVAoFBvDNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVXpXc%2FbtsI04lb9Eg%2FtkKcHpgFgtrtXVAoFBvDNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;574&quot; height=&quot;221&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 제안한 pixleep 방법론이 동일채널 가장 우수한 성능을 보였습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt; Model Interpretation&amp;nbsp; (XAI: eXplainable AI)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pixleep을 통해 만들어진 이미지 데이터에서 모델이 어느 센서정보를 주로 활용하고 보는지 시각화하기 위해 CAM기법을 통해 시각화 하였습니다. 여러 CAM종류 중에 성능이 비교적 우수했던 Full-CAM을 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pixleepFlow방법론은 모델 설명 측면에 대해서도 두드러진 강점을 보입니다. SHAP지수를 이용한 방법과는 달리 어느 시간대에 어느 센서 값을 중요하게 볼 수 있었는지, 어떤 변화가 있을 때 중점을 두는지등을 한 눈에 시각화 할 수 있게 됩니다. 이는 확장하여 LLM과 적용한다면 자동화된 분석 결과를 의사에게 제공하여 참고자료로 활용할 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cczRY9/btsI1QT7kvk/HJkxigbbK4oFKGzkD6k6kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cczRY9/btsI1QT7kvk/HJkxigbbK4oFKGzkD6k6kk/img.png&quot; data-alt=&quot;가속도(x, y, z), 심박수, 액티비티 순&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cczRY9/btsI1QT7kvk/HJkxigbbK4oFKGzkD6k6kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcczRY9%2FbtsI1QT7kvk%2FHJkxigbbK4oFKGzkD6k6kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;934&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가속도(x, y, z), 심박수, 액티비티 순&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 XAI의 결과물을 보았을 때 아래의 결론을 도출하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;activity&lt;/b&gt;: 모델 예측에서 중요한 지표로 작용하지 않음. &lt;br /&gt;&lt;b&gt;가속도&lt;/b&gt;: Y축과 Z축 센서가 중요한 특징으로 자주 사용됨. &lt;br /&gt;&lt;b&gt;심박수&lt;/b&gt;: 일관되게 중요한 요소로 식별됨. &lt;br /&gt;&lt;b&gt;침대에서의&amp;nbsp;시간(TIB)&lt;/b&gt;:&amp;nbsp;수면&amp;nbsp;관련&amp;nbsp;패턴을&amp;nbsp;식별하는&amp;nbsp;데&amp;nbsp;주요&amp;nbsp;초점이&amp;nbsp;됨. &lt;br /&gt;&lt;b&gt;수면&amp;nbsp;중&amp;nbsp;스마트폰&amp;nbsp;사용&lt;/b&gt;: &lt;br /&gt;모델은&amp;nbsp;스마트폰&amp;nbsp;확인과&amp;nbsp;관련된&amp;nbsp;미세한&amp;nbsp;움직임을&amp;nbsp;우선적으로&amp;nbsp;처리함. &lt;br /&gt;이러한&amp;nbsp;움직임은&amp;nbsp;뚜렷한&amp;nbsp;움직임에&amp;nbsp;비해&amp;nbsp;덜&amp;nbsp;두드러졌음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 데이터 수가 적기 때문에 일반적인 결과라고 보기 어렵습니다. 단, 주어진 데이터 내에서는 일반적으로 나타난 해석 결과입니다. 데이터셋이 더욱 풍부해질 때 고도화된 연구 결과가 많이 도출 될 것 같습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;총평&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 데이터셋의 양이 너무 적어 힘들었던 대회였습니다. train셋을 조금 더 잘 활용할 수 있었다면 큰 성능향상을 도출할 수 있었지만 그러지 못해 아쉽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대회를 하면서 시계열 데이터를 다루는 방법에 대해 심도있게 고찰할 수 있었고, 데이터 가공 및 분석능력도 향상되었습니다. 논문도 겸해 작성할 수 있어 좋았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공동저자: [NYH, OSH] &amp;lt;-- 고생해따!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;+) ICTC에서 4(accept), 4(accept), 5(strong accept), 5(strong accept)로 개제 승인이 되었습니다. --&amp;gt; &lt;a href=&quot;https://www.arxiv.org/abs/2502.17469&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.arxiv.org/abs/2502.17469&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;+) 해당 방법론은 참가자 중 최고 스코어를 기록하여 대상을 기록했습니다. 이로 인해 상금과 과학기술정보통신부 장관상을 수여받았습니다. 대단히 감사드립니다.&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oIPeK/btsJ9KxESkS/7RAkNvo2DU1HoKTug4RaP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oIPeK/btsJ9KxESkS/7RAkNvo2DU1HoKTug4RaP1/img.png&quot; data-alt=&quot;제주 바다와 함께&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oIPeK/btsJ9KxESkS/7RAkNvo2DU1HoKTug4RaP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoIPeK%2FbtsJ9KxESkS%2F7RAkNvo2DU1HoKTug4RaP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;제주 바다와 함께&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AHtBb/btsJ1KrIjQV/1zqGKvXLh4s7wko2hhKgwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AHtBb/btsJ1KrIjQV/1zqGKvXLh4s7wko2hhKgwK/img.png&quot; data-alt=&quot;팀명: 통못자핫도그&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AHtBb/btsJ1KrIjQV/1zqGKvXLh4s7wko2hhKgwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAHtBb%2FbtsJ1KrIjQV%2F1zqGKvXLh4s7wko2hhKgwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1792&quot; height=&quot;1024&quot; data-origin-width=&quot;1792&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;팀명: 통못자핫도그&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Deep Learning</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/95</guid>
      <comments>https://sjkoding.tistory.com/95#entry95comment</comments>
      <pubDate>Mon, 12 Aug 2024 14:50:36 +0900</pubDate>
    </item>
    <item>
      <title>[LLM]Llama 3.1 설치 및 ValueError: rope_scaling 해결방법  vLLM 에러 해결 such as '_OpNamespace' '_C' object has no attribute 'rms_norm')</title>
      <link>https://sjkoding.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721794601035&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;meta-llama/Meta-Llama-3.1-8B-Instruct &amp;middot; Hugging Face&quot; data-og-description=&quot;The information you provide will be collected, stored, processed and shared in accordance with the Meta Privacy Policy. LLAMA 3.1 COMMUNITY LICENSE AGREEMENT Llama 3.1 Version Release Date: July 23, 2024 &amp;quot;Agreement&amp;quot; means the terms and conditions for use, &quot; data-og-host=&quot;huggingface.co&quot; data-og-source-url=&quot;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&quot; data-og-url=&quot;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b7sibn/hyWGUU2Uv9/KyyVS17VSBuc9bLv6Y6IFk/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648&quot;&gt;&lt;a href=&quot;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b7sibn/hyWGUU2Uv9/KyyVS17VSBuc9bLv6Y6IFk/img.png?width=1200&amp;amp;height=648&amp;amp;face=0_0_1200_648');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;meta-llama/Meta-Llama-3.1-8B-Instruct &amp;middot; Hugging Face&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The information you provide will be collected, stored, processed and shared in accordance with the Meta Privacy Policy. LLAMA 3.1 COMMUNITY LICENSE AGREEMENT Llama 3.1 Version Release Date: July 23, 2024 &quot;Agreement&quot; means the terms and conditions for use,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;huggingface.co&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 시간으로 7월 24일 새벽에 Llama 3.1 hugging face에 오픈소스로 공개되었다. 파인튜닝할 LLM모델을 탐색중이었는데 마침 타이밍이 딱 맞아떨어져 해당 모델을 바로 사용해보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 모델을 다운로드 받기 위해서, huggingface 계정이 필요하다. 관리자에게 코드 접근 권한을 요청하고 access를 받아야만 다운로드, 조회가 가능하다. (보통 10분내로 access가 자동적으로 이루어지는 것 같다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;accept를 받고 나서, git clone을 할 경우 password를 요구하는데, 이는 access token키를 입력해야한다. 만약 그래도 안된다면&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721794664204&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone https://&amp;lt;TOKEN&amp;gt;@huggingface.co/meta-llama/Meta-Llama-3.1-8B-Instruct&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;TOKEN&amp;gt;자리에 본인의 access token키를 입력한 후, password에도 동일하게 해당 TOKEN을 입력해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌저찌 다운로드가 완료되었으면 모델을 실행시켜야하는데 공통적으로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;ValueError: `rope_scaling` must be a dictionary with two fields&lt;/span&gt; 라는 오류가 발생한다. 대충 rope_scaling은 두 개의 필드를 가진 딕셔너리여야한다는 것인데, 이를 해결하기 위해 transformers 라이브러리를 최신버전으로 업데이트해줘야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1721794791974&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install --upgrade transformers&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 위의 오류는 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 커뮤니티 글을 보면 추가적으로 &lt;span style=&quot;background-color: #ffffff; color: #4b5563; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;'top_k_top_p_filtering' ImportError.&lt;/span&gt; 가 날 수도 있다고 하는데, 이 경우는 &lt;span style=&quot;background-color: #ffffff; color: #4b5563; text-align: start;&quot;&gt;pip install --upgrade trl.로 해결할 수 있다했고, &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4b5563; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4b5563; text-align: start;&quot;&gt;필자의 경우 VLLM을 사용중인데, VLLM관련해서 type에러가 나길래 VLLM을 최신버전으로 업그레이드 시켰더니 해결되었다. 그런데 또다른 오류가 발생했다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AttributeError: '_OpNamespace' '_C' object has no attribute 'rms_norm' (골치 아파보이는 에러...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 에러를 해결하기위해 reinstall을 진행하고 다른 라이브러리를 업데이트해도 해결되지 않았다. 조금 시간이 걸렸는데. &lt;a href=&quot;https://github.com/vllm-project/vllm/issues/5454&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/vllm-project/vllm/issues/5454&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721801622556&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;[Bug]: 0.5.0 AttributeError: '_OpNamespace' '_C' object has no attribute 'rms_norm' &amp;middot; Issue #5454 &amp;middot; vllm-project/vllm&quot; data-og-description=&quot;Your current environment Collecting environment information... PyTorch version: 2.3.0+cu121 Is debug build: False CUDA used to build PyTorch: 12.1 ROCM used to build PyTorch: N/A OS: Ubuntu 22.04.2...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/vllm-project/vllm/issues/5454&quot; data-og-url=&quot;https://github.com/vllm-project/vllm/issues/5454&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://github.com/vllm-project/vllm/issues/5454&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/vllm-project/vllm/issues/5454&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Bug]: 0.5.0 AttributeError: '_OpNamespace' '_C' object has no attribute 'rms_norm' &amp;middot; Issue #5454 &amp;middot; vllm-project/vllm&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Your current environment Collecting environment information... PyTorch version: 2.3.0+cu121 Is debug build: False CUDA used to build PyTorch: 12.1 ROCM used to build PyTorch: N/A OS: Ubuntu 22.04.2...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 시작으로 여러 방법론을 시도한 결과 해결방법은 아래와 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가상환경의 site-package 폴더로 이동 (ex: /home/user/anaconda3/envs/llm-api/lib/python3.10/site-packages)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. vllm 폴더 rm -rf로 전체 삭제&lt;/p&gt;
&lt;pre id=&quot;code_1721803138002&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rm -rf ./vllm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 해당 폴더 그대로 git clone &lt;a href=&quot;https://github.com/vllm-project/vllm.git&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/vllm-project/vllm.git&lt;/a&gt;&amp;nbsp; (vllm 폴더 생성됨)&lt;/p&gt;
&lt;pre id=&quot;code_1721803157350&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git clone https://github.com/vllm-project/vllm.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. vllm 폴더로 이동&lt;/p&gt;
&lt;pre id=&quot;code_1721803175968&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ./vllm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. vllm 직접 설치 pip install -e .&lt;/p&gt;
&lt;pre id=&quot;code_1721803205254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install -e .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 환경변수 설정&lt;/p&gt;
&lt;pre id=&quot;code_1721803261378&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export PYTHONPATH=$PYTHONPATH:/home/user/anaconda3/envs/llm-api/lib/python3.10/site-packages/vllm
# Path는 예시일 뿐, 본인 환경에 맞는 path로 기입해야합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그 후 정상적으로 실행되었다. 별도의 시스템 프롬프트 없이 한글 질문에 대해 한글로 잘 답변하는 것을 확인했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;1212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxmlIo/btsILd3jSYY/dw7zkkKTEyDqgHkyFtI8Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxmlIo/btsILd3jSYY/dw7zkkKTEyDqgHkyFtI8Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxmlIo/btsILd3jSYY/dw7zkkKTEyDqgHkyFtI8Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxmlIo%2FbtsILd3jSYY%2Fdw7zkkKTEyDqgHkyFtI8Qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1492&quot; height=&quot;1212&quot; data-origin-width=&quot;1492&quot; data-origin-height=&quot;1212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>LLM</category>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/94</guid>
      <comments>https://sjkoding.tistory.com/94#entry94comment</comments>
      <pubDate>Wed, 24 Jul 2024 15:42:44 +0900</pubDate>
    </item>
    <item>
      <title>AttributeError: module 'faiss' has no attribute 'StandardGpuResources' 해결법</title>
      <link>https://sjkoding.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;faiss index를 생성할 때, CPU로 진행하면 굉장히 느리므로 GPU를 사용하려고 할 때 자주 보는 에러이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPT에 물어보면 단순히 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;를 install하라고 하는데, 이는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;faiss-cpu&lt;/span&gt;가 설치되어있지 않은 경우를 가정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;faiss-cpu&lt;/span&gt;가 install 되어있을 때, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;를 install하더라도 faiss import시, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;faiss-cpu&lt;/span&gt;가 import되어 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;라이브러리를 인식할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;faiss-cpu&lt;/span&gt;를 uninstall하고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;를 설치해야하며, 만약 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;faiss-cpu&lt;/span&gt;가 설치되어있는 채로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;를 설치했다면 아마 uninstall했을 때 faiss 라이브러리 자체를 불러올 수 없다는 오류(ModuleNotFoundError)가 날 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;faiss-gpu&lt;/span&gt;를 uninstall하고, 다시 설치하면 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요약&lt;/h2&gt;
&lt;pre id=&quot;code_1720575816017&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip uninstall -y faiss-cpu faiss-gpu
pip install faiss-gpu&lt;/code&gt;&lt;/pre&gt;</description>
      <author>성지코딩</author>
      <guid isPermaLink="true">https://sjkoding.tistory.com/93</guid>
      <comments>https://sjkoding.tistory.com/93#entry93comment</comments>
      <pubDate>Wed, 10 Jul 2024 10:46:32 +0900</pubDate>
    </item>
  </channel>
</rss>