From f81714c21bb7274ebbcbb8ca29ca532d52837eca Mon Sep 17 00:00:00 2001 From: IdeaLim Date: Thu, 19 May 2022 16:20:26 +0900 Subject: [PATCH 1/2] =?UTF-8?q?docs:=203=ED=8C=80=20=EC=9E=84=EC=A0=95?= =?UTF-8?q?=EC=84=AD=205=EC=A3=BC=EC=B0=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0_\355\231\215\352\270\270\353\217\231.md" | 0 ...0_\354\236\204\354\240\225\354\204\255.md" | 488 ++++++++++++++++++ 2 files changed, 488 insertions(+) delete mode 100644 "week1/0\355\214\200_\355\231\215\352\270\270\353\217\231.md" create mode 100644 "week5/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" diff --git "a/week1/0\355\214\200_\355\231\215\352\270\270\353\217\231.md" "b/week1/0\355\214\200_\355\231\215\352\270\270\353\217\231.md" deleted file mode 100644 index e69de29..0000000 diff --git "a/week5/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" "b/week5/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" new file mode 100644 index 0000000..4ba437a --- /dev/null +++ "b/week5/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" @@ -0,0 +1,488 @@ + +## 비지도 학습 - 군집 알고리즘 + +### 1\. 비지도 학습이란? + +머신러닝의 한 종류로 훈련 데이터에 타깃(라벨)이 없다. 타깃이 없기 때문에 외부의 도움 없이 스스로 유용한 무언가를 학습해야 한다. 대표적인 비지도 학습 작업은 군집, 차원 축소 등이 있다. + +--- + +### 2\. 군집이란? + +군집은 비슷한 샘플끼리 하나의 그룹으로 모으는 대표적인 비지도 학습 방법이다. 군집 알고리즘으로 모은 샘플 그룹을 클러스터라고 부른다.  + +--- + +### 3\. 군집 알고리즘 예시 + +#### 데이터셋 준비 + +이번 예시로 사용할 데이터 셋은 사과, 바나나, 파인애플의 흑백 사진들이다.  + +``` +!wget https://bit.ly/fruits_300_data -O fruits_300.npy +``` + +``` +import numpy as np +import matplotlib.pyplot as plt + +fruits = np.load('fruits_300.npy') +print(fruits.shape) # output : (300, 100, 100) +print(fruits[0, 0, :]) +''' +[ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 + 2 2 2 2 2 2 1 1 1 1 1 1 1 1 2 3 2 1 + 2 1 1 1 1 2 1 3 2 1 3 1 4 1 2 5 5 5 + 19 148 192 117 28 1 1 2 1 4 1 1 3 1 1 1 1 1 + 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1] +''' +``` + +shape 으로 300 장의 100 x 100 크기 사진으로 구성된 것을 확인할 수 있다.  + +``` +plt.imshow(fruits[0], cmap='gray') +plt.show() +``` + +matplotlib의 imshow() 로 이미지를 출력할 수 있다.  + +``` +plt.imshow(fruits[0], cmap='gray_r') +plt.show() +``` + +cmap 의 값으로 gray\_r 을 주게 되면 반전된 값이 출력된다. + +#### 픽셀 값 분석하기 + +사과, 바나나, 파인애플의 각 데이터(이미지)를 1차원 배열로 만들어보자. + +``` +apple = fruits[0:100].reshape(-1, 100*100) +pineapple = fruits[100:200].reshape(-1, 100*100) +banana = fruits[200:300].reshape(-1, 100*100) + +print(apple.shape) #output: (100,10000) +``` + + 사과 사진들의 픽셀의 평균 값을 구해보자. + +``` +print(apple.mean(axis=1)) +``` + +axis = 1 일 때는 열방향(왼쪽에서 오른쪽)으로 계산한다. 즉, 100개의 평균 값이 담긴 배열을 생성한다. + +각 과일 별로 픽셀의 평균 값을 히스토그램을 이용해 표현해보자. + +``` +plt.hist(np.mean(apple, axis=1), alpha=0.8) +plt.hist(np.mean(pineapple, axis=1), alpha=0.8) +plt.hist(np.mean(banana, axis=1), alpha=0.8) +plt.legend(['apple', 'pineapple', 'banana']) +plt.show() +``` + +히스토그램을 확인해보면 바나나의 평균 사진의 픽셀 값은 20~80 사이에 분포되어 있어서 사진의 픽셀 평균 값으로 판단할 수 있지만 사과와 파인애플은 비슷한 범위에 분포되어 있기 때문에 판단이 힘들다.  + +그렇다면 사진의 픽셀 평균값이 아니라 각 픽셀별 평균(ex. 모든 사진의 1번 픽셀의 평균) 을 사용하면 어떨까? 이를 막대그래프를 이용해서 시각화해보자. + +``` +fig, axs = plt.subplots(1, 3, figsize=(20, 5)) +axs[0].bar(range(10000), np.mean(apple, axis=0)) +axs[1].bar(range(10000), np.mean(pineapple, axis=0)) +axs[2].bar(range(10000), np.mean(banana, axis=0)) +plt.show() +``` + +좌측부터 사과, 파인애플, 바나나의 각 픽셀(1~10000번)의 평균 값 막대그래프이다. 각 과일마다 그래프의 개형이 다른 것을 이용해 구분할 수 있을 것 같다.  + +#### 평균값과 가까운 사진 고르기 + +각 사진의 오차 평균을 구해보자. + +``` +abs_diff = np.abs(fruits - apple_mean) +abs_mean = np.mean(abs_diff, axis=(1,2)) +print(abs_mean.shape) #output: (300,) +``` + +abs\_mean 은 모든 사진에 대한 오차 평균들의 배열이다.  + +다음으로 100개의 사과 사진은 10 x 10 로 이루어진 그래프를 만들어보자. + +``` +apple_index = np.argsort(abs_mean)[:100] +fig, axs = plt.subplots(10, 10, figsize=(10,10)) +for i in range(10): + for j in range(10): + axs[i, j].imshow(fruits[apple_index[i*10 + j]], cmap='gray_r') + axs[i, j].axis('off') +plt.show() +``` + +이렇게 비슷한 샘플끼리 그룹으로 모으는 작업을 **군집**이라 한다. 이렇게 군집 알고리즘에서 만든 그룹을 **클러스터**라 한다.  + +우리는 미리 사과, 바나나, 파인애플이라는 것을 알고 클러스터를 만들었지만 실제 비지도 학습에서는 어떤 과일일지 모르기 때문에 이처럼 샘플의 평균값을 미리 구할 수 없다. 그렇다면 어떻게 비슷한 샘플끼리 그룹으로 모을까? 다음 게시물에서 다룰 k-평균 알고리즘을 통해 해결할 수 있다. + +--- + + + +## 비지도 학습 - k 평균 알고리즘 + +### 1\. K - 평균 알고리즘이란? + +**k-평균 알고리즘**은 처음에 랜덤하게 클러스터 중심을 정하고 클러스터를 만든다. 그 다음 클러스터의 중심을 이동하고 다시 클러스터를 만드는 식으로 반복해서 최적의 클러스터를 구성하는 알고리즘이다. **클러스터 중심**은 k-평균 알고리즘이 만든 클러스터에 속한 샘플의 또 다른 특성으로 사용하거나 새로운 샘플에 대한 예측으로 활용할 수 있다.  + +k-평균 알고리즘 작동방식은 다음과 같다. + +1. 무작위로 k 개의 클러스터 중심을 정한다. +2. 각 샘플에서 가장 가까운 클러스터 중심을 찾아 해당 클러스터의 샘플로 지정한다. +3. 클러스터에 속한 샘플의 평균값으로 클러스터 중심을 변경한다. +4. 클러스터 중심에 변화가 없을 때까지 2번으로 돌아가 반복한다. + +--- + +### 2\. K - 평균 알고리즘 예시 + +#### 데이터셋 + +Chapter 6.1 군집 알고리즘에서 사용한 데이터셋과 동일하다. + +``` +!wget https://bit.ly/fruits_300_data -O fruits_300.npy +``` + +#### KMeans 클래스 + +``` +import numpy as np + +fruits = np.load('fruits_300.npy') +# 사진의 2차원 배열 -> 1차원 배열 +fruits_2d = fruits.reshape(-1, 100*100) +``` + +사이킷런의 k-평균 알고리즘은 sklearn.cluster 모듈 아래 KMeans 클래스에 구현되어 있다.  + +``` +from sklearn.cluster import KMeans + +km = KMeans(n_clusters=3, random_state=42) +km.fit(fruits_2d) +print(km.labels_) +``` + +KMeans 클래스를 사용할 때 클러스터 개수를 지정하는 n\_clusters를 매개변수로 주어야 한다. 군집된 결과는 KMeans 의 labels\_ 속성으로 확인할 수 있다. 이 때 클러스터 개수를 3으로 지정했기 때문에  labels\_의 배열 값은 0,1,2 중 하나이다. + +우선, 각 레이블의 샘플 개수를 확인해보자. + +``` +print(np.unique(km.labels_, return_counts=True)) +''' +(array([0, 1, 2], dtype=int32), array([111, 98, 91])) +''' +``` + + 레이블 0에 대해 111개, 1에 대해 98개, 2에 대해 91개의 샘플이 있다는 것을 확인할 수 있다. + +그 다음 클러스터 안에 있는 샘플 사진들을 보여주는 함수를 만들어보자. + +``` +import matplotlib.pyplot as plt + +def draw_fruits(arr, ratio=1): + n = len(arr) # n은 샘플 개수입니다 + # 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다. + rows = int(np.ceil(n/10)) + # 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다. + cols = n if rows < 2 else 10 + fig, axs = plt.subplots(rows, cols, + figsize=(cols*ratio, rows*ratio), squeeze=False) + for i in range(rows): + for j in range(cols): + if i*10 + j < n: # n 개까지만 그립니다. + axs[i, j].imshow(arr[i*10 + j], cmap='gray_r') + axs[i, j].axis('off') + plt.show() +``` + +위 함수를 이용해서 labels\_ == 0, 1, 2 일 때 샘플들을 확인해보자. + +``` +draw_fruits(fruits[km.labels_==0]) +draw_fruits(fruits[km.labels_==1]) +draw_fruits(fruits[km.labels_==2]) +``` + +#### 클러스터 중심 + +KMeans 클래스가 최종적으로 찾은 클러스터 중심은 cluster\_centers\_ 속성에 저장되어 있다. 이를 2차원 배열로 변환하여 이미지로 출력해보자. + +``` +draw_fruits(km.cluster_centers_.reshape(-1, 100, 100), ratio=3) +``` + +KMeans의 transform 메서드로 훈련 데이터 샘플에서 클러스터 중심까지 거리로 변환할 수 있다. + +``` +print(km.transform(fruits_2d[100:101])) +''' +[[3393.8136117 8837.37750892 5267.70439881]] +''' +``` + +첫 번째 값이 젤 작으므로 100번 째 과일은 0의 라벨을 가진다. 이를 predict 메서드로 확인해보자. + +``` +print(km.predict(fruits_2d[100:101])) +''' +[0] +''' +``` + +k-평균 알고리즘은 앞에서 설명했듯이 반복적으로 클러스터 중심을 옮기면서 최적의 클러스터를 찾는다. 반복 횟수는 KMeans의 n\_iter\_ 속성에 저장된다. + +``` +print(km.n_iter_) # 4 +``` + +--- + +#### 최적의 k 찾기 + +최적의 클러스터 개수를 찾는 대표적인 방법은 엘보우 방법이 있다. 이너셔는 클러스터 중심과 샘플 사이 거리의 제곱 합이다. 클러스터 개수에 따라 이너셔 감소가 꺾이는 지점이 적절한 클러스터 개수 k가 될 수 있다.  + + +KMeans 클래스는 자동으로 이니셔를 계산해서 inertia\_속성으로 제공한다.  + +``` +inertia = [] +for k in range(2, 7): + km = KMeans(n_clusters=k, random_state=42) + km.fit(fruits_2d) + inertia.append(km.inertia_) + +plt.plot(range(2, 7), inertia) +plt.xlabel('k') +plt.ylabel('inertia') +plt.show() +``` +--- + +--- + +## 차원 축소 / 주성분 분석 + +### 1\. 차원 축소란? + +차원 축소는 데이터를 가장 잘 나타내는 일부 특성을 선택하여 데이터 크기를 줄이고 지도 학습 모델의 성능을 향상시킬 수 있는 방법이다. 또한 줄어든 차원에서 다시 원본 차원으로 손실을 최대한 줄이면서 복원할 수도 있다. 대표적인 차원 축소 알고리즘으로 주성분 분석(PCA)이 있다. + +### 2\. 주성분 분석이란?  + +주성분 분석은 데이터에서 가장 분산이 큰 방향을 찾는 방법이다. 이 방향을 주성분이라 한다. 원본 데이터를 주성분에 투영하여 새로운 특성을 만들 수 있다. + +--- + +### 3\. 주성분 분석을 이용한 차원 축소 예시 + +#### 데이터셋​ + +이번에도 과일 데이터셋을 사용하겠다. + +``` +!wget https://bit.ly/fruits_300_data -O fruits_300.npy +``` + +``` +import numpy as np + +fruits = np.load('fruits_300.npy') +fruits_2d = fruits.reshape(-1, 100*100) +``` + +#### PCA 클래스 + +사이킷런은 sklearn.decomposition 모듈 아래 PCA 클래스로 주성분 분석 알고리즘을 제공한다.  + +``` +from sklearn.decomposition import PCA + +pca = PCA(n_components=50) +pca.fit(fruits_2d) +``` + +PCA 객체를 만들 때 n\_components 매개변수에 주성분 개수를 지정해야한다. components\_ 속성으로 확인해보자. + +``` +print(pca.components_.shape) +''' +(50,10000) +''' +``` + +KMeans 예제에서 사용한 draw\_fruis() 함수를 그대로 사용해서 주성분을 그림으로 그려보자. + +``` +import matplotlib.pyplot as plt + +def draw_fruits(arr, ratio=1): + n = len(arr) # n은 샘플 개수입니다 + # 한 줄에 10개씩 이미지를 그립니다. 샘플 개수를 10으로 나누어 전체 행 개수를 계산합니다. + rows = int(np.ceil(n/10)) + # 행이 1개 이면 열 개수는 샘플 개수입니다. 그렇지 않으면 10개입니다. + cols = n if rows < 2 else 10 + fig, axs = plt.subplots(rows, cols, + figsize=(cols*ratio, rows*ratio), squeeze=False) + for i in range(rows): + for j in range(cols): + if i*10 + j < n: # n 개까지만 그립니다. + axs[i, j].imshow(arr[i*10 + j], cmap='gray_r') + axs[i, j].axis('off') + plt.show() +draw_fruits(pca.components_.reshape(-1, 100, 100)) +``` + +transform 메서드를 이용하여 과일 데이터셋의 차원 축소를 해보자. + +``` +print(fruits_2d.shape) # (300, 10000) +fruits_pca = pca.transform(fruits_2d) +print(fruits_pca.shape) # (300, 50) +``` + +데이터가 10000 -> 50으로 축소된 것을 확인할 수 있다. fruits\_pca는 50개의 특성을 가진 데이터 배열이다.  + +#### 원본 데이터 재구성 + +inverse\_transform() 메서드를 통해 축소된 데이터를 원본 데이터로 상당 부분 재구성할 수 있다. 앞에서 만든 fruits\_pca 배열을 원본 데이터로 복구해보자. + +``` +fruits_inverse = pca.inverse_transform(fruits_pca) +print(fruits_inverse.shape) # (300, 10000) +fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100) + +for start in [0, 100, 200]: + draw_fruits(fruits_reconstruct[start:start+100]) + print("\n") +``` + +#### 설명된 분산 + +주성분이 원본 데이터의 분산을 얼마나 잘 나타내는지 기록한 값을 **설명된 분산**이라고 한다. PCA 의 explained\_varience\_ratio\_에 설명된 분산을 저장한다. 이를 다 더하면 50개의 주성분으로 표현하고 있는 총 분산 비율을 얻을 수 있다. + +``` +print(np.sum(pca.explained_variance_ratio_)) +''' +0.9215039913802381 +''' +``` + +92%가 넘는 분산을 유지하고 있는 것을 확인할 수 있다. 설명된 분산을 그래프로 그려보자. + +``` +plt.plot(pca.explained_variance_ratio_) +``` + +첫 번째 설명된 분산 값이 제일 높은 것을 확인할 수 있다. 대략 10개의 주성분이 대부분의 분산을 표현하고 있다.  + +--- + +### 4\. 다른 알고리즘과 함께 사용하기 + +#### 로지스틱 회귀에 적용하기 + +로지스틱 회귀를 이용하여 3개의 과일 사진을 분류하는 모델을 만들어보자. + +``` +from sklearn.linear_model import LogisticRegression + +lr = LogisticRegression() +target = np.array([0] * 100 + [1] * 100 + [2] * 100) +``` + +교차검증을 통해 원본 데이터와 축소된 데이터의 시간을 비교해보자. + +``` +from sklearn.model_selection import cross_validate + +scores = cross_validate(lr, fruits_2d, target) +print(np.mean(scores['test_score'])) +print(np.mean(scores['fit_time'])) +''' +0.9966666666666667 +0.6327765941619873 +''' + +scores = cross_validate(lr, fruits_pca, target) +print(np.mean(scores['test_score'])) +print(np.mean(scores['fit_time'])) +''' +1.0 +0.0364443302154541 +''' +``` + +정확성 측면에서는 둘 다 과대적합이 나왔지만, 걸린 시간 측면에서는 축소된 데이터를 사용했을 때 20배 빠른 결과를 확인할 수 있다.  + +이번에는 설명된 분산의 50%에 달하는 주성분을 찾도록 PCA 모델을 만들어보자. + +``` +pca = PCA(n_components=0.5) +pca.fit(fruits_2d +print(pca.n_components_) # 2 +``` + +n\_components 매개변수에 정수 값이 아닌 비율을 넣어주면 된다. 50%에 달하는 주성분을 갖게 하는 n\_components\_ 값은 2인 것을 확인할 수 있다.  + +``` +fruits_pca = pca.transform(fruits_2d) +print(fruits_pca.shape) # (300, 2) +``` + +주성분이 2개인 데이터셋으로 교차검증을 해보자. + +``` +scores = cross_validate(lr, fruits_pca, target) +print(np.mean(scores['test_score'])) +print(np.mean(scores['fit_time'])) +''' +0.9966666666666667 +0.046887540817260744 +''' +``` + +2개의 주성분을 사용해도 과대적합이 일어난 것을 확인할 수 있다. + +--- + +#### K-평균 알고리즘에 적용하기 + +``` +from sklearn.cluster import KMeans + +km = KMeans(n_clusters=3, random_state=42) +km.fit(fruits_pca) + +print(np.unique(km.labels_, return_counts=True)) + +for label in range(0, 3): + data = fruits_pca[km.labels_ == label] + plt.scatter(data[:,0], data[:,1]) +plt.legend(['apple', 'banana', 'pineapple']) +plt.show() +``` + +--- + +### **참고 자료** + +**\[혼공머신 chapter 6-1 군집 알고리즘.ipynb\] : [https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-1.ipynb#scrollTo=qfV19WdxS0HI](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-1.ipynb#scrollTo=qfV19WdxS0HI)** + +**\[혼공머신 - 6.2 K-평균.ipynb\] : [https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-2.ipynb#scrollTo=FwU\_s1Tnu9lS](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-2.ipynb#scrollTo=FwU_s1Tnu9lS)** + +**\[혼공머신 - 6.3 PCA.ipynb\] : [https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-3.ipynb#scrollTo=FwU\_s1Tnu9lS](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/6-3.ipynb#scrollTo=FwU_s1Tnu9lS)** From 01e9061f24679e3511889cba9b878d92accbf456 Mon Sep 17 00:00:00 2001 From: IdeaLim Date: Thu, 26 May 2022 11:44:24 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=203=ED=8C=80=20=EC=9E=84=EC=A0=95?= =?UTF-8?q?=EC=84=AD=206=EC=A3=BC=EC=B0=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0_\354\236\204\354\240\225\354\204\255.md" | 396 ++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 "week6/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" diff --git "a/week6/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" "b/week6/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" new file mode 100644 index 0000000..3e51364 --- /dev/null +++ "b/week6/3\355\214\200_\354\236\204\354\240\225\354\204\255.md" @@ -0,0 +1,396 @@ +## 인공 신경망 + +### 1\. 인공 신경망 이론 + +#### 인공 신경망이란? + +인공 신경망은 생물학적 뉴런에서 영감을 받아 만든 머신러닝 알고리즘이다. 신경망은 기존의 머신러닝 알고리즘으로 다루기 어려운 이미지, 음성, 텍스트 분야에서 뛰어난 성능을 발휘한다. 최근에는 인공 신경망 알고리즘을 종종 딥러닝이라고 부른다. + +#### 텐서플로란? + +텐서플로는 구글이 만든 딥러닝 라이브러리이다. CPU 와 GPU를 사용해 인공 신경망 모델을 효율적으로 훈련하며 모델 구축과 서비스에 필요한 다양한 도구를 제공한다. 신경망 모델을 빠르게 구성할 수 있는 케라스를 핵심 API로 채택하여 간단한 모델부터 복잡한 모델까지 손쉽게 만들 수 있다. + +#### 밀집층이란? + +가장 간단한 인공 신경망의 층이다. 밀집층에서는 뉴런들이 모두 연결되어 있기 때문에 완전 연결층이라고도 한다. 특별히 출력층에 밀집층을 사용할 때는 분류하려는 클래스와 동일한 개수의 뉴런을 사용한다. + +#### 원-핫 인코딩이란? + +원-핫 인코딩은 정숫값 배열에서 해당 정수 위치의 원소만 1이고 나머지는 모두 0으로 변환한다. 이 같은 변환이 필요한 이유는 다중 분류에서 출력층에서 만든 확률과 크로스 엔트로피 손실을 계산하기 위해서이다.  + +--- + +### 2\. 텐서플로를 이용한 인공 신경망 예제 + +#### 데이터 셋 + +데이터 셋으로 패션 MNIST 데이터셋을 사용한다.  + +``` +import numpy as np +from tensorflow import keras + +(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() +print(train_input.shape, train_target.shape) # (60000, 28, 28) (60000,) +print(test_input.shape, test_target.shape) # (10000, 28, 28) (10000,) +print(np.unique(train_target, return_counts=True)) +''' +(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000])) +''' +``` + +\*load\_data() 메서드는 훈련 데이터 와 테스트 데이터를 분리하여 반환한다. 훈련, 테스트 데이터는 28x28 size로 각각 60000, 10000 개의 데이터로 이루어져 있다. 데이터 종류는 10가지이다. + +#### 로지스틱 회귀로 패션 아이템 분류하기 + +``` +from sklearn.model_selection import cross_validate +from sklearn.linear_model import SGDClassifier + +# 픽셀 0 ~ 255 -> 0 ~ 1 사이 값으로 변환 +train_scaled = train_input / 255.0 +# SGDClassifier는 1차원 배열을 매개변수로 받기 때문에 2차원 배열 -> 1차원 배열로 변환 +train_scaled = train_scaled.reshape(-1, 28*28) + +sc = SGDClassifier(loss='log_loss', max_iter=5, random_state=42) + +scores = cross_validate(sc, train_scaled, train_target, n_jobs=-1) +print(np.mean(scores['test_score'])) +''' +0.8196000000000001 +''' +``` + +SGDClassifier 모델은 10개(클래스 개수)의 방정식에 대한 모델 파라미터(가중치와 절편)을 찾는다. 즉, 총 784개(픽셀 개수)의 가중치와 절편값을 구한다.  + +#### 인공 신경망으로 모델 만들기 + +이제 본격적으로 텐서플로를 이용해 인공 신경망 모델을 만들어보자. + +``` +from sklearn.model_selection import train_test_split + +train_scaled, val_scaled, train_target, val_target = train_test_split( + train_scaled, train_target, test_size=0.2, random_state=42) +``` + +\* 훈련 세트에서 20%를 검증세트로 분리했다. + +``` +dense = keras.layers.Dense(10, activation='softmax', input_shape=(784,)) +``` + +첫 번째 매개변수로는 뉴런 개수를 지정한다. 패션 데이터셋의 클래스가 10개이기 때문에 뉴런 개수를 10으로 설정했다.  + +두 번째 매개변수는 활성화 함수를 지정한다. 다중 분류에 사용할 소프트 맥스 함수로 설정했다. (이진 분류에서는 sigmod 로 설정하면 된다.) + +세 번째 매개변수는 입력값의 크기를 지정한다. 데이터의 size가 28x28 = 784 이기 때문에 (784,)로 설정했다. + +``` +model = keras.Sequential(dense) +``` + +keras.Sequential 클래스로 dense 객체를 넘겨주면 신경망 모델이 생성된다. + +#### 인공 신경망으로 패션 아이템 분류하기 + +``` +model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') +``` + +케라스 모델은 훈련하기 전에 손실함수 종류와 계산하고 싶은 측정값을 지정해야 한다. + +``` +model.fit(train_scaled, train_target, epochs=5) +''' +Epoch 1/5 +1500/1500 [==============================] - 3s 1ms/step - loss: 0.6058 - accuracy: 0.7932 +Epoch 2/5 +1500/1500 [==============================] - 2s 1ms/step - loss: 0.4785 - accuracy: 0.8385 +Epoch 3/5 +1500/1500 [==============================] - 2s 1ms/step - loss: 0.4564 - accuracy: 0.8471 +Epoch 4/5 +1500/1500 [==============================] - 2s 1ms/step - loss: 0.4435 - accuracy: 0.8539 +Epoch 5/5 +1500/1500 [==============================] - 2s 2ms/step - loss: 0.4358 - accuracy: 0.8551 + +''' +``` + + 에포크마다 걸린 시간과 손실, 정확도를 출력한다.  + +``` +model.evaluate(val_scaled, val_target) +''' +375/375 [==============================] - 1s 1ms/step - loss: 0.4579 - accuracy: 0.8483 +[0.45794257521629333, 0.8483333587646484] +''' +``` + +검증 세트로 모델을 평가해본 결과 훈련 세트의 점수보다 조금 낮은 84%의 정확도를 보여준다. + +## 심층 신경망 + +### 1\. 심층 신경망 이론 + +#### 심층 신경망이란? + +2개 이상의 층을 포함한 신경망이다. 다중 인공 신경망, 심층 신경망. 딥러닝은 같은 의미이다. + +#### 렐루 함수 + +이미지 분류 모델의 은닉층에 많이 사용하는 활성화 함수이다. 시그모이드 함수는 층이 많을수록 활성화 함수의 양쪽 끝에서 변화가 작기 떄문에 학습이 어렵다. 렐루 함수는 계산이 간단하며 양쪽 끝 변화의 문제가 없다. + +#### 옵티마이저 + +신경망의 가중치와 절편을 학습하기 위한 알고리즘 또는 방법을 말한다. 케라스에는 다양한 경사 하강법 알고리즘이 구현되어 있다. 대표적으로 SGD, Adam, 네스테로프 모멘텀, Adagard, RMSprop 등이 있다. + +--- + +### 2\. 심층 신경망 예제 + +#### 데이터 셋 + +인공 신경망에서 사용한 패션 데이터셋과 동일하다. + +``` +from tensorflow import keras +from sklearn.model_selection import train_test_split + + +(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data() + +# 데이터 전처리 +train_scaled = train_input / 255.0 +train_scaled = train_scaled.reshape(-1, 28*28) + +train_scaled, val_scaled, train_target, val_target = train_test_split( + train_scaled, train_target, test_size=0.2, random_state=42) +``` + +#### 2개의 층 + +``` +dense1 = keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)) +dense2 = keras.layers.Dense(10, activation='softmax') +``` + +dense1은 활성화 함수를 sigmoid 함수로 설정한 출력층이다. + +dense2은 활성화함수를 softmax 함수로 설정한 은닉층이다. + +#### 심층 신경망 만들기 + +``` +model = keras.Sequential([dense1, dense2]) +# summary() : 모델의 정보를 요약해서 출력 +model.summary() +''' +Model: "sequential" +_________________________________________________________________ + Layer (type) Output Shape Param # +================================================================= + dense (Dense) (None, 100) 78500 + + dense_1 (Dense) (None, 10) 1010 + +================================================================= +Total params: 79,510 +Trainable params: 79,510 +Non-trainable params: 0 +_________________________________________________________________ +''' +``` + +첫 번째 층인 출력층에서는 100개의 노드, 은닉층에서는 10개의 노드로 이루어져 있다. 총 파라미터 개수는 79510 이다. + +훈련 결과는 다음과 같다.  + +``` +model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') +model.fit(train_scaled, train_target, epochs=5) +''' +Epoch 1/5 +1500/1500 [==============================] - 4s 2ms/step - loss: 0.5628 - accuracy: 0.8073 +Epoch 2/5 +1500/1500 [==============================] - 3s 2ms/step - loss: 0.4075 - accuracy: 0.8522 +Epoch 3/5 +1500/1500 [==============================] - 3s 2ms/step - loss: 0.3741 - accuracy: 0.8652 +Epoch 4/5 +1500/1500 [==============================] - 4s 2ms/step - loss: 0.3509 - accuracy: 0.8732 +Epoch 5/5 +1500/1500 [==============================] - 4s 3ms/step - loss: 0.3335 - accuracy: 0.8784 + +''' +``` + +#### 렐루 활성화 함수 + +``` +# add() : 모델에 층을 추가하는 메서드 +model = keras.Sequential() +# Flatten : 입력 데이터의 차원을 일렬로 변환하는 층 +model.add(keras.layers.Flatten(input_shape=(28, 28))) +model.add(keras.layers.Dense(100, activation='relu')) +model.add(keras.layers.Dense(10, activation='softmax')) +``` + +활성화 함수를 relu 로 설정했다.  + +훈련 결과는 다음과 같다. + +``` +model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') + +model.fit(train_scaled, train_target, epochs=5) +''' +Epoch 1/5 +1500/1500 [==============================] - 5s 3ms/step - loss: 0.5336 - accuracy: 0.8090 +Epoch 2/5 +1500/1500 [==============================] - 3s 2ms/step - loss: 0.3934 - accuracy: 0.8579 +Epoch 3/5 +1500/1500 [==============================] - 3s 2ms/step - loss: 0.3554 - accuracy: 0.8717 +Epoch 4/5 +1500/1500 [==============================] - 4s 2ms/step - loss: 0.3337 - accuracy: 0.8799 +Epoch 5/5 +1500/1500 [==============================] - 4s 3ms/step - loss: 0.3181 - accuracy: 0.8859 + +''' +``` + +앞선 입력층과 출력층만으로 이루어진 인공 신경망보다 더 높은 정확성을 보인다.  + +--- + +### 3\. 옵티마이저 예제 + +#### SGD + +``` +sgd = keras.optimizers.SGD() +# 적응적 학습률 적용 +sgd = keras.optimizers.SGD(learning_rate=0.1) +# 네스테로프 모멘텀 : 모멘텀 최적화 2번 진행 +sgd = keras.optimizers.SGD(momentum=0.9, nesterov=True) +model.compile(optimizer=sgd, loss='sparse_categorical_crossentropy', metrics='accuracy') +``` + +#### Adagrad + +``` +adagrad = keras.optimizers.Adagrad() +model.compile(optimizer=adagrad, loss='sparse_categorical_crossentropy', metrics='accuracy') +``` + +#### Rmsprop + +``` +rmsprop = keras.optimizers.RMSprop() +model.compile(optimizer=rmsprop, loss='sparse_categorical_crossentropy', metrics='accuracy') +``` + +## 신경망 모델 훈련 + +### 1\. 신경망 모델 훈련 이론 + +#### 드롭아웃  + +은닉층에 있는 뉴런의 출력을 랜덤하게 껴서 과대적합을 막는 기법이다. 드롭아웃은 훈련 중에 적용되며 평가나 예측에서는 적용하지 않는다. 텐서플로는 이를 자동적으로 처리한다. + +#### 콜백  + +케라스 모델을 훈련하는 도중에 어떤 작업을 수행할 수 있도록 도와주는 도구이다. 대표적으로 최상의 모델을 자동으로 저장해 주거나 검증 점수가 더 이상 향상되지 않으면 일찍 종료할 수 있다. + +#### 조기 종료 + +검증 점수가 더 이상 감소하지 않고 상승하여 과대적합이 일어나면 훈련을 계속 진행하지 않고 멈추는 기법이다. + +--- + +### 2\. 신경망 모델 훈련 예시 + +#### 손실 곡선 + +``` +model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') + +history = model.fit(train_scaled, train_target, epochs=5, verbose=0) +print(history.history.keys()) +''' +dict_keys(['loss', 'accuracy']) +''' +``` + +``` +import matplotlib.pyplot as plt + +plt.plot(history.history['loss']) +plt.xlabel('epoch') +plt.ylabel('loss') +plt.show() +``` + +[##_Image|kage@sGlPZ/btrCxHjDvtV/AqNYpe8KYGTYAb7TqLjiQ0/img.png|CDM|1.3|{"originWidth":392,"originHeight":262,"style":"alignCenter"}_##] + +``` +plt.plot(history.history['accuracy']) +plt.xlabel('epoch') +plt.ylabel('accuracy') +plt.show() +``` + +[##_Image|kage@o0jlR/btrCyYMDs1v/PoZdp3XiTmaaqJUaKAP1kK/img.png|CDM|1.3|{"originWidth":392,"originHeight":266,"style":"alignCenter"}_##] + +#### 검증 손실 + +``` +model = model_fn() +model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy') + +history = model.fit(train_scaled, train_target, epochs=20, verbose=0, + validation_data=(val_scaled, val_target)) +print(history.history.keys()) +''' +dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy']) +''' +``` + +``` +plt.plot(history.history['loss']) +plt.plot(history.history['val_loss']) +plt.xlabel('epoch') +plt.ylabel('loss') +plt.legend(['train', 'val']) +plt.show() +``` + +[##_Image|kage@b2u8nT/btrCCE6J2dj/WkiuD7UnSxuKz2sVEQV2cK/img.png|CDM|1.3|{"originWidth":392,"originHeight":262,"style":"alignCenter"}_##] + +#### 드롭아웃 + +``` +model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', + metrics='accuracy') + +history = model.fit(train_scaled, train_target, epochs=20, verbose=0, + validation_data=(val_scaled, val_target)) +``` + +``` +plt.plot(history.history['loss']) +plt.plot(history.history['val_loss']) +plt.xlabel('epoch') +plt.ylabel('loss') +plt.legend(['train', 'val']) +plt.show() +``` + +--- + +### **참고 자료** + +**\[혼공머신 - 7.1 인공신경망.ipynb\] : [https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-1.ipynb#scrollTo=fMTyGYIMqUE9](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-1.ipynb#scrollTo=fMTyGYIMqUE9)** + +**[**\[혼공머신 - 7.2 심층 신경망.ipynb\] :**](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-1.ipynb#scrollTo=fMTyGYIMqUE9) **[https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-2.ipynb#scrollTo=KkpbSMXWtakr](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-2.ipynb#scrollTo=KkpbSMXWtakr)**** + +**[**\[혼공머신 - 7.3 신경망 모델 훈련.ipynb\] :**](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-1.ipynb#scrollTo=fMTyGYIMqUE9) **[https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-3.ipynb#scrollTo=KkpbSMXWtakr](https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-2.ipynb#scrollTo=KkpbSMXWtakr)**** \ No newline at end of file