728x90

본 실습 내용은 패스트캠퍼스 강의임을 먼저 알립니다 ~!

 

고객 데이터를 통해서 은행상품의 마케팅 효과 알아보는 실습 내용입니다.

변수는 총 20개이며 맨끝 데이터가 target 입니다. 

전처리 및 모델 적용내용은 실습코드 안에 주석으로 했습니다.

rawdata1 <- read.csv('bank.csv', header=TRUE)
str(rawdata1)

#피처확인
unique(rawdata1$age)
unique(rawdata1$job) #unknown 처리 필요(보통 결측치로 처리)
unique(rawdata1$marital) #unknown 
unique(rawdata1$education) #unknown
unique(rawdata1$default)#unknown
unique(rawdata1$loan)#unknown
unique(rawdata1$contact)#unknown
unique(rawdata1$month)
unique(rawdata1$day_of_week)
unique(rawdata1$duration)
unique(rawdata1$campaign)
unique(rawdata1$previous)
unique(rawdata1$poutcome)
unique(rawdata1$emp.var.rate)
unique(rawdata1$nr.employed)
unique(rawdata1$target) #지도학습-이진분류

#결측치 처리
# unknown =>NA 변환
sum(rawdata1=='unknown')
rawdata1[rawdata1=='unknown'] <- NA #비어 있는 값으로 
sum(is.na(rawdata1))

#결측치 행 제거
rawdata1 <- na.omit(rawdata1) #결측치 포함한 행 삭제
str(rawdata1)

#히스토그램
#데이터 표준화가 필요 하다는 걸 알수 있다.
par(mfrow=c(3,3), mar=c(5.1, 4.1, 4.1, 2.1))
hist(rawdata1$age, main="age histogram", xlab="age", col="orange")
hist(rawdata1$duration, main="duration histogram", xlab="duration", col="yellow")
hist(rawdata1$campaign, main="campaign histogram", xlab="campaign", col="green")
hist(rawdata1$previous, main="previous histogram", xlab="previous", col="blue")
hist(rawdata1$emp.var.rate, main="emp.var.rate historgram", xlab="emp.var.rate", col="navy")
hist(rawdata1$cons.price.idx, main="cons.price.idx histogram", xlab="cons.price.idx", col="purple")
hist(rawdata1$cons.conf.idx, main="cons.conf.idx histogram", xlab="cons.conf.idx", col="salmon")
hist(rawdata1$euribor3m, main="euribor3m histogram", xlab="euribor3m", col="gray")
hist(rawdata1$nr.employed, main="nr.employed histogram", xlab="nr.employed", col="black")

#표준화: 숫자형 변수
rawdata1$age <- scale(rawdata1$age)
rawdata1$duration <- scale(rawdata1$duration)
rawdata1$campaign <- scale(rawdata1$campaign)
rawdata1$previous <- scale(rawdata1$previous)
rawdata1$emp.var.rate <- scale(rawdata1$emp.var.rate)
rawdata1$cons.price.idx <- scale(rawdata1$cons.price.idx)
rawdata1$cons.conf.idx <- scale(rawdata1$cons.conf.idx)
rawdata1$euribor3m <- scale(rawdata1$euribor3m)
rawdata1$nr.employed <- scale(rawdata1$nr.employed)

#표준화 후 시각화 
par(mfrow=c(3,3), mar=c(5.1, 4.1, 4.1, 2.1))
hist(rawdata1$age, main="age histogram", xlab="age", col="orange")
hist(rawdata1$duration, main="duration histogram", xlab="duration", col="yellow")
hist(rawdata1$campaign, main="campaign histogram", xlab="campaign", col="green")
hist(rawdata1$previous, main="previous histogram", xlab="previous", col="blue")
hist(rawdata1$emp.var.rate, main="emp.var.rate historgram", xlab="emp.var.rate", col="navy")
hist(rawdata1$cons.price.idx, main="cons.price.idx histogram", xlab="cons.price.idx", col="purple")
hist(rawdata1$cons.conf.idx, main="cons.conf.idx histogram", xlab="cons.conf.idx", col="salmon")
hist(rawdata1$euribor3m, main="euribor3m histogram", xlab="euribor3m", col="gray")
hist(rawdata1$nr.employed, main="nr.employed histogram", xlab="nr.employed", col="black")

#미리 펴준화를 하는 이유
#caret에서 preprocess로 표준화는 오직 숫자로된 변수만 구성되어 있을때나 가능하다. 이번 데이터는 문자형이 섞여 있으므로 미리 표준화를 해주었다.

#범주형 자료 시각화: barplot, pie
par(mfrow=c(3,3), mar=c(5.1,4.1,4.1,2.1))
barplot(prop.table(table(rawdata1$job)), main='직업 비율')
barplot(prop.table(table(rawdata1$marital)), main='결혼여부')
barplot(prop.table(table(rawdata1$education)), main='교육수준')
barplot(prop.table(table(rawdata1$default)), main='파산여부')
barplot(prop.table(table(rawdata1$housing)), main='주택대출여부')
barplot(prop.table(table(rawdata1$loan)), main='개인대출여부')
barplot(prop.table(table(rawdata1$contact)), main='연락방법')
barplot(prop.table(table(rawdata1$month)), main='마지막 연락 달')
barplot(prop.table(table(rawdata1$day_of_week)), main='마지막 연락 요일')

#주성분 분석(보통 90%이상을 대상으로 실행)
num_feature <- c("age","duration",'campaign', 'previous','emp.var.rate', "cons.price.idx", "cons.conf.idx", "euribor3m","nr.employed")

tar <- rawdata1[,"target"]
num_data <- rawdata1[,num_feature]
pca_num <- prcomp(num_data)
plot(pca_num, type='l', main='Principle') #세로축이 높을수록 변동성의 설명력이 높다. 
summary(pca_num)

#rotation : 주성분 벡터
#%*%: 행렬 곱, 원본데이터 * 주성분 데이터 
pca_matrix <- pca_num$rotation
pca_matrix
pca_data <- as.matrix(num_data)%*%pca_matrix
reduced_data <- data.frame(cbind(pca_data[,1:3],tar)) #cbind: 열결합
reduced_data
reduced_data$tar <- as.factor(reduced_data$tar)
str(reduced_data)

#차원 축소를 통한 시각화
library(ggplot2)
ggplot(data=reduced_data, aes(x=PC1, y=PC2))+geom_point(aes(color=tar, shape=tar))+xlab("PC1")+ylab('PC2')+ggtitle("PCA DATA")


#install.packages("scatterplot3d")
library(scatterplot3d)
shapes = c(20, 21) #1,2 => 20, 21
shapes <- shapes[as.numeric(reduced_data$tar)]
scatterplot3d(reduced_data[,1:3], color = reduced_data[,"tar"], pch = shapes, angle=45)
#pch =모양

#데이터분리
set.seed(2021)
newdata <- rawdata1
datatotal <- sort(sample(nrow(newdata), nrow(newdata)*0.7))
train <- newdata[datatotal,]
test <- newdata[-datatotal,]

#===============================
#1.로지스틱
library(caret)
ctrl <- trainControl(method='repeatedcv',repeats=5)
logit_fit <- train(target~.,
              data=train,
              method='glm', #generalized linear model=로지스틱
              trControl = ctrl,
              metric='Accuracy') 
logit_fit            
#예측
logit_pred <- predict(logit_fit,newdata=test)
confusionMatrix(logit_pred,test$target)

#===============================
#2. boosted 로지스틱
library(caret)
ctrl <- trainControl(method='repeatedcv',repeats=5)
logit_boosted_fit <- train(target~.,
                   data=train,
                   method='LogitBoost',
                   trControl = ctrl,
                   metric='Accuracy') 
logit_boosted_fit            
#예측
logit_boosted_pred <- predict(logit_boosted_fit,newdata=test)
confusionMatrix(logit_boosted_pred,test$target)
728x90
728x90

본 실습 내용은 패스트캠퍼스 강의임을 먼저 알립니다 ~!

 

실습 내용은 대학원 입시 합격률 예측입니다. 아래는 학생들 성적과 관련된 것 데이터이며 target은 Chan of admit입니다. 연속형 데이터를 임의로 정한 기준으로 통해 0,1로 구분하여 분류하는 분류 문제로도 실습이 진행되었습니다. 

데이터 전처리 과정보다는 머신러닝에 초점을 맞추어 졌습니다. 

필기은 코드 내에 주석으로 처리되어있습니다.

#파일 로드
rawdata1 <- read.csv('university.csv', head=TRUE)
rawdata1

#데이터 형태 확인
str(rawdata1)

#결측치 확인
sum(is.na(rawdata1$GRE.Score))
sum(is.na(rawdata1$TOEFL.Score))
sum(is.na(rawdata1$University.Rating))
sum(is.na(rawdata1$SOP))
sum(is.na(rawdata1$LOR))
sum(is.na(rawdata1$Research))
sum(is.na(rawdata1$Chance.of.Admit))

#유니크값 확인: 이상치 확인, 데이터 분포 확인 
unique(rawdata1$GRE.Score)
unique(rawdata1$TOEFL.Score)
unique(rawdata1$University.Rating)
u_rating_table <- table(rawdata1$University.Rating)
u_rating_table #각 레이팅 별로 해당하는 데이터가 몇갠지 알수 있다. 3등급 학교출신들이 가장 많다.

unique(rawdata1$SOP) #0.5점 단위 점수를 계산
unique(rawdata1$LOR)
unique(rawdata1$Research) #factor로 볼것이냐 number로 볼것인가(둘다 가능하다)

#타켓값이 가장 중요 
unique(rawdata1$Chance.of.Admit)
#0과1사이에 있는지 확인
max(rawdata1$Chance.of.Admit)
min(rawdata1$Chance.of.Admit)

#보통 연속형 타켓은 값에 제한이 없지만 이 데이터에는 0~1사이라는 제한이 있다. 고로, 로지스틱 회귀를 사용해야한다. (선형회귀를 사용x)

#히스토그램
#par : 한 화면에 그래프 여러 개 그릴때 사용
#mar: 여백설정-> 아래,왼쪽,위,오른쪽 순으로
par(mfrow=c(3,2), mar=c(5.1,4.1,4.1,2.1))

hist(rawdata1$GRE.Score, main='GRE 점수 히스토그램',xlab='GER점수', col='Orange')

hist(rawdata1$TOEFL.Score, main='토플 점수 히스토그램',xlab='토플점수', col='green')

hist(rawdata1$SOP, main='자기소개서 점수 히스토그램',xlab='자기소개서점수', col='blue')

hist(rawdata1$CGPA, main='학부 점수 히스토그램',xlab='학부점수', col='darkmagenta')

hist(rawdata1$LOR, main='추천서 점수 히스토그램',xlab='추천서점수', col='yellow')

boxplot(rawdata1$Chance.of.Admit, main='대학원 합격 확률 점수 히스토그램',xlab='대학원 합격 확률', col='red')

#파이차트
par(mfrow=c(1,2), mar=c(1,1,1,1))
pie(u_rating_table, main='학부 대학 레이팅',radius=2)

#변수 산점도
plot(rawdata1)


##데이터 분리
set.seed(2021)
newdata <- rawdata1
train_ratio <- 0.7
datatotal <- sort(sample(nrow(newdata),nrow(newdata)*train_ratio))
train <- newdata[datatotal,]
test <- newdata[-datatotal,]

library(caret)
#로지스틱회귀
ctrl <- trainControl(method='repeatedcv', repeats = 5)
logistic_fit <- train(Chance.of.Admit~.,
                      data=train,
                      method='glm', #generalized linear model 
                      trControl=ctrl,
                      preProcess=c('center','scale'),
                      metric='RMSE')
logistic_fit

#예측
logistic_pred <- predict(logistic_fit,test)
logistic_pred

#테스트의 RMSE 구하는 세가지 방법
#1. postResample
postResample(pred=logistic_pred, obs= test$Chance.of.Admit)

#2. RMSE
RMSE(logistic_pred, test$Chance.of.Admit)

#3.직접계산
sqrt(mean((logistic_pred-test$Chance.of.Admit)^2))

#Rsquared 직접계산 1- 설명불가능한 변동(오차)
y_bar = mean(test$Chance.of.Admit)
1-(sum((logistic_pred-test$Chance.of.Admit)^2)/sum((test$Chance.of.Admit-y_bar)^2))

#MAE 계산하는 3가지 방법
#1. PostResample
#2. MAE
MAE(logistic_pred, test$Chance.of.Admit)

#3. 직접계산
mean(abs(logistic_pred-test$Chance.of.Admit))


#엘라스틱넷(L1패널티+L2패널티)
#대표적인 목적함수(최적화 시키고자 하는 함수)는 오차제곱 합
#목적함수를 최적화 한다는 것은 목적함수를 최소화(or 최대화) 시키는 모수를 추정
#머신러닝의 목적은 이 모수를 추정하는 것

#제약식=패널티=정규화 : 목적함수의 최적화를 돕는 역할
#최적화된 모수=목적함수+패널티

#L1마름모(라쏘): 최소화 시킬려는 베타값은 마름모 안에 있다.
#L2타원(릿지): 위와 같다
logit_panal_fit <- train(Chance.of.Admit~.,
                      data=train,
                      method='glmnet',
                      trControl=ctrl,
                      preProcess=c('center','scale'),
                      metric='RMSE')
logit_panal_fit
plot(logit_panal_fit)
#알파= 1이 된다면 Lasso 회귀
#알파가=0이면 릿지 회귀
#알파는 두 패널티의 비율을 나타낸다.
#람다: 전체 제약식의 크기를 결정
# 람다[릿지 패널티 + 릿지 패널티]

#예측
logit_penal_pred <- predict(logit_panal_fit,test)

#postResample
postResample(pred=logit_penal_pred, obs= test$Chance.of.Admit)


#랜덤포레스트
rf_fit <- train(Chance.of.Admit~.,
                         data=train,
                         method='rf',
                         trControl=ctrl,
                         preProcess=c('center','scale'),
                         metric='RMSE')
rf_fit
#mtry: 각 트리에서 랜덤하게 선택되는 분할 피쳐 후보 갯수 즉, mtry가 클수록 각 트리의 가지가 많아진다.

rf_pred <- predict(rf_fit, test)
postResample(pred=rf_pred, obs= test$Chance.of.Admit)




#선형서포트벡터머신
svm_fit <- train(Chance.of.Admit~.,
                data=train,
                method='svmLinear',
                trControl=ctrl,
                preProcess=c('center','scale'),
                metric='RMSE')
svm_fit
svm_pred_fit <- predict(svm_fit, test)
postResample(pred=svm_pred_fit, obs= test$Chance.of.Admit) 





#비선형서포트벡터머신
svm_poly_fit <- train(Chance.of.Admit~.,
                 data=train,
                 method='svmPoly',
                 trControl=ctrl,
                 preProcess=c('center','scale'),
                 metric='RMSE')
svm_poly_fit
svm_pred_fit <- predict(svm_poly_fit, test)
postResample(pred=svm_pred_fit, obs= test$Chance.of.Admit)
#scale: 내적을 스케일하는 역할

#-----------분류--------------
#파일 로드
rawdata2 <- read.csv('university.csv', head=TRUE)

#타켓변수 살펴보기
par(mfrow=c(1,2), mar=c(5.1 ,4.1 ,4.1 ,2.1))
hist(rawdata2$Chance.of.Admit, main='대학원 합격 확률 히스토그램', xlab='대학원 합격 확률',col='red')
boxplot(rawdata2$Chance.of.Admit, main='대학원 합격 확률 box-plot', col ='red')
#데이터 중심인 0.7을 기준으로 삼았다.

summary(rawdata2$Chance.of.Admit)
target_median=median(rawdata2$Chance.of.Admit)
target_median

#타켓 연속혀 -> 범주형
#rawdata2[행,열]
rawdata2[(rawdata2$Chance.of.Admit<target_median),'Chance.of.Admit']="0"
rawdata2[(rawdata2$Chance.of.Admit>=target_median),'Chance.of.Admit']="1"
rawdata2$Chance.of.Admit <- as.factor(rawdata2$Chance.of.Admit)
str(rawdata2)

unique(rawdata2$Chance.of.Admit)

#데이터분리
set.seed(2021)
newdata <- rawdata2
train_ratio <- 0.7
datatotal <- sort(sample(nrow(newdata),nrow(newdata)*train_ratio))
train <- newdata[datatotal,]
test <- newdata[-datatotal,]

customGrid <- expand.grid(k=1:20)
knn_fit2 <- train(Chance.of.Admit~.,
                  data=train,
                  method='knn',
                  trControl=ctrl,
                  preProcess=c('center','scale'),
                  tuneGrid=customGrid,
                  metric='Accuracy')
knn_fit2

#예측
knn_pred <- predict(knn_fit2, test)
confusionMatrix(knn_pred,test$Chance.of.Admit)

#=================================

#logit Boost: 간단한 모형 만들어가면서 성능개선
logit_boost_fit <- train(Chance.of.Admit~.,
                  data=train,
                  method='LogitBoost',
                  trControl=ctrl,
                  preProcess=c('center','scale'),
                  metric='Accuracy')
logit_boost_fit

#예측
logit_boost_pred <- predict(logit_boost_fit, test)
confusionMatrix(logit_boost_pred,test$Chance.of.Admit)

#=================================
#penalized 로지스틱:L2정규화
library(caret)
ctrl <- trainControl(method='repeatedcv',repeats = 5)
logit_plr_fit <- train(Chance.of.Admit~.,
                         data=train,
                         method='plr',
                         trControl=ctrl,
                         preProcess=c('center','scale'),
                         metric='Accuracy')
logit_plr_fit
#람다: 제약시의 크기를 조절하는 값
#cp(complexity parameter): 복잡성을 일컫는말, aic or bic(default)
plot(logit_plr_fit)

#예측
logit_plr_pred <- predict(logit_plr_fit, test)
confusionMatrix(logit_plr_pred,test$Chance.of.Admit)

#=================================
#나이브베이즈: 각 피처를 독립으로 가정, 조건부 확률
ctrl <- trainControl(method='repeatedcv',repeats = 5)
nb_fit <- train(Chance.of.Admit~.,
                       data=train,
                       method='naive_bayes',
                       trControl=ctrl,
                       preProcess=c('center','scale'),
                       metric='Accuracy')
nb_fit
#usekernel: 히스토그램을 이용하여 실제 분포를 추정
#adjist: 커널함수값의 bandwidth 값 조절
#laplace: 라플라스 스무딩 파라미터 값 조절. 자세한건 강의 자료참고, 데이터가 적을 경우 추정된 값의 비율이 0또는 1과 같이 극단적인 값으로 추정하는 것 즉 한쪽으로 쏠리는걸 방지
plot(nb_fit)

#예측
nb_pred <- predict(nb_fit, test)
confusionMatrix(nb_pred,test$Chance.of.Admit)


#=================================
#랜덤포레스트
ctrl <- trainControl(method='repeatedcv',repeats = 5)
rf_fit <- train(Chance.of.Admit~.,
                data=train,
                method='rf',
                trControl=ctrl,
                preProcess=c('center','scale'),
                metric='Accuracy')
rf_fit
#예측
rf_pred <- predict(rf_fit, test)
confusionMatrix(rf_pred,test$Chance.of.Admit)


#=================================
#서포트벡터
ctrl <- trainControl(method='repeatedcv',repeats = 5)
svm_fit <- train(Chance.of.Admit~.,
                data=train,
                method='svmLinear',
                trControl=ctrl,
                preProcess=c('center','scale'),
                metric='Accuracy')
svm_fit

#예측
svm_pred <- predict(svm_fit, test)
confusionMatrix(svm_pred,test$Chance.of.Admit)


#=================================
#커널 소프트벡터
ctrl <- trainControl(method='repeatedcv',repeats = 5)
svm_poly_fit <- train(Chance.of.Admit~.,
                data=train,
                method='svmPoly',
                trControl=ctrl,
                preProcess=c('center','scale'),
                metric='Accuracy')
svm_poly_fit
#예측
svm_poly_pred <- predict(svm_poly_fit, test)
confusionMatrix(svm_poly_pred,test$Chance.of.Admit)
728x90
728x90

시계열 데이터 심화 강의의 마지막 단계인 실습프로젝트들 중 주택 가격 예측실습을 포스팅하겠습니다.

본 실습은 성능보다는 어떻게 적용할지에 대한 내용만 간략하게 소개되어 있음을 알립니다.

 

 

MLP

# Data Loading
location = './Data/RealestateKorea_Gangnam/Economy.csv'
raw_all = pd.read_csv(location)
raw_all

# feature engineering
raw_all['Date'] = pd.to_Datetime(Raw_all['Date'])
raw_all.index =raw_all['Date']
raw_all = raw_all[raw_all.index >= '200-01-01']
raw_all = raw_all[raw_all.index <= '2017-12-31']
raw_all.fillna(method='bfill', inplace=True)

# Data split
Y_colname =['Price']
X_remove =['Date','price_Sido']
X_colname =[x for x in raw_all.columns if x not in Y_colname+X_remove]
X_train, X_Test, Y_train, Y_test = datasplit_ts(raw_all, Y_colname, X_colname, '2016-01-01')

# Parameters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
# sequence = 34
batch_size = 32
epoch = 20
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Scaling
X_train = scaler_X_tr.fit_transform(X_train)
Y_train = scaler_Y_tr.fit_transform(Y_train)
X_test = scaler_X_tr.transform(X_test)
Y_test = scaler_Y_tr.transform(Y_test)

# MLP
model = Sequential()
model.add(Dense(128, input_shape=(train.shape[1],), activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Desne(64, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(1))
model.complie(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit=model.fit(X_train. Y_train, batch_size=batch_size,
					epochs=epoch, verbose=verbose)
pd.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

#prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predcit(X_test)

#evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler !=[]:
	Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_test = scaler_Y_tr.inverse_transform(Y_test)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_MLP, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_MLP)

Train, Test

 

RNN

*그래프 결과만 

Train, Test

LSTM

 

GRU

Train, Test

 

 

각 딥러닝 모델에 따른 결과를 출력했습니다. 각자 비슷한 성능을 보이는 가운데 여기서 한번 생각해 봐야 할 점이 있습니다. Y값은 부동산 가격입니다. 그래프를 보면 부동산 가격이 너무 변동이 심하다는 걸 볼수 있습니다. 현실적으로

올해 1억하던 매물이 내년에 갑자기 확 뛰거나 내리는 현상은 위 시각화 처럼 자주 발생하지 않습니다

뭔가 이상하다는 걸 느껴야 합니다. 입력된 데이터에서 뭔가가 잘못되었음을 알수 있습니다.

 

데이터 원본입니다. 빌딩 타입별로 분류가 되어 있습니다. 또한 2006-01-01의 정보를보면 건물 타입과 지역마다 여러 행으로 분리 되어 있습니다. 즉, 이를 한번에 넣고 모델을 돌리게되면 심각한 정보 왜곡이 발생됩니다. 

여기서 우리가 알고 싶은점은 부동산 가격입니다. 이 데이터는 강남지역의 부동산 데이터인데, 위 처럼 여러개의 y값이 아닌 강남 부동산 가격을 대표할만한 y를 추정해야 합니다. 강의에서는 2가지를 예시로 들었습니다.

아래 코드를 통해 어떤식으로 적용했는지 보겠습니다.

실습에 적용된 모델은 GRU로 모두 동일합니다.

 

 

CASE1: year, month의 groupby한 평균값 사용

# Data Loading
location = './Data/RealestateKorea_Gangnam/Economy.csv'
raw_all = pd.read_csv(location)
date = raw_all['Date'].unique()

raw_all = raw_all.groupby(['Year','Month']).mean().rest_index().iloc[:,2:]
raw_all['Date']= date 

# Feature Engineering
raw_all['Date'] = pd.to_datetime(raw_all['Date'])
raw_all.index = raw_all['Date']
raw_all = raw_all[raw_all.index >= '2010-01-01']
raw_all = raw_all[raw_all.index <= '2017-12-31']
raw_all.fillna(method='bfill', inplace=True)

# Data Split
Y_colname = ['Price']

#지역과 빌딩 타입은 숫자의 의미가 없기때문에 삭제
X_remove = ['Date', 'Region', 'Price_Sido', 'Building_Type']
X_colname = [x for x in raw_all.columns if x not in Y_colname+X_remove]
X_train, X_test, Y_train, Y_test = datasplit_ts(raw_all, Y_colname, X_colname, '2016-01-01')

# Parameters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
sequence = 12
batch_size = 32
epoch = 20
verbose = 1
dropout_ratio = 0
# Feature Engineering
## Scaling
X_train_scaled = scaler_X_tr.fit_transform(X_train)
Y_train_scaled = scaler_Y_tr.fit_transform(Y_train)
X_test_scaled = scaler_X_tr.transform(X_test)
Y_test_scaled = scaler_Y_tr.transform(Y_test)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(X_train_scaled) - sequence):
    X_train.append(np.array(X_train_scaled[index: index + sequence]))
    Y_train.append(np.ravel(Y_train_scaled[index + sequence:index + sequence + 1]))
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = [], []
for index in range(len(X_test_scaled) - sequence):
    X_test.append(np.array(X_test_scaled[index: index + sequence]))
    Y_test.append(np.ravel(Y_test_scaled[index + sequence:index + sequence + 1]))  
X_test, Y_test = np.array(X_test), np.array(Y_test) 

## Retype and Reshape
X_train = X_train.reshape(X_train.shape[0], sequence, -1)
X_test = X_test.reshape(X_test.shape[0], sequence, -1)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# GRU
model = Sequential()
model.add(GRU(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(64, return_sequences=False, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler_Y_tr != []:
    Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test = scaler_Y_tr.inverse_transform(Y_test)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_GRU, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_GRU)

Train, Test

 

 

 

CASE2: 특정한 지역과 빌딩타입을 선택

# Data Loading
location = './Data/RealestateKorea_Gangnam/Economy.csv'
raw_all = pd.read_csv(location)
raw_all = raw_all[(raw_all['Region'] == 50000) & (raw_all['Buillding_type'] == 0)]

###이하 내용은 위 GRU 실습내용과 같습니다.

 

case1 보다 case2가 개선된 성능을 보입니다. case2같은 경우에는 처음부터 정보왜곡이 되지 않도록 특정한 범위를 선택한 것에 반해 case1은 평균값이라고 해도 다른 여러 종류의 데이터와 섞이기 때문에 성능에서 차이가 발생했습니다.

 

이 실습을 통해 강사가 알리고자 한 것은 알고리즘이 전부가 아니다. 알고리즘 만큼 중요한 것이 데이터 자체에 있다는 것이였습니다. 이번 강의를 계기로 원본 데이터를 어떻게 설계하느냐가 분석에 큰 영향을 끼칠수 있다는 걸 깨닫게 되었습니다.  이 포스팅을 끝으로 시계열 데이터 심화 강의 포스팅은 마치겠습니다. 좋은 강의를 만들어주신 강사님에게 감사드립니다~ (꾸벅)

728x90
728x90

시계열 데이터 심화 강의의 마지막 단계인 실습프로젝트들 중 자전거 수요예측 실습을 포스팅하겠습니다.

본 실습은 성능보다는 어떻게 적용할지에 대한 내용만 간략하게 소개되어 있음을 알립니다.

 

MLP

# Data Loading
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv'
raw_all = pd.read_csv(location)

#Feature Engineering
raw_fe = feature_engineering(raw_all)
#reality
target = ['coount_trend','count_seasonal','count_Day','count_Week','count_diff']
raw_feR = feature_engineering_year_duplicated(raw_fe, target)

#Data Split
#confirm of input and output
Y_colname=['count']
X_remove=['datetime','DateTime','temp_group','casual','registered']
X_colname = [x for x in raw_fe.columns if x not in Y_colname+X_remove]
X_train_feR, X_test_feR, Y_train_feR, Y_test_feR = datasplit_ts(raw_feR, Y_colname, X_colname,'2017-07-01')
#Reality
target=['count_lag1','count_lag2']
X_test_feR =feature_engineering_lag_modified(Y_test_feR, X_test_feR, target)

#Paramters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Scaling
X_train = scaler_X_tr.fit_transform(X_train_feR)
Y_train = scaler_Y_tr.fit_transform(Y_train_feR)
X_test = scaler_X_tr.transform(X_test_feR)
Y_test = scaler_Y_tr.fransform(Y_test)
'''
MLP는 시퀀스가 없기때문에 2차원 형식으로 들어가면 된다
'''

# MLP
model = Sequential()
model.add(Dense(128, input_shape=(X_train.shape[1],), activation='relu')
model.add(Dropout(dropout_ratio))
model.add(Dense(256,activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(128, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(64, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(1)
model.compile( optimizer='adam', loss='mean_squard_error')
model.summary()
model_fit=model.fit(X_train, Y_train, batch_size=batch_size, epochs = epoch,
					verbose=verbose)
plt.plot(pd.DataFrame(model_fit.history)
plt.grid(True)
plt.show()

#prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

#evaluation
result = model.evaluate(X_test, Y_Test_pred)
if scaler_T_tr !=[]:
	Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test = scaler.Y_tr.inverse_transform(Y_test)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_MLP, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_Train), Y_train_pred.flatten(),
													pd.DataFrame(Y_test), Y_test_pred.flatten(),graph_on=True)
display(Score_MLP)

 

 

RNN

# Data Loading
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv'
raw_all = pd.read_csv(location)

# Feature Engineering
raw_fe = feature_engineering(raw_all)
### Reality ###
target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
raw_feR = feature_engineering_year_duplicated(raw_fe, target)
###############

# Data Split
# Confirm of input and output
Y_colname = ['count']
X_remove = ['datetime', 'DateTime', 'temp_group', 'casual', 'registered']
X_colname = [x for x in raw_fe.columns if x not in Y_colname+X_remove]
X_train_feR, X_test_feR, Y_train_feR, Y_test_feR = datasplit_ts(raw_feR, Y_colname, X_colname, '2012-07-01')
### Reality ###
target = ['count_lag1', 'count_lag2']
X_test_feR = feature_engineering_lag_modified(Y_test_feR, X_test_feR, target)
###############

# Parameters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
sequence = 24
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Scaling
X_train_scaled = scaler_X_tr.fit_transform(X_train_feR)
Y_train_scaled = scaler_Y_tr.fit_transform(Y_train_feR)
X_test_scaled = scaler_X_tr.transform(X_test_feR)
Y_test_scaled = scaler_Y_tr.transform(Y_test_feR)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(X_train_scaled) - sequence):
    X_train.append(np.array(X_train_scaled[index: index + sequence]))
    Y_train.append(np.ravel(Y_train_scaled[index + sequence:index + sequence + 1]))
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = [], []
for index in range(len(X_test_scaled) - sequence):
    X_test.append(np.array(X_test_scaled[index: index + sequence]))
    Y_test.append(np.ravel(Y_test_scaled[index + sequence:index + sequence + 1]))  
X_test, Y_test = np.array(X_test), np.array(Y_test) 

## Retype and Reshape
X_train = X_train.reshape(X_train.shape[0], sequence, -1)
X_test = X_test.reshape(X_test.shape[0], sequence, -1)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# RNN
model = Sequential()
model.add(SimpleRNN(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(64, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(Flatten())
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler_Y_tr != []:
    Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test = scaler_Y_tr.inverse_transform(Y_test)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_RNN, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_RNN)

Train, Test

LSTM

# Data Loading
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv'
raw_all = pd.read_csv(location)

# Feature Engineering
raw_fe = feature_engineering(raw_all)
### Reality ###
target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
raw_feR = feature_engineering_year_duplicated(raw_fe, target)
###############

# Data Split
# Confirm of input and output
Y_colname = ['count']
X_remove = ['datetime', 'DateTime', 'temp_group', 'casual', 'registered']
X_colname = [x for x in raw_fe.columns if x not in Y_colname+X_remove]
X_train_feR, X_test_feR, Y_train_feR, Y_test_feR = datasplit_ts(raw_feR, Y_colname, X_colname, '2012-07-01')
### Reality ###
target = ['count_lag1', 'count_lag2']
X_test_feR = feature_engineering_lag_modified(Y_test_feR, X_test_feR, target)
###############

# Parameters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
sequence = 24
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Scaling
X_train_scaled = scaler_X_tr.fit_transform(X_train_feR)
Y_train_scaled = scaler_Y_tr.fit_transform(Y_train_feR)
X_test_scaled = scaler_X_tr.transform(X_test_feR)
Y_test_scaled = scaler_Y_tr.transform(Y_test_feR)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(X_train_scaled) - sequence):
    X_train.append(np.array(X_train_scaled[index: index + sequence]))
    Y_train.append(np.ravel(Y_train_scaled[index + sequence:index + sequence + 1]))
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = [], []
for index in range(len(X_test_scaled) - sequence):
    X_test.append(np.array(X_test_scaled[index: index + sequence]))
    Y_test.append(np.ravel(Y_test_scaled[index + sequence:index + sequence + 1]))  
X_test, Y_test = np.array(X_test), np.array(Y_test) 

## Retype and Reshape
X_train = X_train.reshape(X_train.shape[0], sequence, -1)
X_test = X_test.reshape(X_test.shape[0], sequence, -1)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# LSTM
model = Sequential()
model.add(LSTM(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(64, return_sequences=False, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler_Y_tr != []:
    Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test = scaler_Y_tr.inverse_transform(Y_test)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_LSTM, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_LSTM)

Train, Test

 

 

GRU

# Data Loading
location = './Data/BikeSharingDemand/Bike_Sharing_Demand_Full.csv'
raw_all = pd.read_csv(location)

# Feature Engineering
raw_fe = feature_engineering(raw_all)
### Reality ###
target = ['count_trend', 'count_seasonal', 'count_Day', 'count_Week', 'count_diff']
raw_feR = feature_engineering_year_duplicated(raw_fe, target)
###############

# Data Split
# Confirm of input and output
Y_colname = ['count']
X_remove = ['datetime', 'DateTime', 'temp_group', 'casual', 'registered']
X_colname = [x for x in raw_fe.columns if x not in Y_colname+X_remove]
X_train_feR, X_test_feR, Y_train_feR, Y_test_feR = datasplit_ts(raw_feR, Y_colname, X_colname, '2012-07-01')
### Reality ###
target = ['count_lag1', 'count_lag2']
X_test_feR = feature_engineering_lag_modified(Y_test_feR, X_test_feR, target)
###############

# Parameters
scaler_X_tr = preprocessing.MinMaxScaler()
scaler_Y_tr = preprocessing.MinMaxScaler()
sequence = 24
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Scaling
X_train_scaled = scaler_X_tr.fit_transform(X_train_feR)
Y_train_scaled = scaler_Y_tr.fit_transform(Y_train_feR)
X_test_scaled = scaler_X_tr.transform(X_test_feR)
Y_test_scaled = scaler_Y_tr.transform(Y_test_feR)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(X_train_scaled) - sequence):
    X_train.append(np.array(X_train_scaled[index: index + sequence]))
    Y_train.append(np.ravel(Y_train_scaled[index + sequence:index + sequence + 1]))
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = [], []
for index in range(len(X_test_scaled) - sequence):
    X_test.append(np.array(X_test_scaled[index: index + sequence]))
    Y_test.append(np.ravel(Y_test_scaled[index + sequence:index + sequence + 1]))  
X_test, Y_test = np.array(X_test), np.array(Y_test) 

## Retype and Reshape
X_train = X_train.reshape(X_train.shape[0], sequence, -1)
X_test = X_test.reshape(X_test.shape[0], sequence, -1)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# GRU
model = Sequential()
model.add(GRU(128, input_shape =(X_train.shape[1], X_train.shape[2]), activation='relu',return_sequences=True))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(256, return_sequneces=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(128, return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(64, return_sequences=False, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(Dense(1, activation='relu')
model.complie( optimizer ='adam', loss='mean_squared_error'))
model.summary()
model_fit = model.fit(X_train, Y_train,batch_size= batch_sizem
					 epochs=epoch, verbose=verbose)
plt.plot(pd.DataFrame(model_fit.history)
plt.grid(True)
plt.show()

#prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

#evaluation
result = model.evaluation(X_test, Y_test_pred)
if scaler_Y_tr != []:
    Y_train = scaler_Y_tr.inverse_transform(Y_train)
    Y_train_pred = scaler_Y_tr.inverse_transform(Y_train_pred)
    Y_test = scaler_Y_tr.inverse_transform(Y_test)
    Y_test_pred = scaler_Y_tr.inverse_transform(Y_test_pred)
Score_GRU, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_GRU)

Train, Test

728x90

'실습 note' 카테고리의 다른 글

2021-07-01(R_대학원 입시 합격률 실습)  (0) 2021.07.02
주택 가격 예측실습  (0) 2021.04.16
bitcoin 예측 실습  (0) 2021.04.14
제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_12(딥러닝2)  (0) 2021.03.05
728x90

시계열 데이터 심화 강의의 마지막 단계인 실습프로젝트들 중 bitcoin을 포스팅하겠습니다.

 

 

MLP

from keras.models import Sequential, Model, load_model
from keras.layers import Input, Dense, Activation, Flatten, Dropout
from keras.layers import SimpleRNN, LSTM, GRU

###MLP
#Data Loading
location= './Data/Cry/Bitcoint.csv')
raw_all= pd.read_csv(location, index_col='Date')

#Parameters
criteria ='2020-01-01'
scaler= predprocessing.minMaxScaler()
sequence=60 
batch_size=32
epoch=10
verbose=1
dropout_ratio=0

# Feature Engineering
# train & test split
train = raw_all.loc[raw_all.index < criteria,:]
test = raw_all.loc[raw_all.inex >= criteria,:]
print('Train_size:', train.shape, 'Test_size:', test.shape)

## Scaling
train_scaled = scaler.fit_transform(train)
test_scaled = scaler.transform(test)

#X/Y split 
X_train, Y_train =[], []
for index in range(len(train_scaled)-sequence):
	X_train.append(train_scaled[index: index+sequence])
    Y_train.append(train_scaled[index + sequence])

X_test, Y_test =[], []
for index in range(len(test_scaled)-sequence):
	X_test.append(test_scaled[index: index + sequence])
    Y_test.append(test_scaled[index+sequence])
    
## Retype and Reshape
X_train, Y_train = np.array(X_train), np.array(Y_train) #리스트로 묶여 있는 걸 어레이로 변경
X_test, Y_test = np.array(X_test), np.array(Y_test)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

X_train=X_train.reshape(X_train.shape[0], X_train.shpae[1])
X_test =X_test.reshape(X_test.shape[0], X_test.shape[1])
print('Reshaping for MLP')

#X_train, test shape is (row, sequence, feature)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

model = Sequential()
model.add(Dense(128, input_shape=(X_train.shape[1],), activation='relu')) 
'''
input은 row를 빼고 다 넣으면된다. 왜? 미니배치(32)가 돌아가면서 끝까지 할테니까
핵심은 안에서 돌아가는 데이터가 무엇이냐가 중요하다
60개 feature가 히든레이어의 input 수
'''
#3차원으로 입력할 경우 (60,1)
# model.add(Dense(128, input_shape=(X_train.shape[1],X_train.shape[2]), activation='relu'))
'''
첫번째 outputshape는 (60,1) -> (none,60,128)로 바뀜
60개 feature가 128개 패턴으로 바뀐게 아니라 1 컬럼이 128개로 증식된것.
사실 이렇게 해도 무방하다 하지만 문제는 최종적으로 나오는 shape이다.
최종 shape는 (1035*60,1)가 나온다. Y_train 의 (1035,1)과 맞지가 않아서 
evaluate를 할수 없다
'''
model.add(Dropout(dropout_ratio)) #128*0.2(dropout) 수 만큼 '지우는것'
model.add(Dense(256, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(128, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(64, activation='relu'))
model.add(Dropout(dropout_ratio))
model.add(Dense(1))

model.complie(doptimaizer='adam', loss='mean_squared_error')
model.summary()

model_fit() =mmodel.fit(X_train, Y_train, batch_size=batch_size, epochs=epoch,verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history())
plt.grid(True)
plt.show()

#prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(x_test)

#evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler !=[]:
	Y_train =scaler.inverse_transform(Y_train)
    Y_train_pred = scaler.inverse_transform(Y_train_pred)
    Y_test - scaler.inverse_tainsform(Y_test)
    Y_test_pred - scaler.inverse_transform(y_test_pred)
Score_MLP, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(),
													  pd.DataFrame(Y_test), Y_test_pred.flatten(),
                                                      graph_on=True)
display(Score_MLP)                      

 

위 예시에서는 input_shape= (X_train.shape[1],) 였는데 이렇게 실행하기 위해서는 사전에 3차원을 2차원으로 축소해야 한다. 

그러면 3차원을 그대로 사용할려면 어떻게 해야 할까?

input_shape= (X_train.shape[1],X_train.shape[2]) 로 변경 가능하다. 즉 (60,1)로 넣을 수가 있다.

하지만 이렇게 진행할 경우 최종 shape가 Y_train shape와 맞지 않아서 Y값끼리 비교가 불가능하다. evaluation을 진행하지 못한다

 

 input_shape= (X_train.shape[1],) 왼쪽처럼 넣게 되면 feature의 수가 60개이다. 이 값이 히든레이어의 수만큼 변형이 되면서 특징을 뽑을 수가 있는데 

 input_shape= (X_train.shape[1],X_train.shape[2])로 넣게 되면 (60,1)로 입력이 되고 Dense(128)를 만나게 되면 feature를 60개로 인식을 안 하고 1로 인식한다. 즉 1->128로 늘어난다. 이 방법이 틀린 게 아니다. 아래 이미지로 추가 설명을 한다면 

dense_49 => (none, 60, 64)이다. 이를 Dense(1) 통과시키면 (none,60,1)이 된다. 대체 어떻게 변한 걸까?

행이 None으로 지정되는 이유는 데이터의 갯수는 계속해서 추가될 수 있기 때문에 딥러닝 모델에서는 주로 행을 무시하는데 이해를 돋기위해서 여기서의 none를 1035라고 하겠습니다(1035는 전체데이터)

None은 총 row인 1035이다. 즉 60*1 이 1035개가 있다는 뜻이 된다. 즉 각 row마다 1035개가 있다.

결국 (60*1035,1)이라는 소리인데 이 모양은 Y_train (1035,1)와 비교는 할 수 없음을 딱 봐도 알 수 있다. 

따라서 문제 해결을 위해서는 60*1035를 1035로 만들어야 한다. 아래 그림을 보면서 설명해본다

dense_49의 형태를 직접 그려 봤다. (60,64) 매트릭스가 1035개가 있는 형태이다. (위 그림의 1034 오타 -> 1035 ), 60*64사이즈의 A4용지가 1035장 쌓여 있는 것이다. 60*64=3840이다. 이 둘을 곱해서 가로로 나열하여 1035를 쌓아버린다. 이때 사용되는 것이 flatten()이다. 최종적으로 세로가 1035*3840의 매트릭스가 되고 이를 Dense(1)에 넣게 되면 3840+1(bias)가 1로 변한다

아래 Param을 보면 3841로 출력되어 있다. (3841 * 1 = 3841)

최종적으로 y_train과 비교가 가능한 (1035,1) 형태가 되었다.

 

flatten 한 후 summary

 

 

 RNN

# Data Loading
location = './Data/Cryptocurrency/Bitcoin.csv'
raw_all = pd.read_csv(location, index_col='Date')
raw_all.index = pd.to_datetime(raw_all.index)

# Parameters
criteria = '2020-01-01'
scaler = preprocessing.MinMaxScaler()
sequence = 60
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Train & Test Split
train = raw_all.loc[raw_all.index < criteria,:]
test = raw_all.loc[raw_all.index >= criteria,:]
print('Train_size:', train.shape, 'Test_size:', test.shape)

## Scaling
train_scaled = scaler.fit_transform(train)
test_scaled = scaler.transform(test)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(train_scaled) - sequence):
    X_train.append(train_scaled[index: index + sequence])
    Y_train.append(train_scaled[index + sequence])
X_test, Y_test = [], []
for index in range(len(test_scaled) - sequence):
    X_test.append(test_scaled[index: index + sequence])
    Y_test.append(test_scaled[index + sequence])

## Retype and Reshape
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = np.array(X_test), np.array(Y_test)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# RNN
model = Sequential()
#return_sequences: 출력된 아웃풋을 그대로 받아 올건지(이전 히든스테이트가 학습에 사용되도록) 
#X_train.shape[1]: 시간 정보 와 X_train.shape[2]: 컬럼을 입력으로 사용
model.add(SimpleRNN(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(SimpleRNN(64, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(Flatten())
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
'''
컬럼이 1 -> 128개로 증식 x
60개 시퀀스를 128개 시퀀스 패턴으로 바뀐다.
즉, 60*1 이라는 패턴을 60*128개로 바꾸는 느낌으로 해석하는게 맞다
시퀀스 자체를 늘린다. 
'''
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler != []:
    Y_train = scaler.inverse_transform(Y_train)
    Y_train_pred = scaler.inverse_transform(Y_train_pred)
    Y_test = scaler.inverse_transform(Y_test)
    Y_test_pred = scaler.inverse_transform(Y_test_pred)
Score_RNN, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_RNN)

# error analysis
# error_analysis(Residual_te, ['Error'], pd.DataFrame(X_train.reshape(X_train.shape[0], X_train.shape[1])), graph_on=True)

Train, Test

 

LSTM

# Data Loading
location = './Data/Cryptocurrency/Bitcoin.csv'
raw_all = pd.read_csv(location, index_col='Date')
raw_all.index = pd.to_datetime(raw_all.index)

# Parameters
criteria = '2020-01-01'
scaler = preprocessing.MinMaxScaler()
sequence = 60
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Train & Test Split
train = raw_all.loc[raw_all.index < criteria,:]
test = raw_all.loc[raw_all.index >= criteria,:]
print('Train_size:', train.shape, 'Test_size:', test.shape)

## Scaling
train_scaled = scaler.fit_transform(train)
test_scaled = scaler.transform(test)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(train_scaled) - sequence):
    X_train.append(train_scaled[index: index + sequence])
    Y_train.append(train_scaled[index + sequence])
X_test, Y_test = [], []
for index in range(len(test_scaled) - sequence):
    X_test.append(test_scaled[index: index + sequence])
    Y_test.append(test_scaled[index + sequence])

## Retype and Reshape
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = np.array(X_test), np.array(Y_test)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# LSTM
model = Sequential()
model.add(LSTM(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(LSTM(64, return_sequences=False, activation="relu"))
'''
마지막 부분에서 return을 False로 놓으면 시퀀스 입력이 중지가 되고
3차원이 시간정보가 사라지면서 2차원으로 줄어든다 즉, flatten기능을 대신 할수있다.
'''
model.add(Dropout(dropout_ratio)) 
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler != []:
    Y_train = scaler.inverse_transform(Y_train)
    Y_train_pred = scaler.inverse_transform(Y_train_pred)
    Y_test = scaler.inverse_transform(Y_test)
    Y_test_pred = scaler.inverse_transform(Y_test_pred)
Score_LSTM, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_LSTM)

# error analysis
# error_analysis(Residual_te, ['Error'], pd.DataFrame(X_train.reshape(X_train.shape[0], X_train.shape[1])), graph_on=True)

 

 

 

 GRU

# Data Loading
location = './Data/Cryptocurrency/Bitcoin.csv'
raw_all = pd.read_csv(location, index_col='Date')
raw_all.index = pd.to_datetime(raw_all.index)

# Parameters
criteria = '2020-01-01'
scaler = preprocessing.MinMaxScaler()
sequence = 60
batch_size = 32
epoch = 10
verbose = 1
dropout_ratio = 0

# Feature Engineering
## Train & Test Split
train = raw_all.loc[raw_all.index < criteria,:]
test = raw_all.loc[raw_all.index >= criteria,:]
print('Train_size:', train.shape, 'Test_size:', test.shape)

## Scaling
train_scaled = scaler.fit_transform(train)
test_scaled = scaler.transform(test)

## X / Y Split
X_train, Y_train = [], []
for index in range(len(train_scaled) - sequence):
    X_train.append(train_scaled[index: index + sequence])
    Y_train.append(train_scaled[index + sequence])
X_test, Y_test = [], []
for index in range(len(test_scaled) - sequence):
    X_test.append(test_scaled[index: index + sequence])
    Y_test.append(test_scaled[index + sequence])

## Retype and Reshape
X_train, Y_train = np.array(X_train), np.array(Y_train)
X_test, Y_test = np.array(X_test), np.array(Y_test)
print('X_train:', X_train.shape, 'Y_train:', Y_train.shape)
print('X_test:', X_test.shape, 'Y_test:', Y_test.shape)

# GRU
model = Sequential()
model.add(GRU(128, input_shape=(X_train.shape[1], X_train.shape[2]), return_sequences=True, activation='relu'))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(256, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(128, return_sequences=True, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(GRU(64, return_sequences=False, activation="relu"))
model.add(Dropout(dropout_ratio)) 
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model_fit = model.fit(X_train, Y_train, 
                      batch_size=batch_size, epochs=epoch,
                      verbose=verbose)

plt.plot(pd.DataFrame(model_fit.history))
plt.grid(True)
plt.show()

# prediction
Y_train_pred = model.predict(X_train)
Y_test_pred = model.predict(X_test)

# evaluation
result = model.evaluate(X_test, Y_test_pred)
if scaler != []:
    Y_train = scaler.inverse_transform(Y_train)
    Y_train_pred = scaler.inverse_transform(Y_train_pred)
    Y_test = scaler.inverse_transform(Y_test)
    Y_test_pred = scaler.inverse_transform(Y_test_pred)
Score_GRU, Residual_tr, Residual_te = evaluation_trte(pd.DataFrame(Y_train), Y_train_pred.flatten(), 
                                                      pd.DataFrame(Y_test), Y_test_pred.flatten(), graph_on=True)
display(Score_GRU)

# error analysis
error_analysis(Residual_te, ['Error'], pd.DataFrame(X_train.reshape(X_train.shape[0], X_train.shape[1])), graph_on=True)

Train, Test

728x90

'실습 note' 카테고리의 다른 글

주택 가격 예측실습  (0) 2021.04.16
자전거 수요예측 실습  (0) 2021.04.16
제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_12(딥러닝2)  (0) 2021.03.05
OpenCV_11(딥러닝)  (0) 2021.03.04
728x90

2021.03.10 - [기록 note] - 2021-03-10(제조공정불량실습)

아래 내용은 머신러닝 강의 교육 중 실습한 내용의 일부분입니다

좋은 참고가 되었으면 합니다

 

개요

의류직물 생산 시 찍힘, 스크래치, 뜯어짐 같은 불량을 인공지능을 통해 구분하는 프로그램을 만드는 내용입니다. 

 

*사용된 모델: inception

*데이터 출처: AITEX FABRIC IMAGE DATABASE

 

불량(왼쪽) 이미지와  정상(오른쪽) 이미지

원본 데이터를 보면 몇몇 의류직물의 패턴이 다른 걸로 보아서 여러 모델의 의류직물이 섞여 있는 것 같습니다

또한 불량 이미지 중에는 사람이 봐도 구분이 가지 않는 불량품이 있음을 확인했습니다.

이제 이 데이터를 가지고 딥러닝을 통해 불량 검출을 해보겠습니다

 

 Import

import glob
import os
from datetime import datetime
import time
import tensorflow as tf
import tensorflow_addons as tfa
import matplotlib.pyplot as plt
import cv2
from tensorflow.keras.layers import Conv2D, MaxPool2D, Concatenate, Flatten, Dense

 

작업 경로 및 파라미터 설정

DATASET_OK_PATTERN = 'dataset/3/OK/*.png'
DATASET_FAIL_PATTERN = 'dataset/3/FAIL/*.png'

TFRECORD_PATH = 'tfrecords/'
IMAGE_PER_TFRECORD = 100 #100개이미지를 하나의 TFRECORD로 묶음

 

  • 이미지를 TFRecord로 변환 시 저장할 위치를 지정합니다
  • 100개 이미지를 하나의 TFRecord로 생성합니다

 

데이터 전처리

ok_list = glob.glob(DATASET_OK_PATTERN)
fail_list = glob.glob(DATASET_FAIL_PATTERN)

#오버샘플링을 위해 데이터 수를 저장 해준다.
num_ok = len(ok_list)
num_fail = len(fail_list)

#fail데이터를 여러번 반복해서 ok데이터 사이즈와 맞춘다
fail_list_new= list()
for _ in range(num_ok//num_fail):
    fail_list_new += fail_list
    
#나머지 부분을 채워주기 위해서 따로 작업해준다
fail_list_new += fail_list[: num_ok % num_fail]
fail_list =fail_list_new

#레이블 생성
ok_label = [0]* len(ok_list)
fail_label = [1]* len(fail_list)

#파일과 레이블을 각각 묶어주기
file_list = ok_list +fail_list
label_list = ok_label +fail_label
  • 불량 데이터가 적으므로 오버샘플링을 사용해서 정상 데이터만큼 늘려줍니다
  • num_ok//num_fail를 통해 차이가 나는 것만큼 채워주고, 나머지는 num_ok%num_fail로 해결해 줍니다
  • 정상은 0번 클래스, 불량은 1번 클래스로 레이블 생성합니다
  • 이미지 파일은 파일대로, 레이블은 레이블대로 묶습니다(TFRecord 만들기 위해서 따로 구분)

 

TFRecord 생성

1. TFRecord 함수

# 함수출처: https://www.tensorflow.org/tutorials/load_data/tfrecord

def _bytes_feature(value):
    """Returns a bytes_list from a string / byte."""
    if isinstance(value, type(tf.constant(0))):
        value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _int64_feature(value):
    """Returns an int64_list from a bool / enum / int / uint."""
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def image_example(image_string, label): 
    image_shape = tf.image.decode_image(image_string).shape

    feature = {
        'height': _int64_feature(image_shape[0]),
        'width': _int64_feature(image_shape[1]),
        'depth': _int64_feature(image_shape[2]),
        'label': _int64_feature(label),
        'image_raw': _bytes_feature(image_string),
    }

    return tf.train.Example(features=tf.train.Features(feature=feature))

 

 

2. TFRecord 저장

#데이터를 원하는 크기 만큼슬라이싱 해서 저장
#tfrecord 저장 폴더
if os.path.exists(TFRECORD_PATH) is False:
    os.mkdir(TFRECORD_PATH)
    
# +1: 딱 나누 떨어지지 않고 나머지가 존재하기 때문
num_tfrecords = len(file_list) // IMAGE_PER_TFRECORD #TFRecord 갯수
if len(file_list) // IMAGE_PER_TFRECORD !=0:
    num_tfrecords+=1
    
for idx in range(num_tfrecords):
    idx0= idx*IMAGE_PER_TFRECORD
    idx1=  idx0+IMAGE_PER_TFRECORD #끝나는점
    record_file =TFRECORD_PATH+'%05d.tfrecords'% idx
    with tf.io.TFRecordWriter(record_file) as writer:
        for filename, label in zip(file_list[idx0:idx1], #0~99,100~99 100개씩
                                  label_list[idx0:idx1]):
            image_string = open(filename, 'rb').read() #rb 바이너리로 읽기
            tf_example = image_example(image_string, label) #파일과 레이블 , 바이너리로 저징
            writer.write(tf_example.SerializeToString()) #저장
  • num_tfrecord: tfrecord파일의 개수를 계산합니다
  • 나머지 부분은 if문으로 따로 처리합니다
  • idx와 IMAGE_PER_TFRRCORD를 사용해서 100개씩 이미지와 레이블을 저장합니다
  • 위에서 정의한 image_example 함수를 통해 이미지와 레이블의 저장 타입을 설정할 수 있습니다

 

  • 각 파일에는 100개 이미지와 100개 레이블 정보가 이진 형태로 함께 저장되어 있습니다
  • 이 tfrecord 데이터로 모델 학습을 진행합니다

하이퍼라마미터 설정

EPOCHS = 1000
RESULT_SAVE_PATH = 'results/'

 

모델 정의

def Model():
    #padding=same을 해줘야 다른 필터들을 적용한 것과 Concatenate가 가능하다
    def inception(filters):
        def subnetwork(x):
            h1 = Conv2D(filters, (1,1), padding='same',activation='relu')(x)
            h1 = MaxPool2D()(h1)
            
            h2 = Conv2D(filters//2, (1,1), padding='same',activation='relu')(x)
            h2 = Conv2D(filters, (3,3), padding='same',activation='relu')(h2)
            h2 = MaxPool2D()(h2)
            
            h3 = Conv2D(filters//2, (1,1), padding='same',activation='relu')(x)
            h3 = Conv2D(filters, (5,5), padding='same',activation='relu')(h3)
            h3 = MaxPool2D()(h3)
            
            return Concatenate()([h1,h2,h3])
        return subnetwork
    #입력 x 설정
    x= tf.keras.Input(shape=(256,256,3)) #입력층을 아는 경우에는 지정하는게 연산과정에서 이득
    h= inception(16)(x)
    h= inception(32)(h)
    h= inception(32)(h)
    h= inception(32)(h)
    h= inception(32)(h)
    h=Flatten()(h)
    h=Dense(1024, activation='relu')(h)
    
    #출력
    y=Dense(1, activation='sigmoid')(h)
    return tf.keras.Model(inputs=x, outputs=y)    

 

이미지 데이터 타입 변환을 위한 함수 정의

def preprocess(img):
    return tf.image.convert_image_dtype(img, tf.float32)

 

데이터 Augmentation 함수 정의

def augmentation(img, label):
    def flip(x):
        x= tf.image.random_flip_left_right(x)
        x= tf.image.random_flip_up_down(x)
        return x
    def rotate(x):
        x = tf.cond(tf.random.uniform(shape=[], minval=0.0, maxval=1.0,dtype=tf.float32)>0.5,
                   lambda: tfa.image.rotate(x, tf.random.uniform(shape=[], minval=0.0, maxval=360.0, dtype=tf.float32),
                                                                interpolation='BILINEAR'),
                   lambda: x)
        return x
                    
    def translation(x):
        dx= tf.random.uniform(shape=[], minval=-10.0, maxval=10.0,dtype=tf.float32)
        dy= tf.random.uniform(shape=[], minval=-10.0, maxval=10.0,dtype=tf.float32)
        x = tf.cond(tf.random.uniform(shape=[], minval=0.0, maxval=1.0, dtype=tf.float32) >0.5,
                   lambda: tfa.image.transform(x, [0,0,dx, 0,0,dy, 0,0], #끝에 두 0은 스케일팩터
                                              interpolation='BILINEAR'),
                   lambda: x)
        return x
    img = flip(img)
    img = rotate(img)
    img = translation(img)    
            
    return img, label
  • [0,0, dx, 0,0, dy]에서 0,0은 각각 x, y좌표인 것 같습니다 x, y의 변화량은 0이고 위치만 dx, dy만큼 변경한다는 내용(추측입니다)

1번 참고 이미지
2번 참고 이미지
3번 참고 이미지
affine 참고 이미지

TFRecords 불러오기

tffiles = glob.glob('tfrecords/*')
raw_image_dataset = tf.data.TFRecordDataset(tffiles)

image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'label': tf.io.FixedLenFeature([], tf.int64),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
}

def _parse_image_function(example_proto):
    return tf.io.parse_single_example(example_proto, image_feature_description)

def _parse_image_label(parsed_dataset):
    return preprocess(tf.image.decode_png(parsed_dataset['image_raw'])), parsed_dataset['label']

parsed_image_dataset = raw_image_dataset.map(_parse_image_function) #각 파일을 image_feature_description를 적용
dataset = parsed_image_dataset.map(_parse_image_label) #레이블은 그대로 출력하고, 이미지는 float32로 타입 변환 후 출력
  • 이미지와 레이블 데이터를 불러올 때 이미지 데이터만 preprocess를 통해 float32로 변환해준다

데이터셋 나누기

ds_size=0
for _ in dataset:
    ds_size+=1
train_size = int(ds_size*0.7)

ds = dataset.shuffle(ds_size)

#배치다음에 map함수가 들어가야 addons함수가 작동이 됨(데이터 증식과 관련됨)
ds_train =ds.take(train_size).shuffle(1024, reshuffle_each_iteration=True).prefetch(1024).batch(32) #.map(augmentation)
ds_valid =ds.skip(train_size).prefetch(1024).batch(32)

 

 

모델 생성

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

 

모델 학습

earlystopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=30, verbose=1)
history = model.fit(ds_train,
                    validation_data=ds_valid,
                    epochs=EPOCHS,
                    callbacks=[earlystopping])

 

학습 결과 Plot

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

plt.figure()
plt.plot(loss, 'ro-')
plt.plot(val_loss, 'bo-')
plt.ylabel('Cross Entropy')
plt.xlabel('Epoch')
plt.title('Training and Validation Loss')
plt.show()

  • 180 epoch에서 큰 폭의 감소가 이뤄졌으며 과적합 현상 없이 잘 학습이 되었습니다

모델 저장

model.save('model/inception_model.h5')
  • 저장된 모델을 사용해서 배치형 동작 프로그램을 생성합니다

*배치형 동작 프로그램 생성하기

배치형 프로그램은 대량의 데이터를 일괄적으로 특정 시간에 처리하는 것을 의미합니다

이번 실습 내용에서는 특정 시간이 되면 자동으로 동작하도록 하는 내용은 없음을 미리 알려드립니다

 

하이퍼 파라미터/ Path 설정

THRES_LEVEL = 0.5

INPUT_PATH = 'data/input_data/'
CSV_PATH = 'data/output_csv/'
  • 0과 1 클래스를 판별하는 기준은 보통 0.5로 사용합니다. 
  • 0.5 이하면 0번 클래스(양품), 크다면 1번 클래스(부적합품)로 구분합니다
  • 이 실습의 고객 요구 사항중 하나는 불량품을 정상품으로 오분류를 절대 허용하지 않아야 한다는 점입니다
  • 즉, 조금이라도 의심이 되면 불량으로 처리해달라는 의미 이므로 THRES_LEVEL를 내리는 방법도 생각해 볼 수 있습니다

 

모델 불러오기

model = tf.keras.models.load_models('model/inception_model.h5')
  • 학습한 모델을 불러와서 새로운 이미지 데이터를 예측할

입력 데이터 전처리를 위한 함수 정의

def preprocess(file_name):
    img = tf.io.read_file(file_name)
    img = tf.image.decode_image(img)
    return tf.image.convert_image_dtype(img, dtype.float32)
  • 불러들인 이미지의 타입을 float32로 변경하는 함수를 정의합니다
  • 이때 이미지는 png가 아니므로 decode_image를 사용합니다

입력 데이터 불러오기

file_list =glob.glob(INPUT_PATH+'*.png') # 파일이름
dataset = tf.data.Dataset.list_files(file_list).map(preprocess) #이미지

 

알고리즘 구동 및 CSV 결과 저장

now = datetime.now().strftime('%Y%m%d%_%H%M%S')
with open(CSV_PATH+now+'.csv','w') as f: #파일을 열고 작업
    for image, filename in zip(dataset, file_list):
        image= image[tf.newaxis,...] # HWC -> batch,HWC
        
        a= time.time()
        predict = model.predict(image)[0][0]
        print('Inference Time:', time.time()-a)
        
        if predict > THRES_LEVEL:
            label = 'FAIL'
        else:
            label ='OK'
        f.write(','.join([filename, label, str(predict)]))
  • 해당 모델을 학습 시 배치가 있었으므로 축을 하나 더 생성하여 형식을 맞춰줍니다 [tf.newaxis,...]
  • 만일 축을 뒤쪽에 생성한다면 [..., tf.newaxis]

  • C 셀을 보면 예측값이 1과 가까운 값이므로 1번 클래스인 FAIL로 되어 있지만
  • A셀에 정답 레이블을 보면 OK인 경우가 다수 존재했음을 알 수가 있습니다

2021.03.09 - [기록 note] - 2021-03-09(제조공정불량검출)

2021.03.10 - [기록 note] - 2021-03-10(제조공정불량실습)

728x90

'실습 note' 카테고리의 다른 글

자전거 수요예측 실습  (0) 2021.04.16
bitcoin 예측 실습  (0) 2021.04.14
OpenCV_12(딥러닝2)  (0) 2021.03.05
OpenCV_11(딥러닝)  (0) 2021.03.04
OpenCV_10(머신러닝)  (0) 2021.03.03
728x90

SSD 얼굴 검출

import sys
import numpy as np
import cv2


model = 'opencv_face_detector/res10_300x300_ssd_iter_140000_fp16.caffemodel'
config = 'opencv_face_detector/deploy.prototxt'
# model = 'opencv_face_detector/opencv_face_detector_uint8.pb'
# config = 'opencv_face_detector/opencv_face_detector.pbtxt'

# cap = cv2.VideoCapture('utub.mp4')
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print('Camera open failed!')
    sys.exit()

net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

while True:
    ret, frame = cap.read()

    if not ret:
        break
    
    #1: 픽셀 0~255
    #resize 크기(300,300)
    #BGR 평균 (104,177,123) 
    blob = cv2.dnn.blobFromImage(frame, 1, (300, 300), (104, 177, 123))
    net.setInput(blob)
    out = net.forward() #(1,1,200,7) 에서 (200,7)만 필요함  *꼭 200이 아닐수 있음
    
    detect = out[0, 0, :, :] #detect 이차원 행렬을 분석한다.
    (h, w) = frame.shape[:2]

    for i in range(detect.shape[0]): #전체 행만큼 순회
        confidence = detect[i, 2] #confidence: 얼굴일 확률
        if confidence < 0.5:
            break
        # print('detect[i, 3]',detect[i, 3])
        #좌표가0~1로 정규화 되어 있으므로 크기를 직접 곱해서 좌표를 구한다    
        #x1,y1:좌측상단       
        x1 = int(detect[i, 3] * w)
        y1 = int(detect[i, 4] * h)
        
        # x2,y2: 우측하단
        x2 = int(detect[i, 5] * w)
        y2 = int(detect[i, 6] * h)

        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0))

        label = f'Face: {confidence:4.2f}'
        # (x1, y1-1): text 위치 지정
        cv2.putText(frame, label, (x1, y1-1), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 1, cv2.LINE_AA)

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) == 27:
        break

cv2.destroyAllWindows()

 

yolo_v3 객체 검출

import sys
import numpy as np
import cv2


# 모델 & 설정 파일
model = 'yolo_v3/yolov3.weights'
config = 'yolo_v3/yolov3.cfg'
class_labels = 'yolo_v3/coco.names'
confThreshold = 0.5
nmsThreshold = 0.4

# 테스트 이미지 파일
img_files = ['person.jpg', 'sheep.jpg', 'kite.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

# 클래스 이름 불러오기

classes = [] #총 80개가 들어옴
with open(class_labels, 'rt') as f:
    classes = f.read().rstrip('\n').split('\n')

#low=0, high=255, size=(80,3)
#3은 RGB
colors = np.random.uniform(0, 255, size=(len(classes), 3)) #80개 각각 다른 색깔

# 출력 레이어 이름 받아오기
# 출력을 하는 3개의 layer 이름을 뽑는다
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# output_layers = ['yolo_82', 'yolo_94', 'yolo_106'] 
'''
* 첫번째 82번 layer: 13*13영상 *3(RGB)=507에다가
컬럼은 총 85개 인데 순서대로 x,y,w,h,confidences,80개 클래스(해당 클래스일 확률이 들어감)
종합해서 507*8,
* 두번째 94번 layer: 2028,85
* 세번재 106번 layer: 8112,85
'''

# 실행

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론
    blob = cv2.dnn.blobFromImage(img, 1/255., (416, 416), swapRB=True)
    net.setInput(blob)

    
    #forward(문자열 리스트):문자열에 해당하는 레이어의 out을 outs에 전달
    outs = net.forward(output_layers)

    # outs는 3개의 ndarray 리스트.
    # 아래 값은 입력이 416일때
    # outs[0].shape=(507, 85), 13*13*3=507
    # outs[1].shape=(2028, 85), 26*26*3=2028
    # outs[2].shape=(8112, 85), 52*52*3=8112

    h, w = img.shape[:2]

    class_ids = []
    confidences = []
    boxes = []

    for out in outs:
        #하나의 행 씩 85개중 앞에 4개는 바운딩박스의 좌표값
        # 그 다음은 objectness Score, 나머지 80개는 Class Scores(80개 클래스에 대한 각각의 확률값)
        for detection in out:
            # detection: 4(bounding box) + 1(objectness_score) + 80(class confidence)
            scores = detection[5:] #80개 클래스 확률값 
            class_id = np.argmax(scores) #80개 클래스 중에서 가장 최대값을 가지는 확률값의 인덱스
            confidence = scores[class_id]
    
            if confidence > confThreshold: #클래스에 대한 확률값이 confThreshold 이상인 경우에만바운딩박스를 취합한다
                # 바운딩 박스 중심 좌표 & 박스 크기
                
                #cx,cy: 바운딩박스 센터좌표
                cx = int(detection[0] * w)
                cy = int(detection[1] * h)
                bw = int(detection[2] * w)
                bh = int(detection[3] * h)

                # 바운딩 박스 좌상단 좌표
                sx = int(cx - bw / 2)
                sy = int(cy - bh / 2)

                #boxes안에 객체 검출할때 쓰인 모든 박스 정보가 들어있다
                #이중에서 대표 박스 하나를 골라야 하므로 NMSBoxes를 사용해야한다
                boxes.append([sx, sy, bw, bh]) 
                confidences.append(float(confidence))
                class_ids.append(int(class_id)) #인식한 객체가 인덱스로 정리되어 있음

    # 비최대 억제
    '''
    한 객체에 여러 바운딩 박스가 있으므로 이 여러 박스 중 가장 좋은 박스를 뽑아내기
    예를들어 두 박스가 있는데 이 겹쳐진 부분이 nmsThreshold%만큼 겹쳐진 것들중
    confidence 값이 confThreshold이상인 것들중에 가장 큰 confidence를 갖는 하나만 골라서 
    indices에 넣기(몇번째 박스인지에 대한 정보)
    '''
    #정리:40% 이상 겹치는 바운딩 박스에 대해 최대 confidence (>0.5)바운딩 박스만 선별
    #nmsThreshold값이 0.99라면 99%이상의 공간을 같이 공유하는 박스들이 겹치게 될것
    # indices.shape=(N, 1)
    indices = cv2.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)

    for i in indices: #각 객체당 선별된 박스가 for loop를 통해 정보 추출
        # print(i)
        i = i[0]
        print
        sx, sy, bw, bh = boxes[i]
        label = f'{classes[class_ids[i]]}: {confidences[i]:.2}'
        color = colors[class_ids[i]]
        cv2.rectangle(img, (sx, sy, bw, bh), color, 2)
        cv2.putText(img, label, (sx, sy - 10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2, cv2.LINE_AA)

    #getPerfProfile: 실행시간 계산에 관련된 함수  
    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

Mask_rcnn

import sys
import numpy as np
import cv2


def drawBox(img, classId, conf, left, top, right, bottom):
    # Draw a bounding box.
    cv2.rectangle(img, (left, top), (right, bottom), colors[classId], 2)

    label = f'{classes[classId]}: {conf:.2f}'

    labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 1)
    top = max(top, labelSize[1])
    cv2.rectangle(img, (left - 1, top - labelSize[1] - baseLine),
                  (left + labelSize[0], top), colors[classId], -1)
    cv2.putText(img, label, (left, top - baseLine), cv2.FONT_HERSHEY_SIMPLEX,
                0.6, (0, 0, 0), 1, cv2.LINE_AA)


# 모델 & 설정 파일
model = 'mask_rcnn/frozen_inference_graph.pb'
config = 'mask_rcnn/mask_rcnn_inception_v2_coco_2018_01_28.pbtxt'
class_labels = 'mask_rcnn/coco_90.names'
confThreshold = 0.6
maskThreshold = 0.3

# 테스트 이미지 파일
img_files = ['dog.jpg', 'traffic.jpg', 'sheep.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

# 클래스 이름 불러오기

classes = []
with open(class_labels, 'rt') as f:
    classes = f.read().rstrip('\n').split('\n')

colors = np.random.uniform(0, 255, size=(len(classes), 3))

# 전체 레이어 이름 받아오기
'''
객체를 바운딩박스 치는 output: (1,1,100,7) => 최대100개까지 객체 검출 가능 하며 7은 클래스 정보 또는 바운딩박스정보
바운딩 된 객체에서 윤곽선을 도출하는 output: (100,90,15,15) => 90개 class에 대한 15*15마스크가 출력된다
                                                        각각의 100개 객체에 대해서 90개의 마스크맵을 출력으로 준다   
'''

layer_names = net.getLayerNames() #네트워크의 모든 레이어 이름 가져오기
# net.getUnconnectedOutLayers(): 출력 레이어의 인덱스를 가져오기(인덱스는 332)
# output_layers: detection_masks 1개(출력레이어)
# 위 내용을 가지고 생각해 보면 네트워크 layer 중에서 마지막 출력 레이어는 네트워크 레이어에 포함되지 않는다는 걸로 연결됨
# 레이어 종류가 네트워크 레이어, 출력 레이어 이렇게 두개로 나뉜걸로 생각할수 있음(뇌피셜이라 확실치 않음)
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
for name in  layer_names:
    print(name)

# 실행

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론

    #blob의 사이즈는 지정 안해도 됨->이미지 크기와 동일한 크기로 만들어줌
    #평균값 디폴트는 0 이므로 여기서는 따로 지정 안함
    blob = cv2.dnn.blobFromImage(img, swapRB=True) #RGB로 학습되어 있음
    net.setInput(blob)

    #detection_out_final: 바운딩박스 정보
    #detection_masks: 각각의 바운딩 박스에서 마스크 정보를 가지고 있음
    #큰 순서: 각 객체의 바운딩박스 정보를 추출한 후에 그 박스 안에 있는 객체윤곽를 추출
    boxes, masks = net.forward(['detection_out_final', 'detection_masks'])

    # boxes.shape=(1, 1, 100, 7)
    # masks.shape=(100, 90, 15, 15)
    '''
    객체를 바운딩박스 치는 output: (1,1,5,7) => 5개 객체 검출함 클래스명을 직접 조사했지만 dog사진에 4개이상의 클래스명은 찾을수 없었다
                                                다시말해 같은 객체를 중복하여 검출했을 거라 생각해 볼수 있다. 
        바운딩 된 객체에서 윤곽선을 도출하는 output: (100,90,15,15) => 90개 class에 대한 15*15마스크가 출력된다
                                                         각각의 100개 객체에 대해서 90개의 마스크맵을 출력으로 준다   
    '''
    h, w = img.shape[:2]
    numClasses = masks.shape[1]  # 90(coco dataset의 class 개수)
    numDetections = boxes.shape[2]  # 5(detection 개수, 100개가 기본값이며 이보다 낮게 나올수도 있다)

    boxesToDraw = []
    for i in range(numDetections):
        box = boxes[0, 0, i]  # box.shape=(7,) 검출된 5개 객체의 바운딩 박스 정보를 가져온다
                              # (7,)짜리가 5개가 있는것이다.
        # classID: 몇번째에 대한 바운딩 박스 인가를 나타냄
        # confidence: 확률값(임계값보다 커야 제대로 찾았다고 인식한다)
        # 입력영상의 크기가 0~1 정규화가 되었다는 가정 하에 x1y1:좌측상단 , x2y2:우측하단
        #box: (0,classID,confidence, x1,y1,x2,y2) -> (7,)
        
        #i번째 객체 검출한것에 대해서 15*15 마스크 맵이 90개가 있는 것
        #90개 마스크를 다 쓰는게 아니라 94번줄의 ClassId에 해당하는 것만 사용
        mask = masks[i]  # mask.shape=(90, 15, 15)
        score = box[2] #confidence값
        if score > confThreshold: # 임계값보다 커야 제대로 찾은 것이다.
            classId = int(box[1]) #classID 추출
            #print(classId, classes[classId], score)

            #변환된 좌표
            x1 = int(w * box[3])
            y1 = int(h * box[4])
            x2 = int(w * box[5])
            y2 = int(h * box[6])

            #변환된 좌표와 원래 img크기를 비교해서
            #변환된 좌표가 본 이미지 크기보다 큰 경우를 없애기 위한 코드?
            x1 = max(0, min(x1, w - 1))
            y1 = max(0, min(y1, h - 1))
            x2 = max(0, min(x2, w - 1))
            y2 = max(0, min(y2, h - 1))

            boxesToDraw.append([img, classId, score, x1, y1, x2, y2])
            
            # classMask: 15*15짜리 행렬의 float형태의 마스크
            # 이 안에서 배경에 해당하는 부분은 값이 작을것이고, 객체에 해당하는 건 값이 크다
            classMask = mask[classId] #ClassID에 해당하는 mask 정보를 가져온다

            # 객체별 15x15 마스크를 바운딩 박스 크기로 resize한 후, 불투명 컬러로 표시
            classMask = cv2.resize(classMask, (x2 - x1 + 1, y2 - y1 + 1)) 
            
            #바운딩박스 안에는 배경과 객체가 있는데, 어떠한 기준값이 있어야 객체와 배경을 구분할수가 있다
            #이 구분하기 위한 기준 값이 maskThreshold (maskThreshold보다 크면 객체 아니면 배경)
            mask = (classMask > maskThreshold)

            #객체마다 다른 색깔로 불투명하게 하는 코드-> 결과영상에서 클래스 윤곽정보를 보여줌
            roi = img[y1:y2+1, x1:x2+1][mask] #원본 실제 객체 이미지
            img[y1:y2+1, x1:x2+1][mask] = (0.7 * colors[classId] + 0.3 * roi).astype(np.uint8)

    # 객체별 바운딩 박스 그리기 & 클래스 이름 표시-> 이게 없으면 결과영상에서 바운딩 박스가 없다
    for box in boxesToDraw:
        drawBox(*box)

    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

OpenPose

import sys
import numpy as np
import cv2


# 모델 & 설정 파일
model = 'openpose/pose_iter_440000.caffemodel'
config = 'openpose/pose_deploy_linevec.prototxt'

# 포즈 점 개수, 점 연결 개수, 연결 점 번호 쌍
nparts = 18 #전체 점의 개수
npairs = 17 # 점과 점 사이를 잇는 직선의 개수(관절표현)

#관절을 어떻게 이을건지를 설정해준다
pose_pairs = [(1, 2), (2, 3), (3, 4),  # 왼팔: 1번점 2번점, 2번점 3번점, 3번점 4번점을 연결하면 왼팔이된다
              (1, 5), (5, 6), (6, 7),  # 오른팔
              (1, 8), (8, 9), (9, 10),  # 왼쪽다리
              (1, 11), (11, 12), (12, 13),  # 오른쪽다리
              (1, 0), (0, 14), (14, 16), (0, 15), (15, 17)]  # 얼굴

# 테스트 이미지 파일
img_files = ['pose1.jpg', 'pose2.jpg', 'pose3.jpg']

# 네트워크 생성
net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Net open failed!')
    sys.exit()

for f in img_files:
    img = cv2.imread(f)

    if img is None:
        continue

    # 블롭 생성 & 추론
    blob = cv2.dnn.blobFromImage(img, 1/255., (368, 368))
    net.setInput(blob)
    out = net.forward()  # out.shape=(1, 57, 46, 46) 46*46가 57개, 앞에서 18개만 사용(keypoint)

    h, w = img.shape[:2]

    # 검출된 점 추출
    points = []
    for i in range(nparts): #nparts:18

        #heatMap 46*46 짜리 행렬이된다
        #heatMap 모양: 관절 부분 point 부분에서 headmap생김
        heatMap = out[0, i, :, :] #46*46의 float32 행렬

        '''
        ##heatmap 시각화##
        heatImg = cv2.normalize(heatMap, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) #0~1 -> 0~255
        heatImg = cv2.resize(heatImg, (w, h))
        heatImg = cv2.cvtColor(heatImg, cv2.COLOR_GRAY2BGR)
        heatImg = cv2.addWeighted(img, 0.5, heatImg, 0.5, 0)
        cv2.imshow('heatImg', heatImg)
        cv2.waitKey()
        '''
        #point: 46*46 행렬에서의 최대값 위치
        _, conf, _, point = cv2.minMaxLoc(heatMap)

        #point 최대값 위치가 전체 영상에서는 어디에 위치해 있는가를 알기 위함->w,h 곱셈
        #입력영상 해상도에 맞는 특정 관절 위치 x,y => (21,9) 위치를 정 사이즈로 변환
        x = int(w * point[0] / out.shape[3]) #out.shape[3]:46,  point[0]:21
        y = int(h * point[1] / out.shape[2]) #out.shape[2]:46,  point[1]:9

        points.append((x, y) if conf > 0.1 else None)  # heat map threshold=0.1

    # 검출 결과 영상 만들기 
    for pair in pose_pairs:
        p1 = points[pair[0]]
        p2 = points[pair[1]]

        if p1 is None or p2 is None: #67번줄에서 None이 들어오면 무시
            continue

        cv2.line(img, p1, p2, (0, 255, 0), 3, cv2.LINE_AA)

        #각각의 끝점을 원으로 그리기
        cv2.circle(img, p1, 4, (0, 0, 255), -1, cv2.LINE_AA)
        cv2.circle(img, p2, 4, (0, 0, 255), -1, cv2.LINE_AA)

    # 추론 시간 출력
    t, _ = net.getPerfProfile()
    label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
    cv2.putText(img, label, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 0, 255), 1, cv2.LINE_AA)

    cv2.imshow('img', img)
    cv2.waitKey()

cv2.destroyAllWindows()

 

728x90

'실습 note' 카테고리의 다른 글

bitcoin 예측 실습  (0) 2021.04.14
제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_11(딥러닝)  (0) 2021.03.04
OpenCV_10(머신러닝)  (0) 2021.03.03
OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
728x90

 

OpenCV DNN(MNIST)

import sys
import numpy as np
import cv2


oldx, oldy = -1, -1


def on_mouse(event, x, y, flags, _):
    global oldx, oldy

    if event == cv2.EVENT_LBUTTONDOWN:
        oldx, oldy = x, y

    elif event == cv2.EVENT_LBUTTONUP:
        oldx, oldy = -1, -1

    elif event == cv2.EVENT_MOUSEMOVE:
        if flags & cv2.EVENT_FLAG_LBUTTON:
            cv2.line(img, (oldx, oldy), (x, y), (255, 255, 255), 40, cv2.LINE_AA)
            oldx, oldy = x, y
            cv2.imshow('img', img)

def norm_digit(img):
	m = cv2.moments(img)
    cx = m['m10'] / m['m00']
    cy = m['m01'] / m['m00']
    h,w = img.shape[:2]
    aff = np.array([[1,0, w/2-cx], [0,1,h/2-cy]], dtype = np.float32)
    dst = cv2.warpAffine(img, aff, (0,0))
    return dst

net = cv2.dnn.readNet('mnist_cnn.pb')

if net.empty():
    print('Network load failed!')
    sys.exit()

img = np.zeros((400, 400), np.uint8) #숫자를 그릴 판

cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)

while True:
    c = cv2.waitKey()

    if c == 27:
        break
    elif c == ord(' '):
        #직접 그린 숫자 400*400짜리 이미지를 blob이라는 객체로 변환
        #blob은 4차원 형식의 ndarray (N,C,H,W)
        #학습 시, 학습데이터 픽셀값을 0~1까지 정규화하여 학습했으므로 1/255.을 넣어서 똑같이 정규화 해준다
        #학습 데이터 mnist 크기그 28*28이였으므로 똑같은 크기인 28*28 resize 시행 
        #내가 그린 숫자를 가운데에 위치시켜 놓고 진행: norm_digit
        blob = cv2.dnn.blobFromImage(norm_digit(img), 1/255., (28, 28))
        net.setInput(blob)

        '''
        prob: (1,10) 10개의 elemnet가 있고,
        확률이 최대값인 element의 인덱스값 = 모델이 인식한 숫자
        '''

        prob = net.forward()
        print('prob',prob)
        #최대값인 확률값과 그 위치를 반환
        _, maxVal, _, maxLoc = cv2.minMaxLoc(prob)
        print('maxLoc',maxLoc)

        digit = maxLoc[0] #최대값 성분의 index값 

        print(f'{digit} ({maxVal * 100:4.2f}%)')

        img.fill(0)
        cv2.imshow('img', img)

cv2.destroyAllWindows()

 

OpenCV DNN_googlenet

import sys
import numpy as np
import cv2


# 입력 영상 불러오기

filename = 'space_shuttle.jpg' #우주선

if len(sys.argv) > 1: #명령창에서 py명[0], 입력영상[1] 쓰면 같이 실행되게끔 하는 ㅋ코드
    filename = sys.argv[1]

img = cv2.imread(filename)

if img is None:
    print('Image load failed!')
    sys.exit()

# 네트워크 불러오기

# Caffe
# model = 'googlenet/bvlc_googlenet.caffemodel'
# config = 'googlenet/deploy.prototxt'

# ONNX
model = 'googlenet/googlenet-9.onnx'
config = '' #ONNX에서는 config 필요 없음

net = cv2.dnn.readNet(model, config)

if net.empty():
    print('Network load failed!')
    sys.exit()

# 클래스 이름 불러오기
classNames = None
with open('googlenet/classification_classes_ILSVRC2012.txt', 'rt') as f:
    classNames = f.read().rstrip('\n').split('\n') #공백 단위로 제거와 분리 진행

# 추론
#1: 학습 시 0~255를 사용했다는 의미
#(104, 117, 123): BGR평균값? 
blob = cv2.dnn.blobFromImage(img, 1, (224, 224), (104, 117, 123))
net.setInput(blob)
prob = net.forward()

# 추론 결과 확인 & 화면 출력

out = prob.flatten()
classId = np.argmax(out) #가장 큰 값이 있는 위치 찾기
confidence = out[classId] #가장 큰 확률 값 나타내기

text = f'{classNames[classId]} ({confidence * 100:4.2f}%)'
cv2.putText(img, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)

cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()

 

 

 

 

 

 

 

 

 

728x90

'실습 note' 카테고리의 다른 글

제조 공정 불량 검출 실습  (0) 2021.03.11
OpenCV_12(딥러닝2)  (0) 2021.03.05
OpenCV_10(머신러닝)  (0) 2021.03.03
OpenCV_9(객체 추적과 모션벡터)  (0) 2021.03.01
OpenCV_8(특징점 검출&매칭)  (0) 2021.02.26

+ Recent posts