TigerCow.Door

안녕하세요. 문범우입니다.

이번에 소개해드릴 알고리즘 문제는, 2017년 카카오톡 블라인드테스트 1차 코딩시험에서 나왔던 문제중 난이도가 제일 낮다는 소개된 '비밀지도' 문제입니다.


해당 문제는 프로그래머스를 통해, 아래 주소에서 만나보실 수 있습니다.

https://programmers.co.kr/learn/courses/30/lessons/17681?language=python3


난이도가 가장 낮다고 소개된 만큼, 문제자체도 간단하고 풀이도 어렵지 않습니다.

따라서 해당 문제는 추가적인 설명대신 코드만 첨부해드리도록 하겠습니다.

추가적으로 궁금한 사항이 있으시면 언제든지 댓글 및 카카오톡이나 이메일을 통해서 연락주시면 바로 답변드리도록 하겠습니다.


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
def solution(n, arr1, arr2):
    answer = []
    decode_arr1 = []
    decode_arr2 = []
    tmp_str = ''
    tmp_answer = ''
    for i in arr1:
        tmp_str = str(bin(i))[2:]
        while(len(tmp_str) < n):
            tmp_str = '0'+tmp_str
        tmp_str = tmp_str.replace('0',' ')
        tmp_str = tmp_str.replace('1','#')
        decode_arr1.append(tmp_str)
    for i in arr2:
        tmp_str = str(bin(i))[2:]
        while(len(tmp_str) < n):
            tmp_str = '0'+tmp_str
        tmp_str = tmp_str.replace('0',' ')
        tmp_str = tmp_str.replace('1','#')
        decode_arr2.append(tmp_str)
    
    for i in range(n):
        for j in range(n):
            if (decode_arr1[i][j] == '#'or (decode_arr2[i][j] == '#'):
                tmp_answer += '#'
            else:
                tmp_answer += ' '
        answer.append(tmp_answer)
        tmp_answer = ''
    return answer
cs


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc

안녕하세요. 문범우입니다.

요새 많은 기업들이 공채시즌이 다가와서 그런지, 평소보다 알고리즘 문제풀이에 대한 학원이나 온라인강의에 대한 광고가 많아진 것 같네요.


요새보면 대부분의 기업에서 SW인원들은 다른 시험보다 코딩테스트를 중요시하고 있고 많은 사람들이 제일 까다로워 하는 부분인 것 같습니다.


요새 개인적으로 공부하는 기계학습이나, 리액트네이티브때문에 블로그활동을 자주못하고 있는데, 오랜만에 프로그래머스에 들어갔다가 2017년 카카오톡 블라인드테스트 1차 코딩문제를 공개해두었길래 이번주에 하나씩 풀어보려합니다.


처음에는 쉬운문제부터 풀어보려했는데.. 나중에 확인해보니 이번에 소개해드릴 '추석트래픽' 문제가 가장 어려웠다고 하네요.


프로그래머스에서 제공하는 작년 카카오톡 코딩테스트 문제는 아래에서 만나보실수 있으며,

https://programmers.co.kr/learn/challenges


이에 대한 전체적인 해설은 아래에서 만나보실수 있습니다.

http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/



오늘 소개해드릴 '추석트래픽' 문제의 정답률이 약18%라고 하지만, 개인적인 생각으로는 2017 카카오톡 블라인드테스트 1차 코딩테스트에서 총 5시간이 주어졌기때문에 어려웠다기보단 시간이 부족했다는 이야기가 많았을 듯 합니다.


문제에 대한 전체적인 안내나, 난이도정도등에 대해서는 위에 소개해드린 해설에서 확인해보시길 바랍니다.



1. 추석 트래픽


추석 트래픽 문제에 대한 설명은 따로 진행하지 않겠습니다.

제가 말로 주구장창 설명하는 것보다 직접 문제와 예제를 보시는게 이해가 빠를 것 같아서요 :'(


특별히, 예제3번에서 하나의 그림을 보여주고 있습니다.

x축을 시간으로 두고 각각의 트래픽을 bar형태로 표시해두었죠.

그리고 1초라는 시간범위(구간)를 정해서, 가장 많은 트래픽이 포함되는 구간에서의 트래픽 개수를 찾아내고 있습니다.


해당 그림을 보면서 어디서 많이 낯익다 싶었습니다.

바로, An activity-selection problem 문제입니다.

작년 알고리즘수업을 들으면서 봤던 문제인데, 잘 모르시는 분들은 한번 쯤 찾아보셔도 좋을 듯 합니다.


먼저 저는 입력되는 lines 를 하나씩 가져와서 datetime 객체로 바꾸고 이를 end_datetime으로 두었으며 lines에서 주는 실행시간을 가져와서 실행시간의 초단위 값 processing_s 와, 실행시간의 micro second단위 값 processing_ms 를 만들었습니다.

그리고 이 세개의 값를 이용해서, 트래픽의 시작시간을 구해 datetime객체로 하여 start_datetime으로 두었습니다.


이들을 이용해 같은 트래픽끼리 하나의 리스트로 묶어서, start_end_datetime 리스트에 저장하였고, 추후 answer를 탐색하기 위해 sorted_time 리스트를 만들어 start_datetime과 end_datetime의 모든 요소를 같이 저장하였습니다.

그리고 모든 lines에 대한 처리가 끝나면 sorted_time 리스트는 sort함수를 통해 오름차순으로 정렬합니다.


즉, 예제 1번과 같이 입력이 다음과 같다면,

입력: [
2016-09-15 01:00:04.001 2.0s,
2016-09-15 01:00:07.000 2s
]


start_end_datetime = [[ '2016-09-15 01:00:02.002000', '2016-09-15 01:00:04.001000' ], [ '2016-09-15 01:00:05.001', '2016-09-15 01:00:07.000']]


sorted_time = [ '2016-09-15 01:00:02.002000', '2016-09-15 01:00:04.001000', '2016-09-15 01:00:05.001', '2016-09-15 01:00:07.000']


과 같이 만들어지게 됩니다.


이제 문제에서 원하는 답을 찾을 차례입니다.

여기서 저도 한번 헤매고, 1000 micro second마다 탐색하는 방법으로 시도해봤더니 역시나 시간초과에 걸렸었습니다....


하지만 조금 더 생각해보면, 구하고자 하는 초당 최대 처리량이 변하는 순간은 단지 어떤 트래픽의 시작 또는 종료 시점뿐 입니다.

즉, 위에서 만들어두었던 sorted_time 리스트에 있는 시간에서만 초당 최대 처리량의 변화가 발생합니다.

따라서 우리는 sorted_time 리스트를 범위로 for문을 돌리면 되고, sorted_time 리스트에서 꺼낸 하나의 요소를 compare_time으로 두었고, 여기에 1초를 더한 시간을 compare_time_one으로 두었습니다.

그리고 start_end_datetime에서 하나씩 꺼내어 compare_time과 compare_time_one이라는 범위에 해당 트래픽이 속하여있는지를 탐색하고 각각의 탐색에 따른 최대값을 찾아 정답으로 반환하면 됩니다.


설명이 잘 된지는 모르겠으나, 실제로 코드를 보시면서 이해해보시면 잘 이해할 수 있을 것이라고 생각됩니다.


전체적인 python 코드는 다음과 같습니다.


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
import datetime
 
def solution(lines):
    start_end_time = []
    sorted_time = []
    tmp_answer = 0
    answer = tmp_answer
    for line in lines:
        split_line = line.split()
        split_day = split_line[0].split('-')
        split_time = split_line[1].split(':')
        split_s = split_time[2].split('.')
 
        Y = int(split_day[0]); M = int(split_day[1]); D = int(split_day[2])
        h = int(split_time[0]); m = int(split_time[1])
        s = int(split_s[0]); ms = int(split_s[1])*1000
        
        end_datetime = datetime.datetime(Y,M,D,h,m,s,ms)
        
        split_processing = split_line[2][:-1].split('.')
        processing_s = int(split_processing[0])
        if len(split_processing) == 1:
            start_datetime = end_datetime - datetime.timedelta(seconds=processing_s)
        else:
            processing_ms = int(split_processing[1]) * 1000
            start_datetime = end_datetime - datetime.timedelta(seconds=processing_s) - datetime.timedelta(microseconds=processing_ms)
        start_datetime = start_datetime + datetime.timedelta(microseconds=1000)
        start_end_time.append([start_datetime,end_datetime])
        sorted_time.append(start_datetime)
        sorted_time.append(end_datetime)
    sorted_time.sort()
    
    for compare_time in sorted_time:
        compare_time_one = compare_time + datetime.timedelta(seconds=1)
        if compare_time >= start_end_time[-1][1]:
            break;
        for each in start_end_time:
            if (compare_time <= each[0])and(each[0< compare_time_one):
                tmp_answer += 1
            elif (compare_time <= each[1])and(each[1< compare_time_one):
                tmp_answer += 1
            elif (each[0<= compare_time)and(compare_time_one <= each[1]):
                tmp_answer += 1
        if answer < tmp_answer:
            answer = tmp_answer
        tmp_answer = 0
    if answer == 0:
        answer += 1
    return answer
cs


만약 코드에 대해 궁금한 사항이나, 보다 효율적인 방법에 대해서 말씀해주실 점이 있다면 언제든지 댓글 또는 카카오톡, 이메일을 이용해서 말씀해주세요 :)

블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc

안녕하세요. 문범우입니다.


최근 장고를 활용하면서 재밌는 아이디어 없을까 하다가..

졸업과 취업을 앞두고 있는 제가 생각나면서

학교 졸업 가능 여부를 일일이 확인하던 모습이 보였습니다.


이에 따라서 교내 행정정보시스템에서 성적표를 .xls파일로 다운 받고, 단순히 그 파일과 영어성적 입력으로 졸업가능 여부를 확인해주는 사이트를 개발하였습니다.


먼저 사이트 주소는 아래와 같습니다.


www.uos-info.com


해당 사이트는 django(2.0 version)를 이용하여 개발되었습니다.


aws ec2와, 도메인 설정을 위해 aws route53을 이용하였습니다.



일단은 제가 속해있는 전자전기컴퓨터공학부에 한해서 서비스가 제공되고 있지만

혹여나 다른 과나 학부에 의한 요청도 들어오면 추가해보도록 하겠습니다.


학교에서 필요로하는 졸업요건은 쉽게 확인이 가능하지만, 각 학과나 학부별로 다른 졸업요건을 제가 일일이 확인할 수가 없어서 서비스에 대한 필요를 말씀해주시는 학과 및 학부에 대해 서비스를 추가할 예정입니다.


해당 서비스에서는 단순하게 여러개의 rule-based를 기반으로 졸업 여부를 확인해줍니다.

시립대 전자전기컴퓨터학부의 경우에는 특정 세부 분야로 지정된 교양을 듣거나, 전공과목을 들어야 하는 조건이 있는데 이에 대해서는 서울시립대학교에서 open API로 제공하는 서비스로 요청을 보내서, 성적표에 있는 수업의 세부분야를 확인하거나 몇학년 몇학기 수업인지 확인하여 졸업요건에 해당하는지를 체크하는 식으로 구성되어 있습니다.


해당 사이트에 대해 추가적인 문의사항이나 건의사항이 있으신 분들은 언제든지 자유롭게 댓글 및 이메일을 통해서 연락주시면 감사하겠습니다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc

4_Overfitting_and_Underfitting


안녕하세요. 문범우입니다.

이번 포스팅에서 다뤄볼 내용은, 텐서플로우 튜토리얼의 4번째 overfitting and underfitting 입니다.


In [41]:
# TensorFlow and tf.keras
# 텐서플로우와 keras를 import한다. 이떄 tensorflow는 tf라는 별칭으로 사용할 것임.
import tensorflow as tf
from tensorflow import keras

# Helper libraries
# numpy와 matplotlib을 사용한다.
import numpy as np
import matplotlib.pyplot as plt
# jupyter notebook에서 matplotlib을 사용하기 위한 매직커맨드
%matplotlib inline

print("사용되는 tensorflow의 버전:",tf.__version__)
사용되는 tensorflow의 버전: 1.9.0

ㄱ. 데이터준비

이번에 사용될 데이터는 지난번 test classification에서 사용되었던 IMDB 영화 데이터입니다.

In [43]:
NUM_WORDS = 10000

(train_data, train_labels), (test_data, test_labels) = keras.datasets.imdb.load_data(num_words=NUM_WORDS)
In [44]:
# 0번째 데이터의 값 확인해보기
print(train_data[0][0:5],". . .",train_data[0][-5:])
[1, 14, 22, 16, 43] . . . [16, 5345, 19, 178, 32]
In [45]:
def multi_hot_sequences(sequences, dimension):
    # Create an all-zero matrix of shape (len(sequences), dimension)
    # sequences의 길이만큼 행을 만들고, dimension만큼 열을 만든다.
    results = np.zeros((len(sequences), dimension))
    # sequence
    for i, word_indices in enumerate(sequences):
        # i번째의 데이터에 대해서 포함되어 있는 단어의 숫자값을 인덱스로 하여 1값으로 가져간다.
        results[i, word_indices] = 1.0  # set specific indices of results[i] to 1s
    return results


train_data = multi_hot_sequences(train_data, dimension=NUM_WORDS)
test_data = multi_hot_sequences(test_data, dimension=NUM_WORDS)

우리는 이번에 overfitting에 대해 공부해볼 예정입니다.

위의 multi_hot_sequences 함수는, 모델이 훈련데이터셋에 대해서 보다 빨리 overfitting이 되도록 합니다.

In [46]:
# 0번째 데이터의 값 확인해보기
print(train_data[0][0:5],". . .",train_data[0][-5:])
[0. 1. 1. 0. 1.] . . . [0. 0. 0. 0. 0.]
In [48]:
# 0번째 데이터 값을 그래프로 확인해보기
plt.plot(train_data[0])
Out[48]:
[<matplotlib.lines.Line2D at 0xb28f28550>]

ㄴ. 기준 모델 만들기

오버피팅을 확인해보기 위해 먼저 기준 모델을 만들어본다.

In [49]:
baseline_model = keras.Sequential([
    # `input_shape` is only required here so that `.summary` works. 
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

baseline_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 16)                160016    
_________________________________________________________________
dense_1 (Dense)              (None, 16)                272       
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,305
Trainable params: 160,305
Non-trainable params: 0
_________________________________________________________________
In [50]:
# 기준 모델을 훈련해보고 측정해본다.
baseline_history = baseline_model.fit(train_data,
                                      train_labels,
                                      epochs=20,
                                      batch_size=512,
                                      validation_data=(test_data, test_labels),
                                      verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 9s - loss: 0.4707 - acc: 0.8128 - binary_crossentropy: 0.4707 - val_loss: 0.3284 - val_acc: 0.8775 - val_binary_crossentropy: 0.3284
Epoch 2/20
 - 7s - loss: 0.2428 - acc: 0.9134 - binary_crossentropy: 0.2428 - val_loss: 0.2843 - val_acc: 0.8873 - val_binary_crossentropy: 0.2843
Epoch 3/20
 - 6s - loss: 0.1789 - acc: 0.9366 - binary_crossentropy: 0.1789 - val_loss: 0.2911 - val_acc: 0.8858 - val_binary_crossentropy: 0.2911
Epoch 4/20
 - 6s - loss: 0.1431 - acc: 0.9512 - binary_crossentropy: 0.1431 - val_loss: 0.3177 - val_acc: 0.8778 - val_binary_crossentropy: 0.3177
Epoch 5/20
 - 7s - loss: 0.1188 - acc: 0.9606 - binary_crossentropy: 0.1188 - val_loss: 0.3433 - val_acc: 0.8732 - val_binary_crossentropy: 0.3433
Epoch 6/20
 - 8s - loss: 0.0975 - acc: 0.9696 - binary_crossentropy: 0.0975 - val_loss: 0.3757 - val_acc: 0.8680 - val_binary_crossentropy: 0.3757
Epoch 7/20
 - 7s - loss: 0.0786 - acc: 0.9776 - binary_crossentropy: 0.0786 - val_loss: 0.4244 - val_acc: 0.8616 - val_binary_crossentropy: 0.4244
Epoch 8/20
 - 8s - loss: 0.0623 - acc: 0.9832 - binary_crossentropy: 0.0623 - val_loss: 0.4540 - val_acc: 0.8631 - val_binary_crossentropy: 0.4540
Epoch 9/20
 - 7s - loss: 0.0478 - acc: 0.9895 - binary_crossentropy: 0.0478 - val_loss: 0.4929 - val_acc: 0.8604 - val_binary_crossentropy: 0.4929
Epoch 10/20
 - 8s - loss: 0.0356 - acc: 0.9938 - binary_crossentropy: 0.0356 - val_loss: 0.5390 - val_acc: 0.8580 - val_binary_crossentropy: 0.5390
Epoch 11/20
 - 6s - loss: 0.0261 - acc: 0.9962 - binary_crossentropy: 0.0261 - val_loss: 0.5758 - val_acc: 0.8578 - val_binary_crossentropy: 0.5758
Epoch 12/20
 - 4s - loss: 0.0186 - acc: 0.9983 - binary_crossentropy: 0.0186 - val_loss: 0.6208 - val_acc: 0.8558 - val_binary_crossentropy: 0.6208
Epoch 13/20
 - 6s - loss: 0.0127 - acc: 0.9989 - binary_crossentropy: 0.0127 - val_loss: 0.6513 - val_acc: 0.8558 - val_binary_crossentropy: 0.6513
Epoch 14/20
 - 7s - loss: 0.0090 - acc: 0.9997 - binary_crossentropy: 0.0090 - val_loss: 0.6821 - val_acc: 0.8548 - val_binary_crossentropy: 0.6821
Epoch 15/20
 - 7s - loss: 0.0065 - acc: 1.0000 - binary_crossentropy: 0.0065 - val_loss: 0.7090 - val_acc: 0.8548 - val_binary_crossentropy: 0.7090
Epoch 16/20
 - 6s - loss: 0.0050 - acc: 1.0000 - binary_crossentropy: 0.0050 - val_loss: 0.7358 - val_acc: 0.8552 - val_binary_crossentropy: 0.7358
Epoch 17/20
 - 7s - loss: 0.0040 - acc: 1.0000 - binary_crossentropy: 0.0040 - val_loss: 0.7585 - val_acc: 0.8551 - val_binary_crossentropy: 0.7585
Epoch 18/20
 - 4s - loss: 0.0032 - acc: 1.0000 - binary_crossentropy: 0.0032 - val_loss: 0.7811 - val_acc: 0.8550 - val_binary_crossentropy: 0.7811
Epoch 19/20
 - 4s - loss: 0.0026 - acc: 1.0000 - binary_crossentropy: 0.0026 - val_loss: 0.8007 - val_acc: 0.8552 - val_binary_crossentropy: 0.8007
Epoch 20/20
 - 4s - loss: 0.0022 - acc: 1.0000 - binary_crossentropy: 0.0022 - val_loss: 0.8192 - val_acc: 0.8548 - val_binary_crossentropy: 0.8192

이번에는 기준 모델보다 hidden units이 적은 모델을 만들어 본다.

In [52]:
smaller_model = keras.Sequential([
    keras.layers.Dense(4, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(4, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

smaller_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_6 (Dense)              (None, 4)                 40004     
_________________________________________________________________
dense_7 (Dense)              (None, 4)                 20        
_________________________________________________________________
dense_8 (Dense)              (None, 1)                 5         
=================================================================
Total params: 40,029
Trainable params: 40,029
Non-trainable params: 0
_________________________________________________________________
In [53]:
smaller_history = smaller_model.fit(train_data,
                                    train_labels,
                                    epochs=20,
                                    batch_size=512,
                                    validation_data=(test_data, test_labels),
                                    verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 5s - loss: 0.6317 - acc: 0.6360 - binary_crossentropy: 0.6317 - val_loss: 0.5714 - val_acc: 0.7279 - val_binary_crossentropy: 0.5714
Epoch 2/20
 - 6s - loss: 0.5187 - acc: 0.8149 - binary_crossentropy: 0.5187 - val_loss: 0.5109 - val_acc: 0.8128 - val_binary_crossentropy: 0.5109
Epoch 3/20
 - 6s - loss: 0.4623 - acc: 0.8725 - binary_crossentropy: 0.4623 - val_loss: 0.4787 - val_acc: 0.8519 - val_binary_crossentropy: 0.4787
Epoch 4/20
 - 7s - loss: 0.4248 - acc: 0.9022 - binary_crossentropy: 0.4248 - val_loss: 0.4587 - val_acc: 0.8713 - val_binary_crossentropy: 0.4587
Epoch 5/20
 - 5s - loss: 0.3962 - acc: 0.9184 - binary_crossentropy: 0.3962 - val_loss: 0.4449 - val_acc: 0.8781 - val_binary_crossentropy: 0.4449
Epoch 6/20
 - 4s - loss: 0.3721 - acc: 0.9321 - binary_crossentropy: 0.3721 - val_loss: 0.4394 - val_acc: 0.8686 - val_binary_crossentropy: 0.4394
Epoch 7/20
 - 5s - loss: 0.3505 - acc: 0.9414 - binary_crossentropy: 0.3505 - val_loss: 0.4345 - val_acc: 0.8696 - val_binary_crossentropy: 0.4345
Epoch 8/20
 - 7s - loss: 0.3317 - acc: 0.9494 - binary_crossentropy: 0.3317 - val_loss: 0.4253 - val_acc: 0.8758 - val_binary_crossentropy: 0.4253
Epoch 9/20
 - 7s - loss: 0.3147 - acc: 0.9567 - binary_crossentropy: 0.3147 - val_loss: 0.4255 - val_acc: 0.8738 - val_binary_crossentropy: 0.4255
Epoch 10/20
 - 7s - loss: 0.2993 - acc: 0.9617 - binary_crossentropy: 0.2993 - val_loss: 0.4202 - val_acc: 0.8758 - val_binary_crossentropy: 0.4202
Epoch 11/20
 - 7s - loss: 0.2854 - acc: 0.9659 - binary_crossentropy: 0.2854 - val_loss: 0.4210 - val_acc: 0.8738 - val_binary_crossentropy: 0.4210
Epoch 12/20
 - 6s - loss: 0.2714 - acc: 0.9697 - binary_crossentropy: 0.2714 - val_loss: 0.4225 - val_acc: 0.8729 - val_binary_crossentropy: 0.4225
Epoch 13/20
 - 4s - loss: 0.2589 - acc: 0.9732 - binary_crossentropy: 0.2589 - val_loss: 0.4269 - val_acc: 0.8699 - val_binary_crossentropy: 0.4269
Epoch 14/20
 - 4s - loss: 0.2474 - acc: 0.9754 - binary_crossentropy: 0.2474 - val_loss: 0.4230 - val_acc: 0.8698 - val_binary_crossentropy: 0.4230
Epoch 15/20
 - 4s - loss: 0.2368 - acc: 0.9781 - binary_crossentropy: 0.2368 - val_loss: 0.4355 - val_acc: 0.8676 - val_binary_crossentropy: 0.4355
Epoch 16/20
 - 4s - loss: 0.2266 - acc: 0.9802 - binary_crossentropy: 0.2266 - val_loss: 0.4397 - val_acc: 0.8671 - val_binary_crossentropy: 0.4397
Epoch 17/20
 - 3s - loss: 0.2175 - acc: 0.9816 - binary_crossentropy: 0.2175 - val_loss: 0.4456 - val_acc: 0.8663 - val_binary_crossentropy: 0.4456
Epoch 18/20
 - 4s - loss: 0.2084 - acc: 0.9832 - binary_crossentropy: 0.2084 - val_loss: 0.4333 - val_acc: 0.8686 - val_binary_crossentropy: 0.4333
Epoch 19/20
 - 3s - loss: 0.2002 - acc: 0.9843 - binary_crossentropy: 0.2002 - val_loss: 0.4555 - val_acc: 0.8657 - val_binary_crossentropy: 0.4555
Epoch 20/20
 - 3s - loss: 0.1927 - acc: 0.9848 - binary_crossentropy: 0.1927 - val_loss: 0.4654 - val_acc: 0.8643 - val_binary_crossentropy: 0.4654

이번에는 기준 모델보다 hidden units이 많은 모델을 만들어 본다.

In [54]:
bigger_model = keras.models.Sequential([
    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(512, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

bigger_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_9 (Dense)              (None, 512)               5120512   
_________________________________________________________________
dense_10 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_11 (Dense)             (None, 1)                 513       
=================================================================
Total params: 5,383,681
Trainable params: 5,383,681
Non-trainable params: 0
_________________________________________________________________
In [55]:
bigger_history = bigger_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 18s - loss: 0.3478 - acc: 0.8466 - binary_crossentropy: 0.3478 - val_loss: 0.2992 - val_acc: 0.8776 - val_binary_crossentropy: 0.2992
Epoch 2/20
 - 18s - loss: 0.1441 - acc: 0.9471 - binary_crossentropy: 0.1441 - val_loss: 0.3556 - val_acc: 0.8651 - val_binary_crossentropy: 0.3556
Epoch 3/20
 - 19s - loss: 0.0532 - acc: 0.9839 - binary_crossentropy: 0.0532 - val_loss: 0.4296 - val_acc: 0.8650 - val_binary_crossentropy: 0.4296
Epoch 4/20
 - 18s - loss: 0.0100 - acc: 0.9985 - binary_crossentropy: 0.0100 - val_loss: 0.5852 - val_acc: 0.8694 - val_binary_crossentropy: 0.5852
Epoch 5/20
 - 19s - loss: 0.0011 - acc: 1.0000 - binary_crossentropy: 0.0011 - val_loss: 0.6643 - val_acc: 0.8680 - val_binary_crossentropy: 0.6643
Epoch 6/20
 - 20s - loss: 2.8284e-04 - acc: 1.0000 - binary_crossentropy: 2.8284e-04 - val_loss: 0.7065 - val_acc: 0.8680 - val_binary_crossentropy: 0.7065
Epoch 7/20
 - 20s - loss: 1.6760e-04 - acc: 1.0000 - binary_crossentropy: 1.6760e-04 - val_loss: 0.7332 - val_acc: 0.8684 - val_binary_crossentropy: 0.7332
Epoch 8/20
 - 20s - loss: 1.1922e-04 - acc: 1.0000 - binary_crossentropy: 1.1922e-04 - val_loss: 0.7526 - val_acc: 0.8683 - val_binary_crossentropy: 0.7526
Epoch 9/20
 - 20s - loss: 9.0721e-05 - acc: 1.0000 - binary_crossentropy: 9.0721e-05 - val_loss: 0.7692 - val_acc: 0.8683 - val_binary_crossentropy: 0.7692
Epoch 10/20
 - 19s - loss: 7.1760e-05 - acc: 1.0000 - binary_crossentropy: 7.1760e-05 - val_loss: 0.7820 - val_acc: 0.8682 - val_binary_crossentropy: 0.7820
Epoch 11/20
 - 23s - loss: 5.8391e-05 - acc: 1.0000 - binary_crossentropy: 5.8391e-05 - val_loss: 0.7941 - val_acc: 0.8682 - val_binary_crossentropy: 0.7941
Epoch 12/20
 - 22s - loss: 4.8347e-05 - acc: 1.0000 - binary_crossentropy: 4.8347e-05 - val_loss: 0.8046 - val_acc: 0.8684 - val_binary_crossentropy: 0.8046
Epoch 13/20
 - 21s - loss: 4.0705e-05 - acc: 1.0000 - binary_crossentropy: 4.0705e-05 - val_loss: 0.8139 - val_acc: 0.8682 - val_binary_crossentropy: 0.8139
Epoch 14/20
 - 19s - loss: 3.4762e-05 - acc: 1.0000 - binary_crossentropy: 3.4762e-05 - val_loss: 0.8229 - val_acc: 0.8681 - val_binary_crossentropy: 0.8229
Epoch 15/20
 - 18s - loss: 2.9985e-05 - acc: 1.0000 - binary_crossentropy: 2.9985e-05 - val_loss: 0.8312 - val_acc: 0.8682 - val_binary_crossentropy: 0.8312
Epoch 16/20
 - 19s - loss: 2.6114e-05 - acc: 1.0000 - binary_crossentropy: 2.6114e-05 - val_loss: 0.8379 - val_acc: 0.8681 - val_binary_crossentropy: 0.8379
Epoch 17/20
 - 19s - loss: 2.2936e-05 - acc: 1.0000 - binary_crossentropy: 2.2936e-05 - val_loss: 0.8461 - val_acc: 0.8687 - val_binary_crossentropy: 0.8461
Epoch 18/20
 - 19s - loss: 2.0306e-05 - acc: 1.0000 - binary_crossentropy: 2.0306e-05 - val_loss: 0.8517 - val_acc: 0.8683 - val_binary_crossentropy: 0.8517
Epoch 19/20
 - 19s - loss: 1.8037e-05 - acc: 1.0000 - binary_crossentropy: 1.8037e-05 - val_loss: 0.8579 - val_acc: 0.8683 - val_binary_crossentropy: 0.8579
Epoch 20/20
 - 19s - loss: 1.6142e-05 - acc: 1.0000 - binary_crossentropy: 1.6142e-05 - val_loss: 0.8643 - val_acc: 0.8686 - val_binary_crossentropy: 0.8643

이렇게 까지해서, baseline, small, bigger 총 세가지 모델을 만들고, 같은 데이터셋으로 훈련과 validation을 진행하였다.

그래프를 통해 오차율을 확인해보자.

In [56]:
def plot_history(histories, key='binary_crossentropy'):
  plt.figure(figsize=(16,10))
    
  for name, history in histories:
    val = plt.plot(history.epoch, history.history['val_'+key],
                   '--', label=name.title()+' Val')
    plt.plot(history.epoch, history.history[key], color=val[0].get_color(),
             label=name.title()+' Train')

  plt.xlabel('Epochs')
  plt.ylabel(key.replace('_',' ').title())
  plt.legend()

  plt.xlim([0,max(history.epoch)])


plot_history([('baseline', baseline_history),
              ('smaller', smaller_history),
              ('bigger', bigger_history)])

위의 그래프를 확인해보면 train데이터를 통한 오차보다 validation데이터를 통한 오차가 어떤 모델에서든 크다는 것을 볼 수 있다.

특히나 bigger와 baseline 모델에서는 epoch이 늘어날 수록 validation의 오차가 크게 증가함을 볼 수 있다.

이렇게 testdataset에만 지나치게 적합되어있는 현상을 과적합, overfitting이라고 한다.

이러한 overfitting은 어떻게 해결할 수 있을까?

Overfitting 전략 - 정규화

튜토리얼 상의 내용을 보면, weight를 학습하는데 있어서 보다 적은 값을 이용하도록 한다.

그러한 과정을 '정규화'라고 하는데, L1 정규화와 L2 정규화가 존재한다.

각각에 대해서는 문서의 본문을 그대로 참고한다.

L1 regularization, where the cost added is proportional to the absolute value of the weights coefficients (i.e. to what is called the "L1 norm" of the weights).

L2 regularization, where the cost added is proportional to the square of the value of the weights coefficients (i.e. to what is called the "L2 norm" of the weights). L2 regularization is also called weight decay in the context of neural networks. Don't let the different name confuse you: weight decay is mathematically the exact same as L2 regularization.

위와 같은 정규화를 케라스에서 사용하여 모델을 만들어본다.

In [57]:
l2_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

l2_model_history = l2_model.fit(train_data, train_labels,
                                epochs=20,
                                batch_size=512,
                                validation_data=(test_data, test_labels),
                                verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 10s - loss: 0.5400 - acc: 0.8033 - binary_crossentropy: 0.5021 - val_loss: 0.3943 - val_acc: 0.8726 - val_binary_crossentropy: 0.3546
Epoch 2/20
 - 7s - loss: 0.3134 - acc: 0.9049 - binary_crossentropy: 0.2687 - val_loss: 0.3354 - val_acc: 0.8869 - val_binary_crossentropy: 0.2869
Epoch 3/20
 - 5s - loss: 0.2578 - acc: 0.9270 - binary_crossentropy: 0.2066 - val_loss: 0.3366 - val_acc: 0.8860 - val_binary_crossentropy: 0.2833
Epoch 4/20
 - 4s - loss: 0.2316 - acc: 0.9386 - binary_crossentropy: 0.1765 - val_loss: 0.3484 - val_acc: 0.8836 - val_binary_crossentropy: 0.2921
Epoch 5/20
 - 6s - loss: 0.2178 - acc: 0.9463 - binary_crossentropy: 0.1598 - val_loss: 0.3613 - val_acc: 0.8794 - val_binary_crossentropy: 0.3022
Epoch 6/20
 - 7s - loss: 0.2043 - acc: 0.9511 - binary_crossentropy: 0.1445 - val_loss: 0.3762 - val_acc: 0.8767 - val_binary_crossentropy: 0.3158
Epoch 7/20
 - 5s - loss: 0.1969 - acc: 0.9543 - binary_crossentropy: 0.1354 - val_loss: 0.3911 - val_acc: 0.8725 - val_binary_crossentropy: 0.3287
Epoch 8/20
 - 4s - loss: 0.1882 - acc: 0.9582 - binary_crossentropy: 0.1251 - val_loss: 0.4013 - val_acc: 0.8716 - val_binary_crossentropy: 0.3379
Epoch 9/20
 - 5s - loss: 0.1819 - acc: 0.9599 - binary_crossentropy: 0.1178 - val_loss: 0.4190 - val_acc: 0.8702 - val_binary_crossentropy: 0.3543
Epoch 10/20
 - 7s - loss: 0.1795 - acc: 0.9620 - binary_crossentropy: 0.1141 - val_loss: 0.4350 - val_acc: 0.8670 - val_binary_crossentropy: 0.3691
Epoch 11/20
 - 7s - loss: 0.1736 - acc: 0.9633 - binary_crossentropy: 0.1071 - val_loss: 0.4417 - val_acc: 0.8660 - val_binary_crossentropy: 0.3746
Epoch 12/20
 - 6s - loss: 0.1699 - acc: 0.9648 - binary_crossentropy: 0.1028 - val_loss: 0.4632 - val_acc: 0.8618 - val_binary_crossentropy: 0.3955
Epoch 13/20
 - 4s - loss: 0.1688 - acc: 0.9660 - binary_crossentropy: 0.1002 - val_loss: 0.4665 - val_acc: 0.8632 - val_binary_crossentropy: 0.3975
Epoch 14/20
 - 4s - loss: 0.1588 - acc: 0.9710 - binary_crossentropy: 0.0899 - val_loss: 0.4748 - val_acc: 0.8610 - val_binary_crossentropy: 0.4062
Epoch 15/20
 - 3s - loss: 0.1523 - acc: 0.9744 - binary_crossentropy: 0.0838 - val_loss: 0.4883 - val_acc: 0.8620 - val_binary_crossentropy: 0.4196
Epoch 16/20
 - 4s - loss: 0.1498 - acc: 0.9744 - binary_crossentropy: 0.0809 - val_loss: 0.5009 - val_acc: 0.8597 - val_binary_crossentropy: 0.4318
Epoch 17/20
 - 5s - loss: 0.1474 - acc: 0.9760 - binary_crossentropy: 0.0782 - val_loss: 0.5079 - val_acc: 0.8590 - val_binary_crossentropy: 0.4383
Epoch 18/20
 - 4s - loss: 0.1455 - acc: 0.9756 - binary_crossentropy: 0.0756 - val_loss: 0.5240 - val_acc: 0.8574 - val_binary_crossentropy: 0.4537
Epoch 19/20
 - 4s - loss: 0.1423 - acc: 0.9772 - binary_crossentropy: 0.0719 - val_loss: 0.5285 - val_acc: 0.8601 - val_binary_crossentropy: 0.4580
Epoch 20/20
 - 3s - loss: 0.1401 - acc: 0.9790 - binary_crossentropy: 0.0693 - val_loss: 0.5415 - val_acc: 0.8562 - val_binary_crossentropy: 0.4702

L2 정규화를 사용하는 l2_model을 구성하였다.

앞의 2개의 레이어에 정규화를 진행시켰는데, kernel_regularizer에 사용할 정규화를 케라스 라이브러리를 통해 입력해준다. 이때 뒤에 소괄호를 통해 넣어주는 값은 정규화의 세기를 의미한다.

l2_model을 그래프로 살펴보고 기준 모델과 비교해본다.

In [58]:
plot_history([('baseline', baseline_history),
              ('l2', l2_model_history)])

Overfitting 전략 - Drop out

이번에 알아볼 Overfitting 전략은 Drop out 방법이다.

이는 쉽게 이야기해서, 학습할 때 모든 노드들이 일하는 것이 아니고, 랜덤하게 특정 노드들은 학습을 하지 않도록 하는 것이다.

이번에도 바로 드랍아웃을 적용한 모델을 만들어 본다.

In [59]:
dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

dpt_model_history = dpt_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 9s - loss: 0.6336 - acc: 0.6349 - binary_crossentropy: 0.6336 - val_loss: 0.5118 - val_acc: 0.8349 - val_binary_crossentropy: 0.5118
Epoch 2/20
 - 7s - loss: 0.4848 - acc: 0.7913 - binary_crossentropy: 0.4848 - val_loss: 0.3582 - val_acc: 0.8785 - val_binary_crossentropy: 0.3582
Epoch 3/20
 - 5s - loss: 0.3747 - acc: 0.8632 - binary_crossentropy: 0.3747 - val_loss: 0.3021 - val_acc: 0.8882 - val_binary_crossentropy: 0.3021
Epoch 4/20
 - 4s - loss: 0.2978 - acc: 0.8969 - binary_crossentropy: 0.2978 - val_loss: 0.2791 - val_acc: 0.8865 - val_binary_crossentropy: 0.2791
Epoch 5/20
 - 5s - loss: 0.2509 - acc: 0.9136 - binary_crossentropy: 0.2509 - val_loss: 0.2811 - val_acc: 0.8858 - val_binary_crossentropy: 0.2811
Epoch 6/20
 - 7s - loss: 0.2168 - acc: 0.9277 - binary_crossentropy: 0.2168 - val_loss: 0.2903 - val_acc: 0.8854 - val_binary_crossentropy: 0.2903
Epoch 7/20
 - 8s - loss: 0.1900 - acc: 0.9368 - binary_crossentropy: 0.1900 - val_loss: 0.3101 - val_acc: 0.8832 - val_binary_crossentropy: 0.3101
Epoch 8/20
 - 8s - loss: 0.1656 - acc: 0.9456 - binary_crossentropy: 0.1656 - val_loss: 0.3192 - val_acc: 0.8840 - val_binary_crossentropy: 0.3192
Epoch 9/20
 - 8s - loss: 0.1520 - acc: 0.9488 - binary_crossentropy: 0.1520 - val_loss: 0.3468 - val_acc: 0.8814 - val_binary_crossentropy: 0.3468
Epoch 10/20
 - 7s - loss: 0.1376 - acc: 0.9524 - binary_crossentropy: 0.1376 - val_loss: 0.3632 - val_acc: 0.8808 - val_binary_crossentropy: 0.3632
Epoch 11/20
 - 4s - loss: 0.1230 - acc: 0.9580 - binary_crossentropy: 0.1230 - val_loss: 0.3925 - val_acc: 0.8796 - val_binary_crossentropy: 0.3925
Epoch 12/20
 - 5s - loss: 0.1120 - acc: 0.9611 - binary_crossentropy: 0.1120 - val_loss: 0.4139 - val_acc: 0.8791 - val_binary_crossentropy: 0.4139
Epoch 13/20
 - 6s - loss: 0.1025 - acc: 0.9632 - binary_crossentropy: 0.1025 - val_loss: 0.4263 - val_acc: 0.8769 - val_binary_crossentropy: 0.4263
Epoch 14/20
 - 4s - loss: 0.0960 - acc: 0.9658 - binary_crossentropy: 0.0960 - val_loss: 0.4587 - val_acc: 0.8750 - val_binary_crossentropy: 0.4587
Epoch 15/20
 - 4s - loss: 0.0876 - acc: 0.9680 - binary_crossentropy: 0.0876 - val_loss: 0.4755 - val_acc: 0.8755 - val_binary_crossentropy: 0.4755
Epoch 16/20
 - 5s - loss: 0.0842 - acc: 0.9687 - binary_crossentropy: 0.0842 - val_loss: 0.4955 - val_acc: 0.8747 - val_binary_crossentropy: 0.4955
Epoch 17/20
 - 4s - loss: 0.0808 - acc: 0.9702 - binary_crossentropy: 0.0808 - val_loss: 0.5094 - val_acc: 0.8769 - val_binary_crossentropy: 0.5094
Epoch 18/20
 - 5s - loss: 0.0787 - acc: 0.9700 - binary_crossentropy: 0.0787 - val_loss: 0.5444 - val_acc: 0.8757 - val_binary_crossentropy: 0.5444
Epoch 19/20
 - 5s - loss: 0.0744 - acc: 0.9712 - binary_crossentropy: 0.0744 - val_loss: 0.5404 - val_acc: 0.8730 - val_binary_crossentropy: 0.5404
Epoch 20/20
 - 7s - loss: 0.0739 - acc: 0.9715 - binary_crossentropy: 0.0739 - val_loss: 0.5570 - val_acc: 0.8724 - val_binary_crossentropy: 0.5570

drop out을 적용한, dpt_model을 구성하였다.

각각의 레이어 다음에 0.5만큼의 drop out을 하도록 설정하였다.

dpt_model 또한 기준 모델과 비교해본다.

In [60]:
plot_history([('baseline', baseline_history),
              ('dropout', dpt_model_history)])

이렇게, 우리는 overfitting을 해결하기 위해 정규화와, 드랍아웃 두가지를 살펴보았다.

이 외에도 아래와 같은 방법을로 overfitting을 해소할 수 있다.

  • Get more training data.
  • Reduce the capacity of the network.
  • Add weight regularization.
  • Add dropout.

tensorflow 튜토리얼의 overfitting and underfitting의 문서는 위의 내용까지이다.

추가적으로 L2정규화와, 드랍아웃을 함께 적용한 모델을 만들고 테스트 해보았다.

In [61]:
l2_dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

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

l2_dpt_model_history = l2_dpt_model.fit(train_data, train_labels,
                                epochs=20,
                                batch_size=512,
                                validation_data=(test_data, test_labels),
                                verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 8s - loss: 0.6572 - acc: 0.6607 - binary_crossentropy: 0.6204 - val_loss: 0.5217 - val_acc: 0.8572 - val_binary_crossentropy: 0.4884
Epoch 2/20
 - 7s - loss: 0.4884 - acc: 0.8236 - binary_crossentropy: 0.4540 - val_loss: 0.3850 - val_acc: 0.8816 - val_binary_crossentropy: 0.3488
Epoch 3/20
 - 8s - loss: 0.3984 - acc: 0.8780 - binary_crossentropy: 0.3599 - val_loss: 0.3424 - val_acc: 0.8878 - val_binary_crossentropy: 0.3015
Epoch 4/20
 - 7s - loss: 0.3490 - acc: 0.8994 - binary_crossentropy: 0.3059 - val_loss: 0.3301 - val_acc: 0.8874 - val_binary_crossentropy: 0.2848
Epoch 5/20
 - 7s - loss: 0.3162 - acc: 0.9143 - binary_crossentropy: 0.2684 - val_loss: 0.3309 - val_acc: 0.8865 - val_binary_crossentropy: 0.2806
Epoch 6/20
 - 7s - loss: 0.2951 - acc: 0.9214 - binary_crossentropy: 0.2429 - val_loss: 0.3382 - val_acc: 0.8872 - val_binary_crossentropy: 0.2840
Epoch 7/20
 - 7s - loss: 0.2763 - acc: 0.9281 - binary_crossentropy: 0.2201 - val_loss: 0.3501 - val_acc: 0.8837 - val_binary_crossentropy: 0.2922
Epoch 8/20
 - 7s - loss: 0.2663 - acc: 0.9337 - binary_crossentropy: 0.2065 - val_loss: 0.3682 - val_acc: 0.8826 - val_binary_crossentropy: 0.3066
Epoch 9/20
 - 7s - loss: 0.2606 - acc: 0.9355 - binary_crossentropy: 0.1975 - val_loss: 0.3688 - val_acc: 0.8818 - val_binary_crossentropy: 0.3043
Epoch 10/20
 - 7s - loss: 0.2468 - acc: 0.9412 - binary_crossentropy: 0.1811 - val_loss: 0.3903 - val_acc: 0.8787 - val_binary_crossentropy: 0.3231
Epoch 11/20
 - 8s - loss: 0.2433 - acc: 0.9438 - binary_crossentropy: 0.1746 - val_loss: 0.4041 - val_acc: 0.8788 - val_binary_crossentropy: 0.3340
Epoch 12/20
 - 8s - loss: 0.2386 - acc: 0.9456 - binary_crossentropy: 0.1674 - val_loss: 0.4017 - val_acc: 0.8767 - val_binary_crossentropy: 0.3291
Epoch 13/20
 - 8s - loss: 0.2349 - acc: 0.9481 - binary_crossentropy: 0.1615 - val_loss: 0.4302 - val_acc: 0.8774 - val_binary_crossentropy: 0.3557
Epoch 14/20
 - 7s - loss: 0.2293 - acc: 0.9500 - binary_crossentropy: 0.1538 - val_loss: 0.4414 - val_acc: 0.8772 - val_binary_crossentropy: 0.3648
Epoch 15/20
 - 8s - loss: 0.2261 - acc: 0.9516 - binary_crossentropy: 0.1487 - val_loss: 0.4367 - val_acc: 0.8774 - val_binary_crossentropy: 0.3582
Epoch 16/20
 - 7s - loss: 0.2263 - acc: 0.9516 - binary_crossentropy: 0.1471 - val_loss: 0.4329 - val_acc: 0.8755 - val_binary_crossentropy: 0.3529
Epoch 17/20
 - 7s - loss: 0.2254 - acc: 0.9534 - binary_crossentropy: 0.1448 - val_loss: 0.4579 - val_acc: 0.8750 - val_binary_crossentropy: 0.3768
Epoch 18/20
 - 8s - loss: 0.2202 - acc: 0.9548 - binary_crossentropy: 0.1386 - val_loss: 0.4616 - val_acc: 0.8748 - val_binary_crossentropy: 0.3797
Epoch 19/20
 - 7s - loss: 0.2215 - acc: 0.9546 - binary_crossentropy: 0.1393 - val_loss: 0.4714 - val_acc: 0.8759 - val_binary_crossentropy: 0.3889
Epoch 20/20
 - 8s - loss: 0.2199 - acc: 0.9564 - binary_crossentropy: 0.1370 - val_loss: 0.4605 - val_acc: 0.8749 - val_binary_crossentropy: 0.3772
In [62]:
plot_history([('baseline', baseline_history),
              ('L2 with dropout', l2_dpt_model_history)])

위와 같이 보다 좋은 결과를 확인할 수 있었다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.


최근 멋쟁이 사자처럼 6기 운영진으로 활동하며, 지난 8월말에 해커톤을 진행하였습니다.

저는 방학간 파이썬, 장고 스터디를 진행하며 함께 공부한 친구들과 장고를 활용한 공유일기장 플랫폼 웹사이트를 개발하였습니다.


aws ec2 프리티어을 이용하여 배포까지 완료하였으나, 실제로 서비스 론칭등의 계획은 없습니다.

장고를 직접 활용해보고 6기 인원들에게는 배포까지 해보는 경험으로써의 토이 프로젝트였습니다.


활용된 스택은 다음과 같습니다.


python: 3.6.5


django: 2.0


postgresql: 10.4



해당 프로젝트에서 저는, 프로젝트 전체 기획 및 진행을 담당하며 세부적으로는 데이터베이스 설계 및 구축, 교환일기장 기능 개발을 담당하였습니다.



- 서비스 소개


카카오톡 소셜 로그인



장고를 활용한 공유일기장 플랫폼에서는 카카오톡 소셜로그인을 통해 누구나 쉽게 서비스를 이용할 수 있도록 개발하였습니다.



메인화면 달력 및 작성한 일기 확인하기


사용자는 메인화면에서 달력을 확인할 수 있고, 그 전에 작성한 일기들은 해당 요일에 제목이 표시됩니다. 제목을 누르면 해당 일기로 이동할 수 있습니다.



일기 작성하기


사용자는 일기 쓰기 탭을 눌러서 일기를 작성할 수 있습니다.

제목, 작성할 교환일기장, 감정, 날씨, 사진, 내용을 입력합니다.

하나라도 작성되지 않을시에는 저장되지 않고 빈칸을 알려줍니다.



교환일기장


교환일기장에서는 개인이 작성한 일기 뿐아니라 다른 사람의 일기를 확인할 수 있습니다. 관심사가 같거나, 친구들끼리 함께 일기를 작성하고 싶을때는 교환일기장을 만들거나, 참여하여 함께 일기를 작성할 수 있습니다.



이 외에도 일기를 보관할 수 있는 '뜯어가기' 기능과 댓글기능 등을 구현하였습니다.



배포된 프로젝트의 모든 코드는 아래 깃헙에서 확인하실 수 있습니다.

https://github.com/doorBW/LAN-Diary


이 외에도 추가적인 질문등은 언제든지 댓글 및 이메일, 카카오톡을 이용해주세요 :)

블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc

3_Regression


안녕하세요. 문범우입니다.

이번 포스팅은 텐서플로우의 튜토리얼 세번째 내용, Regression에 대한 내용입니다.


In [2]:
# TensorFlow and tf.keras
# 텐서플로우와 keras를 import한다. 이떄 tensorflow는 tf라는 별칭으로 사용할 것임.
import tensorflow as tf
from tensorflow import keras

# Helper libraries
# numpy와 matplotlib을 사용한다.
import numpy as np
import matplotlib.pyplot as plt
# jupyter notebook에서 matplotlib을 사용하기 위한 매직커맨드
%matplotlib inline

print("사용되는 tensorflow의 버전:",tf.__version__)
사용되는 tensorflow의 버전: 1.9.0

Regression 이란?

Regression(회귀분석)이란, 관찰되는 연속형 변수들에 대해서 두 변수 사이의 모형을 구한뒤 그 적합도를 측정하는 분석 방식이다.

ㄱ. 데이터 준비

tensorflow를 이용하여 데이터를 다운 받고 데이터를 섞어준다.(shuffle)

이후 데이터를 확인해보는데 이전과 다른점은, 그전보다 데이터의 개수가 훨씬 적다.

실제로 확인해보면 이번 실습에서 사용되는 데이터의 개수는 전체 506개이다.

In [8]:
boston_housing = keras.datasets.boston_housing

(train_data, train_labels), (test_data, test_labels) = boston_housing.load_data()

# Shuffle the training set
order = np.argsort(np.random.random(train_labels.shape))
train_data = train_data[order]
train_labels = train_labels[order]
In [9]:
print("Training set: {}".format(train_data.shape))  # 404 examples, 13 features
print("Testing set:  {}".format(test_data.shape))   # 102 examples, 13 features
Training set: (404, 13)
Testing set:  (102, 13)
In [10]:
train_data[0]
Out[10]:
array([7.8750e-02, 4.5000e+01, 3.4400e+00, 0.0000e+00, 4.3700e-01,
       6.7820e+00, 4.1100e+01, 3.7886e+00, 5.0000e+00, 3.9800e+02,
       1.5200e+01, 3.9387e+02, 6.6800e+00])

위와 같이 하나의 데이터는 총 13개의 특징을 가지고 있다.

각 특징이 나타내는 의미는 다음과 같다.

  1. Per capita crime rate.(1인당 범죄율)

  2. The proportion of residential land zoned for lots over 25,000 square feet.(25,000 평방 피트가 넘는 지역에 거주하는 토지의 비율.)

  3. The proportion of non-retail business acres per town.(마을 당 비 소매 사업 에이커의 비율.)

  4. Charles River dummy variable (= 1 if tract bounds river; 0 otherwise).(Charles River 더미 변수 (강이 경계에 있으면 1, 그렇지 않으면 0).)

  5. Nitric oxides concentration (parts per 10 million).(질소 산화물 농도 (1000 만 분당).)

  6. The average number of rooms per dwelling.(주거 당 평균 객실 수.)

  7. The proportion of owner-occupied units built before 1940.(1940 년 이전에 건설 된 소유 점령 단위의 비율.)

  8. Weighted distances to five Boston employment centers.(5 개의 보스턴 고용 센터에 가중치 적용.)

  9. Index of accessibility to radial highways.(방사형 고속도로 접근성 지수.)

  10. Full-value property-tax rate per $10,000.($ 10,000 당 부당한 재산세 비율.)

  11. Pupil-teacher ratio by town.(마을 별 학생 - 교사 비율.)

  12. 1000 (Bk - 0.63) ** 2 where Bk is the proportion of Black people by town.(1000 (Bk - 0.63) ** 2 여기서 Bk는 도시 별 흑인 비율입니다.)

  13. Percentage lower status of the population.(인구의 낮은 지위의 백분율.)

위와 같은 데이터들은 서로 다른 범위를 가지고 있다.

어떤 데이터는 0,1 의 범위를, 어떤 데이터는 1~12의 범위를, 어떤 데이터는 0~100의 범위를 가지고 있다.

실제 데이터들은 위와 같이 서로 다른 범주를 갖는 경우가 많은데, 이를 잘 분석하고 탐색하는 것은 중요한 기술이다.

먼저 pandas를 이용해서 입력데이터를 column name과 함께 살펴본다.

In [11]:
import pandas as pd

column_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
                'TAX', 'PTRATIO', 'B', 'LSTAT']

df = pd.DataFrame(train_data, columns=column_names)
df.head()
Out[11]:
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
0 0.07875 45.0 3.44 0.0 0.437 6.782 41.1 3.7886 5.0 398.0 15.2 393.87 6.68
1 4.55587 0.0 18.10 0.0 0.718 3.561 87.9 1.6132 24.0 666.0 20.2 354.70 7.12
2 0.09604 40.0 6.41 0.0 0.447 6.854 42.8 4.2673 4.0 254.0 17.6 396.90 2.98
3 0.01870 85.0 4.15 0.0 0.429 6.516 27.7 8.5353 4.0 351.0 17.9 392.43 6.36
4 0.52693 0.0 6.20 0.0 0.504 8.725 83.0 2.8944 8.0 307.0 17.4 382.00 4.63

입력 데이터에 따른 label은 house price(thousands of dollars) 이다.

In [12]:
print(train_labels[0:10])  # Display first 10 entries
[32.  27.5 32.  23.1 50.  20.6 22.6 36.2 21.8 19.5]

ㄴ. 데이터 정규화

위에서 언급한 바와 같이 범위 등이 서로 다른 데이터들은 정규화를 시켜주는 것이 좋다.

각 특징에 대해 특징의 평균을 빼고 표준편차로 나누어준다.

정규화 없이도 모델이 훈련될 수 있지만, 정규화 되지 않은 데이터들은 훈련을 보다 어렵게 할 수 있으며

심지어 모델이 입력되는 데이터의 단위에 의존하게 될 수 있다.

In [15]:
# Test data is *not* used when calculating the mean and std.

mean = train_data.mean(axis=0)
std = train_data.std(axis=0)
train_data = (train_data - mean) / std
test_data = (test_data - mean) / std # test_data도 train_data의 평균과 표준편차를 이용한다.

print(train_data[0])  # First training sample, normalized
[-0.39725269  1.41205707 -1.12664623 -0.25683275 -1.027385    0.72635358
 -1.00016413  0.02383449 -0.51114231 -0.04753316 -1.49067405  0.41584124
 -0.83648691]

ㄷ. 모델 만들기

우리는 sequential 모델을 사용하여 두개의 dense layer를 연결한다.

그리고 최종 출력에서는 하나의 값을 반환하도록 한다.

In [16]:
def build_model():
  model = keras.Sequential([
    keras.layers.Dense(64, activation=tf.nn.relu, 
                       input_shape=(train_data.shape[1],)),
    keras.layers.Dense(64, activation=tf.nn.relu),
    keras.layers.Dense(1)
  ])

  optimizer = tf.train.RMSPropOptimizer(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae'])
  return model

model = build_model()
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 64)                896       
_________________________________________________________________
dense_1 (Dense)              (None, 64)                4160      
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 65        
=================================================================
Total params: 5,121
Trainable params: 5,121
Non-trainable params: 0
_________________________________________________________________

ㄹ. 모델 훈련하기

총 500epochs를 진행하며 각 epoch마다 dot을 통해 표시하도록 한다.

훈련에 대한 것은 history 개체에 저장한다.

In [17]:
# Display training progress by printing a single dot for each completed epoch.
class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self,epoch,logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 500

# Store training stats
history = model.fit(train_data, train_labels, epochs=EPOCHS,
                    validation_split=0.2, verbose=0,
                    callbacks=[PrintDot()])
....................................................................................................
....................................................................................................
....................................................................................................
....................................................................................................
....................................................................................................

history개체에 저장한 것을 그래프로 살펴본다.

In [18]:
def plot_history(history):
  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [1000$]')
  plt.plot(history.epoch, np.array(history.history['mean_absolute_error']), 
           label='Train Loss')
  plt.plot(history.epoch, np.array(history.history['val_mean_absolute_error']),
           label = 'Val loss')
  plt.legend()
  plt.ylim([0,5])

plot_history(history)