<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>유딩월드</title>
    <link>https://dldbwls0818.tistory.com/</link>
    <description>열심히 하자 </description>
    <language>ko</language>
    <pubDate>Wed, 3 Jun 2026 19:40:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dldbwls0818</managingEditor>
    <image>
      <title>유딩월드</title>
      <url>https://tistory1.daumcdn.net/tistory/7337440/attach/bae1f7a02d444328a204e47bad61a1da</url>
      <link>https://dldbwls0818.tistory.com</link>
    </image>
    <item>
      <title>자연어처리(NLP)</title>
      <link>https://dldbwls0818.tistory.com/53</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 자연어처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자연어 처리(Natural Language Processing, NLP)는 컴퓨터가 인간의 언어를 이해하고 처리하며 생성할 수 있도록 돕는 AI 기술 분야입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 텍스트나 음성 데이터를 분석하고, 번역, 요약, 감정 분석, 질의 응답, 음성인식 등 다양한 작업을 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자연어 처리는 언어학, 컴퓨터 과학, 인공지능의 융합으로 이루어지며, 형태소 분석, 구문 분석, 의미 분석 등 여러 단계를 포함합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최근에는 딥러닝 기술과 대규모 언어 모델의 발전으로 자연어 처리 성능이 크게 향상되어 챗봇, 검색 엔진, 추천 시스템과 같은 실생활에서 널리 사용되고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 한국어 자연어 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(한국어의 고유한 언어적 특성과 구조적인 복합성 때문에 한국어 자연어 처리가 영어보다 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-1. 교착어의 특성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국어는 어미와 접사가 붙는 교착어로, 하나의 단어에 여러 문법적 정보가 포함됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;가다&quot;라는 기본 동사에 &quot;갔습니다&quot;, &quot;가겠다&quot;, &quot;가더라&quot; 등등 다양한 어미가 붙어 형태가 복잡하게 변화하는데 이는 형태소 분석을 어렵게 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-2. 어순의 유연성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국어는 주어-목적어-동사(SOV) 구조를 기본으로 하지만, 어순이 비교적 자유로워 맥락에 따라 문장이 달라질 수 있는데 이는 문장의 구문 분석을 어렵게 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나는 운동을 했어. 체육관에서&lt;/li&gt;
&lt;li&gt;나는 체육관에서 운동을 했어&lt;/li&gt;
&lt;li&gt;체육관에서 나는 운동을 했어&lt;/li&gt;
&lt;li&gt;나는 운동을 체육관에서 했어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-3. 단어의 경계가 모호함&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영어는 공백으로 단어를 구분하지만, 한국어는 조사와 어미가 붙는 단어 경계가 명확하지 않은 경우가 많아 단어를 분리하는 작업(형태소 분석)이 까다롭습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이렇게띄어쓰기를전혀하지않고글을썼다고하더라도글을쉽게이해할수있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-4. 높임말과 다양한 표현방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국어에는 다양한 높임말과 경어체가 있어, 같은 의미를 여러가지 방식으로 표현할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;먹다&quot;는 &quot;드시다&quot;, &quot;잡수시다&quot; 등으로 변화하며, 이러한 다양성을 처리하기 위해 추가적인 맥락 분석이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2-5. 어휘적 중의성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한국어는 같은 발음이나 형태를 가진 단어가 여러 의미를 가지는 경우가 많아, 문맥에 따른 의미 해석이 어렵습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;배&quot;는 &lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;'사람&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;배', '배(船)', '배(梨)' 등 다양한 의미를 가집니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 토큰화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 토큰화(Tokenization)는 텍스트 데이터를 분석하거나 처리하기 위해 문장을 의미 있는 단위로 나누는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 단위는 단어, 어절, 형태소, 또는 문자 단위일 수 있으며, NLP의 기초 단계로 매우 중요한 역할을 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영어에서는 공백이나 구두점을 기준으로 단어를 나누는 것이 일반적이지만, 한국어나 일본어처럼 공백이 명확하지 않은 단어에서는 형태소 분석기를 사용하여 어절이나 형태소 단위로 나누는 작업이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3-1. 문장 토큰화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문장 토큰화는 텍스트를 문장 단위로 나누는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일반적으로 마침표(.), 물음표(?), 느낌표(!) 와 같은 문장부호를 기준으로 문장을 구분합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;안녕하세요. 오늘 날씨가 좋네요!&quot; 라는 문장은 &quot;안녕하세요.&quot;와 &quot;오늘 날씨가 좋네요!&quot;로 나눌 수 있습니다.&lt;/li&gt;
&lt;li&gt;하지만 약어(ex : &quot;Dr&quot;, &quot;Mr&quot;)나 숫자(ex : &quot;3.14&quot;) 처럼 마침표를 포함하지만 문장 경계가 아닌 경우를 처리해야 하므로 복잡한 규칙이나 모델이 필요합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 문장 토큰화는 문서 요약, 감정 분석, 번역 등의 작업에서 중요한 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(한국어에서의 문장 토크나이저로 'KSS'를 추천합니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740828194720&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 마침표를 기준으로 split메서드로 나누기
sentence = 'Yonsei University is a private research university in Seoul, South Korea. Yonsei University is deemed as one of the three most prestigious institutions in the country. It is particularly respected in the studies of medicine and business administration.'
sentence.split('. ')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740828339191&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 자연어 처리 패키지인 NLTK를 활용하여 나누기
import nltk
from nltk.tokenize import sent_tokenize

sentence = &quot;His barber kept his word. But keeping such a huge secret to himself was driving him crazy. Finally, the barber went up a mountain and almost to the edge of a cliff. He dug a hole in the midst of some reeds. He looked about, to mae sure no one was near.&quot;
print(sent_tokenize(sentence))&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;size18&quot;&gt;&lt;b&gt;※ punkt&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- NLTK 라이브러리에서 사용하는 명령어로 특정 언어의 구두점을 기준으로 문장을 나누거나, 단어를 나누는 데 도움을 주는 알고리즘을 포함하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자연어 처리 작업에서 텍스트를 효과적으로 분석하고 처리할 수 있게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740828681619&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 코랩 환경에서는 이미 punkt이 기본적으로 다운로드 되어 있지만
# tab을 처리하는 부분은 없기 때문에 다운로드 함
nltk.download('punkt_tab')

# 다음과 같이 nltk의 Tokenizer를 사용하면 약어도 처리할 수 있음
sentence=&quot;I am actively looking for Ph.D. students. and you are a Ph.D student.&quot;
print(sent_tokenize(sentence))&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;size18&quot;&gt;&lt;b&gt;※ 한국어 토크나이징&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740828742727&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!pip install kss&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740828754075&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import kss

text = '딥 러닝 자연어 처리가 재미있기는 합니다. 그런데 문제는 영어보다 한국어로 할 때 너무 어려워요. 이제 해보면 알걸요?'
print(kss.split_sentences(text))&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;size18&quot;&gt;&lt;b&gt;3-2. 단어 토큰화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단어 토큰화는 문장을 단어 또는 어절 단위로 나누는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영어와 같이 공백이 단어 경계를 나타내는 언어에서는 비교적 간단히 처리할 수 있디만, 한국어나 일본어처럼 단어의 경계가 명확하지 않은 언어에서는 형태소 분석기를 사용해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;나는 학교에 간다&quot;를 단어 토큰화 하면 [&quot;나&quot;, &quot;는&quot;, &quot;학교&quot;, &quot;에&quot;, &quot;간다&quot;]와 같이 나눌 수 있습니다.&lt;/li&gt;
&lt;li&gt;&quot;preprocessing&quot; 같은 단어를 다룰 때 서브워드 토큰화를 사용해 &quot;pre&quot;, &quot;process&quot;, &quot;ing&quot;로 나누기도 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 단어 토큰화는 텍스트를 수치화 하거나 분석하기 위한 기초 단계로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;＠ 보통 과정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;문장 토큰화 -&amp;gt; 단어 토큰화 -&amp;gt; 문자를 숫자화 -&amp;gt; 모델 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;※ Punkt Tokenizer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Punkt Tokenizer는 문장 토큰화(Sentence Tokenization)와 단어 토큰화(Word Tokenization)를 수행하는 데 사용되는 패키지 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Punkt Tokenizer는 언어 독립적인 방식으로 설계되었으며, 구두점과 텍스트 패턴을 기반으로 문장을 구분하거나 단어를 추출합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/59bUl/btsMAVX0ZPb/Mw0KcmDGZieN3BCLyBuwKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/59bUl/btsMAVX0ZPb/Mw0KcmDGZieN3BCLyBuwKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/59bUl/btsMAVX0ZPb/Mw0KcmDGZieN3BCLyBuwKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F59bUl%2FbtsMAVX0ZPb%2FMw0KcmDGZieN3BCLyBuwKk%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;799&quot; height=&quot;312&quot; data-origin-width=&quot;799&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1740829128192&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from nltk.tokenize import word_tokenize
from nltk.tokenize import WordPunctTokenizer

sentence = &quot;Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop.&quot;
print(word_tokenize(sentence))
print(WordPunctTokenizer().tokenize(sentence))

# 출력 예시를 통해 토크나이징 방식이 조금 다른 것을 확인할 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740829390167&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sentence = &quot;A Dog Run back corner near spare bedrooms... bedrooms!!&quot;

print(word_tokenize(sentence))
print(sentence.split())

# NLP 모델에 집어넣기 전 수치화를 시키게 되는데 !!가 붙은 것도 하나의 단어로 생각함
# 올바르지 못한 방법(재활용을 할 수 없고, vocab의 메모리 낭비가 발생 할 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 형태소 분석기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 교착어인 한국어의 특성으로 인해 한국어 토크나이저 형태소 분석기를 사용하는 것이 보편적입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Mecab&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;빠르고 정확하며 대규모 데이터 처리에 적합하지만, Windows 설치가 복잡함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kkma&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;세밀한 분석과 구문 분석에 유리하지만 속도가 느리고 결과가 복잡함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hannanum&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;구문 및 통계 분석을 지원하나 처리 속도가 느리고 오류 가능성이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Komoran&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;안정적이고 빠르며 사전 확장이 쉬우나 복잡한 문장에서 정확도가 떨어질 수 있음&lt;/li&gt;
&lt;li&gt;사전 확장이 쉽다 = 사전을 수정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Open Korean Text(OKT)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SNS와 비표준 언어 처리에 강하며 빠르지만, 문어체 분석 정확도는 낮음&lt;/li&gt;
&lt;li&gt;Twitter Data가 기반이기 떄문에 문어체 정확도는 낮을 수 있지만 실생활 언어 분석에는 굉장히 좋을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Konlpy&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;다양한 분석기를 통합 제공하며 Python 친화적이나 분석기 성능 차이가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Khaiii&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Kakao에서 개발한 형태소 분석기로 딥러닝 기반 기술을 사용하여 높은 정확도를 제공&lt;/li&gt;
&lt;li&gt;하지만 속도는 전통적인 분석기보다 느릴 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Soynlp&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;사전(vocab)없이 비지도 학습 방식으로 토큰화를 수행하며, 신조어 및 형태소 경계 추출에 강점&lt;/li&gt;
&lt;li&gt;그러나 대량 데이터 처리 시 속도가 느릴 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;모든 형태소 사용하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1740829907338&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 영어에 NLTK가 있다면, 한국어에는 형태소 분석기 패키지인 KoNLPy(코엔엘파이)가 있음
!pip install konlpy&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740829935606&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Colab에 Mecab 설치
# 설치 후 [런타임] -&amp;gt; [세션 다시 시작 및 모두 실행]을 해야 함
!git clone https://github.com/SOMJANG/Mecab-ko-for-Google-Colab.git
%cd Mecab-ko-for-Google-Colab
!bash install_mecab-ko_on_colab_light_220429.sh&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1740829987994&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from konlpy.tag import *

hannanum = Hannanum()
kkma = Kkma()
komoran = Komoran()
okt = Okt()
mecab = Mecab()

# nouns : 명사 추출
# morphs : 최소 단위로 문장을 쪼갬
# pos : 형태소로 나누고 각 품사 정보를 Tagging

print('OKT-----------------------------')
print(okt.nouns(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(okt.morphs(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(okt.pos(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print('kkma-----------------------------')
print(kkma.nouns(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(kkma.morphs(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(kkma.pos(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print('Komoran-----------------------------')
print(komoran.nouns(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(komoran.morphs(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(komoran.pos(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print('Hannanum-----------------------------')
print(hannanum.nouns(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(hannanum.morphs(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(hannanum.pos(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print('Mecab-----------------------------')
print(mecab.nouns(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(mecab.morphs(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))
print(mecab.pos(&quot;열심히 코딩한 당신, 연휴에는 여행을 가봐요&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 결과 해석&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 형태소 분석기는 성능과 결과가 다르게 나오기 때문에, 형태소 분석기의 선택은 사용하고자 하는 필요 용도에 어떤 형태소 분석기가 가장 적절한지를 판단하고 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 속도를 가장 우선시 한다면 Mecab을 사용할 수 있습니다.&lt;/p&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/53</guid>
      <comments>https://dldbwls0818.tistory.com/53#entry53comment</comments>
      <pubDate>Sat, 1 Mar 2025 20:57:33 +0900</pubDate>
    </item>
    <item>
      <title>Alien vs Predator 데이터셋(Binary Classification)</title>
      <link>https://dldbwls0818.tistory.com/52</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Alien vs predator 데이터셋&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Alien vs predator 데이터셋은 컴퓨터 비전과 이미지 분류 모델을 학습시키기 위해 제공되는 소규모 데이터셋입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 영화 속 캐릭터인 Alien(에일리언)과 Predator(프레데터)의 이미지로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이데이터를 통해 두 클래스를 분류하는 이미지 분류 모델을 학습시킬 수 있습니다.&lt;/p&gt;
&lt;div id=&quot;code_1738595289084&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://www.kaggle.com/datasets/pmigdal/alien-vs-predator-images' target='_blank'&amp;gt;Alien vs Predetor DataSet&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/datasets/pmigdal/alien-vs-predator-images&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Alien vs Predetor DataSet&lt;/a&gt;&lt;/div&gt;
&lt;pre id=&quot;code_1738605316433&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!kaggle datasets download pmigdal/alien-vs-predator-images&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738605324249&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;!unzip -q alien-vs-predator-images.zip&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. AlexNet을 활용한 Alien vs Predator 분류&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738605367898&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;모델 전처리&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738605392574&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;device = 'cuda' if torch.cuda.is_available() else 'cpu'

data_transforms = {
    'train' : transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.RandomAffine(0, shear=10, scale=(0.8, 1.2)),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor()
    ]),
    'validation' : transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor()
    ])
}

def target_transforms(target) :
    return torch.FloatTensor([target])
    
image_datasets = {
    'train' : datasets.ImageFolder('data/train', data_transforms['train'], target_transform=target_transforms),
    'validation' : datasets.ImageFolder('data/validation', data_transforms['validation'], target_transform=target_transforms)
}

dataloaders = {
    'train' : DataLoader(
        image_datasets['train'],
        batch_size=32,
        shuffle=True
    ),
    'validation' : DataLoader(
        image_datasets['validation'],
        batch_size=32,
        shuffle=False
    )
}

imgs, labels = next(iter(dataloaders['train']))
fig, axes = plt.subplots(4, 8, figsize=(16, 8))

for ax, img, label in zip(axes.flatten(), imgs, labels):
    ax.imshow(img.permute(1, 2, 0)) # (3, 224, 224) -&amp;gt; (224, 224, 3)
    ax.set_title(label.item())
    ax.axis('off')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 전이 학습&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 전이 학습(Transfer Learning)은 이미 학습된 모델(주로 대규모 데이터셋에서 사전 학습된 딥러닝 모델)을 새로운 문제에 적용하여 학습 시간을 단축하고 성능을 향상시키는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기존 모델이 학습한 Feature를 활용해, 새로운 데이터셋에서 모델의 일부(주로 마지막 레이어)만 다시 학습하거나 추가 학습(Fine-Tuning)을 진행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특히 데이터가 적거나 학습 리소스가 제한된 상황에서 효과적이며, 이미지 분류(ex: ResNet, VGG), 자연어처리(ex: BERT, GPT) 등 다양한 분야에서 널리 사용됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ywgv8/btsL6n17l2g/4CeZo4HdTpby7IOGNXWVz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ywgv8/btsL6n17l2g/4CeZo4HdTpby7IOGNXWVz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ywgv8/btsL6n17l2g/4CeZo4HdTpby7IOGNXWVz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYwgv8%2FbtsL6n17l2g%2F4CeZo4HdTpby7IOGNXWVz0%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;481&quot; height=&quot;276&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;※ ImageNet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ImagNet은 대규모 이미지 데이터셋으로, 컴퓨터 비전 연구와 딥러닝 모델 학습에 널리 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2009년 스탠포드 대학의 페이페이 리 교수팀이 구축했으며, 약 1,400만 장의 이미지와 22,000개 이상의 카테고리로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 중, 가장 널리 사용되는 ILSVRC 버전은 약 1,000개의 클래스와 120만 장의 이미지를 포함합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ImageNet은 모델이 객체를 분류하고 특징을 학습하는 데에 필요한 풍부한 데이터와 레이블을 제공하며, ResNet, VGG, Inception 등 여러 혁신적인 모델이 ImageNet 대회를 통해 개발되었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738605849532&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 제공하는 alexnet의 가중치를 ImageNet의 가중치로 사용
model = models.alexnet(weights='IMAGENET1K_V1').to(device)&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;size18&quot;&gt;&lt;b&gt;※ Model Freezing&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Model Freezing은 Transfer Learning에서 사전 학습된 모델의 일부 또는 전체 계층의 가중치를 고정하여 학습되지 않도록 설정하는 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 사전 학습된 모델의 초기 계층(Convolutional Layers 등)은 일반적인 특징(ex: 가장자리, 패턴)을 학습했으므로 고정하고, 새로운 데이터셋에 특화된 특징을 학습하기 위해 최상위 계층(분류 헤드 등)만 학습합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 방법은 학습할 가중치의 수를 줄여 계산 비용을 절감하고, Overfitting을 방지하며, 데이터가 부족한 상황에서 특히 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필요에 따라, 초기 학습이 끝난 후 일부 계층을 고정 해제(Fine-Tuning)하여 모델을 더 정교하게 조정할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738606194042&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for param in model.parameters() :
	# 파라미터를 갱신하지 않겠다. 수식 누적도 X
    param.requires_grad = False

model.classifier = nn.Sequential(
	nn.Linear(256 * 6 * 6, 128),
    nn.ReLU(),
    nn.Linear(128, 1),
    nn.Sigmoid()
).to(device)

print(model)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;모델 학습&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738606673096&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Output Layer(FC Layer 등)를 전이 학습 시키기 위해 classifier를 명시함
optimizer = optim.Adam(model.classifier.parameters(), lr=0.001)
epochs = 10

for epoch in range(epochs) :
    for phase in ['train', 'validation'] :
        if phase == 'train' :
            model.train()
        else :
            model.eval()

        sum_losses = 0
        sum_accs = 0

        for x_batch, y_batch in dataloaders[phase] :
            x_batch = x_batch.to(device)
            y_batch = y_batch.to(device)

            y_pred = model(x_batch)
            loss = nn.BCELoss()(y_pred, y_batch)

            if phase == 'train' :
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

            sum_losses += loss
            y_bool = (y_pred &amp;gt;= 0.5).float()
            acc = (y_batch == y_bool).float().sum() / len(y_batch) * 100
            sum_accs += acc

        avg_loss = sum_losses / len(dataloaders[phase])
        avg_acc = sum_accs / len(dataloaders[phase])
        print(f'{phase:10s}: Epoch {epoch+1:4d}/{epochs} Loss: {avg_loss:.4f} Accuracy: {avg_acc:.2f}%')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Validation 폴더내에 있는 Alien, Predator 이미지를 학습된 모델에 넣어 예측해보기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738606702602&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from PIL import Image

img1 = Image.open('/content/data/validation/alien/55.jpg')
img2 = Image.open('/content/data/validation/predator/55.jpg')

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(img1)
axes[0].axis('off')
axes[1].imshow(img2)
axes[1].axis('off')
plt.show()

img1_input = data_transforms['validation'](img1)
img2_input = data_transforms['validation'](img2)

test_batch = torch.stack([img1_input, img2_input])
test_batch = test_batch.to(device)
test_batch.shape

y_pred = model(test_batch)

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].set_title(f'{(1-y_pred[0, 0])*100:.2f}% Alien, {(y_pred[0, 0])*100:.2f}% Prediator')
axes[0].imshow(img1)
axes[0].axis('off')

axes[1].set_title(f'{(1-y_pred[1, 0])*100:.2f}% Alien, {(y_pred[1, 0])*100:.2f}% Prediator')
axes[1].imshow(img2)
axes[1].axis('off')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외부 이미지 다운로드 후 예측하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738606880909&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;img1 = Image.open('/content/Alien_test.jpg')
img2 = Image.open('/content/predator_test.jpg')

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].imshow(img1)
axes[0].axis('off')
axes[1].imshow(img2)
axes[1].axis('off')
plt.show()

img1_input = data_transforms['validation'](img1)
img2_input = data_transforms['validation'](img2)

test_batch = torch.stack([img1_input, img2_input])
test_batch = test_batch.to(device)
test_batch.shape

y_pred = model(test_batch)

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
axes[0].set_title(f'{(1-y_pred[0, 0])*100:.2f}% Alien, {(y_pred[0, 0])*100:.2f}% Prediator')
axes[0].imshow(img1)
axes[0].axis('off')

axes[1].set_title(f'{(1-y_pred[1, 0])*100:.2f}% Alien, {(y_pred[1, 0])*100:.2f}% Prediator')
axes[1].imshow(img2)
axes[1].axis('off')&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/52</guid>
      <comments>https://dldbwls0818.tistory.com/52#entry52comment</comments>
      <pubDate>Tue, 4 Feb 2025 03:22:19 +0900</pubDate>
    </item>
    <item>
      <title>Alexnet 구현하기</title>
      <link>https://dldbwls0818.tistory.com/51</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Alexnet&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Alexnet은 2012년 &lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;ILSVRC(ImageNet Large Scale Visual Recognition Challenge)에서 우승한 딥러닝 모델로, 딥러닝의 대중화를 이끈 중요한 CNN입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;- 8개의 layer(5개의 Convolution layer와 3개의 FC layer)로 구성되어 있으며, ReLU 활성화 함수, Dropout, 데이터 증강 등을 사용해 Overfitting을 방지하고 학습 성능을 향상시켰습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;- Alexnet은 대규모 데이터셋과 GPU 병렬 연산을 활용해 1,000개의 클래스 분류 문제에서 top-1, top-5 error rates가 각각 37.5%, 17.5%로 뛰어난 성능을 보여, 컴퓨터 비전에서 딥러닝이 표준 기법으로 자리 잡는 데에 기여했습니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;- 이 성과는 당시 매우 뛰어난 결과였고 이전에 사용된 전통적인 머신러닝 방법론보다 훨씬 큰 차이로 성능을 끌어올리며, 딥러닝의 가능성을 보여주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;code_1738441758853&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://papers.nips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf' target='_blank'&amp;gt;AlexNet 논문&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://papers.nips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AlexNet 논문&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lCFdB/btsL3qeJEQ7/DBFYGOBgCG9nJtV0srryL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lCFdB/btsL3qeJEQ7/DBFYGOBgCG9nJtV0srryL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lCFdB/btsL3qeJEQ7/DBFYGOBgCG9nJtV0srryL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlCFdB%2FbtsL3qeJEQ7%2FDBFYGOBgCG9nJtV0srryL1%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;765&quot; height=&quot;417&quot; data-origin-width=&quot;765&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ ImageNet LSVRC&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-ImageNet LSVRC는&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Large Scale Visual Recognition Challenge의 약자로, 이미지 인식 및 분류 기술을 겨루는 대회입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: start;&quot;&gt;- 2010년부터 매년 개최되었으며, ImageNet이라는 대규모 이미지 데이터셋을 기반으로 참가자들이 다양한 모델을 설계하고 경쟁했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ImageNet 데이터셋 : 약 1400만 장의 이미지를 포함하며, 1000개의 클래스로 분류된 데규모 이미지 데이터셋입니다.&lt;/li&gt;
&lt;li&gt;목적 : 컴퓨터 비전 및 딥러닝 기술의 발전을 촉진하고, 이미지 인식 분야에서 혁신적인 기술을 발견하는 것이 목표였습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ Error Rate&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지 분류 모델의 성능을 평가하는 지표로, 모델이 이미지를 얼마나 정확히 분류했는지를 나타냅니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Top-1 Error Rate&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;모델이 예측 가능한 가장 높은 확률의 클래스(Top-1)가 정답이 아닐 확률입니다.&lt;/li&gt;
&lt;li&gt;ex) 이미지에 '고양이'가 있고, 모델이 가장 높은확률로 '강아지'라고 예측했다면, Top-1 Error입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Top-2 Error Rate&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;모델이 예측한 상위 5개의 클래스 중 하나라도 정답에 포함되지 않았을 확률입니다.&lt;/li&gt;
&lt;li&gt;ex) 이미지가 '고양이'인데 모델이 '강아지','토끼','고양이','호랑이','여우'를 상위 5개로 예측했다면, 이건 정답으로 간주됩니다.&lt;/li&gt;
&lt;li&gt;Top-5를 사용하는 이유 : 사람들이 보기에 유사한 클래스(ex: 치타와 표범)를 분류하는 것은 어렵기 때문에, 상위 5개 중에 정답이 있는지 확인하는 방식으로 보다 실용적인 성능을 평가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. CIFAR 데이터셋&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CIFAR 데이터셋은 torchvision 라이브러리에서 제공하는 이미지 데이터셋으로, 주로 딥러닝 모델의 학습 및 평가에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CIFAR-10과 CIFAR-100 두 종류가 있으며, 각각 10개와 100개의 클래스에 대해 32x32 크기의 컬러 이미지로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CIFAR-10은 클래스당 6000개(총 60,000개)의 이미지로 이루어져 있으며, CIFAR-100은 클래스당 600개(총 60,000개)로 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- PyTorch는 torchvision.datasets 모듈을 통해 이 데이터셋을 쉽게 불러올 수 있으며, 학습/테스트 데이터셋 분리, 데이터 증강, 정규화 등의 전처리를 지원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CIFAR 데이터셋은 이미지 분류 알고리즘을 실험하고 비교하는 데에 널리 사용됩니다.&lt;/p&gt;
&lt;div id=&quot;code_1738442377318&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://pytorch.org/vision/stable/datasets.html' target='_blank'&amp;gt;PyTorch의 Dataset들&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://pytorch.org/vision/stable/datasets.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;PyTorch의 Dataset들&lt;/a&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. AlexNet 직접 구현(CIFAR 데이터셋 사용)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738442515936&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torchvision import datasets
from torchvision.transforms import transforms
# 이미지에 효과를 넣어줄 때 사용하는 모듈
from torchvision.transforms.functional import to_pil_image&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738442524710&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_img = datasets.CIFAR10(
    root = 'data',
    train=True, # train용 데이터만 다운받기
    download=True,
    transform=transforms.ToTensor()
)

test_img = datasets.CIFAR10(
    root = 'data',
    train=False, # test용 데이터만 다운받기
    download=True,
    transform=transforms.ToTensor()
)

# Normalize 할 때 이미지에 맞는 맞춤형 값 구하는방법
mean = train_img.data.mean(axis=(0,1,2)) / 255
std = train_img.data.std(axis=(0,1,2)) / 255

transform_train = transforms.Compose([
    transforms.ToTensor(),
     # 이미지를 랜덤하게 자르기(사이즈는 정해져있음)
    transforms.RandomCrop(size = train_img.data.shape[1], padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.Normalize(mean,std)
])

transform_test = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean,std)
])

# 이렇게도 적용이 가능함
# 중복되어도 오류가 안남
train_img = datasets.CIFAR10(
    root = 'data',
    train = True,
    download = True,
    transform = transform_train,
)

test_img = datasets.CIFAR10(
    root = 'data',
    train = False,
    download = True,
    transform = transform_test,
)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738442765832&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EPOCH = 10
BATCH_SIZE = 128
LEARNING_RATE = 1e-3
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(&quot;Using Device:&quot;, DEVICE)

train_loader = DataLoader(train_img, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_img, batch_size=BATCH_SIZE, shuffle=False)

train_features, train_labels = next(iter(train_loader))
print(f'Feature Batch Shape: {train_features.size()}')
print(f'Labels Batch Shape: {train_labels.size()}')

labels_map = {
    0: &quot;plane&quot;,
    1: &quot;car&quot;,
    2: &quot;bird&quot;,
    3: &quot;cat&quot;,
    4: &quot;deer&quot;,
    5: &quot;dog&quot;,
    6: &quot;frog&quot;,
    7: &quot;horse&quot;,
    8: &quot;ship&quot;,
    9: &quot;truck&quot;,
}

def denormalize(img, mean, std) :
    # view() : tensor의 형태를 바꿔줌
    # 3, 1, 1 -&amp;gt; 3 : 이미지 채널, 1 : 공간 차원(높이와 너비)
    mean = torch.tensor(mean).view(3, 1, 1)
    std = torch.tensor(std).view(3, 1, 1)
    return img * std + mean
    
figure = plt.figure(figsize = (8, 8))
cols, rows = 5, 5

for i in range(1, cols * rows +1):
    sample_idx = torch.randint(len(train_img), size=(1,)).item()
    img, label = train_img[sample_idx]
    img = denormalize(img, mean, std)  # Normalize 복원
    figure.add_subplot(rows, cols, i)
    plt.title(labels_map[label])
    plt.axis('off')
    # to_pil_image : 이미지 객체로 변환하는데 사용
    # 텐서형태의 이미지를 PIL이미지로 변환
    # 특징 : 0 ~ 255 또는 0 ~ 1 범위를 가져야 함
    plt.imshow(to_pil_image(img))
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738442854568&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class AlexNet(nn.Module) :
    def __init__(self, num_classes = 10) :
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),

            nn.Conv2d(96, 256, kernel_size = 3, padding = 1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),

            nn.Conv2d(256, 384, kernel_size = 3, padding = 1),
            nn.ReLU(inplace=True),

            nn.Conv2d(384, 384, kernel_size = 3, padding = 1),
            nn.ReLU(inplace=True),

            nn.Conv2d(384, 256, kernel_size = 3, padding = 1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride=2),

            )

        self.classifier = nn.Sequential(
            nn.Linear(256*4*4, 4096),
            nn.Dropout(0.5),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes)
        )

    def forward(self, x) :
        x = self.features(x)
        # flatten 직접 하기
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x
        
model = AlexNet().to(DEVICE)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738442935240&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def train(train_loader, model, loss_fn, optimizer):
    model.train()

    size = len(train_loader.dataset)

    for batch, (X, y) in enumerate(train_loader):
        X, y = X.to(DEVICE), y.to(DEVICE)
        pred = model(X)

        loss = loss_fn(pred, y)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f'loss: {loss:&amp;gt;7f}  [{current:&amp;gt;5d}]/{size:5d}')
            
def test(test_loader, model, loss_fn):
    model.eval()

    size = len(test_loader.dataset)
    num_batches = len(test_loader)
    test_loss, correct = 0, 0

    with torch.no_grad():
        for X, y in test_loader:
            X, y = X.to(DEVICE), y.to(DEVICE)
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()

    test_loss /= num_batches
    correct /= size
    print(f&quot;Test Error: \n Accuracy: {(100*correct):&amp;gt;0.1f}%, Avg loss: {test_loss:8f}\n&quot;)
    
for i in range(EPOCH) :
    print(f&quot;Epoch {i+1} \n------------------------&quot;)
    train(train_loader, model, loss, optimizer)
    test(test_loader, model, loss)
print(&quot;Done!&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. itertools&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 파이썬 표준 라이브러리 모듈로 반복과 관련된 효율적이고 고성능의 도구를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다양한 반복 가능한 객체나 순열, 조합을 생성하거나 조작하는 함수들을 포함하고 있습니다&lt;/p&gt;
&lt;pre id=&quot;code_1738443022158&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from itertools import product, permutations, combinations, islice

# product 모듈 : 데카르트 곱을 해주는 모듈
color = ['red', 'blue']
size = ['S', 'M', 'L']

result = list(product(color, size))
print(result)

# permutations 모듈 : 순열 모듈
# 중복 가능
number = [1, 2, 3]
perm = list(permutations(number, 2)) # 길이가 2인 순열 생성
print(perm)

# combinations 모듈 : 조합 모듈
# 중복 없음
letter = ['A', 'B', 'C']
comb = list(combinations(letter, 2))
print(comb)

# islice 모듈 : 슬라이싱 모듈
# 반복 가능한 객체에서 특정 구간만 슬라이싱
number = range(10)

sliced = list(islice(number, 2, 8, 2)) # 2부터 7까지 간격을 2로 설정
print(sliced)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738443068380&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import itertools

def plot_confusion_matrix(cm, target_names=None, cmap=None, normalize=True, labels=True, title='Confusion matrix') : # cm : 행렬

    # np.trace : 혼동 행렬의 대각선 요소의 합
    accuracy = np.trace(cm) / float(np.sum(cm))
    misclass = 1 - accuracy

    if cmap is None :
        cmap = plt.get_cmap('Blues')

    if normalize :
        # [:, np.newaxis] 배열의 차원을 확장하여 열 백터로 확장
        # (3,) =&amp;gt; (3, 1)
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

    plt.figure(figsize=(8, 6))
    # interpolation='nearest' : 픽셀간의 간격을 최소화
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar() # 범례를 추가

    # threshhold : 임계값
    thresh = cm.max() / 1.5 if normalize else cm.max() / 2

    if target_names is not None :
        tick_marks = np.arange(len(target_names))
        plt.xticks(tick_marks, target_names)
        plt.yticks(tick_marks, target_names)

    if labels:
        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            if normalize:
                plt.text(j, i, &quot;{:0.4f}&quot;.format(cm[i, j]),
                         horizontalalignment=&quot;center&quot;,
                         color=&quot;white&quot; if cm[i, j] &amp;gt; thresh else &quot;black&quot;)
            else:
                plt.text(j, i, &quot;{:,}&quot;.format(cm[i, j]),
                         horizontalalignment=&quot;center&quot;,
                         color=&quot;white&quot; if cm[i, j] &amp;gt; thresh else &quot;black&quot;)

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label\naccuracy={:0.4f};\
                         misclass={:0.4f}'.format(accuracy, misclass))
    plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738443087085&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.metrics import confusion_matrix

model.eval()
ylabel = []
ypred_label = []

for batch_idx, (inputs, targets) in enumerate(test_loader):
    inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)
    outputs = model(inputs)
    _, predicted = outputs.max(1)
    ylabel = np.concatenate((ylabel, targets.cpu().numpy()))
    ypred_label = np.concatenate((ypred_label, predicted.cpu().numpy()))
    
plot_confusion_matrix(cnf_matrix,  target_names=labels_map.values(),  title='Confusion matrix, trained by AlexNet')&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/51</guid>
      <comments>https://dldbwls0818.tistory.com/51#entry51comment</comments>
      <pubDate>Sun, 2 Feb 2025 05:56:12 +0900</pubDate>
    </item>
    <item>
      <title>손글씨 도형 분류하기(CNN)</title>
      <link>https://dldbwls0818.tistory.com/50</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 손글씨 도형&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그림판으로 그린 손글씨 이미지 총 300개의 이미지를 압축시켜놓은 파일입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bEk61n/btsL3jGMDUL/u7HjnmofmsGFSESuP694a0/shape.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;shape.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.20MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하던 data 폴더에 압축파일을 옮겨주세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738440061871&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Python에서 사용하는 파일 시스템 경로 변경 명령으로
# 현재 디렉토리를 변경해줍니다
%cd /content/drive/MyDrive/(상위폴더 1)/(상위폴더 2)/data&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738440084844&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 압축풀기
# -qq : quickmode 결과를 출력을 하지 않음.
!unzip -qq &quot;/content/drive/MyDrive/(상위폴더 1)/(상위폴더 2)/data/shape.zip&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738440665154&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import Dataset, DataLoader
import matplotlib.pyplot as plt

transform = transforms.Compose([
	transforms.Resize((28, 28)),
    # Grayscale(1) : 모든 이미지를 Grayscale로 변환, 0.5입력 시 50프로만 랜덤하게
    transforms.Grayscale(1),
    transforms.ToTensor(),
    # RandomInvert(1) : 모든 이미지 색상 반전, 0.5입력 시 50프로만 랜덤하게
    transforms.RandomInvert(1),
    transforms.Normalize((0.5), (0.5)),
])

train_path = '/content/drive/MyDrive/(상위폴더 1)/(상위폴더 2)/data/shape/train'
test_path = '/content/drive/MyDrive/(상위폴더 1)/(상위폴더 2)/data/shape/test'

trainset = torchvision.datasets.ImageFolder(
    root=train_path,
    transform=transform
)
testset = torchvision.datasets.ImageFolder(
    root=test_path,
    transform=transform
)
len(trainset), len(testset)

# 10번째 데이터 가져오기
trainset.__getitem__(10)

# 데이터셋의 class 확인하기
trainset.classes, testset.classes

loader = DataLoader (
    dataset = trainset,
    batch_size = 64,
    shuffle = True
)

imgs, labels = next(iter(loader))
fig, axes = plt.subplots(8, 8, figsize=(16, 16))

for ax, img, label in zip(axes.flatten(), imgs, labels):
    ax.imshow(img.reshape(28, 28), cmap='gray')
    ax.set_title(class_map[label.item()])
    ax.axis('off')
    
# 장치 확인
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. CNN 모델 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1738440959672&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ConvNeuralNetwork(nn.Module) :
	def __init__(self) :
    	super(ConvNeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.classifier = nn.Sequential(
        	# Conv layer 1
            nn.Conv2d(1, 28, kernel_size=3, padding='same'),
            nn.ReLU(),

            # Conv layer2
            nn.Conv2d(28, 28, kernel_size=3, padding='same'),
            nn.ReLU(),

            # Max Pooling layer
            nn.MaxPool2d(kernel_size=2),
            nn.Dropout(0.25),

            # Conv layer3
            nn.Conv2d(28, 56, kernel_size=3, padding='same'),
            nn.ReLU(),

            # Conv layer4
            nn.Conv2d(56, 56, kernel_size=3, padding='same'),
            nn.ReLU(),
            
            # Max Pooling layer
            nn.MaxPool2d(kernel_size=2),
            nn.Dropout(0.25)
        )
        self.Linear = nn.Linear(56 * 7 * 7, 3)
        
	def forward(self, x) :
        x = self.classifier(x)
        x = self.flatten(x)
        output = self.Linear(x)
        return output&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1. CNN 모델 학습시키기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738441000795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model = ConvNeuralNetwork().to(device)
print(model)

loss = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

def train_loop(loader, model, loss_fn, optimizer) :
    sum_losses = 0
    sum_accs = 0
    for x_batch, y_batch in loader :
        x_batch = x_batch.to(device)
        y_batch = y_batch.to(device)
        y_pred = model(x_batch)
        loss = loss_fn(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        sum_losses += loss

        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)
        acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
        sum_accs += acc

    avg_loss = sum_losses / len(loader)
    avg_acc = sum_accs / len(loader)
    return avg_loss, avg_acc
    
epochs = 50

for i in range(epochs) :
    print(f&quot;------------------------------------------------&quot;)
    avg_loss, avg_acc = train_loop(loader, model, loss, optimizer)
    print(f'Epoch: {i+1:4d}/{epochs}, Loss: {avg_loss:.6f}, Accuracy: {avg_acc:.2f}%')
print('Done!!')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-2. CNN 모델 Test하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738441028042&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test_loader = DataLoader(
    dataset=testset,
    batch_size=32,
    shuffle=False
)

imgs, labels = next(iter(test_loader))
fig, axes = plt.subplots(4, 8, figsize=(16, 8))

for ax, img, label in zip(axes.flatten(), imgs, labels):
    ax.imshow(img.reshape(28, 28), cmap='gray')
    ax.set_title(class_map[label.item()])
    ax.axis('off')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738441098978&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def test(model, test_loader) :
    model.eval()

    sum_accs = 0

    img_list = torch.Tensor().to(device)
    y_pred_list = torch.Tensor().to(device)
    y_true_list = torch.Tensor().to(device)

    for x_batch, y_batch in test_loader :
        x_batch = x_batch.to(device)
        y_batch = y_batch.to(device)
        y_pred = model(x_batch)
        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)

        # torch.cat((y_pred_list, y_pred_index), dim = 0) : 행(0)으로 합치기
        y_pred_list = torch.cat((y_pred_list, y_pred_index), dim = 0)
        y_true_list = torch.cat((y_true_list, y_batch), dim = 0)
        img_list = torch.cat((img_list, x_batch), dim = 0)

        acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
        sum_accs += acc

    avg_acc = sum_accs / len(test_loader)
    return y_pred_list, y_true_list, img_list, avg_acc
    
y_pred_list, y_true_list, img_list, avg_acc = test(model, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738441103793&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fig, axes = plt.subplots(4, 8, figsize=(16, 8))

img_list_cpu = img_list.cpu()
y_pred_list_cpu = y_pred_list.cpu()
y_true_list_cpu = y_true_list.cpu()

for ax, img, y_pred, y_true in zip(axes.flatten(), img_list_cpu, y_pred_list_cpu, y_true_list_cpu):
  ax.imshow(img.reshape(28, 28), cmap='gray')
  ax.set_title(f'pred: {class_map[y_pred.item()]}, true: {class_map[y_true.item()]}')
  ax.axis('off')

plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 모델 저장하고 불러오기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738441305442&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모델의 가중치(Weight)와 매개변수(Parameters)만 저장
# 모델의 구조가 저장되지 않으므로 모델 클래스 정의가 없으면 복원 할 수 없음
torch.save(model.state_dict(), 'model_weights.pth')

model2 = ConvNeuralNetwork().to(device)
print(model2)

# 모델을 만들고 학습을 하지 않았기 때문에 정확도는 매우 떨어질 것이다
y_pred_list, y_true_list, img_list, avg_acc = test(model2, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')

# 저장된 모델의 파라미터 불러오기
model2.load_state_dict(torch.load('model_weights.pth'))

# 학습을 마치고 난 이후의 파라미터들이 저장되어있는 것을 가져다 사용했기 때문에
# 학습을 마치고 난 이후의 결과가 나올 것이다
y_pred_list, y_true_list, img_list, avg_acc = test(model2, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 모델 전체 저장하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모델 Class와 Weight가 함께 저장되므로, 복원 시 모델 구조를 별도로 정의할 필요가 없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738441395871&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;torch.save(model, 'model.pth')

model3 = torch.load('model.pth')

# 모델의 구조 자체까지도 저장되었기 때문에 바로 사용이 가능하고
# 정확도도 학습을 마친 정확도가 나오게 된다
y_pred_list, y_true_list, img_list, avg_acc = test(model3, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/50</guid>
      <comments>https://dldbwls0818.tistory.com/50#entry50comment</comments>
      <pubDate>Sun, 2 Feb 2025 05:24:01 +0900</pubDate>
    </item>
    <item>
      <title>CNN</title>
      <link>https://dldbwls0818.tistory.com/49</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. CNN&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN(Convolution Neural Network, 합성곱 신경망)은 주로 이미지나 비정형 데이터의 패턴을 학습하고 분석하는 데에 사용되는 딥러닝 모델입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN은 이미지의 공간적 구조를 효율적으로 처리하기 위해 합성곱 계층(Convolution Layer)를 사용하며, 이 계층은 필터(커널)를 통해 입력 데이터에서 중요한 특징(엣지, 모양 등)을 추출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이어서 풀링 계층(Pooling Layer)를 통해 차원을 축소하고 계산 효율을 높이며, 마지막으로 완전 연결 계층(Fully Connected Layer)를 사용해 특정 클래스나 값을 예측합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN은 이미지 분류, 객체 탐지, 영상 처리 등 다양한 분야에서 높은 성능을 발휘하며, 이미지의 공간적 관계를 보존하면서 학습할 수 있다는 점에서 강점을 가집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLcFKS/btsL3yw0ia4/gMKKtTsKJzcI866X6PwiMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLcFKS/btsL3yw0ia4/gMKKtTsKJzcI866X6PwiMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLcFKS/btsL3yw0ia4/gMKKtTsKJzcI866X6PwiMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLcFKS%2FbtsL3yw0ia4%2FgMKKtTsKJzcI866X6PwiMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;581&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;581&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이미지 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 특징 추출 부분&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지를 이해하기 위한 layer 즉, CNN&lt;/li&gt;
&lt;li&gt;딥러닝과 다른게 아닌 앞에 Convolution layer 계층이 붙어있다고 보면 됩니다.&lt;/li&gt;
&lt;li&gt;특징을 추출한 후 기존 딥러닝 과정을 거칩니다.&lt;/li&gt;
&lt;li&gt;여기서 가장 중요한것은 Convolution을 통해 2차원 행렬 즉 좌표의 의미를 가지기 때문에 이미지를 더 이해하기 쉽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;분류(DNN) 부분&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fully Connected Layer 라고 부릅니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 영상처리에서 CNN을 사용하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지를 분석하는 데에 더 적합한 구조를 가지고 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN은 작은 필터를 사용해 이미지에서 중요한 특징을 효율적으로 추출하며, 이를 반복적으로 사용해 학습해야 할 양을 줄입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지가 조금 이동하거나 변형되어도 특징을 잘 인식할 수 있고, 간단한 요소에서 복잡한 패턴까지 단계적으로 분석할 수 있어 DNN보다 더 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DNN은 모든 픽셀을 개별적으로 학습하려 하기 때문에 계산이 복잡하고 이미지의 공간적 구조를 잘 반영하지 못합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 입력이미지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컴퓨터가 이미지를 인식하는 과정은 이미지를 숫자로 표현하는 것에서 시작됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지는 픽셀 값(흑백 이미지는 밝기를 0~255 사이 숫자로, 컬러 이미지는 RGB 채널값으로)을 가진 행렬로 변환되며, 이 숫자 데이터를 기반으로 컴퓨터가 계산을 수행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2CxAn/btsL4psEWah/WT1FdUESt0uvWkNUtpeKn0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2CxAn/btsL4psEWah/WT1FdUESt0uvWkNUtpeKn0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2CxAn/btsL4psEWah/WT1FdUESt0uvWkNUtpeKn0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2CxAn%2FbtsL4psEWah%2FWT1FdUESt0uvWkNUtpeKn0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;379&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Convolution Layer&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Convolution Layer는 CNN의 핵심 구성 요소로, 이미지에서 중요한 특징을 추축하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 layer는 작은 크기의 필터(커널)를 사용해 입력 데이터(이미지)의 일부분과 합성곱 연산을 수행하며, 필터는 특정 패턴(가장자리, 텍스처 등)을 감지하도록 학습됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필터는 이미지를 스캔하며 각 위치에서 특징 맵(feature map)을 생성하는데, 이는 이미지의 중요한 정보를 강조한 새로운 데이터 표현입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Convolution layer는 이미지의 공간적 구조를 보존하면서 효율적으로 특징을 추출하고, 이를 다음 계층으로 전달해 점점 더 복잡한 패턴을 학습할 수 있게 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-1. 합성곱 연산&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 합성곱 연산(Convolution Operation)은 Convolution Layer에서 입력 데이터(ex : 이미지)와 필터(커널)을 사용해 특징을 추출하는 기본 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 연산은 필터를 이미지 위에서 일정한 크기(Stride)만큼 이동하며, 필터와 해당 영역의 픽셀 값을 요소별 곱셈(element-wise)을 한뒤 합산하여 하나의 값을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 생성된 값들이 모여 새로운 feature map을 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 필터는 학습과정에서 업데이트되며, 특정패턴을 감지할 수 있도록 조정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Convolution Operation은 이미지의 공간적 관계를 보존하면서도 중요한 정보를 강조하고, 불필요한 정보를 줄이는데 매우 효과적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 추가 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;element-wise&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;합성곱 입력이 이미지라고 가정하겠습니다. 커널은 본인이 설정하기 나름인데 이 커널은 이미지를 이해하기 위한 가중치입니다.&lt;/li&gt;
&lt;li&gt;커널(필터)는 이미지를 분석하는 데 필요한 가중치 행렬입니다.(보통 홀수의 정방행렬을 쓰도록 되어있음)&lt;/li&gt;
&lt;li&gt;출력의 한칸은 입력의 빨간칸에 해당하는 값과 커널과 같은 위치에 있는 것과 1대1로 element-wise 곱을 사용하여 계산됩니다.&lt;/li&gt;
&lt;li&gt;위 과정으로 feature map 즉 출력의 모든칸에 다 채워지게 됩니다.&lt;/li&gt;
&lt;li&gt;전부 채워진 후에는 일반적인 딥러닝 과정으로 들어가게 되고 나중에 오차값 등을 구해 비교 후 커널값을 업데이트 하게 됩니다.&lt;/li&gt;
&lt;li&gt;만약 3x3 Kernel과 element-wise곱을 진행할 때 3x3의 Kernel이 두 칸씩 이동한다면 feature map은 2x2가 되는데, 이 때 칸 이동 간격을 의미하는 것이 Stride 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;149&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bigDco/btsL5Br1gWm/MkT0IbICcfBGkSwIkTnWvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bigDco/btsL5Br1gWm/MkT0IbICcfBGkSwIkTnWvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bigDco/btsL5Br1gWm/MkT0IbICcfBGkSwIkTnWvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbigDco%2FbtsL5Br1gWm%2FMkT0IbICcfBGkSwIkTnWvk%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;410&quot; height=&quot;149&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-2. Stride&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스트라이드(Stride)는 합성곱 연산에서 Kernel이 input 위를 이동하는 간격을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적으로 Stride 값이 1이면 필터가 한칸 씩 움직이며 모든 위치에서 연산을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Stride 값이 2이상이면 필터가 더 큰 간격으로 이동하므로, 생성되는 출력의 크기가 작아지고 연산량도 줄어듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Stride를 조절하면 feature map의 크기를 조정할 수 있어, 모델의 계산 효율성을 높이거나 더 큰 영역의 정보를 한 번에 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다만, Stride가 너무 크면 중요한 세부 정보가 손실 될 수 있으므로 적절한 값을 선택하는 것이 중요합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBJi2W/btsL49ikbA0/KKuNkYkoYl4FQBk2iQ7lLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBJi2W/btsL49ikbA0/KKuNkYkoYl4FQBk2iQ7lLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBJi2W/btsL49ikbA0/KKuNkYkoYl4FQBk2iQ7lLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBJi2W%2FbtsL49ikbA0%2FKKuNkYkoYl4FQBk2iQ7lLK%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;639&quot; height=&quot;239&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-3. Padding&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 패딩(Padding)은 합성곱 연산에서 input의 가장자리에 값을 추가하여 출력 크기를 조정하거나 경계 부분의 정보 손실을 방지하는 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일반적으로 가장자리에 0을 추가하는 제로 패딩(Zero Padding)이 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 패딩의 두가지 주요 목적&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 데이터 크기를 유지하여 출력 크기를 줄이지 않고 처리할 수 있게 합니다.(ex : Same Padding)&lt;/li&gt;
&lt;li&gt;경계 부분의 정보를 더 많이 학습 할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 패딩을 사용하지 않으면(Valid Padding) 합성곱 연산이 진행될수록 데이터 크기가 줄어드는 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 모델이 공간 정보를 더 잘 학습할 수 있도록 돕습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rgGKf/btsL4JROk0m/2iuTinaR9PwH1mVoAg6ku0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rgGKf/btsL4JROk0m/2iuTinaR9PwH1mVoAg6ku0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rgGKf/btsL4JROk0m/2iuTinaR9PwH1mVoAg6ku0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrgGKf%2FbtsL4JROk0m%2F2iuTinaR9PwH1mVoAg6ku0%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;343&quot; height=&quot;175&quot; data-origin-width=&quot;343&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-4. Pooling&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 풀링(Pooling)은 CNN에서 특징 맵의 크기를 줄이고, 중요한 정보를 요약하여 계산 효율성을 높이는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 사용되는 Pooling&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Max Pooling&lt;/b&gt;은 작은 영역에서 가장 큰 값을 선택해 주요 특징을 강조합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;평균 풀링(Average Polling)&lt;/b&gt;은 영역의 평균값을 계산하여 전체적인 정보를 요약합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Pooling은 데이터 크기를 줄이면서도 중요한 특징을 유지하고, 모델이 공간적 위치 변화에 덜 민감해지도록 만들어 일반화 성능을 높입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 연산량을 줄이고 Overfitting을 방지하는데 도움을 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vyB0B/btsL3ogYYf5/A2ixpNdbMdK63KHAaxoBYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vyB0B/btsL3ogYYf5/A2ixpNdbMdK63KHAaxoBYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vyB0B/btsL3ogYYf5/A2ixpNdbMdK63KHAaxoBYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvyB0B%2FbtsL3ogYYf5%2FA2ixpNdbMdK63KHAaxoBYk%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;352&quot; height=&quot;127&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. DNN과 CNN&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4-1. DNN의 Weight와 bias&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DNN은 Fully Connected Layer(FC Layer)으로 구성되어 있어, 각 입력 노드가 모든 출력 노드와 연결됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 때문에 입력 노드의 수와 출력 노드의 수에 비례하여 매우많은 weight가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 연결마다 고유한 가중치를 학습하므로, 같은 값이더라도 위치가 다르면 별도의 가중치를 사용합니다.(모든 픽셀에 가중치가 생김)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 모든 노드에 대해 별도의 bias가 존재하며, 가중치와 함께 학습됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4-2. CNN의 Weight와 bias&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN의 합성곱 계층은 작은 크기의 Kernel을 사용하여 input의 특정 영역만을 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Kernel은 여러 위치에서 동일하게 적용되며, 이를 가중치 공유(weight sharing)라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 즉, Kernel에 사용되는 Weight는 input의 모든 영역에서 반복적으로 사용되므로, 학습해야할 weight수가 크게 줄어듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 필터마다 하나의 bias가 있으며, kernel이 어디에 적용되든 동일하게 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- bias는 Kernel 적용 후 더해집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwJgCt/btsL2yEhwov/w13IxWY9ope9lxMWX5pa2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwJgCt/btsL2yEhwov/w13IxWY9ope9lxMWX5pa2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwJgCt/btsL2yEhwov/w13IxWY9ope9lxMWX5pa2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwJgCt%2FbtsL2yEhwov%2Fw13IxWY9ope9lxMWX5pa2K%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;559&quot; height=&quot;262&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;262&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVOIFz/btsL3O7yhj1/5BCKBaycXH5QALUzHAGRM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVOIFz/btsL3O7yhj1/5BCKBaycXH5QALUzHAGRM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVOIFz/btsL3O7yhj1/5BCKBaycXH5QALUzHAGRM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVOIFz%2FbtsL3O7yhj1%2F5BCKBaycXH5QALUzHAGRM1%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;256&quot; height=&quot;192&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 다수의 채널 합성곱 연산&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다수의 채널을 가진 경우(ex : 컬러 이미지), 합성곱 연산은 각 채널별로 개별적으로 진행된 후 합산되어 최종적인 결과를 도출합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필터의 각 채널과 입력 이미지의 대응 채널에 대해 합성곱 연산을 수행합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 필터의 R 채널 부분과 이미지의 R 채널 부분을 합성곱 연산을 수행합니다. 동일하게 G, B채널도 각각 수행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 채널에서 나온 합성곱 결과를 더해서 최종 값 하나를 만듭니다.&lt;/li&gt;
&lt;li&gt;필터는 설정된 스트라이드에 따라 이미지를 위로 이동하며 위 과정을 반복합니다.&lt;/li&gt;
&lt;li&gt;최종적으로 각 위치에서 계산된 결과값들이 모여 하나의 Feature map을 형성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwrMwh/btsL2QLza1Z/8RDAfuUK1Dmi5kkdV5JDYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwrMwh/btsL2QLza1Z/8RDAfuUK1Dmi5kkdV5JDYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwrMwh/btsL2QLza1Z/8RDAfuUK1Dmi5kkdV5JDYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwrMwh%2FbtsL2QLza1Z%2F8RDAfuUK1Dmi5kkdV5JDYK%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;470&quot; height=&quot;254&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. CNN을 구성하는 레이어&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CNN은 주로 다음과 같은 레이어로 구성되며, 이미지를 단계적으로 처리해서 결과를 예측합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Input Layer&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이미지를 숫자행렬(ex: 32x32x3, RGB채널)로 네트워크에 전달합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Convolution Layer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;작은 필터(ex: 3x3)를 사용해 이미지의 중요한 특징을 찾아냅니다.&lt;/li&gt;
&lt;li&gt;필터를 여러 개 사용해 여러가지 특징을 추출합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활성화 함수(ReLU)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;음수 값을 0으로 바꿔 비선형성을 추가하고, 모델이 복잡한 패턴을 학습할 수 있도록 돕습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pooling Layer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이미지 크기를 줄이고(down-sampling) 중요한 정보만 요약합니다.&lt;/li&gt;
&lt;li&gt;ex) 2x2 Pooling은 4개의 값중 가장 큰 값을 선택(Max Pooling)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;uarr; ---------------------여기까지 Convolution Layer&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;FC Layer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이미지의 모든 특징을 하나의 벡터로 평평하게 펼쳐 최종 클래스를 예측합니다.&lt;/li&gt;
&lt;li&gt;ex) 10개의 클래스(고양이, 개 등)에 대해 확률을 계산합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Output Layer&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Softmax 같은 함수를 사용해 각 클래스에 대한 확률을 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&quot;code_1738438926382&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://adamharley.com/nn_vis/' target='_blank'&amp;gt;CNN 체험하기&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://adamharley.com/nn_vis/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CNN 체험하기&lt;/a&gt;&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 간단한 CNN 모델 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738439413180&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.optim as optim

inputs = torch.Tensor(1, 1, 28, 28) # (배치크기, 채널(1: grayScale, 3: TrueColor), 너비, 높이)
print(inputs.shape)

# 32개의 3*3 필터를 사용해 32개의 특징맵을 생성
conv1 = nn.Sequential(
    # in_channels : 채널에 따라 입력값이 달라짐 grayscale이면 1 TrueColor면 3
    # out_channels : 필터에 따라 나오는 개수 설정
    # kernal_size : 필터 크기 설정
    # padding : 출력 크기를 입력 크기와 동일하게 유지(패딩)
    nn.Conv2d(in_channels = 1, out_channels=32, kernel_size=3, padding='same'),
    nn.ReLU()
)

out = conv1(inputs)
print(out.shape)

# MaxPool2d : 스트라이드 기본값은 2
pool1 = nn.MaxPool2d(kernel_size=2)
out = pool1(out)
print(out.shape)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ Pooling 하기 전 출력 리뷰&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- torch.Size([1, 32, 28, 28])&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특징맵을 32개 만들기로 했기 때문에 32가 나온 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738439514710&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 두번째 Convolution Layer
conv2 = nn.Sequential(
    nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding='same'),
    nn.ReLU()
)

out = conv2(out)
print(out.shape)

flatten = nn.Flatten()
out = flatten(out)
print(out.shape)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738439649232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# FC Layer
fc = nn.Sequential(
    nn.Dropout(0.5),
    nn.Linear(3136, 10),
)

out = fc(out)
print(out.shape)&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/49</guid>
      <comments>https://dldbwls0818.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 2 Feb 2025 04:56:28 +0900</pubDate>
    </item>
    <item>
      <title>Multi-class Weather 데이터셋</title>
      <link>https://dldbwls0818.tistory.com/48</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Multi-class Weather DataSet&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Multi-class Weather DataSet은 다양한 기상 조건을 포함하는 이미지 데이터셋으로, 주로 기계 학습 및 딥러닝 모델을 학습하거나 평가하는데에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 맑음, 눈, 비, 흐림과 같은 여러 날씨 유형으로 label이 지정된 Multi-class Classification 문제를 다룹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 class는 다양한 시간대, 계절, 지역에서 촬영된 이미지를 포함하여 현실 세계의 다양성을 반영하도록 설계되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 모델은 날씨 조건을 정확히 분류하고, 기상 관측, 자동화된 날씨 보고, 혹은 자율주행 차량의 환경 인식 시스템과 같은 다양한 응용분야에서 활용될 수 있습니다.&lt;/p&gt;
&lt;div id=&quot;code_1738430441386&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://www.kaggle.com/datasets/pratik2901/multiclass-weather-dataset' target='_blank'&amp;gt;Multi-class Weather DataSet&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/datasets/pratik2901/multiclass-weather-dataset&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Multi-class Weather DataSet&lt;/a&gt;&lt;/div&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;※ kaggle 데이터셋 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크 클릭 &amp;rarr; 로그인 후 우측상단 다운로드 클릭 &amp;rarr; Kaggle CLI 선택 후 리눅스 명령어 복사 &amp;rarr; !로 리눅스 명령어 실행&lt;/p&gt;
&lt;pre id=&quot;code_1738430612077&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;! kaggle datasets download pratik2901/multiclass-weather-dataset&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;※ 데이터셋을 Colab의 세션저장소로 저장하기(세션이 종료되면 사라짐)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738430815947&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import zipfile
import random
from shutil import copyfile, rmtree

zip_file = 'multiclass-weather-dataset.zip'
base_dir = './Multi-class Weather Dataset'
train_dir = './train'
test_dir = './test'
extract_path = '.'

with zipfile.ZipFile(zip_file, 'r') as zip_ref :
    zip_ref.extractall(extract_path)
    
if os.path.exists(train_dir) :
    rmtree(train_dir)
if os.path.exists(test_dir) :
    rmtree(test_dir)
    
# exist_ok=True : 파일이 존재해도 오류가 발생하지 않게 함
os.makedirs(train_dir, exist_ok=True)
os.makedirs(test_dir, exist_ok=True)

for category in categories :
    os.makedirs(os.path.join(train_dir, category), exist_ok=True)
    os.makedirs(os.path.join(test_dir, category), exist_ok=True)
    
# 각 카테고리별 데이터 파일 나누기
for category in categories :
    category_path = os.path.join(base_dir, category)
    # os.listdir(파일이 담긴 폴더경로) : 안에 들어있는 파일 이름들이 담긴 리스트를 반환
    files = os.listdir(category_path)

    # 데이터 섞기
    random.shuffle(files)

    # 데이터를 8:2로 나누기
    split_idx = int(len(files) * 0.8)
    train_files = files[:split_idx]
    test_files = files[split_idx:]

    for file in train_files :
        src = os.path.join(category_path, file)
        dst = os.path.join(train_dir, category, file)
        copyfile(src, dst)

    for file in test_files :
        src = os.path.join(category_path, file)
        dst = os.path.join(test_dir, category, file)
        copyfile(src, dst)

print('데이터 분리가 완료되었습니다.')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;＠ 사용되는 모듈 전부 불러오기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738430845977&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models
import torchvision.datasets as datasets
from torchvision.utils import make_grid
import torch.optim as optim
import torch.nn as nn
# 딥러닝 관련한 함수들을 모아둠.
import torch.nn.functional as F
from torch.utils.data import random_split
from torch.utils.data import DataLoader

import matplotlib.pyplot as plt
import matplotlib.image as image
import numpy as np&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ transforms.ToTensor()&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지를 PyTorch Tensor형태로 변환합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지의 픽셀 값을 [0, 255] 범위에서 [0.0, 1.0] 범위로 정규화 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지 차원을 (H, W, C) 형식에서 PyTorch에서 사용하는 (C, H, W) 형식으로 변환합니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;H : 이미지의 높이(Height)&lt;/li&gt;
&lt;li&gt;W : 이미지의 너비(Width)&lt;/li&gt;
&lt;li&gt;C : 채널(Channel, ex : RGB 이미지의 경우 3, 흑백 이미지의 경우 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ transforms.Normalize(mean, std)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 텐서로 변환된 이미지의 픽셀 값을 -1 ~ 1로 정규화(Normalization)합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mean : 각 채널(R, G, B)의 평균값&lt;/li&gt;
&lt;li&gt;std : 각 채널의 표준편차&lt;/li&gt;
&lt;li&gt;mean = [0.5, 0.5, 0.5] : R, G, B 채널 각각의 평균을 0.5로 설정&lt;/li&gt;
&lt;li&gt;std = [0.5, 0.5, 0.5] : R, G, B 채널 각각의 표준편차를 0.5로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 정규화는 일반적으로 픽셀값의 범위를 [-1, 1][-1, 1][-1, 1]로 조정하기 위해 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( -1 ~ 1 사이로 정규화 시켜주는 것이 더 좋은 방법입니다. )&lt;/p&gt;
&lt;pre id=&quot;code_1738431576883&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Compose : 순차적으로 적용시키게 함
transform_train = transforms.Compose([
	# Resize() : 무조건 적용, 이미지를 입력한 px로 바꿔줌(모델에 학습시킬 때 일정한 크기로 학습시키기 위해)
	transforms.Resize((256, 256)),
    # RandomHorizontalFlip() : 50% 확률로 좌우 반전시킴 
    transforms.RandomHorizontalFlip(),
    # ToTensor() : 무조건 적용됨
    transforms.ToTensor(),
    transforms.Normalize(
    	mean = [0.5, 0.5, 0.5],
        std = [0.5, 0.5, 0.5]
    )
])

# 테스트 데이터에는 노이즈를 줄 필요가 없기 때문에 학습 데이터와 다르게 적용
transform_test = transforms.Compose([
	transforms.Resize((256, 256)),
    transforms.ToTensor(),
    transforms.Normalize(
    	mean = [0.5, 0.5, 0.5],
        std = [0.5, 0.5, 0.5]
    )
])&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ ImageFolder&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- datasets.ImageFolder는 이미지 데이터를 특정 디렉터리 구조에서 로드하는 클래스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 디렉터리 이름을 label로 간주하며, 각 디렉터리 내의 이미지 파일들을 해당 label에 할당합니다. (지도학습과 비슷하다고 생각하시면 편하실겁니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ImageFolder는 이미지 데이터를 PyTorch 데이터셋 형식으로 변환하므로, DataLoader와 함께 사용하여 배치 처리 및 데이터 증강을 쉽게 적용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738431753340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_dataset = datasets.ImageFolder(
    root='train/',
    transform=transform_train,
)

dataset_size = len(train_dataset)
train_size = int(dataset_size * 0.8) # valid(검증)을 사용하기 위해
val_size = dataset_size - train_size

# train 데이터셋을 train과 valid 데이터셋으로 나누기
train_dataset, val_dataset = random_split(train_dataset, [train_size, val_size])

test_dataset = datasets.ImageFolder(
    root='test/',
    transform=transform_test,
)

train_dataloader = DataLoader(train_dataset, batch_size = 64, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=64, 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;&lt;b&gt;※ make_grid&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여러 이미지를 하나의 격자(grid) 형태로 합칩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 출력 이미지의 기본 배치는 가로로 나열된 이미지이며, 간격은 기본적으로 2px입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738431887438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이미지 확인하기
plt.rcParams['figure.figsize'] = [12, 8]
plt.rcParams['figure.dpi'] = 60
plt.rcParams.update({'font.size': 20})

def imshow(input):
    # transpose : 처음 (H, W, C) 형식으로 바꿔줌, transforms를 통해 (C, H, W) 형식으로 변환되었기 때문
    input = input.numpy().transpose((1, 2, 0)) 
    mean = np.array([0.5, 0.5, 0.5])
    std = np.array([0.5, 0.5, 0.5])
    input = std * input + mean # 정규화 해제 (역정규화)
     # clip() : 값이 0보다 작은 경우 0, 1보다 큰 경우 1로 변환
    input = np.clip(input, 0, 1)
    plt.imshow(input)
    plt.show()
    
class_names = { 0:'Cloudy', 1:'Rain', 2:'Shine', 3:'Sunrise' }

iterator = iter(train_dataloader)
imgs, labels = next(iterator)
out = make_grid(imgs[:4])
imshow(out)

print([class_names[labels[i].item()] for i in range(4)])&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 다양한 모델 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-1. nn.Module 상속&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;모델 구성 요소 관리 : layer와 parameter를 자동으로 관리합니다.&lt;/li&gt;
&lt;li&gt;순전파(Forward) 정의 : forward() 메서드를 통해 간단하고 일관된 순전파 과정을 정의합니다.&lt;/li&gt;
&lt;li&gt;계층적 설계 : 서브 모듈을 활용해 복잡한 모델을 쉽게 설계 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;유틸리티 제공 : parameter 저장/로드, 학습/추론 모드 전환 등 다양한 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;PyTorch 호환성 : 최적화, 데이터 로더 등 PyTorch의 다른 기능과 손쉽게 통합 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;추상화 : 저수준 작업을 추상화하여 개발자의 생산성을 향상시킬 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1738432150018&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Model1(nn.Module) :
    def __init__(self) :
        super(Model1, self).__init__()
        self.linear1 = nn.Linear(256*256*3, 4)
        self.flatten = nn.Flatten()

    def forward(self, x) :
        x = self.flatten(x)
        x = self.linear1(x)
        return x&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;＠ Model1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특징 : 단일 선형 계층만 포함되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 활성화 함수나 추가 계층이 없으므로 모델이 표현할 수 있는 함수는 단순한 선형 변환에 제한됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 표현력 부족으로 복잡한 데이터(비선형 데이터)를 학습하지 못할 가능성이 높습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738432234392&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Model2(nn.Module) :
    def __init__(self) :
        super(Model2, self).__init__()
        self.linear1 = nn.Linear(256*256*3, 64)
        self.linear2 = nn.Linear(64, 4)
        self.flatten = nn.Flatten()

    def forward(self, x) :
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x&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;＠ Model2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특징 : 두 개의 선형 계층을 사용하여 입력 데이터를 단계적으로 압축합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 활성화 함수가 없으므로 각 계층 간의 변환은 선형적입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Model1에 비해 표현력이 풍부하지만 여전히 부족하고 활성화 함수가 없기 때문에 비선형 데이터를 학습하지 못할 가능성이 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2-2. nn.Dropout()&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- nn.Dropout()은 PyTorch에서 제공하는 Overfitting을 방지하기 위한 layer입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Dropout은 학습 과정 중 일부 뉴런을 무작위로 '비활성화' 함으로써, 모델이 특정 뉴런에 지나치게 의존하지 않도록 와줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 일반화 성능이 향상됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738432480172&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Model3(nn.Module) :
    def __init__(self) :
        super(Model3, self).__init__()
        self.linear1 = nn.Linear(256*256*3, 128)
        self.dropout1 = nn.Dropout(0.5)
        self.linear2 = nn.Linear(128, 64)
        self.dropout2 = nn.Dropout(0.5)
        self.linear3 = nn.Linear(64, 32)
        self.dropout3 = nn.Dropout(0.5)
        self.linear4 = nn.Linear(32, 4)
        self.flatten = nn.Flatten()

    def forward(self, x) :
        x = self.flatten(x) 
        x = F.relu(self.linear1(x)) 
        x = self.dropout1(x) # 50%의 뉴런을 무작위로 비활성화
        x = F.relu(self.linear2(x))
        x = self.dropout2(x)
        x = F.relu(self.linear3(x)) 
        x = self.dropout3(x)
        x = self.linear4(x)
        return x&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;＠ Model3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특징 : 다중 구조와 ReLU 활성화 함수를 사용하여 비선형적 특징을 학습할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Dropout을 사용하여 Overfitting을 방지하였습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ 학습, 검증, 테스트를 수행하는 함수 정의하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738432794508&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import time

def train() :
    start_time = time.time()
    print(f'***[Epoch: {epoch + 1} - Training]***')
    # model.train() : 모델을 학습모드로 전환함
    # 학습, 드롭아웃, 배치 정규화 등 학습시에만 활성화하도록 설정
    # Gradient Decent(경사 하강)를 활성화 함
    model.train()
    total = 0               # 학습 데이터 수
    running_loss = 0.0      # 배치 단위 loss 값
    running_corrects = 0    # 배치 단위 맞춘 예측 계수

    for i, batch in enumerate(train_dataloader) :
        imgs, labels = batch # batch(imgs, labels)
        imgs, labels = imgs.cuda(), labels.cuda()
        outputs = model(imgs)
        optimizer.zero_grad()
        # 확률값으로 변환하기 전 값(로짓 값)
        # 하나의 배치에 img값도 나오는데 굳이 필요 없이 때문에 _를 사용
        _, preds = torch.max(outputs, 1)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        total += labels.shape[0]
        running_loss += loss.item()
        running_corrects += torch.sum(preds == labels.data)

        if (i == 0) or (i % log_step == log_step - 1) :
            print(f'[Batch: {i+1}] running train loss:{running_loss / total}, running train accuracy: {running_corrects / total}')

    print(f'train loss: {running_loss / total}, accuracy: {running_corrects / total}')
    print('elapsed time:', time.time() - start_time)
    return running_loss / total, (running_corrects / total).item()
    
def validate() :
    start_time = time.time()
    print(f'--[Epoch: {epoch + 1} - Validation]***')
    # model.eval() : 모델을 검증모드로 전환함.
    # 데이터 증강을 비활성화
    # Gradient Decent를 비활성화 함.
    model.eval()
    total = 0
    running_loss = 0.0
    running_corrects = 0

    for i, batch in enumerate(val_dataloader) :
        imgs, labels = batch # batch(imgs, labels)
        imgs, labels = imgs.cuda(), labels.cuda()

        # with torch.no_grad() : gradient decent가 동작하지 않는 영역을 만듬.
        with torch.no_grad() :
            outputs = model(imgs)
            _, preds = torch.max(outputs, 1)
            loss = criterion(outputs, labels)

        total += labels.shape[0]
        running_loss += loss.item()
        running_corrects += torch.sum(preds == labels.data)

        if (i == 0) or (i % log_step == log_step - 1) :
            print(f'[Batch: {i+1}] running val loss:{running_loss / total}, running val accuracy: {running_corrects / total}')

    print(f'val loss: {running_loss / total}, accuracy: {running_corrects / total}')
    print('elapsed time:', time.time() - start_time)
    return running_loss / total, (running_corrects / total).item()
    
def test() :
    start_time = time.time()
    print(f'***[test]***')
    # model.eval() : 모델을 검증모드로 전환함.
    # 데이터 증강을 비활성화
    # Gradient Decent를 비활성화 함.
    model.eval()
    total = 0               # 학습 데이터 수
    running_loss = 0.0      # 배치 단위 loss 값
    running_corrects = 0    # 배치 단위 맞춘 예측 계수

    # i = index
    # 아래 for문은 11개의 배치 세트가 있어서 11번만 돈다.
    for i, batch in enumerate(test_dataloader) :
        imgs, labels = batch # batch(imgs, labels)
        imgs, labels = imgs.cuda(), labels.cuda()

        # with torch.no_grad() : gradient decent가 동작하지 않는 영역을 만듬.
        with torch.no_grad() :
            outputs = model(imgs)
            _, preds = torch.max(outputs, 1) # model 출력값 중에서 최댓값이 나옴(로짓) # [0.1, 0.2, 0.1, 0.6] 이런식으로 그중에 큰값. _는 img가 굳이 필요없어서
            loss = criterion(outputs, labels)

        total += labels.shape[0]
        running_loss += loss.item()
        running_corrects += torch.sum(preds == labels.data)

        if (i == 0) or (i % log_step == log_step - 1) :
            print(f'[Batch: {i+1}] running test loss:{running_loss / total}, running test accuracy: {running_corrects / total}')

    print(f'test loss: {running_loss / total}, accuracy: {running_corrects / total}')
    print('elapsed time:', time.time() - start_time)
    return running_loss / total, (running_corrects / total).item()&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ learning rate를 동적으로 관리하는 함수 정의하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433309692&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def adjust_learning_rate(optimizer, epoch) :
    lr = learning_rate
    if epoch &amp;gt;= 3 :
        lr /= 10
    if epoch &amp;gt;= 7 :
        lr /= 10
    # optimizer.param_groups : 옵티마이저는 학습률과 관련된 파라미터 그룹을 관리
    # 'lr'키로 학습률 값을 설정함
    for param_group in optimizer.param_groups :
        param_group['lr'] = lr&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ 초기화(model1)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433394366&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;learning_rate = 0.01
log_step = 11
model = Model1()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
# momentum : 중력, Adam에 설정된 값, lr에 입력값을 곱함
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum = 0.9)
num_epochs = 20
best_val_acc = 0
best_epoch = 0

history = []
accuracy = []&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ Model1 실행 및 최적의 파라미터 저장하기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433444901&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;os.makedirs(&quot;weights&quot;, exist_ok=True)

for epoch in range(num_epochs) :
    adjust_learning_rate(optimizer, epoch)
    train_loss, train_acc = train()
    val_loss, val_acc = validate()
    history.append((train_loss, val_loss))
    accuracy.append((train_acc, val_acc))
    if val_acc &amp;gt; best_val_acc :
        print('[info] best validation accuarcy!')
        best_val_acc = val_acc
        best_epoch = epoch
        # torch.save() : 파일로 세이브
        # model.state_dic() : 가중치를 저장
        # pth 또는 pt 확장자면 파이토치 파일
        # h5 또는 h 확장자면 텐서플로우 파일
        torch.save(model.state_dict(), f'weights/best_checkpoint_epoch_{epoch + 1}.pth')

torch.save(model.state_dict(), f'weights/last_checkpoint_epoch{epoch + 1}.pth')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ Epoch에 따른 Accuracy값 시각화&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433490417&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel(&quot;Epochs&quot;)
plt.ylabel(&quot;Accuracy&quot;)
plt.legend()&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ Model1의 test 실행&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433587414&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test_loss, test_accuracy = test()
print(f&quot;Test loss: {test_loss:.8f}&quot;)
print(f&quot;Test accuracy: {test_accuracy * 100.:.2f}%&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ Model2로 같은과정 진행&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433642194&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;os.makedirs(&quot;weights&quot;, exist_ok=True)

learning_rate = 0.01
log_step = 20
model = Model2()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
num_epochs = 20
best_val_acc = 0
best_epoch = 0

history = []
accuracy = []

for epoch in range(num_epochs):
    adjust_learning_rate(optimizer, epoch)
    train_loss, train_acc = train()
    val_loss, val_acc = validate()
    history.append((train_loss, val_loss))
    accuracy.append((train_acc, val_acc))

    if val_acc &amp;gt; best_val_acc:
        print(&quot;[Info] best validation accuracy!&quot;)
        best_val_acc = val_acc
        best_epoch = epoch
        torch.save(model.state_dict(), f&quot;weights/best_checkpoint_epoch_{epoch + 1}.pth&quot;)

torch.save(model.state_dict(), f&quot;weights/last_checkpoint_epoch_{num_epochs}.pth&quot;)

plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel(&quot;Epochs&quot;)
plt.ylabel(&quot;Accuracy&quot;)
plt.legend()

test_loss, test_accuracy = test()
print(f&quot;Test loss: {test_loss:.8f}&quot;)
print(f&quot;Test accuracy: {test_accuracy * 100.:.2f}%&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;※ Model3로 같은과정 진행&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738433676484&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;os.makedirs(&quot;weights&quot;, exist_ok=True)

learning_rate = 0.01
log_step = 20
model = Model3()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
num_epochs = 20
best_val_acc = 0
best_epoch = 0

history = []
accuracy = []

for epoch in range(num_epochs):
    adjust_learning_rate(optimizer, epoch)
    train_loss, train_acc = train()
    val_loss, val_acc = validate()
    history.append((train_loss, val_loss))
    accuracy.append((train_acc, val_acc))

    if val_acc &amp;gt; best_val_acc:
        print(&quot;[Info] best validation accuracy!&quot;)
        best_val_acc = val_acc
        best_epoch = epoch
        torch.save(model.state_dict(), f&quot;weights/best_checkpoint_epoch_{epoch + 1}.pth&quot;)

torch.save(model.state_dict(), f&quot;weights/last_checkpoint_epoch_{num_epochs}.pth&quot;)

plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel(&quot;Epochs&quot;)
plt.ylabel(&quot;Accuracy&quot;)
plt.legend()

test_loss, test_accuracy = test()
print(f&quot;Test loss: {test_loss:.8f}&quot;)
print(f&quot;Test accuracy: {test_accuracy * 100.:.2f}%&quot;)&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/48</guid>
      <comments>https://dldbwls0818.tistory.com/48#entry48comment</comments>
      <pubDate>Sun, 2 Feb 2025 03:17:07 +0900</pubDate>
    </item>
    <item>
      <title>딥러닝 : 퍼셉트론과 다층 퍼셉트론</title>
      <link>https://dldbwls0818.tistory.com/47</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 생물학적 뉴런&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 생물학전 뉴런은 신경계를 구성하는 기본 단위로, 정보를 수집, 처리, 전달하는 기능을 담당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뉴런은 크게 3가지 주요 부분으로 나뉩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수상돌기
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;다른 뉴런이나 외부 자극으로부터 신호를 받아들이는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세포체
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;수상돌기에서 받은 신호를 처리하고 통합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;축삭
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;세포체에서 처리된 신호는 축삭을 통해 다름 뉴런이나 근육 혹은 샘과 같은 다른 조직으로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 축삭 끝에는 시냅스가 있어 화학적 신호 또는 전기적 신호를 통해 다른 세포와 연결됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 뉴런은 이러한 작용을 통해 신경계가 복잡한 정보를 효율적으로 처리하고 전달할 수 있도록 돕습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsKFyF/btsL3wZbGa7/b6cVynqlvkl02z0awNcwb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsKFyF/btsL3wZbGa7/b6cVynqlvkl02z0awNcwb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsKFyF/btsL3wZbGa7/b6cVynqlvkl02z0awNcwb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsKFyF%2FbtsL3wZbGa7%2Fb6cVynqlvkl02z0awNcwb1%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;710&quot; height=&quot;326&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 인공신경망(ANN)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인공신경망(Artificial Neural Network, ANN)은 생물학적 신경망의 구조와 기능을 모방한 계산 모델로, 여러 개의 인공 뉴런을 계층적으로 연결하여 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 기본적으로 입력층(input layer), 은닉층(hidden layer), 출력층(output layer)으로 이루어지며, 각 층의 뉴런들은 다음 층의 뉴런과 연결되어 데이터를 전달하고 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력 데이터는 가중치와 활성화 함수 등의 연산을 거쳐 점차 복잡한 특징을 추출하며, 최종적으로 출력층에서 예측값이나 결과를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 신경망은 데이터에 기반한 학습을 통해 가중치를 조정하면서 문제를 해결하도록 최적화됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이러한 특성 덕분에 이미지 분류, 음성 인식, 자연어 처리 등 다양한 분야에서 뛰어난 성능을 발휘하며, 딥러닝의 주요 구성 요소로 활용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ANN은 다층 구조와 비선형 활성화 함수를 통해 복잡한 데이터 간의 관계를 학습할 수 있는 강력한 도구입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 인공 신경망의 역사&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3-1. 1940년대 ~ 1980년대&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인공 신경망(Artificial Neural Network, ANN)의 역사는 1940년대에 시작된 초기 개념부터 현대의 딥러닝에 이르기까지 긴 발전 과정을 거쳤습니다. 1943년, 워런 맥컬록(Warren McCulloch)과 월터 피츠(Walter Pitts)는 생물학적 뉴런을 수학적으로 모델링한 맥컬록-피츠 뉴런을 제안하며 ANN의 기초를 마련했습니다. 1958년, 프랭크 로젠블렛(Frank Rosenblatt)은 단층 퍼셉트론(perceptron)을 개발하여 ANN이 학습과 분류 문제를 해결할 수 있음을 보여주었습니다. 그러나 1969년, 마빈 민스키(Marvin Minsky)와 시모어 페이퍼트(Seymour Papert)는 퍼셉트론의 한계를 지적하며, 비선형 문제를 해결하지 못한다는 사실을 제시하였고, 이는 ANN 연구의 침체기로 이어졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 퍼셉트론&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 퍼셉트론(Perceptron)은 1958년 프랭크 로젠블렛이 제안한 인공 뉴런 모델로, 가장 간단한 형태의 인공 신경망입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- input값과 weight값의 곱을 모두 더한 값에 bias를 더하고, 이를 활성화 함수로 변환하여 binary ouput을 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습과정에서는 output값이 실제와 다를 경우, weight를 조정하는 방식으로 학습이 이루어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 퍼셉트론은 단층 구조로 선형적으로 분리 가능한 문제를 해결할 수 있지만, XOR 문제와 같은 비 선형적으로 분리되는 문제를 해결하지 못하는 한계가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pnE7F/btsL5r35eb4/qZoRcgOeWxnBgXeXSVM611/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pnE7F/btsL5r35eb4/qZoRcgOeWxnBgXeXSVM611/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pnE7F/btsL5r35eb4/qZoRcgOeWxnBgXeXSVM611/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpnE7F%2FbtsL5r35eb4%2FqZoRcgOeWxnBgXeXSVM611%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;683&quot; height=&quot;236&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;논리 회귀(단층 퍼셉트론)로 AND 문제 풀기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738427672627&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.optim as optim

X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [0], [0], [1]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000

for epoch in range(epochs + 1) :
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0 :
        y_bool = (y_pred &amp;gt;= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs}, Loss: {loss:.6f}, Accuracy: {accuracy:.2f}%')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;논리 회귀(단층 퍼셉트론)로 OR 문제 풀기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738427853824&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [1]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000

for epoch in range(epochs + 1) :
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0 :
        y_bool = (y_pred &amp;gt;= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs}, Loss: {loss:.6f}, Accuracy: {accuracy:.2f}%')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;논리 회귀(단층 퍼셉트론)로 XOR 문제 풀기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738428012305&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [0]])

model = nn.Sequential(
    nn.Linear(2, 1),
    nn.Sigmoid()
)

optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000

for epoch in range(epochs + 1) :
    y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0 :
        y_bool = (y_pred &amp;gt;= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs}, Loss: {loss:.6f}, Accuracy: {accuracy:.2f}%')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3-2. 1980년대 ~ 2000년대&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1980년대에 이르러 역전파(Backpropagation) 알고리즘이 재발견 되면서 ANN이 다시 주목받기 시작했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특히, 제프리 힌턴 등 연구자들의 공헌으로 다층 퍼셉트론(Multi-Layer Perceptron, MLP)이 비선형 문제를 해결할 수 있음을 보였고, ANN 연구가 활발해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1990년대에는 합성곱 신경망(CNN)과 순환 신경망(RNN) 등 특화된 구조가 개발되며 ANN이 더 복잡한 문제를 다룰 수 있게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRGiUf/btsL3Ya555N/34RTWrGKlIIIki7J7JgCQ1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRGiUf/btsL3Ya555N/34RTWrGKlIIIki7J7JgCQ1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRGiUf/btsL3Ya555N/34RTWrGKlIIIki7J7JgCQ1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRGiUf%2FbtsL3Ya555N%2F34RTWrGKlIIIki7J7JgCQ1%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;342&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;논리 회귀(다층 퍼셉트론)로 XOR 문제 풀기&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1738428274952&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model = nn.Sequential(
	nn.Linear(2, 4),
    # 여기서 Sigmoid는 곡선화 시키기 위해 사용함(활성화 함수)
    nn.Sigmoid(),
    nn.Linear(4, 1),
    nn.Sigmoid()
)

print(model)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biPvDE/btsL226onJY/yWggKTf4FI5Nb55W3TJ9BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biPvDE/btsL226onJY/yWggKTf4FI5Nb55W3TJ9BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biPvDE/btsL226onJY/yWggKTf4FI5Nb55W3TJ9BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiPvDE%2FbtsL226onJY%2FyWggKTf4FI5Nb55W3TJ9BK%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;694&quot; height=&quot;1164&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738428459923&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
y = torch.FloatTensor([[0], [1], [1], [0]])

optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000

for epoch in range(epochs + 1) :
	y_pred = model(X)
    loss = nn.BCELoss()(y_pred, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    if epoch % 100 == 0 :
        y_bool = (y_pred &amp;gt;= 0.5).float()
        accuracy = (y == y_bool).float().sum() / len(y) * 100
        print(f'Epoch {epoch:4d}/{epochs}, Loss: {loss:.6f}, Accuracy: {accuracy:.2f}%')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 비선형 활성화 함수&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 비선형 활성화 함수는 신경망에서 선형 변환만으로는 표현할 수 없는 복잡한 비선형 패턴을 학습할 수 있도록 도와주는 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- input값을 비 선형적으로 변환하여 신경망의 layer마다 다른 특징을 학습하게 하며, 이를 통해 선형 함수들의 조합으로는 표현할 수 없는 복잡한 함수와 데이터 분포를 모델링 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 ReLU, Sigmoid, Tanh 등이 있으며, 이 함수들은 출력값을 제한하거나 왜곡하여 학습을 안정화하고, 신경망이 더 강력한 표현력을 가지도록 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4-1. Sigmoid&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Sigmoid Function은 비선형 활성화 함수 중 하나로, 주로 신경망에서 출력값을 0과 1사이로 스케일링 하는 데에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력값 x가 양수일수록 출력값은 1에 가까워지고, 음수일수록 0에 가까워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Sigmoid는 입력 값을 확률처럼 해석할 수 있도록 변환하는 특징 때문에 Binary Classification 문제에서 자주 사용되지만, 출력의 미분값이 작은 구간에서 Gradient 소실 문제가 발생할 수 있어, 최근에는 ReLU와 같은 활성화 함수들이 더 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하지만, Sigmoid는 모델의 특정 부분이나 확률적 해석이 필요한 경우에 유용하게 활용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738428906027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
import matplotlib.pyplot as plt

def sigmoid(x) :
    return 1 / (1 + np.exp(-x))
    
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)

plt.plot(x, y)
plt.plot([0, 0], [1.0, 0.0], ':')
plt.title('Sigmoid Function')
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;size18&quot;&gt;&lt;b&gt;4-2. Tanh(하이퍼볼릭탄젠트)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 하이퍼볼릭 탄젠트(Tanh)는 비선형 활성화 함수 중 하나로, 입력 값을 -1에서 1 사이의 값으로 변환하는 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력 값이 큰 양수일수록 1에 가까워지고, 큰 음수일수록 -1에 가까워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Tanh는 출력 범위가 대칭적이어서 Sigmoid와 달리 출력이 0을 기준으로 분포되므로, 데이터가 양수와 음수로 분리되는 문제에서 더 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그러나 입력 값이 매우 크거나 작을 경우 기울기가 0에 가까워지는 '기울기 소실' 문제가 발생 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Tanh는 주로 출력 값의 분포를 중심에 맞추고 싶을 때 사용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738429094537&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;x = np.arange(-5.0, 5.0, 0.1)
y = np.tanh(x)

plt.plot(x, y)
plt.plot([0, 0], [1.0, 0.0], ':')
plt.axhline(y=0, color='orange', linestyle='--')
plt.title('Tanh Function')
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;size18&quot;&gt;&lt;b&gt;4-3. ReLU(렐루)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ReLU(Rectified Linear Unit)는 신경망에서 가장 널리 사용되는 비선형 함수 중 하나로, 입력 값이 0보다 크면 그대로 출력하고, 0 이하이면 0을 출력하는 함수 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 출력값이 양수인 경우 기울기가 1로 일정하게 유지되므로 '기울기 소실' 문제를 완화 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이로 인해 학습이 빠르고 효율적이며, 깊은 신경망에서 성능이 뛰어난 것으로 알려져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그러나 ReLU는 입력값이 0 이하일 때 기울기가 0이 되어 학습되지 않는 '죽은 ReLU' 문제가 발생 할 수 있으며, 이를 보완하기 위해 Leaky ReLU와 같은 변형 함수들이 개발되었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738429268535&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def relu(x) :
    return np.maximum(0, x)
    
x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)

plt.plot(x, y)
plt.plot([0, 0], [5.0, 0.0], ':')
plt.title('ReLU Function')
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;&lt;b&gt;※ ReLU 그래프 자체가 직선인데 활성화 함수로 사용하는 이유&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sRUjt/btsL3yqcoAq/YKBfMk8QIVYgzP8Kc1BNe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sRUjt/btsL3yqcoAq/YKBfMk8QIVYgzP8Kc1BNe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sRUjt/btsL3yqcoAq/YKBfMk8QIVYgzP8Kc1BNe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsRUjt%2FbtsL3yqcoAq%2FYKBfMk8QIVYgzP8Kc1BNe1%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;738&quot; height=&quot;661&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;661&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;&lt;u&gt;(주로 Output Layer에서 다중 클래스 분류를 하기 위해 사용되는 Softmax함수도 비선형성을 갖기 때문에 같이 넣어봤습니다.)&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4-4. Softmax 시각화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Softmax Function은 비선형 활성화 함수로, 주로 Multi Classification 문제에서 출력층에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 입력값의 지수 값을 계산하고, 이를 모든 출력값의 지수 값의 합으로 나누어 각 클래스에 속할 확률을 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 출력값이 0과 1사이의 확률로 정규화 되며, 모든 클래스의 확률 합이 1이됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Softmax는 모델이 각 클래스에 속할 가능성을 명확히 보여주기 때문에, Classification 문제에서 최종 결정을 내리는 데에 유용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738429360689&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;x = np.arange(-5.0, 5.0, 0.1)
y = np.exp(x) / np.sum(np.exp(x))

plt.plot(x, y)
plt.title('Softmax Function')
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;&lt;b&gt; ※ Softmax가 비선형성 함수인 이유&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;611&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhlo37/btsL5i7hrek/8nYKcCIyLahCaCVFGzRK8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhlo37/btsL5i7hrek/8nYKcCIyLahCaCVFGzRK8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhlo37/btsL5i7hrek/8nYKcCIyLahCaCVFGzRK8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhlo37%2FbtsL5i7hrek%2F8nYKcCIyLahCaCVFGzRK8k%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;661&quot; height=&quot;611&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;611&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/47</guid>
      <comments>https://dldbwls0818.tistory.com/47#entry47comment</comments>
      <pubDate>Sun, 2 Feb 2025 02:13:30 +0900</pubDate>
    </item>
    <item>
      <title>손글씨 데이터셋</title>
      <link>https://dldbwls0818.tistory.com/46</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 손글씨 데이터셋&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- sklearn에서 제공하는 데이터 셋으로 0~9까지 8x8픽셀 이미지 데이터들로 이루어진 데이터셋입니다.&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_1738271350025&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

digits = load_digits()
X_data = digits['data']
y_data = digits['target']
print(X_data, y_data)
print(X_data.shape, y_data.shape)&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;※ axes.flatten()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- axes.flatten()은 다차원 배열 형태로 구성된 Matplotlib의 서브플롯 배열을 1차원 배열로 변환하는 메서드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Matplotlib에서 다수의 서브플롯을 생성할 때, plt.subplots()는 2차원 배열 형태로 서브플롯 객체를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 배열은 각 서브 플롯을 접근하기 위해 행과 열의 인덱스를 사용해야하지만, flatten() 메서드를 사용하면 이 배열을 1차원으로 펼쳐서 각 서브플롯을 단일 인덱스로 순회할 수 있게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738272086431&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fig, axes = plt.subplot(nrows=2, ncols=5, figsize=(14, 8))

for i, ax in enumerate(axes.flatten()) :
    ax.imshow(X_data[i].reshape(8,8), cmap='gray')
    ax.set_title(y_data[i])
    ax.axis('off')
    
X_data = torch.FloatTensor(X_data)
y_data = torch.LongTensor(y_data)

X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.3, random_state=2025)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. DataLoader&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DataLoader는 딥러닝 프레임워크(ex : PyTorch)에서 데이터를 효과적으로 관리하고 모델에 공급하기 위해 사용되는 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터셋에서 batch 단위로 데이터를 로드하고, 학습 중에 필요한 데이터 샘플링, 셔플링, 병렬 처리 등을 간편하게 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DataLoader는 데이터셋 객체와 함께 작동하며, 데이터셋의 개별 항목에 접근하는 방식을 정의하는 데이터셋 Class와 달리, 데이터를 미니배치로 묶어서 반복(iteration) 가능한 형태로 제공합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738271804217&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from torch.utils.data import DataLoader

loader = DataLoader(
	# 하나의 데이터와 label이 tuple로 묶여 리스트로 들어간다. ex) ([1, 0, 25, 255, 40], 8)
	dataset = list(zip(X_train, y_train)),
    batch_size = 64,
    shuffle = True,
    # digits 데이터가 64개의 미니배치로 나누면 5개의 데이터가 남는다
    # 5개의 데이터를 버린다면 True, 아니면 False
    drop_last = False
)

imgs, labels = next(iter(loader))

fig, axes = plt.subplots(nrows=8, ncols=8, figsize=(14, 14))

for ax, img, label in zip(axes.flatten(), imgs, labels) :
    ax.imshow(img.reshape(8,8), cmap='gray')
    ax.set_title(str(label))
    ax.axis('off')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738272216273&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;model = nn.Sequential(
	nn.Linear(64, 10)
)

optimizer = optim.Adam(model.parameters(), lr=0.01)
epochs = 50

for epoch in range(epochs + 1) :
	# 배치 단위로 loss와 accuracy를 확인하기 위한 변수
    sum_losses = 0
    sum_accs = 0
    for x_batch, y_batch in loader :
        y_pred = model(x_batch)
        loss = nn.CrossEntropyLoss()(y_pred, y_batch)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        sum_losses += loss
        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)
        acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
        sum_accs += acc

    avg_loss = sum_losses / len(loader)
    avg_acc = sum_accs / len(loader)

    print(f'Epoch {epoch:4d}/{epochs}, Loss: {avg_loss:.6f}, Accuracy: {avg_acc:.2f}%')
    
plt.imshow(X_test[10].reshape(8,8), cmap='gray')
print(y_test[10])

y_pred = model(X_test)
y_prob = nn.Softmax(1)(y_pred)

for i in range(10) :
    print(f'숫자 {i}일 확률: {y_prob[10][i]:.2f}')
    
y_pred_index = torch.argmax(y_prob, axis=1)
accuracy = (y_test == y_pred_inde).float().sum() / len(y_test) * 100
print(f'테스트 정확도는 {accuracy:.2f}% 입니다')&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 데이터 증강&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 증강(Data Augmentation)은 학습 데이터를 인위적으로 변환하여 데이터셋의 다양성을 높이고 모델의 일반화 성능을 향상 시키는 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 회전, 크기 조정, 반전, 블러링, 밝기 조정 등 다양한 변환을 적용하여 원본 데이터로부터 새로운 데이터를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 데이터 부족 문제를 완화하고 모델이 특정 패턴에 Overfitting 되지 않도록 도와줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 특히, 이미지나 음성 데이터와 같이 특징이 직관적인 데이터에서 효과적으로 활용되며, 증강된 데이터는 모델이 예측 대상의 다양한 변형에 대해 강하게 학습할 수 있도록 돕습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738272741340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터 증강을 위한 모듈
from torchvision import transforms
from torch.utils.data import Dataset
# 데이터셋을 Tensor형태로 변환
from torch.utils.data import TensorDataset

X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.3, random_state=2025)
print(X_train.shape, X_test.shape)
print(y_train.shape, y_test.shape)

train_dataset = TensorDataset(X_train, y_train)
test_dataset = TensorDataset(X_test, y_test)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;※ transforms.Compose()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 여러 데이터 변환(transform) 작업을 순차적으로 적용할 수 있도록 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지 데이터 전처리와 증강 과정에서 자주 사용되며, 각 변환을 하나의 리스트로 묶어 실행합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;transforms.RandomRotation(10)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 : 이미지를 -10도에서 +10도 사이로 무작위 회전시킵니다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;10은 회전 범위를 나타냅니다.&lt;/li&gt;
&lt;li&gt;각 호출 시, -10도 ~ +10도 범위에서 무작위로 각도를 선택하여 이미지를 회전합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;transforms.RandomAffine(0, shears=5, scale=(0.9, 1.1))
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 : 이미지를 비틀기(shear), 크기 조정(scale) 등의 변환을 수행합니다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;0 : 회전(각도) 변환을 수행하지 않음을 의미합니다.&lt;/li&gt;
&lt;li&gt;shear = 5 : 이미지를 최대 5도 만큼 비스듬하게 비틀기 변환을 수행합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 정사각형이 평행사변형처럼 기울어질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;scale = (0.9, 1.1)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지를 0.9배에서 1.1배 범위 내에서 무작위 크기 조정을 수행합니다.&lt;/li&gt;
&lt;li&gt;각 호출 시, 무작위로 크기가 변경됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1738273284101&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 데이터 증강 적용
transform = transforms.Compose([
	transforms.RandomRotation(10),
    transforms.RandomAffine(0, shear=5, scale=(0.9, 1.1))
])

# 데이터 증강을 적용시킨 데이터셋을 객체로 만들기 위해 class 정의
class AugmentedDataset(Dataset) :
    def __init__(self, dataset, transform) :
        self.dataset = dataset
        self.transform = transform

    def __len__(self) :
        return len(self.dataset)

    def __getitem__(self, idx) :
        x, y = self.dataset[idx]
        # 이미지로 만들기
        x = x.view(8, 8).unsqueeze(0) # x: (64,) -&amp;gt; (8, 8) -&amp;gt; (1, 8, 8)
        x = self.transform(x)
        return x.flatten(), y
        
augmented_train_dataset = AugmentDataset(train_dataset, transform)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738273583325&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;train_loader = DataLoader(
	augmented_train_dataset,
    batch_size = 64,
    shuffle = True
)

test_loader = DataLoader(
	test_dataset,
    batch_size = 64,
    shuffle = False
)

imgs, labels = next(iter(train_loader))
fig, axes = plt.subplots(nrows=8, ncols=8, figsize=(14, 14))

for ax, img, label in zip(axes.flatten(), imgs, labels):
    ax.imshow(img.reshape((8, 8)), cmap='gray')
    ax.set_title(str(label))
    ax.axis('off')
    
model = nn.Sequential(
	nn.Linear(64, 10)
)

optimizer = optim.Adam(model.parameters(), lr=0.01)
epochs = 50

for epoch in range(epochs + 1):
    sum_losses = 0
    sum_accs = 0

    # data_loader에서 꺼내면서 데이터 증강이 이루어진다
    for x_batch, y_batch in train_loader:
        y_pred = model(x_batch)
        loss = nn.CrossEntropyLoss()(y_pred, y_batch)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        sum_losses = sum_losses + loss

        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)
        acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
        sum_accs = sum_accs + acc

    if epoch % 10 == 0:
        avg_loss = sum_losses / len(loader)
        avg_acc = sum_accs / len(loader)
        print(f'Epoch {epoch:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
        
plt.imshow(X_test[11].reshape((8, 8)), cmap='gray')
print(y_test[11])

y_pred = model(X_test)
y_prob = nn.Softmax(1)(y_pred)

for i in range(10) :
    print(f'숫자 {i}일 확률 : {y_prob[11][i]:.2f}')&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/46</guid>
      <comments>https://dldbwls0818.tistory.com/46#entry46comment</comments>
      <pubDate>Fri, 31 Jan 2025 06:48:34 +0900</pubDate>
    </item>
    <item>
      <title>호텔 예약 취소 여부 예측</title>
      <link>https://dldbwls0818.tistory.com/45</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 호텔 예약 수요 데이터셋&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 호텔 예약 수요 데이터셋은 일반적으로 호텔 예약에 대한 수요 패턴을 분석하기 위한 데이터셋입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 데이터셋은 예약 취소, 체크인 날짜, 고객 유형, 체류 기간, 객실 유형, 예약 경로 등 다양한 요소를 포함하며, 주로 예약 트랜드 분석, 고객 행동 예측, 수요 예측 등에 사용됩니다.&lt;/p&gt;
&lt;div id=&quot;code_1738255243286&quot; data-ke-type=&quot;html&quot; data-source=&quot;&amp;lt;a href='https://www.kaggle.com/datasets/jessemostipak/hotel-booking-demand/data' target='_blank'&amp;gt;호텔 예약 수요 데이터셋&amp;lt;/a&amp;gt;&quot;&gt;&lt;a href=&quot;https://www.kaggle.com/datasets/jessemostipak/hotel-booking-demand/data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;호텔 예약 수요 데이터셋&lt;/a&gt;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 데이터셋 컬럼 설명&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f1f1f; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;hotel: 호텔 유형 (Resort Hotel, City Hotel)&lt;/li&gt;
&lt;li&gt;is_canceled: 예약 취소 여부 (0: 예약 유지, 1: 예약 취소)&amp;nbsp; &amp;larr; label&lt;/li&gt;
&lt;li&gt;lead_time: 예약과 실제 체크인 사이의 기간(일 단위)&lt;/li&gt;
&lt;li&gt;arrival_date_year: 도착 연도&lt;/li&gt;
&lt;li&gt;arrival_date_month: 도착 월&lt;/li&gt;
&lt;li&gt;arrival_date_week_number: 해당 주의 주차&lt;/li&gt;
&lt;li&gt;arrival_date_day_of_month: 도착 일&lt;/li&gt;
&lt;li&gt;stays_in_weekend_nights: 주말(토, 일) 동안의 숙박일 수&lt;/li&gt;
&lt;li&gt;stays_in_week_nights: 주중(월~금) 동안의 숙박일 수&lt;/li&gt;
&lt;li&gt;adults: 성인 투숙객 수&lt;/li&gt;
&lt;li&gt;children: 어린이 투숙객 수&lt;/li&gt;
&lt;li&gt;babies: 유아 투숙객 수&lt;/li&gt;
&lt;li&gt;meal: 예약된 식사 유형&lt;/li&gt;
&lt;li&gt;country: 고객의 국가&lt;/li&gt;
&lt;li&gt;market_segment: 예약 시장 세그먼트&lt;/li&gt;
&lt;li&gt;distribution_channel: 예약 채널 (예: 온라인, 오프라인)&lt;/li&gt;
&lt;li&gt;is_repeated_guest: 재방문 여부&lt;/li&gt;
&lt;li&gt;previous_cancellations: 이전 예약 취소 횟수&lt;/li&gt;
&lt;li&gt;previous_bookings_not_canceled: 이전 예약에서 취소되지 않은 것들&lt;/li&gt;
&lt;li&gt;reserved_room_type: 예약된 객실 유형&lt;/li&gt;
&lt;li&gt;assigned_room_type: 실제 배정된 객실 유형&lt;/li&gt;
&lt;li&gt;booking_changes: 예약 변경 횟수&lt;/li&gt;
&lt;li&gt;deposit_type: 보증금 유형 (No Deposit, Non Refund, Refundable)&lt;/li&gt;
&lt;li&gt;days_in_waiting_list: 대기자 명단에 있었던 일 수&lt;/li&gt;
&lt;li&gt;agent: 예약을 중개한 기관&lt;/li&gt;
&lt;li&gt;customer_type: 고객 유형 (예: Transient, Group)&lt;/li&gt;
&lt;li&gt;adr: 평균 일일 요금 (유로)&lt;/li&gt;
&lt;li&gt;required_car_parking_spaces: 주차 공간 요구 수&lt;/li&gt;
&lt;li&gt;total_of_special_requests: 특별 요청 수&lt;/li&gt;
&lt;li&gt;reservation_status: 예약 상태 (Check-Out, Canceled, No-Show)&lt;/li&gt;
&lt;li&gt;reservation_status_date: 예약 상태가 마지막으로 업데이트된 날짜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 데이터 전처리 및 EDA(데이터 탐색)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이번 데이터 셋에서는 is_canceled를 종속 변수로 두고 독립변수는 선택하여 진행하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738255482921&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738255592168&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;hotel_df = pd.read_csv('/content/drive/MyDrive/(상위폴더 1)/(상위폴더 2)/Data/hotel_bookings.csv')
hotel_df

hotel_df.info()

hotel_df.describe()

hotel_df.isna().sum()&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738255881401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sns.displot(hotel_df['lead_time'])

sns.boxplot(hotel_df['lead_time'])

# IQR 활용하기
# Quantile() : 분위수를 나눠줌
Q1 = hotel_df['lead_time'].quantile(0.25)
Q3 = hotel_df['lead_time'].quantile(0.75)
print(Q1, Q3)

IQR = Q3 - Q1
# min지점 값 만들기
lower_bound = Q1 - 1.5 * IQR
# max지점 값 만들기
upper_bound = Q3 + 1.5 * IQR
print(lower_bound, upper_bound)

# 1사분위수(Q1) 3사분위수(Q3) 사이에 있는 데이터 개수 확인
hotel_df = hotel_df[(hotel_df['lead_time'] &amp;gt;= lower_bound) &amp;amp; (hotel_df['lead_time'] &amp;lt;= upper_bound)]
len(hotel_df)

sns.boxplot(hotel_df['lead_time'])

sns.barplot(x=hotel_df['distribution_channel'], y=hotel_df['is_canceled'])&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;＃ barplot 의 bar 역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;신뢰구간(CI) : 평균값이 속할 것으로 예상되는 값의 범위입니다.&lt;/li&gt;
&lt;li&gt;바 그래프에서 신뢰구간 : 심지(Error Bar)로 나타냅니다.&lt;/li&gt;
&lt;li&gt;신뢰구간이 좁다 : 평균값에 대한 확신이 높다.&lt;/li&gt;
&lt;li&gt;신뢰구간이 넓다 : 평균값에 대한 확인이 낮고 데이터가 흩어져있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1738262701170&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 월별 취소율 시각화
plt.figure(figsize=(15, 5))
sns.barplot(x=hotel_df['arrival_date_month'], y=hotel_df['is_canceled'])

# barplot을 확인해보니 월이 순서대로 되어있지 않다.
import calender

months = []
# 0은 아무것도 없기 때문에 1부터 시작
for i in range(1, 13) :
    months.append(calendar.month_name[i])
print(months)

plt.figure(figsize=(15, 5))
# order : 지정하는 값은 리스트여야하며,
# 그 리스트 안에있는 값과 x축의 값이 일치하면 order의 순서대로 보여지게 된다.
sns.barplot(x=hotel_df['arrival_date_month'], y=hotel_df['is_canceled'], order=months)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738263167089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;hotel_df.isna().sum()

hotel_df['children'].value_counts()

# 0이 굉장히 많기 때문에 null을 0으로 처리해도 괜찮을 거라고 판단
hotel_df['children'] = hotel_df['children'].fillna(0)&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_1738263189364&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이번 데이터셋은 취소 여부를 확인하기 때문에
# W(가중치)를 굳이 3개를 사용하기 보단
# 성인, 아이, 애기 3개의 Feature를 합치는게 나을 것 같다
hotel_df['people'] = hotel_df['adults'] + hotel_df['children'] + hotel_df['babies']
hotel_df.drop(['adults', 'children', 'babies'], axis=1, inplace=True)

hotel_df[hotel_df['people'] == 0]

# 3개의 Feature를 합쳐도 0인 값이 있기 때문에 제거
hotel_df.drop(hotel_df[hotel_df['people'] == 0].index, inplace=True)

# 주중과 주말을 굳이 나눌 필요가 없다고 판단
hotel_df['total_nights'] = hotel_df['stays_in_weekend_nights'] + hotel_df['stays_in_week_nights']
hotel_df.drop(['stays_in_weekend_nights', 'stays_in_week_nights'], axis=1, inplace=True)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738264063093&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Season 파생변수 만들고 'arrival_date_month'를 사용하여 계절로 나누기
# 12, 1, 2 : winter
# 3, 4, 5 : spring
# 6, 7, 8 : summer
# 9, 10, 11 : fall
season_dic = {
    'spring' : {3, 4, 5},
    'summer' : {6, 7, 8},
    'fall' : {9, 10, 11},
    'winter' : {12, 1, 2},
}

new_season_dic = {}
for i in season_dic :
    for j in season_dic[i] :
        new_season_dic[calendar.month_name[j]] = i

new_season_dic

# map(dict) : 키값에 해당하는 값 찾아서 벨류값 집어넣기
hotel_df['season'] = hotel_df['arrival_date_month'].map(new_season_dic)
hotel_df.head()

hotel_df.drop(['arrival_date_month'], axis=1, inplace=True)

# 예약된 룸 타입과 실제 룸타입이 같은지 여부를 확인하는 파생변수 생성
hotel_df['expected_room_type'] = (hotel_df['reserved_room_type'] == hotel_df['assigned_room_type']).astype(int)
hotel_df.drop(['reserved_room_type', 'assigned_room_type'], axis=1, inplace=True)

# 총 예약중 취소 한 비율 파생변수 생성
hotel_df['cancel_rate'] = hotel_df['previous_cancellations'] / (hotel_df['previous_cancellations'] + hotel_df['previous_bookings_not_canceled'])
hotel_df.head()

# 총 예약이 0인 값들도 존재함 (그 값은 NaN으로 되어있다)
hotel_df[hotel_df['cancel_rate'].isna()]

# 위 수식에서 나올 수 없는 값을 넣어 차별점 주기
hotel_df['cancel_rate'] = hotel_df['cancel_rate'].fillna(-1)

hotel_df.drop(['previous_cancellations', 'previous_bookings_not_canceled'], axis=1, inplace=True)

# 예약된 경로를 알수 없는 데이터 확인
hotel_df['agent'].value_counts(dropna=False).sort_index()

# 나올 수 없는 값으로 변경
hotel_df['agent'] = hotel_df['agent'].fillna(-1)

hotel_df['company'].value_counts(dropna=False).sort_index()

hotel_df['company'] = hotel_df['company'].fillna(-1)

# 수치형 데이터가 아닌 컬럼 중 유니크한 데이터의 종류 개수 확인
for i in hotel_df.select_dtypes(exclude=['number']).columns.tolist() :
    print(i, hotel_df[i].nunique())
    
# 연관성이 크게 있어보이지 않는 컬럼들 제거
hotel_df.drop(['meal', 'country', 'reservation_status_date'], axis=1, inplace=True)

# object타입 one-hot encoding
hotel_df = pd.get_dummies(hotel_df, columns=hotel_df.select_dtypes(exclude=['number']).columns.tolist(), drop_first=True)

hotel_df.info()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Logistic Regression의 규제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 규제(Regularization)는 머신러닝 모델이 Overfitting 되는 것을 방지하기 위해 사용되는 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Overfitting이란 모델이 학습 데이터에 지나치게 맞춰져서, 새로운 데이터(Test 데이터)에는 제대로 일반화 하지 못하는 현상입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 규제는 모델의 복잡도를 줄이고, 불필요한 W(가중치)를 작게 만들어 과적합을 방지합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL3zJa/btsL3YgQ89S/QnLfSISssz3jS0EC2oK37K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL3zJa/btsL3YgQ89S/QnLfSISssz3jS0EC2oK37K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL3zJa/btsL3YgQ89S/QnLfSISssz3jS0EC2oK37K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL3zJa%2FbtsL3YgQ89S%2FQnLfSISssz3jS0EC2oK37K%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;1090&quot; height=&quot;220&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738264711303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(X_train, y_train)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복 횟수가 부족하면 ConvergenceWarning 경고가 나타날 수 있습니다.&lt;/li&gt;
&lt;li&gt;이는 알고리즘이 최적의 해를 찾지 못했다는 의미입니다.&lt;/li&gt;
&lt;li&gt;max_iter : 최대 반복 횟수를 지정하여 최적의 가중치를 찾습니다. (기본값은 100입니다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;※ epoch와 max_iter의 차이&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmffFh/btsL2zCbl00/nu7ek7FkKoQk0YYExCdGvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmffFh/btsL2zCbl00/nu7ek7FkKoQk0YYExCdGvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmffFh/btsL2zCbl00/nu7ek7FkKoQk0YYExCdGvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmffFh%2FbtsL2zCbl00%2Fnu7ek7FkKoQk0YYExCdGvk%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;582&quot; height=&quot;154&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 데이터 스케일링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터 스케일링은 서로 다른 범위와 단위를 가진 데이터를 일정한 범위로 변환하여 모델 학습을 더 효율적으로 수행 할 수 있도록 만드는 전처리 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 변수 간의 값의 크기 차이가 클 때 발생하는 불균형을 해결하기 위해 사용되며, 대표적인 방법으로는 표준화(Standardization)와 정규화(Normalization)가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스케일링을 통해 학습 속도를 높이고, 기울기 소실(Gradient Vinishing) 문제를 완화하며, 특정 변수에 모델이 과도하게 의존하는 것을 방지 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5-1. Standardization&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정규화는 데이터의 평균을 0으로, 표준편차를 1로 변환하여 모든 변수가 동일한 척도를 갖도록 만드는 데이터 전처리 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 주로 데이터의 분포가 정규 분포를 따를 때 효과적이며, 값의 크기나 단위가 서로 다른 변수를 비교하거나 머신러닝 알고리즘(ex : Logistic Regression, SVM 등)에서 최적의 성능을 내기 위해 사용됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce6O7v/btsL25ViQYF/fOnOI3knaJNxDUUS5OQF1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce6O7v/btsL25ViQYF/fOnOI3knaJNxDUUS5OQF1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce6O7v/btsL25ViQYF/fOnOI3knaJNxDUUS5OQF1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce6O7v%2FbtsL25ViQYF%2FfOnOI3knaJNxDUUS5OQF1K%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;756&quot; height=&quot;504&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5-2. Normalization&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정규화는 데이터의 값을 특정 범위(주로 0과 1사이)로 변환하여 변수 간의 스케일 차이를 줄이는 데이터 전처리 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이는 주로 최솟값과 최댓값을 사용해 데이터를 조정하며, 대표적인 방법으로는 Min-Max Scaling이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qf9oM/btsL24hOudB/P3nkeZyLc7AD5BbF42U7wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qf9oM/btsL24hOudB/P3nkeZyLc7AD5BbF42U7wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qf9oM/btsL24hOudB/P3nkeZyLc7AD5BbF42U7wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqf9oM%2FbtsL24hOudB%2FP3nkeZyLc7AD5BbF42U7wK%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;690&quot; height=&quot;706&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738265368560&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = sclaer.fit_transform(X_test)

model = LogisticRegression(max_iter=1000)
model.fit(X_train_scaled, y_train)

pred = model.prdict(X_test_scaled)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738265491418&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 분류 모델의 정확도 계산하기 0~1사이의 값을 가짐
# 올바르게 분류 된 샘플의 비율을 반환함
from sklearn.metrics import accuracy_score

accuracy_score(y_test, pred)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 혼돈 행렬&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 혼돈 행렬(Confusion Matrix)은 분류 모델의 성능을 평가하기 위해 사용되는 도구로, 예측 결과와 실제 레이블 간의 관계를 요약하여 나타낸 행렬입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 행렬은 Binary Classification 문제 에서 4가지 값으로 구성됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;True Positive(TP)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;실제값이 양성이고, 모델도 양성으로 올바르게 예측한 경우&lt;/li&gt;
&lt;li&gt;ex : 실제로 스팸 메일이고, 모델이 스펨메일로 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;True Nagative(TN)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;실제값이 음성이고, 모델도 음성으로 올바르게 예측한 경우&lt;/li&gt;
&lt;li&gt;ex : 실제로 정상 메일이고, 모델이 정상 메일로 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;False Positive(FP)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;실제값은 음성이지만, 모델이 양성으로 잘못 예측한 경우&lt;/li&gt;
&lt;li&gt;ex : 정상 메일을 스팸으로 잘못 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;False Negative(FN)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;실제값은 양성이지만, 모델이 음성으로 잘못 예측한 경우&lt;/li&gt;
&lt;li&gt;ex : 스팸 메일을 정상 메일로 잘못 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- TP와 TN은 모델이 올바르게 에측한 경우를 나타내며, FP와 FN은 모델이 잘못 예측된 경우를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 분류 모델의 정확도(Accuracy), 정밀도(Precision), 재현율(Recall), F1-score와 같은 다양한 성능 지표를 계산할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 혼동 행렬은 특히 클래스 간의 불균형이 있는 데이터에서 모델의 예측 성능을 구체적으로 분석할 때 유용합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;111&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7TDVf/btsL1iuEx7v/39H6U7pCUAJItTSwkzZod0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7TDVf/btsL1iuEx7v/39H6U7pCUAJItTSwkzZod0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7TDVf/btsL1iuEx7v/39H6U7pCUAJItTSwkzZod0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7TDVf%2FbtsL1iuEx7v%2F39H6U7pCUAJItTSwkzZod0%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;111&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;111&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 혼돈행렬로 계산할 수 있는 지표&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;519&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHf8Xg/btsL3zBB2mC/FKtDnqdAE5tqvtCq408F1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHf8Xg/btsL3zBB2mC/FKtDnqdAE5tqvtCq408F1K/img.png&quot; data-alt=&quot;조화 평균이란? 얼마만큼 조화롭게 되어있나의 평균&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHf8Xg/btsL3zBB2mC/FKtDnqdAE5tqvtCq408F1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHf8Xg%2FbtsL3zBB2mC%2FFKtDnqdAE5tqvtCq408F1K%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;559&quot; height=&quot;519&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;519&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;조화 평균이란? 얼마만큼 조화롭게 되어있나의 평균&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738266314584&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score

confusion_matrix(y_test, pred)

# 양성으로 예측한 것에서 실제 양성의 비율
print(precision_score(y_test, pred))

# 실제 양성 중에서 양성으로 예측한 비율
print(recall_score(y_test, pred))

# 정밀도와 재현율의 조화평균
print(f1_score(y_test, 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;&lt;b&gt;※ Weight와 bias 값 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738266399192&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 독립 변수의 Weight
lr.coef_

# bias
lr.intercept_&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_1738266547230&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 확률 값 뽑기
proba = lr.predict_proba(X_test)

# Binary Classification 문제 이기 때문에 임계점을 설정하여 2번째 값과 비교 후 분류
proba = lr.predict_proba(X_test)[:, 1]
threshold = 0.5
pred = (proba &amp;gt;= threshold).astype(int)
pred&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 분류 문제에서의 Random Forest (주택 임대로 예측에서 설명하였기 때문에 정의 설명은 생략하겠습니다.)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(과정)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 트리의 Node Split 단계에서, 전체 특성이 아닌 무작위로 선택된 일부 특성만을 사용합니다.&lt;/li&gt;
&lt;li&gt;이를 통해 트리 간의 상관관계를 줄이고, Overfitting을 방지합니다.&lt;/li&gt;
&lt;li&gt;각 트리에 들어가는 데이터의 개수는 원본 데이터셋 크기와 동일합니다.&lt;/li&gt;
&lt;li&gt;그러나 중복을 허용하여 샘플링(부트스트래핑)하므로, 일부 데이터는 여러 번 샘플링 되고, 일부 데이터는 선택되지 않을 수 있습니다.&lt;/li&gt;
&lt;li&gt;부트스트래핑(Bootstrapping)된 데이터와 랜덤하게 선택된 특성을 사용하여 Decision Tree를 학습합니다.&lt;/li&gt;
&lt;li&gt;Sklearn에서 Random Forest의 기본 트리 개수는 100개 입니다.&lt;/li&gt;
&lt;li&gt;다수결(Majority Voting) : Classification 문제에서 가장 많이 예측된 클래스를 선택합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1738267204418&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.ensemble import RandomForestClassifier

X_train, X_test, y_train, y_test = train_test_split(hotel_df.drop('is_canceled', axis=1), hotel_df['is_canceled'], test_size=0.3, random_state=2025)

rf = RandomForestClassifier(random_state=2025)
rf.fit(X_train, y_train)
pred = rf.predict(X_test)
pred

proba = rf.predict_proba(X_test)
# 모든 테스트 데이터에 대한 호텔 예약을 취소 할 확률만 출력
proba[:, 1]

confusion_matrix(y_test, pred)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738267255308&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 혼돈 행렬을 코드 출력값으로 보기
from sklearn.metrics import classification_report

print(classification_report(y_test, pred))&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8. ROC AUC Score&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ROC AUC Score(Receriver Operating Characteristic - Area Under the Curve)는 이진 분류 모델의 성능을 평가하는 지표로, 분류기의 예측 능력을 직관적으로 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ROC곡선은 FPR(거짓 양성 비율)과 TPR(참 양성 비율)을 축으로 하여 다양한 임계값에서 모델의 성능을 시각화한 곡선입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AUC는 ROC곡선 아래의 면적을 나타내며 값이 1에 가까울수록 완벽한 분류 성능을 의미하고, 0.5에 가까울수록 랜덤 추측에 가까운 성능을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 따라서 ROC AUC Score는 모델의 분류 성능이 얼마나 좋은지를 평가하는 데에 중요한 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;8-1. ROC Curve&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ROC 곡선은 Binary Classification Model의 성능을 평가하기 위해 사용하는 곡선으로, 모델의 민감도(참 양성 비율, TPR)와 특이도(참 음성 비율, TNR)의 반대인 거짓 양성 비율(FPR)의 관계를 시각화한 그래프입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yj22X/btsL2J5Wwnh/MQLOxJNrK3b03Y8YUP6RKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yj22X/btsL2J5Wwnh/MQLOxJNrK3b03Y8YUP6RKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yj22X/btsL2J5Wwnh/MQLOxJNrK3b03Y8YUP6RKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyj22X%2FbtsL2J5Wwnh%2FMQLOxJNrK3b03Y8YUP6RKK%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;682&quot; height=&quot;302&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;302&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;8-2. AUC&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AUC는 ROC Curve 아래의 면적을 나타내며, Binary Classification의 성능을 하나의 숫자로 나타내는 지표입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AUC = 1 : 완벽한 분류기&lt;/li&gt;
&lt;li&gt;AUC = 0.5 : 랜덤 추즉 수준&lt;/li&gt;
&lt;li&gt;AUC &amp;lt; 0.5 : 모델 성능이 무작위 추측보다 나쁨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 수학적으로 AUC는 양성 클래스와 음성 클래스의 예측 점수를 비교해 양성 클래스가 더 높은 점수를 받을 확률을 나타냅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738268313491&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.metrics import roc_auc_score
from sklearn.metrics._plot.roc_curve import roc_curve
import matplotlib.pyplot as plt

# roc_auc_score(TestSet의 종속변수, 확률값())
roc_auc_score(y_test, proba[:, 1])

# FPR, TPR, Threshold값 나옴
fpr, tpr, thr = roc_curve(y_test, proba[:, 1])
print(fpr, tpr, thr)

plt.plot(fpr, tpr, label='ROC Curve')
plt.plot([0, 1], [0, 1])
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;9. 교차 검증&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 교차 검증(Cross Validation)은 모델의 성능을 더 정확히 평가하기 위해 데이터를 반복적으로 Train 데이터와, Validation 데이터로 나누어 사용하는 기법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 가장 일반적인 방식인 k-겹 교차 검증(k-fold Cross Validation)은 데이터를 k개의 동일한 크기로 나누고, 각 부분을 한 번씩을 Validation 데이터로 사용하며 나머지 부분을 Train 데이터로 사용하여 모델을 훈련하고 평가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이를 통해 데이터 분할에 따른 편향을 줄이고, 모델의 예측 능력을 신뢰성 있게 측정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Cross Validation은 특히 데이터셋이 작거나 편향된 경우에 유용하며, Overfitting을 방지하는 데 도움을 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Py9Oj/btsL1iOXijP/ks8FF3b27Y8RJz61Gr3oUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Py9Oj/btsL1iOXijP/ks8FF3b27Y8RJz61Gr3oUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Py9Oj/btsL1iOXijP/ks8FF3b27Y8RJz61Gr3oUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPy9Oj%2FbtsL1iOXijP%2Fks8FF3b27Y8RJz61Gr3oUk%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;697&quot; height=&quot;330&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738268768006&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.model_selection import KFold

# n_split : 쪼개는 단위
kf = KFold(n_split=5)
kf

# kf.split() : k개의 폴드로 나눔
for train_index, valid_index in kf.split(range(len(hotel_df))) :
    print(train_index, valid_index, len(train_index), len(valid_index))
    
# 하이퍼 파라미터 조정하기
kf = KFold(n_split=5, random_state=2025, shuffle=True)
kf

for train_index, valid_index in kf.split(range(len(hotel_df))) :
    print(train_index, valid_index, len(train_index), len(valid_index))&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738268991450&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;acc_list = []

for train_index, valid_index in kf.split(range(len(hotel_df))) :
    X = hotel_df.drop('is_canceled', axis=1)
    y = hotel_df['is_canceled']

    X_train = X.iloc[train_index]
    X_valid = X.iloc[valid_index]
    y_train = y.iloc[train_index]
    y_valid = y.iloc[valid_index]

    rf = RandomForestClassifier()
    rf.fit(X_train, y_train)
    pred = rf.predict(X_valid)
    acc_list.append(accuracy_score(y_valid, pred))
    
print(acc_list)
print(pred)
print(y_valid)&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/45</guid>
      <comments>https://dldbwls0818.tistory.com/45#entry45comment</comments>
      <pubDate>Fri, 31 Jan 2025 06:01:11 +0900</pubDate>
    </item>
    <item>
      <title>와인 품종 예측</title>
      <link>https://dldbwls0818.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 와인 품종 DataSet&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- sklearn에서 제공되는 데이터셋으로 이탈리아의 같은 지역에서 재배된 세가지 품종으로 만든 와인을 화학적으로 분석한 결과대한 데이터가 담겨져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이 데이터 셋으로 13개의 성분을 분석하여 어떤 와인인지 구별하는 모델을 만들어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 마지막에 테스트 데이터셋의 0번째 인덱스에 해당되는 데이터를 넣어 어떤 와인인지 출력해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738254045984&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_wine&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. DataSet 다루기&lt;/p&gt;
&lt;pre id=&quot;code_1738254164605&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wine = load_wine()
wine

print(wine['DESCR'])

data = wine['data']
target = wine['target']
feature_names = wine['feature_names']

wine_df = pd.DataFrame(data, columns=feature_names)
wine_df['target'] = target

wine_df.info()&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_1738254343956&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;wine_corr = wine_df.corr()

plt.figure(figsize=(16, 16))
sns.heatmap(wine_corr, annot=True, fmt='.2f', cmap='coolwarm')
plt.title('Feature Correlation Heatmap')
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;3. Train, Test 분리 후 모델 생성 및 다중 분류 예측&lt;/p&gt;
&lt;pre id=&quot;code_1738254842345&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X_train, X_test, y_train, y_test = train_test_split(wine_df.drop('target', axis=1), wine_df['target'], test_size=0.2, random_state=2025)
print(X_train.shape, X_test.shape)
print(y_train.shape, y_test.shape)

model = nn.Sequential(
	nn.Linear(13, 3)
)

list(model.parameters())

X_train = X_train.to_numpy()
y_train = y_train.to_numpy()
X_test = X_test.to_numpy()
y_test = y_test.to_numpy()

X_train = torch.FloatTensor(X_train)
y_train = torch.LongTensor(y_train)
X_test = torch.FloatTensor(X_train)
y_test = torch.LongTensor(y_train)

optimizer = optim.Adam(model.parameters(), lr=0.001)
epochs = 10000

for epoch in range(epochs + 1) :
    y_pred = model(X_train)
    loss = nn.CrossEntropyLoss()(y_pred, y_train)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100 == 0 :
        print(f'Epoch: {epoch}/{epochs}, Loss: {loss:.6f}')
        
y_pred = model(X_test[:1])
y_prob = nn.Softmax(1)(y_pred)

print(f'0일 확률: {y_prob[0][0]:.2f}')
print(f'1일 확률: {y_prob[0][1]:.2f}')
print(f'2일 확률: {y_prob[0][2]:.2f}')&lt;/code&gt;&lt;/pre&gt;</description>
      <author>dldbwls0818</author>
      <guid isPermaLink="true">https://dldbwls0818.tistory.com/44</guid>
      <comments>https://dldbwls0818.tistory.com/44#entry44comment</comments>
      <pubDate>Fri, 31 Jan 2025 01:34:07 +0900</pubDate>
    </item>
  </channel>
</rss>