pycharm에서 tensorflow-cpu로 사용하기 위해서는 다음의 코드를 추가해야함(아마 그럴것.. 나는 주피터에서 돌려서)

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

 

 

categorical_crossentropy를 손실함수로 사용했을 때의 (대략적인) CNN 신경망 코드

import tensorflow as tf
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.datasets.fashion_mnist import load_data
from tensorflow.keras.models import Sequential, save_model, load_model
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D

# Fashion-MNIST 데이터 불러오기
(x_train, y_train), (x_test, y_test) = load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train = x_train.reshape(-1,28,28,1)
x_test = x_test.reshape(-1,28,28,1)

# 원핫인코딩 (one-hot encoding) 처리 (categorical_crossentropy를 사용하기 때문)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# train/valid 분류
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.3,random_state=777)

# 모델 생성
model = Sequential([
  Conv2D(64, kernel_size=(5,5),input_shape=x_train.shape[1:], activation='relu'),
  MaxPooling2D(pool_size=(2, 2), padding='same'),
  Dropout(0.2),
  Flatten(),
  Dense(128, activation='relu'),
  Dense(128, activation='relu'),
  Dense(32, activation='relu'),
  Dropout(0.2),
  Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 모델 학습
hist = model.fit(x_train, y_train, batch_size=100 ,epochs=20, validation_data=(x_val ,y_val))
print(model.evaluate(x_test,  y_test, verbose=1))

# 정확도 시각화
import matplotlib.pyplot as plt
# print(hist.history)

plt.plot(hist.history['accuracy'],'b-', label='training')
plt.plot(hist.history['val_accuracy'],'r:' , label='validation')
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

# 손실값 시각화
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

# 모델 저장
save_model(model,"c:\\data\\fashion_mnist.h5")

# 모델 불러오기
model2 = load_model("c:\\data\\fashion_mnist.h5")

# test 데이터를 사용해 불러온 모델 성능 평가
result = model2.evaluate(x_test,y_test)
print(dict(zip(model.metrics_names, result)))

# sklearn accuracy_score를 사용하여 모델 정확도 평가
from sklearn.metrics import accuracy_score
print(accuracy_score(model2.predict_classes(x_test), np.argmax(y_test,axis=1)))

 

categorical_crossentropy는 다중 분류 손실함수로 one-hot encoding 클래스를 사용한다. 따라서 출력값이 one-hot encoding된 결과로 나오고 정답(label)과 비교하며 학습을 진행하거나 정확도를 알아내기 위해서는 정답(label)도 one-hot encoding된 형태여야 한다. 따라서 위의 코드 구현에서 정답(y_train, y_test)에 대해 one-hot encoding을 하였다.

 

 

 

sparse_categorical_crossentropy를 손실함수로 사용했을 때의 완전연결신경망 코드

import tensorflow as tf
from tensorflow.keras.datasets.fashion_mnist import load_data
from tensorflow.keras.models import Sequential, save_model, load_model
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D

# Fashion-MNIST 데이터 불러오기
(x_train, y_train), (x_test, y_test) = load_data()

# 데이터 정규화
x_train, x_test = x_train / 255.0, x_test / 255.0

# sparse_categorical_crossentropy를 손실함수로 사용하기 때문에 one-hot encoding 사용 안함



# train 데이터 분리 (train/valid)
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.3,random_state=777)

# 신경망 모델 생성
model = Sequential([
  Flatten(input_shape=(28, 28)),
  Dense(128, activation='relu'),
  Dense(128, activation='relu'),
  Dense(32, activation='relu'),
  Dropout(0.2),
  Dense(10, activation='softmax')
])

# 학습할 때 사용할 옵티마이저, 손실함수, 기준에 대한 정보
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['sparse_categorical_accuracy'])

# 모델 학습
hist = model.fit(x_train, y_train, batch_size=64, epochs=20, validation_data=(x_val ,y_val))

# 학습 시각화
import matplotlib.pyplot as plt
# print(hist.history) # hist에 어떤 데이터가 있는지 확인할 수 있음
plt.plot(hist.history['sparse_categorical_accuracy'],'b-', label='training')
plt.plot(hist.history['val_sparse_categorical_accuracy'],'r:' , label='validation')
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.show()

# 학습 손실 값과 검증 손실 값 시각화
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Valid'], loc='upper left')
plt.show()

# 구현한 model의 파라미터들 h5 파일로 저장
save_model(model, "c:\\data\\fashion_mnist2.h5")

# 모델 성능 평가
model2 = load_model("c:\\data\\fashion_mnist2.h5")
print(model2.evaluate(x_test,y_test,verbose=0))

# sklearn의 accuracy_score를 사용하여 정확도 확인
from sklearn.metrics import accuracy_score
print(accuracy_score(model2.predict_classes(x_test), y_test))

 

sparse_categorical_crossentropy 또한 다중 분류 손실함수로, categorical_crossentropy와 동일하지만 integer type 클래스라는 것이 다르다. 결론적으로 sparse_categorical_crossentropy는 정답(label)이 one-hot encoding 형태가 아니어도 된다.

 

sparse_categorical_crossentropy를 사용해서 모델을 학습시키고 이 학습된 모델을 불러와서 정확도를 측정하기 위해서는 metrics가 sparse_categorical_accuracy여야 한다. 안그러면 불러온 모델로 evaluate을 하면 정확도가 엉망으로 나온다...^^ (이걸로 개고생함) 만약 실수로 metrics를 sparse_categorical_accuracy로 안하고 그냥 accuracy로 했다면 evaluate으로 정확도를 평가하지말고 sklearn의 accuracy_score로 확인해야 제대로 값이 나온다는 것을 추가적으로 꼭꼭 알길 바란다.

 

 

 

h5 파일이 어떻게 구성되어 있는지 확인하는 파이썬 코드

import h5py
filename = "c:\\data\\fashion_mnist.h5"

def read_hdf5(path):

    weights = {}

    keys = []
    with h5py.File(path, 'r') as f: # open file
        f.visit(keys.append) # append all keys to list
        for key in keys:
            if ':' in key: # contains data if ':' in key
                print(f[key].name)
                weights[f[key].name] = f[key].value
    return weights

read_hdf5(filename)

 

 

 

 

 

+

 

 

 

 

 

Keras Callbacks

 

Callbacks - Keras Documentation

Usage of callbacks 콜백은 학습 과정의 특정 단계에서 적용할 함수의 세트입니다. 학습 과정 중 콜백을 사용해서 모델의 내적 상태와 통계자료를 확인 할 수 있습니다. 콜백의 리스트는 (키워드 인수

keras.io

 

추가적으로 모델 학습시, keras의 callback 기능으로 최적의 모델을 만들 수 있다. 이에 대한 부분은 위의 kears 링크를 참고하는 것이 빠르다.

 

from tensorflow.keras.datasets import fashion_mnist

# Fashion_MNIST 데이터 불러오기
(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()

import matplotlib.pyplot as plt
import numpy as np

# 정규화, 4차원으로 데이터를 만들어줌
x_train = np.reshape(x_train / 255, (-1, 28, 28, 1))
x_test = np.reshape(x_test / 255, (-1, 28, 28, 1))

from tensorflow.keras.utils import to_categorical
# one-hot encoding
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

from sklearn.model_selection import train_test_split
# train / valid 분리
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size = 0.3, random_state = 777)

print('Fashion-MNIST ready~')

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPool2D, Dense, Flatten

model = Sequential([
    # 항상 모델의 첫 번째 층은 입력의 형태를 명시해주어야함
    Conv2D(filters = 16, kernel_size = 3, strides = (1, 1), padding = 'same', activation = 'relu', input_shape = (28, 28, 1)),
    MaxPool2D(pool_size = (2, 2), strides = 2, padding = 'same'),  
    Conv2D(filters = 32, kernel_size = 3, strides = (1, 1), padding = 'same', activation = 'relu'),
    MaxPool2D(pool_size = (2, 2), strides = 2, padding = 'same'),
    Conv2D(filters = 64, kernel_size = 3, strides = (1, 1), padding = 'same', activation = 'relu'),
    MaxPool2D(pool_size = (2, 2), strides = 2, padding = 'same'),
    Flatten(), # 완전연결층에 들어가기 전 데이터 펼치기
    Dense(64, activation = 'relu'),
    Dense(10, activation = 'softmax') # 10개의 출력을 가지는 신경망
])

model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['acc'])

# kears callbacks 사용
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping

filepath = 'c:\\data\\fashion.hdf5'

# ModelCheckpoint : 학습 과정을 모니터링하다가 val_loss가 가장 작을 때 모델의 가중치를 저장
# EarlyStopping : 모니터링하는 평가지표에서 성능 향상이 일어나지 않는 경우
# (patience=5 면 향상이 일어나지 않는 경우 5번까지는 참아줌) 학습 중단
callbacks = [ ModelCheckpoint( filepath = filepath , monitor = 'val_loss' , verbose=1, save_best_only=True ),
            EarlyStopping(monitor='val_loss', patience=0, verbose=0, mode='auto')]

model.fit(x_train, y_train, batch_size = 32 , validation_data=(x_val , y_val) , epochs=10, callbacks=callbacks )
model.summary() # 모델의 구조 확인

 

 

 

 

 

wisc_bc_data.csv
0.12MB

 

 

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
50
# 유방암 데이터 로드
bc <- read.csv('c:/data/wisc_bc_data.csv',header=T,stringsAsFactors = T)
 
# shuffle
set.seed(1)
bc_shuffle <- bc[sample(nrow(bc)),]
bc2 <- bc_shuffle[-1# 환자번호 제거
 
# 정규화
normalize <- function(x) {
  return ((x-min(x))/(max(x)-min(x)))
}
 
ncol(bc2)
bc_n <- as.data.frame(lapply(bc2[2:31],normalize))
 
# train(90%) / test(10%)
train_num <- round(0.9*nrow(bc_n),0)
 
bc_train <- bc_n[1:train_num,]
bc_test <- bc_n[(train_num+1):nrow(bc_n),]
 
bc_train_label <- bc2[1:train_num,1]
bc_test_label <- bc2[(train_num+1):nrow(bc_n),1]
 
# kmeans 사용
library(stats)
bc_test
 
# test 데이터를 2개로 군집화
result2 <- kmeans(bc_test,2)
 
# 라벨링된 것이 악성인지 양성인지에 대해서는 라벨과 비교해서 내가 알아내야함
result2$cluster # 라벨링이 1, 2로 됨
bc_test_label
# 보면 느낌적으로 B를 1로, M을 2로 클러스터링한 것을 알 수 있음
 
# 시각화
library(factoextra)
fviz_cluster(result2,data=bc_test,stand=T)
 
# test_label도 숫자로 바꿔줌
bc_test_label
label_check <- ifelse(bc_test_label=='M',2,1)
label_check
 
# 군집화의 정확도 확인
real <- length(label_check)
predict <- sum(label_check==result2$cluster)
predict/real*100 # 89.47368
cs

 

1 : B(음성) / 2 : M(양성)

 

 

 

 

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
bc <- read.csv('c:/data/wisc_bc_data.csv',header=T,stringsAsFactors = T)
 
# shuffle
set.seed(1)
bc_shuffle <- bc[sample(nrow(bc)),]
bc2 <- bc_shuffle[-1# 환자번호 제거
 
ncol(bc2)
bc_n <- bc2[2:31]
 
# train(90%) / test(10%)
train_num <- round(0.9*nrow(bc_n),0)
 
bc_train <- bc_n[1:train_num,]
bc_test <- bc_n[(train_num+1):nrow(bc_n),]
 
bc_train_label <- bc2[1:train_num,1]
bc_test_label <- bc2[(train_num+1):nrow(bc_n),1]
 
# kmeans 사용
library(stats)
bc_test
 
# test 데이터를 2개로 군집화
result2 <- kmeans(bc_test,2)
 
# 라벨링된 것이 악성인지 양성인지에 대해서는 라벨과 비교해서 내가 알아내야함
result2$cluster # 라벨링이 1, 2로 됨
bc_test_label
# 보면 느낌적으로 B를 2로, M을 1로 클러스터링한 것을 알 수 있음
 
# 시각화
library(factoextra)
fviz_cluster(result2,data=bc_test,stand=T)
 
# test_label도 숫자로 바꿔줌
bc_test_label
label_check <- ifelse(bc_test_label=='M',1,2)
 
# 군집화의 정확도 확인
real <- length(label_check)
real
 
predict <- sum(label_check==result2$cluster)
predict
 
# 정확도
predict/real*100 # 91.22807
cs

 

1 : M(양성) / 2 : B(음성)

 

 

나는 이 예제를 클러스터링(정답 X)을 하면, 클러스터링된 것을 라벨(정답)과 비교해서 어떻게 클러스터링 했는지를 확인해야 한다는 것을 보여주기 위해 실행해보았다. 하지만 이것보다 더 중요한 사실도 이 예제에 담겨져 있다. 첫번째 실습은 정규화를 수행했고, 두번째 실습은 정규화를 수행하지 않았다. 그 결과 정규화를 하지 않은 데이터가 예측률이 더 높았다. 왜 그런걸까?

 

정규화를 하는 경우는 종속변수와 독립변수의 영향도를 확인하고 싶을 때이고, 실제로 예측을 하는 경우에는 정규화를 하지 않아야한다.

 

 

 

 

 

academy.csv
0.00MB

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 데이터 로드
academy <- read.csv("c:/data/academy.csv")
academy
 
# 학생 번호 빼놓기
student <- academy[,'학생번호']
student
 
# 수학 영어 점수만 사용
academy <- academy[,c(3,4)]
academy
# k-means 4 클러스터링 : 수학o영어o / 수학o영어x / 수학x영어o / 수학x영어x
km <- kmeans(academy,4)
km
 
library(factoextra)
fviz_cluster(km,data=academy,stand=T)
 
cbind(student,academy, km$cluster)
cs

 

 

stand=T인 경우는 평균을 0으로 표준화함

 

 

1
2
fviz_cluster(km,data=academy,stand=F)
 
cs

 

stand=F인 경우는 x축, y축 점수를 그대로 보여줌

 

 

 


 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 데이터 로드
academy <- read.csv("c:/data/academy.csv")
academy
 
# 학생 번호 빼놓기
student <- academy[,'학생번호']
student
 
# 수학 영어 점수만 사용
academy <- academy[,c(3,4,6)]
academy
# k-means 4 클러스터링 : 수학o영어o / 수학o영어x / 수학x영어o / 수학x영어x
km <- kmeans(academy,4)
km
 
library(factoextra)
fviz_cluster(km,data=academy,stand=T)
 
cbind(student,academy, km$cluster)
cs

 

fviz함수 자체가 PCA 기반이므로 컬럼이 3개 이상이면 차원으로 넘어감

 

x축의 Dim1(70.7%)은 약 71%만큼 클러스터링에 영향을 주었다는 뜻이다. 이것도 정규화를 하고 안하고에 따라서 Dim1+Dim2가 100%(stand=F)이거나 100%가 안되거나(stand=T)한다. 표준화를 하면 조금 더 균등하게 차원분석을 통해 클러스터링을 하나, 표준화를 하지 않으면 대부분 Dim1에 의존적으로 클러스터링한다.

 

stand=F인 경우

 

 

 

 

 

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
# k-means 시각화
# 데이터 생성
<- c(3,4,1,5,7,9,5,4,6,8,4,5,9,8,7,8,6,7,2,1)
row <- c("A","B","C","D","E","F","G","H","I","J")
col <- c("X","Y")
data <- matrix( c, nrow= 10, ncol=2, byrow=TRUE, dimnames=list(row,col))
data
 
# 데이터 시각화
plot(data)
 
# k-means 패키지 불러오기
# install.packages("stats")
library(stats)
 
# k개 구하는 공식 : sqrt(n/2) n = 전체 행의 갯수
km <- kmeans(data,2)
km # K-means clustering with 2 clusters of sizes 5, 5
 
# 군집의 무게중심(중앙점) 확인
km$centers
 
# 군집화 확인
cbind(data,km$cluster)
 
# 군집의 무게중심 시각화
plot(round(km$center), col=km$cluster, pch=22, bg=km$center, xlim=range(0:10),ylim=range(0:10))
 
# 기존 데이터 
par(new=T)
plot( data, col=km$cluster, pch=22, xlim=range(0:10), ylim=range(0:10) )
cs

 

R로 시각화한 k-means

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# k-means 시각화
# 데이터 생성
<- c(3,4,1,5,7,9,5,4,6,8,4,5,9,8,7,8,6,7,2,1)
row <- c("A","B","C","D","E","F","G","H","I","J")
col <- c("X","Y")
data <- matrix( c, nrow= 10, ncol=2, byrow=TRUE, dimnames=list(row,col))
data
 
# 클러스터링 시각화 패키지 설치
# install.packages("factoextra")
library(factoextra)
 
km <- kmeans(data,2)
fviz_cluster(km, data = data, stand=F)
cs

 

패키지를 활용해 시각화한 k-means

 

 

 

 

 

 

레미제라블 3D 인물 네트워크

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3D 시각화 패키지 설치
install.packages("networkD3")
install.packages("dplyr")
 
library(networkD3)
library(dplyr)
 
# data set 소설 레미제라블 인물 관계도
# 데이터 로드
data(MisLinks, MisNodes)
head(MisNodes) # size : 몇번 언급되었는지에 대한 정보
head(MisLinks) # value : 인물끼리 몇번 만났는지 데이터 
 
# plot
D3_network_LM<-forceNetwork(Links = MisLinks, Nodes = MisNodes, 
                            Source = 'source', Target = 'target'
                            NodeID = 'name', Group = 'group',opacityNoHover = TRUE,
                            zoom = TRUE, bounded = TRUE,
                            fontSize = 15,
                            linkDistance = 75,
                            opacity = 0.9)
 
D3_network_LM
cs

 

 

허거덩 너무 신기해~!

 

 

모바일관련 소송 시각화

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# IT 회사들간 법적 소송관계도 시각화
# 데이터 로드
links = '[
  {"source": "Microsoft", "target": "Amazon", "type": "licensing"},
{"source": "Microsoft", "target": "HTC", "type": "licensing"},
{"source": "Samsung", "target": "Apple", "type": "suit"},
{"source": "Motorola", "target": "Apple", "type": "suit"},
{"source": "Nokia", "target": "Apple", "type": "resolved"},
{"source": "HTC", "target": "Apple", "type": "suit"},
{"source": "Kodak", "target": "Apple", "type": "suit"},
{"source": "Microsoft", "target": "Barnes & Noble", "type": "suit"},
{"source": "Microsoft", "target": "Foxconn", "type": "suit"},
{"source": "Oracle", "target": "Google", "type": "suit"},
{"source": "Apple", "target": "HTC", "type": "suit"},
{"source": "Microsoft", "target": "Inventec", "type": "suit"},
{"source": "Samsung", "target": "Kodak", "type": "resolved"},
{"source": "LG", "target": "Kodak", "type": "resolved"},
{"source": "RIM", "target": "Kodak", "type": "suit"},
{"source": "Sony", "target": "LG", "type": "suit"},
{"source": "Kodak", "target": "LG", "type": "resolved"},
{"source": "Apple", "target": "Nokia", "type": "resolved"},
{"source": "Qualcomm", "target": "Nokia", "type": "resolved"},
{"source": "Apple", "target": "Motorola", "type": "suit"},
{"source": "Microsoft", "target": "Motorola", "type": "suit"},
{"source": "Motorola", "target": "Microsoft", "type": "suit"},
{"source": "Huawei", "target": "ZTE", "type": "suit"},
{"source": "Ericsson", "target": "ZTE", "type": "suit"},
{"source": "Kodak", "target": "Samsung", "type": "resolved"},
{"source": "Apple", "target": "Samsung", "type": "suit"},
{"source": "Kodak", "target": "RIM", "type": "suit"},
{"source": "Nokia", "target": "Qualcomm", "type": "suit"}
]'
 
link_df = jsonlite::fromJSON(links)
# node의 index 숫자는 0부터 시작
# dplyr::row_number()가 1부터 숫자를 매기기 때문에 1씩 뺌
node_df = data.frame(node = unique(c(link_df$source, link_df$target))) %>
  mutate(idx = row_number()-1)
 
# node_df에서 index값을 가져와서 source와 target에 해당하는 index 값을 저장
link_df = link_df %>
  left_join(node_df %>% rename(source_idx = idx), by=c('source' = 'node')) %>
  left_join(node_df %>% rename(target_idx = idx), by=c('target' = 'node'))
 
# 데이터 확인
node_df
link_df
 
# 3D 시각화 패키지 설치
library(networkD3)
library(dplyr)
 
# plot
D3_network_LM<-forceNetwork(Links = link_df, 
                            Nodes = node_df, 
                            Source = 'source_idx', Target = 'target_idx'
                            NodeID = 'node', Group = 'idx',
                            opacityNoHover = TRUE, zoom = TRUE
                            bounded = TRUE,
                            fontSize = 15,
                            linkDistance = 75,
                            opacity = 0.9)
 
D3_network_LM
 
cs

 

Microsoft 깡패...

 

 

 

+ Recent posts