<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>지으니어스</title>
    <link>https://ji10ji.tistory.com/</link>
    <description>친절한 조언만 환영해요?</description>
    <language>ko</language>
    <pubDate>Mon, 25 May 2026 05:21:20 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>지으니어스</managingEditor>
    <image>
      <title>지으니어스</title>
      <url>https://tistory1.daumcdn.net/tistory/5695101/attach/2dd11e77c115457e964c3815c9d7706e</url>
      <link>https://ji10ji.tistory.com</link>
    </image>
    <item>
      <title>[Python] 프로그래머스 / level 1 / 기사단원의 무기 / 시간초과 / 에라토스테네스의 체</title>
      <link>https://ji10ji.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/136798#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/136798#qna&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722381414993&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/136798#qna&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ikQMD/hyWGUvmXiF/KdG2pEVhZdouMzccdU0K2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bj9QSb/hyWG3sj3nb/HZUR1yl5KHYVSjYTNp00k0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/136798#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/136798#qna&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ikQMD/hyWGUvmXiF/KdG2pEVhZdouMzccdU0K2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bj9QSb/hyWG3sj3nb/HZUR1yl5KHYVSjYTNp00k0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&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;programmers.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;pre id=&quot;code_1722381419747&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(number, limit, power):
    num = [i for i in range(1, number+1)]
    result = []
    
    for j in num:
        answer = 0
        for k in range(1, j+1):
            if j%k==0:
                answer += 1
        if answer&amp;gt;limit:
            result.append(power)
        else:
            result.append(answer)
    
    return sum(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;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: #ee2323;&quot;&gt;약수를 구하는 효율적인 방법&lt;/span&gt; 사용해보기.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722385777708&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(number, limit, power):
    num = [i for i in range(1, number+1)]
    result = []
    
    for j in num:
        answer = 0
        for k in range(1, int(j**(1/2))+1):
            if j%k==0:
                answer += 1
                if (k**2) != j : 
                    answer += 1
        if answer&amp;gt;limit:
            result.append(power)
        else:
            result.append(answer)
        
    return sum(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;ref : &lt;a href=&quot;https://minnit-develop.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://minnit-develop.tistory.com/16&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Coding Test/Python</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/54</guid>
      <comments>https://ji10ji.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 31 Jul 2024 09:30:38 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 프로그래머스 / level 1 / 그리디 / 체육복</title>
      <link>https://ji10ji.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42862&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42862&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1722219980408&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42862&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dx6kDh/hyWGXrvZOY/sfMjdY8pIvPTaQnTQtjCP1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/BX0Gq/hyWGQy9TR2/wz7tuiQ0CdK4DXJS4CXMk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42862&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42862&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dx6kDh/hyWGXrvZOY/sfMjdY8pIvPTaQnTQtjCP1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/BX0Gq/hyWGQy9TR2/wz7tuiQ0CdK4DXJS4CXMk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&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;programmers.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;pre id=&quot;code_1722219986727&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n, lost, reserve):
    student = len(lost)
    
    reserve_i, lost_j = 0, 0
    
    while reserve_i &amp;lt; len(reserve) and lost_j &amp;lt; len(lost):
        
        # 여벌 체육복을 가져온 학생이 체육복 도난 당한 경우
        if reserve[reserve_i] == lost[lost_j]:
            reserve_i += 1
            lost_j += 1
            student -= 1
        
        # -1 했는 학생이 있을 때 
        elif reserve[reserve_i] - 1 == lost[lost_j]:
            reserve_i += 1
            lost_j += 1
            student -= 1
        
        # +1 했는 학생이 있을 때
        elif reserve[reserve_i] + 1 == lost[lost_j]:
            reserve_i += 1
            lost_j += 1
            student -= 1
            
    return n - student&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;그래서 다음과 같이 코드를 작성했지만 시간초과.&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개 모두를 순환해 최악의 경우 시간복잡도 O(len(reserve)*len(lost))가 됨.&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;color: #ee2323;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1722221462741&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(n, lost, reserve):
    
    _reserve = [r for r in reserve if r not in lost]
    _lost = [l for l in lost if l not in reserve]
    
    _reserve.sort()
    _lost.sort()
    
    for r in _reserve:
        q  = r-1
        s = r+1
        if q in _lost:
            _lost.remove(q)
        elif s in _lost:
            _lost.remove(s)
            
    return n - len(_lost)&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>Coding Test/Python</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/53</guid>
      <comments>https://ji10ji.tistory.com/53#entry53comment</comments>
      <pubDate>Mon, 29 Jul 2024 11:52:21 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 프로그래머스 / 모음 사전 / DFS</title>
      <link>https://ji10ji.tistory.com/51</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/84512&quot;&gt;코딩테스트 연습 - 모음사전 | 프로그래머스 스쿨 (programmers.co.kr)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1721628008397&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/84512&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MklyU/hyWCBWFYHg/bIFpEu0egeWYtJqhjN5370/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/v1Zi6/hyWCOPgUSC/eMm5uD5rhgjX1W1iPwZ6ZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/84512&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/84512&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MklyU/hyWCBWFYHg/bIFpEu0egeWYtJqhjN5370/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/v1Zi6/hyWCOPgUSC/eMm5uD5rhgjX1W1iPwZ6ZK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&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;programmers.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;알고리즘 고득점 kit에서 '완전탐색'으로 분류되어 있지만 dfs로 간단히(?) 풀 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721628045750&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(word):
    answer = 1
    moeum = &quot;AEIOU&quot;
    alpha = &quot;A&quot;
    def dfs(alpha, i):
        if alpha==word:
            return 
            
        for i in range(0, len(moeum)):
            dfs(alpha+moeum[i], 1+i)
            answer += i
        
    dfs(alpha, 1)
    return answer&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1721628415118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(word):
    moeum = &quot;AEIOU&quot;
    word_list = []
    def dfs(length, alpha):
        
        # 종료시점
        if length==5:
            return 
            
        for i in range(len(moeum)):
            word_list.append(alpha+moeum[i])
            dfs(length+1, alpha+moeum[i])
        
    dfs(0, &quot;&quot;)
    return word_list.index(word)+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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ref :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@sugenius77/Python%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%AA%A8%EC%9D%8C%EC%82%AC%EC%A0%84&quot;&gt;[프로그래머스/Python] 모음사전 (velog.io)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Coding Test/Python</category>
      <category>Python</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/51</guid>
      <comments>https://ji10ji.tistory.com/51#entry51comment</comments>
      <pubDate>Mon, 22 Jul 2024 15:07:57 +0900</pubDate>
    </item>
    <item>
      <title>교통 표지판 이미지 분류</title>
      <link>https://ji10ji.tistory.com/49</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;*자율주행 기술에 사용된ㄴ 교통 표지판의 내용을 분류하는 프로젝트*&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;a href=&quot;https://www.kaggle.com/datasets/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.kaggle.com/datasets/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716870680701&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;GTSRB - German Traffic Sign Recognition Benchmark&quot; data-og-description=&quot;Multi-class, single-image classification challenge&quot; data-og-host=&quot;www.kaggle.com&quot; data-og-source-url=&quot;https://www.kaggle.com/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&quot; data-og-url=&quot;https://www.kaggle.com/datasets/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VlU8H/hyV9Rfqrx9/hoBl18nYLUapRivacIOINk/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kaggle.com/meowmeowmeowmeowmeow/gtsrb-german-traffic-sign&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VlU8H/hyV9Rfqrx9/hoBl18nYLUapRivacIOINk/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&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;GTSRB - German Traffic Sign Recognition Benchmark&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Multi-class, single-image classification challenge&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.kaggle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(Meta와 Meta.csv는 사용하지 않음)&lt;/p&gt;
&lt;pre id=&quot;code_1716871119777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!pip install -U numpy==1.23.5
!pip install -U seaborn==0.11.2
!pip install -U tensorflow==2.10.0

import os
import random

# Tensorflow 관련 디버그 및 경고 메시지 비활성화
os.environ[&quot;TF_CPP_MIN_LOG_LEVEL&quot;] = &quot;2&quot;

import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from PIL import Image, ImageDraw
from tqdm import tqdm

root_dir = '/mnt/data'

train_metadata = pd.read_csv(os.path.join(root_dir, 'Train.csv'))
test_metadata = pd.read_csv(os.path.join(root_dir, 'Test.csv'))

train_metadata.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buXhov/btsHEZkmAqb/VhScvKqyZwOdrb5RxCDphK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buXhov/btsHEZkmAqb/VhScvKqyZwOdrb5RxCDphK/img.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;190&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.7724%; margin-right: 10px;&quot; data-widthpercent=&quot;55.42&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buXhov/btsHEZkmAqb/VhScvKqyZwOdrb5RxCDphK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuXhov%2FbtsHEZkmAqb%2FVhScvKqyZwOdrb5RxCDphK%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;732&quot; height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edkwVn/btsHDWCchBh/hTnr0VW9Y1Mr6MuELMTLy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edkwVn/btsHDWCchBh/hTnr0VW9Y1Mr6MuELMTLy1/img.png&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;191&quot; data-is-animation=&quot;false&quot; style=&quot;width: 44.0649%;&quot; data-widthpercent=&quot;44.58&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edkwVn/btsHDWCchBh/hTnr0VW9Y1Mr6MuELMTLy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedkwVn%2FbtsHDWCchBh%2FhTnr0VW9Y1Mr6MuELMTLy1%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;592&quot; height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;왼 - train_metadata / 오 - test_metadata&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;`Width`:&amp;nbsp;이미지&amp;nbsp;파일의&amp;nbsp;너비&lt;br /&gt;-&amp;nbsp;`Height`:&amp;nbsp;이미지&amp;nbsp;파일의&amp;nbsp;높이&lt;br /&gt;-&amp;nbsp;`Roi.X1`:&amp;nbsp;이미지&amp;nbsp;파일&amp;nbsp;내에서&amp;nbsp;실제&amp;nbsp;표지판이&amp;nbsp;존재하는&amp;nbsp;곳을&amp;nbsp;상자로&amp;nbsp;감쌌을&amp;nbsp;때&amp;nbsp;좌상단&amp;nbsp;X좌표&lt;br /&gt;-&amp;nbsp;`Roi.Y1`:&amp;nbsp;이미지&amp;nbsp;파일&amp;nbsp;내에서&amp;nbsp;실제&amp;nbsp;표지판이&amp;nbsp;존재하는&amp;nbsp;곳을&amp;nbsp;상자로&amp;nbsp;감쌌을&amp;nbsp;때&amp;nbsp;좌상단&amp;nbsp;Y좌표&lt;br /&gt;-&amp;nbsp;`Roi.X2`:&amp;nbsp;이미지&amp;nbsp;파일&amp;nbsp;내에서&amp;nbsp;실제&amp;nbsp;표지판이&amp;nbsp;존재하는&amp;nbsp;곳을&amp;nbsp;상자로&amp;nbsp;감쌌을&amp;nbsp;때&amp;nbsp;우하단&amp;nbsp;X좌표&lt;br /&gt;-&amp;nbsp;`Roi.Y2`:&amp;nbsp;이미지&amp;nbsp;파일&amp;nbsp;내에서&amp;nbsp;실제&amp;nbsp;표지판이&amp;nbsp;존재하는&amp;nbsp;곳을&amp;nbsp;상자로&amp;nbsp;감쌌을&amp;nbsp;때&amp;nbsp;우하단&amp;nbsp;Y좌표&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: #9d9d9d;&quot;&gt;( RoI는 Region of Interest라는 뜻)&lt;/span&gt;&lt;br /&gt;-&amp;nbsp;`ClassId`:&amp;nbsp;해당&amp;nbsp;이미지의&amp;nbsp;클래스&amp;nbsp;ID&amp;nbsp;(0&amp;nbsp;~&amp;nbsp;42까지&amp;nbsp;존재)&lt;br /&gt;-&amp;nbsp;`Path`:&amp;nbsp;실제&amp;nbsp;이미지가&amp;nbsp;저장된&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;size16&quot;&gt;x = 'Path'와 y = 'ClassId'&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;1) 두 파일 모두 같은 컬럼을 가지고 있음.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 크기가 모두 제각각 -&amp;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;color: #006dd7;&quot;&gt;- 데이터 출력&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716871828274&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sample_metadata = train_metadata.iloc[28589, :]
sample_img = Image.open(os.path.join(root_dir, sample_metadata['Path']))

roi_box = ImageDraw.Draw(sample_img)
roi_box.rectangle(
    (
        sample_metadata['Roi.X1'], # 좌상단 X 좌표
        sample_metadata['Roi.Y1'], # 좌상단 Y 좌표
        sample_metadata['Roi.X2'], # 우하단 X 좌표
        sample_metadata['Roi.Y2'], # 우하단 Y 좌표
    ),
    outline=(255, 0, 0), # Bounding Box 색을 빨간색으로
    width=5 # Bounding Box 선의 두께
)

plt.imshow(sample_img)&lt;/code&gt;&lt;/pre&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;340&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LXDP3/btsHDU5ux1w/wpJkO3jTbuSnQ2lPShqWB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LXDP3/btsHDU5ux1w/wpJkO3jTbuSnQ2lPShqWB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LXDP3/btsHDU5ux1w/wpJkO3jTbuSnQ2lPShqWB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLXDP3%2FbtsHDU5ux1w%2FwpJkO3jTbuSnQ2lPShqWB0%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;340&quot; height=&quot;315&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;315&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;size18&quot;&gt;&lt;b&gt;1. 데이터 분석 및 시각화&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;color: #006dd7;&quot;&gt;- 학습 데이터의 이미지 너비(Width)와 높이(Height)의 분포를 살펴보기.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716871998810&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fig, ax = plt.subplots(2, 1, figsize=(12, 8))
sns.set_palette('tab10')
sns.histplot(train_metadata, x='Width', kde=True, stat='percent', label='Width', ax=ax[0], color='r')
ax[0].legend()
sns.histplot(train_metadata, x='Height', kde=True, stat='percent', label='Height', ax=ax[1], color='b')
ax[1].legend()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpg4t9/btsHDNk7uAZ/Hu8e6ZP4ANvUK0ulE82pBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpg4t9/btsHDNk7uAZ/Hu8e6ZP4ANvUK0ulE82pBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpg4t9/btsHDNk7uAZ/Hu8e6ZP4ANvUK0ulE82pBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpg4t9%2FbtsHDNk7uAZ%2FHu8e6ZP4ANvUK0ulE82pBK%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;569&quot; height=&quot;365&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;578&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;대부분의 이미지 파일의 너비와 높이는 50 이하인 것으로 확인됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CIFAR-10 데이터를 따라 32x32로 통일.&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;또한, train 디렉토리가 class id별로 나누어져 있기 때문에 ImageDataGenerator를 통해 데이터셋을 생성.&lt;/p&gt;
&lt;pre id=&quot;code_1716872281568&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;img_height, img_width = 32, 32

# 정규화
train_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255,
validation_split=0.2)

# flow_from_directory를 통해 데이터셋을 생성
# 클래스 ID별로 저장된 디렉토리 경로명 지정
train_set = train_gen.flow_from_directory(
    os.path.join(root_dir, 'Train'),
    target_size=(img_height, img_width),
    class_mode='categorical',
    batch_size=256,
    shuffle=True,
    seed=SEED,
    subset='training'
)

valid_set = train_gen.flow_from_directory(
    os.path.join(root_dir, 'Train'),
    target_size=(img_height, img_width),
    class_mode='categorical',
    batch_size=256,
    shuffle=False,
    subset='validation'
)&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;반면, test 데이터는 하나로 통일되어 있음.&lt;/p&gt;
&lt;pre id=&quot;code_1716872663664&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test_metadata = pd.read_csv(os.path.join(root_dir, 'Test.csv'))

# flow_from_dataframe 메소드는 클래스 ID에 해당하는 컬럼의 데이터 타입이 문자열(str)이여야 함.
test_metadata['ClassId'] = test_metadata['ClassId'].astype(str)

test_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)

test_set = test_gen.flow_from_dataframe(
    test_metadata,
    directory=root_dir,
    x_col='Path',
    y_col='ClassId',
    target_size=(img_height, img_width),
    class_mode='categorical',
    batch_size=256,
    shuffle=False
)&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;- flow_from_directory에서는 DataFrame의 어떤 컬럼이 입력(X)이고 어떤 컬럼이 라벨(y)인지 지정이 필요.&lt;br /&gt;- 각 이미지 파일의 경로는 'directory' argument의 값과 x_col에 지정한 컬럼의 각 값을 join해서 얻어지기 때문에 'Path' 컬럼이 'Test/00000.png'와 같이 이루어져 있으므로 'directory'에는 데이터셋의 최상위 경로만 지정.&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. CNN 모델 정의 및 학습&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716873140719&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, kernel_size=3, padding='same',
    activation='relu',input_shape=(img_height, img_width, 3)),

    # 뒤에 등장하는 Dense layer에 적용하기 위해 3차원 데이터를 1차원으로 바꿔주는 Layer
    tf.keras.layers.Flatten(),

    # 43개 클래스를 구분해야 하므로 43개의 노드를 가지는 Dense layer를 추가
    tf.keras.layers.Dense(43, activation='softmax')])&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716873166939&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
model.compile(
    optimizer=optimizer,
    loss='categorical_crossentropy',
    metrics=['accuracy'])

num_epochs = 5
history = model.fit(train_set, epochs=num_epochs, validation_data=valid_set)&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;span style=&quot;color: #006dd7;&quot;&gt;- 성능 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716873194161&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;accuracy = history.history['accuracy']
val_accuracy = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(1, num_epochs + 1)

plt.figure(figsize=(16, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, accuracy, label='Training Accuracy')
plt.plot(epochs_range, val_accuracy, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()&lt;/code&gt;&lt;/pre&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;980&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ov0k2/btsHFxur7ON/JVNyuF9mRpxril8ZaBEW6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ov0k2/btsHFxur7ON/JVNyuF9mRpxril8ZaBEW6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ov0k2/btsHFxur7ON/JVNyuF9mRpxril8ZaBEW6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOv0k2%2FbtsHFxur7ON%2FJVNyuF9mRpxril8ZaBEW6K%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;735&quot; height=&quot;372&quot; data-origin-width=&quot;980&quot; data-origin-height=&quot;496&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;pre id=&quot;code_1716873248949&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;_, test_accuracy = model.evaluate(test_set)&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;테스트 정확도 : 83.785%&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;span style=&quot;color: #006dd7;&quot;&gt;- 실제 라벨과 예측 라벨 일치 여부 확인&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716873321285&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;num_sample = 25

test_pred = np.argmax(model.predict(test_set), axis=-1)[:num_sample]
X_test_sample = test_set[0][0][:num_sample, :, :]
y_test_sample = np.argmax(test_set[0][1][:num_sample, :], axis=-1)

plt.figure(figsize=(13, 13))
for i in range(num_sample):
    plt.subplot(5, 5, i + 1)
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    prediction = test_pred[i]
    actual = y_test_sample[i]
    color = 'g'
    if prediction != actual:
        color = 'r'
    
    plt.xlabel(f'Actual={actual} || Pred={prediction}', color=color)
    plt.imshow(tf.keras.utils.array_to_img(X_test_sample[i]))

plt.show()&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>AI &amp;amp; Data Science/Deep Learning</category>
      <category>CNN</category>
      <category>딥러닝</category>
      <category>자율주행</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/49</guid>
      <comments>https://ji10ji.tistory.com/49#entry49comment</comments>
      <pubDate>Tue, 28 May 2024 14:36:11 +0900</pubDate>
    </item>
    <item>
      <title>GPR(지표투과레이더) 데이터를 이용한 매설물 탐지 모델 개발</title>
      <link>https://ji10ji.tistory.com/48</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;지하탐지 분야에서 주목받고 있는 GPR(Ground Pentrating Rader) 데이터를 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CNN (Convolution Neural Network)을 이용하여 배관 등의 매설 위치를 파악하기.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 출처 : &lt;a href=&quot;https://github.com/rpl-cmu/CMU-GPR-Dataset&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/rpl-cmu/CMU-GPR-Dataset&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1716867036220&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - rpl-cmu/CMU-GPR-Dataset: Dataset and utilities for research on localizing ground penetrating radar (GPR).&quot; data-og-description=&quot;Dataset and utilities for research on localizing ground penetrating radar (GPR). - rpl-cmu/CMU-GPR-Dataset&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/rpl-cmu/CMU-GPR-Dataset&quot; data-og-url=&quot;https://github.com/rpl-cmu/CMU-GPR-Dataset&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAWoMn/hyWdsd0U3l/1D0TzfRjcpxmN7Wnnwzl90/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/rpl-cmu/CMU-GPR-Dataset&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/rpl-cmu/CMU-GPR-Dataset&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAWoMn/hyWdsd0U3l/1D0TzfRjcpxmN7Wnnwzl90/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - rpl-cmu/CMU-GPR-Dataset: Dataset and utilities for research on localizing ground penetrating radar (GPR).&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dataset and utilities for research on localizing ground penetrating radar (GPR). - rpl-cmu/CMU-GPR-Dataset&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMU GPR dataset은 GPR 센서의 측정 결과와 측정 위치를 레이블링한 데이터이다. 본 데이터는 GPR을 측정한 정확한 위치가 함께 레이블링 되어 있으나 그 속에 무었이 있는지에 대한 정보를 가지고 있지는 않다.&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 data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;GPR은 전자파를 지면에 방출 시켜서 되돌아 오는 반사파를 기록한다. 만일 지하에 무엇인가 매질이 다른 물질이 있으면 되돌아오는 반사파의 형태가 변하게 된다. 때문에 되돌아오는 반사파의 형태를 분석하면 지하에 무엇이 매설되어 있는지를 추측할 수 있다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsqIQS/btsHCW3HvL2/bKbL0AV33kPehKe8Igax91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsqIQS/btsHCW3HvL2/bKbL0AV33kPehKe8Igax91/img.png&quot; data-alt=&quot;data.head()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsqIQS/btsHCW3HvL2/bKbL0AV33kPehKe8Igax91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsqIQS%2FbtsHCW3HvL2%2FbKbL0AV33kPehKe8Igax91%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;658&quot; height=&quot;189&quot; data-origin-width=&quot;965&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;data.head()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;gpr_meas.csv 파일에는 GPR에서 측정한 200개의 반사된 주파수의 시간별 amplitude(진폭)가 저장되어 있다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K2izj/btsHDIYinWC/iTPJSLkqrcZR6VvPwptpbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K2izj/btsHDIYinWC/iTPJSLkqrcZR6VvPwptpbK/img.png&quot; data-alt=&quot;data.describe()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K2izj/btsHDIYinWC/iTPJSLkqrcZR6VvPwptpbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK2izj%2FbtsHDIYinWC%2FiTPJSLkqrcZR6VvPwptpbK%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;641&quot; height=&quot;199&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;data.describe()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;Amp_0 와 Amp_3 컬럼을 비교해 보면 평균(mean)/분산(std)이 각각 8.29/82.105, -107.94,/60.57로 주파수에 따른 통계적 특성이 제각각 다름을 알 수 있다. &lt;br /&gt;&amp;nbsp;&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;span style=&quot;color: #006dd7;&quot;&gt; &amp;nbsp;&amp;nbsp;- Amp_0, Amp_10, Amp_100 컬럼의 시간에 따른 값 변화&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716868078414&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df[['Amp_0','Amp_10', 'Amp_100']].plot(grid='on')&lt;/code&gt;&lt;/pre&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;493&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKGSb/btsHCV4PBen/pdzukb3tiO561FQUwO50Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKGSb/btsHCV4PBen/pdzukb3tiO561FQUwO50Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKGSb/btsHCV4PBen/pdzukb3tiO561FQUwO50Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKGSb%2FbtsHCV4PBen%2Fpdzukb3tiO561FQUwO50Nk%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;493&quot; height=&quot;335&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;335&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_10 컬럼의 주파수의 amplitude의 변화를 보면 779, 848 등의 위치에서 그 신호가 급격하게 떨어짐.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S7dLL/btsHDi6yHAb/wvgr5Fbw21iM5QKSSWREt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S7dLL/btsHDi6yHAb/wvgr5Fbw21iM5QKSSWREt0/img.png&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;332&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.7209%; margin-right: 10px;&quot; data-widthpercent=&quot;51.32&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S7dLL/btsHDi6yHAb/wvgr5Fbw21iM5QKSSWREt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FS7dLL%2FbtsHDi6yHAb%2Fwvgr5Fbw21iM5QKSSWREt0%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;497&quot; height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8xzDn/btsHEAFb7NX/e37bwZIka8buxPzxPoSaG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8xzDn/btsHEAFb7NX/e37bwZIka8buxPzxPoSaG1/img.png&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;338&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.1164%;&quot; data-widthpercent=&quot;48.68&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8xzDn/btsHEAFb7NX/e37bwZIka8buxPzxPoSaG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8xzDn%2FbtsHEAFb7NX%2Fe37bwZIka8buxPzxPoSaG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/div&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_50에서 60이 변화가 심하였다.&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;span style=&quot;color: #006dd7;&quot;&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;span style=&quot;color: #000000;&quot;&gt;Amp_0 부터 Amp_200까지의 column을 모으면 2D matrix 형태이기 때문에 이미지형태로 변환할 수 있다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;전체 200개의 주파수에 대한 데이터를 최대/최소값을 지정하여&amp;nbsp;&amp;nbsp;normalization(정규화)한 이미지를 표시&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716869225616&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# df.values는 df의 전체 column을 matrix 형태로 변환.
# Y축 방향이 시간이 되기 때문에  transpose 하여 보기 편하도록 matrix의 모양을 변경.
image_like_data = df.values.T

#최대/최소값을 지정하여 그 사이의 값이 0과 1사이가 되도록 min-max normalization을 수행합니다.
(vmax, vmin) = (2500, -1000)
norm_img = (image_like_data - vmin)/(vmax-vmin)

# min-mix normalization만을 수행하면 최대/최소값을 넘어가는 데이터 존재.
# visulization이 잘 되지 않기에 값 조절.
clipped_img = np.clip(0,1, norm_img)

# GPR sensor 데이터를 이미지 형태로 변환한 결과를 출력.
plt.figure(figsize=(32, 4))
plt.imshow(clipped_img, cmap='gray', vmax=1, vmin=0.0)
plt.axvline(x=1615) # 설명을 위한 표시 추가
plt.tight_layout()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQAqKX/btsHEwJBCNK/VXzZJPQbaPVeEAVkC5OAe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQAqKX/btsHEwJBCNK/VXzZJPQbaPVeEAVkC5OAe1/img.png&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;213&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.2716%; margin-right: 10px;&quot; data-widthpercent=&quot;57.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQAqKX/btsHEwJBCNK/VXzZJPQbaPVeEAVkC5OAe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQAqKX%2FbtsHEwJBCNK%2FVXzZJPQbaPVeEAVkC5OAe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;647&quot; height=&quot;213&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdKLaH/btsHEmHhHK5/VktYuLgK0L2OQnLxxUzaAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdKLaH/btsHEmHhHK5/VktYuLgK0L2OQnLxxUzaAk/img.png&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;220&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.5656%;&quot; data-widthpercent=&quot;42.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdKLaH/btsHEmHhHK5/VktYuLgK0L2OQnLxxUzaAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdKLaH%2FbtsHEmHhHK5%2FVktYuLgK0L2OQnLxxUzaAk%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;485&quot; height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/div&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;1615근처의 위치뿐만 아니라 다른 곳곳에서 파형이 돌출되는 현상을 볼 수 있다.&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;size18&quot;&gt;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;b&gt;2. 2차함수의 파형이 없는 이미지(normal) 200장과 파형이 있는 이미지(abnormnal) 200장으로 CNN 모델을 이용해 영상 분류 (classification)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;702&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wHnYK/btsHD74yS6q/9WecHIfoQFRdsRHgER8ymK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wHnYK/btsHD74yS6q/9WecHIfoQFRdsRHgER8ymK/img.png&quot; data-alt=&quot;normal -&amp;amp;gt; 0, abnormal -&amp;amp;gt; 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wHnYK/btsHD74yS6q/9WecHIfoQFRdsRHgER8ymK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwHnYK%2FbtsHD74yS6q%2F9WecHIfoQFRdsRHgER8ymK%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;702&quot; height=&quot;452&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;normal -&amp;gt; 0, abnormal -&amp;gt; 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716869581950&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;image_size = (201, 200)
batch_size = 8
seed = 9721&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;span style=&quot;color: #006dd7;&quot;&gt;- 과적합 방지를 위해 augmentation 수행&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716869642545&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# augmentation pipeline
data_augmentation = keras.Sequential([layers.RandomFlip(mode='horizontal'),])&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;span style=&quot;color: #006dd7;&quot;&gt;- CNN 모델 설계(간단한 Xception network를 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716869800955&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def make_model(input_shape, num_classes):
    inputs = keras.Input(shape=input_shape)
    
    # 이미지 augmentation 설정.
    x = data_augmentation(inputs)
    
    # 초기 레이어 설정하는 코드.
    x = layers.Rescaling(1.0 / 255)(x)
    x = layers.Conv2D(32, 3, strides=2, padding=&quot;same&quot;)(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation(&quot;relu&quot;)(x)

    x = layers.Conv2D(64, 3, padding=&quot;same&quot;)(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation(&quot;relu&quot;)(x)

    previous_block_activation = x  # Set aside residual

    for size in [8, 16, 32, 48]:
        x = layers.Activation(&quot;relu&quot;)(x)
        x = layers.SeparableConv2D(size, 3, padding=&quot;same&quot;)(x)
        x = layers.BatchNormalization()(x)

        x = layers.Activation(&quot;relu&quot;)(x)
        x = layers.SeparableConv2D(size, 3, padding=&quot;same&quot;)(x)
        x = layers.BatchNormalization()(x)

        x = layers.MaxPooling2D(3, strides=2, padding=&quot;same&quot;)(x)

        # Project residual
        residual = layers.Conv2D(size, 1, strides=2, padding=&quot;same&quot;)(
            previous_block_activation
        )
        x = layers.add([x, residual])  # Add back residual.
        previous_block_activation = x  # Set aside next residual

    x = layers.SeparableConv2D(128, 3, padding=&quot;same&quot;)(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation(&quot;relu&quot;)(x)

    x = layers.GlobalAveragePooling2D()(x)
    
    if num_classes == 2:
        activation = &quot;sigmoid&quot;
        units = 1
    else:
        activation = &quot;softmax&quot;
        units = num_classes

    x = layers.Dropout(0.5)(x)
    outputs = layers.Dense(units, activation=activation)(x)
    
    return keras.Model(inputs, outputs)

model = make_model(input_shape=image_size + (3,), num_classes=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;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;설계한 모델 확인하기&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716869832375&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keras.utils.plot_model(model, show_shapes=True)&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;span style=&quot;color: #006dd7;&quot;&gt; - 모델 학습.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716870016503&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;epochs = 30

# callback 함수를 정의
callbacks = [
    # 가장 결과가 좋은 Model을 best.h5로 저장합니다.
    keras.callbacks.ModelCheckpoint(&quot;./models/best.h5&quot;, save_best_only=True, monitor='val_loss'),
    
    # 학습하는 과정에서 결과의 개선이 없으면 learning rate를 조절하는 callback 함수]
    keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, 
    patience=10, verbose=0, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0),
]

model.compile(
    optimizer=keras.optimizers.Adam(1e-3),
    loss=&quot;binary_crossentropy&quot;,
    metrics=[&quot;accuracy&quot;],
)

model.fit(
    train_ds,
    epochs=epochs,
    callbacks=callbacks,
    validation_data=val_ds,
)&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;span style=&quot;color: #006dd7;&quot;&gt;- 모델 추론&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716870285549&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 가장 학습 결과가 좋은 모델을 로딩
model = tf.keras.models.load_model(&quot;./models/best.h5&quot;)

# 테스트를 위해 정상 이미지 1장와 abnormal 이미지 1장을 로딩
normal_img = keras.preprocessing.image.load_img(
    &quot;./data/labeled/normal/1613059433_516002_X_2.3793_Y_-35.1849_T_odom_20.8377_dir_-1.0_0.png&quot;, target_size=image_size
)

abnormal_img = keras.preprocessing.image.load_img(
&quot;./data/labeled/abnormal/1613059614_8893247_X_12.9562_Y_-44.8245_T_odom_35.5064_dir_-1.0_0.png&quot;, target_size=image_size
)

# 이미지를 입력하면 predict를 수행하고 그 결과를 표시하는 함수
def predict_and_show(img):
    img_array = keras.preprocessing.image.img_to_array(img)
    img_array = tf.expand_dims(img_array, 0)  # Create batch axis

    predictions = model.predict(img_array)
    score = predictions[0]
    # print(score)
    print( &quot;This image is %.2f percent abnormal and %.2f normal.&quot; % (100 * (1 - score), 100 * score))

    plt.figure()
    plt.imshow(img, cmap='gray')
    
# normal 이미지를 입력하여 결과
predict_and_show(normal_img)

# abnormal 이미지를 입력하여 결과
predict_and_show(abnormal_img)&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;span style=&quot;color: #ee2323;&quot;&gt;normal 이미지는 99.89%, abnormal 이미지는 96.67%로 추론된다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. ResNet 모델을 이용한 추론&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716870348796&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from tensorflow import Tensor
from tensorflow.keras.layers import Input, Conv2D, ReLU, BatchNormalization, AveragePooling2D, Flatten, Dense
from tensorflow.keras.models import Model

def relu_bn(inputs: Tensor) -&amp;gt; Tensor:
    relu = ReLU()(inputs)
    bn = BatchNormalization()(relu)
    return bn

def residual_block(x: Tensor, downsample: bool, filters: int, kernel_size: int = 3) -&amp;gt; Tensor:
    y = Conv2D(kernel_size=kernel_size,
               strides= (1 if not downsample else 2),
               filters=filters,
               padding=&quot;same&quot;)(x)
    y = relu_bn(y)
    y = Conv2D(kernel_size=kernel_size,
               strides=1,
               filters=filters,
               padding=&quot;same&quot;)(y)

    if downsample:
        x = Conv2D(kernel_size=1,
                   strides=2,
                   filters=filters,
                   padding=&quot;same&quot;)(x)
    out = layers.add([x, y])
    out = relu_bn(out)
    return out

def make_resnet(input_shape, num_classes):
    num_filters = 4
    inputs = keras.Input(shape=input_shape)
    # Image augmentation block
    x = data_augmentation(inputs)
    
    # Entry block
    x = layers.Rescaling(1.0 / 255)(x)
    
    x = BatchNormalization()(x)
    x = Conv2D(kernel_size=3,
               strides=1,
               filters=num_filters,
               padding=&quot;same&quot;)(x)
    x = relu_bn(x)
    
    num_blocks_list = [2, 5, 5, 2]
    for i in range(len(num_blocks_list)):
        num_blocks = num_blocks_list[i]
        for j in range(num_blocks):
            x = residual_block(x, downsample=(j==0 and i!=0), filters=num_filters)
        num_filters *= 2
        
    x = layers.GlobalAveragePooling2D()(x)
    if num_classes == 2:
        activation = &quot;sigmoid&quot;
        units = 1
    else:
        activation = &quot;softmax&quot;
        units = num_classes

    x = layers.Dropout(0.5)(x)
    outputs = layers.Dense(units, activation=activation)(x)
    return keras.Model(inputs, outputs)

resnet_model = make_resnet(input_shape=image_size + (3,), num_classes=2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716870382207&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;epochs = 20
callbacks = [
    keras.callbacks.ModelCheckpoint(&quot;./models/resnet_best.h5&quot;, save_best_only=True, monitor='val_loss'),
    keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=5, verbose=0, mode='auto', min_delta=0.00001, cooldown=0, min_lr=0),
]

resnet_model.compile(
    optimizer=keras.optimizers.Adam(1e-3),
    loss=&quot;binary_crossentropy&quot;,
    metrics=[&quot;accuracy&quot;],
)

resnet_model.fit(
    train_ds,
    epochs=epochs,
    callbacks=callbacks,
    validation_data=val_ds,
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716870407658&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;resnet_model = tf.keras.models.load_model(&quot;./models/resnet_best.h5&quot;)
normal_img = keras.preprocessing.image.load_img(
    &quot;./data/labeled/normal/1613059433_516002_X_2.3793_Y_-35.1849_T_odom_20.8377_dir_-1.0_0.png&quot;, target_size=image_size
)
abnormal_img = keras.preprocessing.image.load_img(
&quot;./data/labeled/abnormal/1613059614_8893247_X_12.9562_Y_-44.8245_T_odom_35.5064_dir_-1.0_0.png&quot;, target_size=image_size
)


def predict_and_show(img):
    img_array = keras.preprocessing.image.img_to_array(img)
    img_array = tf.expand_dims(img_array, 0)  # Create batch axis
    predictions = resnet_model.predict(img_array)
    score = predictions[0]
    print( &quot;This image is %.2f percent abnormal and %.2f normal.&quot; % (100 * (1 - score), 100 * score))
    plt.figure()
    plt.imshow(img, cmap='gray')
    
predict_and_show(normal_img)
predict_and_show(abnormal_img)&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;span style=&quot;color: #ee2323;&quot;&gt;ResNet의 경우 normal은 70.72%, abnormal은 98.55%로 추론.&lt;/span&gt;&lt;/p&gt;</description>
      <category>AI &amp;amp; Data Science/Deep Learning</category>
      <category>CNN</category>
      <category>ResNet</category>
      <category>딥러닝</category>
      <category>이미지분류</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/48</guid>
      <comments>https://ji10ji.tistory.com/48#entry48comment</comments>
      <pubDate>Tue, 28 May 2024 13:37:50 +0900</pubDate>
    </item>
    <item>
      <title>딥러닝 최적화(Optimization)</title>
      <link>https://ji10ji.tistory.com/47</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. GD vs SGD&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GD(Gradient&amp;nbsp;Descent)&amp;nbsp;는&amp;nbsp;시작&amp;nbsp;지점에서&amp;nbsp;기울기의&amp;nbsp;반대&amp;nbsp;방향으로&amp;nbsp;하강하면서&amp;nbsp;손실&amp;nbsp;함수(loss&amp;nbsp;function)를&amp;nbsp;최소화하는&amp;nbsp;지점을&amp;nbsp;찾기&amp;nbsp;위한&amp;nbsp;가장&amp;nbsp;직관적인&amp;nbsp;방법입니다.&amp;nbsp;이처럼&amp;nbsp;전체&amp;nbsp;데이터&amp;nbsp;셋을&amp;nbsp;가지고&amp;nbsp;학습하게&amp;nbsp;되면&amp;nbsp;안정적이긴&amp;nbsp;하지만,&amp;nbsp;계산량과&amp;nbsp;학습&amp;nbsp;비용이&amp;nbsp;많아지게&amp;nbsp;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;이때 전체 데이터 셋이 아닌, 무작위로 뽑은 데이터들에 대한 Gradient Descent를 진행하고, 이를 반복하며 정확도를 찾아 나가는 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;SGD&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;(&lt;/span&gt;&lt;b&gt;Stochastic Gradient Descent&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; 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 data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;데이터셋은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;IMDB 영화 리뷰 데이터 셋&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;을 사용합니다. 해당 데이터셋은 훈련용 데이터 25,000개와 테스트용 데이터 25,000개로 이루어져 있으며, 레이블은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;긍정/부정&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;으로 두 가지입니다. 이때 긍정은 1, 부정은 0으로 표시되어 있습니다. 우리의 목표는 전처리된 영화 리뷰 데이터를 가지고 그 리뷰가 긍정적인지 혹은 부정적인지를 예측하는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;GD와 SGD의 모델은 똑같이 하고 batch size를 GD는 25000, SGD 500으로 하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/691r5/btsHu4fXWyl/m1rpQCrVk6dfHUdtG1RsLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/691r5/btsHu4fXWyl/m1rpQCrVk6dfHUdtG1RsLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/691r5/btsHu4fXWyl/m1rpQCrVk6dfHUdtG1RsLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F691r5%2FbtsHu4fXWyl%2Fm1rpQCrVk6dfHUdtG1RsLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;480&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&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;scores_gd:&amp;nbsp;&amp;nbsp;0.6955338 &lt;br /&gt;scores_sgd:&amp;nbsp;&amp;nbsp;0.63184285&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;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;SGD는 손실 함수(loss function)의 최솟값에 도달하는 동안 Gradient가 진동하여 최적값에 도달하기까지의 시간이 오래 걸리는 단점을 가지고 있습니다. 이를 보완하기 위해 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;모멘텀&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;(&lt;/span&gt;&lt;b&gt;momentum&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot;&gt;) 기법은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;관성&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #151618; 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 style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SGD에서 momentum을 사용하기 위한 함수/라이브러리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tf.keras.optimizers.SGD(lr, momentum):
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lr&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 학습률 (learning rate) (lr &amp;gt;= 0), 기본값 0.1&lt;/li&gt;
&lt;li&gt;momentum&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 진동을 막아주고 SGD를 가속하는 파라미터 (momentum &amp;gt;= 0), 기본값 0.9&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716247022243&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sgd_opt = tf.keras.optimizers.SGD(lr = 0.01, momentum = 0)
sgd_model.compile(loss = 'binary_crossentropy', optimizer = sgd_opt, 
    metrics = ['accuracy', 'binary_crossentropy'])
    
msgd_opt = tf.keras.optimizers.SGD(lr = 0.01, momentum = 0.9)
msgd_model.compile(loss = 'binary_crossentropy', optimizer = msgd_opt, 
    metrics = ['accuracy', 'binary_crossentropy'])&lt;/code&gt;&lt;/pre&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;640&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRas9m/btsHukjor7E/giVKAgeK5KByteXALGoWKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRas9m/btsHukjor7E/giVKAgeK5KByteXALGoWKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRas9m/btsHukjor7E/giVKAgeK5KByteXALGoWKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRas9m%2FbtsHukjor7E%2FgiVKAgeK5KByteXALGoWKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;480&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&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;scores_sgd:&amp;nbsp;&amp;nbsp;0.62154835 &lt;br /&gt;scores_msgd:&amp;nbsp;&amp;nbsp;0.5680819&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;color: #ee2323;&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;adagrad-rmsprop-adam-최적화optimize-알고리즘&quot; style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Adagrad, RMSprop, Adam 최적화(optimize) 알고리즘&lt;/b&gt;&lt;/h4&gt;
&lt;h3 id=&quot;adagrad&quot; style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Adagrad&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Adagrad&lt;/b&gt;(&lt;b&gt;Adaptive Gradient&lt;/b&gt;) 최적화 알고리즘은 손실 함수(loss function)의 값을 최소로 만드는 최적의 가중치를 찾아내기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;learning rate를 조절&lt;/b&gt;해 하강하는 방법 중 하나입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 방식이 가중치들의 업데이트를 같은 속도로 한꺼번에 하는 방법이었다면, Adagrad는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가중치 각각의 업데이트 속도를 데이터에 맞추어&lt;/b&gt;(adaptively) 계산해 적절한 learning rate로 하강하도록 합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tf.keras.optimizers.Adagrad(lr, epsilon, decay)&lt;span&gt;&amp;nbsp;&lt;/span&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lr&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 학습률 (learning rate) (lr &amp;gt;= 0), 기본값 0.1&lt;/li&gt;
&lt;li&gt;epsilon&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 연산 시 분모가 0이 되는 것을 막는, 0에 가까운 상수 (epsilon &amp;gt;= 0), 기본값 0.000001&lt;/li&gt;
&lt;li&gt;decay&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 업데이트마다 학습률을 비율만큼 줄여주는 파라미터 (decay &amp;gt;= 0), 기본값 0.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rmsprop&quot; style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;RMSprop&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RMSprop&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;최적화 알고리즘은 학습이 진행될수록 가중치 업데이트 강도가 약해지는 Adagrad의 단점을 보완하고자 제안된 방법입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RMSProp은 과거의 gradient 값은 잊고 새로운 gradient 값을 크게 반영해서 가중치를 업데이트합니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;RMSprop&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tf.keras.optimizers.RMSprop(lr)&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;/li&gt;
&lt;li&gt;lr : 학습률, 기본값 0.1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;adam&quot; style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Adam&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Adam&lt;/b&gt;은 최적화 알고리즘 중 가장 발전된 기법입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;RMSProp과 모멘텀(momentum)을 함께 사용&lt;/b&gt;함으로써, 진행 방향과 learning rate 모두를 적절하게 유지하면서 학습할 수 있도록 고안되었습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Adam&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #151618; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tf.keras.optimizers.Adam(lr, beta_1, beta_2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;/li&gt;
&lt;li&gt;lr&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 학습률, 기본값 0.01&lt;/li&gt;
&lt;li&gt;beta_1&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 모멘텀을 결정하기 위해 사용하는 파라미터 (beta_1 &amp;gt;= 0 ), 기본값 0.9&lt;/li&gt;
&lt;li&gt;beta_2&lt;span&gt;&amp;nbsp;&lt;/span&gt;: step size를 결정하기 위해 사용하는 파라미터 (beta_2 &amp;gt;= 0), 기본값 0.999&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV9atV/btsHu56Qtb5/05cH4HRg4GMuNTkf7q9P31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV9atV/btsHu56Qtb5/05cH4HRg4GMuNTkf7q9P31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV9atV/btsHu56Qtb5/05cH4HRg4GMuNTkf7q9P31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV9atV%2FbtsHu56Qtb5%2F05cH4HRg4GMuNTkf7q9P31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;480&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;480&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;scores_adagrad:&amp;nbsp;&amp;nbsp;0.6945019 &lt;br /&gt;scores_rmsprop:&amp;nbsp;&amp;nbsp;0.6222704 &lt;br /&gt;scores_adam:&amp;nbsp;&amp;nbsp;0.6003031&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;Adam의&amp;nbsp;성능이&amp;nbsp;제일&amp;nbsp;좋고,&amp;nbsp;그&amp;nbsp;다음&amp;nbsp;RMSProp,&amp;nbsp;Adagrad&amp;nbsp;순으로&amp;nbsp;성능이&amp;nbsp;좋다고&amp;nbsp;알려져&amp;nbsp;있습니다.&lt;/p&gt;</description>
      <category>AI &amp;amp; Data Science/Deep Learning</category>
      <category>딥러닝</category>
      <category>최적화</category>
      <category>파이썬</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/47</guid>
      <comments>https://ji10ji.tistory.com/47#entry47comment</comments>
      <pubDate>Tue, 21 May 2024 13:05:07 +0900</pubDate>
    </item>
    <item>
      <title>[Tensorflow] 딥러닝 모델 구현하기</title>
      <link>https://ji10ji.tistory.com/46</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;*epoch&amp;nbsp;:&amp;nbsp;한&amp;nbsp;번의&amp;nbsp;epoch는&amp;nbsp;전체&amp;nbsp;데이터&amp;nbsp;셋에&amp;nbsp;대해&amp;nbsp;한&amp;nbsp;번&amp;nbsp;학습을&amp;nbsp;완료한&amp;nbsp;상태 &lt;br /&gt;*batch : 나눠진 데이터 셋(보통 mini-batch라고 표현) &lt;br /&gt;*iteration : epoch를 나누어서 실행하는 횟수를 의미 &lt;br /&gt;*units : 레이어 안의 Node의 수&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;b&gt;1. 선형회귀 구현하기&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716175606948&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

from elice_utils import EliceUtils
elice_utils = EliceUtils()

np.random.seed(100)&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;1.&amp;nbsp;선형&amp;nbsp;회귀&amp;nbsp;모델의&amp;nbsp;클래스를&amp;nbsp;구현합니다. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step01.&amp;nbsp;가중치&amp;nbsp;초기값을&amp;nbsp;1.5의&amp;nbsp;값을&amp;nbsp;가진&amp;nbsp;변수&amp;nbsp;텐서로&amp;nbsp;설정하세요. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step02.&amp;nbsp;Bias&amp;nbsp;초기값을&amp;nbsp;1.5의&amp;nbsp;값을&amp;nbsp;가진&amp;nbsp;변수&amp;nbsp;텐서로&amp;nbsp;설정하세요. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step03.&amp;nbsp;W,&amp;nbsp;X,&amp;nbsp;b를&amp;nbsp;사용해&amp;nbsp;선형&amp;nbsp;모델을&amp;nbsp;구현하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716175649955&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class LinearModel:
    
    def __init__(self):
        
        self.W = tf.Variable(1.5)
        
        self.b = tf.Variable(1.5)
        
    def __call__(self, X, Y):
        
        return tf.add(tf.multiply(X, self.W), self.b)&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;2.&amp;nbsp;MSE&amp;nbsp;값을&amp;nbsp;계산해&amp;nbsp;반환하는&amp;nbsp;손실&amp;nbsp;함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716175684614&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def loss(y, pred):
    
    return tf.reduce_mean(tf.square(y-pred))&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.&amp;nbsp;gradient&amp;nbsp;descent&amp;nbsp;방식으로&amp;nbsp;학습하는&amp;nbsp;train&amp;nbsp;함수&lt;/p&gt;
&lt;pre id=&quot;code_1716175720002&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def train(linear_model, x, y):
    
    # 연산기록 
    with tf.GradientTape() as t:
        current_loss = loss(y, linear_model(x, y)) 
    
    # learning_rate 값 선언
    learning_rate = 0.001
    
    # gradient 값 계산
    delta_W, delta_b = t.gradient(current_loss, [linear_model.W, linear_model.b])
    
    # learning rate와 계산한 gradient 값을 이용하여 업데이트할 파라미터 변화 값 계산 
    W_update = (learning_rate * delta_W)
    b_update = (learning_rate * delta_b)
    
    return W_update,b_update&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716175738109&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def main():
    
    # 데이터 생성
    x_data = np.linspace(0, 10, 50)
    y_data = 4 * x_data + np.random.randn(*x_data.shape)*4 + 3
    
    # 데이터 출력
    plt.scatter(x_data,y_data)
    plt.savefig('data.png')
    elice_utils.send_image('data.png')
    
    # 선형 함수 적용
    linear_model = LinearModel()
    
    # epochs 값 선언
    epochs = 100
    
    # epoch 값만큼 모델 학습
    for epoch_count in range(epochs):
        
        # 선형 모델의 예측 값 저장
        y_pred_data=linear_model(x_data, y_data)
        
        # 예측 값과 실제 데이터 값과의 loss 함수 값 저장
        real_loss = loss(y_data, linear_model(x_data, y_data))
        
        # 현재의 선형 모델을 사용하여  loss 값을 줄이는 새로운 파라미터로 갱신할 파라미터 변화 값을 계산
        update_W, update_b = train(linear_model, x_data, y_data)
        
        # 선형 모델의 가중치와 Bias를 업데이트합니다. 
        linear_model.W.assign_sub(update_W)
        linear_model.b.assign_sub(update_b)
        
        # 20번 마다 출력 (조건문 변경 가능)
        if (epoch_count%20==0):
            print(f&quot;Epoch count {epoch_count}: Loss value: {real_loss.numpy()}&quot;)
            print('W: {}, b: {}'.format(linear_model.W.numpy(), linear_model.b.numpy()))
            
            fig = plt.figure()
            ax1 = fig.add_subplot(111)
            ax1.scatter(x_data,y_data)
            ax1.plot(x_data,y_pred_data, color='red')
            plt.savefig('prediction.png')
            elice_utils.send_image('prediction.png')

if __name__ == &quot;__main__&quot;:
    main()&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;2. 비선형회귀 구현 : 텐서플로우와 케라스를 활용하여 다층 퍼셉트론 모델&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716176991119&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tensorflow as tf
import numpy as np
from visual import *

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

np.random.seed(100)
tf.random.set_seed(100)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716175974751&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def main():
    
    # 비선형 데이터 생성
    
    x_data = np.linspace(0, 10, 100)
    y_data = 1.5 * x_data**2 -12 * x_data + np.random.randn(*x_data.shape)*2 + 0.5
    
    '''
    1. 다층 퍼셉트론 모델.
    '''
    # 첫번째만 input_dim 설정하면 됨!
    model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(20, input_dim = 1 ,activation='relu'),
    tf.keras.layers.Dense(20, activation='relu'),
    tf.keras.layers.Dense(1)
])
    
    '''
    2. 모델 학습 방법을 설정.
    '''
    
    model.compile(loss='mean_squared_error', optimizer='adam')
    
    '''
    3. 모델을 학습.
    ''' 
    
    history = model.fit(x_data, y_data, epochs=500, verbose=2)
    
    '''
    4. 학습된 모델을 사용하여 예측값 생성 및 저장
    '''
    
    predictions = model.predict(x_data)
    
    Visualize(x_data, y_data, predictions)
    
    return history, model

if __name__ == '__main__':
    main()&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>AI &amp;amp; Data Science/Deep Learning</category>
      <category>딥러닝</category>
      <category>텐서플로우</category>
      <category>파이썬</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/46</guid>
      <comments>https://ji10ji.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 20 May 2024 12:50:55 +0900</pubDate>
    </item>
    <item>
      <title>[Tesorflow] 텐서 데이터 생성</title>
      <link>https://ji10ji.tistory.com/45</link>
      <description>&lt;pre id=&quot;code_1716174208594&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '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;1. 상수 텐서를 생성하는 constant_tensors 함수.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step01. 5의 값을 가지는 (1,1) shape의 8-bit integer 텐서. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step02. 모든 원소의 값이 0인 (3,5) shape의 16-bit integer 텐서. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step03. 모든 원소의 값이 1인 (4,3) shape의 8-bit integer 텐서.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716174262033&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def constant_tensors():
    
    t1 = tf.constant(5,shape=(1,1), dtype=tf.int8)
    
    t2 = tf.zeros(shape=(3,5), dtype=tf.int16)
    
    t3 = tf.ones(shape=(4,3), dtype=tf.int8)
    
    return t1, t2, t3&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. 시퀀스 텐서를 생성하는 sequence_tensors 함수.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step01. 1.5에서 10.5까지 증가하는 3개의 텐서. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step02. 2.5에서 20.5까지 증가하는 5개의 텐서.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716174311175&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def sequence_tensors():
    
    seq_t1 = tf.range(1.5,11,4.5)
    
    seq_t2 = tf.range(2.5,21,4.5)
    
    return seq_t1, seq_t2&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. 변수를 생성하는 variable_tensor 함수. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step01. 값이 100인 변수 텐서. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step02. 모든 원소의 값이 1인 (2,2) shape의 변수 텐서.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Step03. 모든 원소의 값이 0인 (2,) shape의 변수 텐서.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1716174358351&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def variable_tensor():
    
    var_tensor = tf.Variable(initial_value = 100)
    
    W = tf.Variable(tf.ones(shape=(2,2)), name = 'W')
    
    b = tf.Variable(tf.zeros(shape=(2,)), name = 'b')
    
    return var_tensor, W, b&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;pre id=&quot;code_1716174386074&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def main():
    
    t1, t2, t3 = constant_tensors()
    
    seq_t1,seq_t2 = sequence_tensors()
    
    var_tensor, W, b = variable_tensor()
    
    constant_dict = {'t1':t1, 't2':t2, 't3':t3}
    
    sequence_dict = {'seq_t1':seq_t1, 'seq_t2':seq_t2}
    
    variable_dict = {'var_tensor':var_tensor, 'W':W, 'b':b}
    
    for key, value in constant_dict.items():
        print(key, ' :', value.numpy())
    
    print()
    
    for key, value in sequence_dict.items():
        print(key, ' :', value.numpy())
        
    print()
    
    for key, value in variable_dict.items():
        print(key, ' :', value.numpy())

if __name__ == &quot;__main__&quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI &amp;amp; Data Science/Deep Learning</category>
      <category>딥러닝</category>
      <category>텐서플로우</category>
      <category>파이썬</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/45</guid>
      <comments>https://ji10ji.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 20 May 2024 12:15:48 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 프로그래머스 / level 4 / Union / 쿼리 결과 합치기 / 온라인/오프라인 판매 데이터 통합하기</title>
      <link>https://ji10ji.tistory.com/44</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;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131537#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/131537#qna&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714193546021&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131537#qna&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Cumt9/hyVVIu72r3/97kRPKVqaNQyakkL2bBCK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhPrr7/hyVVy0nZ9x/OWqatxWgJqYRXKKvwuYZ3K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131537#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131537#qna&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Cumt9/hyVVIu72r3/97kRPKVqaNQyakkL2bBCK0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bhPrr7/hyVVy0nZ9x/OWqatxWgJqYRXKKvwuYZ3K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&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;programmers.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;
&lt;pre id=&quot;code_1714193507769&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DATE_FORMAT(SALES_DATE,'%Y-%m-%d') AS SALES_DATE,
PRODUCT_ID, USER_ID, SALES_AMOUNT
FROM ONLINE_SALE
WHERE SALES_DATE LIKE '2022-03%'

UNION 

SELECT DATE_FORMAT(SALES_DATE,'%Y-%m-%d') AS SALES_DATE,
PRODUCT_ID, NULL, SALES_AMOUNT
FROM OFFLINE_SALE

WHERE SALES_DATE LIKE '2022-03%'
ORDER BY SALES_DATE, PRODUCT_ID, USER_ID ;&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;UNION의 경우에는 &quot;중복제거', UNION ALL은 &quot;중복허용&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OFFLINE_SALE 데이터에 USER_ID가 없기 때문에 NULL이라고 두기!&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;WHERE은 두개 모두에 쓰고 ORDER는 한번만 써도 되는 듯&lt;/p&gt;</description>
      <category>Coding Test/MySQL</category>
      <category>SQL</category>
      <category>코테</category>
      <category>프로그래머스</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/44</guid>
      <comments>https://ji10ji.tistory.com/44#entry44comment</comments>
      <pubDate>Sat, 27 Apr 2024 13:53:44 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 프로그래머스 / LIMIT / 조건에 맞는 개수만 출력하기</title>
      <link>https://ji10ji.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/298517#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/298517#qna&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1714093156763&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;프로그래머스&quot; data-og-description=&quot;코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/298517#qna&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6kjSc/hyVS7QyQdC/nHQmVIIVmce6yAKhHYEaJ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/WHLuQ/hyVS8BVQIA/kdiNVxf3hm1Oxo2aRUGKLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/298517#qna&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/298517#qna&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6kjSc/hyVS7QyQdC/nHQmVIIVmce6yAKhHYEaJ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/WHLuQ/hyVS8BVQIA/kdiNVxf3hm1Oxo2aRUGKLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로그래머스&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;programmers.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;은근히 쉬워보이지만 10개만 출력을 어떻게 하는지 감이 오지 않았다;;(나만 그럴수도 ;_;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714093079140&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT ID, LENGTH
FROM FISH_INFO
ORDER BY LENGTH DESC, ID
LIMIT 10&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;ORDER BY를 통해 LENGTH로 내림차순이 되기 때문에 LIMIT을 이용해서 가장 긴 10마리까지만 구할 수 있게 된다!&lt;/p&gt;</description>
      <category>Coding Test/MySQL</category>
      <category>SQL</category>
      <category>코테</category>
      <category>프로그래머스</category>
      <author>지으니어스</author>
      <guid isPermaLink="true">https://ji10ji.tistory.com/43</guid>
      <comments>https://ji10ji.tistory.com/43#entry43comment</comments>
      <pubDate>Fri, 26 Apr 2024 09:59:57 +0900</pubDate>
    </item>
  </channel>
</rss>