TigerCow.Door


이전글

#1_블록체인 무엇인가::소프트웨어 시스템 아키텍처

#2_블록체인 무엇인가::분산 P2P 시스템



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

지난번 포스팅을 통해 분산 P2P 시스템에 대해서 알아보고, 실제로 많은 사람들이 사용하는 토렌트 서비스를 통해서 이해해 보았습니다.

그럼 이번 포스팅에서는 이러한 분산 P2P 시스템을 왜 아직 많은 곳에서 사용하지 않는지, 그리고 그것을 블록체인이 어떻게 해결해 줄 수 있는지에 대해서 알아보며 블록체인에 대해 정의를 내려보도록 하겠습니다.


1. 순수 분산 P2P 시스템의 지속 가능성


사실 우리는 두번째 포스팅에서 순수 분산 P2P 시스템이 산업 전체를 뒤바꿀 수 있을 만큼 강력한 잠재력을 지니고 있다고 알아보았습니다. 그런데 왜 아직 많은 곳에서 사용되지 않는 것 일까요?

즉, 순수 분산 P2P 시스템이 산업 전반에 사용되기 위하여 해결해야 할 주요과제는 무엇일까요?


P2P 시스템에 대한 지속 가능성은 우리가 첫번째 포스팅에서 알아보았던 개념, 신뢰와 무결성에 달려 있습니다.

소프트웨어 시스템의 관점에서 무결성은 시스템의 안전성, 완결성, 일관성, 정확성 및 변형과 오류 없음을 의미하는 비기능적 측면이고, 신뢰란 별도의 증거나 증명 또는 조사 과정 없이도 누군가 또는 무엇인가의 신뢰성, 진실성, 능력을 믿어주는 확고한 신념을 의미합니다.


즉, 사용자들은 P2P 시스템에 대해 일단 시스템에 합류를 하고 시스템에 기여합니다. 이후 지속적인 상호작용에 대한 결과가 기대했던 바와 같으면 더 큰 신뢰가 쌓여가면서 지속적으로 시스템의 구성원으로 남게 됩니다. 이렇게 사용자들의 기대를 충족시키며 시스템에 대한 신뢰를 강화시키기 위해서는 무엇보다 시스템의 무결성이 필요합니다. 

다시 말해, 시스템에 대한 무결성이 확보되지 않는다면 시스템은 사람들에게 신뢰를 잃어갈 것이며, 결국 사용자가 떠나는 문제가 발생하게 됩니다.


그렇다면, 우리가 순수 분산 P2P 시스템의 존립과 직결된 신뢰, 무결성에 대한 중요성을 이해했다면 다음과 같은 질문을 생각해볼 수 있습니다.


"순수 분산 P2P 시스템의 무결성을 확보하고 유지할 수 있는 방법은 무엇일까?"


순수 분산 P2P 시스템의 무결성을 확보하고 유지하는 일은 여러가지 요인에 달려 있지만 가장 중요한 두가지는 다음과 같습니다.


- 전체 노드 또는 피어의 개수를 아는가?

- 각 피어의 신뢰성에 대해 어느 정도 알고 있는가?


분산 P2P 시스템 내의 전체 노드 개수와 각 노드의 신뢰성을 알고 있다면 무결성을 확보할 가능성은 더 커집니다. 최악의 환경은 시스템에 참여한 노드의 개수도 모르고 각 노드의 신뢰성도 전혀 모르는 경우입니다. 모두에게 개방된 순수 P2P 시스템을 인터넷 상에서 운영하는 경우가 바로 그 최악에 해당 하는 것이죠.



2. P2P 시스템의 무결성을 위협하는 요소


그렇다면, P2P 시스템에서 우리가 중요하다고 이야기하는 무결성을 위협하는 요소는 또 무엇이 있을까요?


1. 기술적 결함

P2P 시스템은 인터넷으로 통신하는 사용자들의 개별 컴퓨터로 구성됩니다. 그런데 컴퓨터를 비롯한 모든 전자기기는 언제든지 고장이나 오류가 발생될 수 있습니다. 즉, 모든 분산 시스템에서는 개별 컴퓨터를 비롯하여 네트워크 장비 등이 고장이나 오류가 발생했을 때에 대한 대처가 가능해야 합니다.


2. 악의적 피어

P2P 시스템에서 무결성을 위협하는 두번째 요소는 악의적인 의도를 가진 사용자입니다. 이 요소는 첫번째와 같은 기술적 원인이 아니라, 시스템을 이용해 자신 개인의 이득을 취하려는 악의가 원인입니다.

부정직하고 악의적인 피어는 P2P 시스템의 근간인 신뢰성을 공격하려 하기 때문에 가장 심각한 위협 요소 입니다. 이러한 위협으로 인해 P2P 시스템 내의 사용자들이 다른 피어를 믿지 못하게 된다면 시스템을 떠나게 되고 더 이상 계산자원에 기여하지 않게 됩니다. 결국 전체 시스템 구성원이 감소되고 이로 인해 시스템의 효용성이 저하되며 또 다른 이탈자가 반복되는 악순환이 형성될 수 있습니다.



3. 블록체인, 무결성을 확보하라.


사실 위에서 이야기 한 것과 달리 최고의 상황, 최적의 상황에서 신뢰와 무결성을 확보하여 시스템을 유지하는 것은 어렵지 않습니다. 하지만 실제로 우리가 해야되는 것은 위에서 나온 것들을 바탕으로 한 최악의 조건을 가진 분산 시스템에서 신뢰와 무결성을 확보하는 점 입니다.

그리고 바로 이것이 블록체인이 해결해야 하는 과제 입니다.

즉, 블록체인이 해결해야 되는 문제는 '개수도 알려져 있지 않고 신뢰성과 안정성도 알 수 없는' 피어들로 구성된 순수 분산 P2P 시스템의 무결성을 확보하고 유지하는 것 입니다.



4. 그래서 '블록체인' 이란?


그래서 도대체 '블록체인'이 무엇일까요?

사실 블록체인은 다양한 의미로 사용될 수 있습니다.

먼저 4가지 다른 의미에 대해서 간략하게 알아보도록 하겠습니다.


1. 데이터 구조의 명칭

컴퓨터 과학이나 소프트웨어 공학에서 말하는 데이터 구조(data structure)란, 구체적인 정보나 내용과 상관없이 데이터를 정리하는 방식을 이야기 합니다. 

데이터 구조는 간단하게, 건물 설계도의 평면도 쯤으로 생각해볼 수 있습니다. 평면도는 공간의 구체적인 용도와 상관없이 벽과 바닥 그리고 계단을 사용하여 공간을 분리되기 때문 입니다.

블록체인이 데이터 구저의 명칭으로 사용될 때에는 블록이라 불리는 단위에 모인 모든 데이터를 지칭합니다. 그리고 이 블록들은 책을 구성하는 페이지들과 유사하게 마치 체인처럼 서로 연결되어 있어서 블록체인이라는 이름이 붙었습니다.


2. 알고리즘의 명칭

소프트웨어 공학에서 알고리즘(algorithm)이란 컴퓨터가 실행해야 할 일련의 명령어들을 의미합니다. 그리고 이 명령어들은 대개 데이터 구조를 포함합니다.

블록체인이 알고리즘의 명칭으로 사용될 때에는 순수 분산 P2P 시스템에서 여러 블록체인 데이터 구조 내의 정보 내용을 민주주의 투표 방식과 비슷한 방법을 써서 서로 협상하는 일련의 명렁어를 의미하는 것 입니다.


3. 기술묶음의 명칭

블록체인이 기술 묶음의 명칭으로 사용될 때에는 블록체인 데이터 구조(blockchain-data-structure), 블록체인 알고리즘(blockchain-algorithm), 암호화 및 보안 기술의 조합을 의미하게 됩니다.

이들의 조합은 응용분야와 상관없이 순수 분산 P2P 시스템의 무결성을 확보하는데 이용될 수 있습니다.


4. 일반 응용분야를 가지는 순수 분산 P2P 시스템을 포괄하는 용어

블록체인은 블록체인 기술묶음을 활용하는 거래장부들의 순수 분산 P2P 시스템을 지칭하는 포괄적인 용어로도 사용됩니다. 

즉, 순수 분산 시스템을 구성하는 한 부분인 소프트웨어의 단위를 의미를 이야기하는 것이 아니라 순수 분산 시스템 전체를 의미합니다.


그리고 우리가 이어서 블록체인에 대한 이야기를 할 때, 위에서 알아본 4가지 의미 중 4번째인, 순수 분산 P2P 시스템 전체를 의미하는 용어로 블록체인이라는 단어를 사용합니다.


그럼, 아직 중요하게 알아볼 내용들이 많지만 임시적으로 블록체인에 대한 정의를 내려보면 다음과 같습니다.


블록체인이란 무결성을 확보하고 유지하기 위해 순서에 따라 연결된 블록들의 정보 내용을 암호화 기법과 보안기술을 이용해 협상하는 알고리즘으로 구성된 소프트웨어 요소를 활용하는 원장(거래장부)의 순수 분산 P2P 시스템을 의미한다.



5. 비트코인 기술이 블록체인의 전부는 아니다.


위에서 임시적으로 정의한 내용에서 비트코인(Bitcoin)이나 암호화폐(Cryptographic money)에 대한 어떠한 언급도 존재하지 않습니다.

사실 많은 기사나 읽을거리에서 블록체인의 목적이 디지털 화폐의 소유권을 관리하기 위한 것으로 기술하고 있는데, 이렇게 암호화폐의 소유권을 관리하는 것은 아주 중요하고 자연스러운 블록체인의 응용분야 중 하나일 뿐이며 그 자체가 블록체인의 전부는 절대 아닙니다.


블록체인은 다양한 분야에 폭넓게 응용될 수 있습니다. 그럼에도 블록체인에 따라 암호화폐, 디지털화폐 등에 대한 소유권 관리 측면이 부각되는 이유는 두가지가 있습니다.

첫번째, 이해하기도 설명하기도 가장 쉽기 때문입니다.

두번째는 경제에 가장 크게 영향을 끼치는 실 사례이기 때문입니다.


블록체인을 원장(거래장부)의 분산 P2P 시스템을 관리하는 기술묶음의 용도로 활용하게 된다면 디지털 재화의 소유권 관리나 암호화폐와 같은 특별한 분야에 사용할 수 있습니다. 그러나 우리가 알아볼 때에는 이렇게 특정 분야만 고려하지 않지만, 블록체인을 더 쉽게 이해하도록 특정 재화와 상관없이 소유권을 관리하고 명료화하는 일반적인 응용 예에 대해서만 다룰 것 입니다.



이렇게 순수 분산 P2P 시스템이 유지되기 위해 필요한 점, 그리고 그것을 위협하는 요소들에 대해서 알아보고 이어서 블록체인이라는 용어에 대해 알아보며 임시적인 정의를 내려보았습니다. 그리고 비트코인 기술이 블록체인에 대해 보다 쉽게 이해하기 쉬운 사례일 뿐임을 말씀드렸습니다.

이후 포스팅에서는 우리가 블록체인에 대해 본격적으로 이해하기 위해 먼저, 소유권이라는 본질에 대해서 알아보도록 하겠습니다.

블로그 이미지

Tigercow.Door

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


이전글

#1_블록체인 무엇인가::소프트웨어 시스템 아키텍처



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

지난 첫번째 글에서 '소프트웨어 시스템 아키텍처'에 대해서 알아보았습니다. 그 중에서도 블록체인이 도구로서 활용될 분산 시스템에 대해서 주로 알아보았습니다.

그리고 이번 포스팅에서는 분산 시스템 중에서도 특수한 형태로 나타난 '분산 P2P 시스템'에 대해서 알아보도록 하겠습니다.




1. 분산 P2P 시스템이란


피어 투 피어(peer - to - peer) 시스템은 분산 시스템의 특수한 형태입니다. P2P 시스템에서는 개별 컴퓨터(노드)로 구성되어 있으며 분산 시스템이기 때문에 중앙 노드의 조정 없이 네트워크의 모든 구성원이 서로에게 계산 자원을 제공합니다.

무엇보다 중요한 것은 네트워크 상에서 각 노드는 시스템 내에서 동등한 권리와 역할을 가집니다. 즉, 모든 노드가 자원의 공급자인 동시에 소비자가 됩니다.

쉽게 생각해보면 많은 사람들이 사용하고 있는 '토렌'를 생각해볼 수 있습니다.

토렌트또한 개방형 P2P 시스템으로써, 동일한 네트워크에 참여한 모든 노드가 소비자로서, 피어의 역할을 하게 되며 공급자로서 시드의 역할도 하게 됩니다.


추가로 보다 세부적인 내용에 대한 설명은 아래 블로그들을 참고하시면 좋을 것 같습니다. 아무래도 블록체인과 토렌트의 네트워크 방식이 동일하기 때문에 관련되어 설명하는 부분들이 많습니다. 만약 블록체인과 관련된 내용에 대해 이해하기 어렵다면 무시하시고, 토렌트에서 사용되는 P2P 네트워크에 대해서만 이런거구나 하는 느낌으로 이해하시면 좋을 것 같습니다.

토렌트를 알아보자

토렌트 개념잡기

토렌트와 블록체인


그 내용을 대략적으로 이해해본다면, P2P 네트워크 상에는 더 많은 사용자가 네트워크에 참여할수록 네트워크는 더 거대해지고 더 강력해집니다. 토렌트를 사용해보신분들도 있겠지만 많은 사람들이 다운받으려고 하는 최신 파일을 다운 받을때는 정말 빠른 속도로 다운받을 수 있죠.(물론 우리나라에서는 저작권등의 문제로 불법입니다!)

하지만 토렌트의 단점으로는 오래되거나 사람들에게 관심없는 파일의 경우에는 파일의 조각을 공급해주는 시더가 없기 때문에 다운받는 속도가 느립니다. 그리고 이것이 블록체인과 토렌트의 차이이기도 합니다. 추후에도 알아보겠지만 블록체인에서는 이러한 문제를 막기위해, 시더의 존재를 유지하기 위해 '채굴'이라는 개념이 존재합니다.



2. P2P 네트워크의 잠재력


사실 P2P 네트워크는 과거에도 존재했으며, 특정 산업에 대한 변화도 이끌어내었습니다. 대표적인 것은 바로 음악산업입니다.

요즘은 음악을 듣기 위해 CD를 사기보다 MP3 파일을 공유하는 스트리밍 서비스를 주로 이용합니다. 이런 변화는 사람들이 각자 가지고 있는 음악 파일을 서로 공유할 수 있는 소프트웨어의 등장으로 가능해졌습니다. 그리고 그것의 시작은 냅스터(Napster) 서비스 이었으며 냅스터의 공동 창업자 숀 패닝(Shawn Fanning)은 다음과 같은 말을 하였습니다.

"이 시스템의 어떤 점이 그렇게 흥미로운가 하면, 바로 동료들과 상호작용한다는 점이다. 길거리 사람들 그 누구와도 서로 정보를 주고받을 수 있다."


음악산업은 과거에 다음과 같이 작동하였습니다. 먼저 음악가와 스튜디오가 계약을 맺습니다. 계약이 성사된 후에, 스튜디오는 음악가의 노래를 녹음하고 CD와 테이프와 같은 다양한 매체에 담아서 이를 판매하였습니다. 즉, 스튜디오는 결국 음악가와 음악을 듣고자하는 소비자 사이에서 중개자 역할을 수행하였습니다.

이렇게 스튜디오가 중개자 역할을 할 수 있었던 이유는 음반 제작, 마케팅, 판매채널등에 대한 전문적인 지식을 보유하였기 때문입니다. 그러나 2000년 이후에 스튜디오 환경은 급격히 변화되었습니다.

음악의 디지털화, 저렴한 녹음시설 및 개인 PC의 보급, 인터넷의 등장은 사실상 음악 스튜디오가 사람들에게 필요없게 된 배경입니다. 이전에 스튜디오가 주로 하던 음반 제작, 마케팅, 판매채널에 대한 전문적인 지식의 장벽이 낮아짐에 따라 작곡가나 소비자 스스로가 해결할 수 있게 되었기 때문이죠.

즉, 냅스터는 중개자로서의 음악 스튜디오를 대체하는데 주된 역할을 수행한 것입니다.

냅스터의 등장으로 음악을 듣고자 하는 소비자들은 CD를 구입하지 않아도 최신 인기곡을 들을 수 있게 되었고, 다양한 사람들과 음악 파일을 공유할 수 있게 되었습니다. 스튜디오 산업에는 큰 타격을 입히게 되었지만 결국적으로 음악 소비자들은 이전에 경험하지 못한 폭넓은 음악 세계를 접하게 되었습니다.


이와 같이 P2P 네트워크는 거의 모든 산업을 뒤흔들 잠재력을 가지고 있습니다.

최소한 무형의 상품이나 디지털화 된 상품 또는 서비스를 중개하는 역할을 주업으로 하는 산업은 거의 모두 P2P로 대체될 가능성이 높은 것이죠. 그리고 우리 주변에 이런 종류의 산업중 가장 크게 다가오는 것은 금융업입니다.


은행계좌나 신용카드, 직불카드에 들어있는 것은 결국 무형의 비트와 바이트, 즉 디지털 정보입니다. 즉 이 세상의 대부분의 돈과 자산은 무형의 비트와 바이트 형태로 금융회사의 중앙 정보 기술 시스템에 저장되어 있습니다.

은행을 비롯한 금융계의 많은 회사들은 돈과 재산을 나타내는 비트와 바이트를 생산하고 소비하는 사람들 사이를 단순히 이어주는 중개자 역할을 주로 수행합니다. 우리가 돈을 빌리고, 빌려주는 등의 행위는 사실 중개자가 무형의 상품을 시스템 속에서 대상자에게 전달함으로 이루어집니다. 실질적으로 이용하는 우리는 느끼지 못하지만 간단한 거래하나에도 많은 중개자가 관여하게 됩니다.

'블록체인 무엇인가?'의 책에서 이야기하기로는 국가간의 은행 자금이체의 과정에서는 5개의 중개기관이 관여하게 되며 각 처리단계마다 일정 시간이 소요되며 해당 비용을 청구하게 됩니다. 하지만 P2P 거래에서는 동일한 행위가 훨씬 간단하며 시간과 비용도 거의 들지 않습니다.


즉, 중앙 통제 시스템과 비교하여 P2P 시스템이 가진 장점으로는, 중개자를 통해 간접적으로 상호작용하지 않고 거래 당사자끼리 직접 상호작용한다는 점이며 그 과정속에서 처리 시간과 비용이 현저하게 줄어든다는 점 입니다.



3. P2P 시스템과 블록체인의 연관성


그래서, 이렇게 좋은 P2P 시스템과 우리가 알고자하는 블록체인은 정말 무슨 연관이 있는 것 일까요?

다시한번 P2P 시스템에 대해 결론을 내려보면서 블록체인과의 연관성을 알아보겠습니다.


1. P2P 시스템의 정의

P2P 시스템은 여러 노드(개별 컴퓨터)로 구성된 분산 소프트웨어 시스템으로, 한 노드의 자원(계산 능력, 저장 공간, 정보 배분 등)을 다른 노드들이 직접적으로 사용할 수 있다는 특징을 가집니다. 따라서 모든 사용자의 컴퓨터는 자원의 공급자인 동시에 소비자가 됩니다.


2. P2P 시스템의 아키텍처

P2P 시스템은 구조 자체가 분산 컴퓨터 시스템으로 되어 있습니다. 하지만 여전히 중앙 통제 요소를 가지는 P2P 시스템도 존재합니다. 중앙 통제 P2P 시스템은 중앙 노드를 이용하여 노드 간 상호작용을 중재하고, 피어 노드가 제공하는 서비스 목록들을 유지 관리하고 노드를 검색하며 식별합니다. 이러한 중앙 통제 P2P 시스템의 대표적인 예는 위에서 이야기한 냅스터입니다. 냅스터는 중앙 데이터베이스에 접속한 모든 노드와 각 노드가 보유한 노래 정보를 저장하고 있습니다.

반면 순수 분산 P2P 시스템에는 중앙에서 통제하거나 조정하는 어떠한 요소도 없습니다. 따라서 시스템의 모든 노드는 동일한 과제를 수행하며, 자원과 서비스의 생산자인 동시에 소비자 역할을 수행합니다.


3. P2P 시스템과 블록체인의 연관성

결론부터 이야기하면, 블록체인은 분산 시스템에서 무결성을 확보하고 유지하는 도구입니다. 즉 순수 분산 P2P 시스템은 무결성의 확보와 유지를 위해 블록체인을 도구로서 활용합니다.


즉, 사람들은 전체 산업을 통째로 뒤바꿀 수 있는 장점을 가진 순수 분산 P2P 시스템이 블록체인을 활용하여 무결성을 확보하고 유지할 수 있다는 점 때문에 블록체인에 대해 열광합니다. 그러나 엄밀히 이야기하면 사람들을 정말로 흥분시킨 요소는 '탈중개화'입니다. 즉, 블록체인은 단지 탈중개화를 위한 도구일 뿐입니다.


다시 한번 정리한다면, 사람들이 블록체인에 열광하는 이유는 탈중개화를 통해 전체 산업 생태계를 변화시킬 잠재력을 지닌 순수 분산 P2P시스템이 무결성의 확보와 유지를 위한 도구로 블록체인을 사용할 수 있기 때문입니다.



이렇게 해서 분산 P2P 시스템에 대해서 알아보았습니다.

다음 포스팅에서는 본격적으로 블록체인에 대해서 포커싱을 두며 '왜 우리에게 블록체인이 필요한가', 즉 블록체인이 해결해야 하는 문제점들과 그 문제점을 해결하는 것이 왜 중요한지등을 알아보며 이야기를 해보겠습니다.

추가적으로 궁금하거나 의문이 드는 점, 잘못된 내용들에 대한 피드백은 언제든지 댓글이나 메일, 카톡을 통해서 말씀해주시면 감사하겠습니다.



블로그 이미지

Tigercow.Door

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



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

앞으로 몇회에 걸쳐서 블록체인에 대한 기초적인 내용을 정리해보려 합니다.

단순히 자료를 수집해서 정리해보기에는 아직 제 스스로도 개념적으로 부족한 부분들이 많아서, 다니엘 드레셔 지음, 이병욱 옮김의 '블록체인 무엇인가?' 라는 책을 기반으로 하려 합니다.


정리의 순서가 책의 순서와 비슷할 것이며, 책을 보면서 좀 더 궁금한 내용 같은 부분은 온라인을 통해 공부해가며 추가하여 정리하려 합니다.


궁금하거나 건의사항이 있으신 분은 언제든지 댓글 또는 이메일, 카톡을 통해서 연락주시면 감사하겠습니다.


블록체인을 위한 기초


이번 글에서는 블록체인을 이해하기 위한 기초로써, 소프트웨어 아키텍처에 대해 알아보면서 블록체인이 달성하고자 하는 것에 대해서 함께 알아보도록 하겠습니다.


1. 소프트웨어 아키텍처


소프트웨어 아키텍처를 알아보기 이전에 시스템 자체를 개념적으로 분리하기 위해 사용되는 구분 기준이 있습니다. 크게 두가지로 나뉘어지는데 다음과 같습니다.


1. 응용계층 - 구현계층

2. 기능적 측면 - 비기능적 측면


먼저 응용계층과 구현계층에 대해서 알아봅니다.

사용자의 요구사항과 시스템의 기술 구조를 구분하여 생각해보면 이 둘을 나누어 생각할 수 있습니다.

즉, 응용계층은 사용자의 요구사항, 사용자의 필요와 연관됩니다.

반면에 구현계층은 이러한 요구사항을 실현하는 것 입니다. 즉 구현계층의 구성요소는 본질적으로 기술적이며, 목적 달성을 위한 수단으로 생각될 수 있습니다.


두번째로 기능적 측면과, 비기능적 측면에 대해서 알아보겠습니다.

먼저 기능적 측면은 '시스템이 무엇을 하는가'로 구분되며 비기능적 측면은 '그 무엇을 어떤 식으로 하는가'로 구분됩니다. 

해당 부분이 헷갈릴 수 있기 때문에 핸드폰을 예로 들어 생각해본다면, 기능적 측면으로는 음악 청취, 사진 촬영, 사진의 개별 픽셀 조작 등이 있으며 비기능적 측면으로는 멋진 UI, 실행속도가 빠른 소프트웨어, 사용자 데이터 보호와 저장능력 등이 있습니다. 또한 비기능적 측면에서 중요시 되는 것은 보안과 무결성입니다. 여기서 무결성은 시스템이 의도한 대로 작동하는 것을 의미합니다. 무결성은 보안과 정확성을 포함한 개념이기도 합니다.


이렇게 두가지로 나누어 본 개념들을 함께 고려하여 핸드폰을 예시로 생각해본다면 다음 표와 같습니다.


 

 기능적 측면

 비기능적 측면

 응용 계층

 사진 촬영

 전화 걸기

 이메일 보내기

 인터넷 검색

 문자 메시지 보내기

 보기 좋은 UI

 사용 편의성

 빠른 메시지 전송

 구현 계층

 사용자 데이터 저장

 가장 가까운 모바일 커넥터에 연결

 디지털 카메라의 픽셀에 접근

 효율적인 데이터 저장

 에너지 절약

 무결성 관리

 개인정보 보호


이렇게 응용계층과 구현계층, 기능적 측면과 비기능적 측면으로 핸드폰이라는 시스템을 분리하여 생각해보았습니다.

이중에서 구현 계층의 비기능적 측면인 무결성 관리에 대해서 한번 더 알아보겠습니다.


무결성이란 모든 소프트웨어 시스템이 가지는 중요한 비기능적 측면으로 주로 다음과 같은 세가지 구성요소로 이루어집니다.


데이터 무결성: 시스템에서 사용하고 유지 관리하는 데이터는 완전하고 정확하며 모순이 없다.

작동 무결성: 시스템은 의도한 대로 작동하며 논리적 오류가 없다.

보안: 시스템은 허가받은 사용자에게만 데이터 및 기능에 대한 접근 권한을 부여할 수 있다.


실제로 많은 소프트웨어 이용자들은 무결성이라는 개념을 당연시하게 여깁니다. 그들이 사용하는 소프트웨어들이 다행히 무결성을 잘 지키고 있기 때문입니다. 하지만 실제로 이러한 무결성을 개념을 잘 지키기 위해서 개발자들에 대한 노력은 매우 크게 필요합니다. 만약 핸드폰에서 카카오톡을 실행시켰는데 인터넷 어플이 실행된다던지의 시스템 오류가 발생하면 안될테니까요.



2. 시스템 아키텍처


이렇게 해서 소프트웨어 아키텍처를 개념적으로 분리해서 나누어보았습니다.

이번에는 소프트웨어 아키텍처를 구현하는 다양한 방법 중에서 필수적으로 결정해야 하는 시스템 아키텍처에 대해서 알아보겠습니다.

여기서 시스템 아키텍처란, 구성요소를 구조화하고 구성요소 간 관계를 설정하는 방식을 의미합니다.

소프트웨어 시스템에 주로 사용되는 아키텍처는 크게 두가지로, 중앙 통제(Centralized) 방식과 분산(Distributed) 방식이 존재합니다.



위의 사진에서 좌측이 중앙 통제 시스템이며 우측이 분산 시스템입니다.

사진에서 확인할 수 있듯이 중앙 통제 시스템에서는 중앙의 하나의 노드(컴퓨터)가 모든 노드와 연결되어 있습니다. 반면에 분산형에서는 그렇지 않고 모든 노드가 서로 연결되어 있습니다.


이후에 보다 자세히 설명드리겠지만 실제로 현재 사회에서의 대부분의 시스템은 중앙 통제 시스템이지만, 블록체인은 분산 시스템을 가능하게 합니다.

그럼 블록체인에 앞서서, 분산 시스템 자체에 대한 장단점을 살펴보도록 하겠습니다.



3. 분산 시스템


먼저 분산 시스템의 장점에 대해서 알아보겠습니다.


1. 계산 능력이 더 뛰어나다.

분산 시스템에서의 계산 능력(Computing power)은 서로 연결된 모든 노드(컴퓨터)의 계산 능력이 합쳐져 발현됩니다. 즉, 분산 시스템에서는 대부분 단일 컴퓨터보다 강력한 계산 능력을 가질 수 있게 됩니다.


2. 비용이 절감된다.

분산 시스템에서는 여러 대의 컴퓨터로 구성되기 때문에 초기 비용은 개별 컴퓨터보다 더 많이 들 수 있습니다. 하지만 슈퍼 컴퓨터 하나에 대해 유지 보수하는 비용과 비교했을 때는 분산 시스템의 비용이 더 절감됩니다.

또한 분산 시스템에서는 개별 컴퓨터가 교체될 때 전체 시스템에 큰 영향을 끼치지 않는 점까지 고려하면 더욱 그렇습니다.


3. 더 안정적이다.

위에서 짧게 이야기 했듯이 분산 시스템에서는 개별 노드(컴퓨터)가 교체될때 전체적인 시스템의 안정성에 영향을 미치지 않습니다. 하나의 구성요소가 없거나 오류가 발생되면 다른 요소가 그 일을 대신하게 되기 때문입니다.


4. 자연스럽게 확장된다.

분산 시스템에서는 더 많은 노드(컴퓨터)를 자연스럽게 확장시킬 수 있습니다. 초기부터 그러한 것을 고려되어 설계 및 운영되기 때문에 추가적인 계산 능력을 필요로 하는 등의 상황에서 추가적인 노드를 자연스럽게 추가할 수 있습니다.



이번에는 분산 시스템의 단점에 대해서 알아보도록 하겠습니다.


1. 조정 오버헤드가 발생한다.

분산 시스템에서는 구성요소들을 조정하는 중앙요소가 없습니다. 따라서 각각의 모든 요소가 스스로 조정을 해야하는데 모두가 동등한 지위를 가지고 있기 때문에 이것이 쉽지 않고 모든 요소가 조정을 하는 작업을 필요로 하기 때문에 자원이 소모되며 그로 인해 조정 오버헤드(Coordination overhead)가 발생됩니다.


2. 통신 오버헤드가 발생한다.

조정을 위해서는 서로의 통신이 필요합니다. 따라서 분산 시스템 내 모든 요소들은 서로 통신을 주고 받습니다. 이로 인해 계산 능력의 일부가 통신 프로토콜 지원과 메시지의 송수신 및 처리에 소모됩니다. 결과적으로 통신 오버헤드(Communication overhead)가 발생합니다.


3. 네트워크 의존도가 높다.

위에서 이야기 했듯이 분산 시스템에서는 모든 요소들이 통신을 하게 되며, 그 통신은 네트워크를 통하게 됩니다. 그러나 거의 모든 네트워크에는 자체적인 결함과 장애 가능성이 내재될 수 밖에 없으며 이것은 결국 분산 시스템에서의 통신과 조정에 영향을 미치게 됩니다. 그렇다고 해서 네트워크를 사용하지 않으면 통신과 조정, 노드 간 협력도 불가하기 때문에 네트워크 의존도가 높습니다.


4. 프로그램이 복잡해집니다.

앞에서 이야기 하였듯이 분산 시스템에서는 노드간 조정과 통신이 이루어집니다. 또한 네트워크적인 문제도 발생될 수 있기 때문에 이 모든 것을 해결하기 위해서 소프트웨어가 복잡해 집니다.


5. 보안에 신경써야 한다.

네트워크를 통해 자원 및 정보를 주고받게 되면 악의를 가진 개체가 접근하는 보안 문제를 고려해야 합니다. 그러므로 모든 분산 시스템은 보안에 있어 철저히 대비해야 합니다.


물론 이렇게 알아본 분산 시스템의 장점과 단점을 모은 혼합시스템도 존재합니다.

실질적인 블록체인 응용을 배우기 위해서는 이 부분을 꼭 이해해야 합니다. 혼합시스템은 크게 두가지로 존재합니다.

분산 시스템 내의 중앙 통제와 중앙 통제 시스템 내의 분산 시스템입니다.



좌측과 같은 시스템은 얼핏 보기에 모든 구성요소들이 분산 시스템을 이루는 것처럼 보이지만 사실 모든 원이 중앙의 큰 원에 직접 연결되어 있습니다. 즉 겉보기에는 분산시스템이지만 사실 중앙 통제 시스템입니다.

우측 사진은 이와 상반된 시스템을 보여줍니다.


이러한 혼합시스템에 대해서 고려하는 것은 매우 중요합니다. 이 때, 실제로 하나의 시스템이 분산 시스템인지를 파악하려면 전체 시스템을 동시에 종료할 수 있는 단일 구성요소, 즉 스위치가 있는지 살펴보면 됩니다.



이제 우리가 블록체인을 공부하기에 앞서 이러한 시스템을 왜 살펴보았는지 다시 생각해보아야 합니다.


실제로 중앙 통제 시스템과 분산 시스템은 단순히 하나의 목적을 위한 도구, 수단일 뿐 입니다. 두가지 시스템 모두 장단점이 있기에 더욱 그러합니다.

하지만 그 차이점 중에서, 앞에서 우리가 중요하게 다룬 '무결성'이라는 것에 대해서 두가지 시스템은 매우 다르게 접근합니다. 그리고 이 부분 때문에 블록체인이 중요해집니다.


블록체인은 분산 시스템이 무결성을 확보하게 해주는 도구입니다. 따라서 구현계층의 비기능적 측면을 성취하게 해주는 도구로 볼 수 있습니다.



이렇게 블록체인에 앞서, 소프트웨어 시스템에 대해 기본적인 개념을 살펴보았습니다. 다음 포스팅에서는 분산 시스템에서도 특수한 형태로 등장한 P2P 시스템에 대해서 알아보며 공부해보도록 하겠습니다.

블로그 이미지

Tigercow.Door

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

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

이번에 소개해드릴 알고리즘 문제는, 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