diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000000..5ae69bd5f0e8 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.5 diff --git a/Gemfile b/Gemfile index 1291498971d7..84231f2f24e4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,7 @@ source "https://rubygems.org" -gemspec \ No newline at end of file +gemspec +gem "webrick", "~> 1.7" + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo' +gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/_config.yml b/_config.yml index ba2b50db9660..036751a48189 100644 --- a/_config.yml +++ b/_config.yml @@ -15,24 +15,24 @@ minimal_mistakes_skin : "default" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" # Site Settings -locale : "en-US" -title : "Site Title" -title_separator : "-" -subtitle : # site tagline that appears below site title in masthead -name : "Your Name" -description : "An amazing website." -url : # the base hostname & protocol for your site e.g. "https://mmistakes.github.io" +locale : "ko-KR" +title : "YoonkieNote" +title_separator : "|" +subtitle : "Simply, Deeply" +name : "YoonkieNote" +description : "나만의 개발 공부 일지" +url : "https://minyoongi96.github.io" baseurl : # the subpath of your site, e.g. "/blog" repository : # GitHub username/repo-name e.g. "mmistakes/minimal-mistakes" teaser : # path of fallback teaser image, e.g. "/assets/images/500x300.png" logo : # path of logo image to display in the masthead, e.g. "/assets/images/88x88.png" masthead_title : # overrides the website title displayed in the masthead, use " " for no title -# breadcrumbs : false # true, false (default) +breadcrumbs : true # true, false (default) words_per_minute : 200 comments: - provider : # false (default), "disqus", "discourse", "facebook", "staticman", "staticman_v2", "utterances", "giscus", "custom" + provider : "disqus" # (default), "disqus", "discourse", "facebook", "staticman", "staticman_v2", "utterances", "giscus", "custom" disqus: - shortname : # https://help.disqus.com/customer/portal/articles/466208-what-s-a-shortname- + shortname : "yoonkienote" discourse: server : # https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963 , e.g.: meta.discourse.org facebook: @@ -73,7 +73,7 @@ google: # SEO Related google_site_verification : bing_site_verification : -naver_site_verification : +naver_site_verification : "efd9a2ff3152882228024e338d6cffdcac9804f6" yandex_site_verification : baidu_site_verification : @@ -94,60 +94,40 @@ social: # Analytics analytics: - provider : false # false (default), "google", "google-universal", "google-gtag", "custom" + provider : "google-gtag" # false (default), "google", "google-universal", "google-gtag", "custom" google: - tracking_id : - anonymize_ip : # true, false (default) + tracking_id : "G-D9JJMVGYQH" + anonymize_ip : false # Site Author author: - name : "Your Name" - avatar : # path of avatar image, e.g. "/assets/images/bio-photo.jpg" - bio : "I am an **amazing** person." - location : "Somewhere" + name : "minyoongi96" + avatar : "/assets/images/MyProfile.png" # path of avatar image, e.g. "/assets/images/bio-photo.jpg" + bio : "웹 개발 끄적끄적" + location : #"Somewhere" email : links: - label: "Email" icon: "fas fa-fw fa-envelope-square" - # url: "mailto:your.name@email.com" - - label: "Website" - icon: "fas fa-fw fa-link" - # url: "https://your-website.com" - - label: "Twitter" - icon: "fab fa-fw fa-twitter-square" - # url: "https://twitter.com/" - - label: "Facebook" - icon: "fab fa-fw fa-facebook-square" - # url: "https://facebook.com/" + url: "zoobon63@gmail.com" - label: "GitHub" icon: "fab fa-fw fa-github" - # url: "https://github.com/" + url: "https://github.com/minyoongi96" - label: "Instagram" icon: "fab fa-fw fa-instagram" - # url: "https://instagram.com/" + url: "https://instagram.com/yoon___kie" # Site Footer footer: links: - - label: "Twitter" - icon: "fab fa-fw fa-twitter-square" - # url: - - label: "Facebook" - icon: "fab fa-fw fa-facebook-square" - # url: + - label: "GitHub" icon: "fab fa-fw fa-github" - # url: - - label: "GitLab" - icon: "fab fa-fw fa-gitlab" - # url: - - label: "Bitbucket" - icon: "fab fa-fw fa-bitbucket" - # url: + url: "https://github.com/minyoongi96" - label: "Instagram" icon: "fab fa-fw fa-instagram" - # url: + url: "https://instagram.com/yoon___kie" # Reading Files @@ -216,9 +196,9 @@ sass: # Outputting permalink: /:categories/:title/ -paginate: 5 # amount of posts to show +paginate: 10 # amount of posts to show paginate_path: /page:num/ -timezone: # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +timezone: Asia/Seoul # Plugins (previously gems:) @@ -255,16 +235,16 @@ tag_archive: type: liquid path: /tags/ # https://github.com/jekyll/jekyll-archives -# jekyll-archives: -# enabled: -# - categories -# - tags -# layouts: -# category: archive-taxonomy -# tag: archive-taxonomy -# permalinks: -# category: /categories/:name/ -# tag: /tags/:name/ +jekyll-archives: + enabled: + - categories + - tags + layouts: + category: archive-taxonomy + tag: archive-taxonomy + permalinks: + category: /categories/:name/ + tag: /tags/:name/ # HTML Compression @@ -285,6 +265,7 @@ defaults: layout: single author_profile: true read_time: true - comments: # true + comments: true share: true related: true + show_date : true diff --git a/_data/navigation.yml b/_data/navigation.yml index 6f30866f3bed..851e06b89b48 100644 --- a/_data/navigation.yml +++ b/_data/navigation.yml @@ -1,7 +1,9 @@ # main links main: - - title: "Quick-Start Guide" - url: https://mmistakes.github.io/minimal-mistakes/docs/quick-start-guide/ + - title: "Category" + url: /categories/ + - title: "Tag" + url: /tags/ # - title: "About" # url: https://mmistakes.github.io/minimal-mistakes/about/ # - title: "Sample Posts" @@ -9,4 +11,32 @@ main: # - title: "Sample Collections" # url: /collection-archive/ # - title: "Sitemap" - # url: /sitemap/ \ No newline at end of file + # url: /sitemap/ + +# docs: +# - title: Back-end +# childen: +# - title: "Spring" +# url: spring/ +# category: "springboot" +# - title: AI +# childen: +# - title: "Deep Learning" +# url: deeplearning/ +# category: "딥러닝" +# - title: "Machine Learning" +# url: machinelearning/ +# category: "머신러닝" +# - title: 알고리즘 +# childen: +# - title: "Algorithm" +# url: algorithm/ +# category: "자료구조-알고리즘" +# - title: Git +# childen: +# - title: "Git" +# url: git/ +# category: "git" +# - title: AWS +# url: aws/ +# category: "AWS" \ No newline at end of file diff --git a/_includes/breadcrumbs.html b/_includes/breadcrumbs.html index 75c032a4b724..e714889e5e2f 100644 --- a/_includes/breadcrumbs.html +++ b/_includes/breadcrumbs.html @@ -11,7 +11,7 @@ {% else %} {% assign crumb_path = site.category_archive.path %} {% endif %} - + \ No newline at end of file diff --git a/_includes/nav_list b/_includes/nav_list index a035a5bd7b15..db650bd71f69 100644 --- a/_includes/nav_list +++ b/_includes/nav_list @@ -16,7 +16,8 @@ {% if nav.children != null %} {% endif %} diff --git a/_includes/nav_list_bak b/_includes/nav_list_bak new file mode 100644 index 000000000000..a035a5bd7b15 --- /dev/null +++ b/_includes/nav_list_bak @@ -0,0 +1,26 @@ +{% assign navigation = site.data.navigation[include.nav] %} + + diff --git a/_includes/page__meta.html b/_includes/page__meta.html index 3d228c921205..575542ef23eb 100644 --- a/_includes/page__meta.html +++ b/_includes/page__meta.html @@ -9,14 +9,14 @@ {% endif %} - - {% if document.read_time and document.show_date %}{% endif %} + + {% if document.read_time and document.show_date %}{% endif %} {% if document.read_time %} {% assign words_per_minute = document.words_per_minute | default: site.words_per_minute | default: 200 %} {% assign words = document.content | strip_html | number_of_words %} - + {% endif %}

{% endif %} diff --git a/_includes/sidebar.html b/_includes/sidebar.html index a4ca1ca78151..4c25cc498ab8 100644 --- a/_includes/sidebar.html +++ b/_includes/sidebar.html @@ -5,7 +5,7 @@ {% for s in page.sidebar %} {% if s.image %} {% if s.image_alt %}{{ s.image_alt }}{% endif %} + alt="{% if s.image_alt %}{{ s.image_alt }}{% endif %}"> {% endif %} {% if s.title %}

{{ s.title }}

{% endif %} {% if s.text %}{{ s.text | markdownify }}{% endif %} diff --git a/_pages/category-archive.md b/_pages/category-archive.md new file mode 100644 index 000000000000..3cd6f6e06761 --- /dev/null +++ b/_pages/category-archive.md @@ -0,0 +1,7 @@ +--- +title: "Category" +layout: categories +permalink: /categories/ +author_profile: true +sidebar_main: true +--- \ No newline at end of file diff --git a/_pages/tag-archive.md b/_pages/tag-archive.md new file mode 100644 index 000000000000..58ae8e76afc6 --- /dev/null +++ b/_pages/tag-archive.md @@ -0,0 +1,7 @@ +--- +title: "Tag" +layout: tags +permalink: /tags/ +author_profile: true +sidebar_main: true +--- \ No newline at end of file diff --git a/_posts/2022-01-05-Numpy.md b/_posts/2022-01-05-Numpy.md new file mode 100644 index 000000000000..b2cda2142eb9 --- /dev/null +++ b/_posts/2022-01-05-Numpy.md @@ -0,0 +1,687 @@ +--- +layout: single +title: "[Python] Numpy 개인 정리" +categories: Python +tag: [python, Numpy, 파이썬] +toc: true +toc_sticky: true +--- + + + + + + +```python +import numpy as np +``` + + +```python +# numpy의 배열 생성 +list1 = [1,2,3,4,5] +list2 = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] + +arr1 = np.array(list1) # 1차원 배열 +arr1 +``` + + + + + array([1, 2, 3, 4, 5]) + + + + +```python +arr2 = np.array(list2) # 2차원 배열 +arr2 +``` + + + + + array([[ 1, 2, 3, 4], + [ 5, 6, 7, 8], + [ 9, 10, 11, 12]]) + + + + +```python +# 배열의 크기 확인 +print(arr1.shape) +print(arr2.shape) +``` + + (5,) + (3, 4) + + + +```python +# size는 배열 내의 요소 개수 +print(arr1.size) +print(arr2.size) +``` + + 5 + 12 + + + +```python +# 배열의 데이터 타입 확인 +print(arr1.dtype) +print(arr2.dtype) +``` + + int64 + int64 + + + +```python +# 배열의 차원 확인 +print(arr1.ndim) +print(arr2.ndim) +``` + + 1 + 2 + + + +```python +# 배열 초기화 +arr_zero = np.zeros((3,3)) +print(arr_zero) +print(arr_zero.dtype) + +arr_one = np.ones((2,3)) +print(arr_one) +``` + + [[0. 0. 0.] + [0. 0. 0.] + [0. 0. 0.]] + float64 + [[1. 1. 1.] + [1. 1. 1.]] + + + +```python +# 특정 값으로 배열 초기화 +# np.full(차원, 데이터) + +arr_full = np.full((4,3), 'z') +print(arr_full) +``` + + [['z' 'z' 'z'] + ['z' 'z' 'z'] + ['z' 'z' 'z'] + ['z' 'z' 'z']] + + + +```python +# 범위를 지정해서 배열 생성 +# arange(시작점, 끝점+1, 데이터 폭) +arr = np.arange(1,51,5) +print(arr) +print(arr.shape) +print(arr.size) +``` + + [ 1 6 11 16 21 26 31 36 41 46] + (10,) + 10 + + + +```python +# 배열 생성 시 타입 지정 +arr_type = np.array([1,2,2,5,3,4], dtype=np.str0) + +print(arr_type) + +# 타입 변경 +arr_type = arr_type.astype('int64') +print(arr_type) +``` + + ['1' '2' '2' '5' '3' '4'] + [1 2 2 5 3 4] + + + +```python +# 랜덤 값으로 배열 생성 +# np.random.rand(차원 수) : 랜덤 실수값 +arr_random = np.random.rand(2,3) +print(arr_random) +``` + + [[0.069824 0.56538797 0.08239869] + [0.05746204 0.47192185 0.65286904]] + + + +```python +# np.random.randint(시작점, 끝점, size=(차원 수)) : 시작점부터 끝점-1 까지의 랜덤 정수 값 +arr_random2 = np.random.randint(1,11, size=(3,3)) +arr_random2 +``` + + + + + array([[ 3, 10, 5], + [ 1, 3, 8], + [ 9, 9, 8]]) + + + + +```python +# array 연산 +array1 = np.array([1,2,3]) +array2 = np.array([4,5,6]) + +print(array1+array2) +print(array1 / array2) +print(array1 // array2) +print(array1 % array2) +``` + + [5 7 9] + [0.25 0.4 0.5 ] + [0 0 0] + [1 2 3] + + +- BMI 지수 구하기 + + +```python +# txt파일 불러오기 +data = np.loadtxt('/Users/min-yungi/Desktop/20210905pr/data/height_weight.txt', delimiter = ',') +print(data) +print(data.shape) +print(data[1,0]) +``` + + [[175.2 180.3 175. 169.2 185.2 188. 177.6 178.2 177. 179. ] + [ 65.6 88. 79.2 69.3 55. 71.2 73. 68.9 74. 82. ]] + (2, 10) + 65.6 + + + +```python +height = data[0] * 0.01 +print(height) +``` + + [1.752 1.803 1.75 1.692 1.852 1.88 1.776 1.782 1.77 1.79 ] + + + +```python +weight = data[1] +print(weight) +``` + + [65.6 88. 79.2 69.3 55. 71.2 73. 68.9 74. 82. ] + + + +```python +bmi = weight/(height**2) +print(bmi) +``` + + [21.37153104 27.07018468 25.86122449 24.20652885 16.03543423 20.14486193 + 23.14392095 21.69720651 23.62028791 25.59220998] + + + - Indexing & Slicing + + +```python +array7 = np.arange(10) +print(array7) + +print(array7[3:8]) + +array7[3:8] = 10 +print(array7) +``` + + [0 1 2 3 4 5 6 7 8 9] + [3 4 5 6 7] + [ 0 1 2 10 10 10 10 10 8 9] + + + +```python +# 2차원 배열 생성 +array8 = np.arange(50).reshape(5,10) +print(array8) +print(array8.shape) + +# 2차원 배열 슬라이싱 +print(array8[1:4,4:9]) +``` + + [[ 0 1 2 3 4 5 6 7 8 9] + [10 11 12 13 14 15 16 17 18 19] + [20 21 22 23 24 25 26 27 28 29] + [30 31 32 33 34 35 36 37 38 39] + [40 41 42 43 44 45 46 47 48 49]] + (5, 10) + [[14 15 16 17 18] + [24 25 26 27 28] + [34 35 36 37 38]] + + +- Boolean 색인 + + +```python +name = np.array(['윤기','석준','원빈','은수','태헌']) +name +``` + + + + + array(['윤기', '석준', '원빈', '은수', '태헌'], dtype='=4.5,0].astype('int') +over4 +``` + + + + + array([ 91, 101, 215, 233, 266, 283, 288, 307, 372, 446, 447, + 451, 567, 661, 682, 761, 764, 951, 953, 989, 1021, 1131, + 1315, 1349, 1378, 1437, 1569, 1670, 1702, 1856, 1863, 1940, 1959, + 1986, 2118, 2155, 2243, 2339, 2363, 2497, 2510, 2574, 2593, 2694, + 2726, 2791, 2838, 2849, 2922, 2964, 3036, 3073, 3210, 3282, 3287, + 3306, 3324, 3437, 3461, 3596, 3604, 3699, 3738, 3864, 3902, 4136, + 4176, 4187, 4189, 4273, 4518, 4584, 4589, 4595, 4634, 4649, 4755, + 4801, 4904, 4925, 4982, 5003, 5069, 5073, 5102, 5165, 5212, 5255, + 5343, 5427, 5499, 5542, 5582, 5609, 5696, 5768, 5839, 5862, 5936, + 5984]) + + + + +```python +# 최고 평균 평점 구하기 +max_mean = arr_means[:,1].max() +max_mean +``` + + + + + 4.962962962962963 + + + + +```python +# 최고 평점 구하기 +data[:,2].max() +``` + + + + + 5 + + diff --git a/_posts/2022-01-07-Queue.md b/_posts/2022-01-07-Queue.md new file mode 100644 index 000000000000..345a273c3e48 --- /dev/null +++ b/_posts/2022-01-07-Queue.md @@ -0,0 +1,383 @@ +--- +layout: single +title: "[자료구조/알고리즘] 큐(Queue)와 덱(Deque)" +categories: 자료구조/알고리즘 +tag: [python, 파이썬, Queue, Deque, 큐, 덱, SinglyLinkedList, 자료구조, 알고리즘] +toc: true +toc_sticky: true +--- + + + + + +### 큐(Queue) + +
+ ++ FIFO(선입선출) 형식의 자료구조 ++ 먼저 들어온 데이터가 순서대로 먼저 나가는 구조입니다. +스택과 다르게 한쪽에서 데이터가 추가되고, 다른 한쪽에서 데이터가 삭제되는 구조입니다. + +#### 리스트를 이용한 큐 구현 + +
+ ++ enqueue : 큐의 맨 뒤쪽에 항목 삽입 ++ dequeue : 큐 맨 앞쪽의 항목을 반환하고 제거 ++ peek/front : 큐의 맨 앞쪽 항목을 조회 ++ empty : 큐가 비었는지 확인 ++ size : 큐의 크기를 확인 + + +```python +# 리스트를 이용한 Queue 구현 +class Queue(object): + def __init__(self): + self.items = [] # 값을 담아줄 큐 배열 + + # 큐가 비었는지 확인하는 함수(Empty : True / Not Empty : false) + def isEmpty(self): + return not self.items + + def dequeue(self): + # 큐가 비어있다면 + if self.isEmpty(): + print("Queue is Empty!") + + # 그렇지 않으면 + else: + value = self.items.pop(0) # 큐 배열의 0번째 값을 반환 + return value + + + def enqueue(self, item): + self.items.append(item) # 큐 배열의 맨 뒤에 값을 삽입 + + def size(self): + return len(self.items) # 큐 배열의 크기를 반환 + + def peek(self): + if self.isEmpty(): + print("Queue is Empty!") + + else: + return self.items[0] + + def __repr__(self): + return repr(self.items) +``` + +```python +if __name__ == "__main__": + queue = Queue() + print("큐가 비었습니까? {}".format(queue.isEmpty())) + print("큐에 값을 추가합니다.") + for i in range(10): + queue.enqueue(i) + print("Queue : {}".format(queue)) + print("큐의 크기 : {}".format(queue.size())) + print("peek : {}".format(queue.peek())) + print("dequeue : {}".format(queue.dequeue())) + print("peek : {}".format(queue.peek())) + print("Queue : {}".format(queue)) +``` + + 큐가 비었습니까? True + 큐에 값을 추가합니다. + Queue : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + 큐의 크기 : 10 + peek : 0 + dequeue : 0 + peek : 1 + Queue : [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +#### 노드를 이용한 큐(Queue) 구현 ++ 노드를 이용해서 SingleLinkedList로 구현합니다. + + +```python +# Node를 이용해 큐 구현 + +class Node(object): + def __init__(self, value = None, pointer = None): + self.value = value + self.pointer = pointer + +class LinkedQueue(object): + def __init__(self): + self.head = None # 큐의 맨 앞 + self.tail = None # 큐의 맨 뒤 + self.count = 0 + + def isEmpty(self): + return not bool(self.head) + + def dequeue(self): + if self.isEmpty(): + print("Queue is Empty!") + + else: + node = self.head + self.head = self.head.pointer + self.count -= 1 + + if self.head is None: # 데이터를 삭제함으로써 큐가 빌 경우 + # head와 tail은 같은 노드를 바라보고 있었으므로 + self.tail = None # tail값도 비워주기 + + return node.value + + def enqueue(self, value): + node = Node(value) + if not self.head: # head가 비어있다면 + self.head = node + self.tail = node + else: + self.tail.pointer = node # 현재 tail의 포인터를 node와 연결 + self.tail = node # 연결된 node를 tail로 지정 + self.count += 1 + + def size(self): + return self.count + + def peek(self): + if self.head: + return self.head.value + else: + print("Queue is Empty!") + + def printQueue(self): + node = self.head + while node: + print(node.value, end = " ") + node = node.pointer + print() +``` + +```python +if __name__ == "__main__": + queue = LinkedQueue() + print("스택이 비었습니까? {0}".format(queue.isEmpty())) + print("스택에 값을 추가합니다.") + + for i in range(10): + queue.enqueue(i) + queue.printQueue() + print("큐의 크기는? {0}".format(queue.size())) + print("peek : {}".format(queue.peek())) + print("pop : {}".format(queue.dequeue())) + print("peek : {}".format(queue.peek())) + queue.printQueue() + +# for i in range(9): +# queue.dequeue() +# print(queue.tail) + +``` + + 스택이 비었습니까? True + 스택에 값을 추가합니다. + 0 1 2 3 4 5 6 7 8 9 + 큐의 크기는? 10 + peek : 0 + pop : 0 + peek : 1 + 1 2 3 4 5 6 7 8 9 + + +LinkedQueue의 head는 큐의 맨 앞, tail은 맨 뒤를 의미합니다. + +
+ +Enqueue(데이터 추가)할 때는 데이터 값을 노드 형식(value, pointer)으로 변수 node에 대입한 후 +head가 비어있다면 > 큐에서 유일한 값이 되므로 head와 tail이 모두 추가된 node를 가리키게 됩니다. + +
+ +head가 비어있지 않을땐 > 들어오는 값을 큐에 우선 연결해준 후, tail의 위치를 마지막으로 변경해주면 됩니다. +tail의 다음값으로 지정하기 위해 우선 기존의 tail.pointer에 변수 node를 넣어주고, 추가된 노드를 tail로 지정해줍니다. + +
+ +Dequeue(데이터 삭제)할 때는 큐의 맨 앞, head를 반환해주기 위해 임시 node변수에 대입합니다. +그 후, head에 head.pointer(즉, 기존 head에서 가리키는 다음 노드)를 넣어줍니다. + +
+ +마지막으로 임시 node에 저장된 기존 head값을 return해주기 전에\! +큐의 유일한 노드가 삭제 될 경우는 head와 tail이 그 노드를 동시에 바라보고 있었기 때문에 +tail도 None으로 초기화 해주어야 합니다. + +### 덱(Deque) + +
+ ++ 덱(Double Ended Queue)은 큐와 다르게 양쪽 끝에서 항목을 조회, 삽입, 삭제가 가능합니다. +(스택과 큐의 융합) ++ 위에서 구현했던 큐 리스트를 그대로 상속해서 덱을 구현해보겠습니다. + + +```python +# 리스트를 활용한 덱 구현 +class Deque(Queue): # 큐 리스트를 상속 + # enqueue 반대로 하기 + def enqueue_front(self, item): + self.items.insert(0, item) # 리스트 0번째에 값 추가 + + # dequeue 반대로 하기 + def dequeue_back(self): + if self.isEmpty(): + print("Queue is Empty!") + else: + value = self.items.pop() # 리스트 가장 뒤에 있는 값을 삭제, 반환 + return value +``` + +```python +if __name__ == "__main__": + deque = Deque() + print("덱이 비었습니까? {}".format(deque.isEmpty())) + print("덱에 값을 추가합니다.") + for i in range(1,20,2): + deque.enqueue(i) + print("덱 : {}".format(deque)) + print("peek : {0}".format(deque.peek())) + print("dequeue : {0}".format(deque.dequeue())) + print("덱 : {0}".format(deque)) + deque.enqueue_front(50) + print("덱 : {0}".format(deque)) + print("dequeue_back : {}".format(deque.dequeue_back())) + print("덱 : {0}".format(deque)) +``` + + 덱이 비었습니까? True + 덱에 값을 추가합니다. + 덱 : [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] + peek : 1 + dequeue : 1 + 덱 : [3, 5, 7, 9, 11, 13, 15, 17, 19] + 덱 : [50, 3, 5, 7, 9, 11, 13, 15, 17, 19] + dequeue_back : 19 + 덱 : [50, 3, 5, 7, 9, 11, 13, 15, 17] + + +#### 덱 모듈 사용하기 ++ Python의 Collections 모듈 안에 Deque라는 클래스가 이미 구현되어 있습니다. ++ Deque 클래스는 이중 연결 리스트(Double Linked List)로 구성되어서 여러 기능을 효율적으로 사용이 가능합니다. + + +```python +# 덱 모듈 사용하기 + +from collections import deque + +# deque() : 덱 생성 +q = deque(["Apple", "Banana", "Peach"]) +print(q) + +# 오른쪽에 값을 추가 +q.append("Strawberry") +print(q) + +# 왼쪽에 값을 추가 +q.appendleft("Mango") +print(q) + +# 왼쪽의 값을 반환 +q.popleft() +print(q) + +# 오른쪽의 값을 반환 +q.pop() +print(q) + +# rotate(n) : n의 길이만큼 양수면 오른쪽, 음수면 왼쪽으로 값들이 이동 +q = deque(['Mango', 'Apple', 'Banana', 'Peach', 'Strawberry']) +q.rotate(2) +print(q) + +q.rotate(-1) +print(q) + +# collections안의 Deque은 이중 연결 리스트 형식으로 되어져있기 때문에 +# 이러한 기능이 가능합니다. +``` + + deque(['Apple', 'Banana', 'Peach']) + deque(['Apple', 'Banana', 'Peach', 'Strawberry']) + deque(['Mango', 'Apple', 'Banana', 'Peach', 'Strawberry']) + deque(['Apple', 'Banana', 'Peach', 'Strawberry']) + deque(['Apple', 'Banana', 'Peach']) + deque(['Peach', 'Strawberry', 'Mango', 'Apple', 'Banana']) + deque(['Strawberry', 'Mango', 'Apple', 'Banana', 'Peach']) + + diff --git a/_posts/2022-01-07-Stack.md b/_posts/2022-01-07-Stack.md new file mode 100644 index 000000000000..841c9d5d731f --- /dev/null +++ b/_posts/2022-01-07-Stack.md @@ -0,0 +1,256 @@ +--- +layout: single +title: "[자료구조/알고리즘] 스택(Stack)" +categories: 자료구조/알고리즘 +tag: [python, 파이썬, Stack, 스택, 자료구조, 알고리즘] +toc: true +toc_sticky: true +--- + + + + + +### 스택(Stack) + +
+ + ++ LIFO(후입선출)구조 ++ 배열의 끝에서만 데이터를 접근할 수 있는 선형 자료구조입니다. +데이터의 삽입과 삭제가 한쪽에서만 수행되는 구조입니다. + +#### 리스트를 이용한 Stack + +
+ ++ push : 스택의 맨 위에 항목 삽입 ++ pop : 스택의 맨 위 항목을 반환,삭제 ++ top/peek :스택 맨 끝의 항목을 조회 ++ empty : 스택이 비어있는지 확인 ++ size : 스택의 크기를 확인 + + +```python +class Stack(object): + # 생성자 + def __init__(self): + self.items = [] # 값을 담아줄 스택 형태의 리스트 + + # 스택이 비었는지 확인하는 함수(Empty : True / Not Empty : false) + def isEmpty(self): + return not self.items + + # pop : 스택의 맨 끝의 요소 반환, 삭제 + def pop(self): + # 스택이 비어있다면 + if self.isEmpty(): + print("Stack is Empty!") + else: + value = self.items.pop() # 리스트의 가장 마지막 요소 반환, 삭제 후 value에 저장 + return value + + # push : 스택의 맨 끝에 요소 삽입 + def push(self, value): + self.items.append(value) + + # size : 스택의 크기 조회 + def size(self): + return len(self.items) + + # peek / top : 스택의 맨 위의 항목 조회 + def peek(self): + if self.isEmpty(): + print("Stack is Empty!") + else: + return self.items[-1] # 리스트의 마지막 값 + + def __repr__(self): + return repr(self.items) +``` + +```python +if __name__ == "__main__": + stack = Stack() + print("스택이 비었습니까 ? {}".format(stack.isEmpty())) + print("스택에 값을 추가합니다.") + for i in range(10): + stack.push(i) + print("Stack : {}".format(stack)) + print("스택의 크기 : {}".format(stack.size())) + print("peek : {}".format(stack.peek())) + print("pop : {}".format(stack.pop())) + print("peek : {}".format(stack.peek())) + print("Stack : {}".format(stack)) +``` + + 스택이 비었습니까 ? True + 스택에 값을 추가합니다. + Stack : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + 스택의 크기 : 10 + peek : 9 + pop : 9 + peek : 8 + Stack : [0, 1, 2, 3, 4, 5, 6, 7, 8] + + + + 객체에 대한 정보를 프린트 구문으로 출력하게 만들어주는 메소드 + (당연히 print구문으로 객체들을 호출하면 객체의 주소값이 출력됨 -> __repr__, __str__ 메소드 활용) + +
+ + + __repr__ : 객체의 official(공식적인) 정보를 출력 + -> 시스템이 인식하는 대로, 객체의 모습 그대로를 호출하는 "딱딱한" 호출 + + __str__ : 객체의 informal(비공식적인) 정보를 출력 + -> 사용자 입장에서 보기 쉬운, 조금은 "느슨한" 호출 + +#### 노드를 이용한 Stack 구현 + +
+ ++ 노드의 기본 모양을 먼저 정의합니다. + + +```python +# 노드의 기본 모양 +class Node(object): + def __init__(self, value = None, pointer = None): # value와 pointer 초기화 + self.value = value + self.pointer = pointer +``` + ++ 정의된 노드를 활용하여 스택을 구현합니다. + + +```python +# 스택 구현 +class Stack(object): + def __init__(self): + self.top = None # 초기에 스택은 비어있으므로 top, count 초기화 + self.count = 0 + + def isEmpty(self): + return not bool(self.top) # 스택의 Top이 비어있으면 Empty + + def pop(self): + # 스택이 비어있다면 + if self.isEmpty(): + print("Stack is Empty!") + else: + node = self.top # 임시 node에 스택의 Top부터 담는다 + self.top = self.top.pointer # node의 다음 가리키는 곳을 Top으로 지정 + self.count -= 1 # count 감소 + + return node.value # node의 값 반환(기존의 top의 값) + + def push(self, item): + self.top = Node(item, self.top) # 새로운 값과 기존의 Top을 포인터로 Node형식(값, 포인터) + self.count += 1 # count 증가 + + def size(self): + return self.count + + def peek(self): + if self.isEmpty(): + print("Stack is Empty!") + else: + return self.top.value + + def printStack(self): + node = self.top + while node: + print(node.value, end=" ") + node = node.pointer + print() +``` +```python +if __name__ == "__main__": + stack = Stack() + print("스택이 비었습니까? {}".format(stack.isEmpty())) + print("스택에 값을 추가합니다.") + for i in range(10): + stack.push(i) + stack.printStack() + print("스택의 크기 : {}".format(stack.size())) + print("peek : {}".format(stack.peek())) + print("pop {}".format(stack.pop())) + print("peek : {}".format(stack.peek())) + stack.printStack() +``` + + 스택이 비었습니까? True + 스택에 값을 추가합니다. + 9 8 7 6 5 4 3 2 1 0 + 스택의 크기 : 10 + peek : 9 + pop 9 + peek : 8 + 8 7 6 5 4 3 2 1 0 + diff --git "a/_posts/2022-01-13-1.\354\204\240\355\230\225\355\232\214\352\267\200\354\231\200 \352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.md" "b/_posts/2022-01-13-1.\354\204\240\355\230\225\355\232\214\352\267\200\354\231\200 \352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.md" new file mode 100644 index 000000000000..8d385654e41b --- /dev/null +++ "b/_posts/2022-01-13-1.\354\204\240\355\230\225\355\232\214\352\267\200\354\231\200 \352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.md" @@ -0,0 +1,647 @@ +--- +layout: single +title: "선형 회귀와 경사 하강법 정리" +categories: 딥러닝 +tag: [python, Numpy, 파이썬, 머신러닝, 딥러닝, 기초통계, 선형회귀, 경사하강법] +toc: true +toc_sticky: true + +--- + + + + + + +저는 이 책을 참고하여 개념을 정리했습니다. + + + +
+ + + +![image](/assets/images/모두의딥러닝.png) + + +### 선형 회귀와 로지스틱 회귀 + + + + 선형 회귀는 (x, y) 점들의 특징을 가장 잘 나타내는 선을 그리는 과정입니다. + + + +- 독립변수 x 하나의 값만으로 y값을 설명할 수 있다면 단순 선형 회귀 + + + +
+ + + +- 여러개의 x값이 필요할 땐 다중 선형 회귀 + + +#### 최소 제곱법 + + 최소 제곱법은 주어진 x의 값이 하나일 때 적용이 가능합니다. (단순 선형 회귀일 때) + + 여러개의 x가 주어지는 경우(다중 선형 회귀) 경사하강법을 적용합니다. + +
+ + + +![Alt text](/assets/images/공식_최소제곱법.png) + + + +
+ + + +##### 최소제곱법을 이용하여 a, b 구하기 + + 구하려는 직선이 y = ax + b라고 가정한다면, + + + + a = (x - x평균) * (y - y평균)의 합 / (x - x평균)^2의 합 + + + + b = y - ax이므로 + + = (y의 평균) - (a * x의 평균) + + + +```python +import numpy as np + +x = [2, 4, 6, 8] +y = [81, 93, 91, 97] + +mx = np.mean(x) # x의 평균 +my = np.mean(y) # y의 평균 + +# 기울기 공식의 분모 +divisor = sum([(i - mx)**2 for i in x]) + +# 기울기 공식의 분자 +def top(x, y, mx, my): + d = 0 + + for i in range(len(x)): + d += (x[i] - mx) * (y[i] - my) + + return d +divided = top(x, y, mx, my) + +a = divided / divisor +b = my - mx * a + +print(f"기울기 : {a}") +print(f"y절편 : {b}") +``` + +
+기울기 : 2.3
+y절편 : 79.0
+
+ 하지만, 모든 딥러닝 프로젝트는 여러개의 입력변수를 다룹니다. + + + + 따라서 최소제곱법이 아닌 다른 방법이 필요한데, 가장 많이 사용하는 방법은 + + '일단 그리고 조금씩 수정해 나가기' 방식입니다. + + + + 즉, 나중에 그린선이 먼저 그린 선보다 더 좋은지 나쁜지를 판단해야 하는데, + + 각 선의 오차를 계산하여 오차가 작은 쪽으로 바꾸는 알고리즘이 필요합니다. + + +#### 평균 제곱 오차(MSE) + + 여러개의 x에 대해 오차가 존재하므로 모든 x에 대한 평균 오차를 평균 제곱 오차라고 합니다. + + + +
+ + + +![Alt text](/assets/images/공식_MSE.png) + + + +
+ + + + 따라서, 선형 회귀란 임의의 직선을 그어 이에 대한 평균 제곱 오차(MSE)를 구하고, + + 이 값을 가장 작게 만들어 주는 a와 b 값을 찾아가는 작업입니다. + + + +```python +# 위의 y = ax + b 활용 + +fake_a_b = [a, b] + +# 위에서 구한 직선으로 y값 예측 +def predict(x): + return fake_a_b[0] * x + fake_a_b[1] + +# MSE 함수 +def mse(y, y_hat): # y_hat: y의 평균 + return ((y - y_hat)**2).mean() + +# MSE 함수를 각 y값에 대입하여 최종 값을 구하는 함수 +def mse_val(y, predict_result): + + # 리스트의 각 원소끼리 -연산을 하기 위해 np.array형태 + return mse(np.array(y), np.array(predict_result)) + +# 예측값이 들어갈 리스트 +predict_result = [] + +# 예측값 구하기 +for i in range(len(x)): + predict_result.append(predict(x[i])) + print(f"x값 : {x[i]}, 실제 y값 : {y[i]}, 예측 y값 : {predict_result[i]}") + +# 최종 MSE 출력 +print(f"MSE : {mse_val(predict_result, y)}") +``` + +
+x값 : 2, 실제 y값 : 81, 예측 y값 : 83.6
+x값 : 4, 실제 y값 : 93, 예측 y값 : 88.2
+x값 : 6, 실제 y값 : 91, 예측 y값 : 92.8
+x값 : 8, 실제 y값 : 97, 예측 y값 : 97.4
+MSE : 8.299999999999985
+
+#### 오차 수정하기 + + 기울기 a를 너무 크게 잡거나 너무 작게 잡으면 오차가 커집니다. + + 이러한 기울기 a와 오차의 관계는 이차 함수 그래프로 표현할 수 있습니다. + + + +
+ + + +![Alt text](/assets/images/경사하강법.png) + + + +
+ + + + 오차가 가장 작을 때는 아래쪽의 볼록한 부분 m일때 입니다. + + + + 컴퓨터를 이용해 m의 값을 구하려면 임의의 한점(a1)을 찍고, + + 이점을 m에 가까운 쪽으로 점점 이동(a1 -> a2)시키는 과정이 필요합니다. + + + + 이러한 방법을 미분 기울기를 이용하는 경사 하강법이라고 합니다. + + + +##### 경사 하강법 + + 최솟값 m에서의 순간 기울기는 0입니다. + + 즉, 경사 하강법에서는 미분값이 0인 지점을 찾는 것이 됩니다. + + + ++ 경사 하강법의 과정 + + 1. a1에서 미분을 구합니다. + + 2. 구해진 기울기의 반대 방향(기울기가 +면 음의 방향, -면 양의 방향)으로 + + 이동시킨 a2에서 미분을 구합니다. + + 3. 구한 미분 값이 0이 될때까지 반복합니다. + + + +
+ + + +![Alt text](/assets/images/경사하강법_과정.png) + + + +##### 학습률 + + 기울기의 부호를 바꿔 이동시킬 때 적절한 거리를 찾지 못해 너무 멀리 이동시키면 + + a 값이 한점으로 모이지 않고 위로 치솟아 버립니다. + + + + 따라서 어느 만큼 이동시킬지를 신중히 결정해야 하는데, 이때 이동 거리를 정해주는 것이 바로 학습률입니다. + + + + 딥러닝에서 학습률의 값을 적절히 바꾸면서 최적의 학습률을 찾는 것은 중요한 최적화 과정 중 하나입니다. + + + +
+ + + ++ 따라서, 경사하강법은 오차의 변화에 따라 이차 함수 그래프를 만들고 적절한 학습률을 설정해 + +미분 값이 0인 지점을 구하는 것입니다. + + + +
+ + + ++ y절편 b값(편향)도 이와 같은 성질을 가지고 있기 때문에 최적의 b값을 구할 때 역시 경사하강법을 사용합니다. + + +##### 경사 하강법 실습 + + + +```python +import pandas as pd +import matplotlib.pyplot as plt + +# 그래프로 나타내기 +plt.figure(figsize=(8, 5)) +plt.scatter(x, y) +plt.show() + +x_data = np.array(x) +y_data = np.array(y) + +# 기울기 a와 절편 b의 값 초기화 +a, b = 0, 0 + +lr = 0.03 # 적절한 학습률 정하기 +epochs = 2001 # 몇 번 반복할지 설정 + +# 경사 하강법 시작 +for i in range(epochs): + y_pred = a * x_data + b # y예측값 구하기 + error = y_data - y_pred + + # 오차 함수를 a로 미분한 값 + a_diff = -(2 / len(x_data)) * sum(x_data * error) + + # 오차 함수를 b로 미분한 값 + b_diff = -(2 / len(x_data)) * sum(error) + + a = a - lr * a_diff + b = b - lr * b_diff + + if i % 100 == 0: # 100번째 반복때마다 출력 + print(f"epochs = {i}, 기울기 = {a}, 절편 = {b}") + +# 그래프 다시 그리기 +y_pred = a * x_data + b +plt.scatter(x, y) +plt.plot([min(x_data), max(x_data)], [min(y_pred), max(y_pred)]) +plt.show() +``` + + + +
+epochs = 0, 기울기 = 27.84, 절편 = 5.43
+epochs = 100, 기울기 = 7.073858435872394, 절편 = 50.51166161138297
+epochs = 200, 기울기 = 4.095999380762421, 절편 = 68.28224379060177
+epochs = 300, 기울기 = 2.9756829100119027, 절편 = 74.96781336233505
+epochs = 400, 기울기 = 2.5542024233262106, 절편 = 77.48302865233052
+epochs = 500, 기울기 = 2.3956349066513707, 절편 = 78.42929177728175
+epochs = 600, 기울기 = 2.3359793398132864, 절편 = 78.78529068727728
+epochs = 700, 기울기 = 2.313535987420573, 절편 = 78.91922301600925
+epochs = 800, 기울기 = 2.3050924490666174, 절편 = 78.96961044185792
+epochs = 900, 기울기 = 2.3019158585694823, 절편 = 78.98856697541248
+epochs = 1000, 기울기 = 2.3007207758016315, 절편 = 78.99569871827002
+epochs = 1100, 기울기 = 2.300271167070735, 절편 = 78.99838179089187
+epochs = 1200, 기울기 = 2.3001020172709508, 절편 = 78.9993912045567
+epochs = 1300, 기울기 = 2.300038380484562, 절편 = 78.99977096168232
+epochs = 1400, 기울기 = 2.3000144393354365, 절편 = 78.9999138322214
+epochs = 1500, 기울기 = 2.3000054323026444, 절편 = 78.99996758234106
+epochs = 1600, 기울기 = 2.300002043716771, 절편 = 78.99998780397235
+epochs = 1700, 기울기 = 2.3000007688780433, 절편 = 78.99999541166466
+epochs = 1800, 기울기 = 2.300000289263884, 절편 = 78.99999827379686
+epochs = 1900, 기울기 = 2.3000001088255795, 절편 = 78.9999993505755
+epochs = 2000, 기울기 = 2.3000000409418653, 절편 = 78.99999975567644
+
+ + +##### 학습률 실습 + + + +```python +# 경사하강법 구현 +# 학습률을 여러가지 설정합니다. +lr_list = [0.001, 0.1, 0.5, 0.9] + +def get_derivative(lr): + w_old = 2 + derivative = [w_old] + + y = [w_old ** 2] # 손실함수를 y = w^2 + + for i in range(10): # 미분값 구하기 + dev_value = w_old * 2 + + # 미분값을 이용해서 가중치 업그레이드 + w_new = w_old - lr * dev_value + w_old = w_new + + derivative.append(w_old) # 업데이트한 가중치를 저장 + y.append(w_old ** 2) # 업데이트한 가중치의 손실값을 저장 + + return derivative, y + +x = np.linspace(-2, 2, 50) # -2 ~ 2까지 50구간으로 나누기 +x_square = [i ** 2 for i in x] + +fig = plt.figure(figsize=(12, 7)) + +for i, lr in enumerate(lr_list): + derivative, y = get_derivative(lr) + ax = fig.add_subplot(2, 2, i + 1) + ax.scatter(derivative, y, color = 'red') + ax.plot(x, x_square) + ax.title.set_text('lr = '+str(lr)) + +plt.show() +``` + + + +#### 다중 선형 회귀 + + + + 여러 독립 변수(x)가 존재하는 선형 회귀입니다. + + + +```python +data = [[2, 0, 81], [4, 4, 93], [6, 2, 91], [8, 3, 97]] # [x1, x2, y] + +# data로 부터 x1, x2, y의 리스트 만들기 +x1 = [i[0] for i in data] +x2 = [i[1] for i in data] +y = [i[2] for i in data] + +# 그래프로 확인(점 찍어보기) +ax = plt.axes(projection='3d') # 3차원 그래프 +ax.set_xlabel('x1') +ax.set_ylabel('x2') +ax.set_zlabel('y') +ax.dist = 11 +ax.scatter(x1, x2, y) +plt.show() + +# 리스트 -> numpy 배열 +x1_data = np.array(x1) +x2_data = np.array(x2) +y_data = np.array(y) + +a1, a2, b = 0, 0, 0 # 기울기 a1, a2와 절편 b 초기화 +lr = 0.05 # 학습률 +epochs = 2001 # 반복 횟수 + +for i in range(epochs): # epochs만큼 반복 + y_pred = a1 * x1_data + a2 * x2_data + b + error = y_data - y_pred # 예측값에 대한 오차 + + # 미분 + a1_diff = -(1 / len(x1_data)) * sum(x1_data * error) + a2_diff = -(1 / len(x2_data)) * sum(x2_data * error) + b_diff = -(1 / len(x1_data)) * sum(error) + + a1 = a1 - lr * a1_diff # 학습률을 곱해 a1, a2, b값 업데이트 + a2 = a2 - lr * a2_diff + b = b - lr * b_diff + + if i % 100 == 0: + print(f"epochs = {i}, a1 = {a1}, a2 = {a2}, b = {b}") +``` + + + +
+epochs = 0, a1 = 23.200000000000003, a2 = 10.5625, b = 4.525
+epochs = 100, a1 = 6.434805446608685, a2 = 3.98925524892891, b = 43.97569356791496
+epochs = 200, a1 = 3.7255348759847924, a2 = 3.0541408134809784, b = 62.576629969168025
+epochs = 300, a1 = 2.503714679287745, a2 = 2.6322742530634486, b = 70.96564181265175
+epochs = 400, a1 = 1.952674645725859, a2 = 2.4420125981800993, b = 74.74908051776274
+epochs = 500, a1 = 1.7041559609856545, a2 = 2.356204719590433, b = 76.45540883097016
+epochs = 600, a1 = 1.592074201194008, a2 = 2.31750542401674, b = 77.22496175342586
+epochs = 700, a1 = 1.5415254028566499, a2 = 2.300052067722291, b = 77.57202960424704
+epochs = 800, a1 = 1.5187279287796718, a2 = 2.292180615763661, b = 77.7285569717077
+epochs = 900, a1 = 1.5084462832928398, a2 = 2.28863059622062, b = 77.79915070923249
+epochs = 1000, a1 = 1.5038092680884374, a2 = 2.2870295397926297, b = 77.83098843741102
+epochs = 1100, a1 = 1.5017179773477205, a2 = 2.286307464419652, b = 77.84534723142188
+epochs = 1200, a1 = 1.500774806629192, a2 = 2.285981808911738, b = 77.85182303787037
+epochs = 1300, a1 = 1.5003494372690325, a2 = 2.28583493849654, b = 77.85474362222634
+epochs = 1400, a1 = 1.5001575959734832, a2 = 2.2857687000379943, b = 77.85606080380799
+epochs = 1500, a1 = 1.5000710756781244, a2 = 2.285738826537708, b = 77.85665485181606
+epochs = 1600, a1 = 1.5000320550830635, a2 = 2.2857253536091546, b = 77.85692276706845
+epochs = 1700, a1 = 1.500014456820917, a2 = 2.2857192773274324, b = 77.85704359666722
+epochs = 1800, a1 = 1.5000065200165227, a2 = 2.285716536928462, b = 77.85709809073502
+epochs = 1900, a1 = 1.500002940523069, a2 = 2.2857153010103657, b = 77.85712266752303
+epochs = 2000, a1 = 1.5000013261739265, a2 = 2.2857147436121346, b = 77.85713375163787
+
+#### 로지스틱 회귀 + ++ 참과 거짓(예/ 아니오)중에 하나를 내놓는 과정에서 사용하는 원리입니다. + + + +
+ + + ++ 참(1)과 거짓(0)사이를 구분하는 S자 형태입니다. + + +#### Sigmoid 함수 + + Sigmoid를 이용해 로지스틱 회귀를 풀어나갑니다. + + + +
+ + + +![Alt text](/assets/images/Sigmoid.png) + + + +
+ + + + 지수부분이 (a * x + b)라고 했을 때, + + + + a는 그래프의 경사도를 결정합니다. a값이 커지면 경사가 커지고 a값이 작아지면 경사가 작아집니다. + + + + b는 그래의 좌우 이동을 의미합니다. b값이 크면 왼쪽, 작으면 오른쪽으로 이동합니다. + + + + 따라서, a와 b의 값에 따라 오차가 변합니다. + + + +```python +# sigmoid 구현 + +x_data = [2, 4, 6, 8, 10, 12, 14] +y_data = [0, 0, 0, 1, 1, 1, 1] + +# 그래프로에 점 찍어보기 +plt.scatter(x_data, y_data) +plt.xlim(0, 15) +plt.ylim(-0.1, 1.1) + +a, b = 0, 0 # 기울기, 절편 초기화 +lr = 0.05 # 학습률 + +def sigmoid(x): + return 1 / (1 + np.e**(-x)) + +# 경사 하강법 실행 +for epoch in range(2001): + for i in range(len(x_data)): + # 미분 오차 : 예측값 - 실제값 + a_diff = x_data[i] * (sigmoid(a * x_data[i] + b) - y_data[i]) + b_diff = sigmoid(a * x_data[i] + b) - y_data[i] + + # a, b값 업데이트 + a -= lr * a_diff + b -= lr * b_diff + + if epoch % 1000 == 0: + print(f"epoch = {epoch}, 기울기 a = {a}, 절편 b = {b}") +``` + +
+epoch = 0, 기울기 a = -0.05, 절편 b = -0.025
+epoch = 0, 기울기 a = -0.13879722189107602, 절편 b = -0.047199305472769
+epoch = 0, 기울기 a = -0.2267516349901771, 절편 b = -0.06185837432261918
+epoch = 0, 기울기 a = 0.12010284223274431, 절편 b = -0.018501564669754007
+epoch = 0, 기울기 a = 0.23740192458962306, 절편 b = -0.006771656434066131
+epoch = 0, 기울기 a = 0.27045811205658526, 절편 b = -0.004016974145152613
+epoch = 0, 기울기 a = 0.2860409628939473, 절편 b = -0.0029039133710553225
+epoch = 1000, 기울기 a = 1.497824502953391, 절편 b = -9.940123304992555
+epoch = 1000, 기울기 a = 1.4940419536789271, 절편 b = -9.94106894231117
+epoch = 1000, 기울기 a = 1.4119848217717417, 절편 b = -9.954745130962369
+epoch = 1000, 기울기 a = 1.4949143121842228, 절편 b = -9.944378944660809
+epoch = 1000, 기울기 a = 1.498244938547387, 절편 b = -9.944045882024492
+epoch = 1000, 기울기 a = 1.4984392510394648, 절편 b = -9.94402968931682
+epoch = 1000, 기울기 a = 1.4984505498747405, 절편 b = -9.944028882257157
+epoch = 2000, 기울기 a = 1.9064689962225458, 절편 b = -12.948894836795326
+epoch = 2000, 기울기 a = 1.9054981310086199, 절편 b = -12.949137553098806
+epoch = 2000, 기울기 a = 1.8514893310246738, 절편 b = -12.958139019762797
+epoch = 2000, 기울기 a = 1.9056614126778697, 절편 b = -12.951367509556148
+epoch = 2000, 기울기 a = 1.9067744947792462, 절편 b = -12.95125620134601
+epoch = 2000, 기울기 a = 1.9068037073321078, 절편 b = -12.951253766966605
+epoch = 2000, 기울기 a = 1.9068044592233457, 절편 b = -12.951253713260089
+
+ diff --git "a/_posts/2022-01-13-2.\353\213\244\354\270\265 \355\215\274\354\205\211\355\212\270\353\241\240\352\263\274 \355\231\234\354\204\261\355\231\224 \355\225\250\354\210\230.md" "b/_posts/2022-01-13-2.\353\213\244\354\270\265 \355\215\274\354\205\211\355\212\270\353\241\240\352\263\274 \355\231\234\354\204\261\355\231\224 \355\225\250\354\210\230.md" new file mode 100644 index 000000000000..c6c08b643cdf --- /dev/null +++ "b/_posts/2022-01-13-2.\353\213\244\354\270\265 \355\215\274\354\205\211\355\212\270\353\241\240\352\263\274 \355\231\234\354\204\261\355\231\224 \355\225\250\354\210\230.md" @@ -0,0 +1,313 @@ +--- +layout: single +title: "다층 퍼셉트론(XOR문제)과 활성화 함수" +categories: 딥러닝 +tag: [python, Numpy, 파이썬, 머신러닝, 딥러닝, 기초통계, XOR, 오차 역전파, 활성화 함수] +toc: true +toc_sticky: true + +--- + + + + + + +저는 이 책을 참고하여 개념을 정리했습니다. + + + +
+ + + +![image](/assets/images/모두의딥러닝.png) + + +#### 다층 퍼셉트론으로 XOR 문제 해결 + + + ++ OR게이트와 NAND게이트, 이 두 가지를 내재한 각각의 퍼셉트론과 + + AND게이트를 내제한 퍼셉트론을 사용해서 XOR문제를 해결합니다. + + + +```python +import numpy as np + +w11 = np.array([-2, -2]) # NAND 게이트에 입력되는 가중치와 편향 +b1 = 3 +w12 = np.array([2, 2]) # OR +b2 = -1 +w2 = np.array([1, 1]) # AND +b3 = -1 + +# 퍼셉트론 함수 +def MLP(x, w, b): + y = np.sum(w * x) + b + if y <= 0: + return 0 + else: + return 1 + +def NAND(x1, x2): # NAND 게이트 + return MLP(np.array([x1, x2]), w11, b1) + +def OR(x1, x2): # OR 게이트 + return MLP(np.array([x1,x2]), w12, b2) + +def AND(x1, x2): # AND 게이트 + return MLP(np.array([x1, x2]), w2, b3) + +def XOR(x1, x2): + return AND(NAND(x1, x2), OR(x1, x2)) + +if __name__ == "__main__": + for x1, x2 in [(0, 0), (0, 1), (1, 0), (1, 1)]: + y = XOR(x1, x2) + print(f"입력값 : {(x1, x2)}, 출력값 : {y}") +``` + +
+입력값 : (0, 0), 출력값 : 0
+입력값 : (0, 1), 출력값 : 1
+입력값 : (1, 0), 출력값 : 1
+입력값 : (1, 1), 출력값 : 0
+
++ 퍼셉트론 하나로 해결되지 않던 문제를 은닉층을 만들어 해결했습니다. + ++ 은닉층을 여러개 쌓아올려 복잡한 문제를 해결하는 과정을 '신경망'이라고 부릅니다. + + +#### 오차 역전파 + ++ 다층 퍼셉트론에서 결과값을 얻으면 오차를 구해 이를 토대로 앞선 가중치를 차례로 거슬러 올라가며 조정하는 작업 + + + +
+ + + +#### 오차 역전파 과정 + +![image](/assets/images/오차역전파1.png) + ++ 1. 결과 값과 실제 값을 비교하여 오차를 구합니다. + ++ 2. 경사 하강법을 이용해 바로 앞 가중치를 오차가 작아지는 방향으로 업데이트 합니다. + ++ 3. 위 과정을 더이상 오차가 줄어들지 않을 때까지 반복합니다. + + + +
+ + + +'오차가 작아지는 방향으로 업데이트한다'는 의미는 미분 값이 0에 가까워지는 방향으로 나아간다는 말입니다. + +가중치 수정 작업은 현 가중치에서 가중치에 대한 기울기를 뺀 값(즉, 미분 값)을 빼서 새 가중치로 조정합니다. + + + +![image](/assets/images/오차역전파2.png) + + + +
+ + + +오차 역전파 과정에서 '체인룰'을 활용하여 미분 값을 얻어낼 수 있습니다. + + + +![image](/assets/images/체인룰.png) + + + +
+ + + + + + + +#### 기울기 소실 문제 + + + +
+ + + +은닉층이 늘어나면서 역전파를 통해 전달되는 기울기의 값이 점점 작아져 + +맨 처음 층까지 전달되지 않는 문제입니다. + +이는 활성화 함수로 사용된 시그모이드 함수의 특성이 원인입니다. + + + +
+ + + +![image](/assets/images/시그모이드미분.png) + + + +위 그림과 같이 시그모이드를 미분하면 최대값이 약 0.3이 됩니다. + +1보다 작으므로 계속 곱하다 보면 0에 가까워지게 됩니다. + +따라서, 여러 층을 거칠수록 기울기가 사라져 가중치를 수정하기가 어려워집니다. + +이를 해결하고자 여러 활성화 함수로 대체합니다. + + +#### 고급 경사 하강법 + + + +가중치를 업데이트하는 방법으로 경사 하강법이 존재합니다. + +그런데 경사 하강법은 정확하게 가중치를 찾아가지만, 한 번 업데이트할 때마다 전체 데이터를 + +미분해야 하므로 계산량이 많아 속도가 느리고 최적해를 찾기 전에 멈출수 있다는 단점이 있습니다. + +이러한 점을 보완하기 위해 고급 경사 하강법이 등장합니다. + + + +
+ + + +##### 확률적 경사 하강법(SGD) + +확률적 경사 하강법은 전체 데이터를 사용하는 것이 아니라, 랜덤하게 추출한 일부 데이터를 사용합니다. + +그러므로 더 빨리, 더 자주 업데이트를 하는 것이 가능합니다. + + + +![image](/assets/images/확률적_경사_하강법.png) + + + +그림을 참고한다면, 랜덤한 일부 데이터를 사용하는 만큼 확률적 경사 하강법은 + +중간 결과의 진폭이 크고 불안정해 보일 수 있습니다. + +하지만 속도가 확연히 빠르면서도 최적 해에 근사한 값을 찾아낼 수 있어 경사 하강법의 대안으로 사용되고 있습니다. + + + +
+ + + +##### 모멘텀(momentum) + +momentum이란 '관성, 탄력, 가속도'라는 뜻입니다. 모멘텀 SGD란 말 그대로 경사 하강법에 탄력을 더한 것입니다. + +경사 하강법과 마찬가지로 매번 기울기를 구하지만, 이를 통해 오차를 수정하기 전 바로 앞 수정값과 + +방향(+ / -)을 참고하여 같은 방향으로 일정한 비율만 수정되게 하는 방법입니다. + +따라서 지그재그로 일어나느 현상이 줄어들고, 이전 이동 값을 고려해 일정 비율만큼만 다시 값을 결정하므로 + +관성 효과를 낼 수 있습니다. + + + +![image](/assets/images/모멘텀.png) + + + +
+ + + +##### 고급 경사 하강법 활용법 + + + +![image](/assets/images/활성화함수_테이블.png) + + + +아담(Adam)은 현재 가장 많이 사용되는 고급 경사 하강법입니다. + diff --git "a/_posts/2022-01-25-CNN(Convolution\354\270\265 + Pooling\354\270\265).md" "b/_posts/2022-01-25-CNN(Convolution\354\270\265 + Pooling\354\270\265).md" new file mode 100644 index 000000000000..6ef7bc508bc5 --- /dev/null +++ "b/_posts/2022-01-25-CNN(Convolution\354\270\265 + Pooling\354\270\265).md" @@ -0,0 +1,420 @@ +--- +layout: single +title: "CNN 정리(컨볼루션 층, 풀링 층)" +categories: 딥러닝 +tag: [python, keras, CNN, 컨볼루션, 풀링, Convolution, Pooling, 인공지능, 딥러닝, 머신러닝] +toc: true +toc_sticky: true + +--- + + + + + + +#### 합성곱 신경망 + +합성곱 신경망(Convolutional Neural Network)은 이미지 처리에 탁월한 성능을 보이는 신경망입니다. + +합성곱 신경망은 크게 합성곱층(Convolution layer)과 풀링층(Pooling layer)으로 구성됩니다. + + + +
+ + + +이미지 처리를 하기 위해 앞서 배운 다층 퍼셉트론을 사용할 수는 있지만 한계가 있습니다. + +다층 퍼셉트론을 사용한다면 이미지를 1차원 벡터로 변환하고 입력층으로 사용해야 합니다. + +하지만, 몇가지 픽셀값만 달라져도 예측에 적지 않은 영향을 받게 되고, + +1차원 벡터로 변환하면서 공간적인 구조 정보가 유실되므로 좀 더 정확한 예측을 위해 합성곱 신경망을 사용합니다. + + + +
+ + + +##### 채널 + +이미지는 (높이, 너비, 채널)이라는 3차원 텐서입니다. + +높이는 이미지의 세로 방향 픽셀 수, 너비는 이미지의 가로 방향 픽셀 수, 채널은 색 성분을 의미합니다. + +여기서 흑백 이미지는 채널 수가 1이고, + +컬러 이미지는 적색(Red), 녹색(Green), 청색(Blue) 세가지 색깔의 조합으로 이루어지므로 채널수가 3입니다. + + + +
+ + + +##### 필터(=커널 =가중치) + +합성곱층은 합성곱 연산을 통해 이미지의 특징을 추출하는 역할을 합니다. + +이때, 필터(커널)라는 N x M 크기의 행렬로 이미지를 처음부터 끝까지(가장 왼쪽 위부터 가장 오른쪽 아래까지) + +순차적으로 훑으면서 필터와 겹쳐지는 부분의 각 이미지와 필터의 원소(가중치) 값을 곱해서 모두 더한 값을 출력합니다. + + + +
+ + + + + +아래의 그림은 채널이 1인(흑백 이미지) 2차원 합성곱일 경우 입력층에 필터를 지나쳐 출력이 되는 예시입니다. + +4x4 크기의 입력층과 2x2 크기의 필터를 합성곱 연산할 경우 3x3형태의 출력이 나옵니다. + +물론 필터에는 각 가중치가 존재하면서 편향도 존재합니다. + +예를 들어, 편향이 +1이라면 아래의 그림에 나오는 출력의 각 원소들은 +1이되어 출력이 됩니다. + +이때, 만들어지는 출력을 특성맵(feature map)이라고 합니다. + +입력층이 필터와 합성곱 연산이 되고 특성맵으로 출력이 될때, 활성화 함수가 사용되는 보통 relu함수를 사용합니다. + + + +![Image](/assets/images/합성곱신경망_커널.png) + + + +
+ + + +##### 여러개의 필터(커널) + +Dense층을 여러개를 사용하는 것처럼 여러개의 필터를 사용할 수 있습니다. + +당연히 필터가 여러개면 필터의 가중치는 서로 다릅니다. + +아래의 그림처럼 4x4크기의 입력에 3개의 필터와 합성곱 연산 결과 3개의 출력 즉, 3x3x3크기의 특성맵이 됩니다. + +그림에서는 필터의 크기가 3x3이었지만, 커널의 크기를 사용자가 정할 수 있습니다. + +다만, 그림에선 커널의 크기가 2x2이지만, 커널의 크기가 크면 특징을 감지하는데 효과가 떨어진다고 하여 보통 3x3 또는 5x5를 사용합니다. + + + +
+ + + ++ 커널의 깊이(채널) = 입력 데이터의 깊이(채널) + ++ 합성곱 연산 결과 : 특성 맵은 입력 데이터의 깊이와 상관없이 (높이, 너비)의 특성 맵을 얻습니다. + +(특성 맵의 채널은 1) + ++ 다만, 합성곱 연산에서 다수의 커널을 사용할 경우 : 특성 맵은 (높이, 너비, 커널의 수) 크기가 됩니다. + +(특성 맵의 채널은 합성곱 연산에 사용된 커널의 수) + + + +![Image](/assets/images/합성곱신경망_여러개의필터.png) + + + +
+ + + +##### 스트라이드(stride) + +그림에서는 커널이 입력층 위에 한 칸씩 이동(슬라이딩)하면서 합성곱 연산을 수행합니다. + +하지만, 커널의 슬라이딩 범위 또한 사용자가 정할 수 있습니다. + +이러한 이동 범위를 스트라이드(stride)라고 합니다. + +스트라이드가 2일 경우에 4x4 이미지에 2x2의 필터가 두 칸씩 이동하면서 합성곱 연산을 수행하게 됩니다. + +그렇다면, 최종적으로 2x2x3 크기의 특성 맵을 얻게 됩니다. + + + +
+ + + +##### 케라스의 합성곱 층 + +```python + +from tensorflow import keras + +keras.layers.Conv2D(10, kernel_size=(3, 3), activation='relu') + +``` + + + ++ 첫번재 인자 10은 필터의 개수를 뜻합니다. + ++ kernel_size는 커널(필터)의 크기를 지정하는 인자입니다. + ++ 역시 activation으로 활성화 함수를 지정합니다. + + + +
+ + + +##### 패딩(padding) + ++ 패딩의 목적 + +위 그림에서 4x4 이미지에 2x2 필터로 합성곱 연산을 했을 때, 스트라이드가 1일 경우엔 3x3의 특성 맵을 얻었습니다. + +이처럼 합성곱 연산의 결과로 얻은 특성 맵은 입력보다 크기가 작아진다는 특성이 있습니다. + +그렇다면 합성곱 층을 여러개 쌓은다면 최종적으로 얻는 특성 맵의 크기는 처음 입력보다 매우 작아집니다. + +여러개의 합성곱 연산 이후에도 특성 맵의 크기를 동일하게 유지되도록 하는 작업을 패딩(padding)이라고 합니다. + + + +
+ + + +패딩은 입력 이미지의 가장자리에 지정된 개수의 폭만큼 가상의 픽셀로 테두리를 추가합니다. + +주로 값을 0으로 채우는 제로 패딩(zero padding)을 사용합니다. + +그렇다면 필터의 슬라이딩 범위가 늘어나게 되고 최종적으로 얻는 특성 맵의 크기는 패딩하기 전보다 커지게 됩니다. + +아래는 4x4 크기의 이미지를 1폭 만큼 제로 패딩을 사용했을 때 모습입니다. + +![Image](/assets/images/제로패딩.png) + + + +
+ + + +##### 케라스의 패딩과 스트라이드 설정 + +```python + +from tensorflow import keras + +keras.layers.Conv2D(10, kernel_size=(3, 3), activation='relu', padding='same', strides=1) + +``` + + + ++ padding='same' : (same 패딩) 입력값과 특성맵 크기를 동일하게 해주는 패딩입니다. + +커널을 사용하여 합성곱 연산을 했을 때, 특성맵의 사이즈가 얼마나 될지 쉽게 알 수 있습니다. + ++ padding='valid' : (valid 패딩) 패딩을 사용하지 않는 옵션입니다. + ++ stride는 특수한 상황이 아닌 이상, 보통 1로 설정합니다. + + +##### 풀링 + +일반적으로 합성곱 층(합성곱 연산 + 활성화 함수) 다음에는 풀링 층을 추가합니다. + +합성곱 층(컨볼루션 층)을 통해 나온 특성 맵이 크고 복잡하다면 이를 축소(다운샘플링)해야 합니다. + +이 과정을 풀링 연산(서브샘플링)이라 하며, 이러한 연산을 하는 층을 풀링 층이라고 합니다. + + + +
+ + + +일반적으로 최대 풀링(max pooling)과 평균 풀링(average pooling)이 사용됩니다. + +최대 풀링은 정해진 구역 안에서 최댓값을 뽑아내는 방법이고, + +평균 풀링은 평균값을 뽑아내는 방법입니다. + + + +
+ + + +아래의 그림은 4x4크기의 특성 맵을 스트라이드가 2일때, 2x2 커널로 맥스 풀링하는 모습입니다. + +![Image](/assets/images/맥스풀링.png) + + + +
+ + + +위의 그림에서 특성 맵을 맥스풀링하게 된다면 2x2의 크기, 절반으로 특성 맵이 작아지는 걸 확인할 수 있습니다. + +만약 채널이 추가된다면 즉, 컨볼루션 층이 3개가 사용되어 특성 맵이 4x4x3 크기였다면 맥스 풀링 결과는 2x2x3이 됩니다. + +차원이 여러개 있는 특성 맵에서 풀링은 각 차원마다 수행되므로 채널 차원은 변하지 않습니다. + + + +
+ + + ++ 풀링과 합성곱의 차이 + +풀링도 합성곱 연산과 유사하게 커널을 슬라이딩시켜 특성 맵을 얻으므로 유사하다고 느낄 수 있지만, + +풀링은 합성곱 연산과 달리 곱하기나(가중치) 더하는(편향) 연산이 없는 걸 확인할 수 있습니다. + +또한, 풀링 과정에서 커널이 슬라이딩할 때 서로 겹치지 않습니다. + +즉, 위의 사진에서 커널이 2x2라면 스트라이드는 2로 설정되고 겹치지 않게 이동합니다. + +커널이 3x3이면 스트라이드는 3, 커널이 4x4이면 스트라이드는 4가 됩니다. + +하지만, 통상적으로 풀링은 2x2 커널을 사용합니다. + + + +
+ + + +##### 케라스의 풀링 층 + +```python + +keras.layers.MaxPooling2D(2, strides=2, padding='valid') + +``` + ++ 첫번째 인자 2는 2x2의 커널로 풀링하겠다는 뜻입니다. + ++ strides는 따로 지정하지 않아도 자동으로 풀링의 크기에 맞춰서 셋팅되기 때문에 굳이 지정하지 않아도 됩니다. + ++ 풀링은 패딩을 하지않고(valid패딩), 입력 크기를 줄이는게 목적이기 때문에 굳이 지정하지 않아도 됩니다. + + + +
+ + + +##### 컨볼루션 층 + 풀링 층 사용 + +앞서 확인한 내용들을 바탕으로 컨볼루션 층과 풀링 층은 쌍으로 보통 사용합니다. + +(컨볼루션 층 + 풀링 층) 또는 (컨볼루션 층 + 컨볼루션 층 + 풀링 층) 이런 식으로 사용하게 되는데, + +2차원 이상의 크기로 출력이 됩니다. + +그 후에 밀집층(은닉층+출력층 또는 출력층)을 사용하여 원하는 결과값을 얻기 위해 1차원 배열로 풀어서 펼쳐야 합니다. + +따라서 Flatten()함수를 사용하여 1차원 크기로 바꾸어 사용합니다. + + +#### 3차원 합성곱 + + + +보통 컬러 이미지를 입력 데이터로 사용한다면 3차원 배열(높이, 너비, 깊이(채널)) 크기가 됩니다. + +이러한 경우엔 커널도 동일하게 3차원으로 만들면 됩니다. + +3차원 합성곱에서 커널의 설명은 위에서 설명한 내용과 같습니다. + + + ++ 커널의 깊이(채널) = 입력 데이터의 깊이(채널) + ++ 합성곱 연산 결과 : 특성 맵은 입력 데이터의 깊이와 상관없이 (높이, 너비)의 특성 맵을 얻습니다. + +(특성 맵의 채널은 1) + ++ 다만, 합성곱 연산에서 다수의 커널을 사용할 경우 : 특성 맵은 (높이, 너비, 커널의 수) 크기가 됩니다. + +(특성 맵의 채널은 합성곱 연산에 사용된 커널의 수) + diff --git a/_posts/2022-01-25-Fashion_mnist.md b/_posts/2022-01-25-Fashion_mnist.md new file mode 100644 index 000000000000..4e29023bbe3b --- /dev/null +++ b/_posts/2022-01-25-Fashion_mnist.md @@ -0,0 +1,901 @@ +--- +layout: single +title: "인공신경망 정리, fashion mnist" +categories: 딥러닝 +tag: [python, keras, 파이썬, 딥러닝, fashion mnist, 인공신경망, 다중 분류, 예측] +toc: true +toc_sticky: true + +--- + + + + + + +### Fashion MNIST 실습 + + + +
+ + + +케라스의 fashion_mnist 데이터의 카테고리를 인공신경망을 활용해 분류해보려 합니다. + +처음으로 scikit-leran의 로지스틱 회귀를 통해 간단하게 분류 정확도를 체크하고, + +간단한 인공신경망 구축, 은닉층 추가, 옵티마이저 설정과 과적합을 피하기 위한 방법을 추가하며 결과를 확인해보겠습니다. + + + +
+ + + +Keras의 fashion_mnist데이터 + + + 10개의 패션 아이템 클래스를 가지고 있습니다. + + + 28 x 28 픽셀의 흑백 이미지로 이루어져 있습니다. + + +##### keras의 fashion mnist 데이터 가져오기 + + + +```python +from tensorflow.keras.datasets import fashion_mnist + +(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data() + +X_train.shape, y_train.shape +``` + +
+((60000, 28, 28), (60000,))
+
+##### 데이터 확인해보기 + + + +```python +import matplotlib.pyplot as plt +import numpy as np + +# 0 ~ 9번째 X데이터 출력 +fig, axs = plt.subplots(1, 10, figsize=(10, 10)) + +for i in range(10): + axs[i].imshow(X_train[i], cmap='gray_r') + axs[i].axis('off') +plt.show() + +# 0 ~ 9번째 Y데이터 출력 +print([y_train[i] for i in range(10)]) + +# 카테고리 번호를 출력해보기(return_counts : 각 카테고리당 몇개씩 들어있는지 확인) +print(np.unique(y_train, return_counts=True)) +``` + + + +
+[9, 0, 0, 3, 0, 2, 7, 2, 5, 5]
+(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000]))
+
+#### sikit-learn의 로지스틱 회귀로 예측 성능 확인해보기 + ++ 픽셀값은 0 ~ 255까지 이므로 0부터 1사이의 값으로 맞춰주기 위해 X데이터를 255.0으로 나누어줍니다. + ++ 3차원의 X데이터를 1차원으로 펼쳐주기 위해 reshape를 해줍니다. + + + +```python +X_train = X_train / 255.0 +X_test = X_test / 255.0 + +X_train_scaled = X_train.reshape(-1, 28 * 28) +X_test_scaled = X_test.reshape(-1, 28 * 28) + +X_train_scaled.shape, X_test_scaled.shape +``` + +
+((60000, 784), (10000, 784))
+
++ 로지스틱 회귀를 적용하기 위해 loss 매개변수에 손실 함수로 'log'를 지정합니다. + ++ max_iter 매개변수에 반복횟수로 5를 지정합니다. + ++ 반복 실행시 결과가 동일하게 나오기 위해 난수 초기값을 random_state 매개변수로 지정합니다. + + + +```python +# scikit_learn의 SGDClassifier 클래스를 활용하여 경사하강법을 이용한 로지스틱 회귀를 사용 +from sklearn.linear_model import SGDClassifier +from sklearn.model_selection import cross_validate + +sc = SGDClassifier(loss='log', max_iter=5, random_state=42) + +scores = cross_validate(sc, X_train_scaled, y_train, n_jobs=-1) +print(np.mean(scores['test_score'])) # 훈련데이터에 있어서 약 82프로의 정확도를 얻음 +``` + +
+0.8192833333333333
+
+10개의 클래스를 분류해야하는데 손실함수를 'log'로 사용하는 이유 + ++ SGD는 cross_entropy를 지정하는 곳이 따로 없기 때문에 10개의 클래스를 분류하기 위해 10개의 + ++ 예를 들어, 부츠를 양성, 나머지 9개를 음성으로 분류하여 1개의 모델을 훈련 + ++ 티셔츠를 양성, 나머지 9개를 음성으로 분류하여 1개의 모델을 훈련 -> 이런식으로 10개의 모델을 훈련 + ++ 10개의 계산값이 나오면 softmax함수(이진 분류일땐 sigmoid함수)를 사용하여 확률로 바꿔줍니다. + ++ 이런식으로 이진분류를 다중분류처럼 사용하는 방법을 OVR(One verses Rest)라고 합니다. + + +#### 인공 신경망으로 구현 + ++ 로지스틱 회귀 경우 : 픽셀1 x w1 + 픽셀2 x w2 + ... + 픽셀784 x w784 + b => 10개의 모델 + ++ 이를 인공 신경망으로 구현해봅니다. + + + +```python +# 검증 데이터 0.2 비율로 분리 +from sklearn.model_selection import train_test_split +X_train_scaled, X_val_scaled, y_train, y_val = train_test_split( + X_train_scaled, y_train, test_size=0.2, random_state=42) + +X_train_scaled.shape, y_train.shape, X_val_scaled.shape, y_val.shape +``` + +
+((48000, 784), (48000,), (12000, 784), (12000,))
+
+##### 모델 정의 + ++ Dense 레이어를 사용하여 은닉층과 출력층을 생성합니다. + ++ 은닉층의 활성화 함수에는 자주 쓰이는 'relu'를 사용합니다. + ++ 출력층의 활성화 함수에는 다중분류이므로 'softmax'(이진분류일때는 'sigmoid')를 사용합니다. + + + +##### 모델 컴파일 + ++ 손실 함수 + + + 이진 분류 : binary_crossentropy + + + 다중 분류 : categorical_crossentropy + ++ sparse_categorical_crossentropy란? + + + y데이터의 값은 0 ~ 9 까지의 정수인것을 확인했습니다. + + 이 정수값을 그대로 사용할 순 없고, 출력층에는 10개의 유닛에서 softmax함수값을 거쳐 10개의 확률값이 나옵니다. + + + crossentropy의 공식에 따라 10개의 확률값에 각각 로그를 취하고 타깃값과 곱하게 됩니다. + + (샘플이 티셔츠일 확률 : a1 => -log(a1) x target값, -log(a2) x target값, ...) + + + 여기서, 티셔츠는 첫번째 원소가 1이고 나머지 0(\[1, 0, 0, ... , 0\])인 원 핫 인코딩이 되어있어야지만 + + 첫번째 unit을 제외한 나머지 unit에서의 출력값이 모두 0이 곱해져 상쇄되어 티셔츠에 해당되는 뉴런의 출력값만 손실에 반영됩니다. + + + 하지만 원 핫 인코딩을 사용하지 않고, Y데이터의 정수값 그대로를 사용하려면 sparse_categorical_crossentropy를 사용합니다. + + + + + +```python +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Dense + +model = Sequential() + +# 다중분류이므로 softmax 사용 +model.add(Dense(10, activation='softmax', input_shape=(784, ))) + +model.compile(loss='sparse_categorical_crossentropy', + optimizer='adam', + metrics=['acc']) +``` + + +```python +# 모델 학습 +history = model.fit(X_train_scaled, y_train, epochs=15, batch_size=100, + validation_data=(X_val_scaled, y_val)) +``` + +
+Epoch 1/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.7469 - acc: 0.7560 - val_loss: 0.5672 - val_acc: 0.8115
+Epoch 2/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.5187 - acc: 0.8279 - val_loss: 0.5018 - val_acc: 0.8309
+Epoch 3/15
+480/480 [==============================] - 0s 1ms/step - loss: 0.4758 - acc: 0.8400 - val_loss: 0.4818 - val_acc: 0.8371
+Epoch 4/15
+480/480 [==============================] - 0s 1ms/step - loss: 0.4544 - acc: 0.8457 - val_loss: 0.4677 - val_acc: 0.8382
+Epoch 5/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4401 - acc: 0.8502 - val_loss: 0.4564 - val_acc: 0.8411
+Epoch 6/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4293 - acc: 0.8547 - val_loss: 0.4435 - val_acc: 0.8470
+Epoch 7/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4214 - acc: 0.8556 - val_loss: 0.4428 - val_acc: 0.8488
+Epoch 8/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4149 - acc: 0.8583 - val_loss: 0.4364 - val_acc: 0.8489
+Epoch 9/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4089 - acc: 0.8605 - val_loss: 0.4265 - val_acc: 0.8509
+Epoch 10/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4049 - acc: 0.8609 - val_loss: 0.4224 - val_acc: 0.8533
+Epoch 11/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.4026 - acc: 0.8615 - val_loss: 0.4261 - val_acc: 0.8514
+Epoch 12/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.3986 - acc: 0.8623 - val_loss: 0.4190 - val_acc: 0.8552
+Epoch 13/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.3952 - acc: 0.8644 - val_loss: 0.4185 - val_acc: 0.8533
+Epoch 14/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.3925 - acc: 0.8634 - val_loss: 0.4213 - val_acc: 0.8560
+Epoch 15/15
+480/480 [==============================] - 1s 1ms/step - loss: 0.3901 - acc: 0.8659 - val_loss: 0.4155 - val_acc: 0.8560
+
+ +```python +# 테스트 데이터를 모델에 적용하여 평가하기 [loss, acc] +model.evaluate(X_test_scaled, y_test) +``` + +
+313/313 [==============================] - 0s 854us/step - loss: 0.4530 - acc: 0.8427
+
+
+[0.45295682549476624, 0.8427000045776367]
+
+#### 심층 신경망 + ++ 입력층 784개의 뉴런과 은닉층 100개 뉴런, 출력층 10개 뉴런을 생성해보았습니다. + + + +```python +# 모델을 좀 더 깊게(은닉층 추가) 수정 +model = Sequential() + +model.add(Dense(100, activation='relu', input_shape=(784, ))) # 은닉층 +model.add(Dense(10, activation='softmax')) # 출력층 + +model.compile(loss='sparse_categorical_crossentropy', + optimizer='adam', + metrics=['acc']) +``` + +##### model의 summary() 메서드 + ++ layer의 정보, 각 layer의 출력의 크기, 파라미터의 갯수를 확인할 수 있습니다. + ++ 은닉층의 파라미터 갯수 : 784개의 입력 층과 은닉층의 100개의 뉴런이 있고, 각 뉴런은 b(절편)이 존재하므로 + +100개의 b값이 존재합니다. + +따라서, 784 x 100 + 100 = 78500이 됩니다. + ++ 출력층의 파라미터 갯수 : 은닉층에서 나오는 100개의 출력, 10개의 출력층 뉴런이 있으므로 + +100 x 10 + 10 = 1010이 됩니다. + + + +```python +model.summary() +``` + +
+Model: "sequential_1"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ dense_1 (Dense)             (None, 100)               78500     
+                                                                 
+ dense_2 (Dense)             (None, 10)                1010      
+                                                                 
+=================================================================
+Total params: 79,510
+Trainable params: 79,510
+Non-trainable params: 0
+_________________________________________________________________
+
+ +```python +model.fit(X_train_scaled, y_train, + epochs=15, batch_size=128, validation_data=(X_val_scaled, y_val)) +``` + +
+Epoch 1/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.5933 - acc: 0.7972 - val_loss: 0.4648 - val_acc: 0.8373
+Epoch 2/15
+375/375 [==============================] - 1s 1ms/step - loss: 0.4281 - acc: 0.8506 - val_loss: 0.4153 - val_acc: 0.8555
+Epoch 3/15
+375/375 [==============================] - 1s 1ms/step - loss: 0.3919 - acc: 0.8607 - val_loss: 0.3894 - val_acc: 0.8612
+Epoch 4/15
+375/375 [==============================] - 1s 1ms/step - loss: 0.3631 - acc: 0.8710 - val_loss: 0.3836 - val_acc: 0.8612
+Epoch 5/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.3414 - acc: 0.8799 - val_loss: 0.3521 - val_acc: 0.8702
+Epoch 6/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.3286 - acc: 0.8834 - val_loss: 0.3569 - val_acc: 0.8742
+Epoch 7/15
+375/375 [==============================] - 1s 1ms/step - loss: 0.3144 - acc: 0.8865 - val_loss: 0.3525 - val_acc: 0.8730
+Epoch 8/15
+375/375 [==============================] - 1s 1ms/step - loss: 0.3006 - acc: 0.8908 - val_loss: 0.3457 - val_acc: 0.8777
+Epoch 9/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2924 - acc: 0.8941 - val_loss: 0.3365 - val_acc: 0.8792
+Epoch 10/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2800 - acc: 0.8987 - val_loss: 0.3267 - val_acc: 0.8859
+Epoch 11/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2723 - acc: 0.9005 - val_loss: 0.3283 - val_acc: 0.8832
+Epoch 12/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2653 - acc: 0.9034 - val_loss: 0.3252 - val_acc: 0.8847
+Epoch 13/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2559 - acc: 0.9055 - val_loss: 0.3183 - val_acc: 0.8844
+Epoch 14/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2508 - acc: 0.9078 - val_loss: 0.3135 - val_acc: 0.8886
+Epoch 15/15
+375/375 [==============================] - 1s 2ms/step - loss: 0.2430 - acc: 0.9116 - val_loss: 0.3236 - val_acc: 0.8815
+
+
+
+
+ +```python +model.evaluate(X_test_scaled, y_test) +``` + +
+313/313 [==============================] - 0s 714us/step - loss: 0.3513 - acc: 0.8715
+
+
+[0.3512624502182007, 0.8715000152587891]
+
+#### Relu함수와 Flatten층 + ++ Relu함수 + +간단하게 말하면 Max함수입니다. + +뉴런의 출력값이 0보다 크면 그대로 출력, 0보다 작으면 0으로 출력해주는 단순한 함수입니다. + + + ++ Flatten층 + +실제로 가중치는 존재하지 않는 층이며, 편의를 위해서 추가하는 층입니다. + +위에서 X데이터를 28x28 -> 784의 1차원 배열로 풀어주는 전처리 과정을 포함했습니다. + +이러한 작업을 Fletten이 대신 해줍니다. + +Flatten의 input_shape에 (28, 28)로 지정해주면 784의 1차원 배열로 전달해줍니다. + +summary()에서 보면 Flatten층의 출력 크기는 784로 나오는것을 확인할 수 있습니다. + + + +```python +# Flatten층 사용하기 위해 reshape을 하지 않아도 됩니다. +# 그렇기 위해 귀찮겠지만 다시 데이터를 다시 로드했습니다. + +(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data() + +X_train = X_train / 255.0 +X_test = X_test / 255.0 +``` + + +```python +from tensorflow.keras.layers import Flatten + +model = Sequential() + +model.add(Flatten(input_shape=(28, 28))) +model.add(Dense(100, activation='relu')) +model.add(Dense(10, activation='softmax')) + +model.compile(loss='sparse_categorical_crossentropy', + optimizer='adam', + metrics=['acc']) +``` + + +```python +model.summary() +``` + +
+Model: "sequential_6"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ flatten_4 (Flatten)         (None, 784)               0         
+                                                                 
+ dense_11 (Dense)            (None, 100)               78500     
+                                                                 
+ dense_12 (Dense)            (None, 10)                1010      
+                                                                 
+=================================================================
+Total params: 79,510
+Trainable params: 79,510
+Non-trainable params: 0
+_________________________________________________________________
+
+ +```python +history = model.fit(X_train, y_train, epochs=20, + batch_size=128, validation_split=0.2) +``` + +
+Epoch 1/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.5939 - acc: 0.8002 - val_loss: 0.4570 - val_acc: 0.8438
+Epoch 2/20
+375/375 [==============================] - 1s 1ms/step - loss: 0.4267 - acc: 0.8518 - val_loss: 0.4048 - val_acc: 0.8581
+Epoch 3/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.3846 - acc: 0.8652 - val_loss: 0.3798 - val_acc: 0.8639
+Epoch 4/20
+375/375 [==============================] - 1s 1ms/step - loss: 0.3614 - acc: 0.8720 - val_loss: 0.3696 - val_acc: 0.8674
+Epoch 5/20
+375/375 [==============================] - 1s 1ms/step - loss: 0.3388 - acc: 0.8785 - val_loss: 0.3745 - val_acc: 0.8658
+Epoch 6/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.3238 - acc: 0.8849 - val_loss: 0.3453 - val_acc: 0.8755
+Epoch 7/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.3120 - acc: 0.8859 - val_loss: 0.3625 - val_acc: 0.8701
+Epoch 8/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2972 - acc: 0.8907 - val_loss: 0.3300 - val_acc: 0.8813
+Epoch 9/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2896 - acc: 0.8948 - val_loss: 0.3335 - val_acc: 0.8792
+Epoch 10/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2773 - acc: 0.8988 - val_loss: 0.3262 - val_acc: 0.8821
+Epoch 11/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2702 - acc: 0.9020 - val_loss: 0.3237 - val_acc: 0.8848
+Epoch 12/20
+375/375 [==============================] - 1s 1ms/step - loss: 0.2620 - acc: 0.9047 - val_loss: 0.3225 - val_acc: 0.8835
+Epoch 13/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2531 - acc: 0.9072 - val_loss: 0.3294 - val_acc: 0.8831
+Epoch 14/20
+375/375 [==============================] - 1s 1ms/step - loss: 0.2489 - acc: 0.9087 - val_loss: 0.3149 - val_acc: 0.8861
+Epoch 15/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2437 - acc: 0.9115 - val_loss: 0.3265 - val_acc: 0.8832
+Epoch 16/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2362 - acc: 0.9131 - val_loss: 0.3123 - val_acc: 0.8893
+Epoch 17/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2324 - acc: 0.9145 - val_loss: 0.3193 - val_acc: 0.8874
+Epoch 18/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2246 - acc: 0.9180 - val_loss: 0.3212 - val_acc: 0.8847
+Epoch 19/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2232 - acc: 0.9179 - val_loss: 0.3140 - val_acc: 0.8867
+Epoch 20/20
+375/375 [==============================] - 1s 2ms/step - loss: 0.2141 - acc: 0.9224 - val_loss: 0.3102 - val_acc: 0.8913
+
+ +```python +model.evaluate(X_test, y_test) +``` + +
+313/313 [==============================] - 0s 765us/step - loss: 0.3447 - acc: 0.8824
+
+
+[0.34466418623924255, 0.8823999762535095]
+
+#### 옵티마이저 + ++ 학습률 : 경사하강법을 비유하자면, 산을 내려가면서 최적값을 찾아갈때 이동하는 거리. + +학습률을 너무 높게 잡는다면 최적값을 지나칠 수도 있기 때문에 적절한 학습률 조정이 필요합니다. + + + +기본 경사 하강법 옵티마이저 + ++ SGD + + + 기본 학습률은 0.01입니다. + + model.compile(optimizer='sgd') + + + 학습률 조정도 가능합니다. (0.1로 변경) + + sgd = tensorflow.keras.optimizers.SGD(learning_rate=0.1) + ++ 모멘텀 + + + SGD에서 momentum > 0 + + sgd = tensorflow.keras.optimizers.SGD(momentum=0.9) + ++ 네스테로프 모멘텀 + + + SGD의 설정에서 nesterov = True를 주어 사용합니다. + + + +
+ + + +경사하강법에서 학습률에 따라 최적값을 찾아갈때, 최적값과 멀리 있을 땐 높은 이동 거리로 빠르게 접근하고, + +최적값과 가까워질 땐 좁은 거리로 이동하며 최대한 최적값에 수렴해가는게 좋습니다. + +이렇게 변화할 수 있는 학습률을 가지고 있는 것이 적응적 학습률 옵티마이저입니다. + + + +
+ + + +적응적 학습률 옵티마이저 + ++ RMSProp + ++ Adam + ++ Adagrad + + +#### 정확도와 손실 시각화해보기 + +model.fit()의 history는 훈련 과정 중 epoch별로 loss와 acc의 결과를 담고 있습니다. + +이를 활용해 모델의 정확도와 손실을 시각화 해볼 수 있습니다. + + + +
+ + + +시각화를 한 결과, epoch가 증가할 수록 훈련 데이터와 검증 데이터의 loss가 같이 줄어들고, + +정확도는 동시에 증가하는 것을 볼 수 있습니다. + +즉, 과적합이 많이 나타나지 않는 괜찮은 성능의 모델이라 확인할 수 있습니다. + + + +```python +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() +``` + +
+
+
+ + +#### 드롭아웃 + ++ 가장 많이 사용하는 과적합을 피하는 방법 중 하나입니다. + ++ 모델을 훈련할 때, 0 ~ 1사이의 확률로 랜덤적으로 뉴런의 계산을 끄고 학습을 진행합니다. + ++ 제외하지 않은 나머지 뉴런에서만 훈련이 이루어집니다. + ++ 특정 뉴런의 의존하게 되는 계산을 막을 수 있습니다. + ++ 모델을 평가할때는 모든 뉴런을 사용합니다. + + + +```python +from tensorflow.keras.layers import Dropout + +model = Sequential() + +model.add(Flatten(input_shape=(28, 28))) +model.add(Dense(100, activation='relu')) +model.add(Dropout(0.3)) # 0.3비율로 Dropout +model.add(Dense(10, activation='softmax')) + +model.compile(loss='sparse_categorical_crossentropy', + optimizer='adam', + metrics=['acc']) + +model.summary() +``` + +
+Model: "sequential_9"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ flatten_7 (Flatten)         (None, 784)               0         
+                                                                 
+ dense_17 (Dense)            (None, 100)               78500     
+                                                                 
+ dropout_4 (Dropout)         (None, 100)               0         
+                                                                 
+ dense_18 (Dense)            (None, 10)                1010      
+                                                                 
+=================================================================
+Total params: 79,510
+Trainable params: 79,510
+Non-trainable params: 0
+_________________________________________________________________
+
+ +```python +history = model.fit(X_train, y_train, + epochs=20, + validation_split=0.2) +``` + +
+Epoch 1/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.5865 - acc: 0.7941 - val_loss: 0.4211 - val_acc: 0.8484
+Epoch 2/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.4389 - acc: 0.8434 - val_loss: 0.4098 - val_acc: 0.8489
+Epoch 3/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.4026 - acc: 0.8535 - val_loss: 0.3723 - val_acc: 0.8635
+Epoch 4/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3810 - acc: 0.8605 - val_loss: 0.3629 - val_acc: 0.8709
+Epoch 5/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3659 - acc: 0.8661 - val_loss: 0.3551 - val_acc: 0.8708
+Epoch 6/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3514 - acc: 0.8716 - val_loss: 0.3622 - val_acc: 0.8639
+Epoch 7/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3432 - acc: 0.8738 - val_loss: 0.3498 - val_acc: 0.8747
+Epoch 8/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3318 - acc: 0.8772 - val_loss: 0.3304 - val_acc: 0.8803
+Epoch 9/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3288 - acc: 0.8775 - val_loss: 0.3341 - val_acc: 0.8805
+Epoch 10/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3150 - acc: 0.8828 - val_loss: 0.3430 - val_acc: 0.8723
+Epoch 11/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3119 - acc: 0.8841 - val_loss: 0.3254 - val_acc: 0.8847
+Epoch 12/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3086 - acc: 0.8851 - val_loss: 0.3414 - val_acc: 0.8780
+Epoch 13/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.3001 - acc: 0.8880 - val_loss: 0.3325 - val_acc: 0.8831
+Epoch 14/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2963 - acc: 0.8879 - val_loss: 0.3212 - val_acc: 0.8842
+Epoch 15/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2917 - acc: 0.8915 - val_loss: 0.3254 - val_acc: 0.8861
+Epoch 16/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2840 - acc: 0.8941 - val_loss: 0.3248 - val_acc: 0.8859
+Epoch 17/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2847 - acc: 0.8938 - val_loss: 0.3197 - val_acc: 0.8875
+Epoch 18/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2788 - acc: 0.8957 - val_loss: 0.3405 - val_acc: 0.8804
+Epoch 19/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2766 - acc: 0.8964 - val_loss: 0.3131 - val_acc: 0.8906
+Epoch 20/20
+1500/1500 [==============================] - 2s 1ms/step - loss: 0.2723 - acc: 0.8971 - val_loss: 0.3260 - val_acc: 0.8868
+
+시각화를 해보면, Dropout을 사용했을 때 train_loss와 val_loss의 폭이 좀 더 줄어들고, + +val_loss의 증가율이 좀 더 낮아졌음을 볼 수 있습니다. + + + +```python +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() +``` + +
+
+
+ + +#### 모델 저장 및 복원 + ++ model.save_weights() : 모델의 구조는 저장하지않고, 파라미터만 저장합니다. (가중치, 편향) + ++ model.load_weights() : 저장된 모델 객체를 불러옵니다. + + + +
+ + + ++ model.save() : 모델 구조 자체를 모두 저장합니다. + ++ model.load_model() : 저장된 모델을 불러옵니다. + + + +```python +# 모델 저장 +model.save('./fashion_mnist_model-whole.h5') +``` + +model.predict() : 10개의 클래스가 존재하므로 각 샘플마다 10개의 확률을 출력해줍니다. + +10개의 확률 중 np.argmax()를 통해 가장 높은 값을 찾아서 그 인덱스를 예측값으로 사용합니다. + +얻은 예측값과 실제 테스트 데이터를 비교하여 평균을 내어 정확도를 내줍니다. + +아래에서 예측을 수행한 결과 약 88%의 정확도를 확인할 수 있습니다. + + + +```python +# model.predict() : 각 샘플마다 10개의 확률을 출력해주는 메서드 +# 10개의 확률 중 가장 높은 값을 찾아서 그 인덱스를 예측 값으로 사용합니다. + +predictions = model.predict(X_test) +val_labels = np.argmax(predictions, axis=1) # axis=1 : 행 기준으로 연산 수행(<-> axis=0 : 열 기준) +print(np.mean(val_labels == y_test)) # True : 1, False : 0 +``` + +
+0.8728
+
+#### 조기종료 + +학습이 진행될수록 학습셋의 정확도는 올라가지만 과적합으로 인해 테스트셋의 실험 결과가 점점 나빠질 수 있습니다. + +이렇게 학습이 진행되어도 텟트셋 오차가 줄지 않을 경우 학습을 멈추게 하는 함수입니다. + + + +
+ + + ++ patience = 2 : 검증셋의 손실이 2번 증가하면 중지 + ++ restore_best_weights=True : 가장 손실이 낮았던 곳으로 되돌리기 + + + +```python +import keras + +checkpoint_cb = keras.callbacks.ModelCheckpoint('fashion_mnist_model-whole.h5') +early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, + restore_best_weights=True) + +history = model.fit(X_train, y_train, epochs=50, verbose=0, + validation_split=0.2, callbacks=[checkpoint_cb, early_stopping_cb]) + +print(f"종료될 떄의 epoch : {early_stopping_cb.stopped_epoch}") + +loss = history.history['loss'] +val_loss = history.history['val_loss'] + +plt.plot(loss) +plt.plot(val_loss) +plt.xlabel('epoch') +plt.ylabel('loss') +plt.legend(['train', 'val']) +plt.show() +``` + +
+종료될 떄의 epoch : 11
+
+ diff --git "a/_posts/2022-02-04-\354\210\234\354\260\250 \353\215\260\354\235\264\355\204\260\354\231\200 \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235.md" "b/_posts/2022-02-04-\354\210\234\354\260\250 \353\215\260\354\235\264\355\204\260\354\231\200 \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235.md" new file mode 100644 index 000000000000..51ce65377c98 --- /dev/null +++ "b/_posts/2022-02-04-\354\210\234\354\260\250 \353\215\260\354\235\264\355\204\260\354\231\200 \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235.md" @@ -0,0 +1,382 @@ +--- +layout: single +title: "순환신경망(RNN) 정리" +categories: 딥러닝 +tag: [python, keras, 순환신경망, 순차데이터, RNN, 딥러닝] +toc: true +toc_sticky: true + +--- + + + + + + +다음의 출처를 참고했습니다. + + + + +### 순차 데이터 + +순차 데이터는 순서에 의미가 있으며, 순서가 달라질 경우 의미가 손상되는 데이터입니다. + +시간적 의미가 있는 경우 Temporal Sequence라고 하며, 일정한 시간차라면 Time Series라고 합니다. + + +### 순환 신경망(RNN) + +순환 신경망은 순차 데이터와 같이 시간의 흐름에 따라 변화하는 데이터를 학습하기 위한 인공신경망입니다. + +따라서, 과거의 출력 데이터를 재귀적으로 참조합니다. + +순환되는 고리가 있는 신경망입니다. + + + +
+ + + +![RNN](/assets/images/RNN.png) + + +위의 그림을 보면 은닉층의 노드에서 나온 결과값이 출력층 방향으로도 보내지고, + +다시 은닉층 노드의 다음 계산을 위한 입력으로도 보내지는 특징이 있습니다. + +그러므로, 결과값 O(t)는 결과값 O(t-1)에 대한 정보가 어느정도 포함(기억)되고, + +O(t+1)은 O(t)와 O(t-1)의 정보가 어느정도 포함(기억)된다고 할 수 있습니다. + +이렇게 이전의 계산에서 나온 출력값을 다시 다음 단계 계산에서 사용하는 하나의 사이클을 Time Step이라고 합니다. + + + +
+ + + ++ 셀 : 은닉층에서 결과를 두 뱡향(출력층과 다음 연산)으로 내보내는 노드를 메모리 셀 혹은 셀이라고 합니다. + + + +
+ + + +완전 연결층에서 출력되는 값은 활성화 출력, 합성곱 층에서 출력되는 값은 특성 맵이라고 하듯이, + +셀에서 출력하는 값은 은닉 상태(Hidden State)라고 합니다. + +또한, RNN에서는 입력층/출력층을 입력벡터/출력벡터 라고 합니다. + + + +
+ + + +##### RNN 수식 이해하기 + + + +![RNN 수식](/assets/images/RNN수식.PNG) + + + ++ ht : 현재 타임 스텝 t에서의 은닉 상태값 + ++ wx : 입력 벡터의 입력값과 곱해질 가중치 + ++ wh : 이전 타임 스텝 t-1에서의 은닉 상태값 ht-1과 곱해질 가중치 + + + +따라서 ht를 계산하는 수식은 다음과 같습니다. + ++ ht = activation_function((wh * ht-1) + (wx * xt) + b) + ++ yt = activation_function((wy * ht) + b) + + + +RNN에서도 역시 활성화 함수를 사용하는데, 보통 tanh함수를 많이 사용합니다.(relu를 사용하기도) + +(tanh도 역시 S자 모양으로 -1 ~ 1값을 가지기 때문에 시그모이드라고 불리기도 합니다.) + + + +RNN은 이렇게 각 타임 스텝마다 wx와 wh를 동일하게 사용합니다. + +이런 부분을 보았을 때, RNN은 타임 스텝에 따라서 가중치를 공유하며 모델의 파라미터를 효율적으로 사용할 수 있습니다. + + +##### 순환 신경망의 입력과 출력 + +RNN층은 (batch_size, timesteps, input_dim) 형태의 3D 텐서를 입력받습니다. + ++ batch_size는 한번에 RNN이 학습하는 데이터의 양을 의미합니다. + ++ timesteps는 입력 시퀀스의 크기입니다. input_length와 동일합니다. + ++ input_dim은 입력의 크기입니다. + + + +```python +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import SimpleRNN + +model = Sequential() +model.add(SimpleRNN(3, input_shape=(2, 10))) +# batch_size=8, timesteps=2, input_dim=10 + +model.summary() +``` + +
+Model: "sequential_3"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ simple_rnn_3 (SimpleRNN)    (8, 3)                    42        
+                                                                 
+=================================================================
+Total params: 42
+Trainable params: 42
+Non-trainable params: 0
+_________________________________________________________________
+
+RNN의 출력값은 (batch_size, output_dim)형태로 출력됩니다. + +units는 RNN층의 은닉층의 갯수를 의미하고, output_dim은 은닉층의 갯수(units)가 됩니다. + +위와 같이 (2, 10)형태의 2D 텐선을 입력하면 units는 3이고, batch_size는 알 수 없으므로 (None, 3)이 출력됩니다. + + + +```python +model = Sequential() +model.add(SimpleRNN(3, batch_input_shape=(8, 2, 10))) +# RNN층의 units = 3, batch_size=8, timesteps=2, input_dim=10 + +model.summary() +``` + +
+Model: "sequential_4"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ simple_rnn_4 (SimpleRNN)    (8, 3)                    42        
+                                                                 
+=================================================================
+Total params: 42
+Trainable params: 42
+Non-trainable params: 0
+_________________________________________________________________
+
+batch_size를 기재하면 입력은 3D 텐서이고, 출력값으로 (batch_size, output_dim)이 리턴됩니다. + +하지만, return_sequences 매개 변수를 True로 지정해주면 (batch_size, timesteps, output_dim)크기의 + +3D 텐서를 리턴할 수 있습니다. + + + +
+ + + +##### return_sequences + +셀의 각 시점(time step)의 은닉 상태값들을 모아서 전체 시퀀스를 리턴하려면 return_sequences=True를 설정하면 + +됩니다. + + + +
+ + + +![return_sequences](/assets/images/리턴시퀸스.PNG) + + + +위의 그림은 time step가 3일 때, return_sequences=True로 설정했을 때와 아닐 때의 차이를 보여줍니다. + +return_sequences=True로 설정하면 셀의 모든 시점(time step)에 대한 은닉 상태값을 출력하고, + +return_sequences=False일 경우에 셀은 하나의 마지막 시점의 은닉 상태값만 출력합니다. + + + +```python +model = Sequential() +model.add(SimpleRNN(3, batch_input_shape=(8, 2, 10), return_sequences=True)) +# RNN층의 units = 3, batch_size=8, timesteps=2, input_dim=10 + +model.summary() +``` + +
+Model: "sequential_5"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ simple_rnn_5 (SimpleRNN)    (8, 2, 3)                 42        
+                                                                 
+=================================================================
+Total params: 42
+Trainable params: 42
+Non-trainable params: 0
+_________________________________________________________________
+
+return_sequences=True를 설정하면 출력값으로 (batch_size, timesteps, output_dim) 크기의 + +3D 텐서가 출력되는 것을 확인할 수 있습니다. + + +##### RNN의 활용 + +RNN은 입력과 출력의 길이가 고정되어 있지 않습니다. 그러므로, 설계에 따라 다양한 용도로 신경망을 사용할 수 있습니다. + + + +![RNN활용](/assets/images/RNN활용.PNG) + + + +일대다 모델 + ++ 하나의 이미지 입력에 대해서 사진의 제목을 출력하는 이미지 캡셔닝(Image Captioning)작업에 사용할 수 있습니다. + +사진의 제목은 단어들의 나열이므로 시퀀스 출력입니다. + + + +다대일 모델 + ++ 입력 문서가 긍정적인지 부정적인지 판별하는 감성 분류(sentiment classification) + ++ 메일이 정상 메일인지 스팸 메일인지 판별하는 스팸 메일 분류(spam detection)등에 사용할 수 있습니다. + + + +다대다 모델 + ++ 사용자가 문장을 입력하면 대답 문장을 출력하는 챗봇 + ++ 입력 문장으로부터 번역된 문장을 출력하는 번역기 등이 있습니다. + + +#### 양방향 순환 신경망 + + + +양방향 RNN은 이전과 이후의 시점 모두를 고려해서 현재 시점의 예측을 더욱 정확하게 할 수 있도록 고안된 방법입니다. + +기본적으로 두 개의 메모리 셀을 사용합니다. + +첫번째 셀은 기존과 동일하게 앞 시점의 은닉 상태를 전달받아 현재의 은닉 상태를 계산합니다. + +두번째 셀은 뒤 시점의 은닉상태를 전달 받아 현재의 은닉 상태를 계산합니다.(입력 시퀀스를 반대 방향으로 읽습니다.) + +이처럼 앞, 뒤 2개의 시점을 이용하여 현재 시점의 은닉 상태를 출력합니다. + + + + +```python +from tensorflow.keras.layers import Bidirectional + +model = Sequential() +model.add(Bidirectional(SimpleRNN(3, return_sequences=True), input_shape=(2, 10))) + +model.summary() +``` + +
+Model: "sequential_7"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ bidirectional_1 (Bidirectio  (None, 2, 6)             84        
+ nal)                                                            
+                                                                 
+=================================================================
+Total params: 84
+Trainable params: 84
+Non-trainable params: 0
+_________________________________________________________________
+
\ No newline at end of file diff --git "a/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\213\234\352\260\201\355\231\224.md" "b/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\213\234\352\260\201\355\231\224.md" new file mode 100644 index 000000000000..a6c36f9796dd --- /dev/null +++ "b/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\213\234\352\260\201\355\231\224.md" @@ -0,0 +1,403 @@ +--- +layout: single +title: "합성곱 신경망 시각화" +categories: 딥러닝 +tag: [python, 파이썬, keras, CNN 시각화, 합성곱 시각화, Fashion MNIST, 딥러닝] +toc: true +toc_sticky: true + +--- + + + + + + +### CNN 시각화 + + + +이전에는 Fashion MNIST 데이터셋 분류 모델을 CNN으로 구현해보았습니다. + +이번 포스팅에서는 합성곱 계층을 시각화 해보겠습니다. + + + +
+ + + +먼저 이전에 CNN으로 구현해서 저장해두었던 모델을 불러와서 모델의 계층을 확인해 보았습니다. + + + +```python +from tensorflow.keras.models import load_model + +model = load_model('./models/fasion_mnist_cnn_model.h5') + +# 모델의 계층 확인 +model.layers +``` + +
+[,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ]
+
+ +```python +model.layers +``` + +
+[,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ]
+
+첫번째 층인 Conv2D 계층의 가중치를 확인하기 위해 모델의 layers속성에 0번째 인덱스로 접근해서 conv객체에 저장하겠습니다. + +conv객체의 weights속성에는 그 계층의 필터와 가중치가 포함되어 있습니다. + +(필터의 갯수만큼 가중치의 갯수가 정해집니다.) + + + +```python +conv = model.layers[0] +print(conv.weights[0].shape, conv.weights[1].shape) +``` + +
+(3, 3, 1, 32) (32,)
+
+conv객체의 weights\[0\]은 필터의 가중치, weights\[1\]은 절편입니다. + +크기를 출력해보면, 필터의 크기가 3x3x1(흑백 이미지이므로 채널은 1)이고, 32개의 필터가 사용되었음을 알 수 있습니다. + +weights\[1\]에서 필터의 갯수가 32이므로 절편의 갯수도 32임을 확인할 수 있습니다. + + + +
+ + + +##### 층의 가중치 분포 + + + +이제 층의 가중치 분포를 시각화해보겠습니다. + +conv객체의 weights[0]의 가중치를 numpy 배열로 변환하여 conv_weights 객체에 저장하고, + +reshape을 사용해서 2번째 차원이 1이 되도록 즉, 열 벡터가 되도록 쭉 펼쳐서 + +히스토그램을 통해 시각화를 해봅니다. + + + +```python +import numpy as np +import matplotlib.pyplot as plt + +conv_weights = conv.weights[0].numpy() +plt.hist(conv_weights.reshape(-1, 1)) +plt.xlabel('weight') +plt.ylabel('count') +plt.show() +``` + + + + +```python +# 훈련 전 모델 +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout + +no_training_model = Sequential() +no_training_model.add(Conv2D(32, kernel_size=3, activation='relu', padding='same', input_shape=(28,28,1))) + + +no_training_conv = no_training_model.layers[0] +no_training_conv_weights = no_training_model.weights[0].numpy() + +conv_weights = no_training_conv.weights[0].numpy() +plt.hist(no_training_conv_weights.reshape(-1, 1)) +plt.xlabel('weight') +plt.ylabel('count') +plt.show() +``` + + + +약 100개 정도의 원소가 0에 가까운 값을 가지고 있고, 약 20개 정도는 0.25 ~ 0.5의 값을 가지고 있습니다. + +마이너스 값을 가진 원소들도 확인 할 수 있는데요. + +학습하기전의 그래프 모양은 -부터 +까지 균등분포 형태를 가질것입니다. + +학습 전에는 가중치가 무작위로 초기화되어 규칙성이 없기 때문입니다. + +하지만, 학습을 마친 필터는 규칙성이 생기므로 이러한 분포를 나타냅니다. + +큰 양의 값과 큰 음의 값은 입력 이미지에서 어떠한 특징을 감지하기 위한 값들이고, + +0에 가까운 값일 수록 의미있는 값을 학습하는 가중치라고 할 수 없습니다. + + +##### 층의 가중치 시각화 + + + +필터를 (3x3)크기로 32개 만큼 시각화 했습니다. + +matplotlib의 imshow()는 배열의 값을 최솟값에 가까울수록 어둡게, 최댓값에 가까울수록 밝게 이미지로 출력해줍니다. + +이 수치가 동일한 기준을 갖기 위해 vmin, vmax으로 설정했습니다. + + + +
+ + + +가중치 시각화도 마찬가지로 학습하기 전은 흑백의 정도에 규칙성이 없이 균등하게 나타납니다. + +하지만, 학습을 마친 필터에는 나름의 규칙성이 있는 이미지화가 되어 다음과 같이 출력됩니다. + + + +```python +fig, axs = plt.subplots(2, 16, figsize=(15, 2)) + +for i in range(2): + for j in range(16): + axs[i, j].imshow(conv_weights[:, :, 0, i * 16 + j], vmin=-0.5, vmax=0.5) + axs[i, j].axis('off') + +plt.show() +``` + + + + +```python +# 학습 전 +fig, axs = plt.subplots(2, 16, figsize=(15, 2)) + +for i in range(2): + for j in range(16): + axs[i, j].imshow(no_training_conv_weights[:, :, 0, i * 16 + j], vmin=-0.5, vmax=0.5) + axs[i, j].axis('off') + +plt.show() +``` + + + +##### 합성곱의 특성맵 시각화 + + + +특성맵을 시각화 하기위해 함수형API를 사용하여 모델을 구축해야합니다. + +이전에는 Sequential클래스를 사용했지만, 보다 복잡한 모델(다중 입력 또는 다중 출력)을 구성하기 위해서는 + +함수형API를 사용합니다. + + + +
+ + + ++ 함수형 API + + 케라스에서 가장 권장하는 방법 중 하나입니다. + + 복잡한 모델을 유연하게 구성할 수 있습니다. + + 다중 입력, 출력이 가능합니다. + + + +
+ + + +```python + +from tensorflow.keras.models import Model + +from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, GlobalAveragePooling2D + +from tensorflow.keras.layers import Input + +from tensorflow.keras.utils import plot_model + + + +# 함수형 API는 Input층을 통해서 입력값의 형태를 정합니다. + +inputs = Input(shape=(28, 28, 3)) + +x = Conv2D(32, kernel_size=3, activation='relu', padding='same')(inputs) + +x = Conv2D(32, kernel_size=3, activation='relu', padding='same')(x) + +x = MaxPooling2D(2)(x) + +x = GlobalAveragePooling2D()(x) + +x = Dense(10, activation='softmax')(x) + + + +# 위에서 정의된 층을 포함하고 있는 모델을 생성합니다. + +model = Model(inputs=inputs, outputs=x) + +``` + + +##### 첫 번째 특성 맵 시각화 + +첫번째 Conv층의 특성맵을 시각화하기 위해 앞서 기존에 만든 model의 중간 부분만 뽑아오겠습니다. + +model의 Input Layer를 입력으로, model의 첫번째 Conv층을 출력으로 지정해서 새로운 모델을 생성했습니다. + + + +
+ + + +conv_acti에 임의로 하나의 데이터를 입력해서 특성맵을 뽑아보았습니다. + + + + +```python +from tensorflow.keras.models import Model + +conv_acti = Model(model.input, model.layers[0].output) + +inputs = X_train[0:1].reshape(-1, 28, 28, 1) / 255.0 # X_train의 (1, 28, 28, 1) +feature_map = conv_acti.predict(inputs) + +fig, axs = plt.subplots(4, 8, figsize=(15, 8)) +for i in range(4): + for j in range(8): + axs[i, j].imshow(feature_map[0, :, :, i * 8 + j]) + axs[i, j].axis('off') +plt.show() +``` + + + +##### 두 번째 특성 맵 시각화 + + + +첫 번째 특성 맵을 시각화할때 사용한 input을 그대로 사용해서 두 번째 합성곱층의 특성 맵을 시각화해보았습니다. + +두 번째 합성곱 층은 아래의 결과를 보았을 때, 어떤 부분을 학습하는 지 유추하기 어렵습니다. + + + +```python +conv_acti2 = Model(model.input, model.layers[2].output) +feature_map = conv_acti2.predict(inputs) + +fig, axs = plt.subplots(8, 8, figsize=(15, 8)) +for i in range(8): + for j in range(8): + axs[i, j].imshow(feature_map[0, :, :, i * 8 + j]) + axs[i, j].axis('off') +plt.show() +``` + + + +따라서, 낮은 층에서 저수준 특성(눈에 보이는 확실한 패턴)을 학습하고, 층이 깊어질수록 고수준 특성(추상적인 패턴)을 + +학습함을 알 수 있습니다. + diff --git "a/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235(CNN, Fashion MNIST \353\266\204\353\245\230).md" "b/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235(CNN, Fashion MNIST \353\266\204\353\245\230).md" new file mode 100644 index 000000000000..530727f33396 --- /dev/null +++ "b/_posts/2022-02-04-\355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235(CNN, Fashion MNIST \353\266\204\353\245\230).md" @@ -0,0 +1,431 @@ +--- +layout: single +title: "합성곱 신경망(CNN, Fasion MNIST 분류)" +categories: 딥러닝 +tag: [python, 파이썬, keras, CNN, 합성곱, Fashion MNIST, 분류, 딥러닝] +toc: true +toc_sticky: true + +--- + + + + + + +#### CNN을 활용한 Fashion MNIST 예측 + + + +
+ + + +이전에 다층 퍼셉트론을 이용하여 Fashion MNIST를 예측해 보았는데요. + +이번엔 이미지 데이터에 효과적인 CNN(컨볼루션 층 + 풀링 층)을 공부해 보았으니 + +CNN을 활용하여 Fashion MNIST를 예측하는 모델을 구성해보겠습니다. + + +이전과 동일하게 케라스에서 제공하는 Fashion MNIST 데이터를 불러오고, + +X데이터를 픽셀값 255로 나눠줌으로써 각 값들이 0 ~ 1사이의 값을 가질 수 있도록 만듭니다. + +또한, CNN을 공부할때, 입력되는 이미지 데이터는 (높이, 너비, 깊이) 형태인 것을 알 수 있었습니다. + +깊이는 이미지 데이터의 채널을 뜻하며, 흑백은 1, 컬러는 3이었죠? + +Fashion MNIST 데이터는 흑백 이미지이기 때문에 numpy의 reshape함수를 사용하여 깊이 차원을 추가해줍니다. + +그리고 모델 학습 시 과적합 여부를 확인하기 위해 훈련 데이터셋과 검증 데이터셋으로 나눕니다. + + + +```python +from tensorflow.keras.datasets import fashion_mnist +from sklearn.model_selection import train_test_split + +# 데이터 불러오기 +(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data() + +# X데이터를 0 ~ 1 값을 가질 수 있도록 맞춰주기 +X_train = X_train / 255.0 +X_test = X_test / 255.0 + +# 이미지 데이터에 깊이 차원을 만들어주기 +X_train = X_train.reshape(-1, 28, 28, 1) +X_test = X_test.reshape(-1, 28, 28, 1) + +# 검증 데이터셋 분리 +X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, + test_size=0.2, random_state=42) + +# 입력 데이터의 크기 확인 +X_train.shape, X_val.shape, X_test.shape +``` + +
+((48000, 28, 28, 1), (12000, 28, 28, 1), (10000, 28, 28, 1))
+
+#### 모델 구성 + + + +```python +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout + +model = Sequential() + +# 첫번째 합성곱 층 +model.add(Conv2D(32, kernel_size=3, activation='relu', padding='same', input_shape=(28,28,1))) +model.add(MaxPooling2D(2)) + +# 두번째 합성곱 층 +model.add(Conv2D(64, kernel_size=3, activation='relu', padding='same')) +model.add(MaxPooling2D(2)) + +# 완전 연결층 +model.add(Flatten()) +model.add(Dense(100, activation='relu')) +model.add(Dropout(0.4)) +model.add(Dense(10, activation='softmax')) # 10개의 클래스 중 택1, 10개의 확률을 얻기위해 softmax 사용 +``` + +첫번째 컨볼루션 층에서는 32개의 커널을 사용, 커널의 사이즈는 (3,3,1)이며, 활성화 함수는 relu를 사용하겠습니다. + +(입력 데이터의 채널이 1이므로 커널의 채널도 1이 됩니다. 만약 입력 데이터가 컬러이면 채널은 3이 되겠습니다.). + +same 패딩을 사용할 것이고, 입력 사이즈는 배치 차원없이 (28, 28, 1)이 됩니다. + +그럼 출력되는 특성 맵은 (28, 28, 32) 크기가 됩니다. + + + +
+ + + +특성 맵을 맥스 풀링을 해줍니다. 이때 풀링에 사용되는 커널은 2x2사이즈로 해서 절반으로 줄여줍니다. + +최종적으로 첫번째 (컨볼루션 + 풀링)층에서 나오는 특성 맵의 크기는 (14, 14, 32)가 됩니다. + + + +
+ + + +두 번째 합성곱 층에선 64개의 필터를 사용했습니다. + +동일한 커널 사이즈와 활성화 함수 패딩을 사용했으므로 나오는 특성 맵의 크기는 (14, 14, 64)가 됩니다. + +동일하게 맥스 풀링을 통과하면 특성 맵의 크기는 최종적으로 (7, 7, 64)가 됩니다. + + + +
+ + + +그 다음엔 Dense층을 놓고 클래스 개수에 맞는 10개의 확률값을 얻어야하기 때문에 Flatten()을 사용하여 + +(7, 7, 64) 특성 맵을 1차원 배열로 만들어줍니다. + + + +
+ + + +첫 번째 Dense층에서 활성화 함수 relu를 사용하는 뉴런 100개를 은닉층으로 두었습니다. + +3136개의 입력이 100개의 뉴런에 완전 연결이 되었으므로 굉장히 많은 가중치가 생성될 거 같네요. + +그래서 과적합을 피해보기 위해 은닉층 뒤에 Dropout을 사용해서 훈련 시에 40%의 뉴런을 끄도록 지정해 보았습니다. + +최종 출력층에는 10개의 출력을 가지고 softmax를 사용해야 10개의 확률을 얻을 수 있습니다. + + +#### 모델 summary + +각 층마다 출력되는 특성 맵과 출력 데이터의 크기와 파라미터 개수는 summary()함수를 통해 다시 한 번 확인해봅니다. + + + +```python +model.summary() +``` + +
+Model: "sequential"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ conv2d (Conv2D)             (None, 28, 28, 32)        320       
+                                                                 
+ max_pooling2d (MaxPooling2D  (None, 14, 14, 32)       0         
+ )                                                               
+                                                                 
+ conv2d_1 (Conv2D)           (None, 14, 14, 64)        18496     
+                                                                 
+ max_pooling2d_1 (MaxPooling  (None, 7, 7, 64)         0         
+ 2D)                                                             
+                                                                 
+ flatten (Flatten)           (None, 3136)              0         
+                                                                 
+ dense (Dense)               (None, 100)               313700    
+                                                                 
+ dropout (Dropout)           (None, 100)               0         
+                                                                 
+ dense_1 (Dense)             (None, 10)                1010      
+                                                                 
+=================================================================
+Total params: 333,526
+Trainable params: 333,526
+Non-trainable params: 0
+_________________________________________________________________
+
+summary 내용을 확인해 보았을 때, 첫번째 Dense층의 100개의 뉴런이 Flatten 층에서 나온 3136개의 입력 배열과 + +완전 연결이 되었으므로 굉장히 많은 가중치가 생긴 걸 확인할 수 있네요. + +그 위에 있는 합성곱층 2개의 가중치를 모두 더한것보다 훨씬 많은 것을 확인할 수 있는데요. + +이 점을 보았을 때 완전 연결층은 과적합이 쉽게 나타날 수 있고 + +반대로, 합성곱 층은 적은 개수의 파라미터로 효과적으로 이미지의 특징을 잘 잡아낼 수 있는 거 같습니다. + + +#### plot_model + +keras에는 plot_model()이라는 라이브러리가 있습니다. + +모델 구성 정보에 대한, summary()함수로 확인할 수 있는 정보들을 시각화해주는 라이브러리입니다. + +show_shapes=True로 주면 각 층의 input shape과 output shape을 나타내줍니다. + + + +```python +from tensorflow.keras.utils import plot_model + +plot_model(model, show_shapes=True) +``` + + + +#### 모델 컴파일 및 훈련 + +옵티마이저는 'adam'을 사용했고, y데이터를 원 핫 인코딩 하지않고 그대로 사용하기 위해 + +손실 함수를 'sparse_categorical_crossentropy'로 지정했습니다. + + + +```python +# 모델 컴파일 +model.compile(optimizer='adam', + loss='sparse_categorical_crossentropy', + metrics=['acc']) +``` + +체크 포인트를 models 폴더 안에 'fashion_mnist_cnn_model.h5'로 지정하고 + +검증 셋의 점수가 2회 이상 증가했을 때 조기종료를 하고, 가장 손실이 낮았던 곳으로 되돌리기 위해 콜백을 지정했습니다. + + + +```python +# 모델 훈련 +from tensorflow.keras import callbacks +import os + +# models라는 폴더에 모델(h5파일)을 저장하려는데 해당 폴더가 없으면 만들어주기 +if not os.path.exists('./models/'): + os.mkdir('./models/') + +checkpoint_ch = callbacks.ModelCheckpoint('./models/fasion_mnist_cnn_model.h5') + +early_stopping_cb = callbacks.EarlyStopping(patience=2, restore_best_weights=True) + +history = model.fit(X_train, y_train, verbose=0, + epochs=20, validation_data=(X_val, y_val), + callbacks=[checkpoint_ch, early_stopping_cb]) +``` + +#### 훈련 시각화 + +훈련 셋과 검증 셋의 정확도와 손실을 시각화 해보겠습니다. + +아래와 같이 8번째 epoch(0부터)에서 훈련이 멈췄고 patience를 2로 주었기 때문에 + +6번째 에포크에서 가장 낮은 검증 손실을 얻을 수 있다고 확인할 수 있습니다. + +이 이후에는 검증 셋의 손실이 올라가기 때문에 과적합이 존재한다고 볼 수 있습니다. + + + +```python +import matplotlib.pyplot as plt + +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() +``` + +
+
+
+ + +#### 모델 평가와 예측 + + + +```python +model.evaluate(X_val, y_val) +``` + +
+375/375 [==============================] - 1s 3ms/step - loss: 0.2228 - acc: 0.9231
+
+
+[0.22275471687316895, 0.9230833053588867]
+
+evaluate 메소드를 사용해서 이 모델을 검증 데이터로 평가해보면 + +손실값은 약 0.22 정도 나오고, 정확도는 0.92정도가 나옵니다. + + + +
+ + + +이미지 하나를 28x28로 reshape 해서 이미지를 출력해보면 아래와 같은 가방 이미지가 출력됩니다. + +그리고 predict 메소드를 사용해서 각 10개의 카테고리에 포함될 10개의 확률을 확인 할 수 있습니다. + +9번째 확률값이 제일 높은 1이므로, 이 이미지는 카테고리 9에 해당하는 데이터라고 예측 됨을 확인 할 수 있습니다. + + + +```python +plt.imshow(X_val[0].reshape(28, 28), cmap='gray') +plt.show() + +preds = model.predict(X_val[0:1]) +print(preds) +``` + + + +
+[[2.5790641e-21 1.0722967e-27 1.9750217e-24 1.0985332e-21 5.8698841e-18
+  2.0373612e-21 2.8928411e-18 3.8926373e-19 1.0000000e+00 3.8500301e-20]]
+
+이번에는 테스트 데이터를 evaluate 메소드를 통해 예측을 해보면 결과는 검증 셋보다 + +약간 더 높은 0.25 정도의 손실값과 약 0.91의 정확도가 나오는 것을 확인 할 수 있습니다. + + + +```python +model.evaluate(X_test, y_test) +``` + +
+313/313 [==============================] - 1s 4ms/step - loss: 0.2519 - acc: 0.9155
+
+
+[0.2519080638885498, 0.9154999852180481]
+
\ No newline at end of file diff --git "a/_posts/2022-02-07-IMDB \352\270\215\354\240\225 \354\227\254\353\266\200 \354\230\210\354\270\241(RNN, Embedding).md" "b/_posts/2022-02-07-IMDB \352\270\215\354\240\225 \354\227\254\353\266\200 \354\230\210\354\270\241(RNN, Embedding).md" new file mode 100644 index 000000000000..4b019e78d05d --- /dev/null +++ "b/_posts/2022-02-07-IMDB \352\270\215\354\240\225 \354\227\254\353\266\200 \354\230\210\354\270\241(RNN, Embedding).md" @@ -0,0 +1,627 @@ +--- +layout: single +title: "IMDB 긍정 여부 분류 (RNN, Embedding)" +categories: 딥러닝 +tag: [python, 파이썬, keras, 딥러닝, imdb, RNN, 시퀀스 패딩, Embedding, 예측] +toc: true +toc_sticky: true + +--- + + + + + + +#### IMDB 영화 리뷰 긍정 여부 예측 모델 학습 + +총 25000개의 샘플이 존재하며, 각 샘플은 영화 리뷰 한 건을 의미합니다. + +데이터셋은 이미 정수로 인코딩되어 있고, 정수값은 단어의 빈도수를 나타냅니다. + + + +
+ + + ++ imdb.load_data()의 인자로 num_words : 단어의 등장 빈도 순위로 몇 등까지 사용할 것인지를 의미합니다. + + num_words를 10000으로 설정하여 단어의 등장 빈도 순위가 10000을 넘는 단어는 보이지 않게 해서 데이터셋을 + + 좀 더 간단하게 표현하기 위해 사용합니다. + + 즉, 이 데이터에 사용할 단어 사전에 10000개의 단어를 사용합니다. + + + +```python +from tensorflow.keras.datasets import imdb +import matplotlib.pyplot as plt +import numpy as np + +num_word = 500 + +(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_word) + +X_train.shape, y_train.shape +``` + +
+((25000,), (25000,))
+
+X_train의 샘플을 확인해보면 각 단어의 빈도 순위가 정수형으로 나타나 있는걸 확인할 수 있습니다. + + + +```python +print(X_train[0]) +``` + +
+[1, 14, 22, 16, 43, 2, 2, 2, 2, 65, 458, 2, 66, 2, 4, 173, 36, 256, 5, 25, 100, 43, 2, 112, 50, 2, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 2, 2, 17, 2, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2, 19, 14, 22, 4, 2, 2, 469, 4, 22, 71, 87, 12, 16, 43, 2, 38, 76, 15, 13, 2, 4, 22, 17, 2, 17, 12, 16, 2, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2, 2, 16, 480, 66, 2, 33, 4, 130, 12, 16, 38, 2, 5, 25, 124, 51, 36, 135, 48, 25, 2, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 2, 15, 256, 4, 2, 7, 2, 5, 2, 36, 71, 43, 2, 476, 26, 400, 317, 46, 7, 4, 2, 2, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2, 56, 26, 141, 6, 194, 2, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 2, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 2, 88, 12, 16, 283, 5, 16, 2, 113, 103, 32, 15, 16, 2, 19, 178, 32]
+
+이 데이터 셋은 리뷰의 긍정여부를 나타내기 때문에 y값은 0과 1 두개의 값만 가지는 것을 확인할 수 있습니다. + + + +```python +print(np.unique(y_train)) +``` + +
+[0 1]
+
+이 데이터는 토큰화와 정수 인코딩이라는 텍스트 전처리가 완료된 상태입니다. + +다음에 시퀀스 패딩을 사용하기 위해 적절한 리뷰의 길이 즉, 토큰의 길이와 그에 따른 빈도 수를 확인해봅니다. + + + +
+ + + +대체적으로 1000이하의 길이를 가지며, 100 ~ 500정도의 길이를 가진 데이터가 많은 것을 확인할 수 있습니다. + + + +```python +from sklearn.model_selection import train_test_split + +X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, + test_size=0.2, random_state=42) + +length = np.array([len(x) for x in X_train]) +print(f"X_train의 평균 : {np.mean(length)}\nX_train의 중간값 : {np.median(length)}") + +plt.hist(length) +plt.xlabel('length') +plt.ylabel('frequency') +plt.show() +``` + +
+X_train의 평균 : 239.00925
+X_train의 중간값 : 178.0
+
+ + +#### 시퀀스 패딩 + ++ 서로 다른 개수의 단어로 이루어진 문장을 같은 길이로 만들어주기 위해 패딩을 사용합니다. + ++ 패딩을 사용하기 위해서 tensorflow.keras.preprocessing.sequence 모듈의 pad_sequences함수를 사용합니다. + ++ pad_sequences 함수는 숫자 0을 이용해서 같은 길이의 시퀀스로 변환합니다. + + + +
+ + + +###### padding 파라미터 + ++ 'post' : 시퀀스의 뒤에 패딩이 채워집니다. 디폴트는 'pre'입니다. + ++ maxlen 파라미터 + + + 시퀀스의 최대 길이를 제한합니다. + ++ truncating 파라미터 + + + 최대 길이를 넘는 시퀀스를 잘라낼 위치를 지정합니다. + + + 'post'로 지정하면 뒷부분을 잘라냅니다. + + + +
+ + + +pad_sequences()의 인자 maxlen을 통해 패딩할 길이를 설정합니다. + +위에서 데이터의 토큰 길이를 시각화해보고 100이 적절하다고 생각하여 maxlen을 100으로 설정합니다. + + + +```python +from tensorflow.keras.preprocessing.sequence import pad_sequences + +max_len = 100 + +X_train_seq = pad_sequences(X_train, maxlen=max_len) +X_val_seq = pad_sequences(X_val, maxlen=max_len) + +X_train_seq.shape, X_val_seq.shape +``` + +
+((20000, 100), (5000, 100))
+
+#### 원 핫 인코딩 + +단어 집합의 크길르 벡터 차원으로 만들어줍니다. + +표현하고 싶은 단어의 인덱스에 1의 값을 부여하고, 나머지는 0을 부여하는 벡터 표현 방식입니다. + + + +```python +from tensorflow import keras + +X_train_seq = keras.utils.to_categorical(X_train_seq) +X_val_seq = keras.utils.to_categorical(X_val_seq) + +X_train_seq.shape, X_val_seq.shape +``` + +
+((20000, 100, 500), (5000, 100, 500))
+
+#### 순환 신경망 모델 만들기 + + + +```python +model = keras.Sequential() + +model.add(keras.layers.SimpleRNN(8, input_shape=(100, 500))) +model.add(keras.layers.Dense(1, activation='sigmoid')) +``` + +단순 순환 신경망 하나로 이루어진 간단한 모델입니다. + +은닉층 크기는 8, 입력 크기는 원 핫 인코딩을 끝낸 벡터의 차원을 입력해서 SimpleRNN을 사용합니다. + +RNN층 다음에 Dense층을 사용할 때는 합성곱층과 달리 Flatten층을 사용할 필요가 없습니다. + +Dense층은 긍정/부정 두가지 레이블을 판별하므로 sigmoid를 사용했습니다. + + + +```python +model.summary() +``` + +
+Model: "sequential"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ simple_rnn (SimpleRNN)      (None, 8)                 4072      
+                                                                 
+ dense (Dense)               (None, 1)                 9         
+                                                                 
+=================================================================
+Total params: 4,081
+Trainable params: 4,081
+Non-trainable params: 0
+_________________________________________________________________
+
+순환신경망의 출력 벡터는 입력 벡터의 크기와 동일하고, 8개의 뉴런과 500개의 원핫 인코딩 입력이 완전 연결되므로 500 x 8, + +은닉 상태에서 8개의 뉴런이 완전 연결되도록 순환하므로 8 x 8, 8개의 절편이 존재하므로 +8이 되어 4072개가 됩니다. + +Dense층에서 8 x 1 + 1이므로 9개가 되어 총 4081개의 파라미터를 확인 할 수 있습니다. + + + + +```python +rmsprop = keras.optimizers.RMSprop(learning_rate=1e-4) + +model.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) +``` + + +```python +checkpoint = keras.callbacks.ModelCheckpoint('./models/imdb-simplernn-model.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, + restore_best_weights=True) + +history = model.fit(X_train_seq, y_train, epochs=100, batch_size=64, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() + +model.evaluate(X_val_seq, y_val) +``` + +
+157/157 [==============================] - 2s 13ms/step - loss: 0.4702 - acc: 0.7810
+
+
+[0.47018691897392273, 0.781000018119812]
+
+ + +단순히 SimpleRNN 하나의 층만을 사용해서 약 0.78 정도의 정확도를 얻을 수 있었습니다. + +결과를 시각화해보면 40번째 epoch에서 과적합이 심해져 조기 종료되었음을 확인 할 수 있습니다. + + + +
+ + + +원 핫 인코딩을 사용해서 입력 데이터를 준비한다면, 단어 사전을 유연하게 늘리기가 어렵습니다. + +단어 사전이 증가할수록 또는 토큰의 개수가 늘어날수록 벡터 차원의 개수가 매우 많이 늘어나기 때문입니다. + +또한, 원 핫 인코딩은 하나의 벡터 원소만 1이고 나머진 0으로 채워지기 때문에 각 토큰 사이의 관련성을 알기 어렵습니다. + +이에 대비해서 임베딩 방법이 존재합니다. + +임베딩은 토큰들을 지정된 갯수의 실수 벡터 즉, 밀집 벡터로 변환해줍니다. + +원 핫 인코딩에 비해 단어 사이에 의미 있는 정보를 얻을 수 있는 방법입니다. + +임베딩을 사용하여 두번째 모델을 만들어 보겠습니다. + + + +
+ + + +Embedding() + ++ 단어를 밀집 벡터로 만드는 작업을 워드 임베딩(word embedding)이라고 합니다. + ++ 원-핫 인코딩과 상대적으로 저차원을 가지며 모든 원소의 값이 실수입니다. + + + 첫번째 인자 : 단어 사전의 크기(총 단어의 개수) + + + 두번째 인자 : 임베딩 벡터의 출력 차원(결과로 나오는 임베딩 벡터의 크기) + + 만약, embedding층과 연결된 층이 순환신경망이면 사용하지 않습니다. + + + input_length : time step의 길이(입력 시퀀스의 길이) + + 만약, 다음에 Flatten층이 오게 되면 반드시 input_length를 명시해주어야 합니다. + + + +```python +model2 = keras.Sequential() + +model2.add(keras.layers.Embedding(500, 16, input_length=100)) +model2.add(keras.layers.SimpleRNN(8)) +model2.add(keras.layers.Dense(1, activation='sigmoid')) + +model2.summary() +``` + +
+Model: "sequential_1"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ embedding (Embedding)       (None, 100, 16)           8000      
+                                                                 
+ simple_rnn_1 (SimpleRNN)    (None, 8)                 200       
+                                                                 
+ dense_1 (Dense)             (None, 1)                 9         
+                                                                 
+=================================================================
+Total params: 8,209
+Trainable params: 8,209
+Non-trainable params: 0
+_________________________________________________________________
+
+500개의 입력데이터가 Embedding층을 통과하면 16개의 벡터 크기로 출력됩니다. + +그러므로 SimpleRNN층에서 처리하는 벡터의 갯수가 훨씬 줄어들게 됩니다. + +input_length를 100으로 지정해서 입력 토큰 즉, time step의 갯수를 지정해줍니다. + + + +
+ + + +summary의 결과입니다. + +Embedding층에서 500개의 입력 데이터와 16개의 뉴런이 완전 연결되어 + +100 x 16개의 파라미터가 사용되고, 16개의 출력 벡터가 나옵니다. + +SimpleRNN층에서 16개의 입력 벡터와 8개의 뉴런이 완전 연결되어 16 x 8, + +다시 순환하여 8 x 8, 8개의 절편을 포함하여 총 200개의 파라미터가 사용되고, + +마지막 Dense층에서 파라미터의 개수가 8 x 1 + 1이 됨을 확인할 수 있습니다. + + + +```python +max_len = 100 + +X_train_seq = pad_sequences(X_train, maxlen=max_len) +X_val_seq = pad_sequences(X_val, maxlen=max_len) + +checkpoint = keras.callbacks.ModelCheckpoint('./models/imdb-embedding-simplernn-model.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, + restore_best_weights=True) +``` + + +```python +model2.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) + +history2 = model2.fit(X_train_seq, y_train, epochs=100, batch_size=64, verbose=0, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +model2.evaluate(X_val_seq, y_val) +``` + +
+157/157 [==============================] - 0s 3ms/step - loss: 0.4535 - acc: 0.7884
+
+
+[0.4534836411476135, 0.7883999943733215]
+
+ +```python +loss2 = history2.history['loss'] +val_loss2 = history2.history['val_loss'] +loss = history2.history['loss'] +val_loss = history2.history['val_loss'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('Model1 loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, loss2, color='green', label='train_acc') +ax2.plot(epochs, val_loss2, color='red', label='val_acc') +ax2.set_title('Model2 loss') +ax2.set_xlabel('epochs') +ax2.set_ylabel('loss') +ax2.legend() +``` + +
+
+
+ + +위에서 데이터를 간소화하기 위해 단어의 갯수를 500개로 제한하고, 패딩의 길이를 100으로 설정했습니다. + +임베딩의 효과를 더 보기 위해 이번엔 단어의 갯수를 10000개로 늘리고 패딩의 길이를 500으로 설정하여 + +모델을 구성해보겠습니다. + + + +```python +# 데이터 불러오기, 단어 사전의 길이를 10000개로 지정 +num_word = 10000 + +(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_word) +``` + + +```python +# 시퀀스 패딩하기 +X_train_seq = pad_sequences(X_train, maxlen=500) +X_test_seq = pad_sequences(X_test, maxlen=500) + +# 검증 셋 분리 +X_train_seq, X_val_seq, y_train, y_val = train_test_split(X_train_seq, y_train) + +X_train_seq.shape, X_val_seq.shape +``` + +
+((18750, 500), (6250, 500))
+
+ +```python +# 모델 정의 및 컴파일 +model = keras.Sequential() + +model.add(keras.layers.Embedding(10000, 16, input_length=500)) +model.add(keras.layers.SimpleRNN(8)) +model.add(keras.layers.Dense(1, activation='sigmoid')) + +model.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) +``` + + +```python +# 콜백, 모델 학습 +checkpoint = keras.callbacks.ModelCheckpoint('./models/imdb10000-simplernn-embedding.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True) + +history = model.fit(X_train_seq, y_train, epochs=100, batch_size=64, verbose=0, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +# 손실과 정확도 시각화 +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() +``` + +
+
+
+ + + +```python +# 모델 평가 +model.evaluate(X_test_seq, y_test) +``` + +
+782/782 [==============================] - 9s 11ms/step - loss: 0.3963 - acc: 0.8402
+
+
+[0.39633744955062866, 0.8401600122451782]
+
+모델 학습 과정에서 손실과 정확도를 시각화해보면 검증 셋에서 약 0.84정도의 정확도를 얻었습니다. + +epoch가 약 30에서 과적합이 심해져 조기 종료 되었음을 확인 할 수 있습니다. + +테스트 데이터에 모델을 적용한 결과 약 0.84의 정확도의 나쁘지 않은 결과를 얻을 수 있었습니다. + diff --git "a/_posts/2022-02-12-LSTM, GRU(imdb \354\230\210\354\270\241).md" "b/_posts/2022-02-12-LSTM, GRU(imdb \354\230\210\354\270\241).md" new file mode 100644 index 000000000000..48f6ebdf29b3 --- /dev/null +++ "b/_posts/2022-02-12-LSTM, GRU(imdb \354\230\210\354\270\241).md" @@ -0,0 +1,625 @@ +--- +layout: single +title: "LSTM과 GRU를 사용한 IMDB 분류" +categories: 딥러닝 +tag: [python, 파이썬, 딥러닝, 순환신경망, LSTM, GRU, IMDB] +toc: true +toc_sticky: true + +--- + + + + + + +#### LSTM + + + +RNN은 관련 정보와 그 정보를 사용하는 지점 사이 거리가 멀 경우 역전파시 그래디언트가 점차 줄어 학습능력이 떨어진다고 알려져 있습니다. (vanishing gradient problem) + +이 문제를 보완하기 위해 LSTM이 등장합니다. + + + +LSTM(Long Short Term Memory)는 기존의 RNN이 출력과 먼 위치에 있는 정보를 기억할 수 없다는 단점을 보완한 방법입니다. + +장기 / 단기 기억을 가능하게 설계한 신경망의 구조입니다. + +주로 시계열, 자연어 처리에 사용됩니다. + + + +
+ + + +#### LSTM의 구조 + + + +LSTM은 RNN과 다르게 한 개의 tanh layer가 아닌 4개의 layer로 구성되어 서로 정보를 주고 받는 방식입니다. + +또한, LSTM 셀에서는 상태가 크게 두 가지의 상태가 순환합니다. + +RNN의 은닉 상태(hidden state)에 셀 상태(cell state)가 추가됩니다. + +LSTM의 출력으로 사용되는 것은 은닉 상태, 셀 상태는 셀 안에서 순환하는 상태입니다. + + + +![LSTM구조](/assets/images/LSTM구조.png) + +<이미지 출처 : https://imgur.com/jKodJ1u> + + + +여기서 LSTM 모듈에는 4개의 layer가 존재하는 것을 알 수 있습니다. + + + +
+ + + +#### LSTM 과정 + + + +![LSTM순전파](/assets/images/LSTM기호.png) + +노란색 박스는 학습된 neural network layer이고, 분홍색 동그라미는 vector 연산과 같은 pointwise operation을 나타냅니다. + +합쳐지는 선은 concatenateion을 의미하고, 갈라지는 선은 정보를 복사해서 다른쪽으로 보내는 fork입니다. + + + +
+ + + +![LSTM순전파](/assets/images/LSTM_cell상태.png) + + + +Cell state는 모듈 상단에 수평으로 그어진 윗 선에 해당됩니다. + +Cell state는 컨베이어 벨트와 같이, 정보가 전혀 바뀌지 않고 그대로 흐르게만 하는 역할을 합니다. + +LSTM은 Cell state에 뭔가를 더하거나 없애는 과정을 반복합니다. 이 과정에서 3가지의 gate를 사용합니다. + + + +
+ + + +![LSTM순전파](/assets/images/LSTM_forget게이트.png) + + + +LSTM의 첫 단계로 Cell state로부터 어떤 정보를 버릴 것인지 정하는 forget gate 입니다. + +ht-1과 xt를 받아 시그모이드를 취해(0 ~ 1값) ct-1에 보내줍니다. + +이 값이 1이면 "모든 정보 전달", "0이면 모두 버리기"가 됩니다. + + + +
+ + + +![LSTM순전파](/assets/images/LSTM_input게이트.png) + + + +다음 단계는 입력되는 새로운 정보 중 어떤 것을 Cell state에 저장할 것인지 정하는 input gate 입니다. + +먼저 sigmoid layer가 어떤 값을 업데이트할 지 정하고, 그 다음에 tanh layer가 새로운 후보 값 c~t라는 vector를 만들고 Cell state에 더할 준비를 합니다. + +이렇게 두 단계에서 나온 정보를 합쳐서 state에 업데이트할 준비를 합니다. + + + +
+ + + +![LSTM순전파](/assets/images/LSTM_cell_update.png) + + + +이전 state인 ct-1에 ft를 곱해서 forget gate에서 잊어버리기로 정했던 정보들을 모두 잊어버립니다. + +그리고나서 it x c~t를 더해줍니다. 이 더한 값은 두번째 단계에서 업데이트하기로 한 값을 얼마나 업데이트할 지 정한 만큼 scale한 값이 됩니다. + + + +
+ + + +![LSTM순전파](/assets/images/LSTM_output게이트.png) + + + +마지막으로 출력으로 내보내는 output gate 입니다. + +먼저, sigmoid layer에 input 데이터를 넣어서 Cell state의 어느 부분을 ouput으로 보낼지 정합니다. + +그리고 Cell state를 tanh layer에 전달해서 -1과 1사이의 값을 받은 뒤에 방금 전의 sigmoid layer의 output과 곱합니다. + +그 후, ouput으로 보내게 됩니다. + + +#### GRU 셀 + +GRU 셀은 LSTM 셀에서 좀 더 간소화된 구조라고 말할 수 있습니다. + +LSTM에 비해 Gate가 2개이며 reset gate(r)와 update gate(z)로 이루어집니다. + ++ reset gate는 이전 상태를 얼마나 잊어버릴지를 결정합니다. + ++ update gate는 이전 상태와 현재 상태를 얼마만큼의 비율로 반영할지를 결정합니다. + + + +LSTM 셀에 존재하는 cell state와 hidden state가 하나로 합쳐집니다. + + + +![GRU](/assets/images/GRU셀.png) + + + +Input + +이전 시점의 셀에서 전달된 hidden state(h(t-1))와 새로운 input값인 x(t)가 합쳐지고 두 방향으로 나뉘어 전달됩니다. + +하나는 게이트에 전달될 정보가 되고, 다른 하나는 LSTM의 Candidate state의 역할을 합니다. + + + +reset gate + +이전 상태의 은닉 상태와 현재 상태의 x를 받아 sigmoid처리를 합니다. + +candidate state(h_hat(t))에 전달되는 데이터에 어떤 정보를 지우고, 어떤 정보를 전달할지 결정합니다. + + + +update gate + +이전 상태의 은닉 상태와 현재 상태의 x를 받아 sigmoid처리를 합니다. + +LSTM 셀의 forget과 input 게이트와 비슷한 역할을 하지만, Update 되는 정보의 양에 1이라는 제한이 있습니다. + +이전 정보인 h(t-1)과 reset gate를 지나온 candidate state(h_hat(t))에 동시에 전달되는데, + +이때 한쪽에 x의 크기가 전달되면, 반대쪽은 1-x만큼 전달됩니다. + +즉, 정보를 지운만큼만 새로운 정보를 입력하고, 새로운 정보를 입력한 만큼 정보를 지울 수 있습니다. + + + +candidate state + +현재 셀에 입력된 정보 중에서 Output과 다음 셀로 전달할 중요한 후보 정보를 담고 있는 state입니다. + +reset gate를 거친 정보들은 tanh함수를 취해 update gate까지 지나며 h(t-1)과 합쳐집니다. + + + +hidden state + +LSTM의 cell state의 역할까지 동시에 합니다. + +update gate를 통과하면서 의미 없는 데이터를 삭제하고 현재 셀의 중요한 정보를 담고 있는 candidate state와 + +합쳐져 output이 되고, 동시에 다음 시점의 셀로 정보를 전달합니다. + + +#### LSTM 신경망으로 IMDB 예측 + + + +이전에 SimpleRNN과 Embedding을 사용하여 예측했던 IMDB 데이터 분류를 LSTM을 사용하여 다시 분류해보겠습니다. + +데이터 처리 과정은 이전과 동일하게 수행하겠습니다. + + + +```python +from tensorflow import keras +import numpy as np +import matplotlib.pyplot as plt +from sklearn.model_selection import train_test_split +from tensorflow.keras.preprocessing.sequence import pad_sequences + +(X_train, y_train), (X_test, y_test) = keras.datasets.imdb.load_data(num_words=10000) + +X_train_seq = pad_sequences(X_train, maxlen=500) +X_test_seq = pad_sequences(X_test, maxlen=500) + +X_train_seq, X_val_seq, y_train, y_val = train_test_split(X_train_seq, y_train) + +X_train_seq.shape, X_val_seq.shape +``` + +
+((18750, 500), (6250, 500))
+
+ +```python +model = keras.Sequential() + +model.add(keras.layers.Embedding(10000, 16, input_length=500)) +model.add(keras.layers.LSTM(8)) +model.add(keras.layers.Dense(1, activation='sigmoid')) + +model.summary() +``` + +
+Model: "sequential_2"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ embedding_2 (Embedding)     (None, 500, 16)           160000    
+                                                                 
+ lstm_2 (LSTM)               (None, 8)                 800       
+                                                                 
+ dense_1 (Dense)             (None, 1)                 9         
+                                                                 
+=================================================================
+Total params: 160,809
+Trainable params: 160,809
+Non-trainable params: 0
+_________________________________________________________________
+
+summary 정보에서 파라미터 갯수를 확인해보면 embedding층에서는 10000 x 16개, + +LSTM층에서는 embedding층의 출력인 16이 입력이 되어 8개의 뉴런과 완전 연결되어 16 x 8, + +은닉 상태의 셀이 순환되어 8 x 8, 그리고 절편 8개를 포함하여 200개가 되는데 LSTM은 4개의 layer가 존재하므로 + +200 x 4 = 800이 되는 것을 확인할 수 있습니다. + + + +```python +rmsprop = keras.optimizers.RMSprop(learning_rate=1e-4) + +model.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) + +checkpoint = keras.callbacks.ModelCheckpoint('./models/imdb10000-lstm-model.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True) + +history = model.fit(X_train_seq, y_train, epochs=100, batch_size=64, verbose=0, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +model.evaluate(X_test_seq, y_test) +``` + +
+782/782 [==============================] - 13s 17ms/step - loss: 0.3348 - acc: 0.8679
+
+
+[0.33479073643684387, 0.8679199814796448]
+
+ +```python +# 손실과 정확도 시각화 +loss = history.history['loss'] +val_loss = history.history['val_loss'] +acc = history.history['acc'] +val_acc = history.history['val_acc'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, loss, color='blue', label='train_loss') +ax1.plot(epochs, val_loss, color='orange', label='val_loss') +ax1.set_title('train and val loss') +ax1.set_xlabel('epochs') +ax1.set_ylabel('loss') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, acc, color='green', label='train_acc') +ax2.plot(epochs, val_acc, color='red', label='val_acc') +ax2.set_title('train and val acc') +ax2.set_xlabel('epochs') +ax2.set_ylabel('acc') +ax2.legend() +``` + +
+
+
+ + +
+ +#### Dropout 추가 + + + +이전에 구성했던 모델을 좀 더 정확한 예측을 위해 신경망을 좀 더 깊게 수정하고 Dropout을 추가해보았습니다. + +LSTM층에서 다음 LSTM층을 쌓아 연결할때는, 각 타임 스텝의 은닉상태를 모두 출력해주어야 마지막에 있는 순환 셀이 제대로 동작할 것입니다. + +기본적으로 keras의 순환층은 마지막 타임 스텝의 은닉상태만 출력하기 때문에 모든 타임 스텝마다 은닉상태를 출력해주기 위해 return_sequences=True를 설정해주어야 합니다. + +LSTM에서 Dropout을 사용할 땐 따로 층을 추가하지 않고 매개변수로서 추가를 해줘야 합니다. + + + +```python +from tensorflow import keras +import numpy as np +import matplotlib.pyplot as plt +from sklearn.model_selection import train_test_split +from tensorflow.keras.preprocessing.sequence import pad_sequences + +(X_train, y_train), (X_test, y_test) = keras.datasets.imdb.load_data(num_words=10000) + +X_train_seq = pad_sequences(X_train, maxlen=500) +X_test_seq = pad_sequences(X_test, maxlen=500) + +X_train_seq, X_val_seq, y_train, y_val = train_test_split(X_train_seq, y_train) + +X_train_seq.shape, X_val_seq.shape +``` + +
+Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
+17465344/17464789 [==============================] - 0s 0us/step
+17473536/17464789 [==============================] - 0s 0us/step
+
+
+((18750, 500), (6250, 500))
+
+ +```python +model2 = keras.Sequential() + +model2.add(keras.layers.Embedding(10000, 16, input_length=500)) +model2.add(keras.layers.LSTM(8, dropout=0.3, return_sequences=True)) +model2.add(keras.layers.LSTM(8, dropout=0.3)) +model2.add(keras.layers.Dense(1, activation='sigmoid')) + +model2.summary() +``` + + +```python +rmsprop = keras.optimizers.RMSprop(learning_rate=1e-4) + +model2.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) + +checkpoint = keras.callbacks.ModelCheckpoint('/content/gdrive/MyDrive/models/imdb10000-lstm-model.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True) + +history = model2.fit(X_train_seq, y_train, epochs=100, batch_size=64, verbose=0, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +model2.evaluate(X_test_seq, y_test) +``` + +
+782/782 [==============================] - 52s 67ms/step - loss: 0.3029 - acc: 0.8813
+
+
+[0.302852600812912, 0.8813199996948242]
+
+ +```python +acc = history.history['acc'] +val_acc = history.history['val_acc'] +loss = history.history['loss'] +val_loss = history.history['val_loss'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, acc, color='blue', label='train_loss') +ax1.plot(epochs, val_acc, color='orange', label='val_loss') +ax1.set_title('train and val acc') +ax1.set_xlabel('epochs') +ax1.set_ylabel('acc') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, loss, color='green', label='train_acc') +ax2.plot(epochs, val_loss, color='red', label='val_acc') +ax2.set_title('train and val loss') +ax2.set_xlabel('epochs') +ax2.set_ylabel('loss') +ax2.legend() +``` + +
+
+
+ + +드롭아웃을 적용한 모델에서 훈련 데이터와 검증 데이터의 손실값 차이가 좀 더 적게 나타난 것을 확인할 수 있습니다. + +다음은 GRU셀을 이용해서 동일한 방법으로 모델을 구성해보았습니다. + + + +```python +model3 = keras.Sequential() + +model3.add(keras.layers.Embedding(10000, 16, input_length=500)) +model3.add(keras.layers.GRU(8, dropout=0.3, return_sequences=True)) +model3.add(keras.layers.GRU(8, dropout=0.3)) +model3.add(keras.layers.Dense(1, activation='sigmoid')) + +model3.summary() +``` + +
+Model: "sequential_3"
+_________________________________________________________________
+ Layer (type)                Output Shape              Param #   
+=================================================================
+ embedding_3 (Embedding)     (None, 500, 16)           160000    
+                                                                 
+ gru_2 (GRU)                 (None, 500, 8)            624       
+                                                                 
+ gru_3 (GRU)                 (None, 8)                 432       
+                                                                 
+ dense_3 (Dense)             (None, 1)                 9         
+                                                                 
+=================================================================
+Total params: 161,065
+Trainable params: 161,065
+Non-trainable params: 0
+_________________________________________________________________
+
+ +```python +model3.compile(optimizer=rmsprop, + loss='binary_crossentropy', + metrics=['acc']) + +checkpoint = keras.callbacks.ModelCheckpoint('/content/gdrive/MyDrive/models/imdb10000-gru-model.h5') +early_stopping = keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True) + +history2 = model3.fit(X_train_seq, y_train, epochs=100, batch_size=64, verbose=0, + validation_data=(X_val_seq, y_val), + callbacks=[checkpoint, early_stopping]) +``` + + +```python +model3.evaluate(X_test_seq, y_test) +``` + +
+782/782 [==============================] - 49s 63ms/step - loss: 0.3073 - acc: 0.8774
+
+
+[0.30730995535850525, 0.8773599863052368]
+
+ +```python +acc = history2.history['acc'] +val_acc = history2.history['val_acc'] +loss = history2.history['loss'] +val_loss = history2.history['val_loss'] + +epochs = range(1, len(loss) + 1) +fig = plt.figure(figsize=(10, 5)) + +ax1 = fig.add_subplot(1, 2, 1) +ax1.plot(epochs, acc, color='blue', label='train_loss') +ax1.plot(epochs, val_acc, color='orange', label='val_loss') +ax1.set_title('train and val acc') +ax1.set_xlabel('epochs') +ax1.set_ylabel('acc') +ax1.legend() + +ax2 = fig.add_subplot(1, 2, 2) +ax2.plot(epochs, loss, color='green', label='train_acc') +ax2.plot(epochs, val_loss, color='red', label='val_acc') +ax2.set_title('train and val loss') +ax2.set_xlabel('epochs') +ax2.set_ylabel('loss') +ax2.legend() +``` + +
+
+
+ + +IMDB 데이터셋을 분류할 때, LSTM 셀을 사용한 방법과 GRU 셀을 사용한 방법이 비슷한 정확도를 가질 수 있는 것을 확인했습니다. + +실제로 GRU 셀을 사용했을 때 학습시간이 덜 걸린 것을 확인할 수 있었습니다. \ No newline at end of file diff --git a/_posts/2022-09-10-ml01_K-Nearest Neighbors(KNN).md b/_posts/2022-09-10-ml01_K-Nearest Neighbors(KNN).md new file mode 100644 index 000000000000..452125d12ad1 --- /dev/null +++ b/_posts/2022-09-10-ml01_K-Nearest Neighbors(KNN).md @@ -0,0 +1,253 @@ +--- +layout: single +title: "K-Nearest Neighbors(KNN)" +categories: 머신러닝 +tag: [KNN, 머신러닝, python] +toc: true +toc_sticky: true + +--- + + + + + +## k-최근접 이웃 알고리즘이란? + +- 새로운 데이터 포인트와 가장 가까운 훈련 데이터셋의 데이터 포인트를 찾아 예측 +- **k 값에 따라 가까운 이웃의 수가 결정** +- **분류**와 **회귀**에 모두 사용 가능 + +![01](/assets/images/ml01/01.png) + +## 특징 + +- **k 값이 작을 수록** 모델의 **복잡도가 상대적으로 증가**.(noise 값에 민감) +- 반대로 **k 값이 커질수록** 모델의 **복잡도가 낮아진다.** +- 100개의 데이터를 학습하고 k를 100개로 설정하여 예측하면 **빈도가 가장 많은 클래스** 레이블로 분류 +- 이해하기 매우 쉬운 모델 +- 훈련 데이터 세트가 크면(특성,샘플의 수) 예측이 느려진다 +- 수백 개 이상의 많은 특성을 가진 데이터 세트와 특성 값 대부분이 0인 희소(sparse)한 데이터 세트에는 잘 동작하지 않는다 +- 거리를 측정하기 때문에 같은 scale을 같도록 **정규화** 필요 + +## 데이터 포인트(sample) 사이 거리 값 측정 방법 + +- 유클리디언 거리공식 (Euclidean Distance) + +![02](/assets/images/ml01/02.png) + +## scikit-learn 주요 매개변수 + +- metric : 유클리디언 거리 방식 +- n_neighbors : 이웃의 수 +- weight : 가중치 함수 + - uniform : 가중치를 동등하게 설정. + - distance : 가중치를 거리에 반비례하도록 설정 + +## KNN 알고리즘 직접 구현 + +### 과제 + +- 예측 데이터와 모든 학습 데이터(500개)와의 거리 계산 -> 유클리드 거리 계산 +- 계산된 모든 거리값 중 설정된 k값(k=5)만큼 가장 가까운 데이터 추출 +- 추출된 데이터의 비율 확인 후 예측 + +### 데이터 로딩 및 가공 + +```python +import pandas as pd + +data = pd.read_csv("./data/bmi_lbs.csv") +data['Weight(kg)'] = data['Weight(lbs)'] * 0.453592 # kg 단위로 변환 +``` + +### 학습 데이터 + +```python +X = data[['Height','Weight(kg)']] +y = data['Label'] +``` + +### 예측할 샘플 데이터 + +```python +sample_data = data.iloc[[30,110,150,433,498],[2,4]] +ground_truth = data.iloc[[30,110,150,433,498],0] +``` + +### KNN 함수 + +```python +# my_KNN +# 입력 변수 (예측할 데이터 샘플, k값) +def my_KNN(input_data, k): + # 카운터 딕셔너리 + from collections import Counter + + # 1. 모든 데이터와 input데이터 사이의 거리계산 + distance_list = [] + + for i in range(len(input_data)): + temp = (X - input_data.iloc[i]) ** 2 # X데이터 전체[키, 몸무게] - i번째 인풋[키, 몸무게] -> 결과 : [a제곱, b제곱] + distance = (temp.iloc[:, 0] + temp.iloc[:, 1])**0.5 # (키 + 몸무게) 의 제곱근 + + distance_list.append(distance) + distance_list = pd.Series(distance_list, index=input_data.index) # list -> series 변환, 크기 : 샘플데이터 갯수 X 500 + #print(distance_list) + + # 2. k값만큼 가장 가까운 거리의 데이터 추출 + k_neighbors = [] + + for i in range(len(input_data)): + input_i = distance_list.iloc[i] + temp = [] + for j in range(k): + # k개만큼 최솟값들 뽑기 + #idx = input_i[input_i == input_i.min()].index[0] + idx = input_i.idxmin() # 구한 최솟값의 인덱스 구하기 + temp.append(y.loc[idx]) + input_i.drop([idx], inplace=True) # 최솟값 중복 없애게 이번에 뽑은 최솟값은 제거해주기 + k_neighbors.append(temp) # k_neighbors -> 크기 : (샘플데이터 갯수 X k개의 최소거리 인덱스) + + #print(k_neighbor) + + # 3. 추출된 데이터의 비율 확인 후 예측 + output = [] + for nb in k_neighbors: + count = Counter(nb) # key : 결과, value: key값이 나온 갯수 + output.append(max(count,key=count.get)) + + output = pd.Series(output, index=input_data.index) # input값의 인덱스 유지하기 위해 series화 + return output +``` + +### 테스트 + +- 예측 + +```python +sample2 = data.iloc[[0,1,2,3,4],[2,4]] +my_KNN(sample2, 5) +``` + +``` +0 Obesity +1 Normal +2 Obesity +3 Overweight +4 Overweight +dtype: object +``` + +- 실제 정답 + +```python +y.iloc[[0,1,2,3,4]] +``` + +``` +0 Obesity +1 Normal +2 Obesity +3 Overweight +4 Overweight +Name: Label, dtype: object +``` + +- 예측 + +```python +sample3 = data.iloc[[12,16,19,21,31],[2,4]] +my_KNN(sample3, 5) +``` + +``` +12 Overweight +16 Extreme Obesity +19 Extreme Obesity +21 Extreme Obesity +31 Weak +dtype: object +``` + +- 실제 정답 + +```python +y.iloc[[12,16,19,21,31]] +``` + +``` +12 Overweight +16 Extreme Obesity +19 Extreme Obesity +21 Extreme Obesity +31 Weak +Name: Label, dtype: object +``` \ No newline at end of file diff --git "a/_posts/2022-09-15-ml02_\353\215\260\354\235\264\355\204\260 \354\212\244\354\274\200\354\235\274\353\247\201.md" "b/_posts/2022-09-15-ml02_\353\215\260\354\235\264\355\204\260 \354\212\244\354\274\200\354\235\274\353\247\201.md" new file mode 100644 index 000000000000..c98bc02266b3 --- /dev/null +++ "b/_posts/2022-09-15-ml02_\353\215\260\354\235\264\355\204\260 \354\212\244\354\274\200\354\235\274\353\247\201.md" @@ -0,0 +1,121 @@ +--- +layout: single +title: "데이터 스케일링(Data Scaling)" +categories: 머신러닝 +tag: [KNN, 머신러닝, python, 스케일링, Scaling] +toc: true +toc_sticky: true + +--- + + + + + + +## 2. 데이터 스케일링이란? + +- **특성(Feature)들의 범위(range)를 정규화** 해주는 작업 +- 특성마다 다른 범위를 가지는 경우 머신러닝 모델들이 제대로 학습되지 않을 가능성이 있다. +(KNN, SVM, Neural network 모델, Clustering 모델 등) + +![01.png](/assets/images/ml02/01.png) + +- 시력과 키를 함께 학습시킬 경우 키의 범위가 크기때문에 거리 값을 기반으로 학습 할 때 영향을 많이 준다. + +## 장점 + +- 특성들을 비교 분석하기 쉽게 만들어 준다. +- **Linear Model, Neural network Model** 등에서 학습의 안정성과 속도를 개선시킨다. +- 하지만 특성에 따라 원래 범위를 유지하는게 좋을 경우는 scaling을 하지 않아도 된다. + +## 종류 + +![02.png](/assets/images/ml02/02.png) + +### StandardScaler + +- 변수의 **평균,표준편차를 이용**해 **정규분포 형태**로 변환 (평균 0, 분산 1) +- **이상치(Outlier)에 민감**하게 영향을 받는다 + +### RobustScaler + +- 변수의 **사분위수**를 이용해 변환 +- **이상치가 있는 데이터 변환**시 사용 할 수 있다. + +### MinMaxScaler + +- 변수의 **Max 값, Min 값을 이용**해 변환 (0 ~ 1 사이 값으로 변환) +- **이상치에 민감**하게 영향을 받는다. + +### Normalizer + +- **특성 벡터의 길이가 1**이 되도록 조정 (**행마다 정규화** 진행) +- 특성 벡터의 길이는 상관 없고 **데이터의 방향(각도)만 중요할 때** 사용. \ No newline at end of file diff --git "a/_posts/2022-09-20-ml03_Decision Tree(\352\262\260\354\240\225\355\212\270\353\246\254).md" "b/_posts/2022-09-20-ml03_Decision Tree(\352\262\260\354\240\225\355\212\270\353\246\254).md" new file mode 100644 index 000000000000..f055434083f5 --- /dev/null +++ "b/_posts/2022-09-20-ml03_Decision Tree(\352\262\260\354\240\225\355\212\270\353\246\254).md" @@ -0,0 +1,290 @@ +--- +layout: single +title: "Decision Tree 결정트리" +categories: 머신러닝 +tag: [머신러닝, python, Decision Tree, 결정트리, 분류] +toc: true +toc_sticky: true + +--- + + + + + + +## Decision Tree란? + +- Tree를 만들기 위해 예/아니오 질문을 반복하며 학습한다. +- 다양한 **앙상블**(ensemble) 모델이 존재한다 (RandomForest, GradientBoosting, XGBoost, LightGBM) +- **분류**와 **회귀**에 모두 사용 가능 + +![01.png](/assets/images/ml03/01.png) + +- 타깃 값이 한 개인 리프 노드를 순수 노드라고 한다. +- 모든 노드가 **순수 노드**가 될 때 까지 학습하면 **복잡해지고 과대적합**이 된다. + +## 결정 트리 과대적합 제어 + +- 노드 생성을 미리 중단하는 **사전 가지치기(pre-pruning)**와 트리를 만든후에 크기가 작은 노드를 삭제하는 **사후 가지치기(pruning)**가 있다 (sklearn은 사전 가지치기만 지원) +- 트리의 최대 깊이(**max_depth, 값이 클수록 모델의 복잡도가 올라간다**)나 리프 노드의 최대 개수(**max_leaf_nodes**)를 제어 +- 노드가 분할하기 위한 데이터 포인트의 최소 개수(**min_samples_leaf**)를 지정 + +## 지니 불순도 + +![02.png](/assets/images/ml03/02.png) + +- 지니지수는 얼마나 불확실한가? (=**얼마나 많은 것들이 섞여있는가**?)를 보여준다. +- 지니 지수가 0이라는 것은 불확실성이 0이라는 것으로 **같은 특성을 가진 객체들끼리** 잘 모여있다는 의미이다. +- 지니 지수가 **0.5**(최대)라는 것은 **반반** 섞여 있다는 의미 + +# Decision Tree 실습 + +## 목표 + +- 독버섯과 식용버섯을 분리하는 tree 모델 만들기 +- tree 모델 시각화 +- tree 모델의 특성 중요도 확인 + +```python +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +from sklearn.metrics import accuracy_score +from sklearn.model_selection import train_test_split +``` + +- 데이터 불러오기 + +```python +data = pd.read_csv('./data/mushroom/mushroom.csv') +display(data.shape) +display(data.head()) +``` + +``` +(8124, 23) +``` + +| | poisonous | cap-shape | cap-surface | cap-color | bruises | odor | gill-attachment | gill-spacing | gill-size | gill-color | … | stalk-surface-below-ring | stalk-color-above-ring | stalk-color-below-ring | veil-type | veil-color | ring-number | ring-type | spore-print-color | population | habitat | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | p | x | s | n | t | p | f | c | n | k | … | s | w | w | p | w | o | p | k | s | u | +| 1 | e | x | s | y | t | a | f | c | b | k | … | s | w | w | p | w | o | p | n | n | g | +| 2 | e | b | s | w | t | l | f | c | b | n | … | s | w | w | p | w | o | p | n | n | m | +| 3 | p | x | y | w | t | p | f | c | n | n | … | s | w | w | p | w | o | p | k | s | u | +| 4 | e | x | s | g | f | n | f | w | b | k | … | s | w | w | p | w | o | e | n | a | g | + +5 rows × 23 columns + +```python +data.info() +``` + +``` + +RangeIndex: 8124 entries, 0 to 8123 +Data columns (total 23 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 poisonous 8124 non-null object + 1 cap-shape 8124 non-null object + 2 cap-surface 8124 non-null object + 3 cap-color 8124 non-null object + 4 bruises 8124 non-null object + 5 odor 8124 non-null object + 6 gill-attachment 8124 non-null object + 7 gill-spacing 8124 non-null object + 8 gill-size 8124 non-null object + 9 gill-color 8124 non-null object + 10 stalk-shape 8124 non-null object + 11 stalk-root 8124 non-null object + 12 stalk-surface-above-ring 8124 non-null object + 13 stalk-surface-below-ring 8124 non-null object + 14 stalk-color-above-ring 8124 non-null object + 15 stalk-color-below-ring 8124 non-null object + 16 veil-type 8124 non-null object + 17 veil-color 8124 non-null object + 18 ring-number 8124 non-null object + 19 ring-type 8124 non-null object + 20 spore-print-color 8124 non-null object + 21 population 8124 non-null object + 22 habitat 8124 non-null object +dtypes: object(23) +memory usage: 1.4+ MB +``` + +```python +X = data.iloc[:, 1:] +y = data['poisonous'] + +X.shape, y.shape +``` + +((8124, 22), (8124,)) + +- 데이터 전체를 원핫인코딩 + +```python +X_onehot = pd.get_dummies(X)X_onehot.head() +``` + +| | cap-shape_b | cap-shape_c | cap-shape_f | cap-shape_k | cap-shape_s | cap-shape_x | cap-surface_f | cap-surface_g | cap-surface_s | cap-surface_y | … | population_s | population_v | population_y | habitat_d | habitat_g | habitat_l | habitat_m | habitat_p | habitat_u | habitat_w | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | … | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | +| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | … | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | +| 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | … | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | +| 3 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | … | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | +| 4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | … | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | + +5 rows × 117 columns + +```python +X_train, X_test, y_train, y_test = train_test_split(X_onehot, y, test_size=0.3, random_state=926) + +X_train.shape, X_test.shape, y_train.shape, y_test.shape +``` + +((5686, 117), (2438, 117), (5686,), (2438,)) + +- 모델 생성 및 학습 + +```python +from sklearn.tree import DecisionTreeClassifier + +tree_model = DecisionTreeClassifier() +tree_model.fit(X_train, y_train) + +pred = tree_model.predict(X_test) +``` + +- 모델 평가 + +```python +accuracy_score(pred, y_test) +``` + +1.0 + +- 트리의 특성 중요도 확인 + - 트리 모델은 각 특성의 중요도를 확인 할 수 있음 + - **tree_model.feature_importances_** + +```python +# 데이터프레임화 하기, 중요도 기준으로 내림차순 정렬 +df = pd.DataFrame([X_train.columns, tree_model.feature_importances_]).T +df.sort_values(by=1, ascending=False) +``` + +| | 0 | 1 | +| --- | --- | --- | +| 27 | odor_n | 0.615161 | +| 53 | stalk-root_c | 0.16913 | +| 55 | stalk-root_r | 0.093209 | +| 100 | spore-print-color_r | 0.034151 | +| 33 | gill-spacing_c | 0.024172 | +| … | … | … | +| 39 | gill-color_g | 0.0 | +| 38 | gill-color_e | 0.0 | +| 37 | gill-color_b | 0.0 | +| 34 | gill-spacing_w | 0.0 | +| 116 | habitat_w | 0.0 | + +117 rows × 2 columns + +### Graphviz 시각화 + +- tree 모델 시각화 +- **Gini Impurity(지니 불순도)** 확인해보기 + +```python +from sklearn.tree import export_graphvizimport graphviz +``` + +```python +export_graphviz(tree_model, # 저장할 트리 모델 객체 + out_file='tree.dot', # 결과로 저장할 파일 + class_names=['독', '식용'], # 클래스 이름 설정 + feature_names=X_train.columns, # 컬럼 이름 넣어주기 + impurity=True, # 불순도 표기 여부 + filled=True, # 색상 채우기 여부 + rounded=True # 수치값 반올림 여부 + ) +``` + +```python +# 저장한 시각화 파일 불러오기 +with open('./tree.dot', encoding='utf-8') as f: + dot_graph = f.read() + +display(graphviz.Source(dot_graph)) +``` + +![output_20_0.svg](/assets/images/ml03/output_20_0.svg) \ No newline at end of file diff --git "a/_posts/2022-09-24-ml04_\354\247\221\352\260\222 \354\230\210\354\270\241 DecisionTree(\355\232\214\352\267\200).md" "b/_posts/2022-09-24-ml04_\354\247\221\352\260\222 \354\230\210\354\270\241 DecisionTree(\355\232\214\352\267\200).md" new file mode 100644 index 000000000000..1a7319e99c34 --- /dev/null +++ "b/_posts/2022-09-24-ml04_\354\247\221\352\260\222 \354\230\210\354\270\241 DecisionTree(\355\232\214\352\267\200).md" @@ -0,0 +1,708 @@ +--- +layout: single +title: "Decision Tree 집값 예측(회귀)" +categories: 머신러닝 +tag: [머신러닝, python, Decision Tree, 결정트리, 회귀] +toc: true +toc_sticky: true + +--- + + + + + + +## 목표 + +- Decision Tree 모델 사용하기 +- 모델 최적화하기 + +```python +# 예측하기 좋은 최적의 질문을 만들어 학습하는 모델 +from sklearn.tree import DecisionTreeRegressor + +house_model = DecisionTreeRegressor() +``` + +### 2. 모델 학습 + +- 데이터 로딩 후 탐색 + +```python +import pandas as pd + +# 데이터 로딩 +train = pd.read_csv('./data/house/train.csv') +test = pd.read_csv('./data/house/test.csv') +train.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | Car | Landsize | BuildingArea | YearBuilt | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | Price | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 5467 | Rosanna | 22 Douglas St | 2 | h | S | Miles | 19/11/2016 | 11.4 | 3084 | … | 1.0 | 757 | NaN | NaN | Banyule | -37.74280 | 145.07000 | Eastern Metropolitan | 3540 | 1200000 | +| 1 | 4365 | North Melbourne | 103/25 Byron St | 1 | u | SP | Jellis | 16/07/2016 | 2.3 | 3051 | … | 1.0 | 0 | 60.0 | 2012.0 | Melbourne | -37.80200 | 144.95160 | Northern Metropolitan | 6821 | 450000 | +| 2 | 9741 | Surrey Hills | 4/40 Durham Rd | 3 | u | SP | Noel | 17/06/2017 | 10.2 | 3127 | … | 1.0 | 149 | NaN | NaN | Boroondara | -37.82971 | 145.09007 | Southern Metropolitan | 5457 | 780000 | +| 3 | 11945 | Cheltenham | 3/33 Sunray Av | 2 | t | S | Buxton | 29/07/2017 | 17.9 | 3192 | … | 1.0 | 171 | NaN | NaN | Kingston | -37.96304 | 145.06421 | Southern Metropolitan | 9758 | 751000 | +| 4 | 4038 | Mont Albert | 7/27 High St | 3 | t | S | Fletchers | 15/10/2016 | 11.8 | 3127 | … | 2.0 | 330 | 148.0 | 2001.0 | Whitehorse | -37.81670 | 145.10700 | Eastern Metropolitan | 2079 | 1310000 | + +5 rows × 22 columns + +```python +# 전체 데이터 갯수 파악 +train.shape, test.shape +``` + +((10185, 22), (3395, 21)) + +```python +# 컬럼 확인 +train.info() +``` + +``` + +RangeIndex: 10185 entries, 0 to 10184 +Data columns (total 22 columns): + # Column Non-Null Count Dtype +--- ------ -------------- ----- + 0 Id 10185 non-null int64 + 1 Suburb 10185 non-null object + 2 Address 10185 non-null object + 3 Rooms 10185 non-null int64 + 4 Type 10185 non-null object + 5 Method 10185 non-null object + 6 SellerG 10185 non-null object + 7 Date 10185 non-null object + 8 Distance 10185 non-null float64 + 9 Postcode 10185 non-null int64 + 10 Bedroom2 10185 non-null int64 + 11 Bathroom 10185 non-null int64 + 12 Car 10142 non-null float64 + 13 Landsize 10185 non-null int64 + 14 BuildingArea 5367 non-null float64 + 15 YearBuilt 6153 non-null float64 + 16 CouncilArea 9174 non-null object + 17 Lattitude 10185 non-null float64 + 18 Longtitude 10185 non-null float64 + 19 Regionname 10185 non-null object + 20 Propertycount 10185 non-null int64 + 21 Price 10185 non-null int64 +dtypes: float64(6), int64(8), object(8) +memory usage: 1.7+ MB +``` + +```python +# 기술 통계, include='all' 범주형 통계 값 포함(고유값, 최빈값, ...) +train.describe(include='all') +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | Car | Landsize | BuildingArea | YearBuilt | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | Price | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| count | 10185.000000 | 10185 | 10185 | 10185.000000 | 10185 | 10185 | 10185 | 10185 | 10185.000000 | 10185.000000 | … | 10142.000000 | 10185.000000 | 5367.000000 | 6153.000000 | 9174 | 10185.000000 | 10185.000000 | 10185 | 10185.000000 | 1.018500e+04 | +| unique | NaN | 310 | 10066 | NaN | 3 | 5 | 243 | 58 | NaN | NaN | … | NaN | NaN | NaN | NaN | 33 | NaN | NaN | 8 | NaN | NaN | +| top | NaN | Reservoir | 2 Bruce St | NaN | h | S | Nelson | 27/05/2017 | NaN | NaN | … | NaN | NaN | NaN | NaN | Moreland | NaN | NaN | Southern Metropolitan | NaN | NaN | +| freq | NaN | 261 | 3 | NaN | 7106 | 6753 | 1156 | 364 | NaN | NaN | … | NaN | NaN | NaN | NaN | 887 | NaN | NaN | 3525 | NaN | NaN | +| mean | 6802.613942 | NaN | NaN | 2.943250 | NaN | NaN | NaN | NaN | 10.198213 | 3105.172607 | … | 1.613883 | 573.426411 | 154.137372 | 1964.904599 | NaN | -37.809763 | 144.995347 | NaN | 7447.172018 | 1.077961e+06 | +| std | 3926.702100 | NaN | NaN | 0.952794 | NaN | NaN | NaN | NaN | 5.866640 | 90.198740 | … | 0.959076 | 4550.757180 | 614.711880 | 37.603561 | NaN | 0.079922 | 0.104255 | NaN | 4354.473015 | 6.364301e+05 | +| min | 3.000000 | NaN | NaN | 1.000000 | NaN | NaN | NaN | NaN | 0.000000 | 3000.000000 | … | 0.000000 | 0.000000 | 0.000000 | 1196.000000 | NaN | -38.182550 | 144.431810 | NaN | 249.000000 | 1.310000e+05 | +| 25% | 3384.000000 | NaN | NaN | 2.000000 | NaN | NaN | NaN | NaN | 6.200000 | 3044.000000 | … | 1.000000 | 178.000000 | 93.920000 | 1940.000000 | NaN | -37.857700 | 144.929500 | NaN | 4380.000000 | 6.500000e+05 | +| 50% | 6838.000000 | NaN | NaN | 3.000000 | NaN | NaN | NaN | NaN | 9.300000 | 3084.000000 | … | 2.000000 | 448.000000 | 127.000000 | 1970.000000 | NaN | -37.802900 | 145.000130 | NaN | 6543.000000 | 9.050000e+05 | +| 75% | 10223.000000 | NaN | NaN | 4.000000 | NaN | NaN | NaN | NaN | 13.000000 | 3149.000000 | … | 2.000000 | 652.000000 | 175.000000 | 2000.000000 | NaN | -37.756710 | 145.059280 | NaN | 10331.000000 | 1.330000e+06 | +| max | 13577.000000 | NaN | NaN | 8.000000 | NaN | NaN | NaN | NaN | 48.100000 | 3977.000000 | … | 10.000000 | 433014.000000 | 44515.000000 | 2018.000000 | NaN | -37.408530 | 145.526350 | NaN | 21650.000000 | 7.650000e+06 | + +11 rows × 22 columns + +- 문제와 정답 추출 +- 일단은 결측치가 존재하는 컬럼과 문자형태의 컬럼은 배제 + +```python +X_train = train[['Propertycount', 'Rooms', 'Bedroom2']] +y_train = train['Price'] +``` + +```python +# train -> 7.5 : 2.5비율로 train2, validation 데이터로 나누기 +from sklearn.model_selection import train_test_split + +X_train2, X_val, y_train2, y_val = train_test_split(X_train, y_train, random_state=3) +X_train2.shape, X_val.shape, y_train2.shape, y_val.shape +``` + +((7638, 3), (2547, 3), (7638,), (2547,)) + +```python +house_model.fit(X_train2, y_train2) +``` + +DecisionTreeRegressor() + +### 3. 모델 예측 + +```python +pred = house_model.predict(X_val) +pred +``` + +array([ 451840. , 1344925. , 684462.5, …, 1843500. , 1300000. , 2272500. ]) + +### 4. 모델 평가 + +- MAE(Mean Absolute Error, 평균 절대값 오차) 활용한 평가 + +```python +from sklearn.metrics import mean_absolute_error +error = mean_absolute_error(y_val, pred) +error +``` + +255227.3455560717 + +### 캐글에 업로드 하기 + +```python +X_test = test[['Propertycount', 'Rooms', 'Bedroom2']] +X_test.shape +``` + +(3395, 3) + +```python +test_pre = house_model.predict(X_test) +test_pre +``` + +array([ 382333.33333333, 522500. , 700000. , …, 710500. , 651357.14285714, 1042205.88235294]) + +```python +# 정답지 파일 로딩 +submission = pd.read_csv("./data/house/sample_submission.csv") +submission +``` + +| | Id | Price | +| --- | --- | --- | +| 0 | 3189 | 0 | +| 1 | 2539 | 0 | +| 2 | 9171 | 0 | +| 3 | 4741 | 0 | +| 4 | 12455 | 0 | +| … | … | … | +| 3390 | 12276 | 0 | +| 3391 | 4618 | 0 | +| 3392 | 12913 | 0 | +| 3393 | 11741 | 0 | +| 3394 | 1072 | 0 | + +3395 rows × 2 columns + +```python +test.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | Bathroom | Car | Landsize | BuildingArea | YearBuilt | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 3189 | Hawthorn | 22/9 Lisson Gr | 1 | u | S | Biggin | 19/11/2016 | 4.6 | 3122 | … | 1 | 1.0 | 0 | 52.0 | 1970.0 | Boroondara | -37.82610 | 145.02690 | Southern Metropolitan | 11308 | +| 1 | 2539 | Fitzroy | 113/300 Young St | 1 | u | SP | Jellis | 19/11/2016 | 1.6 | 3065 | … | 1 | 1.0 | 0 | 52.0 | 2011.0 | Yarra | -37.79740 | 144.97990 | Northern Metropolitan | 5825 | +| 2 | 9171 | Greenvale | 7 Murray Ct | 5 | h | S | Barry | 3/06/2017 | 20.4 | 3059 | … | 3 | 5.0 | 1750 | 310.0 | 1990.0 | Hume | -37.65439 | 144.89113 | Northern Metropolitan | 4864 | +| 3 | 4741 | Port Melbourne | 172 Albert St | 2 | h | S | hockingstuart | 10/12/2016 | 3.8 | 3207 | … | 1 | 0.0 | 106 | 70.0 | 1910.0 | Port Phillip | -37.83460 | 144.93730 | Southern Metropolitan | 8648 | +| 4 | 12455 | Brunswick West | 47 Everett St | 4 | h | VB | Nelson | 9/09/2017 | 5.2 | 3055 | … | 2 | 2.0 | 600 | 180.0 | 2004.0 | NaN | -37.75465 | 144.94144 | Northern Metropolitan | 7082 | + +5 rows × 21 columns + +```python +submission['Price'] = test_pre +submission.head() +``` + +| | Id | Price | +| --- | --- | --- | +| 0 | 3189 | 3.823333e+05 | +| 1 | 2539 | 5.225000e+05 | +| 2 | 9171 | 7.000000e+05 | +| 3 | 4741 | 9.572778e+05 | +| 4 | 12455 | 1.294818e+06 | + +```python +# csv파일로 저장 +submission.to_csv("./data/house/myPrediction.csv", + index=False) +``` + +## 다른 컬럼을 이용해보자. + +1. 결측치가 있는 컬럼 + - 데이터를 버린다. -> drop, dropna + - 데이터를 채운다. -> fillna + - 기술통계 활용 + - 모델 활용 -> 결측치를 정답, 주변컬럼을 문제로 설정 +2. 문자형태의 컬럼 + - 문자타입 -> 숫자타입 변경(인코딩) + - 라벨 인코딩 -> 임의의 숫자를 글자에 부여 + - 원핫 인코딩 -> 0과1을 이용해서 변환 + +```python +test.columns +``` + +Index([‘Id’, ‘Suburb’, ‘Address’, ‘Rooms’, ‘Type’, ‘Method’, ‘SellerG’, ‘Date’, ‘Distance’, ‘Postcode’, ‘Bedroom2’, ‘Bathroom’, ‘Car’, ‘Landsize’, ‘BuildingArea’, ‘YearBuilt’, ‘CouncilArea’, ‘Lattitude’, ‘Longtitude’, ‘Regionname’, ‘Propertycount’], dtype=‘object’) + +```python +train.corr() +``` + +| | Id | Rooms | Distance | Postcode | Bedroom2 | Bathroom | Car | Landsize | BuildingArea | YearBuilt | Lattitude | Longtitude | Propertycount | Price | h | t | u | Method_label | Regionname_label | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| Id | 1.000000 | 0.100741 | 0.293943 | 0.092843 | 0.116731 | 0.040834 | 0.099056 | 0.026959 | 0.024208 | 0.104456 | 0.040772 | 0.056133 | 0.008075 | -0.051498 | 0.114506 | -0.041921 | -0.099133 | 0.011529 | 0.267904 | +| Rooms | 0.100741 | 1.000000 | 0.294621 | 0.053791 | 0.937357 | 0.588991 | 0.406340 | 0.024508 | 0.115067 | -0.059154 | 0.012710 | 0.104277 | -0.081669 | 0.497539 | 0.507407 | -0.028028 | -0.543692 | 0.003428 | 0.166209 | +| Distance | 0.293943 | 0.294621 | 1.000000 | 0.430208 | 0.294438 | 0.120574 | 0.268467 | 0.024602 | 0.108834 | 0.245371 | -0.134113 | 0.239075 | -0.052206 | -0.164388 | 0.213490 | -0.012074 | -0.228571 | -0.093669 | 0.510509 | +| Postcode | 0.092843 | 0.053791 | 0.430208 | 1.000000 | 0.059840 | 0.108927 | 0.052475 | 0.027304 | 0.061235 | 0.021593 | -0.408562 | 0.450340 | 0.057250 | 0.111511 | -0.024155 | -0.008960 | 0.032696 | 0.016300 | -0.055349 | +| Bedroom2 | 0.116731 | 0.937357 | 0.294438 | 0.059840 | 1.000000 | 0.579122 | 0.402223 | 0.024382 | 0.112563 | -0.045148 | 0.012189 | 0.105248 | -0.080096 | 0.473742 | 0.485838 | -0.027327 | -0.520256 | 0.005557 | 0.165695 | +| Bathroom | 0.040834 | 0.588991 | 0.120574 | 0.108927 | 0.579122 | 1.000000 | 0.319449 | 0.038824 | 0.106673 | 0.154065 | -0.072667 | 0.116156 | -0.050214 | 0.464396 | 0.169435 | 0.119998 | -0.267174 | 0.084622 | 0.015280 | +| Car | 0.099056 | 0.406340 | 0.268467 | 0.052475 | 0.402223 | 0.319449 | 1.000000 | 0.023537 | 0.096233 | 0.113786 | -0.003670 | 0.067147 | -0.024338 | 0.235853 | 0.253054 | -0.014562 | -0.270764 | 0.012097 | 0.112987 | +| Landsize | 0.026959 | 0.024508 | 0.024602 | 0.027304 | 0.024382 | 0.038824 | 0.023537 | 1.000000 | 0.546089 | 0.040293 | 0.010407 | 0.010326 | -0.009704 | 0.040665 | 0.022618 | -0.018688 | -0.012693 | 0.029722 | 0.022445 | +| BuildingArea | 0.024208 | 0.115067 | 0.108834 | 0.061235 | 0.112563 | 0.106673 | 0.096233 | 0.546089 | 1.000000 | 0.021732 | 0.052281 | -0.033764 | -0.029216 | 0.082028 | 0.060088 | -0.004645 | -0.064177 | -0.001155 | 0.060186 | +| YearBuilt | 0.104456 | -0.059154 | 0.245371 | 0.021593 | -0.045148 | 0.154065 | 0.113786 | 0.040293 | 0.021732 | 1.000000 | 0.060937 | -0.017734 | 0.006838 | -0.324162 | -0.393885 | 0.298914 | 0.230626 | 0.027549 | 0.130729 | +| Lattitude | 0.040772 | 0.012710 | -0.134113 | -0.408562 | 0.012189 | -0.072667 | -0.003670 | 0.010407 | 0.052281 | 0.060937 | 1.000000 | -0.359648 | 0.060830 | -0.210428 | 0.108648 | -0.035545 | -0.096862 | -0.027790 | 0.141548 | +| Longtitude | 0.056133 | 0.104277 | 0.239075 | 0.450340 | 0.105248 | 0.116156 | 0.067147 | 0.010326 | -0.033764 | -0.017734 | -0.359648 | 1.000000 | 0.056610 | 0.206866 | -0.008365 | 0.006092 | 0.005237 | 0.022174 | -0.006846 | +| Propertycount | 0.008075 | -0.081669 | -0.052206 | 0.057250 | -0.080096 | -0.050214 | -0.024338 | -0.009704 | -0.029216 | 0.006838 | 0.060830 | 0.056610 | 1.000000 | -0.046582 | -0.065180 | -0.020591 | 0.085853 | -0.005943 | -0.184688 | +| Price | -0.051498 | 0.497539 | -0.164388 | 0.111511 | 0.473742 | 0.464396 | 0.235853 | 0.040665 | 0.082028 | -0.324162 | -0.210428 | 0.206866 | -0.046582 | 1.000000 | 0.391641 | -0.061995 | -0.392931 | 0.029182 | -0.237278 | +| h | 0.114506 | 0.507407 | 0.213490 | -0.024155 | 0.485838 | 0.169435 | 0.253054 | 0.022618 | 0.060088 | -0.393885 | 0.108648 | -0.008365 | -0.065180 | 0.391641 | 1.000000 | -0.453989 | -0.807573 | -0.065250 | 0.191063 | +| t | -0.041921 | -0.028028 | -0.012074 | -0.008960 | -0.027327 | 0.119998 | -0.014562 | -0.018688 | -0.004645 | 0.298914 | -0.035545 | 0.006092 | -0.020591 | -0.061995 | -0.453989 | 1.000000 | -0.158859 | 0.008709 | -0.037968 | +| u | -0.099133 | -0.543692 | -0.228571 | 0.032696 | -0.520256 | -0.267174 | -0.270764 | -0.012693 | -0.064177 | 0.230626 | -0.096862 | 0.005237 | 0.085853 | -0.392931 | -0.807573 | -0.158859 | 1.000000 | 0.066537 | -0.186580 | +| Method_label | 0.011529 | 0.003428 | -0.093669 | 0.016300 | 0.005557 | 0.084622 | 0.012097 | 0.029722 | -0.001155 | 0.027549 | -0.027790 | 0.022174 | -0.005943 | 0.029182 | -0.065250 | 0.008709 | 0.066537 | 1.000000 | -0.070270 | +| Regionname_label | 0.267904 | 0.166209 | 0.510509 | -0.055349 | 0.165695 | 0.015280 | 0.112987 | 0.022445 | 0.060186 | 0.130729 | 0.141548 | -0.006846 | -0.184688 | -0.237278 | 0.191063 | -0.037968 | -0.186580 | -0.070270 | 1.000000 | +- Type 컬럼 전처리 + +```python +# 원한인코딩 함수 +type_onehot = pd.get_dummies(train['Type']) +type_onehot +``` + +| | h | t | u | +| --- | --- | --- | --- | +| 0 | 1 | 0 | 0 | +| 1 | 0 | 0 | 1 | +| 2 | 0 | 0 | 1 | +| 3 | 0 | 1 | 0 | +| 4 | 0 | 1 | 0 | +| … | … | … | … | +| 10180 | 1 | 0 | 0 | +| 10181 | 1 | 0 | 0 | +| 10182 | 1 | 0 | 0 | +| 10183 | 1 | 0 | 0 | +| 10184 | 0 | 1 | 0 | + +10185 rows × 3 columns + +```python +type_onehot_test = pd.get_dummies(test['Type']) +type_onehot_test +``` + +| | h | t | u | +| --- | --- | --- | --- | +| 0 | 0 | 0 | 1 | +| 1 | 0 | 0 | 1 | +| 2 | 1 | 0 | 0 | +| 3 | 1 | 0 | 0 | +| 4 | 1 | 0 | 0 | +| … | … | … | … | +| 3390 | 1 | 0 | 0 | +| 3391 | 1 | 0 | 0 | +| 3392 | 0 | 1 | 0 | +| 3393 | 1 | 0 | 0 | +| 3394 | 0 | 0 | 1 | + +3395 rows × 3 columns + +```python +train = pd.concat([train, type_onehot], axis=1) +train.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | YearBuilt | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | Price | h | t | u | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 5467 | Rosanna | 22 Douglas St | 2 | h | S | Miles | 19/11/2016 | 11.4 | 3084 | … | NaN | Banyule | -37.74280 | 145.07000 | Eastern Metropolitan | 3540 | 1200000 | 1 | 0 | 0 | +| 1 | 4365 | North Melbourne | 103/25 Byron St | 1 | u | SP | Jellis | 16/07/2016 | 2.3 | 3051 | … | 2012.0 | Melbourne | -37.80200 | 144.95160 | Northern Metropolitan | 6821 | 450000 | 0 | 0 | 1 | +| 2 | 9741 | Surrey Hills | 4/40 Durham Rd | 3 | u | SP | Noel | 17/06/2017 | 10.2 | 3127 | … | NaN | Boroondara | -37.82971 | 145.09007 | Southern Metropolitan | 5457 | 780000 | 0 | 0 | 1 | +| 3 | 11945 | Cheltenham | 3/33 Sunray Av | 2 | t | S | Buxton | 29/07/2017 | 17.9 | 3192 | … | NaN | Kingston | -37.96304 | 145.06421 | Southern Metropolitan | 9758 | 751000 | 0 | 1 | 0 | +| 4 | 4038 | Mont Albert | 7/27 High St | 3 | t | S | Fletchers | 15/10/2016 | 11.8 | 3127 | … | 2001.0 | Whitehorse | -37.81670 | 145.10700 | Eastern Metropolitan | 2079 | 1310000 | 0 | 1 | 0 | + +5 rows × 25 columns + +```python +test = pd.concat([test, type_onehot_test], axis=1) +test.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | BuildingArea | YearBuilt | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | h | t | u | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 3189 | Hawthorn | 22/9 Lisson Gr | 1 | u | S | Biggin | 19/11/2016 | 4.6 | 3122 | … | 52.0 | 1970.0 | Boroondara | -37.82610 | 145.02690 | Southern Metropolitan | 11308 | 0 | 0 | 1 | +| 1 | 2539 | Fitzroy | 113/300 Young St | 1 | u | SP | Jellis | 19/11/2016 | 1.6 | 3065 | … | 52.0 | 2011.0 | Yarra | -37.79740 | 144.97990 | Northern Metropolitan | 5825 | 0 | 0 | 1 | +| 2 | 9171 | Greenvale | 7 Murray Ct | 5 | h | S | Barry | 3/06/2017 | 20.4 | 3059 | … | 310.0 | 1990.0 | Hume | -37.65439 | 144.89113 | Northern Metropolitan | 4864 | 1 | 0 | 0 | +| 3 | 4741 | Port Melbourne | 172 Albert St | 2 | h | S | hockingstuart | 10/12/2016 | 3.8 | 3207 | … | 70.0 | 1910.0 | Port Phillip | -37.83460 | 144.93730 | Southern Metropolitan | 8648 | 1 | 0 | 0 | +| 4 | 12455 | Brunswick West | 47 Everett St | 4 | h | VB | Nelson | 9/09/2017 | 5.2 | 3055 | … | 180.0 | 2004.0 | NaN | -37.75465 | 144.94144 | Northern Metropolitan | 7082 | 1 | 0 | 0 | + +5 rows × 24 columns + +- Method 컬럼 전처리 + +```python +# 라벨인코딩 +# 캐글의 metadata 정보 참고 +method_dict = { + 'S' : 0, + 'SP' : 1, + 'PI' : 2, + 'PN' : 3, + 'SN' : 4, + 'NB' : 5, + 'VB' : 6, + 'W' : 7, + 'SA' : 8, + 'SS' : 9 +} +method_label = train['Method'].map(method_dict) +method_label_test = test['Method'].map(method_dict) +method_label +``` + +``` +0 0 +1 1 +2 1 +3 0 +4 0 + .. +10180 0 +10181 2 +10182 0 +10183 2 +10184 0 +Name: Method, Length: 10185, dtype: int64 +``` + +```python +train['Method_label'] = method_label +test['Method_label'] = method_label_test +train.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | CouncilArea | Lattitude | Longtitude | Regionname | Propertycount | Price | h | t | u | Method_label | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 5467 | Rosanna | 22 Douglas St | 2 | h | S | Miles | 19/11/2016 | 11.4 | 3084 | … | Banyule | -37.74280 | 145.07000 | Eastern Metropolitan | 3540 | 1200000 | 1 | 0 | 0 | 0 | +| 1 | 4365 | North Melbourne | 103/25 Byron St | 1 | u | SP | Jellis | 16/07/2016 | 2.3 | 3051 | … | Melbourne | -37.80200 | 144.95160 | Northern Metropolitan | 6821 | 450000 | 0 | 0 | 1 | 1 | +| 2 | 9741 | Surrey Hills | 4/40 Durham Rd | 3 | u | SP | Noel | 17/06/2017 | 10.2 | 3127 | … | Boroondara | -37.82971 | 145.09007 | Southern Metropolitan | 5457 | 780000 | 0 | 0 | 1 | 1 | +| 3 | 11945 | Cheltenham | 3/33 Sunray Av | 2 | t | S | Buxton | 29/07/2017 | 17.9 | 3192 | … | Kingston | -37.96304 | 145.06421 | Southern Metropolitan | 9758 | 751000 | 0 | 1 | 0 | 0 | +| 4 | 4038 | Mont Albert | 7/27 High St | 3 | t | S | Fletchers | 15/10/2016 | 11.8 | 3127 | … | Whitehorse | -37.81670 | 145.10700 | Eastern Metropolitan | 2079 | 1310000 | 0 | 1 | 0 | 0 | + +5 rows × 26 columns + +### 결측치와 문자형태를 처리해서 다양한 컬럼으로 학습해보자. + +1. train, test 데이터에 원하는 결측치,인코딩 처리 실시 +2. 원하는 컬럼 선택 +3. train을 train2와 val로 분리 +4. 모델 학습 후 평가 +5. test 데이터를 예측해 kaggle에 업로드 + +- Car 컬럼 전처리 + +```python +# Car 컬럼의 결측치 채우기 +train['Car'].describe() +``` + +``` +count 10142.000000 +mean 1.613883 +std 0.959076 +min 0.000000 +25% 1.000000 +50% 2.000000 +75% 2.000000 +max 10.000000 +Name: Car, dtype: float64 +``` + +```python +# 중앙값으로 채우기 +train['Car'] = train['Car'].fillna(train['Car'].median()) +test['Car'] = test['Car'].fillna(train['Car'].median()) +``` + +- Regionname 컬럼 전처리 + +```python +train['Regionname'].value_counts() +``` + +``` +Southern Metropolitan 3525 +Northern Metropolitan 2912 +Western Metropolitan 2219 +Eastern Metropolitan 1096 +South-Eastern Metropolitan 348 +Eastern Victoria 37 +Northern Victoria 30 +Western Victoria 18 +Name: Regionname, dtype: int64 +``` + +```python +regionname_dict = { + 'Southern Metropolitan' : 0, + 'Northern Metropolitan' : 1, + 'Western Metropolitan' : 2, + 'Eastern Metropolitan' : 3, + 'South-Eastern Metropolitan' : 4, + 'Eastern Victoria' : 5, + 'Northern Victoria' : 6, + 'Western Victoria' : 7 +} + +regionname_label = train['Regionname'].map(regionname_dict) +regionname_label_test = test['Regionname'].map(regionname_dict) +regionname_label +``` + +```python +train['Regionname_label'] = regionname_label +test['Regionname_label'] = regionname_label_test +train.head() +``` + +| | Id | Suburb | Address | Rooms | Type | Method | SellerG | Date | Distance | Postcode | … | Lattitude | Longtitude | Regionname | Propertycount | Price | h | t | u | Method_label | Regionname_label | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 5467 | Rosanna | 22 Douglas St | 2 | h | S | Miles | 19/11/2016 | 11.4 | 3084 | … | -37.74280 | 145.07000 | Eastern Metropolitan | 3540 | 1200000 | 1 | 0 | 0 | 0 | 3 | +| 1 | 4365 | North Melbourne | 103/25 Byron St | 1 | u | SP | Jellis | 16/07/2016 | 2.3 | 3051 | … | -37.80200 | 144.95160 | Northern Metropolitan | 6821 | 450000 | 0 | 0 | 1 | 1 | 1 | +| 2 | 9741 | Surrey Hills | 4/40 Durham Rd | 3 | u | SP | Noel | 17/06/2017 | 10.2 | 3127 | … | -37.82971 | 145.09007 | Southern Metropolitan | 5457 | 780000 | 0 | 0 | 1 | 1 | 0 | +| 3 | 11945 | Cheltenham | 3/33 Sunray Av | 2 | t | S | Buxton | 29/07/2017 | 17.9 | 3192 | … | -37.96304 | 145.06421 | Southern Metropolitan | 9758 | 751000 | 0 | 1 | 0 | 0 | 0 | +| 4 | 4038 | Mont Albert | 7/27 High St | 3 | t | S | Fletchers | 15/10/2016 | 11.8 | 3127 | … | -37.81670 | 145.10700 | Eastern Metropolitan | 2079 | 1310000 | 0 | 1 | 0 | 0 | 3 | + +5 rows × 27 columns + +- CouncilArea 전처리 + +```python +X_train = train[['Rooms', 'Distance', 'Bedroom2', 'Bathroom', 'Car', 'Landsize', 'Propertycount', 'h', 't', 'u', 'Method_label', 'Regionname_label', 'Lattitude', 'Longtitude']] +y_train = train['Price'] + +X_test = test[['Rooms', 'Distance', 'Bedroom2', 'Bathroom', 'Car', 'Landsize', 'Propertycount', 'h', 't', 'u', 'Method_label', 'Regionname_label', 'Lattitude', 'Longtitude']] +X_train.head() +``` + +| | Rooms | Distance | Bedroom2 | Bathroom | Car | Landsize | Propertycount | h | t | u | Method_label | Regionname_label | Lattitude | Longtitude | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 2 | 11.4 | 2 | 1 | 1.0 | 757 | 3540 | 1 | 0 | 0 | 0 | 3 | -37.74280 | 145.07000 | +| 1 | 1 | 2.3 | 1 | 1 | 1.0 | 0 | 6821 | 0 | 0 | 1 | 1 | 1 | -37.80200 | 144.95160 | +| 2 | 3 | 10.2 | 2 | 1 | 1.0 | 149 | 5457 | 0 | 0 | 1 | 1 | 0 | -37.82971 | 145.09007 | +| 3 | 2 | 17.9 | 2 | 1 | 1.0 | 171 | 9758 | 0 | 1 | 0 | 0 | 0 | -37.96304 | 145.06421 | +| 4 | 3 | 11.8 | 3 | 2 | 2.0 | 330 | 2079 | 0 | 1 | 0 | 0 | 3 | -37.81670 | 145.10700 | + +```python +X_test.head() +``` + +| | Rooms | Distance | Bedroom2 | Bathroom | Car | Landsize | Propertycount | h | t | u | Method_label | Regionname_label | Lattitude | Longtitude | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 0 | 1 | 4.6 | 1 | 1 | 1.0 | 0 | 11308 | 0 | 0 | 1 | 0 | 0 | -37.82610 | 145.02690 | +| 1 | 1 | 1.6 | 1 | 1 | 1.0 | 0 | 5825 | 0 | 0 | 1 | 1 | 1 | -37.79740 | 144.97990 | +| 2 | 5 | 20.4 | 5 | 3 | 5.0 | 1750 | 4864 | 1 | 0 | 0 | 0 | 1 | -37.65439 | 144.89113 | +| 3 | 2 | 3.8 | 2 | 1 | 0.0 | 106 | 8648 | 1 | 0 | 0 | 0 | 0 | -37.83460 | 144.93730 | +| 4 | 4 | 5.2 | 4 | 2 | 2.0 | 600 | 7082 | 1 | 0 | 0 | 6 | 1 | -37.75465 | 144.94144 | +- 검증데이터 분리 + +```python +X_train3, X_val3, y_train3, y_val3 = train_test_split(X_train, y_train, test_size=0.2, random_state=916) +``` + +- 모델 정의 + +```python +house_model2 = DecisionTreeRegressor() +``` + +- 모델 학습 + +```python +house_model2.fit(X_train3, y_train3) +``` + +DecisionTreeRegressor() + +- 모델 예측 + +```python +pred = house_model2.predict(X_val3) +``` + +- 모델 평가 + +```python +mean_absolute_error(y_val3, pred) +``` + +245946.3264604811 + +- 캐글 제출 + +```python +submission['Price'] = house_model2.predict(X_test) +submission.head() +``` + +| | Id | Price | +| --- | --- | --- | +| 0 | 3189 | 348000.0 | +| 1 | 2539 | 597000.0 | +| 2 | 9171 | 725500.0 | +| 3 | 4741 | 1000000.0 | +| 4 | 12455 | 1610000.0 | + +```python +submission.to_csv("./data/house/myPrediction.csv", + index=False) +``` + +### 모델 최적화 + +- 모델복잡도 제어하기 +- KNN은 이웃의 숫자로 모델의 복잡도 제어 + - 이웃의 숫자가 커질수록 단순, + - 숫자가 적어질수록 복잡해진다. +- DecisionTree는 질문의 깊이로 모델의 복잡도를 제어(max_depth) + - 깊이가 얕으면 단순, + - 깊이가 깊으면 복잡해진다. + +```python +train_score_list = [] +val_score_list = [] + +for d in range(1, 30): + m = DecisionTreeRegressor(max_depth=d) + m.fit(X_train3, y_train3) + pred_train = m.predict(X_train3) + pred_val = m.predict(X_val3) + + score_train = mean_absolute_error(y_train3, pred_train) + score_val = mean_absolute_error(y_val3, pred_val) + train_score_list.append(score_train) + val_score_list.append(score_val) + print(d, ":", score_val) +``` + +``` +1 : 417733.49974970485 +2 : 343806.0797298899 +3 : 296665.1121222014 +4 : 266627.09369623766 +5 : 250658.9323204579 +6 : 240011.4545997507 +7 : 228006.44228511458 +8 : 225544.86401968033 +9 : 223158.24205112088 +10 : 222866.61170201903 +11 : 222247.53782971326 +12 : 226750.59009251397 +13 : 232785.61967598234 +14 : 236449.60651906623 +15 : 238339.72952208374 +16 : 235256.46193522654 +17 : 239032.74728354442 +18 : 246129.8931403534 +19 : 245102.87083875437 +20 : 248124.2068576584 +21 : 248081.48209490062 +22 : 247554.49879324844 +23 : 247564.5162821142 +24 : 243753.52724594992 +25 : 248604.58184694266 +26 : 244163.59204712813 +27 : 244919.02258222876 +28 : 245388.98429062346 +29 : 248771.09327442318 +``` + +```python +# 시각화 +import matplotlib.pyplot as plt + +plt.figure(figsize=(10, 5)) +plt.plot(range(1, 30), train_score_list) +plt.plot(range(1, 30), val_score_list) +plt.show() +``` + +![output_61_0.png](/assets/images/ml04/output_61_0.png) + +- max_depth가 11일때 가장 낮은 MAE값을 얻을 수 있다. \ No newline at end of file diff --git "a/_posts/2022-09-29-ml05_Ensemble(\354\225\231\354\203\201\353\270\224).md" "b/_posts/2022-09-29-ml05_Ensemble(\354\225\231\354\203\201\353\270\224).md" new file mode 100644 index 000000000000..b80eab6e9071 --- /dev/null +++ "b/_posts/2022-09-29-ml05_Ensemble(\354\225\231\354\203\201\353\270\224).md" @@ -0,0 +1,155 @@ +--- +layout: single +title: "Ensemble(앙상블)" +categories: 머신러닝 +tag: [머신러닝, python, Ensemble, 결정트리, 앙상블] +toc: true +toc_sticky: true + +--- + + + + + +## Decision Tree Ensemble(결정트리 앙상블) + +- 앙상블(ensemble)은 **여러 머신러닝 모델을 연결**하여 더 강력한 모델을 만드는 기법 +- 결정트리의 가지치기 후 **과대적합되는 단점을 보완**하는 모델 +- **RandomForest, GradientBoosting, XGBoost, LightGBM, CatBoost** 등 +- 회귀와 분류에 모두 사용 가능 + +## 앙상블 기법 + +1. **보팅(Voting)** + - 서로 다른 모델을 학습시켜 예측 결과를 **다수의 결과로 투표**하는 방법 + - 앙상블의 가장 기본 원리 + - **하드 보팅**(최종 예측 결과로만 보팅), **소프트 보팅**(모델들의 예측 확률로 보팅)으로 나뉜다. +2. **배깅(Bagging)** + - 같은 알고리즘을 가진 모델들을 학습시켜 예측 결과를 투표하는 방법 + - 학습 데이터(행)를 모델마다 다르게 샘플링(Bootstraping), 병렬 학습 + - 학습에 사용되는 컬럼(열)을 다르게 랜덤 선택 + - 배깅이 적용된 Decision Tree가 **RandomForest** +3. **부스팅** + - 같은 알고리즘을 가진 모델을 학습시켜 예측결과를 투표하는 방법 + - **이전 모델이 잘못 예측한 부분을 다음 모델이 강조해서 학습**하는 방법 + - 순차적 학습 -> 학습 속도가 비교적 느림 + +## RandomForest (배깅 모델) + +- 서로 다른 방향으로 **과대적합된 트리를 많이 만들고 평균을 내어 일반화** 시키는 모델 +- 다양한 트리를 만드는 방법 두 가지 + - 트리를 만들 때 사용하는 데이터 포인트 샘플을 무작위로 선택한다. + - 노드 구성시 기준이 되는 특성을 무작위로 선택하게 한다. +- **결정트리의 단점을 보완**하고 **장점은 그대로** 가지고 있는 모델이어서 별다른 조정 없이도 괜찮을 결과를 만들어낸다. +- 트리가 여러 개 만들어지기 때문에 비전문가에게 예측과정을 보여주기는 어렵다. +- 랜덤하게 만들어지기 때문에 random_state를 고정해야 같은 결과를 볼 수 있다. + +### 주요 매개변수 + +- n_estimators : 생성할 트리의 갯수 +- n개의 데이터 부트스트랩 샘플 구성 (n개의 데이터 포인트 중 무작위로 n 횟수만큼 반복 추출, 중복된 데이터가 들어 있을 수 있다.) +- max_features : 무작위로 선택될 후보 특성의 개수 (각 노드 별로 max_features 개수 만큼 무작위로 특성을 고른 뒤 최선의 특성을 찾는다.) +- max_features를 높이면 트리들이 비슷해진다. + +```python +from sklearn.ensemble import RandomForestClassifier + +rf_model = RandomForestClassifier(random_state=923, + n_estimators=1000, # 앙상블할 모델(tree)의 갯수 + max_features=0.6, # 학습에 사용할 특성(컬럼) 수 (설정된 값은 60%) + max_depth=15 # 트리의 깊이 설정 + ) +``` + +## GradientBoosting (부스팅 모델) + +- 정확도가 낮더라도 얕은 깊이의 모델을 만든 뒤, 나타난 예측 오류를 두 번째 모델이 보완한다. +- **이전 트리의 예측 오류를 보완하여 다음 트리를 만드는 작업을 반복**한다. +- 마지막까지 **성능을 쥐어짜고 싶은 경우** 사용한다, 주로 경진 대회에서 많이 활용. +(GradientBoosting을 더 발전시킨 **XGBoost**도 있음) +- 보통 트리의 깊이를 깊게하지 않기 때문에 **예측 속도는 비교적 빠르다**. 하지만 이전 트리의 오차를 반영해서 새로운 트리를 만들기 때문에 **학습속도가 느리다**. +- 특성의 **스케일을 조정하지 않아도 된다.** + +### 주요 매개변수 + +- n_estimators : 생성할 트리의 개수 (트리가 많아질수록 과대적합이 될 수 있다.) +- learning_rate : 오차를 보정하는 정도 (값이 높을수록 오차를 많이 보정하려고 한다.) +- max_depth : 트리의 깊이 (일반적으로 **트리의 깊이를 깊게 설정하지 않는다.**) + +```python +from sklearn.ensemble import GradientBoostingClassifier + +gbtree = GradientBoostingClassifier(n_estimators=100, # 트리의 갯수(순차적으로 생성되고, 이전 트리의 오류에 가중치가 더해짐) + learning_rate=0.1, # 이전트리의 오류를 다음트리에 얼마나 반영할지 + max_depth=5, # 트리의 깊이 + subsample=1 # 1: 전체데이터 사용, 과적합이 우려된다면 값을 줄여도 됨 + ) +``` \ No newline at end of file diff --git "a/_posts/2022-10-01-DL01_\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225,\354\230\244\354\260\250\354\227\255\354\240\204\355\214\214,\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230 \354\240\225\353\246\254.md" "b/_posts/2022-10-01-DL01_\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225,\354\230\244\354\260\250\354\227\255\354\240\204\355\214\214,\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230 \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..b31027c1f61e --- /dev/null +++ "b/_posts/2022-10-01-DL01_\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225,\354\230\244\354\260\250\354\227\255\354\240\204\355\214\214,\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230 \354\240\225\353\246\254.md" @@ -0,0 +1,163 @@ +--- +layout: single +title: "경사하강법,오차역전파,활성화함수 정리" +categories: 딥러닝 +tag: [딥러닝, python, 경사하강법, 오차역전파, 활성화함수, 신경망] +toc: true +toc_sticky: true + +--- + + + + + +## 오차 역전파 + +- 순전파 : 입력 데이터를 입력층에서부터 출력층까지 정방향으로 이동시키며 출력 값을 예측해 나가는 과정 +- 역전파 : 출력층에서 발생한 오차를 입력층 쪽으로 전파시키면서 최적의 결과를 학습해 나가는 과정 + +![img2.png](/assets/images/DL01/img2.png) + +## 경사하강법 + +- 그 자리에서 loss가 작아지는 방향으로 이동하는 방법 +- 즉, 비용함수(loss)의 기울기를 구하여 기울기가 낮은 쪽으로 계속 이동하여 값을 최적화 시키는 방법이다. + +![img1.png](/assets/images/DL01/img1.png) + +- 비용함수의 기울기 = loss 변화량 / w 변화량 + - w값의 변화량에 따라 loss가 변화하는 정도 + - 즉, 모델은 학습할 때, loss가 감소하는 w로 최적화한다. + - 최적화 함수(optimizer)가 경사하강법을 수행하면서 모델을 최적화한다. + +## 기울기 소실(Vanishing Gradient) + +![img3.png](/assets/images/DL01/img3.png) + +- 깊은 층을 만들어 보니 출력층에서 시작된 가중치의 업데이트(역전파)가 처음 층까지 잘 전달되지 않는 현상 발생 +- 이를 기울기 소실이라고 함 +- 시그모이드 함수의 특성 때문 + +### sigmoid의 문제점 + +- 시그모이드 함수를 미분하면 최대치는 약 0.3임 +- 1보다 작기때문에 계속 곱하다 보면 0에 가까워져 가중치를 수정하기 어려워짐 + +![img4.png](/assets/images/DL01/img4.png) + +## 활성화 함수 종류 + +- sigmoid의 문제점을 해결하기 위해 다양한 활성화 함수가 존재 + +![img5.png](/assets/images/DL01/img5.png) + +## 최적화 함수(Optimizer)의 종류 + +### SGD(확률적 경사 하강법) + +- 경사하강법은 전체 데이터를 이용해 업데이트 하는 방법이다 +- 하지만, 실제로는 전체 데이터를 모두 활용하여 모델을 학습하기는 불가능(경사하강법은 이론상으로만 존재) +- SGD, 확률적 경사 하강법 : 확률적으로 선택된 일부 데이터를 이용해 업데이트 +- SGD를 수행할 때 확률적으로 선택할 데이터 갯수 : batch_size로 결정한다 + +![img6.png](/assets/images/DL01/img6.png) + +### batch size + +- 일반적으로 PC 메모리의 한계 및 속도 저하 때문에 대부분의 경우 한번의 epoch에 모든 데이터를 집어넣기 힘듦 +- batch_size를 줄임 + - 메모리 소모가 적음 + - 학습 속도가 느림, 정확도는 높아짐 +- batch_size를 높임 + - 메모리 소모가 큼 + - 학습 속도가 빠름, 정확도는 낮아짐 +- batch_size의 디폴트 값은 32이며 일반적으로 32, 64가 많이 사용됨 + +### 모멘텀 + +- 경사 하강법에 관성을 적용해 업데이트함 +- 현재 batch 뿐만 아니라 이전 batch 데이터의 학습결과도 반영하는 방법 +- 개선된 모멘텀 방식으로는 네스테로프 모멘텀이 있다. + +### Adagrad(에이다그래드) + +![img9.png](/assets/images/DL01/img9.png) + +- 학습을 진행하면서 학습률을 점차 줄여가는 방법 +- 처음에는 크게 학습하다가 조금씩 작게 학습함 +- 학습을 빠르고 정확하게 할 수 있는 장점이 있다. + +### 최적화 함수(Optimizer) 종류 한눈에 보기 + +![img10.png](/assets/images/DL01/img10.png) + +- 방향(스텝 방향)과 학습률(스텝 사이즈)을 모두 고려하는게 Adam +- Adam을 사용하면 기본은 간다 \ No newline at end of file diff --git "a/_posts/2022-10-05-DL02_CNN \355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" "b/_posts/2022-10-05-DL02_CNN \355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..98d519bd5821 --- /dev/null +++ "b/_posts/2022-10-05-DL02_CNN \355\225\251\354\204\261\352\263\261 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" @@ -0,0 +1,319 @@ +--- +layout: single +title: "Tensorflow:: CNN 합성곱 신경망 정리" +categories: 딥러닝 +tag: [딥러닝, python, 컨볼루젼, 합성곱, 신경망, 2D, 이미지 처리, tensorflow, CNN] +toc: true +toc_sticky: true + +--- + + + + + +## MLP에서의 이미지 분석 + +- MLP 신경망을 이미지 처리에 사용하면 이미지의 위치에 민감하게 동작하여 **위치에 종속**적인 결과를 얻게 됨 +- 이는 모든 픽셀을 연산하기 때문 +- MLP로 이미지 처리를 하기 위해서는 이미지를 1차원 벡터로 변환하고 입력층으로 사용해야 하는데, 이러면 공간적인 구조 정보가 유실되므로 좀 더 정확한 예측이 힘들다. + +# CNN (Convolution Neural Network) + +- MLP에서는 크기가 바뀌거나 이미지 데이터의 위치, 회전 정도가 다를 경우 특징 추출이 굉장히 힘들다. +- 이러한 문제를 **CNN**으로 해결할 수 있다. + +합성곱 신경망은 이미지 처리에 탁월한 성능을 보이는 신경망이고, 특성추출부와 MLP로 이루어져 있다. + +![01_1.png](/assets/images/DL02/01_1.png) + +## 특성추출부 + +- Convolution Layer(합성곱층) + + 특징들을 부각해주는 역할을 함 + +- Pooling Layer(풀링층) + + 특징이 약한 부분을 없애주는 역할 + + +**Conv Layer**는 특정 연산을 수행하기 때문에 뒤에 활성화 함수가 붙지만, **Pooling Layer**는 필요 없는 픽셀을 제거하는 역할만 수행하기 때문에 뒤에 활성화 함수가 오지 않는다. + +### 채널 + +- 합성곱 계층에서 이미지의 색상 정보를 채널이라고 부름 +- 이미지는 (높이, 너비, 채널)형태의 3차원 텐서 +- 흑백 이미지는 채널이 1, 컬러 이미지는(RGB) 3이다. + +## 필터(=커널 = 가중치) + +합성곱층은 합성곱 연산을 통해 이미지의 특징을 추출한다. + +이때, **필터**라는 N * M 크기의 행렬로 이미지를 처음부터 끝까지(가장 왼쪽 위 > 오른쪽 아래) 순차적으로 훑으면서(**슬라이딩**) 필터와 겹쳐지는 부분의 각 이미지와 필터의 원소(**가중치**) 값을 곱해서 모두 더한 값을 출력한다. 필터를 걸쳐 출력되는 데이터를 **특성맵**(feature map)이라고 한다. + +![01_2.png](/assets/images/DL02/01_2.png) + +- 그림 설명 + + 채널이 1인 (흑백 이미지) 2차원 합성곱일 경우 입력층에 필터를 지나쳐 출력 되는 예시이다. + + **4x4**크기 Input 이미지와 **2x2**크기 kernel을 합성곱 연산할 경우 **3x3**형태의 특성맵이 출력됨. + + 물론, 필터에는 각 가중치가 존재하면서 **편향**도 존재한다. + + 예를 들어, 편향이 +1 이라면 출력되는 특성맵의 각 원소들은 +1이 되어 출력된다. + + +### 여러개의 필터 + +Dense 층을 여러개를 사용하는 것처럼 여러개의 필터를 사용할 수 있고, 각 필터의 가중치도 서로 다르다. + +여러개의 필터를 사용하면 특징 추출을 더 세밀하게 할 수 있다. + +- 채널 C개 입력 * 채널 C인 **필터가 FN개** = **채널 FN개 출력** +- 즉, **출력 데이터의 채널 수 = 필터의 개수** + +![01_3.png](/assets/images/DL02/01_3.png) + +- 우선 Input 이미지는 크기가 4X4인 상태이다. + + 채널 1인 Input 이미지에 채널 1인 2X2 kernel 3개를 사용하면 3개의 3X3 크기의 특성맵을 얻을 수 있다. + + 즉, 한 이미지의 특징을 추출한 부분을 3개로 세분화 시켰고, 이미지의 크기는 줄어들었다. + + +### 3차원 합성곱 정리 + +보통 컬러 이미지를 입력 데이터로 사용한다면 3차원 배열(높이, 너비, 채널(깊이)) 형태이다. + +이러한 경우엔 커널도 동일한 채널을 갖게 된다. + +(**입력의 채널 수와 필터의 채널 수가 같아야함**) + +- **kernel의 채널(깊이)의 수 = Input 데이터의 채널(깊이)의 수** +- **합성곱 연산 결과** : Input 데이터는 **채널 수와 상관없이 kernel 별로 1개의 특성맵**이 만들어진다.즉, **입력 데이터의 깊이와 상관없이 (높이, 너비, 1)**의 특성 맵을 얻음 +- 다만, 합성곱 연산에서 다수의 커널을 사용할 경우 : 특성 맵은 **(높이, 너비, 커널의 수)** 크기 + + (특성 맵의 채널은 합성곱 연산에 사용된 커널의 수) + + +![01_6.png](/assets/images/DL02/01_6.png) + +## 패딩(padding) + +합성곱 연산을 수행하며 kernel을 통과할때마다 특성맵의 크기는 점점 **줄어든다**. 하지만, 복잡한 학습을 위해 깊은 층을 쌓아야 한다면 크기가 점점 줄어드는 탓에 더 이상 연산이 힘들어지게 된다. + +그러므로, 여러 합성곱 연산 이후에도 특성맵의 크기를 비슷하게 유지되도록 **패딩**을 수행할 수 있다. + +![01_4.png](/assets/images/DL02/01_4.png) + +- 입력 이미지의 가장 자리에 지정된 폭만큼 가상의 픽셀로 **테두리를 추가**한다. +- 그렇다면 필터의 **슬라이딩 범위가 늘어나게** 되고 kernel에서 출력되는 특성맵의 크기는 패딩하기 전보다 커지게 된다. +- 주로 0으로 채우기 대문에 제로 패딩(zero padding)이라고도 함 + +## 축소 샘플링 + +합성곱 수행 후 다음 계층으로 전달할 때, 모든 정보를 전달하지 않고 일부만 샘플링하여 넘겨주는 작업을 말한다. 크게 **스트라이드(stride)**와 **풀링(pooling)**이 있다. + +## 스트라이드(stride) + +그림에서는 kernel이 Input 이미지에 한 칸씩 이동(슬라이딩)하면서 합성곱 연산을 수행한다. + +하지만, 커널의 슬리이딩 범위 또한 사용자가 정할 수 있다. + +이러한 이동 범위를 **스트라이드(stride)**라고 한다. + +- kernel이 2픽셀. 3픽셀씩 건너 뛰면서 합성곱 연산을 수행하는 방법 +- stride2 또는 stride3이라고 하는데, 이렇게 하면 **ouput 특성맵의 크기를 더 줄일 수 있다.** + +## 풀링(pooling) + +일반적으로 합성곱 층(합성곱 연산 + 활성화 함수) 다음에는 풀링 층을 추가한다. + +합성곱 층 ouput인 특성맵이 크고 복잡하다면 이를 **축소(다운 샘플링)**해야 한다. 이 과정을 풀링 연산이라 하며, 이러한 연산을 하는 층이 **풀링 층**이다. + +- 일반적으로 **최대 풀링(max pooling)**과 **평균 풀링(average pooling)**이 사용된다. +- **최대 풀링**은 지역 내 최대 값을 뽑아내는 방법이다. +- 최대 풀링을 하면 지역 내의 대표 정보만 남기고 나머지 신호들을 제거하는 효과가 있음 +- **평균 풀링**은 지역 내 평균 값을 뽑아내는 방법이다. + +![01_5.png](/assets/images/DL02/01_5.png) + +- 2X2 Max Pooling 수행 + + 4X4 특성맵을 2X2 맥스 풀링하면 절반으로 특성맵이 작아지는 것을 확인할 수 있다. + + 풀링은 통상적으로 2X2 풀링을 사용한다. + + +## 합성곱과 풀링의 차이 + +풀링도 합성곱 연산과 유사하게 커널을 슬라이딩 시켜 특성 맵을 얻으므로 유사한 느낌을 가질 수 있다. + +하지만, 풀링은 합성곱 연산과 달리 **곱하기나(가중치)** **더하는(편향)** 연산이 없고, 풀링 과정에서 커널이 슬라이딩할 때 서로 겹치지 않는다. + +## 합성곱층 + 풀링층 사용 + +앞서 확인한 내용들을 바탕으로 컨볼루션 층과 풀링 층은 쌍으로 보통 사용한다. + +(컨볼루션 층 + 풀링 층) 또는 (컨볼루션 층 + 컨볼루션 층 + 풀링 층) 이런 식으로 사용하게 되는데, + +2차원 이상의 크기로 출력됨 + +그 후에 밀집층(은닉층+출력층 또는 출력층)을 사용하여 원하는 결과값을 얻기 위해 1차원 배열로 풀어서 펼치는 작업 수행, 따라서 Flatten을 사용하여 1차원 크기로 바꾸어 사용한다. + +## CNN 모델 만들기 + +```python +from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +``` + +- Conv2D : 2D 이미지 데이터에 대해 특징이 되는 부분들을 부각시켜줌 + - input_shape : Input 데이터 크기(height, width, channel) + - filters : 필터의 갯수 + - kernel_size : 필터의 크기 + - padding=‘same’ : 원본 데이터의 크기에 맞게 알아서 패딩 적용(valid : 적용X) +- MaxPool2D : 2D 이미지 데이터에 대해 필요 없는 정보를 삭제(축소 샘플링) + - pool_size : 디폴트 값은 2(2 X 2) + +```python +# 모델 설계 +cnn_model = Sequential() + +# 특성 추출부(Conv층) +cnn_model.add(Conv2D(input_shape=(224, 224, 3), filters=128, kernel_size=(3, 3), padding='same', activation='relu')) + +# 특성 추출부(Pooling층) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu')) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu')) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu'))cnn_model.add(MaxPool2D()) + +# 분류기(MLP) +cnn_model.add(Flatten()) +cnn_model.add(Dense(128, activation='relu')) +cnn_model.add(Dense(64, activation='relu')) +cnn_model.add(Dense(32, activation='relu')) +cnn_model.add(Dense(3, activation='softmax')) +``` + +- 생성한 CNN 모델 정보 확인하기 + +```python +cnn_model.summary() +``` + +``` +Model: "sequential_1" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + conv2d (Conv2D) (None, 224, 224, 128) 3584 + + max_pooling2d (MaxPooling2D (None, 112, 112, 128) 0 + ) + + conv2d_1 (Conv2D) (None, 112, 112, 256) 295168 + + max_pooling2d_1 (MaxPooling (None, 56, 56, 256) 0 + 2D) + + conv2d_2 (Conv2D) (None, 56, 56, 128) 295040 + + max_pooling2d_2 (MaxPooling (None, 28, 28, 128) 0 + 2D) + + conv2d_3 (Conv2D) (None, 28, 28, 64) 73792 + + max_pooling2d_3 (MaxPooling (None, 14, 14, 64) 0 + 2D) + + flatten_1 (Flatten) (None, 12544) 0 + + dense_5 (Dense) (None, 128) 1605760 + + dense_6 (Dense) (None, 64) 8256 + + dense_7 (Dense) (None, 32) 2080 + + dense_8 (Dense) (None, 3) 99 + +================================================================= +Total params: 2,283,779 +Trainable params: 2,283,779 +Non-trainable params: 0 +_________________________________________________________________ +``` \ No newline at end of file diff --git "a/_posts/2022-10-09-springboot01_Spring Boot \355\224\204\353\241\234\354\240\235\355\212\270 \354\213\234\354\236\221.md" "b/_posts/2022-10-09-springboot01_Spring Boot \355\224\204\353\241\234\354\240\235\355\212\270 \354\213\234\354\236\221.md" new file mode 100644 index 000000000000..a42d2f4f0c85 --- /dev/null +++ "b/_posts/2022-10-09-springboot01_Spring Boot \355\224\204\353\241\234\354\240\235\355\212\270 \354\213\234\354\236\221.md" @@ -0,0 +1,282 @@ +--- +layout: single +title: "Spring Boot 프로젝트 시작" +categories: SpringBoot +tag: [Java, Spring, Spring Boot, STS, Eclipse] +toc: true +toc_sticky: true + +--- + + + + + + +## STS로 스프링 부트 시작하기 + +- Java Development Kit(JDK): 8이상 (11이상 권장) +- STS 다운로드 : [https://spring.io/tools](https://spring.io/tools) + +## 프로젝트 생성하기 + +Spring Initializer로 프로젝트 세팅 후 STS에서 프로젝트를 시작하는 방법이다. + +[https://start.spring.io/](https://start.spring.io/) + +![00_1.png](/assets/images/springboot01/00_1.png) + +- 프로젝트 환경 + - Tool : STS + - build : Maven + - Language : Java + - Spring Boot Version : 2.7.4 + - Packageing : Jar + - JAVA Version : 8 + +이니셜라이저를 사용하게 되면 프로젝트를 좀 더 간편하게 생성할 수 있다. + +필요한 기능을 사용하기 위해 우측의 Dependencies에서 선택하여 프로젝트를 생성할 수 있기 때문에 초반 세팅에 귀찮은 작업에 낭비되는 시간을 절약할 수 있다. + +프로젝트 셋팅 완료 후 다운로드 받은 후, 해당 파일을 STS의 workspace로 이동시킨다. + +## Spring Boot 프로젝트 설정 + +## 1. porm.xml 설정 + +### **POM(프로젝트 객체 모델(Project Object Model))** + +- Maven의 기능을 이용하기 위해서 POM이 사용된다. +- POM은 pom.xml파일을 말하며 pom.xml은 Maven을 이용하는 프로젝트의 root에 존재하는 xml 파일이다. + + (하나의 자바 프로젝트에 빌드 툴을 Maven으로 설정하면, 프로젝트 최상위 디렉토리에 "pom.xml"이라는 파일이 생성된다.) + +- 파일은 프로젝트마다 1개이며, pom.xml만 보면 프로젝트의 모든 설정, 의존성 등을 알 수 있다. +- 다른 파일이름으로 지정할 수도 있다. (mvn -f 파일명.xml test). 하지만 pom.xml으로 사용하기를 권장 + +**ex) pom.xml 예시** + +```xml + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.4 + + + com.example + demo + 0.0.1-SNAPSHOT + demo + Demo project for Spring Boot + + 1.8 + + + + org.springframework.boot + spring-boot-starter-web + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.2.2 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + +``` + +### 엘리먼트 + +- modelVersion : POM model의 버전 +- parent : 프로젝트의 계층 정보 +- groupId : 프로젝트를 생성하는 조직의 고유 아이디를 결정한다. 일반적으로 도메인 이름을 거꾸로 적는다. +- artifactId : 프로젝트 빌드시 파일 대표이름 이다. groupId 내에서 유일해야 한다. Maven을 이용하여 빌드시 다음과 같은 규칙으로 파일이 생성 된다. + + artifactid-version.packaging. 위 예의 경우 빌드할 경우 bo-0.0.1-SNAPSHOT.war 파일이 생성된다.  (하단 예시 파일 참고) + +- version : 프로젝트의 현재 버전, 프로젝트 개발 중일 때는 SNAPSHOT을 접미사로 사용. +- packaging : 패키징 유형(jar, war, ear 등) +- name : 프로젝트, 프로젝트 이름 +- description : 프로젝트에 대한 간략한 설명 +- url : 프로젝트에 대한 참고 Reference 사이트 +- properties : 버전관리시 용이 하다. ex) 하당 자바 버전을 선언 하고 dependencies에서 다음과 같이 활용 가능 하다. + + ${java.version} + +- dependencies : dependencies태그 안에는 프로젝트와 의존 관계에 있는 라이브러리들을 관리 한다. +- build : 빌드에 사용할 플러그인 목록 + +### 라이브러리 + +Spring부트는 spring-boot-starter로 시작하는 라이브러리를 제공한다. starter-parent에 지정된 라이브러리 버전을 따른다. + +- spring-boot-starter-web + + : Spring MVC를 사용한 RESTful서비스를 개발하는데 사용. + +- spring-boot-starter-test + + : Junit, Hamcrest, Mockito를 포함하는 스프링 어플리케이션을 테스트 가능하도록 한다. + +- spring-boot-devtools + + : devtools는 Spring boot에서 제공하는 개발 편의를 위한 모듈이다. 쉽게 말하면 브라우저로 전송되는 내용들에 대한 코드가 변경되면, **자동으로 어플리케이션을 재시작**하여 브라우저에도 업데이트를 해주는 역할을 한다. + +- mybatis-spring-boot-starter + + : 스프링부트 위에 MyBatis 애플리케이션을 빠르게 빌드 할 수 있다. + + - DataSource 를 자동 감지합니다. + - SqlSessionFactory 를 전달 하는 인스턴스를 자동 생성하고 등록합니다 + - DataSource.SqlSessionFactoryBean 의 인스턴스를 만들고 등록합니다. + - @Mapper주석이 표시된 매퍼를 자동 스캔하고에 연결합니다. + - SqlSessionTemplateSpring 컨텍스트에 등록하여 Bean에 주입 할 수 있도록합니다. +- mysql-connector-java + + : 스프링부트에서 MySQL을 사용하기 위한 라이브러리 + +- lombok + + : Java 라이브러리로 반복되는 getter, setter, toString 등의 메서드 작성 코드를 줄여주는 코드 다이어트 라이브러리 + +- spring-boot-starter-thymeleaf + + : ThymeLeaf 템플릿을 사용하기 위한 라이브러리 + + +## 2. application.properties 설정 + +이 파일은 스프링부트가 애플리케이션을 구동할 때 자동으로 로딩하는 파일이다. + +key - value 형식으로 값을 정의하면 애플리케이션에서 참조하여 사용할 수 있다. + +![01_1.png](/assets/images/springboot01/01_1.png) + +- url을 호출할 때 필요한 context-path +- Server 포트 설정 + + 기본 포트는 8080 + +- JSP View Resolver(JSP 사용할 때) +- MySQL 접속 정보 +- mapper.xml 경로 설정(별도의 경로를 사용할 때 설정) +- ThymeLeaf 설정 + + 기본 경로는 classpath:/templates/ \ No newline at end of file diff --git "a/_posts/2022-10-10-DL03_\354\240\204\354\235\264\355\225\231\354\212\265 fine_tuning.md" "b/_posts/2022-10-10-DL03_\354\240\204\354\235\264\355\225\231\354\212\265 fine_tuning.md" new file mode 100644 index 000000000000..c3e891687584 --- /dev/null +++ "b/_posts/2022-10-10-DL03_\354\240\204\354\235\264\355\225\231\354\212\265 fine_tuning.md" @@ -0,0 +1,106 @@ +--- +layout: single +title: "Tensorflow:: 전이학습, Fine tuning" +categories: 딥러닝 +tag: [딥러닝, python, 전이학습, 사전학습, Fine tuning, tensorflow] +toc: true +toc_sticky: true + +--- + + + + + +전이학습이란 다른 데이터 셋으로 이미 학습한 모델을 유사한 다른 데이터를 인식하는데 사용하는 기법 + +- 이 방법은 특히 새로 훈련시킬 데이터가 충분히 확보되지 못한 경우에 높은 학습 효율을 높여줌 +- 전이학습 모델을 적절히 이용하는 방법은 특성 추출(feature extraction) 방식과 미세 조정(fine-tuning) 방식이 있다. + +### 전이학습 - 특성 추출 방식(feature extraction) + +![02_1.png](/assets/images/DL03/02_1.png) + +CNN 층에서 특성추출부만 가져와서 사용하는 방식이다. + +- 특성추출부 부분만 사용하는 이유는 분류기(MLP)의 경우 우리가 해결 하고자 하는 문제에 맞게 새로 설정해줘야 하기 때문 +- 단, 새롭게 분류할 클래스의 종류가 사전 학습에 사용된 데이터와 특징이 매우 다르면, 특성추출부 전체를 재사용해서는 안되고 앞 단의 일부 계층만을 재사용해야 함(심플한 특징들만 추출해내기 위해) + +### 전이학습 - 미세 조정 방식(fine-tuning) + +![02_2.png](/assets/images/DL03/02_2.png) + +'사전 학습된 모델의 가중치’ 를 목적에 맞게 전체 또는 일부를 재학습시키는 방식이다. + +특성 추출부의 층들 중 하단부 몇 개의 계층을 전결합층 분류기(MLP)와 함께 새로 학습시킨다. + +- 처음부터 특성추출부 계층들과 분류기(MLP)를 같이 훈련시키면 새롭게 만든 분류기에서 발생하는 큰 에러 값으로 인해, 특성추출부에서 사전 학습된 가중치가 많이 손실될 수 있음 +- 처음에는 분류기(MLP)의 파라미터가 랜덤하게 초기화 되어 있으므로 컨볼루션 베이스 중 앞 단 계층들을 고정(동결)하고 뒷 단의 일부 계층만 학습이 가능하게 설정한 후, MLP와 같이 학습시켜 +파라미터(w, b) 들을 적당하게 잡아 준다. \ No newline at end of file diff --git "a/_posts/2022-10-14-DL04_\353\213\244\354\244\221\353\266\204\353\245\230_\353\252\250\353\215\270_\353\247\214\353\223\244\352\270\260(3\354\242\205\353\245\230_\353\217\231\353\254\274).md" "b/_posts/2022-10-14-DL04_\353\213\244\354\244\221\353\266\204\353\245\230_\353\252\250\353\215\270_\353\247\214\353\223\244\352\270\260(3\354\242\205\353\245\230_\353\217\231\353\254\274).md" new file mode 100644 index 000000000000..c344d3387c1b --- /dev/null +++ "b/_posts/2022-10-14-DL04_\353\213\244\354\244\221\353\266\204\353\245\230_\353\252\250\353\215\270_\353\247\214\353\223\244\352\270\260(3\354\242\205\353\245\230_\353\217\231\353\254\274).md" @@ -0,0 +1,688 @@ +--- +layout: single +title: "Tensorflow:: 다중분류_모델_만들기(3종류_동물)" +categories: 딥러닝 +tag: [딥러닝, python, 전이학습, 사전학습, Fine tuning, tensorflow, 다중분류, 이미지, CNN] +toc: true +toc_sticky: true + +--- + + + + + +# 목표 + +1. CNN망 직접 설계하여 이미지 다중분류 하기(3개의 클래스) +2. VGG16모델 전이학습 활용하여 모델 보완 + 1. 전이학습 - 특성 추출 방식 + 2. 전이학습 - 미세 조정 방식 +3. 데이터 증식(ImageDataGenerator 사용) 활용하여 모델 보완 + +구글에 고슴도치, 햄스터, 푸들을 검색한 결과로 나온 이미지 각 400장을 크롤링하여 저장해 놓은 npz 데이터를 활용한다. + +저장된 npz 데이터를 활용하여 고슴도치, 햄스터, 푸들로 분류할 수 있는 CNN 모델 생성하기 + +## 생성한 NPZ 파일 로드 + +```python +data = np.load('/content/drive/MyDrive/Colab Notebooks/2022GJAI_DL/GJAI_DL/data/animal.npz') +``` + +```python +X_train = data['X_train'] +X_test = data['X_test'] +y_train = data['y_train'] +y_test = data['y_test'] + +X_train.shape, X_test.shape, y_train.shape, y_test.shape +``` + +``` +((960, 224, 224, 3), (240, 224, 224, 3), (960,), (240,)) +``` + +# 1. CNN 모델 만들기 + +```python +from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +``` + +- **Conv2D** : 2D 이미지 데이터에 대해 특징이 되는 부분들을 부각시켜줌 + - input_shape : Input 데이터 크기(높이 ,넓이, 채널) + - filters : 필터의 갯수 + - kernel_size : 필터의 크기 + - padding=‘same’ : 원본 데이터의 크기에 맞게 알아서 패딩 적용(valid : 적용X) +- **MaxPool2D** : 2D 이미지 데이터에 대해 필요 없는 정보를 삭제(축소 샘플링) + - pool_size : 디폴트 값은 2(2 X 2) + +```python +# 모델 설계 +cnn_model = Sequential() + +# 특성 추출부(Conv층) +cnn_model.add(Conv2D(input_shape=(224, 224, 3), filters=128, kernel_size=(3, 3), padding='same', activation='relu')) + +# 특성 추출부(Pooling) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu')) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu')) +cnn_model.add(MaxPool2D()) +cnn_model.add(Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu'))cnn_model.add(MaxPool2D()) + +# 분류기(MLP) +cnn_model.add(Flatten()) +cnn_model.add(Dense(128, activation='relu')) +cnn_model.add(Dense(64, activation='relu')) +cnn_model.add(Dense(32, activation='relu')) +cnn_model.add(Dense(3, activation='softmax')) +``` + +### **생성한 CNN 모델 정보 확인하기** + +```python +cnn_model.summary() +``` + +``` +Model: "sequential_1" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + conv2d (Conv2D) (None, 224, 224, 128) 3584 + + max_pooling2d (MaxPooling2D (None, 112, 112, 128) 0 + ) + + conv2d_1 (Conv2D) (None, 112, 112, 256) 295168 + + max_pooling2d_1 (MaxPooling (None, 56, 56, 256) 0 + 2D) + + conv2d_2 (Conv2D) (None, 56, 56, 128) 295040 + + max_pooling2d_2 (MaxPooling (None, 28, 28, 128) 0 + 2D) + + conv2d_3 (Conv2D) (None, 28, 28, 64) 73792 + + max_pooling2d_3 (MaxPooling (None, 14, 14, 64) 0 + 2D) + + flatten_1 (Flatten) (None, 12544) 0 + + dense_5 (Dense) (None, 128) 1605760 + + dense_6 (Dense) (None, 64) 8256 + + dense_7 (Dense) (None, 32) 2080 + + dense_8 (Dense) (None, 3) 99 + +================================================================= +Total params: 2,283,779 +Trainable params: 2,283,779 +Non-trainable params: 0 +_________________________________________________________________ +``` + +### **모델 컴파일** + +```python +cnn_model.compile(loss="sparse_categorical_crossentropy", + optimizer='Adam', + metrics=['acc'] + ) +``` + +### **모델 학습** + +```python +h1 = cnn_model.fit(X_train, y_train, validation_split=0.2, epochs=50, batch_size=128) +``` + +### **학습 과정 시각화** + +```python +plt.figure(figsize=(15, 5)) +plt.plot(h1.history['acc'], label='acc') +plt.plot(h1.history['val_acc'], label='val_acc') +plt.legend() +plt.show() +``` + +![output_18_0.png](/assets/images/DL04/output_18_0.png) + +훈련 데이터에서는 정확도가 높지만, 검증셋에서 정확도가 매우 낮아지는 과적합 상태를 확인할 수 있다 + +### **정확도 외에 정밀도, 재현율, F1스코어 까지 확인해보기** + +- 모델의 예측결과는 각 클래스에 대한 확률값으로 나오기 때문에(softmax) +- 가장 높은 값의 인덱스를 반환해주는 np.argmax로 변환해서 점수 확인 + +```python +from sklearn.metrics import classification_report +pred = cnn_model.predict(X_test) +print(classification_report(y_test, np.argmax(pred, axis=1))) +``` + +``` +8/8 [==============================] - 2s 151ms/step + precision recall f1-score support + + 0 0.52 0.43 0.47 76 + 1 0.53 0.43 0.47 84 + 2 0.46 0.62 0.53 80 + + accuracy 0.50 240 + macro avg 0.50 0.50 0.49 240 +weighted avg 0.50 0.50 0.49 240 +``` + +- precision(정밀도) : 모델이 True라고 분류한것 중 실제 True의 비율 +- recall(재현율) : 실제 True인 것 중 모델이 True라고 예측한 비율 +- accuracy(정확도) : 전체 중에서 모델이 옳게 예측한 비율 +- f1-score : 정밀도와 재현율의 조화평균 + +정확도는 0.50으로 낮은 결과가 나왔다. + +즉, 직접 설계한 CNN 모델로는 한번에 좋은 결과를 도출하기 어려움 + +구글에서 크롤링한 데이터이기 때문에, 좋은 결과를 얻기 위해 VGG16모델을 이용해 전이학습을 해보자. + +# 2. VGG16 전이학습 수행 + +### VGG16 모델 불러오기 + +```python +from tensorflow.keras.applications import VGG16 +``` + +```python +pre_trained_model = VGG16(include_top=False, + weights='imagenet', + input_shape=(224, 224, 3) + ) +``` + +- include_top=False : 불러온 모델의 MLP층(분류기)을 사용하지 않고 특성추출부만 사용(=특성 추출 방식) +- weights=‘imagenet’ : 이미지넷 챌린지 대회에서 학습한 해당 모델의 w,b값을 그대로 사용(default) + +### VGG16 모델 정보 확인해보기 + +```python +pre_trained_model.summary() +``` + +``` +Model: "vgg16" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + input_1 (InputLayer) [(None, 224, 224, 3)] 0 + + block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 + + block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 + + block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 + + block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 + + block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 + + block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 + + block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 + + block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 + + block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 + + block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 + + block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 + + block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 + + block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 + + block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 + + block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 + +================================================================= +Total params: 14,714,688 +Trainable params: 14,714,688 +Non-trainable params: 0 +_________________________________________________________________ +``` + +## a. 전이학습 - 특성 추출 방식 이용 + +imagenet 챌린지 대회에서는 1000개의 이미지를 분류했으나 여기선 3개의 이미지를 분류할것이기 때문에 MLP층만 다르게 설정하는 특성 추출 방식으로 전이학습을 해보자 + +- VGG16의 특성추출부를 Sequential 객체에 추가하고, Flatten을 수행하여 직접 MLP를 정의해서 사용 +- 이전에 생성했던 CNN 모델과 비교를 하기 위해 은닉층의 형태와 컴파일 작업을 동일한 형태로 수행했다. + +```python +cnn_model2 = Sequential() + +# VGG16의 특성추출부 +cnn_model2.add(pre_trained_model) +# MLP +cnn_model2.add(Flatten()) +cnn_model2.add(Dense(128, activation='relu')) +cnn_model2.add(Dense(64, activation='relu')) +cnn_model2.add(Dense(32, activation='relu')) +cnn_model2.add(Dense(3, activation='softmax')) + +cnn_model2.compile(loss="sparse_categorical_crossentropy", + optimizer='Adam', + metrics=['acc'] + ) +``` + +```python +cnn_model2.compile(loss="sparse_categorical_crossentropy", + optimizer='Adam', + metrics=['acc'] + ) +``` + +```python +cnn_model2.fit(X_train, y_train, validation_split=0.2, epochs=50, batch_size=128) +``` + +### 정확도 확인해보기 + +정확도만 먼저 비교해보기 위해 과적합 여부를 확인하기 위한 시각화는 수행하지 않았다. + +```python +pred = cnn_model2.predict(X_test) +print(classification_report(y_test, np.argmax(pred, axis=1))) +``` + +``` +8/8 [==============================] - 3s 370ms/step + precision recall f1-score support + + 0 0.63 0.71 0.67 76 + 1 0.49 0.50 0.49 84 + 2 0.50 0.42 0.46 80 + + accuracy 0.54 240 + macro avg 0.54 0.55 0.54 240 +weighted avg 0.54 0.54 0.54 240 +``` + +직접 생성한 CNN모델보다 결과는 좀 더 좋아졌지만, 아직 많이 부족하기 때문에 미세 조정 방식을 사용해보자. + +## b. 전이학습 - 미세 조정 방식 이용 + +이번엔, VGG16 특성추출부의 맨 마지막 부분의 합성곱층을 재학습하는 작업을 추가 + +VGG16 모델을 다시 불러온다. + +```python +pre_trained_model2 = VGG16(include_top=False, + weights='imagenet', + input_shape=(224, 224, 3) + ) +``` + +```python +pre_trained_model2.summary() +``` + +### **VGG16 모델의 Layer 이름에 접근해보기** + +모든 VGG16의 layer 이름을 확인해본 출력값이다. + +```python +for layer in pre_trained_model2.layers: + print(layer.name) +``` + +``` +input_2 +block1_conv1 +block1_conv2 +block1_pool +block2_conv1 +block2_conv2 +block2_pool +block3_conv1 +block3_conv2 +block3_conv3 +block3_pool +block4_conv1 +block4_conv2 +block4_conv3 +block4_pool +block5_conv1 +block5_conv2 +block5_conv3 +block5_pool +``` + +맨 마지막 층인 block5_conv3 층만 재학습 시키고 나머지 Layer는 동결하기 + +### **layer.trainable 이용** + +```python +for layer in pre_trained_model2.layers: + if layer.name == 'block5_conv3': + layer.trainable = True + else: + layer.trainable = False +pre_trained_model2.summary() +``` + +``` +Model: "vgg16" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + input_2 (InputLayer) [(None, 224, 224, 3)] 0 + + block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 + + block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 + + block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 + + block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 + + block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 + + block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 + + block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 + + block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 + + block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 + + block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 + + block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 + + block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 + + block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 + + block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 + + block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 + + block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 + +================================================================= +Total params: 14,714,688 +Trainable params: 2,359,808 +Non-trainable params: 12,354,880 +_________________________________________________________________ +``` + +summary 정보를 확인해보면 Trainable params에 block5_conv3의 param 갯수가 표시된다 + +즉, block5_conv3를 재학습 시킬 수 있다는 뜻이다. + +- Trainable params : 재학습 시킬 수 있는 파라미터 갯수 + +### **MLP 설계** + +이제 MLP(분류기)층을 설계해준다. 이전에 수행했던 특성 추출 방식과 비교해보기 위해 동일한 형태로 설정해준다. + +```python +cnn_model3 = Sequential() +# VGG16의 특성추출부 +cnn_model3.add(pre_trained_model2) +# MLP +cnn_model3.add(Flatten()) +cnn_model3.add(Dense(128, activation='relu')) +cnn_model3.add(Dense(64, activation='relu')) +cnn_model3.add(Dense(32, activation='relu')) +cnn_model3.add(Dense(3, activation='softmax')) +cnn_model3.summary() +``` + +``` +Model: "sequential_5" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + vgg16 (Functional) (None, 7, 7, 512) 14714688 + + flatten_5 (Flatten) (None, 25088) 0 + + dense_21 (Dense) (None, 128) 3211392 + + dense_22 (Dense) (None, 64) 8256 + + dense_23 (Dense) (None, 32) 2080 + + dense_24 (Dense) (None, 3) 99 + +================================================================= +Total params: 17,936,515 +Trainable params: 5,581,635 +Non-trainable params: 12,354,880 +_________________________________________________________________ +``` + +- MLP를 직접 추가한 모델 + + Trainable params에 MLP 파라미터 갯수까지 추가된 걸 확인할 수 있다. + + 즉, 마지막 conv층 한개와 MLP(분류기)층을 다시 수행하고자 하는 목표에 맞게 재학습하게 될것이다. + + +### **모델 컴파일, 학습 및 결과** + +```python +cnn_model3.compile(loss="sparse_categorical_crossentropy", + optimizer='Adam', + metrics=['acc'] + ) +``` + +```python +cnn_model3.fit(X_train, y_train, validation_split=0.2, epochs=50, batch_size=128) +``` + +```python +pred = cnn_model3.predict(X_test) +print(classification_report(y_test, np.argmax(pred, axis=1))) +``` + +``` +8/8 [==============================] - 1s 155ms/step + precision recall f1-score support + + 0 0.85 0.79 0.82 76 + 1 0.80 0.86 0.83 84 + 2 0.91 0.90 0.91 80 + + accuracy 0.85 240 + macro avg 0.85 0.85 0.85 240 +weighted avg 0.85 0.85 0.85 240 +``` + +VGG16 모델을 미세 조정 방식으로 학습해본 결과 정확도는 0.85로 비교적 좋은 결과가 나왔다. + +즉, VGG16모델을 전이학습을 진행한 결과 직접 설계한 CNN모델에 비해 훨씬 결과가 잘 나오는 것을 확인할 수 있다. + +# 3. 데이터 증강(Data Augmantation) + +- 기존 이미지와 유사한 이미지를 추가로 생성하여 학습시 반영해주는 데이터 증식 기법 + +## ImageDataGenerator + +- 이미지 데이터를 생성하기 위한 조건을 설정할 수 있다. +- rotation_range : 이미지 회전 각도 설정 +- width_shift_range : 수평(x축) 이동 범위 설정 +- height_shift_range : 수직(y축) 이동 범위 설정 +- zoom_range : 축소/확대 비율 설정 +- horizontal_flip : 수평 방향으로 뒤집기 여부 설정 +- fill_mode : 이미지가 변형되면서 비는 공간에 어떻게 픽셀로 채워줄지(nearest: 가장 가까운 픽셀로 채우기) + +### **ImageDataGenerator 객체 생성** + +- 필요한 설정을 파라미터로 설정함 + +```python +from tensorflow.keras.preprocessing.image import ImageDataGeneratoraug = ImageDataGenerator(rotation_range=30, width_shift_range=0.2, # 20% 내외 수평이동 height_shift_range=0.2, # 20% 내외 수직이동 zoom_range=0.2, # 0.8 ~ 1.2배로 축소/확대 horizontal_flip=True, # 수평방향으로 뒤집기 fill_mode='nearest' ) +``` + +### **VGG16 모델 불러오기** + +- 목적에 맞게 학습시키기 위해 마지막 합성곱층 외에 동결시키기(전이학습 - 미세 조정 방식) +- VGG16의 마지막 합성곱층 이름은 block5_conv3로 확인할 수 있음 + +```python +pre_trained_model3 = VGG16(include_top=False, weights='imagenet', input_shape=(224, 224, 3) )for layer in pre_trained_model3.layers: if layer.name == 'block5_conv3': layer.trainable = True else: layer.trainable = False +``` + +``` +Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5 +58889256/58889256 [==============================] - 0s 0us/step +``` + +### **MLP(분류기) 정의하기** + +- 목적에 맞게 입력층, 은닉층, 출력층 생성 +- 활성화함수 설정 + +```python +cnn_model4 = Sequential()# VGG16의 특성추출부cnn_model4.add(pre_trained_model3)# MLPcnn_model4.add(Flatten())cnn_model4.add(Dense(128, activation='relu'))cnn_model4.add(Dense(64, activation='relu'))cnn_model4.add(Dense(32, activation='relu'))cnn_model4.add(Dense(3, activation='softmax')) +``` + +### **모델 컴파일하기** + +```python +cnn_model4.compile(loss='sparse_categorical_crossentropy', optimizer='Adam', metrics=['acc']) +``` + +### **ImageDataGenerator로 설정한 조건으로 모델 학습** + +- ImageDataGenerator를 사용하여 학습하는 방법 + 1. .flow(x, y) + 2. .flow_from_directory(directory) +- aug.flow() : ImageDataGenerator로 설정한 조건으로 생성된 이미지로 학습에 적용시켜준다. +- steps_per_epoch = (훈련 샘플수 / 배치 사이즈) : 제너레이터로부터 얼마나 많은 샘플을 뽑을 것인지 결정 + - steps_per_epoch를 (X_train 길이 / batch_size) 즉, 7.5로 설정이 되면 한 epoch당 128개의 이미지를 활용하므로(batch_size때문에) 1epoch당 총 960개의 데이터를 활용하게 된다. +- 1epoch 때는 증강된 이미지 960개로 학습, 2epoch떄는 960개 추가되어 총 1920개로 학습 + +```python +cnn_model4.fit(aug.flow(X_train, y_train, batch_size=128), + steps_per_epoch=len(X_train) / 128, + epochs=50 + ) +``` + +```python +from sklearn.metrics import classification_report +pred = cnn_model4.predict(X_test) +print(classification_report(y_test, np.argmax(pred, axis=1))) +``` + +``` +8/8 [==============================] - 1s 156ms/step + precision recall f1-score support + + 0 0.80 0.93 0.86 76 + 1 0.96 0.79 0.86 84 + 2 0.89 0.91 0.90 80 + + accuracy 0.88 240 + macro avg 0.88 0.88 0.87 240 +weighted avg 0.88 0.88 0.87 240 +``` + +- ImageDataGenerator로 데이터 증식을 해서 학습하면 정확도가 약 88%로 더 나은 결과를 확인할 수 있음 +- 데이터의 수가 적을 경우 데이터 증강을 진행한 후 정확도가 더 향상됨 +- 데이터의 종류에 따라 정확도 개선의 정도는 다를 수 있음 \ No newline at end of file diff --git "a/_posts/2022-10-16-springboot02_Spring Boot \354\227\220\354\204\234 jsessionid \353\254\270\354\240\234 \355\225\264\352\262\260.md" "b/_posts/2022-10-16-springboot02_Spring Boot \354\227\220\354\204\234 jsessionid \353\254\270\354\240\234 \355\225\264\352\262\260.md" new file mode 100644 index 000000000000..d4a2e6d627a1 --- /dev/null +++ "b/_posts/2022-10-16-springboot02_Spring Boot \354\227\220\354\204\234 jsessionid \353\254\270\354\240\234 \355\225\264\352\262\260.md" @@ -0,0 +1,121 @@ +--- +layout: single +title: "Spring Boot 에서 jsessionid 문제 해결" +categories: SpringBoot +tag: [Java, Spring, Spring Boot, STS, Eclipse] +toc: true +toc_sticky: true + +--- + + + + + + +## jsessionid란? + +- jsessionid는 새 세션이 만들어지면 클라이언트가 쿠키를 지원하는지 여부를 서버가 알 수 없으므로, 쿠키와 URL에 모두 jsessionid를 만들어 주는 것을 의미한다. +- url에 붙거나 헤더에 붙여서 표시된다. +- jsessionid를 탈취당하면 **사용자 ID, Password를 몰라도 접근이 가능하게 된다.** + +# 해결방법 + +### 1. application.properties에 아래와 같은 옵션을 추가한다. + +![00_1.png](/assets/images/springboot02/00_1.png) + +### 2. 클래스 계승 시작 SpringBootServletInitializer 재 작성 onStartup 방법 + +```java +@Override +public void onStartup(ServletContext servletContext) throws ServletException { + super.onStartup(servletContext); + servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE)); + SessionCookieConfig sessionCookieConfig=servletContext.getSessionCookieConfig(); + sessionCookieConfig.setHttpOnly(true); +} +``` + +### 3. @ Configuration 설정 클래스 에 bean 등록 + +ServletContextInitializer 클래스를 Bean객체로 등록하여 스프링 부트가 jseesion과 관련된 설정을 읽도록 해 주면 된다. + +```java +@Bean +public ServletContextInitializer servletContextInitializer1() { + return new ServletContextInitializer() { + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE) ); + } + }; +} +``` \ No newline at end of file diff --git "a/_posts/2022-10-20-DL05_\352\260\235\354\262\264 \355\203\220\354\247\200.md" "b/_posts/2022-10-20-DL05_\352\260\235\354\262\264 \355\203\220\354\247\200.md" new file mode 100644 index 000000000000..e1ec57589c19 --- /dev/null +++ "b/_posts/2022-10-20-DL05_\352\260\235\354\262\264 \355\203\220\354\247\200.md" @@ -0,0 +1,211 @@ +--- +layout: single +title: "객체 탐지 기술 정리" +categories: 딥러닝 +tag: [딥러닝, python, 객체탐지] +toc: true +toc_sticky: true + +--- + + + + + +# 객체 탐지란 + +- 이미지 내에서 객체(사람, 사물 등)를 감지해 내는 것 + +![05_1.png](/assets/images/DL05/05_1.png) + +# 평가지표 + +## IoU(Intersection over Union) + +- 이미지 내에 있는 **하나의 객체**를 탐지할 때 사용하는 평가지표이다. +- 실제 객체 면적과 모델이 예측한 면적의 **(교차 영역 / 전체 영역) X 100** +- 범위는 **0 ~ 1.0 사이** (일반적으로 **0.5**가 넘으면 맞게 예측했다고 판단) + +![05_2.png](/assets/images/DL05/05_2.png) + +## mAP(mean Average Precision) + +- 한 이미지에서 **여러 개의 객체(클래스)**를 찾을 때 사용되는 평가지표이다. +- 각 객체(클래스)별 평균 정밀도(AP)를 계산한 후 **클래스 전체에 대한 평균(mean)**을 구하는 방식으로 범위값은 0 ~ 1.0 사이 +- IoU 기준에 따라 mAP는 달라진다(IoU가 높으면 mAP는 낮아짐) + +## 평균 정밀도(AP) + +- 일반적으로 정밀도와 재현율(Recall)은 **반비례** 관계이다. +- 두 값을 모두 고려하여 모델의 성능을 판단하는 것이 합리적이다. +- 재현율의 11개 지점(0.0 ~ 1.0)에 대해 정밀도를 구해서(11점 보간법) 평균을 낸 것이 AP이다. + +# 객체 탐지 알고리즘 + +## 1. Traditional Detection Methods + +- **슬라이딩 윈도우(Sliding Window)** + + 고정된 크기의 Window(=초록박스)로 이미지의 좌상단부터 우하단으로 **일일이 객체를 검출**해 나가는 방식 + +- **문제점** + + 객체가 없는 영역도 무조건 Sliding해야 하며 여러 Scale의 이미지를 스캔하여 검출하는 방식이므로 **수행시간은 늘고, 검출성능은 떨어진다.** + + +## 2. Two-stage detector + +- **영역추정(Region Proposal)**과 **탐지(Detection)** 두 단계를 따로 수행하는 방식 + + Sliding Window의 비효율성으로 인해 R-CNN 알고리즘에서는 **객체가 있을 법한 2000개의 영역**을 찾고 **그 영역에 대해서만 객체를 탐지**하는 두 단계를 제안함 + + 대표적으로는 R-CNN, Fast R-CNN, Faster R-CNN 모델이 있음 + +- **영역추정의 문제점** + + 객체들이 각기 다른 크기와 형태를 가지고 있다면 후보 영역을 찾는 정확도가 떨어지게 됨 + + 영역추정의 정확도를 향상시키기 위해 **미리 이미지에서 객체 영역을 분할**해 두면 후보 영역을 찾기가 더 쉽지 않을까 연구 진행 + +- **선택적 검색(Selective Search)** + + 영역추정의 문제점을 해결하기 위해 고안된 방법 + + 1. 처음에는 분할된 모든 부분들을 Bounding box로 만들어 리스트에 추가 + 2. 색상, 무늬, 크기, 형태에 따라 **유사도가 비슷한 부분들을 그룹핑**(Bbox 개수 감소) + 3. 1, 2단계를 계속 반복 + + +## 3. One-stage detector + +Two-stage detector는 Selective search 방식으로 인해 과거 대비 높은 정확도로 객체 탐지가 가능했지만, 여전히 낮은 속도로 **실시간 적용**은 어려웠음 + +One-stage detector는 **영역추정**과 **객체탐지**를 통합해 **한 번에 수행** + +가장 큰 장점은 탐지 속도의 획기적인 향상으로 **실시간 탐지가 가능**하다. + +# YOLO(You Only Look Once) + +- 대표적인 **One-stage detector** 방식 실시간 객체 검출 알고리즘 + - **객체 영역 판단**과 **객체 인식**을 동시에 진행하는 방식 + - 기존 CNN은 이미지 전체를 하나의 레이블(클래스)로 표시한다면, Yolo는 이미지 내에 특정한 위치(영역 추정)와 객체 탐지를 동시에 진행한 후, 이를 설정된 레이블로 표시해줌 +- 16년 **version1**부터 22년 **version7**까지 오픈소스로 출시됨 +- Yolo v1(GoogLeNet 적용)은 Two-stage detector의 Faster RCNN(vgg16 적용)보다 6배 빠른 속도로 논문에 기재됨 + +## YOLO(You Only Look Once) - v1 + +![05_3.png](/assets/images/DL05/05_3.png) + +- 입력 이미지(448x448x3)를 7x7 Grid 영역으로 나눔 +- 각 Grid cell당 2개의 Bounding Box를 생성(총 98개) +- 각각의 Bbox는 **x, y, w, h**와 **confidence**로 구성됨 +- **x, y**는 Bbox의 중심점, **w, h**는 너비, 높이 +ex) x가 cell의 가장 왼쪽에 있다면 0이고 y가 cell의 중간에 있다면 0.5 +ex) 바운딩 박스의 w가 이미지 전체 너비의 절반이라면 w는 0.5 +- **Confidence**는 Bbox가 객체를 포함한다는 예측을 얼마나 확신 하는지에 대한 지표 + +![05_4.png](/assets/images/DL05/05_4.png) + +- **Pr** : Grid Cell 내에 물체가 존재할 확률 (존재하면 1, 존재하지 않으면 0) +- confidence가 **0.5 이하**인 Bbox는 모두 삭제(0.5라는 기준은 사용자 지정 가능) +- 또한 confidence가 **가장 높은** Bbox만 남기고, 중복된다면 첫번째를 제외한 나머지 Bbox들은 삭제하여 **한 객체당 하나의 Bbox만 남김** + +## v2 + +- Bbox의 개수를 늘리고 GoogLeNet 대신 **Darknet-19** 모델을 사용하는 등 v1에 비해 **mAP 향상** +- Multi-Scaling기법을 사용하여 v1의 문제점인 **작은 객체에 대한 인식률 향상** + +## v3 + +- Darknet-53 모델로 변경하고 내부 구조를 조정하여 **FPS를 2배 이상 향상** +- 특성맵의 크기를 조절하여 크기가 **큰 객체의 검출 성능 향상** +- 다수의 객체 예측 시 softmax 대신 **개별 클래스별 sigmoid를 활용**하여 검출 + + (하나의 Bbox안에 복수의 객체가 존재하는 경우 softmax의 성능이 떨어짐) + + +## v4 + +- CSPDarknet53, SPP, PAN, BoF, Bos 등의 기법을 통해 v3에 비해 **mAP, FPS를 각각 10%, 12%씩 향상** + +## v5 ~ v6 + +- 논문 없이 깃 허브로 코드만 공유 +- V4에 비해 **낮은 용량, 빠른 속도(높은 FPS), 비슷한 성능(mAP)** +- Darknet 대신 **Pytorch**로 구현 +- 검출되는 객체의 **크기 별 전용 버전인 s, m, l, x**로 버전 세분화 +- Pascal VOC 데이터 셋 대신 **COCO 데이터 셋(20만개, 클래스 80개)**으로 훈련 + +## v7 + +- COCO 데이터 셋 기준 30FPS 이상의 실시간 감지에서 **AP 56.8%로 Yolo버전 중 가장 높음** +- 인간의 포즈를 추정할 수 있는 **포즈추정 모델 포함**(Yolo에서 첫 등장) + +![05_5.png](/assets/images/DL05/05_5.png) \ No newline at end of file diff --git "a/_posts/2022-10-22-DL06_Yolov5 \354\213\244\354\212\265.md" "b/_posts/2022-10-22-DL06_Yolov5 \354\213\244\354\212\265.md" new file mode 100644 index 000000000000..0d1dc8f493e8 --- /dev/null +++ "b/_posts/2022-10-22-DL06_Yolov5 \354\213\244\354\212\265.md" @@ -0,0 +1,320 @@ +--- +layout: single +title: "Yolov5 파인 튜닝 실습" +categories: 딥러닝 +tag: [딥러닝, python, 객체탐지, Yolov5] +toc: true +toc_sticky: true + +--- + + + + + +# 객체 탐지용 오픈소스 Yolov5 사용 + +- 객체 영역 판단과 객체 인식을 동시에 진행하는 **One-stage detector** 방식 +- 기존 CNN은 이미지 전체를 하나의 레이블(클래스)로 표시한다면, Yolo는 이미지 내에 특정한 위치(영역 추정)와 객체 탐지를 동시에 진행한 후, 이를 설정된 레이블로 표시해줌 + +## 1. 데이터 수집 + +- CNN처럼 이미지와 정답만 있으면 되는 것이 아니라 이미지 내에 정답이 될 객체들을 일일이 분리(라벨링)해서 정답으로 설정해줘야 함 +- roboflow 사이트에서 이미 라벨링 된 권총 데이터 사용 https://roboflow.com/ +- 실제 프로젝트에서 사용할 만한 라벨링 데이터는 ‘labelimg’ 라는 툴이 있음 + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +``` + +### 라벨링 된 권총 데이터 불러오기(from roboflow) + +- 코드로 권총 데이터셋을 다운로드하면, export 폴더(images, labels 존재)와 README파일 2개, data.yaml 파일이 다운로드 된다. +- 위 파일들을 roboflow_dataset이라는 디렉토리를 생성 후 이동시켜 줌 +- images + - 실제 학습 이미지 데이터 + - labels의 첫번째 0은 권총이라는 label(class)를 의미 +- labels + - 객체에 대한 정보들이 표시되어 있음 + - 나머지 값들은 Bbox의 x, y, w, h 값을 의미 + +```python +! curl -L "https://public.roboflow.com/ds/0wHxiSXST0?key=CMDIufmI48" > roboflow.zip; unzip roboflow.zip; rm roboflow.zip +``` + +### 환경설정 및 사전작업 + +1. 소스코드 가져오기 +- Yolov5 github url : https://github.com/ultralytics/yolov5 +- 위의 url을 복사, github clone으로 yolov5 소스코드 복제해오기 +- Google Drive의 /content 내에 yolov5 코드 복제함 + +```python +%cd /content + +!git clone https://github.com/ultralytics/yolov5 +``` + +1. yolov5 구동에 필요한 라이브러리 정의 +- yolov5 폴더 내에 requirements.txt에 필요한 라이브러리 정보가 정의되어 있음 +- 로컬 환경에서 작업하면 필요한 라이브러리 버전을 맞추는데에 어려움이 있어 Colab 환경에서 실행함 + +```python +# 해당 경로 파일의 모든 내용을 출력 +%cd /content/yolov5/ + +!pip install -r requirements.txt +``` + +1. data.yaml 파일 내용 확인 +- 데이터에 대한 정보가 담겨져 있는 파일로 yolo 학습시 사용 +- data.yaml 파일 내용 출력해보기 + +```python +%cat /content/roboflow_dataset/data.yaml +``` + +``` +train: ../train/images +val: ../valid/images + +nc: 1 +names: ['pistol'] +``` + +1. 이미지 데이터 불러오기 +- glob : 많은 양의 파일들의 처리를 쉽게 해주는 라이브러리 +- glob처리하면 img_list 변수에는 이미지 데이터들의 경로값이 담기게 된다. + +```python +from glob import glob + +img_list = glob('/content/roboflow_dataset/export/images/*.jpg') +len(img_list) +``` + +``` +2971 +``` + +- Train/Val 데이터 분리 + +```python +from sklearn.model_selection import train_test_split + +train_img_list, val_img_list = train_test_split(img_list, test_size=0.2, random_state=11) +len(train_img_list), len(val_img_list) +``` + +``` +(2376, 595) +``` + +- 데이터 경로들을 하나의 txt파일에 담아주기(train, val 별도) + +```python +# train +with open('/content/roboflow_dataset/train.txt', 'w') as f: + f.write('\n'.join(train_img_list) + '\n') +# val +with open('/content/roboflow_dataset/val.txt', 'w') as f: + f.write('\n'.join(val_img_list) + '\n') +``` + +1. data.yaml 파일의 train, val 경로를 맞게 재설정해주기 +- data.yaml 파일 읽어오기 + +```python +import yaml +with open('/content/roboflow_dataset/data.yaml', 'r') as f: + data = yaml.safe_load(f)data +``` + +``` +{'train': '../train/images', + 'val': '../valid/images', + 'nc': 1, + 'names': ['pistol']} +``` + +- data.yaml은 key, value 쌍의 딕셔너리 형태로 load됨 +- 경로 재설정하기 + +```python +data['train'] = '/content/roboflow_dataset/train.txt' +data['val'] = '/content/roboflow_dataset/val.txt'data +``` + +``` +{'train': '/content/roboflow_dataset/train.txt', + 'val': '/content/roboflow_dataset/val.txt', + 'nc': 1, + 'names': ['pistol']} +``` + +- yaml.dump로 data.yaml파일에서 data의 값들을 f에 덮어씌우기 + +```python +with open('/content/roboflow_dataset/data.yaml', 'w') as f: + yaml.dump(data, f) +``` + +### 모델 학습 + +- 모델을 학습시키는데 필요한 코드 파일인 train.py를 실행시킨다. + +### train.py 옵션 + +- –img : 입력 이미지의 크기, 해당 이미지 데이터의 크기는 416 X 416이다. +- –batch : 배치 사이즈 설정(데이터의 양이 많기 때문에 메모리를 고려하여 16정도까지만 높여줌) +- –data : data.yaml 파일 경로 설정 +- –cfg : yolo 모델의 세부 모델 설정(s, m, l, x 등) +- –weights : 기존 모델에 학습되어 있는 가중치 값을 그대로 사용(사용하는 모델의 가중치를 기입해야함, yolov5s.pt), 일부는 사용 목적에 맞게 재학습되도록 설정되어 있음 +- –name : 저장되는 결과 파일명 + +```python +%cd /content/yolov5 + +!python train.py --img 416 --batch 16 --epochs 50 --data /content/roboflow_dataset/data.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt --name gun_yolov5s_results +``` + +### yolov5모델 학습 결과 해석 + + +![result1.png](/assets/images/DL06/result1.png) + +
+ +![09_3.png](/assets/images/DL06/09_3.png) + +### 1. mAP50 + +- IoU = 0.5(실제와 예측이 50% 이상 겹쳤을 때 정답이라고 본다)일 때의 점수 + +### 2. mAP50-95 + +- IoU값을 0.5에서 0.05씩 증가시키며 0.95까지의 mAP값들의 평균값 + +보통 mAP50으로 모델의 성능을 판단하지만, 더 복잡해질 상황을 고려한다면 mAP50-95와 같이 판단, 고려해야함 + +## 학습 완료 후 평가지표 + +- 학습이 완료되면 모델 학습 설정에서 지정한 결과 파일명에 해당하는 디렉토리가 생성된다. +- 해당 폴더의 ./weights의 best.pt, last.pt + - best.pt : 학습 진행 중 가장 mAP가 높았을 때의 가중치가 저장됨 + - last.pt : 마지막 epoch에서의 가중치가 저장됨 + +### 평가지표 시각화하기 + +- 평가지표들을 tensorboard로 시각화해서 결과를 보기 쉽게 출력해보기 + +```python +%load_ext tensorboard +%tensorboard --logdir /content/yolov5/runs +``` +![09_4.jpg](/assets/images/DL06/result2.png) + + +## 모델 테스트 + +- 실제로 이미지를 넣어 제대로 검출되는지 확인해보기 +- 학습에 사용되지 않은 val 데이터로 확인 + +### 1. 검증용 데이터에서 임의로 한장 불러오기 + +```python +from IPython.display import Image + +val_img_path = val_img_list[8] +Image(val_img_path) +``` + +![09_4.jpg](/assets/images/DL06/09_4.jpg) + +### 2. 학습된 yolo 모델에 객체 검출 요청하기 + +- detect.py 파일을 실행하여 모델에 요청한다 +- –weights 가중치 설정, 여기서는 best.pt(mAP가 가장 좋은 가중치)로 설정하였다. +- –conf : 0.5로 설정하였으므로 점수가 0.5보다 낮은 결과가 나오면 출력이 되지 않는다. + +```python +!python detect.py --weights /content/yolov5/runs/train/gun_yolov5s_results/weights/best.pt --img 416 --conf 0.5 --source "{val_img_path}" +``` + +![result3.png](/assets/images/DL06/result3.png) + +- 결과 확인은 runs/detect/exp로 저장되었다고 나와있음 +- 여러번 하면 exp2, exp3, … 로 저장되게 된다. +- 결과 형태를 변경하고 싶거나, 다른 처리를 위해 핸들링하기 위해선 detect.py 파일 내의 코드를 수정하면 된다. + + +![09_5.png](/assets/images/DL06/09_5.png) \ No newline at end of file diff --git a/_posts/2022-10-24-springboot03_Spring Data JPA.md b/_posts/2022-10-24-springboot03_Spring Data JPA.md new file mode 100644 index 000000000000..fbac83b23e5a --- /dev/null +++ b/_posts/2022-10-24-springboot03_Spring Data JPA.md @@ -0,0 +1,129 @@ +--- +layout: single +title: "Spring Data JPA란?" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, STS, Eclipse] +toc: true +toc_sticky: true + +--- + + + + + + + +## ORM이란? + +어플리케이션의 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑해주는 것을 의미 + +- Java의 데이터 클래스와 관계형 데이터베이스의 테이블을 매핑 + +객체지향 프로그래밍과 관계형 데이터베이스의 차이로 발생하는 제약사항을 해결해주는 역할을 수행 + +대표적으로 JPA, Hibernate 등이 있음 (Persistent API) + +## ORM의 장점 + +1. SQL 쿼리가 아닌 직관적인 코드로 데이터를 조작할 수 있음 + - 개발자가 보다 비즈니스 로직에 집중할 수 있음 +2. 재사용 및 유지보수가 편리 + - ORM은 독릭접으로 작성되어 있어 재사용이 가능 + - 매핑정보를 명확하게 설계하기 때문에 따로 데이터베이스를 볼 필요가 없음 +3. DBMS에 대한 종속성이 줄어듬 + - DBMS를 교체하는 작업을 비교적 적은 리스크로 수행 가능 + +## ORM의 단점 + +1. 복잡성이 커질 경우 ORM만으로 구현하기 어려움 + - 직접 쿼리를 구현하지 않아 복잡한 설계가 어려움 +2. 잘못 구현할 경우 속도 저하 발생 +3. 대형 쿼리는 별도의 튜닝이 필요할 수 있음 + +## JPA (Java Persistance API) + +### **Hibernate** + +ORM Framework중 하나 + +JPA의 실제 구현체 중 하나이며, 현재 JPA 구현체 중 가장 많이 사용됨 + +![00_1.png](/assets/images/springboot03/00_1.png) + +### Spring Data JPA + +Spring Framework에서 JPA를 편리하게 사용할 수 있게 지원하는 라이브러리 + +- CRUD 처리용 인터페이스 제공 +- Repository 개발 시 인터페이스만 작성하면 구현 객체를 동적으로 생성해서 주입 +- 데이터 접근 계층 개발시 인터페이스만 작성해도 됨 + +Hibernate에서 자주 사용되는 기능을 조금 더 쉽게 사용할 수 있게 구현 \ No newline at end of file diff --git "a/_posts/2022-10-30-DL07_RNN \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" "b/_posts/2022-10-30-DL07_RNN \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..90fb411a2345 --- /dev/null +++ "b/_posts/2022-10-30-DL07_RNN \354\210\234\355\231\230 \354\213\240\352\262\275\353\247\235 \354\240\225\353\246\254.md" @@ -0,0 +1,402 @@ +--- +layout: single +title: "RNN 순환 신경망 정리" +categories: 딥러닝 +tag: [딥러닝, python, 순환 신경망, RNN] +toc: true +toc_sticky: true + +--- + + + + + +# RNN의 필요성 + +- 문장을 듣고 무엇을 의미하는지 알아야 하는 서비스 제공이 가능해진다. +- 문장을 듣고 이해한다는 것은 많은 문장을 이미 학습해 놓았다는 것이다. +- 문장의 의미를 전달하려면 각 단어가 **정해진 순서대로** 입력되어야 한다. +- **과거에 입력된 데이터와 나중에 입력된 데이터 사이의 관계를 고려**해야 하는 문제가 생긴다. +- **시간적 개념**이 들어간 데이터들을 해결하기 위해 **순환신경망(RNN)**이 고안되었다. + +# 순환신경망과 일반신경망의 차이 + +- RNN은 여러 개의 데이터가 순서대로 입력되었을 때 **앞서 입력 받은 데이터의 연산 결과를 잠시 기억**해 놓는 방식이다. +- 기억된 데이터를 가지고 다음 데이터로 넘어가면서 **함께 연산**한다. + +![07_1.png](/assets/images/DL07/07_1.png) + +- **앞에서 나온 입력에 대한 결과가 뒤에서 나오는 입력 값에 영향**을 주는 것을 알 수 있다. +- 예를 들어, 비슷한 두 문장이 입력되어도 **앞에서 나온 입력 값을 구별**하여 출력 값에 반영할 수 있다. + +![07_2.png](/assets/images/DL07/07_2.png) + +- 모든 입력 값에 이 작업을 순서대로 실행하므로 같은 층을 맴도는 것처럼 보인다. +- **같은 층안에서 맴도는 성질**때문에 순환 신경망이라고 부른다. + +![07_3_1.png](/assets/images/DL07/07_3_1.png) + +### RNN 활용 데이터 종류 + +: 분석에 사용되는 특성들이 **시간적, 순차적 특징**을 지닌 데이터에 RNN 기법이 활용된다. + +- 시계열 데이터 +- 음악 데이터 +- 문장(자연어) 데이터 +- 번역 기술 등 + +### RNN 수식 살펴보기 + +![07_3_2.png](/assets/images/DL07/07_3_2.png) + +- 지금까지 신경망에서는 대부분 높은 성능을 위해 활성화 함수로 relu를 사용하였다. +- 하지만, RNN에서는 이전 가중치를 기억해야하는데, relu는 0보다 작으면 0으로 만들어버리는 성질로 인해 이전 가중치에 대한 정보를 유지할 수 없다. +- 따라서, RNN에서는 -1 ~ 1 값을 가지는 하이퍼볼릭 탄젠트(tanh)를 사용한다. + +# RNN 기본 신경망(SimpleRNN) 코드 + +```python +SimpleRNN(units=3, imput_shape=(4, 9)) +``` + +- units : 퍼셉트론(뉴런의 개수) +- input_shape : (timesteps, features) 형태의 튜플로 들어감 + - timesteps : 순환 횟수 설정, 입력 시퀀스의 크기가 된다. + + +# RNN 데이터 구조 + +![07_4.png](/assets/images/DL07/07_4.png) + +- features : 특성의 갯수 +- examples : 데이터 갯수 +- timesteps : 시간의 순서 + +# RNN 활용 구조 + +## 1. 다수 입력 단일 출력 + +![07_5.png](/assets/images/DL07/07_5.png) + +- ex) **문장을 읽고 뜻을 파악**할 때 활용 가능 + +```python +model = Sequential() +model.add(SimpleRNN(units = output_size, + input_shape=(timesteps, features))) +``` + +## 2. 단일 입력 다수 출력 + +![07_6.png](/assets/images/DL07/07_6.png) + +- ex) **사진의 캡션을 만들 때** 활용 가능 + +```python +model = Sequential() +model.add(RepeatVector(number_of_times, + input_shape=input_shape)) + +model.add(SimpleRNN(units = output_size, + return_sequences=True)) +``` + +※ number_of_times : 출력 개수 설정, ex) 3개의 캡션을 원하면 3으로 설정 + +※ return_sequences=True : SimpleRNN 신경망이 순환하며 단일 값을 계속 출력 + +## 3. 다수 입력 다수 출력 + +![07_7.png](/assets/images/DL07/07_7.png) + +- ex) **문장을 번역**할 때 활용, **Video에서 Frame 단위 분류**에 활용 가능 +- RNN층을 여러개 쌓기 위해서 활용 가능 +- 여러 층으로 쌓기 위해서는 이전 RNN층이 **다수입력 다수출력 상태**가 되어야한다. +- 그래야 **다음 RNN층의 input 형태가 이전 RNN층과 같은 형태**가 되기 때문이다 + +```python +model = Sequential() +model.add(SimpleRNN(units = output_size, + input_shape=(timesteps, features), + return_sequences=True)) +``` + +# Simple RNN의 문제점 + +## 장기 의존성 문제(Long-Term Dependency) + +활성화 함수로 tanh를 사용하기 때문에 **timesteps(순환횟수)가 길어질수록 역전파시 기울기가 점차 줄어** 학습 능력이 저하된다 + +→ **기울기 소실 문제** 발생 + +→ 시간이 지나면 이전의 입력값을 잊어버리게 된다. + +![07_8.png](/assets/images/DL07/07_8.png) + +# LSTM (Long Short Term Memory) + +: RNN의 문제점을 극복하기 위해 나온 대안 + +- 순환횟수가 많더라도 앞에서 연산한 결과를 **장기간 유지할 수 있는 ‘구조’**가 필요 +: RNN에 **메모리 셀(cell)** 추가 +- **장기기억**과 **단기기억**의 중요성을 계산해준다. +- 메모리 셀(cell) + - 시각 t에서 메모리 셀의 c에는 과거로부터 **현재시각 t까지의 필요한 대부분의 정보가 저장** + - 오차역전파 시 **tanh와 같은 활성화 함수를 통과하지 않아서 기울기 소실이 일어나지 않음** + - 데이터를 LSTM 계층 내에서만 주고 받으며 다른 계층으로는 전달하지 않음 + +## LSTM의 구조 + +- LSTM 1개는 3개의 gates**(forget, input, output)**로 구성 +- **forget gate**는 이전 상태 정보를 얼마나 버리고 얼마 만큼을 저장할지 결정하고, +- **Input gate**는 입력되는 새로운 정보를 얼마만큼 저장할지 결정하며, +- **output gate**는 현재 LSTM 셀의 어떤 부분을 다음 LSTM 셀로 전달할지를 결정 + +![07_9.png](/assets/images/DL07/07_9.png) + +- **h는 단기 상태(Short-Term state)**를 **c는 장기 상태(Long-Term state)**라고 볼 수 있음 +- 이전 스텝의 장기 기억 ct -1은 왼쪽에서 오른쪽으로 통과하면서 Forget gate를 지나면서 일부 정보를 잃고(sigmoid가 곱해지므로), Input gate로부터 덧셈(+) 연산을 통해 새로운 정보를 추가하여 현재 타임 스텝의 장기 기억 ct 가 생성 됨 +- ct는 Output gate의 tanh 함수로 전달되어 단기 상태 ht를 만듦 + +![07_10.png](/assets/images/DL07/07_10.png) + +- LSTM의 복잡성을 줄여 속도측면에서 더 빠른 효과를 볼 수 있는 **GRU**가 존재(목적에 맞는 속도에 따라 LSTM / GRU 선택) + +### 다중 LSTM Layer + +- LSTM층 또한, RNN과 마찬가지로 다중으로 쌓기 위해서는 이전 LSTM층이 **다수입력 다수출력 상태**가 되어야한다. +- 그래야 **다음 RNN층의 input 형태가 이전 RNN층과 같은 형태**가 되기 때문이다 +- LSTM, RNN층에서 순환할때마다 출력값을 만들어주는 **return_sequences=True** 옵션을 사용해야함 + +
+ +# 워드 임베딩(Word Embedding) + +- 컴퓨터가 자연어를 이해하고 효율적으로 처리하기 위해서는 **단순한 인코딩이 아닌 컴퓨터가 더 잘 이해할 수 있도록 변환** 할 필요가 있음 +- 워드 임베딩은 한 **단어의 의미를 풍부하게 만들어주는역할**(특성을 늘려주는 역할)을 함 +- 주로 **희소 표현(원 핫 인코딩)**에서 **밀집 표현(실수형태)**으로 변환하는 것을 의미 +- 밀집표현을 통해 해당 단어와 **유사한 다른 단어들의 수치(유사도)**까지 표시함 + +![07_11.png](/assets/images/DL07/07_11.png) + +- 임베딩 과정을 통해 나온 결과를 **임베딩 벡터(embedding vector)**라고 함 +- 케라스에도 제공하는 도구인 **Embedding()**은 **랜덤한 값을 가지는 밀집 벡터로 변환**한 뒤에, 인공 신경망의 가중치를 학습하게 됨 + +![07_12.png](/assets/images/DL07/07_12.png) + +### Embedding 사용 + +- **Embedding(사용하는 단어사전의 수, 한 단어를 표현할 특징의 수)**을 순환신경망층 가장 앞에 추가하기 +- 사용하는 단어 사전의 수는 **학습에 사용되는 단어의 갯수**이다 +- 한 단어를 표현할 특징의 수는 **적절한 수로 설정**해서 모델이 알아서 특징을 검출하게 해준다 + +# 순환 신경망 사용해보기 (SimpleRNN) + +## 1. 데이터 직접 준비 + +- 5개의 단어로 문자 하나하나를 단위로 하여 RNN을 사용해보기 +- “hello”, “apple”, “lobby”, “daddy”, “bobby” +- 문제 데이터 : “hell”, “appl”, “lobb”, “dadd”, “bobb” +- 정답 데이터 : “o”, “e”, “y”, “y”, “y” + +입력 데이터의 문자 갯수는 모두 4개이므로, **timesteps(순환 횟수)를 4**로 설정 + +### 학습을 위해 문자 데이터를 숫자 데이터로 인코딩하기 + +- RNN 데이터의 구조를 파악하기 위해 직접 one-hot 인코딩 수행 +- 문제, 정답 데이터에 등장하는 모든 문자(unique value)는 **h, e, l, o, a, p, b, y, d로 총 9개**이다. + - h : [1,0,0,0,0,0,0,0,0] + - e : [0,1,0,0,0,0,0,0,0] + - l : [0,0,1,0,0,0,0,0,0] + - o : [0,0,0,1,0,0,0,0,0] + - a : [0,0,0,0,1,0,0,0,0] + - p : [0,0,0,0,0,1,0,0,0] + - b : [0,0,0,0,0,0,1,0,0] + - y : [0,0,0,0,0,0,0,1,0] + - d : [0,0,0,0,0,0,0,0,1] + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# 문제 데이터 +X_train = np.array( + [ + + # 각각의 단어들 + [[1,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0],[0,0,1,0,0,0,0,0,0]], # h, e, l, l + [[0,0,0,0,1,0,0,0,0],[0,0,0,0,0,1,0,0,0],[0,0,0,0,0,1,0,0,0],[0,0,1,0,0,0,0,0,0]], # a, p, p, l + [[0,0,1,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,1,0,0]], # l, o, b, b + [[0,0,0,0,0,0,0,0,1],[0,0,0,0,1,0,0,0,0],[0,0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0,1]], # d, a, d, d + [[0,0,0,0,0,0,1,0,0],[0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,1,0,0]] # b, o, b, b + ]) + +# 정답 데이터 +y_train = np.array( + [ + [0,0,0,1,0,0,0,0,0], # o + [0,1,0,0,0,0,0,0,0], # e + [0,0,0,0,0,0,0,1,0], # y + [0,0,0,0,0,0,0,1,0], # y + [0,0,0,0,0,0,0,1,0] # y + + ]) + +X_train.shape, y_train.shape +``` + +``` +((5, 4, 9), (5, 9)) +``` + +### 데이터 구조 확인 + +- 문제 데이터의 크기 = (samples, timesteps, features) = (5, 4, 9) + - 5 : samples, 데이터의 갯수 + - 4 : timesteps, 순환 횟수 + - 9 : features, 특성 수(원핫 인코딩된 컬럼 수) +- 출력되는 정답을 알파벳 전체로 하고 싶다면 26개로 원핫 인코딩을 시켜주면 됨 +- 현재는 간단한 실습을 위해 9개의 문자로만 문제와 정답 설정 + +## 2. RNN 신경망 모델링 + +- SimpleRNN(units, input_shape=(timesteps, features)) + - units : 퍼셉트론(뉴런의 개수) + - input_shape : (timesteps, features) 형태의 튜플로 들어감 + +```python +from tensorflow.keras import Sequential +from tensorflow.keras.layers import Dense, SimpleRNN + +model = Sequential() +model.add(SimpleRNN(8, input_shape=(4, 9))) # 입력층 + 중간층 +model.add(Dense(9, activation='softmax')) # 출력층 +``` + +- 입력 시퀀스의 크기(순환 해야하는 횟수가 됨)는 4, 입력 데이터의 특성은 9 이므로 input_shapes = (4, 9) +- RNN층(중간층)에 사용되는 뉴런은 8개이다. +- 9개의 특성에서 정답을 맞춰야 하므로 출력층의 뉴런은 9이다. + +```python +model.summary() +``` + +``` +Model: "sequential_2" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + simple_rnn_2 (SimpleRNN) (None, 8) 144 + + dense_2 (Dense) (None, 9) 81 + +================================================================= +Total params: 225 +Trainable params: 225 +Non-trainable params: 0 +_________________________________________________________________ +``` + +RNN은 가중치가 두 종류가 존재한다 (과거 데이터의 가중치, 현재 데이터의 가중치) + +- 현재 데이터의 가중치 + + → 9(입력 특성) X 8(RNN층 뉴런 수) + 8(RNN층 뉴런 수) = 80 + +- 과거 데이터의 가중치 + + → 8(RNN층 뉴런 수) X 8(RNN층 뉴런 수) = 64 + + - RNN층의 순환 횟수와는 상관없이 최종적으로 출력되는 연산 결과에만 가중치가 존재하므로 +- 파라미터 갯수 → 80 + 64 = 144 + +### 모델 컴파일 및 학습 + +```python +model.compile(loss='categorical_crossentropy', + optimizer='Adam', + metrics=['acc']) + +h = model.fit(X_train, y_train, epochs=300) +``` + +### 학습 현황 시각화 + +```python +plt.figure(figsize=(15, 5)) + +plt.plot(h.history['acc'], label='acc', marker='.') +plt.legend() +plt.show() +``` + +![Untitled](/assets/images/DL07/Untitled.png) \ No newline at end of file diff --git "a/_posts/2022-11-05-DL08-1_RNN \355\231\234\354\232\251 \353\260\217 \354\213\244\354\212\265.md" "b/_posts/2022-11-05-DL08-1_RNN \355\231\234\354\232\251 \353\260\217 \354\213\244\354\212\265.md" new file mode 100644 index 000000000000..4a603e60c40c --- /dev/null +++ "b/_posts/2022-11-05-DL08-1_RNN \355\231\234\354\232\251 \353\260\217 \354\213\244\354\212\265.md" @@ -0,0 +1,387 @@ +--- +layout: single +title: "RNN 실습, 뉴스 기사 분류" +categories: 딥러닝 +tag: [딥러닝, python, 순환 신경망, RNN, 다중분류] +toc: true +toc_sticky: true + +--- + + + + + +# RNN을 활용한 로터스 뉴스 분류 + +- 영국의 뉴스 통신사 로이터의 ’기사 내용’이 들어가면 어떤 ’주제’인지 분류하는 RNN 모델 실습 + +## keras에서 제공하는 데이터셋 불러오기 + +- 실제 뉴스 기사의 내용이 이미 단어단위로 토큰화, 라벨 인코딩 되어 저장이 된 상태이다. +- 단어가 많은 경우 원핫인코딩 상태로 저장을 한다면, 저장공간 측면에서 매우 비효율적임 +- 또한, 텍스트 처리 분야에서는 문제 데이터에 라벨 인코딩을 활용하면 단어의 빈도수까지 고려해줄 수 있음 +- 1: 뉴스의 시작을 알리는 인덱스 번호 +- 2 : oov(Out of Vocabulary)로 사용 +- 3 ~ : 뉴스 전체 내용에서 빈도수 기준으로 랭크를 나타낸다 + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from tensorflow.keras.datasets import reuters + +data = reuters.load_data() +(X_train, y_train), (X_test, y_test) = data + +X_train.shape, y_train.shape, X_test.shape, y_test.shape +``` + +``` +((8982,), (8982,), (2246,), (2246,)) +``` + +0번째 훈련 데이터 에는 87개의 단어가 포함되어 있다. + +```python +len(X_train[0]) +``` + +``` +87 +``` + +### 로이터 뉴스 기사의 단어들이 어떤 숫자로 인코딩 되어 있는지 확인 + +1. reuters.get_word_index()로 확인이 가능 +- key, value 쌍의 딕셔너리 형태 + +```python +news_words = reuters.get_word_index() +news_words +``` + +``` +{'mdbl': 10996, + 'fawc': 16260, + 'degussa': 12089, + 'woods': 8803, + 'hanging': 13796, + ...} +``` + +1. value값 기준으로 news_words 정렬하기 + +```python +sorted(news_words.items(), key=lambda x : x[1]) +``` + +``` +[('the', 1), + ('of', 2), + ('to', 3), + ('in', 4), + ('said', 5), + ...] +``` + +1. 기사가 어떤 단어로 구성되어 있는지 단어들을 이어붙여 확인해보기 +- key값과 value 값의 위치를 교체 + +```python +word_of_news = {} + +for k, v in news_words.items(): + word_of_news[v] = k +``` + +- 단어 이어 붙이기 + +```python +print(' '.join([word_of_news[w] for w in X_train[0]])) +``` + +``` +the wattie nondiscriminatory mln loss for plc said at only ended said commonwealth could 1 traders now april 0 a after said from 1985 and from foreign 000 april 0 prices its account year a but in this mln home an states earlier and rise and revs vs 000 its 16 vs 000 a but 3 psbr oils several and shareholders and dividend vs 000 its all 4 vs 000 1 mln agreed largely april 0 are 2 states will billion total and against 000 pct dlrs +``` + +## 뉴스 주제의 개수를 알아보기 + +- 뉴스 카테고리 갯수 : 46가지 + +```python +np.unique(y_train) +``` + +``` +array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]) +``` + +## 데이터 가공 + +- timestpes를 설정해야 하는데 각 문제 데이터(X_train)가 포함하는 단어의 갯수는 모두 다르다. +- 그러므로, 문제 데이터의 **단어 개수를 같게(입력 시퀀스 맞춰주기)** 맞춰줘야 학습이 가능하다. +- 즉, **긴 기사는 잘라내고, 짧은 기사는 붙여 넣는 작업**이 필요하다. + +### 시퀀스 길이 맞추기 + +몇번 순환 시킬지(timesteps) 고정 시켜주기 위함 - 각 문제 데이터의 길이들을 불러와서 기술 통계값 확인해보기 + +```python +# 각 문제 데이터의 길이 저장 +train_len = [len(x) for x in X_train] + +# 기술 통계값 확인 +print(f'최댓값 : {max(train_len)}') +print(f'최솟값 : {min(train_len)}') +print(f'평균값 : {np.mean(train_len)}') +print(f'중앙값 : {np.median(train_len)}') +``` + +``` +최댓값 : 2376 +최솟값 : 13 +평균값 : 145.5398574927633 +중앙값 : 95.0 +``` + +- 히스토그램으로 데이터 밀도 구성 확인 +- x축은 뉴스 길이를 각 구간별로 표시, y축은 누적개수 + +```python +plt.hist(train_len, bins=20) +plt.xlabel('news_len') +plt.ylabel('count')plt.show() +``` + +![output_19_0.png](/assets/images/DL08-1/output_19_0.png) + +- 라인 차트로 기사 별 길이 시각화 + +```python +plt.figure(figsize=(15, 5)) +plt.plot(train_len) +plt.xlabel('news_index') +plt.ylabel('news_len') +plt.show() +``` + +![output_21_0.png](/assets/images/DL08-1/output_21_0.png) + +## 시퀀스 길이 맞추는 작업 수행 + +- 기술통계값을 확인해본 결과 시퀀스의 길이를 120으로 맞추는게 적절하다고 생각함 +- 긴 기사는 잘라내고, 짧은 기사는 패딩 작업을 해주기 +- sequence.pad_sequences() : maxlen에 지정된 수만큼 길이를 앞에서부터 자르거나 패딩하여 맞춘다. 옵션을 주면 뒤에서 부터 가능 + +```python +from tensorflow.keras.preprocessing import sequence + +X_train_seq = sequence.pad_sequences(X_train, maxlen=120) +X_test_seq = sequence.pad_sequences(X_test, maxlen=120) +``` + +- 각 단어 데이터는 라벨 인코딩 상태이므로 feature는 1이된다. +- RNN 학습을 위해 input_shape을 맞춰주기 : (samples, timesteps, feature) + +```python +X_train_seq = X_train_seq.reshape(8982, 120, 1) +X_test_seq = X_test_seq.reshape(2246, 120, 1) + +X_train_seq.shape, X_test_seq.shape +``` + +``` +((8982, 120, 1), (2246, 120, 1)) +``` + +## SimpleRNN 모델링 + +- 현재 한개의 feature는 단어의 빈도수를 의미하므로, 빈도수만을 이용해서 예측하는 RNN 모델을 설계하게 되는것이다 +- 다수 입력(input 120) 단일 출력(output 1) 형태 + +```python +from tensorflow.keras import Sequential +from tensorflow.keras.layers import InputLayer, Dense, SimpleRNN +from tensorflow.keras.optimizers import Adam + +model = Sequential() +model.add(InputLayer(input_shape=(120, 1))) +model.add(SimpleRNN(128))model.add(Dense(46, activation='softmax')) + +model.compile(loss='sparse_categorical_crossentropy', + optimizer=Adam(learning_rate=0.001), + metrics=['acc']) +``` + +```python +history = model.fit(X_train_seq, y_train, validation_split=0.2, batch_size=128, epochs=20) +``` + +```python +plt.figure(figsize=(15, 5)) +plt.plot(history.history['acc'], label='train_acc') +plt.plot(history.history['val_acc'], label='val_acc') +plt.legend() +plt.show() +``` + +![output_29_0.png](/assets/images/DL08-1/output_29_0.png) + +데이터가 빈도수를 나타내는 feature만 존재하긴 하지만, SimpleRNN으로는 높은 성능을 얻기 힘들다는 것을 확인 + +## LSTM 모델 학습 + +- 다수 입력(input 120) 단일 출력(output 1) +- LSTM을 여러 층으로 쌓기 위해서는 이전 LSTM층이 **다수입력 다수출력 상태**가 되어야한다. +- 그래야 **다음 LSTM층의 input 형태가 이전 LSTM층과 같은 형태**가 되기 때문이다 +- LSTM, RNN층에서 순환할때마다 출력값을 만들어주는 (다수입력 다수출력 형태) **return_sequences=True** 옵션을 사용해야 한다. + +```python +from tensorflow.keras.layers import LSTM, GRU + +model2 = Sequential() +model2.add(InputLayer(input_shape=(120, 1))) +model2.add(LSTM(128, return_sequences=True)) +model2.add(LSTM(128))model2.add(Dense(46, activation='softmax')) + +model2.compile(loss='sparse_categorical_crossentropy', + optimizer=Adam(learning_rate=0.001), + metrics=['acc']) +``` + +```python +history2 = model2.fit(X_train_seq, y_train, validation_split=0.2, batch_size=128, epochs=20) +``` + +```python +plt.figure(figsize=(15, 5)) +plt.plot(history2.history['acc'], label='train_acc') +plt.plot(history2.history['val_acc'], label='val_acc') +plt.legend() +plt.show() +``` + +![output_34_0.png](/assets/images/DL08-1/output_34_0.png) + +## 워드 임베딩(Word Embedding) + +- 언어 모델의 성능을 높이는 방법은 모델의 구조를 변경하는 방법과 단어의 표현방법을 고도화 하는방법이 있다, +- 단어의 표현을 **밀집되게 실수형태로 표현하게 하는 방법**론이 워드 임베딩이다. +- 학습을 통해서 **각 단어들의 수치값을 정밀하게** 만드는 방법이다. + +### 데이터 불러올 때 등장 빈도가 낮은 단어 제거하기 + +- num_words=1500 : reuters의 수치데이터 의미는 단어 빈도수 랭크이다. 해당 옵션을 주면 각 기사내용에 1500위까지의 단어만 가져오게 된다. +- 1500위 외의 단어들은 oov 즉, 2값으로 표현된다. + +```python +from tensorflow.keras.layers import Embedding + +(X_train, y_train), (X_test, y_test) = reuters.load_data(num_words=1500) + +# 시퀀스 길이 맞추기 +X_train_seq = sequence.pad_sequences(X_train, maxlen=120) +X_test_seq = sequence.pad_sequences(X_test, maxlen=120) +``` + +### Embedding 추가 GRU 모델 설계 + +- Embedding(사용하는 단어사전의 수, 한 단어를 표현할 특징의 수)을 가장 앞 층에 추가하기 +- 사용하는 단어 사전의 수는 학습에 사용되는 단어의 갯수이다 +- 한 단어를 표현할 특징의 수는 적절한 수로 설정해서 모델이 알아서 특징을 검출하게 해준다 + +```python +embedding_model = Sequential() + +embedding_model.add(Embedding(1500, 50)) +embedding_model.add(GRU(128, return_sequences=True)) +embedding_model.add(GRU(128)) +embedding_model.add(Dense(46, activation='softmax')) +embedding_model.compile(loss='sparse_categorical_crossentropy', + optimizer=Adam(learning_rate=0.001), + metrics=['acc']) +``` + +```python +history3 = embedding_model.fit(X_train_seq, y_train, epochs=20, validation_split=0.2, batch_size=128) +``` + +```python +plt.figure(figsize=(15, 5)) +plt.plot(history3.history['acc'], label='train_acc') +plt.plot(history3.history['val_acc'], label='val_acc') +plt.legend() +plt.show() +``` + +![output_40_0.png](/assets/images/DL08-1/output_40_0.png) \ No newline at end of file diff --git "a/_posts/2022-11-09-git01_Git\354\234\274\353\241\234 \355\230\221\354\227\205 \352\270\260\353\212\245 \354\240\225\353\246\254.md" "b/_posts/2022-11-09-git01_Git\354\234\274\353\241\234 \355\230\221\354\227\205 \352\270\260\353\212\245 \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..2c8707df8249 --- /dev/null +++ "b/_posts/2022-11-09-git01_Git\354\234\274\353\241\234 \355\230\221\354\227\205 \352\270\260\353\212\245 \354\240\225\353\246\254.md" @@ -0,0 +1,289 @@ +--- +layout: single +title: "git을 활용한 협업 기능 정리" +categories: git +tag: [git, branch, merge, 에러, fetch, pull] +toc: true +toc_sticky: true + +--- + + + + + +## Git의 branch 관리 + +### 1. **branch 만들기, branch 확인하기** + +브랜치 만들기 : `git branch [원하는 브랜치명]` + +브랜치 리스트 확인 : `git branch` 또는 `git branch —list` + +```bash +$ git branch yoonkie + +$ git branch +* master + yoonkie +``` + +### 2. 만들어진 branch로 이동 + +**git switch [브랜치명]** 또는 **git checkout [브랜치명]** + +```bash +$ git checkout yoonkie +Switched to branch 'yoonkie' +``` + +### switch vs checkout ?? + +기존에 git을 사용하면서 c**heckout**으로 브랜치를 이동했는데 최근 **switch** 명령어를 많이 사용(?)한다고 한다. + +알고보면, switch는 checkout의 분리된 기능이다. + +### switch : 브랜치를 변경한다 + +**switch**를 통해 브랜치를 **변경**할 수도 있고, 기존에 없는 **브랜치를 생성하면서 변경**도 가능 + +( master → yoonkie) + +```bash +$ git switch yoonkie +Switched to branch 'yoonkie' +``` + +### restore : 작업중인 파일을 되돌린다 (복원) + +작업중인 파일 중 기존 **마지막 커밋의 상태로 되돌리고자** 할 때 **restore**를 사용한다 + +```bash +$ git restore README.md +``` + +--- + +## 3. 브랜치 병합하기 Merge + +**git merge** 명령어를 통해 다른 브랜치와 병합할 수 있다. + +1. **matser** 브랜치에서 **git merge yoonkie** 수행 + + : yoonkie 브랜치를 master 브랜치에 병합한다는 뜻 + +2. **yoonkie** 브랜치에서 **git merge master** 수행 + + : master 브랜치를 yoonkie 브랜치에 병합한다는 뜻 + + +### Merge 충돌 관리 + +여려명이 같은 기능, 파일을 수정하면 merge 하면서 **충돌**이 쉽게 발생한다. + +두 명이서 같은 파일을 작업한다면 기존의 내용이 서로 다를 수 있으며, 이를 한쪽에서 merge 하면 git은 **어떤 코드를 반영**해야할지 모른다면서 충돌이 나게 되는것이다. + +> 예시 +> +- master 브랜치에서 수정한 README.md 파일을 commit한 상태 + +![01.png](/assets/images/git01/01.png) + +- yoonkie 브랜치에서 수정한 README.md 파일을 commit한 상태 + +![02.png](/assets/images/git01/02.png) + +- master 브랜치에서 yoonkie 브랜치 merge 수행 + +![03.png](/assets/images/git01/03.png) + +충돌이 발생했다고 표시되며, 브랜치 표시가 **(master|MERGING)**으로 변경된 것을 확인할 수 있다. + +(master|MERGING) : 충돌을 해결하기 위한 임의의 브랜치라고 보면 된다. + +![04.png](/assets/images/git01/04.png) + +> *<<<<< +> +> *[HEAD]의 코드* +> +> *===========* : **현재 브랜치와 병합 브랜치의 구분선** +> +> *[병합 할 브랜치]의 코드* +> +> *>>>>>>[브랜치 명]* +> + +실제로 README.md파일을 확인하면 위와같이 어떤 변경이 있었는지 확인할 수 있다. + +해당 부분을 **프로젝트 관리자**가 수정 후 다시 commit 하면 된다. + +- **git diff** : 병합 전 어떻게 바뀌었는지 확인할 수 있는 명령어 + +```bash +$ git diff +diff --cc README.md +index aa7a1fc,10703ad..0000000 +--- a/README.md ++++ b/README.md +@@@ -1,3 -1,3 +1,7 @@@ + # literate-engine + +- 마스터가 쓴 텍스트 +++<<<<<<< HEAD +++마스터가 쓴 텍스트 +++======= ++

윤기가 만진 p태그

+++>>>>>>> yoonkie +``` + +두 주석 모두 변경사항으로 반영하기로 하고 commit 하기 + +![05.png](/assets/images/git01/05.png) + +그러면 (master|MERGING)에서 다시 (master)브랜치로 돌아오게 된다. + +### Merge 취소하기 + +merge 중에 발생한 충돌을 해결하는 또 다른 방법은 merge 전으로 다시 되돌리는 것이다. + +`git merge —abort` + +### 공백 무시하고 Merge 하기 + +공백때문에 충돌이 나는 경우도 있는데, 해당 충돌이 단순한 공백으로 인해 충돌났을 경우엔 **Merge를 취소**한 다음에 해당 옵션을 주어 다시 Merge하면 된다. + +`git merge -Xignore-space-change [병합할 브랜치명]` + +또는 + +`git merge -Xignore-all-space [병합할 브랜치명]` + +```bash +$ git merge -Xignore-space-change yoonkie +Auto-merging README.md +Merge made by the 'recursive' strategy. + hello.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +``` + +## Git fetch와 pull의 차이 + +`fetch`는 로컬 Git에게 원격 저장소에서 최신 메타데이터 정보를 확인하라는 명령을 전달하는 것이다. + +즉, `fetch`는 원격 저장소에 **변경사항이 있는지만 확인**하고, 변경된 데이터를 로컬에 실제로 가져오지는 않는다. + +`pull`은 원격 저장소에서 변경된 메타데이터 정보를 확인하고 **최신 데이터를 복사하여 로컬**에 가져온다. + +`fetch` 후 `merge`를 수행하면 `pull` 명령을 실행했을 때와 같은 이력이 만들어진다. + +### Fetch로 변경 사항 먼저 확인하는 법 + +1. fetch 한 후에 FETCH_HEAD의 변경 사항을 확인하면 된다. +2. git diff로 변경사항 확인 +- git fetch + +```bash +$ git fetch origin master +From https://github.com/minyoongi96/SSM-Project + * branch master -> FETCH_HEAD +``` + +- git diff + +![06.png](/assets/images/git01/06.png) + +### Pull로 원격 저장소의 최신 내용을 가져오기 + +```bash +$ git pull origin master +From https://github.com/minyoongi96/SSM-Project + * branch master -> FETCH_HEAD +Updating 85b7a2f..ceda8cd +Fast-forward + README.md | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) +``` + +## LF will be replaced by CRLF in - Git 경고 메시지 뜰 경우 + +txt, md 파일 등에서 개행문자(줄바꿈 : \n 등)가 운영체제마다 인식하는 방법이 달라서 git이 이 부분을 어떤 운영체제에 맞게 인식처리 할 지 몰라서 나는 오류이다. + +- **LF (Line-Feed)** + - Mac, 리눅스 (Unix 계열) 줄바꿈 문자열 : \n +- **CRLF (Carriage-Return + Line-Feed)** + - 윈도우, DOS 줄바꿈 문자열 : \r\n + - CR(\r) + LF(\n) 두 동작을 합친것임 + +### 해결방법 : git config 설정을 변경해주기 + +- 윈도우, DOS인 경우 : git config --global core.autocrlf true 입력 +- Linux, Mac인 경우 : git config --global core.autocrlf input 입력 \ No newline at end of file diff --git "a/_posts/2022-11-10-springboot04_Spring JPA \354\204\244\354\240\225 \353\260\217 \354\202\254\354\232\251 \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230.md" "b/_posts/2022-11-10-springboot04_Spring JPA \354\204\244\354\240\225 \353\260\217 \354\202\254\354\232\251 \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230.md" new file mode 100644 index 000000000000..bfb3c289a6b3 --- /dev/null +++ "b/_posts/2022-11-10-springboot04_Spring JPA \354\204\244\354\240\225 \353\260\217 \354\202\254\354\232\251 \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230.md" @@ -0,0 +1,252 @@ +--- +layout: single +title: "Spring JPA 설정 및 사용 어노테이션" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, STS, Eclipse] +toc: true +toc_sticky: true + +--- + + + + + + +## application.yml 설정 + +```yaml +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + password: 1234 + url: jdbc:mysql://localhost:3306/mysql + username: root + # JPA 설정 + jpa: + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect # 데이터베이스 종류 + hibernate: + ddl-auto: update # jpa로 entity 처음 생성시 테이블 없으면 create, 만든 다음엔 update로 변경해야함 + properties: + hibernate: + format_sql: true + show-sql: true +``` + +## 엔티티와 매핑 + +### @Entity란 ? + +@Entity가 붙은 클래스는 JPA가 관리하는 객체이다. + +```java +@Entity +// 제약조건이나 테이블 명 등의 옵션 설정 가능 +@Table(name = "BOARD2") +@Data +public class Board { + + @Id // PK라는 뜻 + @GeneratedValue(strategy = GenerationType.IDENTITY) // 자동증가 라는 뜻(strategy의 Identity: mysql) + private Long idx; + + @Column(nullable = false) + private String memId; + + @Column(length = 1000) // 컬럼 상세 설정 + private String title; + + @Column(length = 2000) + private String contents; + + @ColumnDefault("0") + private int count; + + @Column(length = 100) + private String writer; + + @Temporal(TemporalType.TIMESTAMP) + @Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private Date indate; + +} +``` + +- 객체와 테이블 매핑 : @Entity, @Table +- 기본키 매핑 : @Id +- 필드와 컬럼 매핑 : @Column +- 연관관계 매핑 : @ManyToOne, @JoinColumn +- 자동증가 : @GeneratedValue(strategy = GenerationType.IDENTITY) + +### 1. @Entity + +- 테이블과의 매핑 +- JPA가 관리하는 것으로 엔티티라고 불림 +- 속성 + - name : JPA에서 사용할 엔티티 이름을 지정, 보통 기본값인 클래스 이름을 사용 + +### 2. @Table + +- 에니티와 매핑할 테이블을 지정 +- 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용 +- 속성 + - name : 매핑할 테이블 이름 (default : 엔티티 이름 사용) + - catalog : catalog 기능이 있는 DB에서 catalog를 매핑 + - schema : schema 기능이 있는 DB에서 schema를 매핑 + - uniqueConstraints : DDL 생성 시 **유니크 제약조건을 생성**, 스키마 자동생성 기능을 사용해서 DDL을 만들때만 사용됨 + +### 3. @Column + +- 객체 필드를 테이블 컬럼에 매핑 +- 속성 + - name : 필드와 매핑할 테이블 컬럼 이름 (default : 객체의 필드 이름) + - nullable (DDL) : **null 값의 허용 여부** 설정, false : not null (default : true) + - unique (DDL) : @Table의 uniqueConstraints와 같지만 **한 컬럼에 간단히 유니크 제약조건**을 적용 + - columnDefinition (DDL) : 데이터베이스 **컬럼 정보**를 **직접** 줄수 있음 + - length (DDL) : 문자 길이 제약조건, **String** 타입에만 적용 (default : 255) + - percision, scale (DDL) : **BigDecimal, BigInteger** 타입에만 적용, 아주 큰 숫자나 정밀한 소수를 다룰때 사용 (default : precision = 19, scale = 2) + +### 4. @Enumerated + +- 자바의 enum 타입을 매핑할 때 사용 +- EnumType.ORDINAL : enum 순서를 데이터베이스에 저장 +- EnumType.STRING : enum 이름을 데이터베이스에 저장 (default : EnumType.ORDINAL) + +### 5. @Temporal + +- 날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용 +- 자바의 Date 타입에는 년월일 시분초가 있지만, 데이터베이스에는 date(날짜), time(시간), timestamp(날짜와 시간)라는 세 가지 타입이 별도로 존재 +- @Temporal을 생략하면 자바의 Date와 가장 유사한 **timestamp**로 정의 +- 하지만 timestamp대신에 **datetime**을 예약어로 사용하는 데이터베이스도 있는데, 데이터베이스 방언 덕분에 애플리케이션 코드는 변경하지 않아도 됨 +- datetime : MySQL +- timestamp : H2, 오라클, PostgreSQL + 1. TemporalType.**DATE** +  : 날짜, 데이터베이스 date 타입과 매핑 (예 : 2013-10-11) + 2. TemporalType.**TIME** +  : 시간, 데이터베이스 time 타입과 매핑 (예 : 11:11:11) + 3. TemporalType.**TIMESTAMP** +  : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 (예 : 2013-10-11 11:11:!1) + +### Default 값을 넣는 방법 + +**@DynamicInsert :** Default값을 적용하기 위해서는 이 어노테이션을 써야한다. Insert 시 지정된 Default값을 적용시킨다. + +**@ColumnDefault :** ColumnDefault는 Default값 설정을 할 때 사용한다. + +## @Builder 어노테이션 올바른 사용 + +Entity를 선언할 때 주의점 + +1. @Setter : 객체가 무분별하게 변경될 가능성이 있다 +2. @NoArgsConstructor : 기본 생성자의 접근 제어자가 불명확하다 +3. @AllArgsConstructor : 객체 내부의 인스턴스멤버들을 모두 가지고 있는 생성자를 생성한다 + +@Builder 어노테이션을 사용하여 문제점들을 해결할 수 있다. + +- 객체 생성자 + +```java +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Member { + + @Id + private String memId; + + @Column(length = 100) + private String memPwd; + + @Column(length = 100) + private String memName; + + // 의미있는 객체 생성 + @Builder + public Member(String memId, String memPwd, String memName) { + this.memId = memId; + this.memPwd = memPwd; + this.memName = memName; + } +} +``` + +- 테스트 코드 + +```java +@Test + void insertMember() { + Member vo = Member.builder() + .memId("admin") + .memPwd("1234") + .memName("관리자").build(); + + mRepository.save(vo); + } +``` \ No newline at end of file diff --git "a/_posts/2022-11-14-springboot05_AssertJ \354\202\254\354\232\251\355\225\264\353\263\264\352\270\260.md" "b/_posts/2022-11-14-springboot05_AssertJ \354\202\254\354\232\251\355\225\264\353\263\264\352\270\260.md" new file mode 100644 index 000000000000..2426423f5207 --- /dev/null +++ "b/_posts/2022-11-14-springboot05_AssertJ \354\202\254\354\232\251\355\225\264\353\263\264\352\270\260.md" @@ -0,0 +1,145 @@ +--- +layout: single +title: "AssertJ 사용해보기" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, STS, Eclipse, AssertJ, JUnit] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + +## AssertJ의 특징 + +JUit이 기본적으로 제공해주는 Assert는 너무 불편해서 AssertJ를 사용해보았다. + +## 장점 + +- 메소드 체이닝을 지원해주기 때문에 좀 더 깔끔하고 읽기 쉬운 테스트 코드를 작성할 수 있다. +- 테스트를 하면서 필요하다고 상상할 수 있는 거의 모든 메소드를 제공한다. + +## 라이브러리 의존성 설정 + +Java8 이상은 3.x 버전을 사용해야 한다. + +- Gradle + +```yaml +testCompile 'org.assertj:assertj-core:3.6.2' +``` + +- Maven + +```xml + + org.assertj + assertj-core + + 3.6.2 + test + +``` + +## 사용방법 + +모든 테스트 코드는 assertThat() 메소드에서 출발한다. 다음과 같은 포맷으로 AssertJ에서 제공하는 다양한 메소드를 연쇄 호출하면서 작성할 수 있다. + +```java +assertThat(테스트 타켓).메소드1().메소드2().메소드3(); +``` + +### 문자열 테스트 + +```java +assertThat("Hello, world! Nice to meet you.") // 주어진 "Hello, world! Nice to meet you."라는 문자열은 + .isNotEmpty() // 비어있지 않고 + .contains("Nice") // "Nice"를 포함하고 + .contains("world") // "world"도 포함하고 + .doesNotContain("ZZZ") // "ZZZ"는 포함하지 않으며 + .startsWith("Hell") // "Hell"로 시작하고 + .endsWith("u.") // "u."로 끝나며 + .isEqualTo("Hello, world! Nice to meet you."); // "Hello, world! Nice to meet you."과 일치합니다. +``` + +### 숫자 테스트 + +```java +assertThat(3.14d) // 주어진 3.14라는 숫자는 + .isPositive() // 양수이고 + .isGreaterThan(3) // 3보다 크며 + .isLessThan(4) // 4보다 작습니다 + .isEqualTo(3, offset(1d)) // 오프셋 1 기준으로 3과 같고 + .isEqualTo(3.1, offset(0.1d)) // 오프셋 0.1 기준으로 3.1과 같으며 + .isEqualTo(3.14); // 오프셋 없이는 3.14와 같습니다 +``` \ No newline at end of file diff --git "a/_posts/2022-11-16-springboot06_JPA \354\227\260\352\264\200\352\264\200\352\263\204 \353\247\244\355\225\221.md" "b/_posts/2022-11-16-springboot06_JPA \354\227\260\352\264\200\352\264\200\352\263\204 \353\247\244\355\225\221.md" new file mode 100644 index 000000000000..743f93ae9f7a --- /dev/null +++ "b/_posts/2022-11-16-springboot06_JPA \354\227\260\352\264\200\352\264\200\352\263\204 \353\247\244\355\225\221.md" @@ -0,0 +1,169 @@ +--- +layout: single +title: "JPA 연관관계 매핑" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, join] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + + +## 연관관계 매핑 + +연관관계 매핑이란 객체의 참조와 테이블의 **외래키를 매핑**하는 것을 의미한다. + +**JPA**에서는 **Mybatis**를 사용했을 때와 다르게 연관 관계에 있는 상대 테이블의 PK를 멤버변수로 갖지 않고, 엔티티 **객체 자체를 통째로 참조**한다. + +### 용어 + +- **방향** +1. 단방향 관계 : 두 엔티티가 관계를 맺을 때, **한 쪽의 엔티티만 참조**하고 있는 것을 의미한다. +2. 양방향 관계 : 두 엔티티가 관계를 맺을 때, **양 쪽이 서로 참조**하고 있는 것을 의미한다. + +데이터 모델링에서는 관계를 맺어주기만 하면 자동으로 양방향 관계가 되어 서로 참조하지만, 객체지향 모델링에서는 구현하고자 하는 서비스에 따라 단방향 관계인지, 양방향 관계인지 적절한 선택을 할 필요가 있다. + +하지만, 어느 정도의 비즈니스에서는 단방향 관계만으로도 해결이 가능하기 때문에 양방향 관계를 꼭 해야하는 것은 아니다. + +그리고 양방향 관계란 서로 다른 단방향 관계 2개를 묶어서 양방향인 것처럼 보이게 할 뿐, 양방향 연관 관계는 사실 존재하지 않는다고 할 수 있다. + +- **다중성** +1. ManyToOne : 다대일 (N : 1) +2. OneToMany : 일대다 (1 : N) +3. OneToOne : 일대일 (1 : 1) +4. ManyToMany : 다대다 (N : M) + +- **연관관계의 주인 (Owner)** + +연관 관계에서 주인을 찾는 방법은 관계를 갖는 두 테이블에 대해서 **외래키를 갖는 테이블**이 연관 관계의 주인이라고 할 수 있다. + +연관 관계의 주인만이 **외래키를 등록, 수정, 삭제**할 수 있고, 반면 주인이 아닌 엔티티는 읽기만 할 수 있기 때문이다. + +### 예시 - @ManyToOne (단방향) + +```java +@Entity +@Table +@Data +public class Categories { + @Id + @Column(name = "cate_seq") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long cateSeq; + + @Column(name = "cate_name", length = 400) + private String cateName; +} + +@Entity +@Table +@Data +public class Items { + @Id + @Column(name = "item_seq") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long itemSeq; + + @Column(name = "item_name", length = 45) + private String itemName; + + @Column(name = "item_price") + private int itemPrice; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "cate_seq") + private Categories categoriesVO; +} +``` + +단방향은 한 쪽의 엔티티가 상대 엔티티를 참조하고 있는 상태이다. + +그래서 Items 엔티티에만 @ManyToOne 어노테이션을 추가했다. + +- **@ManyToOne** + + @ManyToOne 어노테이션은 이름 그대로 다대일 관계 매핑 정보이다. + + Items 입장에서는 Categories 와 다대일 관계이므로 ManyToOne 어노테이션을 사용했다. + + 연관 관계를 매핑할 때는 이렇게 다중성을 나타내는 어노테이션을 필수로 사용해야 하며, **엔티티 자신을 기준**으로 다중성을 생각해야 한다. + +- @JoinColumn(name=”cate_seq”) + + @JoinColumn 어노테이션은 외래 키를 매핑할 때 사용한다. + + name 속성에는 매핑할 외래 키 이름을 지정한다. + + Items 엔티티의 경우 Categories 엔티티의 PK를 “cate_seq”라는 이름의 외래키를 가진다는 뜻으로 작성이 된다. \ No newline at end of file diff --git "a/_posts/2022-11-20-springboot07_JPA ,Query \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230, JPQL, DTO \353\247\244\355\225\221, function.md" "b/_posts/2022-11-20-springboot07_JPA ,Query \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230, JPQL, DTO \353\247\244\355\225\221, function.md" new file mode 100644 index 000000000000..b494fda49786 --- /dev/null +++ "b/_posts/2022-11-20-springboot07_JPA ,Query \354\226\264\353\205\270\355\205\214\354\235\264\354\205\230, JPQL, DTO \353\247\244\355\225\221, function.md" @@ -0,0 +1,357 @@ +--- +layout: single +title: "JPA ,Query 어노테이션, JPQL, DTO 매핑, function 사용" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, join] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + +### JPA 장점 + +- SQL문이 아닌 Method를 통해 DB를 조작할 수 있어 개발자가 비즈니스 로직 구성에 좀 더 집중할 수 있음 +- 쿼리문 등의 부수적인 코드가 줄어들어 가독성이 높아짐 +- 오직 객체지향적 접근만 고려되므로 생산정 증가 +- 매핑 정보가 Class로 명시되어 있어서 ERD를 보는 의존도를 낮출 수 있고 유지보수 및 리팩토링에 유리 + +### JPA 단점 + +- 프로젝트의 규모가 크고 복잡하여 설계가 잘못된 경우, 속도 저하 및 일관성을 무너뜨리는 문제점이 생길 수 있음 +- 복잡하고 무거운 Query는 속도를 위해 별도의 튜닝이 필요하기 때문에 결국 SQL문을 써야할 수도 있음 + +JPA가 쿼리를 자동으로 생성해주지만 상황에 따라 직접 쿼리를 작성할 필요가 생긴다. + +### JPA에서 직접 쿼리를 작성할 수 있는 방법 + +- JPQL 작성 +- 네이티브 쿼리(일반 SQL) 작성 + +JPQL은 JPA의 일부분으로 정의된 플랫폼 독립적인 **객체지향 쿼리 언어**이다. + +**네이티브 쿼리는 데이터베이스를 바라보고 작성**한다면 **JPQL은 엔티티 클래스를 바라보고 작성**해야 한다. + +JPQL에서는 **대 소문자 구분**을 하고 select, from과 같은 **키워드는 구분하지 않는다.** + +## @Query 어노테이션 + +JpaRepository에서 쿼리(JPQL, native query 둘 다)를 직접 작성해줄 때 사용한다. + +메서드 명은 기존 자동생성 방식과 달리 **자유롭게 작성**할 수 있다. + +그리고 **nativeQuery**라는 속성을 이용하여 JPQL로 작성한 것인지 SQL로 작성한 것인지 구분할 수 있다. + +- nativeQuery = false(default) → JPQL +- nativeQuery = true → SQL + +### Entity : Broadcasting (방송 정보) + +```java +@Entity +@Table +@Data +public class Broadcasting { + + @Id + @Column(name = "bc_seq") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long bcSeq; + + @Column(name = "bc_title", nullable = false, length = 400) + private String bcTitle; +``` + +### Entity : ViewerReaction (시청자 반응) + +```java +@Entity +@Table(name = "viewer_reaction") +@Data +public class ViewerReaction { + @Id + @Column(name ="vr_seq") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long vrSeq; + + @Column(name ="vr_viewers", nullable = false) + private int vrViewers; + + @Column(name ="vr_sales", nullable = false) + private int vrSales; + + @Column(name ="vr_comments", nullable = false) + private int vrComments; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "bc_seq") + private Broadcasting broadcastingVO; +} +``` + +### 1. @Query 사용 방법 (일반 쿼리) + +JPQL은 **엔티티의 이름과 속성명을 사용**하고, 일반 SQL은 **설계된 테이블명과 칼럼명** 사용 + +```java +@Repository +public interface ViewerReactionRepository extends JpaRepository { + + // JPQL 사용 + @Query(value = "select vr.vrSeq from ViewerReaction vr") + List selectAllVrSeq(); + // 일반 SQL 사용 + @Query(value = "select vr.vr_seq from viewer_reaction vr", nativeQuery = true) + List selectAllVr_seq(); +} +``` + +### 2. @Query 사용 방법 (파라미터 사용) + +```java +@Repository +public interface ViewerReactionRepository extends JpaRepository { + + // JPQL 일반 파라미터 쿼리, @Param 사용 X, 엔티티 변수명 "vrSeq" 사용 + @Query(value = "select vr from ViewerReaction " + + "vr where vr.vrSeq = ?1") + List selectAllByVrSeq(long seq); + + // 일반 SQL문 파라미터 쿼리 ,@Param 사용 X, 테이블 컬럼명 "vr_seq" 사용 + @Query(value = "select * from viewer_reaction " + + "where vr_seq = ?1", nativeQuery = true) + List selectAllByVr_seq(long seq); + + // JPQL 일반 파라미터 쿼리, @Param 사용 O + @Query(value = "select vr from ViewerReaction vr where vr.vrSeq = :seq") + List selectAllByVrSeq2(@Param(value = "seq") long seq); + + // 일반 SQL문 파라미터 쿼리 ,@Param 사용 O + @Query(value = "select * from viewer_reaction " + + "where vr_seq = :seq", nativeQuery = true) + List selectAllByVr_seq2(@Param(value = "seq") long seq); + + // JPQL 객체 파라미터 쿼리, :#{#객체명}으로 사용 + @Query(value = "select vr.vrTitle from ViewerReaction vr " + + "where vr.vrSeq < :#{#bc.bcSeq}") + List selectVrTitleByBc(@Param(value = "bc") Broadcasting bc) + + // 일반 SQL문 객체 파라미터 쿼리, :#{#객체명}으로 사용 + @Query(value = "select vr_title from viewer_reaction " + +"where vr_seq < :#{#bc.bcSeq}", nativeQuery = true) + List selectVrTitleByBc(@Param(value = "bc") Broadcasting bc) +``` + +### 3. @Query 사용 방법(집계 함수 단독) + +객체 파라미터를 사용할 때 여기서는 ManyToOne 매핑이 되어 ViewerReaction 엔티티가 Broadcasting의 매핑 주인이 된다. + +그러므로, JPQL 사용 할 때에는 외래키 속성 변수가 객체 형태가 되므로 주의해서 참고 + +```java +@Repository +public interface ViewerReactionRepository extends JpaRepository { + + // 집계함수 SUM 사용 + // JPQL 사용, broadcastingVO 형태 + @Query(value = "select SUM(vr.vrSales) from ViewerReaction vr " + + "where vr.broadcastingVO = :#{#bc}") + Integer vrSalesSum(@Param("bc") Broadcasting bc); + + // 일반 SQL 사용, 테이블에선 컬럼이 객체 형태가 아님 + @Query(value = "select SUM(vr.vr_sales) from viewer_reaction vr " + + "where vr.bc_seq = :bcSeq", nativeQuery = true) + Integer vrSalesSum(@Param("bcSeq") long bcSeq); +``` + +## DTO Mapping + +JPQL을 작성하면서 여러 `function`과 `join`을 사용하다보면 결과가 Entity 형태로 나오지 않을 경우도 있다. 이를 위해 **DTO 반환**이 필요하다. + +**@Query** 어노테이션을 사용하여 DTO 반환을 하기 위해서는 **select 구분에서 생성자를 통해 객체를 반환**해야 한다. + +### Entity : User + +```java +@Entity +@Table(name = "user") +@Data +public class User { + @Id + private String id; + private String name; + private String phone; + private String deptId; +} +``` + +### JpaRepository + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select u from User u where u.name = :name") + List findByName(@Param("name") String name); +} +``` + +### DTO + +```java +@Data +public class UserDTO { + private String id; + private String name; + private String deptId; + private String deptName; +} +``` + +### @Query로 DTO 반환하기 + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select" + + "new com.yoonkie.dto.UserDto(u.id, u.name, u.deptId, d.deptName " + + "from User u left outer join Dept d on u.deptId = d.deptId") + List findUserDept(); +} +``` + +## SQL Function + +JPQL에서는 기본적으로 select 구문의 **max, min, count, sum, avg**를 제공하며 `기본 function` 으로는 **COALESCE, LOWER, UPPER** 등을 지원하며 자세한 Function은 문서를 참고하면 된다. + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select max(u.id) " + + "from User user " + + "where u.deptId is not null") + String findMaxUserId(); +} +``` + +이러한 JPQL에서 기본적으로 지원하는 `ANSI Query Function`만으로는 비지니스 조회를 해결하기에 한계가 존재한다. + +`DataBase Function` 을 사용하는 방식은 JPQL에서 `function()` 을 활용하여 **hibernate에 등록된** 각 DataBase의 `Dialect에 정의된 function`을 사용하는 방법이 있다. + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select function('date_format', :date, '%Y/%m/%d') " + + "from User u" + String findNow(@Param("date") LocalDateTime date); +} +``` + +하지만, **hibernate**에서 기본적으로 등록되는 function에서도 **누락되는 function이 존재**한다. 이러한 경우 `MetadataBuilderContributor`의 **구현체를 구현하는 방식**으로 사용할 수 있다. + +(이전에는 **Dialect를 상속받아 구현하는 방식** 사용) + +```java +public class MyMetadataBuilderContributor implements MetadataBuilderContributor{ + @Override + public void contribute(MetadataBuilder metadataBuilder) { + metadataBuilder.applySqlFunction("JSON_EXTRACT", new StandardSQLFunction("JSON_EXTRACT", StringType.INSTANCE)) + .applySqlFunction("JSON_UNQUOTE", new StandardSQLFunction("JSON_UNQUOTE", StringType.INSTANCE)) + .applySqlFunction("STR_TO_DATE", new StandardSQLFunction("STR_TO_DATE", LocalDateType.INSTANCE)) + .applySqlFunction("MATCH_AGAINST", new SQLFunctionTemplate(DoubleType.INSTANCE, "MATCH (?1) AGAINST (?2 IN BOOLEAN MODE)")) + } +} +``` + +`applySqlFunction`의 첫번째 파라미터는 **JPQL**에서 `function(”함수명”)`에서 **함수명**에 해당하는 등록명이다. + +`StandardSQLFunction`은 **기본적인 함수를 등록하기 위한 Class**로 생성자의 **첫번째 파라미터**는 `실제 DataVase Function명`이며, **두번째 파라미터**는 function의 `리턴 타입`이 되야 한다. + +`StandardSQLFunction`의 경우 파라미터는 함수에 순서에 맞게 **JPQL function(’등록 함수명’, 파라미터1, 파라미터2, …) 같이 정의**하여 사용하면 된다. + +`SQLFunctionTemplete`은 **문법이 존재하는 function을 등록할 때 사용가능**하며, **첫번째 파라미터**가 `function의 리턴타입`이고, **두번째 파라미터**가 `function`이다. + +**?1, ?2**와 같이 명시하여 JPQL function()에서 전달되는 **파라미터**의 순서대로 파싱된다. + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select u from User u " + + "where function('JSON_UNQUOTE', function('JSON_EXTRACT', u.phone, '$.id')) = 'admin' ") + List findAllByPhoneAdmin(); +} +``` + +```java +public interface UserRepository extends JpaRepository { + @Query(value = "select user from User u" + + "where function('MATCH_AGAINST', u.name, :name) > 0") + List findAllByName(@Param("name") String name); + +} +``` \ No newline at end of file diff --git "a/_posts/2022-11-27-springboot08_Spring \355\224\204\353\241\234\354\240\235\355\212\270 \352\263\204\354\270\265 \354\225\204\355\202\244\355\205\215\354\262\230 .md" "b/_posts/2022-11-27-springboot08_Spring \355\224\204\353\241\234\354\240\235\355\212\270 \352\263\204\354\270\265 \354\225\204\355\202\244\355\205\215\354\262\230 .md" new file mode 100644 index 000000000000..e3ef9128a3ca --- /dev/null +++ "b/_posts/2022-11-27-springboot08_Spring \355\224\204\353\241\234\354\240\235\355\212\270 \352\263\204\354\270\265 \354\225\204\355\202\244\355\205\215\354\262\230 .md" @@ -0,0 +1,162 @@ +--- +layout: single +title: "Spring 프로젝트 계층 아키텍처" +categories: SpringBoot +tag: [Java, Spring, JPA, Spring Boot, 아키텍쳐] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + + +스프링의 계층은 **Presentation Layer**, **Business, Layer**, **Data Access Layer** 크게 3개로 나눌 수 있다. + +![01.png](/assets/images/springboot08/01.png) + +## 각 계층의 역할 및 특징 정리 + +### 프레젠테이션 계층 + +- 브라우저상의 웹 클라이언트의 요청 및 응답을 처리하는 계층이다 +- Service 계층, Data Access 계층에서 발생하는 Exception을 처리 +- @Controller 어노테이션을 사용하여 작성된 Controller 클래스가 이 계층에 속함 + +### 서비스 계층 + +- 애플리케이션 비즈니스 로직 처리와 비즈니스와 관련된 도메인 모델의 적합성 검증 +- 트랜잭션을 관리한다 +- Presentation 계층과 Data Access 계층 사이에서 직접적으로 통신하지 않게 함 +- Service 인터페이스와 @Service 어노테이션을 사용하여 작성된 Service 구현 클래스가 이 계층에 속함 + +### 데이터 엑세스 계층 + +- ORM(Mybatis 혹은 Hibernate)를 주로 사용하는 계층 +- DAO 인터페이스와 @Repository 어노테이션을 사용하여 작성된 DAO 구현 클래스가 이 계층에 속함 +- 데이터베이스에 CRUD하는 계층 + +### 프로젝트에서 직접 작성했던 Repository 인터페이스 + +![02.png](/assets/images/springboot08/02.png) + +### 도메인 모델 계층 + +- DB의 테이블과 매칭될 클래스 +- Entity 클래스라고도 부른다. + +## 계층에 관한 용어 정리 + +### DTO (Data Transfer Object) + +- 각 계층간 데이터 교환을 위한 객체 (데이터를 주고 받을 형태 혹은 포맷) +- Domain, VO라고도 부름 +- DB에서 데이터를 얻어 Service, Controller 등으로 보낼때 사용함 +- 로직을 갖지 않고 순수하게 getter, setter 메소드를 가진다. + +![03.png](/assets/images/springboot08/03.png) + +### DAO (Data Access Object) + +- DB에 접근하는 객체 혹은 DB를 사용해 데이터를 조작하는 기능을 하는 객체 +- MyBatis 사용시에 DAO or Mapper, JPA 사용시에 Repository +- Service 계층과 DB를 연결하는 고리 역할을 한다. + +### Entity 클래스 + +- Domain 이라고도 부름 (JPA에서 사용) +- 실제 DB 테이블과 매칭될 클래스 +- Entity 클래스 또는 가장 Core한 클래스라고 부름 +- Domain 로직만을 가지고 있어야하며 Presentation Logic을 가지고 있어서는 안됨 + +![04.png](/assets/images/springboot08/04.png) + +## Domain 클래스와 DTO 클래스를 분리하는 이유 + +![05.png](/assets/images/springboot08/05.png) + +- 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 되지만 View와 통신하는 DTO 클래스는 자주 변경되므로 분리할 필요가 있음 +- DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용함 +- View Layer와 DB Layer의 역할을 철저하게 분리하기 위해 + +## RestController와 @Service를 나누는 이유 + +- 모든 기능들을 세분화해서 서비스 계층에 작성하고 나중에는 서비스의 기능들을 **조합**만 해서 새로운 기능으로 만들 수 있음 +- 중복되는 코드가 발생하면 따로 모듈화를 해서 나눠주면 **유지보수**하기 편리하다. +- 비즈니스 로직을 서비스 구현체에서 구현하여 **확장성**과 **재사용성** 그리고 **중복 코드 제거**를 확보할 수 있다. + +### Service 계층에서 비즈니스 로직 처리 + +프로젝트에서 내가 직접 구현했던 Service 구현 클래스 + +![06.png](/assets/images/springboot08/06.png) \ No newline at end of file diff --git "a/_posts/2024-03-02-aws02_EC2, EBS, ELB \353\202\264\354\232\251 \354\240\225\353\246\254.md" "b/_posts/2024-03-02-aws02_EC2, EBS, ELB \353\202\264\354\232\251 \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..07e44df76aeb --- /dev/null +++ "b/_posts/2024-03-02-aws02_EC2, EBS, ELB \353\202\264\354\232\251 \354\240\225\353\246\254.md" @@ -0,0 +1,110 @@ +--- +layout: single +title: "EC2, EBS, ELB 뜻 정리" +categories: [AWS] +tag: [AWS, EC2, EBS, ELB] +toc: true +toc_sticky: true +post-header: false + +--- + +Elastic Compute Cloud의 약자로 가장 큰 장점인 클라우드라는 공간에서 크기가 유연하게 변경되는 기능을 제공한다. + +예측할 수 없는 데이터 처리 및 계산이 불가능한 크기의 데이터가 밀려오는 상황에 사용량이 많아지면 그만큼 늘리면 되고 반대로 적어지면 또 그만큼 줄여주는 Auto Scaling 가능 + +## EC2의 다양한 지불 방법 + +On-demand + +- 시간 단위로 가격이 고정되어 있음. +- 시간당 정해진 비용을 지불하며 편하게 사용할 수 있고, 소프트웨어 및 서버 개발시 최초로 EC2인스턴스 deploy할 때에 종종 쓰임 +- 또는 사용 기간을 미리 알 수 없는 경우에 유용. + +Reverse + +- 한정된 EC2용량 사용 가능, 1~3년 동안 시간별로 할인 적용 받을 수 있다. +- 선불로 특정한 금액을 지불할 경우 추가적으로 지정되는 컴퓨팅 시스템을 사용할 수 있음. +- On-demand보다 조금 저렵한 가격에 사용할 수 있는 장점이 있지만, On-demand와 달리 크기를 늘리고 줄이는 기능이 없고 특정한 사이즈에 정해지기 때문에 가격이 저렴한 것 같음. +- 무언가를 개발할 때 요구사항이 자주 반복되지 않거나 개발 시간에 대해 예측이 가능하다면 해당 방식 유용 + +Spot + +- 경매와 같이 입찰 가격 적용. 가장 큰 할인률을 적용받으며 특히 인스턴스의 시작과 끝기간이 전혀 중요하지 않을 때 매우 유용 + +## EBS (Elastic Block Storage) + +저장 공간이 생성되어지며 EC2 인스턴스에 부착된다. + +디스크 볼륨 위에 File System이 생성된다. 따라서, EC2인스턴스 접근 뿐만 아니라 파일을 로컬 디스크로 옮기는 작업도 가능하다. + +EBS는 특정 Availability Zone에 생성되므로 Availability Zone을 설정해주어야 함. + +- Availability Zone은 AZ라고도 종종 불리며 하나의 Region 안에 여러개의 AZ가 존재할 수 있음. +- 중심부로부터 복사본들이 존재하여 한쪽 서버가 망가지거나 셧다운되었을 경우 AZ 백업을 통해 서비스 제공을 가능하게 해주는 일종의 Disaster Recovery가 가능. + +## EBS 볼륨 타입 + +< SSD > + +1. General Purpose SSD (GP2) + - 최대 10K IOPS를 지원하며 1GB당 3IOPS 속도가 나옴. + - SSD중에 가장 보편적으로 사용됨. +2. Provisioned IOPS SSD (IO1) + - 극도의 I/O률을 요구하는(ex. 매우 큰 DB관리) 환경에서 주로 사용됨. 10K이상의 IOPS를 지원함 + - 매우 큰 빅데이터 분석 시에도 사용 가능 + +< Magnetic / HDD > + +1. Throughput Optimized HDD (ST1) + - 빅데이터 Datawarehouse, Log 프로세싱시 주로 사용 (boot volume으로 사용 불가능) + - 운영체제를 가지고 있을 수 없음 +2. CDD HDD (SC1) + - 파일 서버와 같이 드문 입출력 즉, 드문 volume 접근 시 주로 사용 + - boot volume으로는 사용 불가능하나 비용이 매우 저렴함 + - 오랫동안 보관해도 괜찮은 데이터들을 처리하는 용도로 쓰기 좋음 +3. Magnetic (Standard) + - 디스크 1GB당 가장 싼 비용을 자랑함. + - boot volume으로 사용 가능. + +## ELB (Elastic Load Balancers) + +수많은 서버의 흐름을 균형있게 배분, 흘려보내는데 중추적인 역할을 함 + +하나의 서버로 트래픽이 몰리는 병목현상을 방지 + +Unhealth instance → Healthy instance + +- EC2 인스턴스는 예상치 못한 이유로 갑자기 셧다운되거나 시간초과 등이 발생하는 unhealthy상태가 됨. 이러한 트래픽 상태를 해결할 수 있음. + +### 1. Application Load Balancer + +OSI Layer7에서 작동됨 (가장 바깥부분) + +- HTTP, HTTPS와 같은 트래픽의 load balancing에 가장 적합함. +- 별도의 라우팅 설정을 통하여 특정 서버로 request를 보낼 수 있음. + + → ELB가 임의로 하지 않고 커스터마이즈인 라우팅이 가능하다는 뜻. + + +### 2. Network Load Balancer + +OSI Layer4에서 작동됨 (Transport Layer). TCP 트래픽을 정리하는데 적합함. + +- 극도의 performance가 요구되는 TCP traffic에서 적합함 +- 초당 수백만개의 request를 아주 미세한 delay로 처리가 가능하다. +- Google, Naver같이 큰 서버에서 적합할듯 하다. + +### 3. Classic Load Balancer + +Legacy ELB라고도 함. (거의 쓰이지 않음) + +- Layer7의 HTTP/HTTPS 라우팅 기능 지원 +- Layer4의 TCP 트래픽 라우팅 기능도 지원 + +## Route 53 + +AWS에서 제공하는 DNS 서비스이다. + +- EC2 instance, S3 Bucket, Load Balancer 등 사용하는 서버의 이름을 부여할 수 있다. +- 도메인 주소를 생성하고 구매하여 위의 3가지 서버로 연결시켜줄 수 있다. \ No newline at end of file diff --git "a/_posts/2024-03-13-aws01_IAM \354\240\225\353\246\254.md" "b/_posts/2024-03-13-aws01_IAM \354\240\225\353\246\254.md" new file mode 100644 index 000000000000..ffd117d89a73 --- /dev/null +++ "b/_posts/2024-03-13-aws01_IAM \354\240\225\353\246\254.md" @@ -0,0 +1,170 @@ +--- +layout: single +title: "IAM 기본 정리" +categories: [AWS] +tag: [AWS, IAM] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + +## IAM 이란? + +**유저를 관리하고 접근 레벨 및 권한에 대한 관리** + +- 접근키(Access Key), 비밀키(Secret Access Key) +- 매우 세밀한 접근 권한 부여 기능 (Granular Permission) +- 비밀번호를 수시로 변경 가능하게 해줌 +- Multi-Factor Authentication(다중 인증) 가능 + +- 그룹(Group) +- 유저(User) +- 역할(Role): 유저와 의미는 비슷하나 역할에 하나 혹은 다수의 정책을 지정할 수 있음, 유저마다 다양한 정책을 부여 +- 정책(Policy) : 주로 JSON 형태로 되어 있는 다큐먼트, 세밀한 접근 권한을 일일히 설정하여 하나의 정책 다큐먼트를 만들 수 있음. + - 정책은 그룹, 역할에 추가시킬 수 있다. 유저에게 직접적으로 정책을 줄 수도 있지만 사용자 그룹에 대해서 줄수도 있다. + - 하나의 그룹 안에 다수의 유저가 존재 가능하다. + - 그룹에 역할 혹은 정책을 추가시키게 되면 그 안의 모든 유저에게 영향이 간다. + +- IAM은 유니버셜함 → 지역 변경이 필요 없음. + +### User 사용자 생성 + +IAM > 액세스 관리 > 사용자 생성 클릭 후 사용자 이름 입력 + +![스크린샷 2024-08-22 오전 11.06.53.png](/assets/images/aws01/01.png) + +자동 생성된 암호 선택 : 사용자 생성 후 자동 생성된 암호를 csv로 다운로드 후 닫기버튼 눌러야함. (닫은 후에는 다시 확인 불가) + +2단계 : 권한 설정 + +![스크린샷 2024-08-22 오전 11.07.13.png](/assets/images/aws01/02.png) + +권한 옵션을 선택하여 생성하는 사용자를 기존 그룹에 추가할 수 있다. + +### Group 그룹 + +![스크린샷 2024-08-22 오전 11.10.22.png](/assets/images/aws01/03.png) + +생성된 그룹 정보에서 사용자 및 권한을 추가할 수 있다. + +### Role 역할 생성 + +![스크린샷 2024-08-22 오전 11.11.31.png](/assets/images/aws01/04.png) + +역할 유형을 선택(AWS 서비스)을 하고, 사용할 서비스를 선택한다. + +### Policy 정책 생성 + +정책 생성 > 정책에 적용되는 서비스를 선택 + +![스크린샷 2024-08-22 오전 11.56.10.png](/assets/images/aws01/05.png) + +여기서 액세스 수준을 선택할 수 있는데 읽기, 쓰기 모두 선택함. + +아래에 리소스를 모두 선택할 수 있고, 특정 리소스를 선택할 수도 있다. + +![스크린샷 2024-08-22 오전 11.57.07.png](/assets/images/aws01/06.png) + +권한 목록에서 생성한 권한을 클릭 후, JSON 형태로 확인/수정 가능하다. + +![스크린샷 2024-08-22 오전 11.15.21.png](/assets/images/aws01/07.png) + +## IAM 정책 시뮬레이터 + +개발환경에서 실제 환경 프로덕션으로 빌드하기 전에 IAM 정책 또는 Role들이 잘 작동되는지 테스트하기 위한 툴 + +IAM과 관련된 문제들을 디버깅하기에 최적화된 툴, 이미 실제로 유저에 부여된 다양한 정책들도 테스트 가능 + +IAM > 대시보드 > 오른쪽 메뉴에 정책 시뮬레이터 클릭 + +왼쪽 메뉴의 드롭다운에서 시뮬레이션 할 대상을 선택 (Users, Groups, Roles 선택 가능) + +![스크린샷 2024-08-22 오전 11.16.30.png](/assets/images/aws01/08.png) + +Select Service : 시뮬레이션 할 서비스 선택한다. + +![스크린샷 2024-08-22 오전 11.16.58.png](/assets/images/aws01/09.png) + +Select actions : 시뮬레이션할 기능들을 선택한다. (나는 Select All 클릭) + +![스크린샷 2024-08-22 오전 11.17.10.png](/assets/images/aws01/10.png) + +Run Simulation을 실행하면 시뮬레이션 결과로 권한이 access / denied로 나옴 + +![스크린샷 2024-08-22 오전 11.17.27.png](/assets/images/aws01/11.png) + +시뮬레이션 한 유저에 AmazonDynamoDBReadOnlyAccess 추가 후 다시 테스트 + +![스크린샷 2024-08-22 오전 11.19.57.png](aws01/12.png) \ No newline at end of file diff --git a/_posts/2024-04-25-aws03_X-Forwared-For.md b/_posts/2024-04-25-aws03_X-Forwared-For.md new file mode 100644 index 000000000000..9609f718085d --- /dev/null +++ b/_posts/2024-04-25-aws03_X-Forwared-For.md @@ -0,0 +1,31 @@ +--- +layout: single +title: "X-Forwared-For란?" +categories: [AWS] +tag: [AWS] +toc: true +toc_sticky: true +post-header: false + +--- + +### X-Forwared-For 헤더 + +단순히 포트만 열어두고 Application 서비스를 올리는 경우가 아닌 NGINX 및 AWS CloudFront 또는 Application Load Balancer 같이 앞단에 프록시 서버를 두는 경우가 있다. + +이러한 경우 앱 서버(WAS)는 유저의 request가 리버스 프록시를 통해 접속하는데, 이 경우 서버의 접속 로그에 찍히는 IP는 리버스 프록시 서버의 IP(Private IP)만 가져온다. 출처를 알 수 없음 + +![스크린샷 2024-08-22 오후 1.48.39.png](/assets/images/aws03/01.png) + +이러한 문제를 해결하기 위해 표준헤더인 X-Forwarded-For가 등장하게 되고, HTTP 헤더에 타고 있는 X-Forwarded-For를 통해 프록시 및 로드밸런서 아이피를 기록한다. + +> X-Forwared-For: <client>, <proxy1>, <proxy2> +> + +HTTP HEAD에 타고 있는 형태로 구성되며, client IP → Proxy Server1 → Proxy Server2 → … 순차적으로 추가되는 방식으로 구성 + +이 설정은 각 프록시 서버별로 세팅이 필요하거나 자동으로 해더에 같이 넣어줌 + +- AWS ELB → 자동으로 X-Forwarded-For 헤더가 추가되거나 새롭게 생성 + +즉, 순차적으로 서버를 넘어가면서 받은 아이피를 기록하는 해더에서 실제 출처 IP를 찾을 수 있다. \ No newline at end of file diff --git "a/_posts/2024-05-02-aws4_AWS VPC\354\231\200 Public,Private Subnet \354\203\235\354\204\261.md" "b/_posts/2024-05-02-aws4_AWS VPC\354\231\200 Public,Private Subnet \354\203\235\354\204\261.md" new file mode 100644 index 000000000000..26007c5d3ee9 --- /dev/null +++ "b/_posts/2024-05-02-aws4_AWS VPC\354\231\200 Public,Private Subnet \354\203\235\354\204\261.md" @@ -0,0 +1,282 @@ +--- +layout: single +title: "AWS VPC와 Public,Private Subnet 생성" +categories: [AWS] +tag: [AWS, EC2, VPC] +toc: true +toc_sticky: true +post-header: false + +--- + +## 구축 순서 + +VPC 생성 → 서브넷 생성 → 인터넷 게이트웨이 생성 → 퍼블릭 라우팅 → 라우팅 테이블 생성 및 설정 + +![스크린샷 2024-08-23 오후 3.33.55.png](/assets/images/aws04/01.png) + +## VPC (Virtual Private Cloud) + +- AWS 클라우드의 프라이빗 가상 네트워크 +- 보통 AWS 리전 및 가용 영역의 고가용성을 기반으로 구축한다. +- VPC는 한 리전 내에 상주하며, 여러 가용영역에 걸쳐 사용 가능하다. +- VPC는 네트워크 구성을 완벽하게 제어할 수 있도록 허용한다. +- VPC 내부의 리소스를 격리하고 노출할 수 있는 기능이 있다, (서브넷, 액세스 제어 목록 정의, 라우팅 규칙 등) +- 여러 계층의 보안 제어 기능을 제공한다. +- 특정 인터넷 및 내부 트래픽을 허용 및 거부할 수 있는 기능이 있다. +- 다른 AWS 서비스를 VPC에 배포할 수 있다. + +## 1. VPC 생성 + +VPC 이름은 이름-리전-vpc로 작성하였다. + +이후, IPv4 CIDR 블록에 생성할 VPC IP 대역대를 입력 + +![스크린샷 2024-08-22 오후 4.05.26.png](/assets/images/aws04/02.png) + +## 2. Public subnet 생성 + +### Subnet이란? + +VPC를 나누는 데 사용된다. VPC안에 나누어진 부분 네트워크라고 할 수 있다. + +보통 VPC를 IP로 구분해 나눈 후에 다중 AZ(가용영역)에 걸쳐 서브넷을 구성한다. + +- 퍼블릭 서브넷 + - 인터넷에 직접 엑세스가 가능한 서브넷이다. + - 인터넷 게이트웨이를 VPC에 연결하고 퍼블릭 서브넷의 라우팅 테이블을 업데이트하여 로컬이 아닌 트래픽을 인터넷 게이트웨이로 보내면 퍼블릭 서브넷처럼 사용할 수 있다. +- 프라이빗 서브넷 + - 인터넷에 직접 액세스가 불가능한 서브넷이다. + - 보통 회사 내부 서버나 프로그램들은 프라이빗 서브넷에 위치시켜 인터넷을 통해 아무나 접근이 불가능하게 한다. + +### Public Subnet을 각각 A,C 가용영역에 생성해보기 + +![스크린샷 2024-08-22 오후 4.01.51.png](/assets/images/aws04/03.png) + +서브넷을 생성할 VPC를 목록에서 선택하고, 서브넷 이름은 이름-public-subnet-가용영역으로 생성하였다. + +![스크린샷 2024-08-22 오후 4.09.50.png](/assets/images/aws04/04.png) + +첫번째로, 가용영역 A에 서브넷을 생성해준다. + +IPv4 CIDR 블록에는 선택한 VPC의 IP범위 내, 생성할 서브넷의 IP 대역대를 입력한다. + +![스크린샷 2024-08-22 오후 4.12.16.png](/assets/images/aws04/05.png) + +새 서브넷 추가를 클릭하여 가용영역 C에 서브넷을 하나 더 추가해준다. + +![스크린샷 2024-08-22 오후 4.54.01.png](/assets/images/aws04/06.png) + +## 3. Internet Gateway 생성 + +Internet Gateway란 + +- VPC에 부착되어, VPC와 인터넷 간에 통신할 수 있게 해주는 출입문 역할을 한다. +- 방금 만든 서브넷들이 퍼블릭 서브넷 역할을 하게끔 해주려면, 인터넷으로 접속할 수 있어야 하기 때문이다. + +![스크린샷 2024-08-22 오후 4.17.29.png](/assets/images/aws04/07.png) + +이제 방금 만든 인터넷 게이트웨이를 선택해서 VPC와 연결을 해준다. + +![스크린샷 2024-08-22 오후 4.18.42.png](/assets/images/aws04/08.png) + +![스크린샷 2024-08-22 오후 4.19.53.png](/assets/images/aws04/09.png) + +![스크린샷 2024-08-22 오후 4.20.27.png](/assets/images/aws04/10.png) + +## 4. Public 전용 라우팅 테이블 생성 + +Routing Table 이란 + +- IP 주소에 트래픽 라우팅 경로를 정의하여 Subnet 안팎으로 나가는 트래픽에 대한 라우팅 경로 설정 기능을 수행한다. +- 인터넷을 통해 요청이 들어왔을 때, 요청이 들어올 경로 안내를 하는 네비게이션 역할을 한다. + +라우팅 테이블이 사용할 VPC를 목록에서 선택 후 생성해준다. + +![스크린샷 2024-08-22 오후 4.24.05.png](/assets/images/aws04/11.png) + +그다음, 라우팅 테이블 목록에서 라우팅 테이블을 체크 후 ‘서브넷 연결 편집’ 메뉴를 통해 서브넷과 연결해준다. + +![스크린샷 2024-08-22 오후 4.26.06.png](/assets/images/aws04/12.png) + +‘서브넷 연결 편집’은 해당 라우팅 테이블이 어떤 서브넷에 적용이 되는지 설정해주는 곳이다. + +퍼블릭 서브넷 역할을 하게 할 라우팅 테이블이므로, 퍼블릭 역할을 하게 될 서브넷들만 선택한다. + +![스크린샷 2024-08-22 오후 4.27.49.png](/assets/images/aws04/13.png) + +이제 어떤 라우팅을 해줄 것인지 설정해주면 된다. + +방금 등록한 라우팅 테이블을 선택 후 ‘라우팅 편집 버튼’을 클릭하여 설정해준다. + +![스크린샷 2024-08-22 오후 4.28.47.png](/assets/images/aws04/14.png) + +local : 현재 기본 설정되어 있는 라우팅, VPC 대역대에 있는 IP들 (즉, VPC 내부의 Private IP)들이 서로 알고있게끔 하는 기본 설정이다. + +라우팅을 추가하여 대상에는 0.0.0.0/0을 입력, 만든 Internet Gateway로 설정한다. + +즉, 위치 무관 아무나 들어올 수 있게 추가한다는 의미 + +![스크린샷 2024-08-22 오후 4.32.17.png](/assets/images/aws04/15.png) + +이제 VPC에 priavte subnet을 구축해보자 + +프라이빗 서브넷 생성 → 프라이빗 라우팅 테이블 생성 및 설정 순으로 진행 + +## 5. Private Subnet 생성 + +이전과 비슷한 방식으로 가용영역 A,C에 생성해준다. + +이름-private-subnet-가용영역 으로 생성하고, 서브넷의 IP대역대를 설정해준다. + +![스크린샷 2024-08-22 오후 4.44.27.png](/assets/images/aws04/16.png) + +![스크린샷 2024-08-22 오후 4.47.24.png](/assets/images/aws04/17.png) + +## 6. Private 라우팅 테이블 생성 + +라우팅 테이블 이름과 사용될 VPC를 선택하고 생성해준다. + +![스크린샷 2024-08-22 오후 4.48.23.png](/assets/images/aws04/18.png) + +‘서브넷 연결 편집’ 메뉴에서 방금 만든 private subnet들을 선택하여 등록해준다. + +![스크린샷 2024-08-22 오후 4.50.01.png](/assets/images/aws04/19.png) + +private subnet에 위치하게 될 리소스들은 private IP만 가지기 때문에 내부가 아닌 외부의 리소스들과 통신을 할 수 없게 된다. + +### NAT 인스턴스 생성 + +private IP를 public IP로 변환해 private IP는 감추고, 통신을 할 수 있도록 하게 해준다. + +NAT Gateway는 비용이 비싸므로 NAT역할을 할 수 있는 NAT Instance를 생성하여 EC2의 t2.micro 비용으로 NAT 역할을 하는 서버를 만들것이다. + +프라이빗 라우팅 테이블에 이 NAT Instance를 추가하면 private subnet안의 리소드들은 이를 통해 외부 리소스들과 통신할 수 있게 된다. + +## 7. EC2(NAT Instance) 생성 + +- private subnet 내의 웹 서버들이 외부로 통신을 하기 위해 사용하는 서버 +- 보통 NAT서버를 public subnet안에 구축하여 NAT를 통해 외부로 통신함 + +AMI 선택 + +AMI > ‘nat’로 검색 > 아무버전이나 선택 > AMI로 인스턴스 시작 + +![스크린샷 2024-08-22 오후 5.46.13.png](/assets/images/aws04/20.png) + +인스턴스 유형 : t2.micro 선택 + +VPC : 내가 만든 vpc 선택 + +서브넷 : public subnet - a 선택 + +스토리지 : default + +![스크린샷 2024-08-22 오후 5.51.53.png](/assets/images/aws04/21.png) + +새로운 keypair 생성 + +보안 그룹 추가 : 내 PC에서만 SSH 접속이 가능하도록 설정 + +마지막으로, NAT는 소스/대상 확인을 하면 안됩니다 + +그렇기 때문에 방금 생성한 nat instance 서버를 체크하고 작업-네트워킹-소스/대상 확인 변경 클릭 + +소스/대상 확인의 ‘중지’를 체크하고 저장하기 + +![스크린샷 2024-08-22 오후 5.58.21.png](/assets/images/aws04/22.png) + +## 8. 탄력적 IP 주소 할당 + +- 탄력적 IP 주소는 인터넷에서 연결 가능한 퍼블릭 IPv4 주소 이다. +- AWS 계정에 할당되며 릴리스할 때까지 할당된 상태로 유지된다. +- 탄력적 IP주소를 생성해 방금 만든 인스턴스에 연결해주면 해당 인스턴스 IP는 고정 IP주소가 된다. + +![스크린샷 2024-08-22 오후 6.01.05.png](/assets/images/aws04/23.png) + +생성할 때, 맨 아래에 Name 태그를 하나 추가해줘서 식별해주기 + +![스크린샷 2024-08-22 오후 6.02.07.png](/assets/images/aws04/24.png) + +### 탄력적 IP주소 연결 + +EIP를 생성했으면 해당 EIP를 사용할 인스턴스를 연결해야 한다. + +해당 EIP를 체크해주고, 작업 매뉴에서 탄력적 IP 주소 연결 실행 + +![스크린샷 2024-08-22 오후 6.02.57.png](/assets/images/aws04/25.png) + +연결할 인스턴스를 선택하고 연결 버튼 클릭. + +주의) EIP는 AWS에게 IP주소를 빌려오는 개념이기 때문에 EIP에 인스턴스를 연결해주지 않으면 오히려 요금이 부과되는 형태이다. 만약 EC2 인스턴스를 릴리즈(종료)할려면, 꼭 EIP도 같이 릴리즈하기 + +![스크린샷 2024-08-22 오후 6.04.44.png](/assets/images/aws04/26.png) + +이제 NAT Instance 생성 및 설정이 완료되었으니, 0.0.0.0/0 트래픽을 NAT를 통해 들어올 수 있도록 바꾸면 된다. + +라우틴 테이블 편집하여 대상을 0.0.0.0/0, 인스턴스 선택 → nat instance를 선택한다. + +![스크린샷 2024-08-22 오후 6.07.37.png](/assets/images/aws04/27.png) + +이제 private subnet a에 EC2 인스턴스 생성하여 웹서버를 구축해준다. + +기존에 가지고 있던 간단한 AMI로 생성해준다. + +keypair는 nat instance의 keypair로 사용. + +private subnet으로 네트워크 설정을 했으므로 아래와 같이 퍼블릭 IP주소는 할당이 안되게 잘 생성해주자. + +![스크린샷 2024-08-22 오후 6.52.48.png](/assets/images/aws04/28.png) + +## 9. ALB & Target Group 생성 + +### ALB(Application Load Balancer) + +- 둘 이상의 가용 영역에서 EC2 인스턴스, 컨테이너, IP주소 등 여러 대상에 걸쳐 수신되는 트래픽을 자동으로 분산하는 서비스 +- LB는 등록된 대상의 상태를 모니터링하며, 상태가 양호한 대상으로만 트래픽을 라우팅 해준다. +- LB에는 여러 종류가 있음(Application LB, Network LB, Gateway LB, Classic LB) +- 특히, ALB는 HTTP의 URL, FTP의 파일명, 쿠키 정보 등을 분석해 더 정교한 로드 밸런싱이 가능한 서비스이다. + +EC2 - 로드 밸런싱 - 로드밸런서 클릭 + +![스크린샷 2024-08-22 오후 7.00.33.png](/assets/images/aws04/29.png) + +[Application Load Balancer 선택] + +이름 : tester-alb + +체계 : 인터넷 경계 + +VPC : tester-seoul-vpc + +가용영역 : a,c체크 및 public-subnet-a,c 선택 + +보안그룹 : 인바인드 규칙 0.0.0.0/0 80port + +![스크린샷 2024-08-22 오후 7.02.06.png](/assets/images/aws04/30.png) + +![스크린샷 2024-08-22 오후 7.03.10.png](/assets/images/aws04/31.png) + +리스너 및 라우팅 + +간단하게 http 통신을 해볼것이기 때문에 80포트 사용(spring, node.js 등의 웹서버를 올리려면 해당 웹서버에서 사용하는 포트로 지정) + +![스크린샷 2024-08-22 오후 7.11.11.png](/assets/images/aws04/32.png) + +대상 그룹 생성 클릭하여 대상 그룹 지정해주기 + +ALB 대상은 인스턴스이므로 인스턴스 선택 + +프로토콜 : 포트 지정 + +![스크린샷 2024-08-22 오후 7.13.19.png](/assets/images/aws04/33.png) + +![스크린샷 2024-08-22 오후 7.13.42.png](/assets/images/aws04/34.png) + +ALB가 해당 옵션으로 타겟의 healthy/unhealty 상태를 검사함. + +![스크린샷 2024-08-22 오후 7.14.00.png](/assets/images/aws04/35.png) + +생성을 클릭하면 아래와 같은 화면에서 등록할 대상 즉, 인스턴스를 선택할 수 있다. + +![스크린샷 2024-08-22 오후 7.16.26.png](/assets/images/aws04/36.png) \ No newline at end of file diff --git "a/_posts/2024-05-04-OLAP\354\231\200 OLTP.md" "b/_posts/2024-05-04-OLAP\354\231\200 OLTP.md" new file mode 100644 index 000000000000..1f8a10e1942f --- /dev/null +++ "b/_posts/2024-05-04-OLAP\354\231\200 OLTP.md" @@ -0,0 +1,80 @@ +--- +layout: single +title: "OLAP와 OLTP" +categories: [CS] +tag: [cs] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + +## 1. OLTP (Online Transaction Processing) + +### OLTP 정의 + +- ‘운영’계 데이터 및 데이터를 처리하는 방법을 의미한다. +- 복수의 사용자 PC에서 발생되는 트랜잭션을 DB서버가 처리, 그 결과를 요청한 사용자에게 실시간으로 결과값을 되돌려주는 과정 +- 1개의 트랜잭션에서 발생되는 INSERT, UPDATE, DELETE를 무결성 보장하여 처리하고 결과를 SELECT하는 과정 + +### OLTP의 특징 + +- 과거에는 주로 RDBMS 기반의 시스템을 근간으로 했으나 NoSQL도 운영계 데이터의 성격을 띤다면 OLTP로 분류 가능 +- 현재 데이터가 처리가 얼마나 정확하고 무결한지가 중요 +- 실질적인 데이터의 저장, 삭제, 수정 등의 작업을 의미 +- 비교적 작은 규모의 트랜잭션들로 구성 +- CRUD와 관련된 쿼리들이 주를 이룸 +- 전통적인 DBMS들이 주로 사용됨 + +## 2. OLAP (Online Analytical Processing) + +### OLAP의 정의 + +- ‘분석’계 데이터 및 데이터를 처리하는 방법을 의미한다. +- 데이터 웨어하우스(DW), DB에 저장되어 있는 데이터를 분석, 사용자에게 유의미한 정보를 제공해주는 처리 방법이다. +- 기존에 저장되어 있는 데이터를 사용자의 요구와 목적에 맞게 분석하여 정보를 제공하는 개념 + +### OLAP의 특징 + +- 분석을 통해 BI(Business Intelligence)와 연계하여 특정 지표 추출, 리포트 생산, 의사 결정에 도움 +- 이미 저장된 데이터를 바탕으로 어떤 정보를 제공하는지가 중요 +- 데이터가 무결, 정확하다는 전재 하에 정보를 어떤 식으로 표현하고 제공하는지를 의미 +- 대용량 데이터를 취급 +- 통계/집계 등의 복잡한 쿼리들이 주를 이룸 +- DW(Data Warehouse)를 구축 +- 데이터가 어느정도 중복이 되더라도 별 상관이 없으며 많은 데이터 수집이 필요 + +## OLTP와 OLAP 비교 + +| 구분 | OLTP | OLAP | +| --- | --- | --- | +| 목적 | 비즈니스 활동 지원 | 비즈니스 활동에 대한 평가, 분석 | +| 주 트랜잭션 형태 | SELECT, INSERT, UPDATE, DELETE | SELECT | +| 속도 | 수 초 이내 | 수 초 이상 수 분 이내 | +| 데이터 표현 시간 | 실시간 | 과거 | +| 관리 단위 | 테이블 | 분석된 정보 | +| 최적화 방법 | 트랜잭션 효율화, 무결성 극대화 | 조회 속도, 정보의 가치, 편의성 | +| 데이터의 특성 | 트랜잭션 중심 | 정보 중심 | +| 중요점 | 데이터의 정확도, 무결성 | 결과의 속도, 표현 방식 | +| 활용자 | 운영자 | 분석가, 의사결정자1 | + +- OLTP와 OLAP 중 가장 선행되어야 할 부분은 OLTP (데이터 처리 과정 및 데이터 자체의 무결성 중요) +- OLTP가 원천 데이터의 제공처이며 ETL작업을 통해 OLAP에 데이터를 제공 \ No newline at end of file diff --git "a/_posts/2024-05-10-RDS\354\235\230 ElastiCache.md" "b/_posts/2024-05-10-RDS\354\235\230 ElastiCache.md" new file mode 100644 index 000000000000..8d303edc99a0 --- /dev/null +++ "b/_posts/2024-05-10-RDS\354\235\230 ElastiCache.md" @@ -0,0 +1,45 @@ +--- +layout: single +title: "RDS의 ElastiCache" +categories: [AWS] +tag: [AWS, RDS] +toc: true +toc_sticky: true +post-header: false + +--- + +## ElastiCache + +- 클라두으 내에서 In-memory 캐시를 만들어줌 +- 데이터베이스에서 데이터를 읽어오는것이 아니라 캐시에서 빠른 속도로 데이터를 읽어옴 + - 수백, 수천만 개의 프로세싱을 동시다발적으로 처리할 경우 큰 차이가 생김 + - 종종 불러오는 레코드들은 예를 들면 SNS, 네이버 실시간 검색어 Top10 등 많은 사람들에 의해서 읽혀지는 데이터들을 캐시에 넣음으로써 빠른 로딩을 가능하게 함 +- Read-Heavy 어플리케이션에서 상당한 Latency 감소 효과가 있음 +- 초반 어플리케이션 개발 및 테스트 용도로는 적합하지 않음 +- Elasti Cache는 Memcached와 Redis가 존재한다. + +## Memcached + +- Object 캐시 시스템으로 잘 알려져 있음 +- ElastiCache는 Memcached의 프로토콜을 디폴트로 따름 +- EC2 Auto Scaling처럼 데이터 처리 사용량에 따라 캐시의 크기가 커졌다 작아졌다 가능함 +- Memcached는 오픈 소스이다. + +### Memcached는 이럴때 사용하면 좋다! + +1. 가장 단순한 캐싱 모델이 필요한가요? Yes +2. Object caching이 주된 모기적인가요? Yes +3. 캐시 크기를 마음대로 scaling하기를 원하나요? Yes + +## Redis + +- Key-Value, Set, List와 같은 형태의 데이터를 In-Memory에 저장 가능함 +- 오픈 소스이다. +- Multi-AZ 기능을 지원한다. (Disaster Recovery 기능) + +### Redis는 이럴때 사용하면 좋다! + +1. List, Set과 같은 데이터셋을 사용하나요? Yes +2. 리더보드처럼 데이터셋의 랭킹을 정렬하는 용도가 필요한가요? Yes +3. Multi AZ기능이 필요하나요? Yes \ No newline at end of file diff --git "a/_posts/2024-05-10-aws5_AWS RDS \353\260\261\354\227\205.md" "b/_posts/2024-05-10-aws5_AWS RDS \353\260\261\354\227\205.md" new file mode 100644 index 000000000000..2f5d652b8edd --- /dev/null +++ "b/_posts/2024-05-10-aws5_AWS RDS \353\260\261\354\227\205.md" @@ -0,0 +1,40 @@ +--- +layout: single +title: "AWS RDS 백업" +categories: [AWS] +tag: [AWS, RDS] +toc: true +toc_sticky: true +post-header: false + +--- + +AWS RDS에는 두 가지 백업 기능이 존재한다. + +- Automated Backups (자동 백업) +- DB Snapshots (데이터베이스 스냅샷) + +## Automated Backups(AB) - 자동 백업 + +1. Retention Period(1 ~ 35일) 안의 어떤 시간으로 돌아가게 할 수 있음 + - 현 시점부터 35일 전까지가 Retenntion Period에 해당 +2. AB는 그날 생성된 스냅샷과 Transaction logs(TL)을 참고함 + - AB는 복원을 대비하기 위해 매일 스냅샷과 트랜잭션 로그를 끊임없이 생성함 + - 유저가 고른 날짜로 돌아가길 원한다면 그 날짜에 해당하는 스냅샷과 트랜잭션 로그를 참조한다. +3. 디폴트로 AB기능이 설정되어 있으며 백업 정보는 S3에 저장됨 + - RDS 인스턴스 크기만큼에 해당되는 용량까지만 무료로 사용 가능 +4. AB동안 약간의 I/O suspension이 존재할 수 있음(체감상 크게 느껴지지는 않지만 어느정도 딜레이 존재) + +## DB Snapshots - 데이터베이스 스냅샷 + +1. 주로 사용자에 의해 실행됨 +2. 원본 RDS Instance를 삭제해도 스냅샷은 존재함 + - 원본 RDS 인스턴스를 삭제해도 스냅샷은 S3에 존재함 + - AB 기능은 원본 인스턴스를 삭제할 시 사라짐 + +## 데이터베이스 백업했을 때 + +![스크린샷 2024-08-24 오후 9.52.55.png](/assets/images/aws05/1.png) + +- 전혀 다른 RDS 인스턴스가 생성된다. +- 전혀 다른 RDS 엔드포인트가 생성된다. \ No newline at end of file diff --git "a/_posts/2024-05-10-aws6_RDS\354\235\230 Multi AZ, Read Replicas.md" "b/_posts/2024-05-10-aws6_RDS\354\235\230 Multi AZ, Read Replicas.md" new file mode 100644 index 000000000000..d5089602a22e --- /dev/null +++ "b/_posts/2024-05-10-aws6_RDS\354\235\230 Multi AZ, Read Replicas.md" @@ -0,0 +1,39 @@ +--- +layout: single +title: "RDS의 Multi AZ, Read Replicas" +categories: [AWS] +tag: [AWS, RDS] +toc: true +toc_sticky: true +post-header: false + +--- + +## Multi AZ + +- 원래 존재하는 RDS DB에 무언가 변화(ex. write)가 생길 때 다른 Availability Zone에 똑같은 복제본이 만들어짐 = Synchronize +- AWS에 의해서 자동으로 관리가 이루어짐 (No admin intervention) +- 원본 RDS DB에 문제가 생길 시 자동으로 다른 AZ의 복제본이 사용됨 (Disaster Recovery) +- 성능 개선을 위해서 사용되지는 않음 → 성능 개선을 기대하기 위해선 Read Replica 사용 + +![스크린샷 2024-08-24 오후 10.00.31.png](/assets/images/aws06/1.png) + +- 3개의 인스턴스가 하나의 프로덕션 RDS DB에 연결되어 있고 쓰기 기능이 실행된다면, +- 현재 RDS 엔드포인트는 ap-northeast-2a 이지만 쓰기 기능이 실행된 후 똑같은 복제본이 다른 AZ(ap-northeast-2b)에 쓰여진다. +- 만약 AZ 2a의 RDS에 문제가 생긴다면 RDS는 자동으로 AZ 2b로 failover를 한다. + +## Read Replica + +- 프로덕션 DB의 읽기 전용 복제본이 생성됨 +- 주로 Read-Heavy DB 작업시 효율성의 극대화를 위해 사용된다 (Scaling) +- Disaster Recovery 용도가 아님 +- 최대 5개의 Read Replica DB가 허용됨 +- Read Replica의 Read Replica 생성이 가능(단, 약간의 Latency 발생) +- 각각의 Read Replica는 자기만의 고유 엔드포인트가 존재한다. +- RDS DB는 IP 주소가 아닌 엔드포인트로 고유 식별을 할 수 있다. + +![스크린샷 2024-08-24 오후 10.29.56.png](/assets/images/aws06/2.png) + +- 3개의 인스턴스가 하나의 메인 프로덕션 RDS에 연결되어 있을 때 쓰기 작업이 실행될 시 read replica에 의해 똑같은 RDS 복제본이 생성된다, +- 그리고 3개의 인스턴스에서 Read Traffic이 일어날 때, 메인 프로덕션 DB로 모두 연결시키는것이 아니라 하나의 EC2 인스턴스를 각각의 Read Replica로 연결시켜줌 +- 따라서, 메인 DB의 워크로드를 현저히 낮출 수 있으며 성능 개선 효과를 누릴 수 있다. \ No newline at end of file diff --git "a/_posts/2024-05-15-aws07_RDS \354\203\235\354\204\261 \353\260\217 EC2 \354\235\270\354\212\244\355\204\264\354\212\244 \354\227\260\352\262\260.md" "b/_posts/2024-05-15-aws07_RDS \354\203\235\354\204\261 \353\260\217 EC2 \354\235\270\354\212\244\355\204\264\354\212\244 \354\227\260\352\262\260.md" new file mode 100644 index 000000000000..858e9cc649d2 --- /dev/null +++ "b/_posts/2024-05-15-aws07_RDS \354\203\235\354\204\261 \353\260\217 EC2 \354\235\270\354\212\244\355\204\264\354\212\244 \354\227\260\352\262\260.md" @@ -0,0 +1,154 @@ +--- +layout: single +title: "RDS 생성 및 EC2 인스턴스 연결하기" +categories: [AWS] +tag: [AWS, RDS] +toc: true +toc_sticky: true +post-header: false + +--- + +## RDS 생성 + +RDS > 데이터베이스 생성 > MySQL로 생성 > 버전은 기본으로 선택(MySQL 8.0.35) + +![스크린샷 2024-08-26 오전 12.24.32.png](/assets/images/aws07/1.png) + +템플릿에서 프로덕션과 개발/테스트 를 선택하면 아래에 Multi AZ 기능을 사용할 수 있다. + +프리티어에서는 사용 불가. + +![스크린샷 2024-08-26 오전 12.25.56.png](/assets/images/aws07/2.png) + +DB인스턴스 이름과 어드민 사용자 이름, 암호를 설정한다. + +![스크린샷 2024-08-26 오전 12.27.22.png](/assets/images/aws07/3.png) + +그다음에 인스턴스 구성을 한다. 프리티어를 선택했기 때문에 버스터블 클래스 이외에는 선택사항이 없다. + +버스터블 클래스란 상황에 따라서 CPU의 성능을 버스트시킬 수 있다는 뜻이다. + +![스크린샷 2024-08-26 오전 12.34.24.png](/assets/images/aws07/4.png) + +스토리지 유형은 범용 SSD(gp2)로 선택한다. 스토리지 유형 목록을 보면 GP3란게 있는데, 이건 추가 비용을 냄으로써 IOPS 처리량을 늘릴 수 있다. + +할당된 스토리지의 크기는 간단한 시스템을 유지하기 위해 20GIB로 설정한다. + +스토리지 자동 조정 활성화란게 있는데 오토 스케일링을 뜻한다. 최대 스토리지 임계값은 디폴트(1000GIB)로 설정해준다. + +![스크린샷 2024-08-26 오전 12.35.57.png](/assets/images/aws07/5.png) + +## EC2 인스턴스 연결 + +그 다음은 컴퓨팅 리소스에 대해서 묻는데, 최근 UI 업데이트를 통해 여기서 직접 EC2 인스턴스를 만들어서 RDS와 바로 연결시킬 수 있다. + +![스크린샷 2024-08-26 오전 12.40.32.png](/assets/images/aws07/6.png) + +여기서 RDS와 연결해줄 EC2 인스턴스를 생성해둔다. + +- 인스턴스명 : aws-learner-rds-ec2-instance, 내가 가지고 있는 기존 키페어(testkey.pem) 선택 +- 보안 그룹 : http 80포트와 ssh 22포트를 위치무관 접속할 수 있게 설정. + + ![스크린샷 2024-08-26 오전 12.50.23.png](/assets/images/aws07/7.png) + +- 고급 세부 정보 > 사용자 데이터 에서 편리한 설정을 위해 EC2 인스턴스가 생성되면서 실행될 스크립트 내용을 넣어준다. +- EC2 인스턴스 생성 후 apache, php, mysql을 yes 옵션으로 설치 후 아파치 실행 +- 간단한 php파일을 아파치 서버 디렉토리 내에 index.php로 저장 +- wget 명령어로 S3내의 connect.php 파일을 다운로드 + +connect.php 파일 내용 + +```php +"; +$selected = mysql_select_db("$dbname",$dbhandle) or die("MySQL DB 연결 실패... - 다시 시도해보세요!"); +?> +``` + +EC2 인스턴스 생성이 완료되었으면 다시 RDS 생성 화면으로 돌아와서 방금 생성한 EC2 인스턴스를 선택해준다. + +![스크린샷 2024-08-26 오전 12.53.56.png](/assets/images/aws07/8.png) + +VPC는 디폴트로 만들어질것이고, DB 서브넷 그룹은 기존 항목을 선택하거나 자동설정으로 선택해준다. + +VPC 보안 그룹은 선택/생성이 있는데 기존에 생성했던 ssh, http 접근이 가능한 보안그룹으로 선택해줬다. + +![스크린샷 2024-08-26 오전 12.57.35.png](/assets/images/aws07/9.png) + +다음으로 가용영역이 있는데, 지금은 프리티어 용이라 Multi-AZ 기능을 사용할 수 없으므로 선택 권한이 없다. + +추가 구성에서 데이터베이스 포트를 지정할 수 있다. (MySQL default 포트는 3306) + +![스크린샷 2024-08-26 오전 12.58.21.png](/assets/images/aws07/10.png) + +다음은 데이터페이스 암호 인증을 선택할 수 있는 곳이다. 여기선 위에서 부여했던 어드민 사용자, 암호를 가지고 데이터베이스에 접속할 수 있게끔 ‘암호 인증’을 선택해 줬다. + +![스크린샷 2024-08-26 오전 1.00.07.png](/assets/images/aws07/11.png) + +마지막으로 추가구성에서 데이터베이스 옵션에서는 초기 데이터베이스 이름을 설정해주고 나머지는 디폴트로 설정해줬다. + +![스크린샷 2024-08-26 오전 1.03.15.png](/assets/images/aws07/12.png) + +## EC2 인스턴스 확인 + +방금 RDS와 연결한 인스턴스를 퍼블릭 IP주소로 접속해보면 php 화면이 뜬다. + +![스크린샷 2024-08-26 오전 1.54.05.png](/assets/images/aws07/13.png) + +이제 이 EC2 인스턴스에 터미널로 접속해본다. + +![스크린샷 2024-08-26 오전 1.56.45.png](/assets/images/aws07/14.png) + +아까 EC2를 생성할 때 입력했던 구문중 connect.php 파일 내용 확인 + +/var/www/html 폴더에 wget 이동 + +![스크린샷 2024-08-26 오전 1.58.31.png](/assets/images/aws07/15.png) + +- vi connect.php +- hostname 값을 생성한 RDS 인스턴스의 엔드포인트명으로 바꿔준다. + + ![스크린샷 2024-08-26 오전 3.20.47.png](/assets/images/aws07/16.png) + + +수정 한 후 ec2 DNS명/connect.php로 확인해보기 + +확인해보면 아래와 같이 MySQL에 연결할 수 없다고 나온다. + +![스크린샷 2024-08-26 오전 2.06.19.png](/assets/images/aws07/17.png) + +이유는 현재 RDS 보안그룹은 RDS 인스턴스 안에서만 존재하며, + +우리가 웹에서 접속한 EC2 인스턴스에서는 별개의 보안그룹이 존재한다. + +두 개의 서로 다른 클라우드에서 다른 보안 그룹이 존재하므로 현재 EC2에서 RDS로 통신이 불가능한 상태이다. + +## RDS 보안 그룹 확인하기 + +생성한 RDS의 보안 그룹 > 인바운드 규칙 확인 + +그다음, 이 소스를 지우고 아까 EC2 인스턴스가 속해 있는 보안 그룹을 찾아서 연결해준다. + +![스크린샷 2024-08-26 오전 2.34.04.png](/assets/images/aws07/18.png) + +그러면 이렇게 ‘기존 IPv4 CIDR 규칙에 a 참조된 그룹 ID를 지정할 수 없습니다.’ 라는 에러가 뜬다. + +위 에러를 해결하려면, 이 규칙을 삭제하고 다시 똑같이 만들어주면 지정이 된다. + +![스크린샷 2024-08-26 오전 2.36.24.png](/assets/images/aws07/19.png) + +다시 똑같이 만들어 준 후에 저장을 누른다. + +(DB 파라미터 그룹은 따로 정리.) + +다시 /connect.php 화면을 로딩해서 접속 성공 여부를 확인한다. + +![스크린샷 2024-08-26 오전 3.21.41.png](/assets/images/aws07/20.png) \ No newline at end of file diff --git "a/_posts/2024-05-15-aws08_RDS \355\214\214\353\235\274\353\257\270\355\204\260 \352\267\270\353\243\271.md" "b/_posts/2024-05-15-aws08_RDS \355\214\214\353\235\274\353\257\270\355\204\260 \352\267\270\353\243\271.md" new file mode 100644 index 000000000000..7ac610f3d0ce --- /dev/null +++ "b/_posts/2024-05-15-aws08_RDS \355\214\214\353\235\274\353\257\270\355\204\260 \352\267\270\353\243\271.md" @@ -0,0 +1,106 @@ +--- +layout: single +title: "RDS 파라미터 그룹" +categories: [AWS] +tag: [AWS, RDS] +toc: true +toc_sticky: true +post-header: false + +--- + + + + + +## RDS 파라미터 그룹 설정 + +데이터베이스 파라미터 그룹은 데이터베이스 구성 방법을 지정해준다. 데이터베이스에 할당할 메모리 등의 리소스 양을 지정할 수 있다. + +또한, DB 인스턴스와 다중 AZ DB 클러스터를 파라미터 그룹과 연결하여 데이터베이스 구성을 관리하는 작업도 지원한다고 한다. + +RDS > 파라미터 그룹에서 새로운 파라미터 그룹을 생성한다. + +![스크린샷 2024-08-26 오전 2.46.02.png](/assets/images/aws08/2.46.02.png) + +아래와 같이 설정을 마치고 생성해준다. + +- 파라미터 그룹 이름 입력 +- 엔진 유형 : MySQL Community +- 파라미터 그룹 패밀리 : mysql8.0 +- 유형 : DB Parameter Group + +![스크린샷 2024-08-26 오전 2.51.27.png](/assets/images/aws08/2.51.27.png) + +파라미터 그룹을 생성한 후에 해당 파라미터 그룹을 클릭한다. + +편집을 눌러서 파라미터 값을 수정해주면 된다. + +![스크린샷 2024-08-26 오전 2.54.49.png](/assets/images/aws08/2.54.49.png) + +1. Character Set (문자 인코딩 설정) + - 기본적으로 utf8은 많이 들어보았지만, 가변3바이트인 utf8에는 이모지 문자가 입력이 되지 않는다. + - 따라서, 4바이트를 사용하는 utf8mb4로 설정한다. +2. Time Zone(시간 설정) +3. Collation (데이터의 정렬 기준을 위한 설정) + +### 1. Character Set 설정 + +- character_set_client, character_set_connection, character_set_database, character_set_server, character_set_filesystem, character_set_results = utf8mb4 +- MySQL의 character에 대한 정리 + + +| 파라미터 | 설명 | +| ---| --- | +| **character_set_client** | - MySQL Client의 Default Character set
- Client로부터 전송되는 쿼리문장의 문자집합을 말함
- 각 커넥션에서 임의의 문자집합으로 변경해서 사용 가능 | +| **character_set_connection** | - MySQL Server가 Client로부터 전달받은 쿼리 문장에서 인트로듀서(Introducer)가 없는 리터럴(literal) 또는 숫자(number) 값을 문자(String)열로 변환할 때 사용하는 Character set
- 각 커넥션에서 임의의 문자집합으로 변경해서 사용 가능 | +| **character_set_database** | - MySQL Database의 Default Character set
- 이 변수가 지정되지 않았다면 character_set_server와 같은 값을 가짐
- 각 DB, TABLE, COLUMN은 기본 문자셋과 관계없이 개별적인 문자집합을 가질 수 있으며 DB를 생성할 때 아무런 문자집합이 명시되지 않았다면, 이 변수의 값이 기본값으로 사용됨 | +| **character_set_filesystem** | - LOAD DATA INFILE ... 또는 SELECT ... INTO OUTFILE 문장이 실행될 때 파일의 읽고 쓰기에 사용되는 Character set
- 데이터 파일의 내용을 읽을 때 사용하는 문자집합이 아닌, 파일의 이름을 찾을 때 사용하는 문자 집합
- 파일을 오픈하려는 시도가 있기 전에 character_set_client에서 character_set_filesystem으로 변환
- 기본값은 binary인데, 이것은 아무런 변환이 없다는 것을 의미
- 멀티 바이트 파일 이름을 사용할 수 있는 시스템에서는 서로 다른 값을 사용하도록 함
- 예를 들면 시스템이 UTF8로 파일이름을 표시한다면, 'utf8'로 설정
- 이 변수는 MySQL 5.1.6에서 추가
- 각 커넥션에서 임의의 문자집합으로 변경해서 사용 가능 | +| **character_set_results** | - MySQL Server가 쿼리의 처리 결과 또는 error 를 Client로 retuen 할 때 사용하는 Character set
- 각 커넥션에서의 임의의 문자집합으로 변경해서 사용 가능 | +| **character_set_server** | - MySQL Server의 Default Character set
- DB나 TABLE 또는 COLUMN에 아무런 문자집합이 설정되지 않았을 때, 이 변수의 값이 기본값으로 사용됨
- 각 커넥션에서의 임의의 문자집합으로 변경해서 사용 가능 | +| **character_set_system** | - MySQL Server가 T 식별자(Identifier, 테이블명이나 컬럼명 등)를 저장하기 위해 사용하는 캐릭터셋
- 항상 utf8로 설정되어있으며, 사용자가 설정하거나 변경할 수 없음 | + + +### 2. Time Zone 설정 + +- time_zone = **Asia/Seoul** + +### 3. Collation 설정 + +- collation_connection, collation_server = utf8_unicode_ci + +파라미터 그룹 설정 완료 후 아까 만들어둔 RDS 인스턴스에 접속하여 수정 진행. + +파라미터 그룹을 방금 만든것으로 수정 후 즉시적용 선택 + +![스크린샷 2024-08-26 오전 3.04.03.png](/assets/images/aws08/3.04.03.png) + +RDS 인스턴스 수정이 완료되면 상태가 되면, 재부팅을 해주어야 적용이 된다. \ No newline at end of file diff --git a/_sass/minimal-mistakes/_reset.scss b/_sass/minimal-mistakes/_reset.scss index 2259fd0c2388..1574e3058ca9 100644 --- a/_sass/minimal-mistakes/_reset.scss +++ b/_sass/minimal-mistakes/_reset.scss @@ -8,18 +8,18 @@ html { /* apply a natural box layout model to all elements */ box-sizing: border-box; background-color: $background-color; - font-size: 16px; + font-size: 14px; @include breakpoint($medium) { - font-size: 18px; + font-size: 16px; } @include breakpoint($large) { - font-size: 20px; + font-size: 16px; } @include breakpoint($x-large) { - font-size: 22px; + font-size: 16px; } -webkit-text-size-adjust: 100%; diff --git a/assets/css/main.scss b/assets/css/main.scss index 23346e773b1b..0f204fabe737 100644 --- a/assets/css/main.scss +++ b/assets/css/main.scss @@ -5,4 +5,11 @@ @charset "utf-8"; @import "minimal-mistakes/skins/{{ site.minimal_mistakes_skin | default: 'default' }}"; // skin -@import "minimal-mistakes"; // main partials \ No newline at end of file +@import "minimal-mistakes"; // main partials + +@import url('https://fonts.googleapis.com/css?family=Inconsolata'); + +.archive a { + color: #696969; // 메인 포스트 a태그 제목 색 + text-decoration: none; +} \ No newline at end of file diff --git a/assets/images/DL01/img1.png b/assets/images/DL01/img1.png new file mode 100644 index 000000000000..0e153986b85a Binary files /dev/null and b/assets/images/DL01/img1.png differ diff --git a/assets/images/DL01/img10.png b/assets/images/DL01/img10.png new file mode 100644 index 000000000000..90b91a1906cb Binary files /dev/null and b/assets/images/DL01/img10.png differ diff --git a/assets/images/DL01/img2.png b/assets/images/DL01/img2.png new file mode 100644 index 000000000000..f1408e5bbb0e Binary files /dev/null and b/assets/images/DL01/img2.png differ diff --git a/assets/images/DL01/img3.png b/assets/images/DL01/img3.png new file mode 100644 index 000000000000..d41985d31c26 Binary files /dev/null and b/assets/images/DL01/img3.png differ diff --git a/assets/images/DL01/img4.png b/assets/images/DL01/img4.png new file mode 100644 index 000000000000..1da3d50907a0 Binary files /dev/null and b/assets/images/DL01/img4.png differ diff --git a/assets/images/DL01/img5.png b/assets/images/DL01/img5.png new file mode 100644 index 000000000000..67e776e29b4d Binary files /dev/null and b/assets/images/DL01/img5.png differ diff --git a/assets/images/DL01/img6.png b/assets/images/DL01/img6.png new file mode 100644 index 000000000000..0bb59b24ce4f Binary files /dev/null and b/assets/images/DL01/img6.png differ diff --git a/assets/images/DL01/img9.png b/assets/images/DL01/img9.png new file mode 100644 index 000000000000..c8e227108f57 Binary files /dev/null and b/assets/images/DL01/img9.png differ diff --git a/assets/images/DL02/01_1.png b/assets/images/DL02/01_1.png new file mode 100644 index 000000000000..8d8bd74d2d44 Binary files /dev/null and b/assets/images/DL02/01_1.png differ diff --git a/assets/images/DL02/01_2.png b/assets/images/DL02/01_2.png new file mode 100644 index 000000000000..20587b24b6ba Binary files /dev/null and b/assets/images/DL02/01_2.png differ diff --git a/assets/images/DL02/01_3.png b/assets/images/DL02/01_3.png new file mode 100644 index 000000000000..d60cc061e47b Binary files /dev/null and b/assets/images/DL02/01_3.png differ diff --git a/assets/images/DL02/01_4.png b/assets/images/DL02/01_4.png new file mode 100644 index 000000000000..0bcc59971120 Binary files /dev/null and b/assets/images/DL02/01_4.png differ diff --git a/assets/images/DL02/01_5.png b/assets/images/DL02/01_5.png new file mode 100644 index 000000000000..7266182da7c4 Binary files /dev/null and b/assets/images/DL02/01_5.png differ diff --git a/assets/images/DL02/01_6.png b/assets/images/DL02/01_6.png new file mode 100644 index 000000000000..bba4c5815fa4 Binary files /dev/null and b/assets/images/DL02/01_6.png differ diff --git a/assets/images/DL03/02_1.png b/assets/images/DL03/02_1.png new file mode 100644 index 000000000000..cf5f18351691 Binary files /dev/null and b/assets/images/DL03/02_1.png differ diff --git a/assets/images/DL03/02_2.png b/assets/images/DL03/02_2.png new file mode 100644 index 000000000000..b0fd03e1df86 Binary files /dev/null and b/assets/images/DL03/02_2.png differ diff --git a/assets/images/DL04/output_18_0.png b/assets/images/DL04/output_18_0.png new file mode 100644 index 000000000000..fa793d294c1b Binary files /dev/null and b/assets/images/DL04/output_18_0.png differ diff --git a/assets/images/DL05/05_1.png b/assets/images/DL05/05_1.png new file mode 100644 index 000000000000..099bcab97138 Binary files /dev/null and b/assets/images/DL05/05_1.png differ diff --git a/assets/images/DL05/05_2.png b/assets/images/DL05/05_2.png new file mode 100644 index 000000000000..9cf687c7ad25 Binary files /dev/null and b/assets/images/DL05/05_2.png differ diff --git a/assets/images/DL05/05_3.png b/assets/images/DL05/05_3.png new file mode 100644 index 000000000000..279fe352763a Binary files /dev/null and b/assets/images/DL05/05_3.png differ diff --git a/assets/images/DL05/05_4.png b/assets/images/DL05/05_4.png new file mode 100644 index 000000000000..fe8458176494 Binary files /dev/null and b/assets/images/DL05/05_4.png differ diff --git a/assets/images/DL05/05_5.png b/assets/images/DL05/05_5.png new file mode 100644 index 000000000000..3ff90cbd12c9 Binary files /dev/null and b/assets/images/DL05/05_5.png differ diff --git a/assets/images/DL06/09_3.png b/assets/images/DL06/09_3.png new file mode 100644 index 000000000000..65712511017d Binary files /dev/null and b/assets/images/DL06/09_3.png differ diff --git a/assets/images/DL06/09_4.jpg b/assets/images/DL06/09_4.jpg new file mode 100644 index 000000000000..0156801efe43 Binary files /dev/null and b/assets/images/DL06/09_4.jpg differ diff --git a/assets/images/DL06/09_5.png b/assets/images/DL06/09_5.png new file mode 100644 index 000000000000..767e6622e00e Binary files /dev/null and b/assets/images/DL06/09_5.png differ diff --git a/assets/images/DL06/result1.png b/assets/images/DL06/result1.png new file mode 100644 index 000000000000..7739c4188cb7 Binary files /dev/null and b/assets/images/DL06/result1.png differ diff --git a/assets/images/DL06/result2.png b/assets/images/DL06/result2.png new file mode 100644 index 000000000000..7ba83434b4e3 Binary files /dev/null and b/assets/images/DL06/result2.png differ diff --git a/assets/images/DL06/result3.png b/assets/images/DL06/result3.png new file mode 100644 index 000000000000..a3586100ce9f Binary files /dev/null and b/assets/images/DL06/result3.png differ diff --git a/assets/images/DL07/07_1.png b/assets/images/DL07/07_1.png new file mode 100644 index 000000000000..a1ac68c58b92 Binary files /dev/null and b/assets/images/DL07/07_1.png differ diff --git a/assets/images/DL07/07_10.png b/assets/images/DL07/07_10.png new file mode 100644 index 000000000000..6a54ce6331ae Binary files /dev/null and b/assets/images/DL07/07_10.png differ diff --git a/assets/images/DL07/07_11.png b/assets/images/DL07/07_11.png new file mode 100644 index 000000000000..27e2a8115178 Binary files /dev/null and b/assets/images/DL07/07_11.png differ diff --git a/assets/images/DL07/07_12.png b/assets/images/DL07/07_12.png new file mode 100644 index 000000000000..8988b93f138f Binary files /dev/null and b/assets/images/DL07/07_12.png differ diff --git a/assets/images/DL07/07_2.png b/assets/images/DL07/07_2.png new file mode 100644 index 000000000000..b4add6ed0c9a Binary files /dev/null and b/assets/images/DL07/07_2.png differ diff --git a/assets/images/DL07/07_3_1.png b/assets/images/DL07/07_3_1.png new file mode 100644 index 000000000000..2554a51aa369 Binary files /dev/null and b/assets/images/DL07/07_3_1.png differ diff --git a/assets/images/DL07/07_3_2.png b/assets/images/DL07/07_3_2.png new file mode 100644 index 000000000000..5722c1545f0e Binary files /dev/null and b/assets/images/DL07/07_3_2.png differ diff --git a/assets/images/DL07/07_4.png b/assets/images/DL07/07_4.png new file mode 100644 index 000000000000..7498d21b9b69 Binary files /dev/null and b/assets/images/DL07/07_4.png differ diff --git a/assets/images/DL07/07_5.png b/assets/images/DL07/07_5.png new file mode 100644 index 000000000000..eea3893c6880 Binary files /dev/null and b/assets/images/DL07/07_5.png differ diff --git a/assets/images/DL07/07_6.png b/assets/images/DL07/07_6.png new file mode 100644 index 000000000000..828ffd936d43 Binary files /dev/null and b/assets/images/DL07/07_6.png differ diff --git a/assets/images/DL07/07_7.png b/assets/images/DL07/07_7.png new file mode 100644 index 000000000000..8758383debaf Binary files /dev/null and b/assets/images/DL07/07_7.png differ diff --git a/assets/images/DL07/07_8.png b/assets/images/DL07/07_8.png new file mode 100644 index 000000000000..5322883164f6 Binary files /dev/null and b/assets/images/DL07/07_8.png differ diff --git a/assets/images/DL07/07_9.png b/assets/images/DL07/07_9.png new file mode 100644 index 000000000000..d0f12a9fd54d Binary files /dev/null and b/assets/images/DL07/07_9.png differ diff --git a/assets/images/DL07/Untitled.png b/assets/images/DL07/Untitled.png new file mode 100644 index 000000000000..9e1b58f5dc21 Binary files /dev/null and b/assets/images/DL07/Untitled.png differ diff --git a/assets/images/DL08-1/output_19_0.png b/assets/images/DL08-1/output_19_0.png new file mode 100644 index 000000000000..b7e2522d6ec7 Binary files /dev/null and b/assets/images/DL08-1/output_19_0.png differ diff --git a/assets/images/DL08-1/output_21_0.png b/assets/images/DL08-1/output_21_0.png new file mode 100644 index 000000000000..2bf2efc14a70 Binary files /dev/null and b/assets/images/DL08-1/output_21_0.png differ diff --git a/assets/images/DL08-1/output_29_0.png b/assets/images/DL08-1/output_29_0.png new file mode 100644 index 000000000000..d17687a2a8ba Binary files /dev/null and b/assets/images/DL08-1/output_29_0.png differ diff --git a/assets/images/DL08-1/output_34_0.png b/assets/images/DL08-1/output_34_0.png new file mode 100644 index 000000000000..70b54f8eff1d Binary files /dev/null and b/assets/images/DL08-1/output_34_0.png differ diff --git a/assets/images/DL08-1/output_40_0.png b/assets/images/DL08-1/output_40_0.png new file mode 100644 index 000000000000..1f1827a14da9 Binary files /dev/null and b/assets/images/DL08-1/output_40_0.png differ diff --git "a/assets/images/GRU\354\205\200.png" "b/assets/images/GRU\354\205\200.png" new file mode 100644 index 000000000000..67604eec7eb5 Binary files /dev/null and "b/assets/images/GRU\354\205\200.png" differ diff --git a/assets/images/LSTM_cell_update.png b/assets/images/LSTM_cell_update.png new file mode 100644 index 000000000000..d838218861a1 Binary files /dev/null and b/assets/images/LSTM_cell_update.png differ diff --git "a/assets/images/LSTM_cell\354\203\201\355\203\234.png" "b/assets/images/LSTM_cell\354\203\201\355\203\234.png" new file mode 100644 index 000000000000..1e15571e388b Binary files /dev/null and "b/assets/images/LSTM_cell\354\203\201\355\203\234.png" differ diff --git "a/assets/images/LSTM_forget\352\262\214\354\235\264\355\212\270.png" "b/assets/images/LSTM_forget\352\262\214\354\235\264\355\212\270.png" new file mode 100644 index 000000000000..ebf842727866 Binary files /dev/null and "b/assets/images/LSTM_forget\352\262\214\354\235\264\355\212\270.png" differ diff --git "a/assets/images/LSTM_input\352\262\214\354\235\264\355\212\270.png" "b/assets/images/LSTM_input\352\262\214\354\235\264\355\212\270.png" new file mode 100644 index 000000000000..a23c5f6f793a Binary files /dev/null and "b/assets/images/LSTM_input\352\262\214\354\235\264\355\212\270.png" differ diff --git "a/assets/images/LSTM_output\352\262\214\354\235\264\355\212\270.png" "b/assets/images/LSTM_output\352\262\214\354\235\264\355\212\270.png" new file mode 100644 index 000000000000..c651d44b34b0 Binary files /dev/null and "b/assets/images/LSTM_output\352\262\214\354\235\264\355\212\270.png" differ diff --git "a/assets/images/LSTM\352\265\254\354\241\260.png" "b/assets/images/LSTM\352\265\254\354\241\260.png" new file mode 100644 index 000000000000..2a078543b6a7 Binary files /dev/null and "b/assets/images/LSTM\352\265\254\354\241\260.png" differ diff --git "a/assets/images/LSTM\352\270\260\355\230\270.png" "b/assets/images/LSTM\352\270\260\355\230\270.png" new file mode 100644 index 000000000000..a112c1c77bc1 Binary files /dev/null and "b/assets/images/LSTM\352\270\260\355\230\270.png" differ diff --git a/assets/images/MyProfile.png b/assets/images/MyProfile.png new file mode 100644 index 000000000000..f7b066a32ecc Binary files /dev/null and b/assets/images/MyProfile.png differ diff --git a/assets/images/RNN.png b/assets/images/RNN.png new file mode 100644 index 000000000000..b40d64761f3c Binary files /dev/null and b/assets/images/RNN.png differ diff --git "a/assets/images/RNN\354\210\230\354\213\235.PNG" "b/assets/images/RNN\354\210\230\354\213\235.PNG" new file mode 100644 index 000000000000..d1586b88dda2 Binary files /dev/null and "b/assets/images/RNN\354\210\230\354\213\235.PNG" differ diff --git "a/assets/images/RNN\355\231\234\354\232\251.PNG" "b/assets/images/RNN\355\231\234\354\232\251.PNG" new file mode 100644 index 000000000000..ac2062badb32 Binary files /dev/null and "b/assets/images/RNN\355\231\234\354\232\251.PNG" differ diff --git a/assets/images/Sigmoid.png b/assets/images/Sigmoid.png new file mode 100644 index 000000000000..a7d3be13c4b7 Binary files /dev/null and b/assets/images/Sigmoid.png differ diff --git "a/assets/images/Sigmoid_\354\204\261\354\247\210.png" "b/assets/images/Sigmoid_\354\204\261\354\247\210.png" new file mode 100644 index 000000000000..444bdd5fb35c Binary files /dev/null and "b/assets/images/Sigmoid_\354\204\261\354\247\210.png" differ diff --git a/assets/images/aws01/01.png b/assets/images/aws01/01.png new file mode 100644 index 000000000000..9f0aee5d5f9d Binary files /dev/null and b/assets/images/aws01/01.png differ diff --git a/assets/images/aws01/02.png b/assets/images/aws01/02.png new file mode 100644 index 000000000000..0cc1c3089152 Binary files /dev/null and b/assets/images/aws01/02.png differ diff --git a/assets/images/aws01/03.png b/assets/images/aws01/03.png new file mode 100644 index 000000000000..f0f12d71c8a1 Binary files /dev/null and b/assets/images/aws01/03.png differ diff --git a/assets/images/aws01/04.png b/assets/images/aws01/04.png new file mode 100644 index 000000000000..d5e6d4852a35 Binary files /dev/null and b/assets/images/aws01/04.png differ diff --git a/assets/images/aws01/05.png b/assets/images/aws01/05.png new file mode 100644 index 000000000000..c961b49623ea Binary files /dev/null and b/assets/images/aws01/05.png differ diff --git a/assets/images/aws01/06.png b/assets/images/aws01/06.png new file mode 100644 index 000000000000..7a8f353aa509 Binary files /dev/null and b/assets/images/aws01/06.png differ diff --git a/assets/images/aws01/07.png b/assets/images/aws01/07.png new file mode 100644 index 000000000000..f565c55a7647 Binary files /dev/null and b/assets/images/aws01/07.png differ diff --git a/assets/images/aws01/08.png b/assets/images/aws01/08.png new file mode 100644 index 000000000000..d5b5dd061700 Binary files /dev/null and b/assets/images/aws01/08.png differ diff --git a/assets/images/aws01/09.png b/assets/images/aws01/09.png new file mode 100644 index 000000000000..3523548a1750 Binary files /dev/null and b/assets/images/aws01/09.png differ diff --git a/assets/images/aws01/10.png b/assets/images/aws01/10.png new file mode 100644 index 000000000000..87be6e619762 Binary files /dev/null and b/assets/images/aws01/10.png differ diff --git a/assets/images/aws01/11.png b/assets/images/aws01/11.png new file mode 100644 index 000000000000..6cadf899ad93 Binary files /dev/null and b/assets/images/aws01/11.png differ diff --git a/assets/images/aws01/12.png b/assets/images/aws01/12.png new file mode 100644 index 000000000000..5901e4f38d0b Binary files /dev/null and b/assets/images/aws01/12.png differ diff --git a/assets/images/aws03/01.png b/assets/images/aws03/01.png new file mode 100644 index 000000000000..1616d0b660cd Binary files /dev/null and b/assets/images/aws03/01.png differ diff --git a/assets/images/aws04/01.png b/assets/images/aws04/01.png new file mode 100644 index 000000000000..7515804fbb2c Binary files /dev/null and b/assets/images/aws04/01.png differ diff --git a/assets/images/aws04/02.png b/assets/images/aws04/02.png new file mode 100644 index 000000000000..55d05762d595 Binary files /dev/null and b/assets/images/aws04/02.png differ diff --git a/assets/images/aws04/03.png b/assets/images/aws04/03.png new file mode 100644 index 000000000000..3bcf250140d6 Binary files /dev/null and b/assets/images/aws04/03.png differ diff --git a/assets/images/aws04/04.png b/assets/images/aws04/04.png new file mode 100644 index 000000000000..8ca8beaee775 Binary files /dev/null and b/assets/images/aws04/04.png differ diff --git a/assets/images/aws04/05.png b/assets/images/aws04/05.png new file mode 100644 index 000000000000..a18d20dbd007 Binary files /dev/null and b/assets/images/aws04/05.png differ diff --git a/assets/images/aws04/06.png b/assets/images/aws04/06.png new file mode 100644 index 000000000000..4ad7a07d5029 Binary files /dev/null and b/assets/images/aws04/06.png differ diff --git a/assets/images/aws04/07.png b/assets/images/aws04/07.png new file mode 100644 index 000000000000..277ec2097296 Binary files /dev/null and b/assets/images/aws04/07.png differ diff --git a/assets/images/aws04/08.png b/assets/images/aws04/08.png new file mode 100644 index 000000000000..b0f38ef3c4fc Binary files /dev/null and b/assets/images/aws04/08.png differ diff --git a/assets/images/aws04/09.png b/assets/images/aws04/09.png new file mode 100644 index 000000000000..12fcfbae8714 Binary files /dev/null and b/assets/images/aws04/09.png differ diff --git a/assets/images/aws04/10.png b/assets/images/aws04/10.png new file mode 100644 index 000000000000..5867e85c491e Binary files /dev/null and b/assets/images/aws04/10.png differ diff --git a/assets/images/aws04/11.png b/assets/images/aws04/11.png new file mode 100644 index 000000000000..22c5c3cab252 Binary files /dev/null and b/assets/images/aws04/11.png differ diff --git a/assets/images/aws04/12.png b/assets/images/aws04/12.png new file mode 100644 index 000000000000..760888565d58 Binary files /dev/null and b/assets/images/aws04/12.png differ diff --git a/assets/images/aws04/13.png b/assets/images/aws04/13.png new file mode 100644 index 000000000000..a2399e5ffce4 Binary files /dev/null and b/assets/images/aws04/13.png differ diff --git a/assets/images/aws04/14.png b/assets/images/aws04/14.png new file mode 100644 index 000000000000..a60965e1a420 Binary files /dev/null and b/assets/images/aws04/14.png differ diff --git a/assets/images/aws04/15.png b/assets/images/aws04/15.png new file mode 100644 index 000000000000..61325c92b5f8 Binary files /dev/null and b/assets/images/aws04/15.png differ diff --git a/assets/images/aws04/16.png b/assets/images/aws04/16.png new file mode 100644 index 000000000000..24a47f1050dd Binary files /dev/null and b/assets/images/aws04/16.png differ diff --git a/assets/images/aws04/17.png b/assets/images/aws04/17.png new file mode 100644 index 000000000000..e6fff3cda6fc Binary files /dev/null and b/assets/images/aws04/17.png differ diff --git a/assets/images/aws04/18.png b/assets/images/aws04/18.png new file mode 100644 index 000000000000..8eca004ddab7 Binary files /dev/null and b/assets/images/aws04/18.png differ diff --git a/assets/images/aws04/19.png b/assets/images/aws04/19.png new file mode 100644 index 000000000000..8b43d279ce4e Binary files /dev/null and b/assets/images/aws04/19.png differ diff --git a/assets/images/aws04/20.png b/assets/images/aws04/20.png new file mode 100644 index 000000000000..d202e99b0c2b Binary files /dev/null and b/assets/images/aws04/20.png differ diff --git a/assets/images/aws04/21.png b/assets/images/aws04/21.png new file mode 100644 index 000000000000..4e378d9aa71c Binary files /dev/null and b/assets/images/aws04/21.png differ diff --git a/assets/images/aws04/22.png b/assets/images/aws04/22.png new file mode 100644 index 000000000000..759543dc4283 Binary files /dev/null and b/assets/images/aws04/22.png differ diff --git a/assets/images/aws04/23.png b/assets/images/aws04/23.png new file mode 100644 index 000000000000..8a8405476eec Binary files /dev/null and b/assets/images/aws04/23.png differ diff --git a/assets/images/aws04/24.png b/assets/images/aws04/24.png new file mode 100644 index 000000000000..39b7fba5cbd1 Binary files /dev/null and b/assets/images/aws04/24.png differ diff --git a/assets/images/aws04/25.png b/assets/images/aws04/25.png new file mode 100644 index 000000000000..f0e74de6bd11 Binary files /dev/null and b/assets/images/aws04/25.png differ diff --git a/assets/images/aws04/26.png b/assets/images/aws04/26.png new file mode 100644 index 000000000000..99b7ad265676 Binary files /dev/null and b/assets/images/aws04/26.png differ diff --git a/assets/images/aws04/27.png b/assets/images/aws04/27.png new file mode 100644 index 000000000000..39e537c0959c Binary files /dev/null and b/assets/images/aws04/27.png differ diff --git a/assets/images/aws04/28.png b/assets/images/aws04/28.png new file mode 100644 index 000000000000..4df0bfc1c229 Binary files /dev/null and b/assets/images/aws04/28.png differ diff --git a/assets/images/aws04/29.png b/assets/images/aws04/29.png new file mode 100644 index 000000000000..401031309f9d Binary files /dev/null and b/assets/images/aws04/29.png differ diff --git a/assets/images/aws04/30.png b/assets/images/aws04/30.png new file mode 100644 index 000000000000..87666f43ce10 Binary files /dev/null and b/assets/images/aws04/30.png differ diff --git a/assets/images/aws04/31.png b/assets/images/aws04/31.png new file mode 100644 index 000000000000..07eed66ebef2 Binary files /dev/null and b/assets/images/aws04/31.png differ diff --git a/assets/images/aws04/32.png b/assets/images/aws04/32.png new file mode 100644 index 000000000000..b6070dd1f203 Binary files /dev/null and b/assets/images/aws04/32.png differ diff --git a/assets/images/aws04/33.png b/assets/images/aws04/33.png new file mode 100644 index 000000000000..4e74958cf99b Binary files /dev/null and b/assets/images/aws04/33.png differ diff --git a/assets/images/aws04/34.png b/assets/images/aws04/34.png new file mode 100644 index 000000000000..166ed48a076e Binary files /dev/null and b/assets/images/aws04/34.png differ diff --git a/assets/images/aws04/35.png b/assets/images/aws04/35.png new file mode 100644 index 000000000000..12d4c85216ff Binary files /dev/null and b/assets/images/aws04/35.png differ diff --git a/assets/images/aws04/36.png b/assets/images/aws04/36.png new file mode 100644 index 000000000000..a98debf0d498 Binary files /dev/null and b/assets/images/aws04/36.png differ diff --git a/assets/images/aws05/1.png b/assets/images/aws05/1.png new file mode 100644 index 000000000000..142897b0eb14 Binary files /dev/null and b/assets/images/aws05/1.png differ diff --git a/assets/images/aws06/1.png b/assets/images/aws06/1.png new file mode 100644 index 000000000000..2f482266d8af Binary files /dev/null and b/assets/images/aws06/1.png differ diff --git a/assets/images/aws06/2.png b/assets/images/aws06/2.png new file mode 100644 index 000000000000..e1a06937e120 Binary files /dev/null and b/assets/images/aws06/2.png differ diff --git a/assets/images/aws07/1.png b/assets/images/aws07/1.png new file mode 100644 index 000000000000..6d58e79034cd Binary files /dev/null and b/assets/images/aws07/1.png differ diff --git a/assets/images/aws07/10.png b/assets/images/aws07/10.png new file mode 100644 index 000000000000..e4ab75edd31f Binary files /dev/null and b/assets/images/aws07/10.png differ diff --git a/assets/images/aws07/11.png b/assets/images/aws07/11.png new file mode 100644 index 000000000000..9da53722cd04 Binary files /dev/null and b/assets/images/aws07/11.png differ diff --git a/assets/images/aws07/12.png b/assets/images/aws07/12.png new file mode 100644 index 000000000000..5888b1144f83 Binary files /dev/null and b/assets/images/aws07/12.png differ diff --git a/assets/images/aws07/13.png b/assets/images/aws07/13.png new file mode 100644 index 000000000000..90e173c2d490 Binary files /dev/null and b/assets/images/aws07/13.png differ diff --git a/assets/images/aws07/14.png b/assets/images/aws07/14.png new file mode 100644 index 000000000000..3a0c5d002bfb Binary files /dev/null and b/assets/images/aws07/14.png differ diff --git a/assets/images/aws07/15.png b/assets/images/aws07/15.png new file mode 100644 index 000000000000..17897c2cb72c Binary files /dev/null and b/assets/images/aws07/15.png differ diff --git a/assets/images/aws07/16.png b/assets/images/aws07/16.png new file mode 100644 index 000000000000..1fee2a06d406 Binary files /dev/null and b/assets/images/aws07/16.png differ diff --git a/assets/images/aws07/17.png b/assets/images/aws07/17.png new file mode 100644 index 000000000000..0ba178e80b99 Binary files /dev/null and b/assets/images/aws07/17.png differ diff --git a/assets/images/aws07/18.png b/assets/images/aws07/18.png new file mode 100644 index 000000000000..1762d5582800 Binary files /dev/null and b/assets/images/aws07/18.png differ diff --git a/assets/images/aws07/19.png b/assets/images/aws07/19.png new file mode 100644 index 000000000000..4833172d6838 Binary files /dev/null and b/assets/images/aws07/19.png differ diff --git a/assets/images/aws07/2.png b/assets/images/aws07/2.png new file mode 100644 index 000000000000..1fd5b26ce2b5 Binary files /dev/null and b/assets/images/aws07/2.png differ diff --git a/assets/images/aws07/20.png b/assets/images/aws07/20.png new file mode 100644 index 000000000000..d3506d3f7344 Binary files /dev/null and b/assets/images/aws07/20.png differ diff --git a/assets/images/aws07/3.png b/assets/images/aws07/3.png new file mode 100644 index 000000000000..5856a367771f Binary files /dev/null and b/assets/images/aws07/3.png differ diff --git a/assets/images/aws07/4.png b/assets/images/aws07/4.png new file mode 100644 index 000000000000..b6eae43d83d7 Binary files /dev/null and b/assets/images/aws07/4.png differ diff --git a/assets/images/aws07/5.png b/assets/images/aws07/5.png new file mode 100644 index 000000000000..482558826cc1 Binary files /dev/null and b/assets/images/aws07/5.png differ diff --git a/assets/images/aws07/6.png b/assets/images/aws07/6.png new file mode 100644 index 000000000000..d18e4d680787 Binary files /dev/null and b/assets/images/aws07/6.png differ diff --git a/assets/images/aws07/7.png b/assets/images/aws07/7.png new file mode 100644 index 000000000000..06e79dcb346c Binary files /dev/null and b/assets/images/aws07/7.png differ diff --git a/assets/images/aws07/8.png b/assets/images/aws07/8.png new file mode 100644 index 000000000000..7ddd7825ed39 Binary files /dev/null and b/assets/images/aws07/8.png differ diff --git a/assets/images/aws07/9.png b/assets/images/aws07/9.png new file mode 100644 index 000000000000..3f21629cd27f Binary files /dev/null and b/assets/images/aws07/9.png differ diff --git a/assets/images/aws08/2.46.02.png b/assets/images/aws08/2.46.02.png new file mode 100644 index 000000000000..6d120db4863d Binary files /dev/null and b/assets/images/aws08/2.46.02.png differ diff --git a/assets/images/aws08/2.51.27.png b/assets/images/aws08/2.51.27.png new file mode 100644 index 000000000000..c99d7af02b96 Binary files /dev/null and b/assets/images/aws08/2.51.27.png differ diff --git a/assets/images/aws08/2.54.49.png b/assets/images/aws08/2.54.49.png new file mode 100644 index 000000000000..708ccc069591 Binary files /dev/null and b/assets/images/aws08/2.54.49.png differ diff --git a/assets/images/aws08/3.04.03.png b/assets/images/aws08/3.04.03.png new file mode 100644 index 000000000000..1f84e0ff2c2d Binary files /dev/null and b/assets/images/aws08/3.04.03.png differ diff --git a/assets/images/git01/01.png b/assets/images/git01/01.png new file mode 100644 index 000000000000..78a6f0d6724e Binary files /dev/null and b/assets/images/git01/01.png differ diff --git a/assets/images/git01/02.png b/assets/images/git01/02.png new file mode 100644 index 000000000000..d05c3e51879f Binary files /dev/null and b/assets/images/git01/02.png differ diff --git a/assets/images/git01/03.png b/assets/images/git01/03.png new file mode 100644 index 000000000000..8bd8862ccad1 Binary files /dev/null and b/assets/images/git01/03.png differ diff --git a/assets/images/git01/04.png b/assets/images/git01/04.png new file mode 100644 index 000000000000..a2df38409840 Binary files /dev/null and b/assets/images/git01/04.png differ diff --git a/assets/images/git01/05.png b/assets/images/git01/05.png new file mode 100644 index 000000000000..6d50148fbdcd Binary files /dev/null and b/assets/images/git01/05.png differ diff --git a/assets/images/git01/06.png b/assets/images/git01/06.png new file mode 100644 index 000000000000..e44dc307dfa8 Binary files /dev/null and b/assets/images/git01/06.png differ diff --git a/assets/images/ml01/01.png b/assets/images/ml01/01.png new file mode 100644 index 000000000000..984e1d40e74e Binary files /dev/null and b/assets/images/ml01/01.png differ diff --git a/assets/images/ml01/02.png b/assets/images/ml01/02.png new file mode 100644 index 000000000000..0ee416d8c61a Binary files /dev/null and b/assets/images/ml01/02.png differ diff --git a/assets/images/ml02/01.png b/assets/images/ml02/01.png new file mode 100644 index 000000000000..03f43ce97b83 Binary files /dev/null and b/assets/images/ml02/01.png differ diff --git a/assets/images/ml02/02.png b/assets/images/ml02/02.png new file mode 100644 index 000000000000..6b9cb1a745b6 Binary files /dev/null and b/assets/images/ml02/02.png differ diff --git a/assets/images/ml03/01.png b/assets/images/ml03/01.png new file mode 100644 index 000000000000..d46c1d4b120e Binary files /dev/null and b/assets/images/ml03/01.png differ diff --git a/assets/images/ml03/02.png b/assets/images/ml03/02.png new file mode 100644 index 000000000000..9da015d9730f Binary files /dev/null and b/assets/images/ml03/02.png differ diff --git a/assets/images/ml03/output_20_0.svg b/assets/images/ml03/output_20_0.svg new file mode 100644 index 000000000000..48e0ac096b9e --- /dev/null +++ b/assets/images/ml03/output_20_0.svg @@ -0,0 +1,396 @@ + + + + + + +Tree + + + +0 + +odor_n <= 0.5 +gini = 0.499 +samples = 5686 +value = [2980, 2706] +class = 독 + + + +1 + +stalk-root_c <= 0.5 +gini = 0.29 +samples = 3175 +value = [558, 2617] +class = 식용 + + + +0:->1: + + +True + + + +12 + +spore-print-color_r <= 0.5 +gini = 0.068 +samples = 2511 +value = [2422, 89] +class = 독 + + + +0:->12: + + +False + + + +2 + +stalk-root_r <= 0.5 +gini = 0.142 +samples = 2811 +value = [216, 2595] +class = 식용 + + + +1:->2: + + + + + +9 + +odor_m <= 0.5 +gini = 0.114 +samples = 364 +value = [342, 22] +class = 독 + + + +1:->9: + + + + + +3 + +gill-spacing_c <= 0.5 +gini = 0.05 +samples = 2664 +value = [69, 2595] +class = 식용 + + + +2:->3: + + + + + +8 + +gini = 0.0 +samples = 147 +value = [147, 0] +class = 독 + + + +2:->8: + + + + + +4 + +odor_c <= 0.5 +gini = 0.499 +samples = 132 +value = [69, 63] +class = 독 + + + +3:->4: + + + + + +7 + +gini = 0.0 +samples = 2532 +value = [0, 2532] +class = 식용 + + + +3:->7: + + + + + +5 + +gini = 0.0 +samples = 69 +value = [69, 0] +class = 독 + + + +4:->5: + + + + + +6 + +gini = 0.0 +samples = 63 +value = [0, 63] +class = 식용 + + + +4:->6: + + + + + +10 + +gini = 0.0 +samples = 342 +value = [342, 0] +class = 독 + + + +9:->10: + + + + + +11 + +gini = 0.0 +samples = 22 +value = [0, 22] +class = 식용 + + + +9:->11: + + + + + +13 + +stalk-surface-below-ring_y <= 0.5 +gini = 0.03 +samples = 2460 +value = [2422, 38] +class = 독 + + + +12:->13: + + + + + +24 + +gini = 0.0 +samples = 51 +value = [0, 51] +class = 식용 + + + +12:->24: + + + + + +14 + +cap-surface_g <= 0.5 +gini = 0.006 +samples = 2419 +value = [2412, 7] +class = 독 + + + +13:->14: + + + + + +21 + +gill-size_n <= 0.5 +gini = 0.369 +samples = 41 +value = [10, 31] +class = 식용 + + + +13:->21: + + + + + +15 + +gill-size_b <= 0.5 +gini = 0.002 +samples = 2415 +value = [2412, 3] +class = 독 + + + +14:->15: + + + + + +20 + +gini = 0.0 +samples = 4 +value = [0, 4] +class = 식용 + + + +14:->20: + + + + + +16 + +population_c <= 0.5 +gini = 0.042 +samples = 139 +value = [136, 3] +class = 독 + + + +15:->16: + + + + + +19 + +gini = 0.0 +samples = 2276 +value = [2276, 0] +class = 독 + + + +15:->19: + + + + + +17 + +gini = 0.0 +samples = 136 +value = [136, 0] +class = 독 + + + +16:->17: + + + + + +18 + +gini = 0.0 +samples = 3 +value = [0, 3] +class = 식용 + + + +16:->18: + + + + + +22 + +gini = 0.0 +samples = 10 +value = [10, 0] +class = 독 + + + +21:->22: + + + + + +23 + +gini = 0.0 +samples = 31 +value = [0, 31] +class = 식용 + + + +21:->23: + + + + + diff --git a/assets/images/ml04/output_61_0.png b/assets/images/ml04/output_61_0.png new file mode 100644 index 000000000000..64939ca6457d Binary files /dev/null and b/assets/images/ml04/output_61_0.png differ diff --git a/assets/images/springboot01/00_1.png b/assets/images/springboot01/00_1.png new file mode 100644 index 000000000000..bb80801ee633 Binary files /dev/null and b/assets/images/springboot01/00_1.png differ diff --git a/assets/images/springboot01/01_1.png b/assets/images/springboot01/01_1.png new file mode 100644 index 000000000000..dbe7035149fd Binary files /dev/null and b/assets/images/springboot01/01_1.png differ diff --git a/assets/images/springboot02/00_1.png b/assets/images/springboot02/00_1.png new file mode 100644 index 000000000000..cc0213dae9e7 Binary files /dev/null and b/assets/images/springboot02/00_1.png differ diff --git a/assets/images/springboot03/00_1.png b/assets/images/springboot03/00_1.png new file mode 100644 index 000000000000..e0584ab96c05 Binary files /dev/null and b/assets/images/springboot03/00_1.png differ diff --git a/assets/images/springboot08/01.png b/assets/images/springboot08/01.png new file mode 100644 index 000000000000..ed32fbd23b64 Binary files /dev/null and b/assets/images/springboot08/01.png differ diff --git a/assets/images/springboot08/02.png b/assets/images/springboot08/02.png new file mode 100644 index 000000000000..c0e0e16af781 Binary files /dev/null and b/assets/images/springboot08/02.png differ diff --git a/assets/images/springboot08/03.png b/assets/images/springboot08/03.png new file mode 100644 index 000000000000..663dd8717810 Binary files /dev/null and b/assets/images/springboot08/03.png differ diff --git a/assets/images/springboot08/04.png b/assets/images/springboot08/04.png new file mode 100644 index 000000000000..8f2e5d73318a Binary files /dev/null and b/assets/images/springboot08/04.png differ diff --git a/assets/images/springboot08/05.png b/assets/images/springboot08/05.png new file mode 100644 index 000000000000..7e571a62d443 Binary files /dev/null and b/assets/images/springboot08/05.png differ diff --git a/assets/images/springboot08/06.png b/assets/images/springboot08/06.png new file mode 100644 index 000000000000..402aa070e7a9 Binary files /dev/null and b/assets/images/springboot08/06.png differ diff --git "a/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.png" "b/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.png" new file mode 100644 index 000000000000..cc5809644ce4 Binary files /dev/null and "b/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225.png" differ diff --git "a/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225_\352\263\274\354\240\225.png" "b/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225_\352\263\274\354\240\225.png" new file mode 100644 index 000000000000..e8e5b0a800f4 Binary files /dev/null and "b/assets/images/\352\262\275\354\202\254\355\225\230\352\260\225\353\262\225_\352\263\274\354\240\225.png" differ diff --git "a/assets/images/\352\263\265\354\213\235_MSE.png" "b/assets/images/\352\263\265\354\213\235_MSE.png" new file mode 100644 index 000000000000..315f4f016420 Binary files /dev/null and "b/assets/images/\352\263\265\354\213\235_MSE.png" differ diff --git "a/assets/images/\352\263\265\354\213\235_\354\265\234\354\206\214\354\240\234\352\263\261\353\262\225.png" "b/assets/images/\352\263\265\354\213\235_\354\265\234\354\206\214\354\240\234\352\263\261\353\262\225.png" new file mode 100644 index 000000000000..516775f9c4db Binary files /dev/null and "b/assets/images/\352\263\265\354\213\235_\354\265\234\354\206\214\354\240\234\352\263\261\353\262\225.png" differ diff --git "a/assets/images/\353\246\254\355\204\264\354\213\234\355\200\270\354\212\244.PNG" "b/assets/images/\353\246\254\355\204\264\354\213\234\355\200\270\354\212\244.PNG" new file mode 100644 index 000000000000..ff015f94cbf7 Binary files /dev/null and "b/assets/images/\353\246\254\355\204\264\354\213\234\355\200\270\354\212\244.PNG" differ diff --git "a/assets/images/\353\247\245\354\212\244\355\222\200\353\247\201.png" "b/assets/images/\353\247\245\354\212\244\355\222\200\353\247\201.png" new file mode 100644 index 000000000000..7266182da7c4 Binary files /dev/null and "b/assets/images/\353\247\245\354\212\244\355\222\200\353\247\201.png" differ diff --git "a/assets/images/\353\252\250\353\221\220\354\235\230\353\224\245\353\237\254\353\213\235.png" "b/assets/images/\353\252\250\353\221\220\354\235\230\353\224\245\353\237\254\353\213\235.png" new file mode 100644 index 000000000000..431d79a6d0bc Binary files /dev/null and "b/assets/images/\353\252\250\353\221\220\354\235\230\353\224\245\353\237\254\353\213\235.png" differ diff --git "a/assets/images/\353\252\250\353\251\230\355\205\200.png" "b/assets/images/\353\252\250\353\251\230\355\205\200.png" new file mode 100644 index 000000000000..0be08065b09c Binary files /dev/null and "b/assets/images/\353\252\250\353\251\230\355\205\200.png" differ diff --git "a/assets/images/\354\213\234\352\267\270\353\252\250\354\235\264\353\223\234\353\257\270\353\266\204.png" "b/assets/images/\354\213\234\352\267\270\353\252\250\354\235\264\353\223\234\353\257\270\353\266\204.png" new file mode 100644 index 000000000000..debf33b19da7 Binary files /dev/null and "b/assets/images/\354\213\234\352\267\270\353\252\250\354\235\264\353\223\234\353\257\270\353\266\204.png" differ diff --git "a/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2141.png" "b/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2141.png" new file mode 100644 index 000000000000..2975e6e76087 Binary files /dev/null and "b/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2141.png" differ diff --git "a/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2142.png" "b/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2142.png" new file mode 100644 index 000000000000..abec3e47f1ca Binary files /dev/null and "b/assets/images/\354\230\244\354\260\250\354\227\255\354\240\204\355\214\2142.png" differ diff --git "a/assets/images/\354\240\234\353\241\234\355\214\250\353\224\251.png" "b/assets/images/\354\240\234\353\241\234\355\214\250\353\224\251.png" new file mode 100644 index 000000000000..0bcc59971120 Binary files /dev/null and "b/assets/images/\354\240\234\353\241\234\355\214\250\353\224\251.png" differ diff --git "a/assets/images/\354\262\264\354\235\270\353\243\260.png" "b/assets/images/\354\262\264\354\235\270\353\243\260.png" new file mode 100644 index 000000000000..c94e3bc0fb89 Binary files /dev/null and "b/assets/images/\354\262\264\354\235\270\353\243\260.png" differ diff --git "a/assets/images/\355\215\274\354\205\211\355\212\270\353\241\240.png" "b/assets/images/\355\215\274\354\205\211\355\212\270\353\241\240.png" new file mode 100644 index 000000000000..aacf1507317e Binary files /dev/null and "b/assets/images/\355\215\274\354\205\211\355\212\270\353\241\240.png" differ diff --git "a/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\227\254\353\237\254\352\260\234\354\235\230\355\225\204\355\204\260.png" "b/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\227\254\353\237\254\352\260\234\354\235\230\355\225\204\355\204\260.png" new file mode 100644 index 000000000000..d60cc061e47b Binary files /dev/null and "b/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\227\254\353\237\254\352\260\234\354\235\230\355\225\204\355\204\260.png" differ diff --git "a/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\273\244\353\204\220.png" "b/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\273\244\353\204\220.png" new file mode 100644 index 000000000000..20587b24b6ba Binary files /dev/null and "b/assets/images/\355\225\251\354\204\261\352\263\261\354\213\240\352\262\275\353\247\235_\354\273\244\353\204\220.png" differ diff --git "a/assets/images/\355\231\225\353\245\240\354\240\201_\352\262\275\354\202\254_\355\225\230\352\260\225\353\262\225.png" "b/assets/images/\355\231\225\353\245\240\354\240\201_\352\262\275\354\202\254_\355\225\230\352\260\225\353\262\225.png" new file mode 100644 index 000000000000..c2236b88f4e5 Binary files /dev/null and "b/assets/images/\355\231\225\353\245\240\354\240\201_\352\262\275\354\202\254_\355\225\230\352\260\225\353\262\225.png" differ diff --git "a/assets/images/\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230_\355\205\214\354\235\264\353\270\224.png" "b/assets/images/\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230_\355\205\214\354\235\264\353\270\224.png" new file mode 100644 index 000000000000..0016812b3269 Binary files /dev/null and "b/assets/images/\355\231\234\354\204\261\355\231\224\355\225\250\354\210\230_\355\205\214\354\235\264\353\270\224.png" differ diff --git a/docs/_config.yml b/docs/_config.yml index 6cba47ff893c..be2216581228 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -10,7 +10,7 @@ remote_theme : "mmistakes/minimal-mistakes@4.24.0" minimal_mistakes_skin : "default" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise" # Site Settings -locale : "en-US" +locale : "ko-KR" # "en-US" title : "Minimal Mistakes" title_separator : "-" subtitle : "A Jekyll theme" @@ -25,9 +25,9 @@ masthead_title : # overrides the website title displayed in the masthe # breadcrumbs : false # true, false (default) words_per_minute : 200 comments: - provider : "false" # false (default), "disqus", "discourse", "facebook", "staticman_v2", "staticman", "utterances", "giscus", "custom" + provider : "disqus" # false (default), "disqus", "discourse", "facebook", "staticman_v2", "staticman", "utterances", "giscus", "custom" disqus: - shortname : + shortname : "yoonkienote" discourse: server : # https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963 , e.g.: meta.discourse.org facebook: @@ -210,10 +210,11 @@ defaults: values: layout: single author_profile: true - read_time: true + read_time: false + show_date: true comments: true share: true - related: true + related: false # _pages - scope: path: "_pages" diff --git a/docs/_pages/category-archive.md b/docs/_pages/category-archive.md index 4cb3860e91be..6b7011e2ecf1 100644 --- a/docs/_pages/category-archive.md +++ b/docs/_pages/category-archive.md @@ -3,4 +3,5 @@ title: "Posts by Category" layout: categories permalink: /categories/ author_profile: true +sidebar_main: true --- diff --git a/google285e0ef783d2b56a.html b/google285e0ef783d2b56a.html new file mode 100644 index 000000000000..4e85c74a3dac --- /dev/null +++ b/google285e0ef783d2b56a.html @@ -0,0 +1 @@ +google-site-verification: google285e0ef783d2b56a.html \ No newline at end of file