<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>yeon's</title>
    <link>https://yeonjins.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 13 Jun 2026 01:42:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>yeonjins</managingEditor>
    <image>
      <title>yeon's</title>
      <url>https://tistory1.daumcdn.net/tistory/5627045/attach/9d32b026034f41aebf4e02e7cd38b0ed</url>
      <link>https://yeonjins.tistory.com</link>
    </image>
    <item>
      <title>[프로그래머스 정규식 활용]</title>
      <link>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EA%B7%9C%EC%8B%9D-%ED%99%9C%EC%9A%A9</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문자열 다루기 기본&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 길이가 4 or 6 이면서, 모두 숫자로만 구성되있는지 확인하는 문제&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;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ^ : 시작 부분 문자열&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- \d{4} | \d{6} : \d 숫자가 4개 또는 6개 인지 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- $ : 끝 부분 문자열&lt;/p&gt;
&lt;pre id=&quot;code_1746768632437&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re
def solution(s):
    return bool(re.search(r'^(\d{4}|\d{6})$', s))&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;&lt;b&gt;[다른 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;re.search&lt;/b&gt; 에서 처음과 끝에 해당하는 기호인&lt;b&gt; ^&lt;/b&gt;와 &lt;b&gt;$&lt;/b&gt;를 활용하는 대신 &lt;b&gt;re.fullmatch&lt;/b&gt;를 활용&lt;/p&gt;
&lt;pre id=&quot;code_1746768684540&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re
def solution(s):
    return bool(re.fullmatch(r'\d{4}|\d{6}',s))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;옹알이 (1)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 &quot;aya&quot;, &quot;ye&quot;, &quot;woo&quot;, &quot;ma&quot; 이렇게 4가지를 조합해 완성할 수 있는지 여부 확인하는 문제&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;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- re.sub : 해당되는 문자열을 공백으로 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모두 변경되어 문자열이 공백이 되면 4가지 조합으로 완성 가능한 것이므로 +1&lt;/p&gt;
&lt;pre id=&quot;code_1746768895006&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re
def solution(babbling):
    answer = 0
    for bab in babbling:
        if not re.sub(&quot;(aya|ye|woo|ma)&quot;,&quot;&quot;,bab):
            answer += 1
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ re 라이브러리 공부&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 대문자, 소문자 상관없이 변경하길 원하면 &lt;b&gt;flags = re.IGNORECASE&lt;/b&gt; 활용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;re.sub('(aya|ye|woo|ma)','',bab, flags=re.IGNORECASE)&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;2. 대체 하고 싶은 횟수가 2개이면 &lt;b&gt;count=2&lt;/b&gt; 활용하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;re.sub('(aya|ye|woo|ma)','',bab, count=2)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;&amp;nbsp;&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;b&gt;- 몇 개 이상일때는 [ ] 로 감싸주기 :&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;&amp;nbsp; ([ ] 안에 {,}가 들어가면 문자 하나하나로 인식됨)&lt;/p&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;pre id=&quot;code_1746769913913&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re
def solution(new_id):
    new_id = new_id.lower()
    new_id = re.sub(r&quot;[^a-z0-9-_.]&quot;,'', new_id)
    new_id = re.sub(&quot;[.]{2,}&quot;,&quot;.&quot;, new_id)
    new_id = re.sub(&quot;^[.]|[.]$&quot;,&quot;&quot;,new_id)
    if not new_id : new_id = 'a'
    if len(new_id)&amp;gt;=16 : new_id = new_id[:15]
    new_id = re.sub(&quot;[.]$&quot;,&quot;&quot;,new_id)
    if len(new_id)&amp;lt;=2:
        while len(new_id)&amp;lt;3:
            new_id = new_id + new_id[-1]
    print(new_id)
    return new_id&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[3차] 파일명 정렬&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,10,2,3,4 이렇게 정렬되는 것을 막고, 01,1도 1,01 순으로 정렬되도록&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;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746785596123&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import re
def solution(files):
    allFiles = []
    for file in files:
        tmpFile = []
        tmpFile.append(re.search('^[^0-9]+',file).group())
        tmpFile.append(re.search('[0-9]{1,5}',file).group())
        tmpFile.append(file[len(tmpFile[0])+len(tmpFile[1]):])
        allFiles.append(tmpFile)
        
    allFiles.sort(key=lambda x: (x[0].lower(), int(x[1])))
    allFiles = [''.join(f) for f in allFiles]
    return allFiles&lt;/code&gt;&lt;/pre&gt;</description>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/42</guid>
      <comments>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%A0%95%EA%B7%9C%EC%8B%9D-%ED%99%9C%EC%9A%A9#entry42comment</comments>
      <pubDate>Fri, 9 May 2025 15:15:54 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 level.2] 정답률 70 이상</title>
      <link>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level2-%EC%A0%95%EB%8B%B5%EB%A5%A0-70-%EC%9D%B4%EC%83%81</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&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;1. 경우의 수를 몇가지 계산해보면 &lt;b&gt;피보나치&lt;/b&gt;인 것을 알 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주의할 점은 n이 1 또는 2일때!&lt;/p&gt;
&lt;pre id=&quot;code_1746115369016&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n):
    if n==1:
        return 1
    if n==2:
        return 2
    
    arr = [0]*(n+1)
    arr[1], arr[2] = 1, 2
    
    for i in range(3, n+1):
        arr[i] = arr[i-1]+arr[i-2]
    return arr[n]%1234567&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;N의 최소 공배수&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;1. 배열 내의 &lt;b&gt;최댓값의 배수&lt;/b&gt; 중 남은 모든 값으로 나눠 떨어지는 값 구하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최댓값의 배수는 1,2,3.. 순으로 쭉 곱하기&lt;/p&gt;
&lt;pre id=&quot;code_1746115451745&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(arr):
    n = 1
    max_num = max(arr)
    arr.remove(max_num)
    
    while True:
        n+=1
        cnt = 0
        for i in arr:
            if (max_num*n) % i != 0:
                break
            else:
                cnt +=1
                if cnt == len(arr):
                    return max_num*n&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;1. 이진수로 바꿔 1의 개수 구해두고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 십진수에서 1씩 더해가며 이진수로 변환해 1의 개수 비교하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+ re 모듈의 findall을 활용하면 효율성에서 시간초과가 난다. count가 훨씬 좋음!&lt;/p&gt;
&lt;pre id=&quot;code_1746115801616&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n):
    nb = format(n,'b')
    while True:
        n += 1
        if nb.count('1') == format(n,'b').count('1'):
            return n&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;1. 이진수에서 0 제거 &amp;rarr; 제거된 개수 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 길이를 이진수로 변환&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 위 과정 반복&lt;/p&gt;
&lt;pre id=&quot;code_1746115974596&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s):
    cnt_0 = 0
    cnt = 0
    while int(s)&amp;gt;1:
        # 0 제거
        prev = len(s)
        s = s.replace('0','')
        len_s = len(s)
        cnt_0 += (prev-len_s)
        # 변환
        s = format(len_s,'b')
        cnt += 1
    
    return [cnt, cnt_0]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;- (큰 값 x 작은 값)이 되도록&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746116146294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(A,B):
    return sum([i*j for i,j in zip(sorted(A),sorted(B,reverse=True))])&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;1. 시간 초과 &amp;rarr; 정확성:&amp;nbsp;82.4&lt;/p&gt;
&lt;pre id=&quot;code_1746117107822&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(k, tangerine):
    dic={}
    answer = 0
    for t in tangerine:
        dic[t] = dic.get(t,0) + 1
        
        if dic[t] &amp;gt; k:
            return 1
    while k&amp;gt;0:
        max_key = max(dic, key=dic.get)
        k -= dic[max_key]
        del dic[max_key]
        answer += 1
        if k &amp;lt;=0:
            return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 정렬을 미리 해주니 모두 통과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 위 코드에서는 max를 탐색과정을 반복하니 시간 초과가 뜬 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1746117663710&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(k, tangerine):
    dic={}

    for t in tangerine:
        dic[t] = dic.get(t,0) + 1
        
        if dic[t] &amp;gt; k:
            return 1
    
    lst = sorted(list(dic.values()), reverse=True)
    answer, cnt = 0, 0
    for l in lst:
        answer += 1
        cnt += l
        
        if cnt &amp;gt;= k:
            return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;피보나치&lt;/b&gt; 형태는 위에서 한 번 다룸&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 문제는 이 형태로 푸는 것이 가장 편한 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1746118157699&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n):
    arr = [0]*(n+1)
    arr[0], arr[1] = 0, 1
    for i in range(2, n+1):
        arr[i] = arr[i-1]+arr[i-2]   
    return arr[n]%1234567&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;카펫&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746125073340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(brown, yellow):
    x_y = (brown-4)//2
    # 한줄일 경우 : x+y = yellow+1
    if x_y == yellow+1:
        return [yellow+2,3]
    
    # 두줄 이상일 경우 : xy = yellow
    else: 
        for x in range(2, x_y//2+1):
            if (x*(x_y-x)==yellow):
                return [x_y-x+2, x+2]&lt;/code&gt;&lt;/pre&gt;</description>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/41</guid>
      <comments>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level2-%EC%A0%95%EB%8B%B5%EB%A5%A0-70-%EC%9D%B4%EC%83%81#entry41comment</comments>
      <pubDate>Fri, 2 May 2025 03:15:31 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 level.1] 기출문제</title>
      <link>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Lv1-%EC%97%B0%EC%8A%B5</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[PCCE&amp;nbsp;기출문제]&amp;nbsp;9번&amp;nbsp;/&amp;nbsp;이웃한&amp;nbsp;칸&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746005459222&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(board, h, w):
    answer = 0
    # 현재 색
    cur_color = board[h][w]
    dx = [0, 0, -1, 1]
    dy = [-1, 1, 0, 0]
    for i in range(4):
        nh, nw = h+dx[i], w+dy[i]
        if 0 &amp;lt;= nh &amp;lt; len(board) and 0 &amp;lt;= nw &amp;lt; len(board[0]):
            if board[nh][nw] == cur_color:
                answer+=1
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[PCCE&amp;nbsp;기출문제]&amp;nbsp;9번&amp;nbsp;/&amp;nbsp;지폐&amp;nbsp;접기&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;- 지폐의 길이가 작은 쪽 &amp;gt; 지갑의 작은 쪽 , &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;지폐의&lt;/span&gt; 길이가 큰 쪽 &amp;gt; 지갑의 큰 쪽이면 &lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;지폐의&lt;span&gt; &lt;/span&gt;&lt;/span&gt;큰 쪽을 반 나누기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746005588267&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(wallet, bill):
    answer = 0
    while (min(bill)&amp;gt;min(wallet)) or (max(bill)&amp;gt;max(wallet)):
        if bill[0]&amp;gt;bill[1]:
            bill[0] = bill[0]//2
        elif bill[0]&amp;lt;bill[1]:
            bill[1] = bill[1]//2
        answer += 1
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[1차] 비밀지도&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;- 첫 if 문까지 : 10진수 &amp;rarr; 2진수 변경 format(10진수,'b')&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 길이가 짧은 경우 앞에 '0'을 붙여줘야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다음 for문 : 비교해서 모두 공백인 경우&lt;/p&gt;
&lt;pre id=&quot;code_1746008949249&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n, arr1, arr2):
    lenmap = len(format(max(arr1+arr2), 'b'))
    answer = []
    for a1, a2 in zip(arr1, arr2):
        a1 = format(a1,'b')
        a2 = format(a2,'b')
        if (len(a1) != lenmap) | (len(a2) != lenmap):
            a1 = '0'*(lenmap-len(a1)) + a1
            a2 = '0'*(lenmap-len(a2)) + a2
        
        row = ''
        for idx in range(len(a1)):
            if (a1[idx]=='0') and (a2[idx]=='0'):
                row += ' '
            else:
                row += '#'
        answer.append(row)
        
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[PCCE&amp;nbsp;기출문제]&amp;nbsp;10번&amp;nbsp;/&amp;nbsp;데이터&amp;nbsp;분석&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;- 비교 기준, 정렬 기준 인덱스 구하고&amp;nbsp;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746010198938&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(data, ext, val_ext, sort_by):
    val = ['code','date','maximum','remain']
    val_idx = val.index(ext)
    sort_by_idx = val.index(sort_by)
    
    answer = []
    for d in data:
        if d[val_idx] &amp;lt; val_ext:
            answer.append(d)
    
    answer.sort(key = lambda x: x[sort_by_idx])
    
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[PCCE&amp;nbsp;기출문제]&amp;nbsp;10번&amp;nbsp;/&amp;nbsp;공원&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[GPT 풀이,,]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- all( ) 함수로 사이즈 안의 모든 좌표가 '-1' 일 경우에만 size를 리턴&lt;/p&gt;
&lt;pre id=&quot;code_1746080888729&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(mats, park):
    n, m = len(park), len(park[0])
    mats.sort(reverse=True)  # 큰 돗자리부터 시도

    for size in mats:
        for i in range(n - size + 1):
            for j in range(m - size + 1):
                if all(park[x][y] == '-1' for x in range(i, i+size) for y in range(j, j+size)):
                    return size
    return -1&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;[PCCP&amp;nbsp;기출문제]&amp;nbsp;1번&amp;nbsp;/&amp;nbsp;붕대&amp;nbsp;감기&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;/p&gt;
&lt;pre id=&quot;code_1746014977513&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(bandage, health, attacks):
    # 최대 시간
    curr_h = health
    all_time = attacks[-1][0]
    cnt = 0
    for time in range(all_time+1):
        # 공격 받을때
        if time == attacks[0][0]:
            minus = attacks.pop(0)
            curr_h -= minus[1]
            cnt = 0
        # 공격 없을때
        else:
            # 기준보다 작으면 채우기
            if curr_h &amp;lt; health:
                curr_h += bandage[1]
                cnt += 1
                if cnt == bandage[0]:
                    curr_h += bandage[2]
                    cnt = 0
            # 기준 넘으면 가만히
            else:
                curr_h = health
                
        if curr_h &amp;lt;= 0:
            return -1
        # 0이하로 떨어지면 return
        
    return curr_h&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;택배 상자 꺼내기&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 코드]&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 풀긴 풀었는데 왜 전부 맞춘건지 모르겠다..&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;간단하게 풀이를 적어보면&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 고르는 택배가 있는 층 구하기&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 총 몇층까지 택배가 쌓여있는지 구하기&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 2-1. 마지막 층에 남는게 없으면 : return&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 2-2. 마지막 층에 짜투리가 있으면 : [ 1 1 0 0 0 ] 이런식으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;마지막 층만 리스트&lt;/b&gt;를 만들기&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;홀수 층이면 왼쪽부터 채우고, 짝수 층이면 오른쪽 부터 채우고&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;고르는 택배&lt;/b&gt;가 있는 위치 정하기 (왼쪽부터)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;홀수 층이면&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;왼쪽부터 나머지 그대로, 짝수 층이면 w+1 빼기 나머지&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;4. 위에서 구한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;마지막 층 리스트&lt;/b&gt;에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;고르는 택배 위치&lt;/b&gt;가 0인지, 1인지에 따라 return&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1746091179294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n, w, num):
    # 고르는 택배가 몇 층에 있는지
    person_floor = num//w if num%w==0 else (num//w)+1
    
    # 총 몇 층인지
    if n%w==0: 
        floor = n//w
        return (floor-person_floor)+1 #층수가 나눠 떨어지면 return
    else: # 나머지가 있으면
        floor = (n//w)+1
        upper_floor = [0 for _ in range(w)]
        if floor%2 != 0: # 왼쪽부터 채우기
            upper_floor[:n%w] = [1]*(n%w)
        else: # 오른쪽부터 채우기
            upper_floor[:n%w] = [1]*(n%w)
            upper_floor = upper_floor[::-1]
    
    # 고르는 택배가 왼쪽부터 몇 번째에 있는지
    if person_floor%2!=0: # 홀수층: 왼부터
        pick_floor = w if num%w==0 else num%w
    else: # 짝수층 : 우부터
        pick_floor = 1 if num%w==0 else (w+1)-(num%w)
    
    if upper_floor[pick_floor-1] == 0: # 맨 위층에는 택배가 없으면
        return floor-person_floor
    elif upper_floor[pick_floor-1] == 1:  # 맨 위층에 택배가 있으면
        return floor-person_floor+1&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS study/자료구조</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/40</guid>
      <comments>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Lv1-%EC%97%B0%EC%8A%B5#entry40comment</comments>
      <pubDate>Wed, 30 Apr 2025 21:14:08 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스 level.1] 정답률 70~74</title>
      <link>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level1-%EC%A0%95%EB%8B%B5%EB%A5%A0-7074</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 가장 가까운 같은 글자&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;- lst.index('a') : 'a'와 같은 원소 인덱스 반환 (젤 첫번째)&lt;/p&gt;
&lt;pre id=&quot;code_1745932025947&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s):
    answer = []
    for idx, alph in enumerate(s):
        try:
            answer.append(list(s[:idx][::-1]).index(alph)+1)
        except:
            answer.append(-1)
    return answer&lt;/code&gt;&lt;/pre&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;pre id=&quot;code_1745932243794&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s):
    answer = []
    d = {}
    
    for idx, alph in enumerate(s):
        if alph not in d:
            answer.append(-1)
        else:
            answer.append(idx-d[alph])
        d[alph] = idx

    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이중 for 문 활용 : 현재 원소와 그 앞 원소들을 비교&lt;/p&gt;
&lt;pre id=&quot;code_1745932427922&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s):
    answerList = [-1]*len(s)
    for i in range(len(s)):
        for j in range(i):
            if (s[i] == s[j]):
                answerList[i] = i-j          
    return answerList&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 시저 암호&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;/p&gt;
&lt;pre id=&quot;code_1745934405472&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s, n):
    answer = []
    for alph in s:
        if alph.isupper(): # 65~90
            if ord(alph)+n &amp;gt; ord('Z'):
                modify = chr(ord('A') + n - (ord('Z')-ord(alph)) - 1)
            else:
                modify = chr(ord(alph)+n)
            
        elif alph.islower(): # 97~122
            if ord(alph)+n &amp;gt; ord('z'):
                modify = chr(ord('a') + n - (ord('z')-ord(alph)) - 1)
            else:
                modify = chr(ord(alph)+n)
        else:
            modify = ' '
        answer.append(modify)
    return ''.join(answer)&lt;/code&gt;&lt;/pre&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1745934418558&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s, n):
    s = list(s)
    
    for idx in range(len(s)):
        if s[idx].isupper():
            s[idx] = chr((ord(s[idx]) + n - ord('A')) % 26 + ord('A'))
        elif s[idx].islower():
            s[idx] = chr((ord(s[idx]) + n - ord('a')) % 26 + ord('a'))
    
    return ''.join(s)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 두 개 뽑아서 더하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745935915868&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(numbers):
    all_sum = []
    for idx in range(len(numbers)):
        all_sum.extend(numbers[idx]+n for n in numbers[idx+1:])
    return sorted(set(all_sum))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. K번째 수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745936545363&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(array, commands):
    answer = []
    for problems in commands:
        problems_array = array[problems[0]-1 : problems[1]]
        problems_array = sorted(problems_array)
        answer.append(problems_array[problems[2]-1])
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[다른 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745936058098&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(array, commands):
    answer = []
    for c in commands:
        arr = array[c[0]-1:c[1]]
        arr.sort()
        answer.append(arr[c[2]-1])
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 숫자 문자열과 영단어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[내 풀이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1745937163152&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(s):
    dic = {'zero':0,'one':1,'two':2,'three':3,'four':4,'five':5,
          'six':6,'seven':7,'eight':8,'nine':9}
    for d in dic:
        s = s.replace(d,str(dic[d]))
    return int(s)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS study/자료구조</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/38</guid>
      <comments>https://yeonjins.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level1-%EC%A0%95%EB%8B%B5%EB%A5%A0-7074#entry38comment</comments>
      <pubDate>Tue, 29 Apr 2025 23:50:37 +0900</pubDate>
    </item>
    <item>
      <title>에어비앤비 호스트 가입 추천인 등록 (4만원) 링크</title>
      <link>https://yeonjins.tistory.com/entry/%EC%97%90%EC%96%B4%EB%B9%84%EC%95%A4%EB%B9%84-%ED%98%B8%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9E%85-%EC%B6%94%EC%B2%9C%EC%9D%B8-%EB%93%B1%EB%A1%9D-4%EB%A7%8C%EC%9B%90-%EB%A7%81%ED%81%AC</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;에어비앤비를&amp;nbsp;열심히&amp;nbsp;운영중인데&amp;nbsp;첫&amp;nbsp;호스트를&amp;nbsp;가입하려고&amp;nbsp;하는&amp;nbsp;사람에게&amp;nbsp;추천하면&amp;nbsp;&lt;b&gt;가입자&lt;/b&gt;와&amp;nbsp;&lt;b&gt;추천인&lt;/b&gt; 모두&amp;nbsp;추가 금액을 받을&amp;nbsp;수&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;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;에어비앤비&amp;nbsp;호스트&amp;nbsp;추천&amp;nbsp;링크&amp;nbsp;아래&amp;nbsp;남겨둡니다!&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.airbnb.co.kr/r/247d762&quot;&gt;http://www.airbnb.co.kr/r/247d762&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;4만원&amp;nbsp;받아가세요! &lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;위&amp;nbsp;링크를&amp;nbsp;통해&amp;nbsp;&lt;b&gt;호스트,&amp;nbsp;숙소를&amp;nbsp;등록&lt;/b&gt;하고 &lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;호스트&amp;nbsp;등록&amp;nbsp;후&amp;nbsp;90일&amp;nbsp;내로&amp;nbsp;예약이&amp;nbsp;되어&amp;nbsp;&lt;b&gt;첫&amp;nbsp;숙박&amp;nbsp;완료&lt;/b&gt;&amp;nbsp;후&amp;nbsp;14일이&amp;nbsp;지나면 &lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;&amp;nbsp;보너스가 계정으로 지급된다고 합니다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크를 통해서 가입자는 4만원을 받으실 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;+ 추가로 알게된 정보인데 첫 예약때 숙박일수 상관없이 한화 13만원 이상 (미화 100달러) 예약건에만 지급된다고 합니다. &lt;br /&gt;​ &lt;br /&gt;&lt;br /&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;에어비앤비&amp;nbsp;호스트&amp;nbsp;추천&amp;nbsp;링크 &lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.airbnb.co.kr/r/247d762&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://www.airbnb.co.kr/r/247d762&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736010749183&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;에어비앤비 호스팅을 통해 수익을 창출할 수 있도록 Anna님이 초대하셨습니다&quot; data-og-description=&quot;에어비앤비에서는 신뢰할 수 있는 게스트를 만나고, 안전하게 대금을 수령하며, 편안한 마음으로 호스팅을 즐길 수 있습니다. 호스팅을 통해 얻을 수 있는 수익을 알아보세요.&quot; data-og-host=&quot;www.airbnb.co.kr&quot; data-og-source-url=&quot;http://www.airbnb.co.kr/r/247d762&quot; data-og-url=&quot;https://www.airbnb.co.kr/r/247d762&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/W3cvu/hyXWrSzn5G/sYl5Ja3XPiPFGXiwMjYMD0/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=493_76_763_161,https://scrap.kakaocdn.net/dn/tFWlp/hyXWAopz51/juuWkJsXWQC8jLTLgVVE11/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=493_76_763_161,https://scrap.kakaocdn.net/dn/JkVh2/hyXWsDVtLD/sTtR3yBym7HUypgmkyTatK/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=489_90_554_161&quot;&gt;&lt;a href=&quot;http://www.airbnb.co.kr/r/247d762&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://www.airbnb.co.kr/r/247d762&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/W3cvu/hyXWrSzn5G/sYl5Ja3XPiPFGXiwMjYMD0/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=493_76_763_161,https://scrap.kakaocdn.net/dn/tFWlp/hyXWAopz51/juuWkJsXWQC8jLTLgVVE11/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=493_76_763_161,https://scrap.kakaocdn.net/dn/JkVh2/hyXWsDVtLD/sTtR3yBym7HUypgmkyTatK/img.jpg?width=1200&amp;amp;height=600&amp;amp;face=489_90_554_161');&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;에어비앤비 호스팅을 통해 수익을 창출할 수 있도록 Anna님이 초대하셨습니다&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;www.airbnb.co.kr&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>숙박업</category>
      <category>숙박업 추천인</category>
      <category>에어비앤비</category>
      <category>에어비앤비 추천인</category>
      <category>에어비앤비 호스트</category>
      <category>에어비앤비 호스트등록</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/37</guid>
      <comments>https://yeonjins.tistory.com/entry/%EC%97%90%EC%96%B4%EB%B9%84%EC%95%A4%EB%B9%84-%ED%98%B8%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9E%85-%EC%B6%94%EC%B2%9C%EC%9D%B8-%EB%93%B1%EB%A1%9D-4%EB%A7%8C%EC%9B%90-%EB%A7%81%ED%81%AC#entry37comment</comments>
      <pubDate>Sun, 5 Jan 2025 02:15:46 +0900</pubDate>
    </item>
    <item>
      <title>ValueError: The following `model_kwargs` are not used by the model: ['image_sizes'] (note: typos in the generate arguments will also show up in this list) huggingface llava 문제 해결</title>
      <link>https://yeonjins.tistory.com/entry/ValueError-The-following-modelkwargs-are-not-used-by-the-model-imagesizes-note-typos-in-the-generate-arguments-will-also-show-up-in-this-list-huggingface-llava-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;허깅페이스에서 오피셜 라마 경로 &lt;b&gt;llava-hf/llava-v1.6-vicuna-7b-hf&lt;/b&gt; 를 사용하는데 model generate 중에 오류가 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;ValueError: The following `model_kwargs` are not used by the model: ['image_sizes'] (note: typos in the generate arguments will also show up in this list)&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;해결방법은 2가지인 것 같다.&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 첫 번째는 아래 링크에서 확인하자.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/haotian-liu/LLaVA/issues/1131&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/haotian-liu/LLaVA/issues/1131&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하자면 llava-hf에서 제공하는 경로 말고, &lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;liuhaotian에서 제공하는 모델을 사용하라고 한다. (llava 모델 경로에 버그가 있다나)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;하지만 나는... 논문에서 말하는 실험 환경과 똑같이 세팅해야 했기에(핑계) 그리고 이미 모델을 로컬로 다운받아왔기 때문에 기다림의 인내심이 바닥났다. 그래서 새로 다운받을 수 없었다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 순차적으로 해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 모델이 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;['image_sizes']를 받지 않는다는 말이니 직접 삭제했다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, processor를 통해 만든 값(모델의 인풋으로 들어갈 값)에서 image_sizes 키에 해당하는 부분을 삭제했다.&lt;/p&gt;
&lt;pre id=&quot;code_1730287171412&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inputs = processor(images=image1, text=text_prompt, return_tensors=&quot;pt&quot;).to(&quot;cuda:0&quot;)
for k,v in inputs.items():
    print(k,v.shape)
    
input_ids torch.Size([1, 38])
attention_mask torch.Size([1, 38])
pixel_values torch.Size([1, 5, 3, 336, 336])
image_sizes torch.Size([1, 2])

del inputs['image_sizes']&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;위 문제를 해결하니 다음 오류가 났다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;RuntimeError:&amp;nbsp;Expected&amp;nbsp;3D&amp;nbsp;(unbatched)&amp;nbsp;or&amp;nbsp;4D&amp;nbsp;(batched)&amp;nbsp;input&amp;nbsp;to&amp;nbsp;conv2d,&amp;nbsp;but&amp;nbsp;got&amp;nbsp;input&amp;nbsp;of&amp;nbsp;size:&amp;nbsp;[1,&amp;nbsp;5,&amp;nbsp;3,&amp;nbsp;336,&amp;nbsp;336]&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;따라서 직접 패키지 경로로 들어가 수정하였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로는 대충 이렇다. 아마 거의 다들 비슷할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;.../miniconda3/envs/yeonjin/lib/python3.8/site-packages/transformers/models/llava_next&lt;b&gt;/image_processing_llava_next.py&lt;/b&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;확인해보니 get_image_patches 함수 마지막 부분에 pathes를 더해주는 부분에서 4가 더해지는 것을 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 patches 를 빼주고, &lt;b&gt;resized_original_image만 출력할 수 있게&lt;/b&gt; 바꿔주었다. (그냥 return만 바꿈..)&lt;/p&gt;
&lt;pre id=&quot;code_1730287666627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;resized_original_image = resize(
    image,
    size=size,
    resample=resample,
    data_format=data_format,
    input_data_format=input_data_format,
)
print('### ---- patches 개수 확인 &amp;gt;&amp;gt; ', len(patches))

image_patches = [resized_original_image] + patches

return [resized_original_image]   # &amp;lt;- image_patches를 바꾼 것임&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;3) 마지막으로 pixel_values 차원만 수정해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[1, 1, 3, 336, 336] &amp;rarr; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[1, 3, 336, 336]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; &lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730288108436&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inputs['pixel_values']=inputs['pixel_values'][0]&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;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;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qqlLT/btsKq1eZlL7/qyfNyspIcDSJJN1VkeQxTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qqlLT/btsKq1eZlL7/qyfNyspIcDSJJN1VkeQxTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qqlLT/btsKq1eZlL7/qyfNyspIcDSJJN1VkeQxTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqqlLT%2FbtsKq1eZlL7%2FqyfNyspIcDSJJN1VkeQxTK%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;208&quot; height=&quot;182&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;USER:&amp;nbsp; &lt;/b&gt;&lt;br /&gt;&lt;b&gt;What&amp;nbsp;is&amp;nbsp;shown&amp;nbsp;in&amp;nbsp;this&amp;nbsp;image?&amp;nbsp;ASSISTANT:&lt;/b&gt;&amp;nbsp;The&amp;nbsp;image&amp;nbsp;appears&amp;nbsp;to&amp;nbsp;be&amp;nbsp;a&amp;nbsp;scatter&amp;nbsp;plot&amp;nbsp;or&amp;nbsp;a&amp;nbsp;heat&amp;nbsp;map&amp;nbsp;that&amp;nbsp;compares&amp;nbsp;the&amp;nbsp;performance&amp;nbsp;of&amp;nbsp;different&amp;nbsp;models&amp;nbsp;or&amp;nbsp;algorithms&amp;nbsp;on&amp;nbsp;a&amp;nbsp;task.&amp;nbsp;The&amp;nbsp;x-axis&amp;nbsp;represents&amp;nbsp;different&amp;nbsp;models&amp;nbsp;or&amp;nbsp;algorithms,&amp;nbsp;and&amp;nbsp;the&amp;nbsp;y-axis&amp;nbsp;represents&amp;nbsp;some&amp;nbsp;sort&amp;nbsp;of&amp;nbsp;performance&amp;nbsp;metric,&amp;nbsp;which&amp;nbsp;could&amp;nbsp;be&amp;nbsp;accuracy,&amp;nbsp;F1&amp;nbsp;score,&amp;nbsp;or&amp;nbsp;another&amp;nbsp;evaluation&amp;nbsp;metric. &lt;br /&gt;&lt;br /&gt;Each&amp;nbsp;point&amp;nbsp;on&amp;nbsp;the&amp;nbsp;plot&amp;nbsp;represents&amp;nbsp;the&amp;nbsp;performance&amp;nbsp;of&amp;nbsp;a&amp;nbsp;specific&amp;nbsp;model&amp;nbsp;or&amp;nbsp;algorithm&amp;nbsp;on&amp;nbsp;the&amp;nbsp;task.&amp;nbsp;The&amp;nbsp;color&amp;nbsp;intensity&amp;nbsp;indicates&amp;nbsp;the&amp;nbsp;level&amp;nbsp;of&amp;nbsp;performance,&amp;nbsp;with&amp;nbsp;warmer&amp;nbsp;colors&amp;nbsp;(reds&amp;nbsp;and&amp;nbsp;yellows)&amp;nbsp;suggesting&amp;nbsp;better&amp;nbsp;performance&amp;nbsp;and&amp;nbsp;cooler&amp;nbsp;colors&amp;nbsp;(blues)&amp;nbsp;suggesting&amp;nbsp;worse&amp;nbsp;performance.&lt;/p&gt;</description>
      <category>Life hack</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/36</guid>
      <comments>https://yeonjins.tistory.com/entry/ValueError-The-following-modelkwargs-are-not-used-by-the-model-imagesizes-note-typos-in-the-generate-arguments-will-also-show-up-in-this-list-huggingface-llava-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0#entry36comment</comments>
      <pubDate>Wed, 30 Oct 2024 20:38:00 +0900</pubDate>
    </item>
    <item>
      <title>Warning: Permanently added 'node000' (000) to the list of known hosts. 오류 해결</title>
      <link>https://yeonjins.tistory.com/entry/Warning-Permanently-added-node000-000-to-the-list-of-known-hosts-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: color(srgb 1 1 1); color: color(srgb 0.120353 0.120353 0.120353); text-align: start;&quot;&gt;우리 학과 서버는 SLURM으로 GPU를 할당받아 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: color(srgb 0.120353 0.120353 0.120353);&quot;&gt;&lt;span style=&quot;background-color: color(srgb 1 1 1);&quot;&gt; &lt;i&gt;SSH [NODELIST(REASON)] &lt;/i&gt;코드로 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: color(srgb 0.120353 0.120353 0.120353);&quot;&gt;&lt;span style=&quot;background-color: color(srgb 1 1 1);&quot;&gt;내가 할당받은 노드에 접속하는데 처음에 아래와 같은 에러가 났다.&lt;/span&gt;&lt;/span&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;b&gt;&lt;i&gt;Warning: Permanently added 'node00' (000) to the list of known hosts.&lt;/i&gt;&lt;/b&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;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;SSH로 인스턴스 연결을 시도할 때 나타나는 오류인데... &amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;Windows용으로 컴파일된 OpenSSH 클라이언트가 known_hosts 파일을 확인하지 않기 때문에 발생한다고 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;해결방법은 ~/.ssh/config 파일에 아래 코드를 넣으면 된다.&lt;br /&gt;UserKnownHostsFile ~/.ssh/known_hosts&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life hack</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/35</guid>
      <comments>https://yeonjins.tistory.com/entry/Warning-Permanently-added-node000-000-to-the-list-of-known-hosts-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0#entry35comment</comments>
      <pubDate>Mon, 30 Sep 2024 23:01:20 +0900</pubDate>
    </item>
    <item>
      <title>백준 기초 (파이썬)</title>
      <link>https://yeonjins.tistory.com/entry/%EB%B0%B1%EC%A4%80-%EA%B8%B0%EC%B4%88-%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;15552번&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input() 말고 map(int,sys.stdin.readline().split()) 이렇게 받으면 더 빠름&lt;/p&gt;
&lt;pre id=&quot;code_1726734377116&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys

N = int(sys.stdin.readline())

for _ in range(N):
  a, b = map(int,sys.stdin.readline().split())
  print(a+b)&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;10989번 수 정렬하기 3&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 sort를 사용하면 메모리초과 뜸&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;int의 크기 = 4byte&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;최대 10,000,000라고 가정하면 &lt;/span&gt;40,000,000byte = 40MB 임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 8MB로 메모리 제한을 줌&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;a href=&quot;https://kill-xxx.tistory.com/entry/python-%EA%B3%84%EC%88%98%EC%A0%95%EB%A0%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kill-xxx.tistory.com/entry/python-%EA%B3%84%EC%88%98%EC%A0%95%EB%A0%AC&lt;/a&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;p data-ke-size=&quot;size16&quot;&gt;1. 원소가 모두 0으로 이루어진 리스트 생성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 숫자가 들어오면 리스트에서 해당 인덱스(=숫자)에 +1을 해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 프린트 : 리스트의 원소가 0이면 해당 인덱스 숫자는 없는 것이므로 넘어가고, 0이 아닐경우 해당 숫자 개수만큼 인덱스를 출력함&lt;/p&gt;
&lt;pre id=&quot;code_1726735652555&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
N = int(sys.stdin.readline())
lst=[0]*10001

for _ in range(N):
    lst[int(sys.stdin.readline())]+=1

for idx in range(len(lst)):
    if lst[idx]!=0:
        for _ in range(lst[idx]):
            print(idx)&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;2577번&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;숫자의 개수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 계수 정렬 방법으로 풀었음&lt;/p&gt;
&lt;pre id=&quot;code_1726736634545&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
n=1
for _ in range(3):
    n*=int(sys.stdin.readline())


lst=[0]*10
for idx in str(n):
  lst[int(idx)]+=1

for i in range(10):
  print(lst[i])&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;다른 방법&lt;/p&gt;
&lt;pre id=&quot;code_1726736814994&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
n=1
for _ in range(3):
    n*=int(sys.stdin.readline())


result = list(str(n))
for i in range(0,10):
    count = 0
    for num in result:
        if i == int(num):
            count += 1
    print(count)&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;둘 다 메모리, 시간이 똑같음&lt;/p&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스택, 큐&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1158번 요세푸스 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 문제인데 3달전에는 왜 이렇게 오래걸렸는지 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 기본 리스트를 사용하면 런타임에러가 나서 deque를 꼭 사용해야 한다.&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_1726931855483&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque
N, K = map(int,input().split())
lst=deque([i+1 for i in range(N)])

s=1

print('&amp;lt;',end='')
while lst:
  if s%K==0:
    if len(lst)==1:
        print(f'{lst.popleft()}&amp;gt;')
    else:
      print(f'{lst.popleft()}, ', end='')
  else:
    lst.append(lst.popleft())
  s+=1&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;정석(?) 풀이&lt;/p&gt;
&lt;pre id=&quot;code_1726931903662&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque

N, k = map(int, input().split())

lst = deque([i+1 for i in range(N)])
answer = []

while lst:
    for _ in range(k-1):
        lst.append(lst.popleft())
    answer.append(lst.popleft())
print(str(answer).replace('[', '&amp;lt;').replace(']', '&amp;gt;'))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9012번 괄호&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;내 풀이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;w.replace 를 w에 안넣어줘서 자꾸 에러가 났다.&lt;/p&gt;
&lt;pre id=&quot;code_1726933152569&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N = int(input())

for _ in range(N):
  w = input()
  
  # 홀수개면 NO
  if len(w)%2 != 0:
    print('NO')
  else:
    for _ in range(len(w)//2):
      w = w.replace('()','')
    if w != '':
      print('NO')
    else:
      print('YES')&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;정석(?)풀이&lt;/p&gt;
&lt;pre id=&quot;code_1726933228723&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
num = int(sys.stdin.readline())

for _ in range(num):
    inp = sys.stdin.readline().rstrip()  # 마지막 \n 제거
    
    while '()' in inp:
        inp = inp.replace('()','')
    if inp:
        print('NO')
    else:
        print('YES')&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;9093번 단어 뒤집기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 옛날 풀이가 훨씬 간결한데 걸린 시간은 3배가 넘는다.&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_1726933575736&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N = int(input())

for _ in range(N):
  sent = input().split()
  result=''
  for i in sent:
    result += i[::-1] + ' '
  print(result)&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;옛날 풀이&lt;/p&gt;
&lt;pre id=&quot;code_1726933603676&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n = int(input())

for _ in range(n):
    a = input()
    answer = ' '.join([i[::-1] for i in a.split()])
    print(answer)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;DFS / BFS&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1260번 DFS와 BFS&lt;/h2&gt;
&lt;pre id=&quot;code_1726936817104&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N,M,V = map(int,input().split())
graph = [[] for _ in range(N+1)]
for _ in range(M):
  a, b = map(int,input().split())
  graph[a].append(b)
  graph[b].append(a)

# 그래프 내에서 작은수부터 탐색하도록
for i in graph:
  i.sort()

# DFS 코드
visited=[0]*(N+1)
def dfs(graph, v, visited):
  print(v, end=' ')
  visited[v]=True
  
  for i in graph[v]:
    if visited[i] != True:
      dfs(graph, i, visited)
dfs(graph, V, visited)
print()

# BFS 코드
from collections import deque
visited=[0]*(N+1)
def bfs(graph, start, visited):
  cur = deque([start])
  visited[start]=True
  while cur:
    v = cur.popleft()
    print(v, end=' ')
    for i in graph[v]:
      if visited[i] != True:
        cur.append(i)
        visited[i]=True
bfs(graph, V, visited)&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;좀 더 깔끔한 코드를 찾았다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 코드는 292ms 이 코드는 60ms이다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보니까 내 코드에서 input() 을 sys 로 변경하니 60ms가 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 잊지 말아야겠다 &lt;b&gt;sys.stdin.readline().split()&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1726939867192&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
from collections import deque

# 입력
n, m, v = map(int, sys.stdin.readline().split())
graph = [[] for _ in range(n+1)]
visited = [False] * (n + 1)
# 인접리스트 만들기
for _ in range(m):
    a, b = map(int, sys.stdin.readline().split())
    graph[a].append(b)
    graph[b].append(a)
# sorting
for i in range(1, n+1):
    graph[i].sort()
    
def dfs(n):
    print(n, end=' ')
    visited[n] = True
    for i in graph[n]:
        if not visited[i]:
            dfs(i)

def bfs(n):
    visited[n] = True
    queue = deque([n])
    while queue:
        v = queue.popleft()
        print(v, end= ' ')
        for i in graph[v]:
            if not visited[i]:
                queue.append(i)
                visited[i] = True


dfs(v)
visited = [False] * (n + 1)
print()
bfs(v)&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;p data-ke-size=&quot;size16&quot;&gt;아래는 런타임에러가 나는디... 왜?&lt;/p&gt;
&lt;pre id=&quot;code_1726939666481&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;N,M,V = map(int,input().split())
graph = [[] for _ in range(N+1)]

for _ in range(M):
  a, b = map(int,input().split())
  graph[a].append(b)
  graph[b].append(a)

for i in graph:
  i.sort()

visited=[False]*(N+1)
def dfs(v):
  print(v, end=' ')
  visited[v]=True
  for i in graph[v]:
    if not visited[i]: #방문하지 않았다면
      dfs(i)
dfs(V)

print('')
from collections import deque
def bfs(v):
  cur = deque([n])
  visited[n]=True
  while cur:
    v = cur.popleft()
    print(v, end=' ')
    for i in graph[v]:
      if not visited[i]: #방문하지 않았다면
        cur.append(i)
        visited[i]=True
        
visited=[False]*(N+1)
bfs(graph, V, visited)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2667번 단지번호붙이기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1012번 유기농배추&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이면 연결된 것이라 하나로 통합&amp;rarr; 이렇게 통합된 지역이 몇 개인지 구하는 문제&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;dfs bfs 문제 나만 어려워..?&amp;nbsp;&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;sys.setrecursionlimit(10000)&lt;/b&gt; 꼭 해주자..&lt;/p&gt;
&lt;pre id=&quot;code_1727016493627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
sys.setrecursionlimit(10000) # 재귀 깊이 설정

for _ in range(int(sys.stdin.readline())):
  M,N,K=map(int,sys.stdin.readline().split())
  graph=[[0]*M for i in range(N)]
  
  for _ in range(K):
    X,Y= map(int,sys.stdin.readline().split())
    graph[Y][X]=1
  
  def dfs(y,x):
    if x&amp;lt;0 or y&amp;lt;0 or x&amp;gt;=M or y&amp;gt;=N:
      return False
    
    if graph[y][x]==1:
      graph[y][x]=0
      dfs(y-1,x)
      dfs(y,x-1)
      dfs(y+1,x)
      dfs(y,x+1)
      return True
    else:
      return False
  
  count=0
  for i in range(N):
    for j in range(M):
      if dfs(i,j)==True:
        count+=1
  
  print(count)&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;이건 너무 잘하신 분 코드 가져온것..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 진짜 너무 못해 ㅜ0ㅠ 때려쳐.. 아니야 계속해...&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727016942382&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
sys.setrecursionlimit(10000) # 재귀 깊이 설정

T = int(sys.stdin.readline())

dx = [-1,1,0,0]
dy = [0,0,-1,1]
def dfs(y,x):
  if x&amp;lt;0 or y&amp;lt;0 or x&amp;gt;=M or y&amp;gt;=N:
    return False

  if graph[y][x]==1:
    graph[y][x]=0
    for i in range(4): #모든 방향 탐색
      dfs(y+dy[i],x+dx[i])      
    return True
  else:
    return False

for _ in range(T):
  M,N,K=map(int,sys.stdin.readline().split())
  graph=[[0]*M for i in range(N)]
  
  for _ in range(K):
    X,Y= map(int,sys.stdin.readline().split())
    graph[Y][X]=1
  
  count=0
  for i in range(N):
    for j in range(M):
      if dfs(i,j)==True:
        count+=1
  
  print(count)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11724번 연결 요소의 개수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1012번과 비슷하게 그래프에서 서로 연결된 부분을 하나로 보고 &amp;rarr; 이렇게 통합된 노드가 몇 개인지 구하는 문제&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;이제는 dfs코드는 그래도 좀 작성할 줄 아는 것 같음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 변형된 건 너무 못해..&lt;/p&gt;
&lt;pre id=&quot;code_1727019207618&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
sys.setrecursionlimit(1000000) # 재귀 깊이 설정

N,M=map(int,sys.stdin.readline().split())
graph=[[] for _ in range(N+1)]
for _ in range(M):
  a,b= map(int,sys.stdin.readline().split())
  graph[a].append(b)
  graph[b].append(a)

visited=[0]*(N+1)
def dfs(v):
  visited[v]+=1
  for i in graph[v]:
    if visited[i]==0:
      dfs(i)

cnt=0
for i in range(1,N+1):
  if visited[i]==0:
    dfs(i)
    cnt+=1  #dfs가 끝날때 +1

print(cnt)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2178 미로탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(N,M) 위치로 가는 가장 빠른 칸 수를 구하는 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지나갈 수 있는 길은 1로 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지나간 길은 순차적으로 더해주는 방법을 사용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1727021831830&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
from collections import deque

N,M=map(int,sys.stdin.readline().split())
graph=[]
for _ in range(N):
  a = list(map(int,sys.stdin.readline().rstrip()))
  graph.append(a)

dx = [-1,1,0,0]
dy = [0,0,1,-1]

def bfs(x,y):
  queue = deque()
  queue.append((x,y))
  while queue:
    x,y=queue.popleft()
    for i in range(4):
      nx, ny = x+dx[i], y+dy[i]
      if nx&amp;lt;0 or ny&amp;lt;0 or nx&amp;gt;=N or ny&amp;gt;=M:
        continue
      if graph[nx][ny]==0:
        continue
      if graph[nx][ny]==1:
        queue.append((nx,ny))
        graph[nx][ny]=graph[x][y]+1
  return graph[N-1][M-1]

print(bfs(0,0))&lt;/code&gt;&lt;/pre&gt;</description>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/34</guid>
      <comments>https://yeonjins.tistory.com/entry/%EB%B0%B1%EC%A4%80-%EA%B8%B0%EC%B4%88-%ED%8C%8C%EC%9D%B4%EC%8D%AC#entry34comment</comments>
      <pubDate>Thu, 19 Sep 2024 20:08:35 +0900</pubDate>
    </item>
    <item>
      <title>CLIP 코드 분해(1) 텍스트 파트</title>
      <link>https://yeonjins.tistory.com/entry/CLIP-%EC%BD%94%EB%93%9C-%EB%B6%84%ED%95%B4</link>
      <description>&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;&lt;a href=&quot;https://huggingface.co/transformers/v4.6.0/_modules/transformers/models/clip/modeling_clip.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://huggingface.co/transformers/v4.6.0/_modules/transformers/models/clip/modeling_clip.html&lt;/a&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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 이번에는 모델의 안쪽 구조도 내가 원하는 방향으로 바꿔보고 싶어 대표적인 모델 중 CLIP 소스코드를 허깅페이스에서 직접 가져와 분석해보았다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;허깅페이스에서 CLIP을 가져와보면 큰 구조는 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;텍스트와 비전 파트 모두 encoder에서 총 11개의 동일한 구조의 레이어를 쌓았다.&lt;/p&gt;
&lt;pre id=&quot;code_1725968633990&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- CLIPModel

    - (text_model): CLIPTextTransformer(
        - (embeddings): token_embedding(49408, 512), position_embedding(77, 512)
        - (encoder): layers 11개
                self_attn
                layer_norm1
                mlp
                layer_norm2
        - (final_layer_norm)
    )
        
    - (vision_model): CLIPVisionTransformer(
        - (embeddings): patch_embedding(Conv2d), position_embedding(50, 768)
        - (pre_layrnorm) 
        - (encoder): layers  11개
                    self_attn
                    layer_norm1
                    mlp
                    layer_norm2
        - (post_layernorm): 
        )
        
    - (visual_projection)
    
    - (text_projection)&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;이 중 텍스트 파트의 코드를 확인해보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 임베딩&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 토큰 임베딩 &lt;/b&gt;: 사전 개수(voca size) 만큼의 임베딩을 생성함. [vocab size, 512]&lt;/h4&gt;
&lt;pre id=&quot;code_1726028595165&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.token_embedding = nn.Embedding(args.vocab_size, embed_dim)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 포지션 임베딩 &lt;/b&gt;: 각 인풋 토큰 위치에 따라 포지션 임베딩을 생성함. 기본 CLIP의 인풋 최대길이는 77.&lt;/h4&gt;
&lt;pre id=&quot;code_1726028639190&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.position_embedding = nn.Embedding(args.max_position_embeddings, embed_dim)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 기타&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1) position_ids&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 0부터 max 개수까지 순서 인덱스 값을 가진 텐서 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: shape : [77]&amp;nbsp; &amp;rarr;&amp;nbsp; &lt;i&gt;expand((1, -1))&lt;/i&gt; &amp;rarr;&amp;nbsp; [1, 77]&lt;/p&gt;
&lt;pre id=&quot;code_1726028805854&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.register_buffer(&quot;position_ids&quot;, torch.arange(args.max_position_embeddings).expand((1, -1)))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[ register_buffer ]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state_dict에 저장되지만 backpropagation을 진행하지 않고, 최적화에 사용하지 않을때 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://aigong.tistory.com/429&quot;&gt;https://aigong.tistory.com/429&lt;/a&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 로컬에 미리 토크나이저를 받아놔서 local_files_only=True 인자를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인풋에 position_ids와 input_embeds가 없을 경우에는&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;1) 각 토큰에 input_ids 에 해당하는 &lt;b&gt;토큰 임베딩&lt;/b&gt;을 사용하고&lt;/p&gt;
&lt;pre id=&quot;code_1726029789440&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inputs_embeds = self.token_embedding(input_ids)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 각 토큰 위치 position_ids 에 해당하는 &lt;b&gt;포지션 임베딩&lt;/b&gt;을 사용하여&lt;/p&gt;
&lt;pre id=&quot;code_1726029807056&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;position_ids = self.position_ids[:, :seq_length]
position_embeddings = self.position_embedding(position_ids)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 둘을 합해 텍스트 임베딩을 내보낸다.&lt;/p&gt;
&lt;pre id=&quot;code_1726026695499&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from torch import nn
import torch
import argparse


class CLIPTextEmbeddings(nn.Module):
    def __init__(self, args):
        super().__init__()
        embed_dim = args.hidden_size

        self.token_embedding = nn.Embedding(args.vocab_size, embed_dim)
        self.position_embedding = nn.Embedding(args.max_position_embeddings, embed_dim)

        # position_ids (1, len position emb) is contiguous in memory and exported when serialized
        self.register_buffer(&quot;position_ids&quot;, torch.arange(args.max_position_embeddings).expand((1, -1)))

    def forward(self, input_ids=None, position_ids=None, inputs_embeds=None):
    	# 토큰 길이
        seq_length = input_ids.shape[-1] if input_ids is not None else inputs_embeds.shape[-2]

        if position_ids is None:
            position_ids = self.position_ids[:, :seq_length]

        if inputs_embeds is None:
            inputs_embeds = self.token_embedding(input_ids)

        position_embeddings = self.position_embedding(position_ids)
        embeddings = inputs_embeds + position_embeddings

        return embeddings&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;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;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 멀티헤드&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;: Transformer 논문의 멀티헤드어텐션 사용함&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1) head_dim&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;임베딩 차원은 텍스트는 512, 이미지는 768이고, 나눠서 계산할 head 개수는 텍스트는 8개, 이미지는 12개임&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 한번에 계산할 head 묶음(head_dim은&amp;nbsp; 모두 64개&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;2) 어텐션을 계산하기 전 Query값을 스케일링 해주기 위한 값을 지정함&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;텍스트 기준으로 &lt;u&gt;head_dim ^ -0.5&lt;/u&gt; = 64 ** -0.5 = 1/8 이 되는 셈이므로 &lt;u&gt;0.125&lt;/u&gt; 를 쿼리에 곱해 스케일링함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1726030892176&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.head_dim = self.embed_dim // self.num_heads # 텍스트 512//8 = 64, 비전 768//12 = 64
# 수치가 정확히 맞는지 확인하기 위해 가정설정문 사용
assert (
            self.head_dim * self.num_heads == self.embed_dim
        ), f&quot;embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`: {self.num_heads}).&quot;
self.scale = self.head_dim ** -0.5
self.dropout = args.attention_dropout&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Query, Key, Value&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어텐션을 계산할 query, key, value 생성&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;텍스트 기준 Lineary의 인풋, 아웃풋 모두 512차원임&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726030934212&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 기타&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) shape 조정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;transpose로 shape 조정할때 원소들의 위치는 변화되지 않고, 접근 인덱스만 변화됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 원소의 위치까지 변화를 주기 위해 contiguous( ) 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[문장개수, 문장길이, 512] &amp;rarr; [문장개수, head개수, 문장길이, head묶음]&lt;/b&gt; 으로 차원을 변경해줌&lt;/p&gt;
&lt;pre id=&quot;code_1726038297816&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def _shape(self, tensor: torch.Tensor, seq_len: int, bsz: int):
        return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous()&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 실행&lt;/b&gt;&lt;/h4&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;어텐션 계산의 흐름은 이 글에서도 설명되겠지만 Query, Key, Value 계산과정의 의미는 아래 Transformer 논문 리뷰에 자세하게 적어놓았다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&quot;&gt;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726137873514&quot; contenteditable=&quot;false&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cjkeWz/hyW22lpF2g/cXy0GWjIUfTqi9Tk8ugT5k/img.png?width=501&amp;amp;height=717&amp;amp;face=0_0_501_717,https://scrap.kakaocdn.net/dn/OCfow/hyW2TPwB1E/wiagZkSzwMYGtWSC0rZK80/img.png?width=501&amp;amp;height=717&amp;amp;face=0_0_501_717,https://scrap.kakaocdn.net/dn/JhA36/hyWZjI67MS/1IFWNva1GdO4hOCk6XKueK/img.png?width=552&amp;amp;height=114&amp;amp;face=0_0_552_114&quot; data-og-url=&quot;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&quot; data-og-source-url=&quot;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&quot; data-og-host=&quot;yeonjins.tistory.com&quot; data-og-description=&quot;2017년 NIPS에서 발표된 Attention Is All You Need는 구글이 낸 논문으로 이를 기반으로 Bert, GPT, VIT 등 자연어뿐만 아니라 이미지에도 적용되는 모델들이 나왔다. 대학원 첫 세미나로 이 논문을 발표하게&quot; data-og-title=&quot;[Paper] Attention Is All You Need(NIPS, 2017)&quot; data-og-type=&quot;article&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&quot; data-source-url=&quot;https://yeonjins.tistory.com/entry/Paper-Attention-Is-All-You-NeedNIPS-2017&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;[Paper] Attention Is All You Need(NIPS, 2017)&lt;/p&gt;
&lt;p style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;2017년 NIPS에서 발표된 Attention Is All You Need는 구글이 낸 논문으로 이를 기반으로 Bert, GPT, VIT 등 자연어뿐만 아니라 이미지에도 적용되는 모델들이 나왔다. 대학원 첫 세미나로 이 논문을 발표하게&lt;/p&gt;
&lt;p style=&quot;color: #909090;&quot; data-ke-size=&quot;size16&quot;&gt;yeonjins.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜스포머 원래 논문에서는 쿼리와 키를 스케일링 해줄때 루트d차원으로 나눴는데 이 부분은 이 글 3-1에서 적용된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 어텐션 계산&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Key, Value&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 shape 조정 후 사용&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;color: #333333; text-align: start;&quot;&gt;문장개수 , 문장길이&lt;span&gt; , 512]&lt;/span&gt;&lt;/span&gt; &amp;rarr;&amp;nbsp; shape 조정 &amp;rarr; [문장개수, 8, &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;문장길이&lt;span&gt; &lt;/span&gt;&lt;/span&gt;, 64]&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;rarr; shape 조정 (proj_shape)&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;rarr;&amp;nbsp; &lt;b&gt;[문장개수 x 8, 문장길이, 64 ]&lt;/b&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;b&gt;Query&lt;/b&gt; 는 스케일링 후 shape 조정&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스케일링 &amp;rarr;&amp;nbsp; [&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;문장개수,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 문장길이, 512] &amp;rarr; shape 조정 &amp;rarr; [문장개수 , 8,&amp;nbsp; 문장길이, 64] &amp;rarr; shape 조정 (proj_shape)&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&amp;rarr;&lt;b&gt; [문장개수 x 8, 문장길이, 64]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726036129115&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bsz, tgt_len, embed_dim = hidden_states.size() #문장개수, 문장길이, 차원512

proj_shape = (bsz * self.num_heads, -1, self.head_dim)


query_states = self.q_proj(hidden_states) * self.scale
query_states = self._shape(query_states, tgt_len, bsz).view(*proj_shape)

key_states = self._shape(self.k_proj(hidden_states), -1, bsz)
key_states = key_states.view(*proj_shape)

value_states = self._shape(self.v_proj(hidden_states), -1, bsz)
value_states = value_states.view(*proj_shape)&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) Query와 Key 행렬곱 : attention weight&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- torch.bmm : [B,&amp;nbsp;N,&amp;nbsp;M]&amp;nbsp;x&amp;nbsp;[B,&amp;nbsp;M,&amp;nbsp;P]&amp;nbsp;=&amp;nbsp;[B,&amp;nbsp;N,&amp;nbsp;P]&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3D텐서가 입력되면 즉, 곱하는 두 행렬 모두 batch 단위일때 행렬곱을 해줌&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서는 문장개수가 batch가 됨&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;따라서 쿼리와 키가 서로 곱해질 수 있도록 transpose를 해줘야함&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Query : [문장개수 x 8, 문장길이, 64]&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Key : &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;[문장개수 x 8, 문장길이, 64] &amp;rarr; [문장개수 x 8, 64, 문장길이]&lt;/span&gt;&lt;/span&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;위 두 값이 torch.bmm 을 거치면 (곱해지면)&amp;nbsp; &amp;rarr; &lt;b&gt;[문장개수 x 8, 문장길이, 문장길이]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726135923881&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;src_len = key_states.size(1)  # [문장개수 x 8, 문장길이, 64 ] -&amp;gt; 문장길이
attn_weights = torch.bmm(query_states, key_states.transpose(1, 2)) #3차원끼리 행렬곱

# 차원이 맞는지 확인
if attn_weights.size() != (bsz * self.num_heads, tgt_len, src_len):
        raise ValueError(
            f&quot;Attention weights should be of size {(bsz * self.num_heads, tgt_len, src_len)}, but is {attn_weights.size()}&quot;
        )&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;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3) 여기서 attention mask가 적용됨&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726136922893&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if causal_attention_mask is not None:
    if causal_attention_mask.size() != (bsz, 1, tgt_len, src_len):
        raise ValueError(
            f&quot;Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is {causal_attention_mask.size()}&quot;
        )
    attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + causal_attention_mask
    attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len)

if attention_mask is not None:
    if attention_mask.size() != (bsz, 1, tgt_len, src_len):
        raise ValueError(
            f&quot;Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is {causal_attention_mask.size()}&quot;
        )
    attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + attention_mask
    attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len)&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4) Softmax&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Softmamx를 거쳐 attention score를 생성함&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 쿼리와 키가 곱해지면 둘의 유사한 정도가 나오고, 소프트맥스 함수를 거쳐 0~1 사이로 정규화가 되어 유사도가 확률로 나타남&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 쿼리 하나당 키의 유사도가 구해지고, 쿼리 하나에 따른 키의 확률들의 합은 1이 됨&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;[????]&lt;/b&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;dropout&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; [문장개수, 문장길이, 512]&lt;/p&gt;
&lt;pre id=&quot;code_1726136693475&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;attn_weights = F.softmax(attn_weights, dim=-1)

if output_attentions:
    # True이면 위에서 query, key 곱한 후 softmax를 취한 attentnion score를 사용할지 정함
    # 코드에는 attention weight의 gradient를 유지하기 위한 것이라고 설명되어 있음
    attn_weights_reshaped = attn_weights.view(bsz, self.num_heads, tgt_len, src_len)
    attn_weights = attn_weights_reshaped.view(bsz * self.num_heads, tgt_len, src_len)
else:
    attn_weights_reshaped = None

attn_probs = F.dropout(attn_weights, p=self.dropout, training=self.training)&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;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5) attention score와 Value의 행렬곱&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Attention score : [문장개수 x 8, 문장길이, 문장길이] ???&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Value :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; [문장개수 x 8, 문장길이, 64]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&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;color: #333333; text-align: start;&quot;&gt;위 두 값이 torch.bmm 을 거치면 (곱해지면)&amp;nbsp; &amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;[문장개수 x 8, 문장길이, 64]&amp;nbsp; &lt;/b&gt;???&lt;/p&gt;
&lt;pre id=&quot;code_1726137303214&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;attn_output = torch.bmm(attn_probs, value_states)

# 차원 확인
if attn_output.size() != (bsz * self.num_heads, tgt_len, self.head_dim):
        raise ValueError(
            f&quot;`attn_output` should be of size {(bsz, self.num_heads, tgt_len, self.head_dim)}, but is {attn_output.size()}&quot;
        )&lt;/code&gt;&lt;/pre&gt;
&lt;p 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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6) Output shape 변경&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[문장개수 x 8, 문장길이, 64]&lt;span&gt; &amp;rarr; [문장개수, 8, 문장길이, 64] &amp;rarr; &amp;nbsp;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[문장개수, 문장길이, 8, 64]&lt;span&gt; &amp;rarr; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;[문장개수,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;문장길이, 512]&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&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;pre id=&quot;code_1726137558382&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# attn_output : [문장개수 x 8, 문장길이, 64]
attn_output = attn_output.view(bsz, self.num_heads, tgt_len, self.head_dim)  # [문장개수, 8, 문장길이, 64]
attn_output = attn_output.transpose(1, 2)   # [문장개수, 문장길이, 8, 64]
attn_output = attn_output.reshape(bsz, tgt_len, embed_dim)  # [문장개수, 문장길이, 512] 

attn_output = self.out_proj(attn_output)&lt;/code&gt;&lt;/pre&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;전체 코드&lt;/p&gt;
&lt;pre id=&quot;code_1726142119515&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CLIPAttention(nn.Module):
    # 'Attention Is All You Need' 의 멀티헤드 어텐션 사용함

    def __init__(self, args):
        super().__init__()
        self.embed_dim = args.hidden_size
        self.num_heads = args.num_attention_heads
        self.head_dim = self.embed_dim // self.num_heads # 텍스트 512//8 = 64, 비전 768//12 = 64
        # 수치가 정확히 맞는지 확인하기 위해 가정설정문 사용
        assert (
            self.head_dim * self.num_heads == self.embed_dim
        ), f&quot;embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`: {self.num_heads}).&quot;
        self.scale = self.head_dim ** -0.5
        self.dropout = args.attention_dropout

        self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
        self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
        self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
        self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)

    def _shape(self, tensor: torch.Tensor, seq_len: int, bsz: int):
        return tensor.view(bsz, seq_len, self.num_heads, self.head_dim).transpose(1, 2).contiguous()

    def forward(self, hidden_states, attention_mask, causal_attention_mask, output_attentions):
        &quot;&quot;&quot;Input shape: Batch x Time x Channel&quot;&quot;&quot;

        bsz, tgt_len, embed_dim = hidden_states.size() #문장개수, 문장길이, 차원512

        # get query proj
        proj_shape = (bsz * self.num_heads, -1, self.head_dim)

        query_states = self.q_proj(hidden_states) * self.scale
        query_states = self._shape(query_states, tgt_len, bsz).view(*proj_shape)

        key_states = self._shape(self.k_proj(hidden_states), -1, bsz)
        key_states = key_states.view(*proj_shape)

        value_states = self._shape(self.v_proj(hidden_states), -1, bsz)
        value_states = value_states.view(*proj_shape)

        src_len = key_states.size(1)   # [문장개수 x 8, 문장길이, 64 ] -&amp;gt; 문장길이
        
        ### 쿼리, 키 행렬곱 ###
        attn_weights = torch.bmm(query_states, key_states.transpose(1, 2)) #3차원끼리 행렬곱

        if attn_weights.size() != (bsz * self.num_heads, tgt_len, src_len):
            raise ValueError(
                f&quot;Attention weights should be of size {(bsz * self.num_heads, tgt_len, src_len)}, but is {attn_weights.size()}&quot;
            )

        # attention_mask 있으면 사용
        if causal_attention_mask is not None:
            if causal_attention_mask.size() != (bsz, 1, tgt_len, src_len):
                raise ValueError(
                    f&quot;Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is {causal_attention_mask.size()}&quot;
                )
            attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + causal_attention_mask
            attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len)

        if attention_mask is not None:
            if attention_mask.size() != (bsz, 1, tgt_len, src_len):
                raise ValueError(
                    f&quot;Attention mask should be of size {(bsz, 1, tgt_len, src_len)}, but is {causal_attention_mask.size()}&quot;
                )
            attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) + attention_mask
            attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len)

		### softmax 계산 : 어텐션 스코어 ###
        attn_weights = F.softmax(attn_weights, dim=-1)

		# output_attentions 어텐션 스코어까지 계산한 것 사용할지 선택사항!
        if output_attentions:
            attn_weights_reshaped = attn_weights.view(bsz, self.num_heads, tgt_len, src_len)
            attn_weights = attn_weights_reshaped.view(bsz * self.num_heads, tgt_len, src_len)
        else:
            attn_weights_reshaped = None

        attn_probs = F.dropout(attn_weights, p=self.dropout, training=self.training)

		### 어텐션 스코어, 벨류 행렬곱 ###
        attn_output = torch.bmm(attn_probs, value_states)

        if attn_output.size() != (bsz * self.num_heads, tgt_len, self.head_dim):
            raise ValueError(
                f&quot;`attn_output` should be of size {(bsz, self.num_heads, tgt_len, self.head_dim)}, but is {attn_output.size()}&quot;
            )

        attn_output = attn_output.view(bsz, self.num_heads, tgt_len, self.head_dim)
        attn_output = attn_output.transpose(1, 2)
        attn_output = attn_output.reshape(bsz, tgt_len, embed_dim)

        attn_output = self.out_proj(attn_output)

		# 어텐션 결과, output_attentions이 False 이면 None값
        return attn_output, attn_weights_reshaped&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;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;3. CLIPMLP&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. GELU activation function&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허깅페이스의 활성화 함수 모음은 아래 깃헙에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/huggingface/transformers/blob/main/src/transformers/activations.py#L90&quot;&gt;https://github.com/huggingface/transformers/blob/main/src/transformers/activations.py#L90&lt;/a&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;BERT, GPT, ViT는 인코더의 MLP구조의 활성화 함수로 ReLU가 아닌 GELU를 사용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- ReLU : 입력 x의 부호에 따라 self-gating (부호에 따라 deterministic하게 1 or 0을 곱함)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- Dropout : 1 or 0을 stochastic하게 곱함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- GELU : 이 둘의 개념을 합침. x가 줄어들수록&amp;nbsp; dropped될 확률이 높아짐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;GELU&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모든 점에서 미분가능하고, 단조증가함수가 아니 때문에 비선형 활성화 함수 활용 목적에 맞게 복잡한 함수를 모델링하는데 도움됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(참고자료:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hongl.tistory.com/236&quot;&gt;https://hongl.tistory.com/236&lt;/a&gt;)&lt;/span&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;532&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzistF/btsJzPn1KZL/5p8dvG3P91owrHWBLcnj50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzistF/btsJzPn1KZL/5p8dvG3P91owrHWBLcnj50/img.png&quot; data-alt=&quot;GELU vs ReLU&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzistF/btsJzPn1KZL/5p8dvG3P91owrHWBLcnj50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzistF%2FbtsJzPn1KZL%2F5p8dvG3P91owrHWBLcnj50%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;361&quot; height=&quot;254&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GELU vs ReLU&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1726141963147&quot; class=&quot;haskell&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;from collections import OrderedDict

class QuickGELUActivation(nn.Module):
    def forward(self, input):
        return input * torch.sigmoid(1.702 * input)

class ClassInstantier(OrderedDict):
    def __getitem__(self, key):
        content = super().__getitem__(key)
        cls, kwargs = content if isinstance(content, tuple) else (content, {})
        return cls(**kwargs)

ACT2CLS = {&quot;quick_gelu&quot;: QuickGELUActivation}
ACT2FN = ClassInstantier(ACT2CLS)
&amp;gt; ClassInstantier([('quick_gelu', __main__.QuickGELUActivation)])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[문장개수, 문장길이, 512] &amp;nbsp;&amp;rarr; 리니어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[&lt;span&gt;&amp;nbsp;&lt;/span&gt;문장개수 ,&lt;span&gt;&amp;nbsp;&lt;/span&gt;문장길이 , 2048]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 활성화 함수&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[문장개수, 문장길이, 512]&lt;/p&gt;
&lt;pre id=&quot;code_1726141963149&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;class CLIPMLP(nn.Module):
    def __init__(self, args):
        super().__init__()
        self.activation_fn = ACT2FN[args.hidden_act]
        self.fc1 = nn.Linear(args.hidden_size, args.intermediate_size) # intermediate_size : 2048
        self.fc2 = nn.Linear(args.intermediate_size, args.hidden_size)

    def forward(self, hidden_states):
        hidden_states = self.fc1(hidden_states)
        hidden_states = self.activation_fn(hidden_states)
        hidden_states = self.fc2(hidden_states)
        return hidden_states&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;4. 인코더 레이어&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베딩 &amp;rarr; residual connection &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;레이어정규화1&amp;nbsp; &amp;rarr; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;셀프 어텐션계산 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt; residual connection&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&lt;span&gt; 레이어정규화2 &amp;rarr;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; MLP&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726141999493&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;class CLIPEncoderLayer(nn.Module):
    def __init__(self, args):
        super().__init__()
        self.embed_dim = args.hidden_size
        self.self_attn = CLIPAttention(args)
        self.layer_norm1 = nn.LayerNorm(self.embed_dim)
        self.mlp = CLIPMLP(args)
        self.layer_norm2 = nn.LayerNorm(self.embed_dim)

    def forward(self, hidden_states, attention_mask,causal_attention_mask, output_attentions):
        residual = hidden_states

        hidden_states = self.layer_norm1(hidden_states)
        hidden_states, attn_weights = self.self_attn(
            hidden_states=hidden_states,
            attention_mask=attention_mask,
            causal_attention_mask=causal_attention_mask,
            output_attentions=output_attentions,
        )
        hidden_states = residual + hidden_states

        residual = hidden_states
        hidden_states = self.layer_norm2(hidden_states)
        hidden_states = self.mlp(hidden_states)
        hidden_states = residual + hidden_states

        outputs = (hidden_states,)

        if output_attentions:
            outputs += (attn_weights,)

        return outputs&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;모델 구조 출력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5ZGIJ/btsJAyza2uk/7XTXlyt6cm00wd8k5IzdyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5ZGIJ/btsJAyza2uk/7XTXlyt6cm00wd8k5IzdyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5ZGIJ/btsJAyza2uk/7XTXlyt6cm00wd8k5IzdyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5ZGIJ%2FbtsJAyza2uk%2F7XTXlyt6cm00wd8k5IzdyK%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;617&quot; height=&quot;255&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;255&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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 인코더 레이어 스택&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. nn.ModuleList&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;텍스트 기준으로 12개의 인코더 레이어를 쌓는다.&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;1) nn.Sequential vs nn.ModuleList&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- Sequential&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;- ModuleList&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;forward 함수에서 fore문을 사용해야 함&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;i&gt;참고: &lt;/i&gt;&lt;a href=&quot;https://michigusa-nlp.tistory.com/26&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;&lt;i&gt;https://michigusa-nlp.tistory.com/26&lt;/i&gt;&lt;/a&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;항상 레이어를 쌓을때 그냥 python list가 아닌 nn.ModuleList로 담는게 궁금했는데, ModuleList가 안에 담긴 모듈들을 인식하고, optimizer를 정의할 때 파라미터들을 인식한다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1726226876726&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.layers = nn.ModuleList([CLIPEncoderLayer(args) for _ in range(args.num_hidden_layers)])&lt;/code&gt;&lt;/pre&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 실행&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) nn.ModuleList로 묶어 놓은 인코더 레이어를 for문으로 실행&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;2) 내장함수 getattr&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt; getattr(object, attribute, default)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- object : 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- attribute : 클래스 안의 함수 (속성값)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- default : attribute 자리에 적은 함수가 object 클래스 안에 없을 경우 내뱉을 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;ex. &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;np&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #df4a68; text-align: left;&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #e57523; text-align: left;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;) &amp;rarr; gettattr(np, 'array')([1])&lt;/span&gt;&lt;/i&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;따라서 학습시에, gradient_checkpointing이 True일 경우 if문이 실행됨&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;참고 : &lt;/i&gt;&lt;a href=&quot;https://chancoding.tistory.com/188&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;&lt;i&gt;https://chancoding.tistory.com/188&lt;/i&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726227721428&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if getattr(self.config, &quot;gradient_checkpointing&quot;, False) and self.training:&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;전체 코드&lt;/p&gt;
&lt;pre id=&quot;code_1726229646490&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CLIPEncoder(nn.Module):
    def __init__(self, args):
        super().__init__()
        # 인코더 레이어 쌓기
        self.layers = nn.ModuleList([CLIPEncoderLayer(args) for _ in range(args.num_hidden_layers)]) 
        # self.output_attentions = args.output_attentions
        # # self.output_hidden_states = args.output_hidden_states
        # # self.use_return_dict = args.use_return_dict
        # # self.use_return_dict = args.use_return_dict
        self.args = args

    def forward(
        self, inputs_embeds, attention_mask=None, causal_attention_mask=None, output_attentions=None, 
        output_hidden_states=None, return_dict=None,
    ):
        
        # output_attentions True일 경우 : attention weight 출력 여부임, defalut=False
        output_attentions = output_attentions if output_attentions is not None else self.args.output_attentions
        all_attentions = () if output_attentions else None
        
        # output_hidden_states True일 경우 : 각 layer의 hidden state 출력할지 여부임, defalut=False
        output_hidden_states = (
            output_hidden_states if output_hidden_states is not None else self.args.output_hidden_states)
        encoder_states = () if output_hidden_states else None

        return_dict = return_dict if return_dict is not None else self.args.use_return_dict


        # 레이어 순서대로 실행
        hidden_states = inputs_embeds
        for idx, encoder_layer in enumerate(self.layers):

            # output_hidden_states True일 경우만
            if output_hidden_states:
                encoder_states = encoder_states + (hidden_states,)
            
            # 학습할 경우 / 학습안할 경우
            if getattr(self.args, &quot;gradient_checkpointing&quot;, False) and self.training:

                def create_custom_forward(module):
                    def custom_forward(*inputs):
                        return module(*inputs, output_attentions) 

                    return custom_forward

                layer_outputs = torch.utils.checkpoint.checkpoint(
                    create_custom_forward(encoder_layer),
                    hidden_states,
                    attention_mask,
                    causal_attention_mask,
                )
            else:
                layer_outputs = encoder_layer(
                    hidden_states,
                    attention_mask,
                    causal_attention_mask,
                    output_attentions=output_attentions,
                )

                hidden_states = layer_outputs[0]

            if output_attentions:
                all_attentions = all_attentions + (layer_outputs[1],)

        if output_hidden_states:
            encoder_states = encoder_states + (hidden_states,)

        # # return_dict : False일 경우
        if not return_dict:
            return tuple(v for v in [hidden_states, encoder_states, all_attentions] if v is not None)
        # return_dict : True일 경우
        return BaseModelOutput(
            last_hidden_state=hidden_states, hidden_states=encoder_states, attentions=all_attentions
        )&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;실행 코드&lt;/p&gt;
&lt;pre id=&quot;code_1726746373976&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from clip_textencoder import CLIPTextEmbeddings, CLIPAttention, CLIPMLP, CLIPEncoderLayer, CLIPEncoder
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--vocab_size', default=49408, help='vocab_size')
parser.add_argument('--hidden_size', default=512, help='hidden_size')
parser.add_argument('--max_position_embeddings', default=77, help='max_position_embeddings')
parser.add_argument('--num_attention_heads', default=8, help='num_attention_heads')
parser.add_argument('--attention_dropout', default=0.0, help='attention_dropout')
parser.add_argument('--hidden_act', default=&quot;quick_gelu&quot;, help='hidden_act')
parser.add_argument('--intermediate_size', default=2048, help='intermediate_size')

parser.add_argument('--num_hidden_layers', default=12, help='num_hidden_layers')

parser.add_argument('--gradient_checkpointing', default=False, help='gradient_checkpointing')
parser.add_argument('--output_attentions', default=False, help='output_attentions')
parser.add_argument('--output_hidden_states', default=False, help='output_hidden_states')
parser.add_argument('--use_return_dict', default=False, help='use_return_dict')

args, _ = parser.parse_known_args()

from transformers import AutoProcessor
# from transformers import CLIPProcessor
repo = &quot;/home/leeanna/2024_practice/clip/clip-vit-base-patch32&quot;
processor = AutoProcessor.from_pretrained(repo, local_files_only=True)
inputs = processor(text=[&quot;a photo of a cat&quot;, &quot;a photo of a dog&quot;], return_tensors=&quot;pt&quot;, 
                   padding=True)


# 1. 임베딩
embedding_class = CLIPTextEmbeddings(args)
text_embedding = embedding_class(input_ids=inputs.input_ids, position_ids=None, inputs_embeds=None)

print(text_embedding.shape)
&amp;gt; torch.Size([2, 7, 512])

# 정규화
residual = text_embedding

from torch import nn
layer_norm1 = nn.LayerNorm(512)
hidden_states = layer_norm1(text_embedding)
print('layer_norm1 : ', hidden_states.size())
&amp;gt; layer_norm1 :  torch.Size([2, 7, 512])

# 2. 어텐션
self_attn = CLIPAttention(args)
hidden_states, attn_weights = self_attn(
            hidden_states=hidden_states,
            attention_mask=None,
            causal_attention_mask=None,
            output_attentions=None,
        )
print('어텐션 끝 hidden_states : ',hidden_states.shape)
&amp;gt; 어텐션 끝 hidden_states :  torch.Size([2, 7, 512])

hidden_states = residual + hidden_states
residual = hidden_states

# 정규화2
layer_norm2 = nn.LayerNorm(512)
hidden_states = layer_norm2(hidden_states)
print('layer_norm2 : ', hidden_states.size())
&amp;gt; layer_norm2 :  torch.Size([2, 7, 512])

# 3. mlp
mlp = CLIPMLP(args)
hidden_states = mlp(hidden_states)
print('mlp : ', hidden_states.size())
&amp;gt; mlp :  torch.Size([2, 7, 512])

hidden_states = residual + hidden_states

# 결과
outputs = (hidden_states,)

# 4. 인코더 실행
one_encoder = CLIPEncoderLayer(args)
print(one_encoder)
one_encoder_output = one_encoder(hidden_states, attention_mask=None, causal_attention_mask=None, output_attentions=None)
print(one_encoder_output[0].shape) 
&amp;gt; torch.Size([2, 7, 512])

# 5. 인코터 스택
# layers = nn.ModuleList([CLIPEncoderLayer(args) for _ in range(args.num_hidden_layers)])

# hidden_states = text_embedding
# for idx, encoder_layer in enumerate(layers): 
#     layer_outputs = encoder_layer(hidden_states, attention_mask=None, causal_attention_mask=None, output_attentions=None)
#     hidden_states = layer_outputs[0]

# print(hidden_states.shape)

all_encoder = CLIPEncoder(args)
all_encoder_output = all_encoder(text_embedding, attention_mask=None, causal_attention_mask=None, output_attentions=None, output_hidden_states=None, return_dict=None)
print(all_encoder_output[0].shape)
&amp;gt; torch.Size([2, 7, 512])&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;</description>
      <category>code</category>
      <category>clip</category>
      <category>clip text encoder</category>
      <category>clip코드</category>
      <category>huggingface</category>
      <category>huggingface clip</category>
      <category>허깅페이스</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/33</guid>
      <comments>https://yeonjins.tistory.com/entry/CLIP-%EC%BD%94%EB%93%9C-%EB%B6%84%ED%95%B4#entry33comment</comments>
      <pubDate>Tue, 10 Sep 2024 21:40:31 +0900</pubDate>
    </item>
    <item>
      <title>huggingface 활용하기</title>
      <link>https://yeonjins.tistory.com/entry/huggingface-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;Transformer 관련 모델들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Transformer&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 2017년 6월&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;GPT&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;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;2018년 6월, 최초의 pretrained transformer 모델로 각 task에 맞게 finetuning해서 사용할 수 있도록 했다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;BERT&lt;/b&gt; : 2018년 10월, 똑같이 pretrained된 모델로 gpt와 비슷한 크기로 만들어 비교하며 성능이 뛰어남을 보였다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;GPT-2&lt;/b&gt; : 2019년 2월&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;DistillBERT :&lt;/b&gt; 2019년 10월, 메모리 소비를 40% 줄이고, 속도를 60% 높이고, BERT의 97% 성능을 유지했다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;BART, T5&lt;/b&gt; : 2019년 10월, 트랜스포머 모델과 동일한 아키텍처를 사용한 pretrained 모델&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;GPT-3&lt;/b&gt; : 2020년 5월, 미세 조정 없이 다양한 task가 가능한 zero-shot learning 모델&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&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;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;GPT&lt;/b&gt;계열은 트랜스포머의 디코더 파트를 활용한 auto-regressive transformer모델로 (CTRL, GPT, GPT-2, Transformer XL) text generation에 적합하다.&lt;/span&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;b&gt;BERT&lt;/b&gt; 계열은 인코더 파트를 활용한 auto-encoding transformer 모델로 (ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa) sentece classification, NER, extractice QA에 적합하다.&lt;/span&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;b&gt;BART&lt;/b&gt;와 &lt;b&gt;T5&lt;/b&gt;는 seq2seq transformer 모델로(BART, mBART, Marian, T5) summarization, translation, generative QA에 잘 활용된다.&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&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;783&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQGZ1U/btr61hHdanC/4HigOQbXTOZwLR2rNd3Du0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQGZ1U/btr61hHdanC/4HigOQbXTOZwLR2rNd3Du0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQGZ1U/btr61hHdanC/4HigOQbXTOZwLR2rNd3Du0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQGZ1U%2Fbtr61hHdanC%2F4HigOQbXTOZwLR2rNd3Du0%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;426&quot; height=&quot;293&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p 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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Pipeline&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;허깅페이스 transformers 라이브러리의 pipeline은 데이터 전처리, 모델입력, 후처리의 3단계를 한번에 실행해주어 매우 편하다. 객체를 생성할때 체크포인트를 넣는데, 모델을 지정하지 않아도 선택한 체크포인트에 적합한 모델 아키택쳐를 자동으로 추출해주어 매우 편하다.&lt;/p&gt;
&lt;pre id=&quot;code_1680159757700&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from transformers import pipeline
classifier = pipeline(&quot;sentiment-analysis&quot;)&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;위처럼 감성분석의 경우 &lt;b&gt;sentiment-analysis&lt;/b&gt;을 활용하면 되고, 각 파이프라인에 따라 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&lt;b&gt; zero-shot-classification&lt;/b&gt; : 제로샷 분류 모델로 레이블을 새로 지정해 활용가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 생성하고 나서 활용할때 candidate_labels 로 원하는 레이블을 지정하면 된다.&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;b&gt;- text-generation&lt;/b&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; max_length 로 텍스트의 총 길이를 지정할 수 있다.&lt;/span&gt;&lt;/span&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;b&gt;-&amp;nbsp; fill-mask&lt;/b&gt; : 중간 단어를 &amp;lt;mask&amp;gt; 토큰으로 지우면 해당 위치에 들어올 확률 높은 단어를 예측해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 생성하고 나서 활용할때 top_k로 후보 단어의 개수를 지정할 수 있다.&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;b&gt;- ner&lt;/b&gt; : 사람은 PER, 조직은 ORG, 위치는 LOC 처럼 입력 텍스트에서 개체명을 인식해준다. (grouped_entitles)&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;b&gt;- question-answering&lt;/b&gt; : 질문에 대한 응답을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 생성하고 나서 활용할때&amp;nbsp; context 정보를 함께 제공하면 된다.&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;b&gt;- summarization&lt;/b&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;b&gt;- translation&lt;/b&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;&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;또 해당 task에 원하는 &lt;b&gt;모델을 직접 지정&lt;/b&gt;해서 활용도 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1680159808118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;generator = pipeline(&quot;text-generation&quot;, mmodel = &quot;distilgpt2&quot;)&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Pipeline 활용하지 않고 실행&lt;/b&gt;&lt;/h3&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;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;1032&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vkndH/btr6UCslbZr/1xBq5UmLLcETjb0EX8f1IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vkndH/btr6UCslbZr/1xBq5UmLLcETjb0EX8f1IK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vkndH/btr6UCslbZr/1xBq5UmLLcETjb0EX8f1IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvkndH%2Fbtr6UCslbZr%2F1xBq5UmLLcETjb0EX8f1IK%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;720&quot; height=&quot;253&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 인풋 전처리하기 - 토크나이저 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;트랜스포머 라이브러리의 AutoTokenizer를 활용해 인풋을 모델에 넣을 수 있는 형태로 바꿔야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680164300957&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from transformers import AutoTokenizer

checkpoint = &quot;distilbert-base-uncased-finetuned-sst-2-english&quot;
tokenizer = AutoTokenizer.from_pretrained(checkpoint)

inputs = [&quot;문장1&quot;,&quot;문장2&quot;]

# return_tensors로 출력 텐서의 유형을 지정가능
inputs = tokenizer(inputs, padding=True, truncation=True, return_tensors=&quot;pt&quot;)
inputs
&amp;gt; {'input_ids': tensor([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,2607,  2026,  2878,  2166,  1012,   102],
        [  101,  1045,  5223,  2023,  2061,  2172,   999,   102,     0,     0,    0,     0,     0,     0,     0,     0]]), 
   'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]])}&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;토크나이저의 아웃풋 형태는 딕셔너리로 input_ids와 attention_mask가 나온다. 또 return_tensors로 텐서의 유형을 지정가능하다.&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 모델&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;트랜스포머 라이브러리의 AutoModel을 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1680164634550&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from transformers import AutoModel

checkpoint = &quot;distilbert-base-uncased-finetuned-sst-2-english&quot;
model = AutoModel.from_pretrained(checkpoint)

outputs = model(**inputs)

outputs.last_hidden_state.shape
&amp;gt; torch.Size([2, 16, 768])&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;p data-ke-size=&quot;size16&quot;&gt;이렇게 나온&amp;nbsp; 아웃풋은 hidden state로 모델 헤드의 입력이 된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. Head&lt;/b&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;hidden state를 헤드에 넣어 원하는 차원만큼으로 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680165053392&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from transformers import AutoModelForSequenceClassification

checkpoint = &quot;distilbert-base-uncased-finetuned-sst-2-english&quot;
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

outputs = model(**inputs)
outputs
&amp;gt; SequenceClassifierOutput(loss=None, logits=tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=&amp;lt;AddmmBackward0&amp;gt;), hidden_states=None, attentions=None)

outputs.logits.shape
&amp;gt; torch.Size([2, 2])&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;p data-ke-size=&quot;size16&quot;&gt;앞에서 2개의 문장을 넣고, class는 두 개 였다. 따라서 한 문장씩 두 class에 대한 logit값이 나와 2x2 벡터가 출력된다.&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 후처리&lt;/b&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;Head를 통해 나온 결과는 logit으로 확률이 아니다. 따라서 softmax를 취해 확률값으로 변환해주어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1680165482151&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;outputs.logits
&amp;gt; tensor([[-1.5607,  1.6123],
        [ 4.1692, -3.3464]], grad_fn=&amp;lt;AddmmBackward0&amp;gt;)
        
# logit 값들을 확률로 변환
predictions = torch.nn.functional.softmax(outputs.logits, dim=-1)
predictions
&amp;gt; tensor([[4.0195e-02, 9.5980e-01],
        [9.9946e-01, 5.4418e-04]], grad_fn=&amp;lt;SoftmaxBackward0&amp;gt;)


# config.id2label : 각 숫자별 레이블
model.config.id2label
&amp;gt; {0: 'NEGATIVE', 1: 'POSITIVE'}&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>papers/자연어</category>
      <author>yeonjins</author>
      <guid isPermaLink="true">https://yeonjins.tistory.com/32</guid>
      <comments>https://yeonjins.tistory.com/entry/huggingface-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0#entry32comment</comments>
      <pubDate>Thu, 30 Mar 2023 17:38:24 +0900</pubDate>
    </item>
  </channel>
</rss>