딥러닝 관련 논문이나 오픈된 소스를 보면서 공부한 것을 공유하고자 합니다.

  • NASA FDL 2017 연구 소개


    저희회사((주)인스페이스)에서 충남대학교 백마인턴쉽 과정으로 함께 하게된 박천용 인턴님의 첫과제로 조사한 내용을 공유드립니다. 주제는 NASA Frontier Development Lab에서 진행되고 있는 연구 소개입니다.

    img

    미국 NASA의 Frontier Development Lab (FDL)은 항공 기관인 Ames Research Center와 SETI에 의해 공동 운영 되고 있으며, 이들은 잠재적 위험성을 가지고 있는 소행성과 혜성으로부터 지구를 보호하는 방법을 연구하고자 인공지능을 이용하겠다고 발표하였습니다.

    • NASA FDL Homepage: NASA FDL
    • NASA FDL 팀의 발표영상과 프레젠테이션 자료: NASA PPT

    지난 2014년에 매년 6월 30일을 국제 소행성 날 (International Asteroid Day)로 지정하고 Near Earth Objects(NEOs)로 부터 오는 잠재적 위협에 대한 연구결과를 발표하는 연내행사를 계획하는 것으로 만들어졌습니다. 6월 30일이 선택된 이유는 1908년에 일어난 러시에 시베리아 위치한 퉁구스카에 충돌체 사건을 기념하는 날이기 때문이었기 때문입니다. 연내 기념행사는 천체물리학자이자 Queen의 리드 기타리스트인 Brian May, 그리고 영화 제작자인 Grigorij Richters의 아이디어이었습니다. NASA FDL 팀은 NASA Frontier Development Lab 2017(FDL 2017)발표를 통해 딥러닝 기반의 다양한 연구성과를 알리게 되었습니다.


    1. Solar storm prediction

    개요

    인공지능을 사용하여 플레어를 탐지하고, 우주 비행 임무에 결정적인 태양활동 및 우주 기상 현상의 중요성을 이해합니다. 태양 자기장 complexity 분석을 수행하고, 태양 UV 이미지를 연결하기 위해 multiple CNN을 배치했습니다. 이 연구는 태양 플레어 예측의 신뢰성과 정확성을 향상시킬 수 있는 잠재력이 있음을 보여줍니다.

    플레어(Flare)란?

    플레어란 태양 대기에서 발생하는, 수소폭탄 수천만 개에 해당하는 격렬한 폭발을 말합니다.

    img

    태양의 플레어는 단파장의 전자기 방사선을 발생시킵니다. 이는 상층 대기의 이온화와 가열을 초래하고, GPS와 HF의 통신에 영향을 미칩니다.

    FlareNet

    어떻게 NOAA(기상위성)가 플레어를 예상할수 있을까요? 태양 흑점 형태와 지속성, 즉 태양이 변하지 않는 다는 것을 가정합니다. FDL팀은 전문가들 보다 최소한 한시간 빠르게 플레어의 위험을 예측하는 것을 목표로 하였습니다.

    img img

    데이터셋으로는 태양의 SDO(Solar Dynamic Observatory)/AIA(Atmospheric Imaging Assembly) Image를 사용합니다. 그러나 AIA 데이터는 높은 동적 범위(High dynamic range)의 문제가 존재하기 때문에 Log Transform 을 하여 데이터를 전처리합니다. 전처리 과정을 거친 데이터를 아래의 CNN모델로 학습시킵니다.

    img

    결론

    • FlareNet은 상위 수준의 X 선 플럭스 활동을 생성 할 수 있습니다.
    • FlareNet은 태양의 구조 뿐만 아니라 active regions의 중요성을 학습하였습니다.

    2. Long Period Comets

    개요

    천문학적인 유성우의 발견은 천년기에 지구 궤도를 가로지르는 긴 주기의 혜성의 존재를 암시합니다. 머신러닝과 딥러닝을 사용한 유성 분류의 자동화를 연구합니다. 유성우 관측에 기계 학습을 적용하여 오랜 기간 혜성 충돌에 대한 더 많은 경고를 제공합니다. 유성우 궤도는 예상 궤도를 따라 전용 검색을 가능하게 합니다.

    CAMS

    LSTM을 이용한 유성 판별

    img img

    각 개체의 시간에 따른 위치를 X,Y 좌표계로 나타내고, Intensity(밝기,빛의 모양 등)를 시간에 따라 그래프로 나타내었습니다. 위 그림은 유성인 것과 유성이 아닌 것에 대한 비교 그래프입니다. 유성의 경우 규칙적인 값을 갖는 반면에, 유성이 아닌 경우 불규칙적인 값을 갖습니다.

    img

    위의 Tracklets(궤도)데이타를 입력으로 하는 LSTM 모델을 활용하여 유성을 판별합니다.

    CNN을 이용한 유성 판별

    img

    위 이미지와 같은 Label된 데이터를 바탕으로 Convolution Neural Network를 이용하여 유성 여부를 판별합니다.

    img

    이미지를 입력으로 하는 CNN 모델을 활용하여 유성을 판별합니다.

    결론

    다음은 각 모델 별로 정확도와 F1 스코어를 계산한 값입니다. LSTM을 사용한 모델이 F1 score가 제일 높게 나온 것을 확인 할 수 있습니다.

    img


    3. Lunar Water and Volatiles

    개요

    수자원이 풍부한 지역을 탐사하기 위한 crater map의 자동 제작을 연구합니다. 달의 남극에서 대규모 데이터 셋을 수집하고 크레이터 감지에 초점을 둔 고급의 feature 추출을 수행합니다. 98,4%의 높은 성공률로 전문가보다 100배 빠른 속도향상을 이루어냈습니다.

    달에 물이 존재하는 곳

    • 극 근처에 존재하는 크레이터
    • 태양이 닿지 않는 크레이터의 바닥
    • 영원히 그림자 진 지역(PSRs)

    img

    대부분의 달에 존재하는 물은 극점에 있는 PSRs에 존재합니다. 따라서 달에 존재하는 물을 찾기위해서는 먼저 PSR 및 크레이터를 연구할 필요가 있습니다. 그러나 달의 극점을 Mapping 하기위한 문제점이 존재합니다.

    • Co-regstration issues
    • Artifacts
    • Image illumination

    따라서 의미 있는 실험을 수행하기 위해서는 노동집약적인 많은 데이터가 필요합니다.

    Deep Learning Classifier

    달의 크레이터를 분별하기 위해서 달의 사진을 데이터 셋으로 사용합니다. 달의 DEM(Digital Elevation Model)/NAC(Narrow Angle Camera)을 Annotation 한 뒤 사용합니다. 사용된 데이터 셋의 크기는 다음과 같습니다.

    img

    Annotation 과정을 거친 데이터 셋은 CNN을 사용하는 Classifier 모델을 학습시키는 데 사용됩니다.

    img

    결론

    FDL팀이 연구한 CNN 모델이 지난 팀들이 연구한 패턴인식을 사용한 방법이나 CNN 모델 보다 월등히 뛰어난 정확도를 보이고 있습니다.

    img


    4. Radar 3D Shape Modeling

    개요

    2016 년부터 작업을 계속하면서 팀은 형상 모델링 워크 플로에 따라 AI 기술을 적용했습니다. 소행체 모양 모델링은 기존 소프트웨어를 사용하는 전문가가 수동으로 개입하는 데 최대 4 주가 소요됩니다. 이 팀은 Neural Nets를 최적화하고 GAN(Generative Adversarial Nets)을 활용하여 몇 시간 내에 NEO(Near Earth Object)를 모델링 할 수있는 자동화를위한 파이프 라인을 시연했습니다.

    데이터셋

    DBSCAN(Density-Based spatial clustering of applications with noise)은 주변 데이터들의 밀도를 이용해 군집을 생성해 나가는 방식을 말합니다. DBSCAN 결과에 image를 Masking 하여 이미지 데이터 전처리를 실시합니다.

    img

    GAN모델을 이용한 소행성 모델링 생성

    GAN(Generative adversarial networks)이란 Generator 네트워크와 Discriminator 네트워크가 서로 경쟁하며 성능을 점차 증진시켜나가는 방식의 모델입니다.

    img

    Generator에서 만들어진 모델링을 Discriminator가 판별하여 결과를 Generator에게 알려줍니다. 이를 계속 반복하면 Discriminator는 가짜를 판별하는 능력이 향상될 것이며 Generator는 실제 모델링과 비슷한 모델링을 만들어 낼 것 입니다. 두 네트워크의 경쟁을 통해 실제와 비슷한 모델링을 만들어 내는 것이 목표입니다.


    5. Solar Terrestrial Interactions

    개요

    지구 자기권의 적도 전류링 문제를 풀면서 딥러닝 기술을 과학적인 돌파구를 위한 도구로서의 가능성을 살펴보겠습니다. 오픈 소스 시스템 학습 프레임 워크 위에 STING (Solar Terrestrial Interactions Neural Network Generator)이라는 지식 검색 모듈을 구축하여 연구자가 복잡한 데이터 세트를 더 자세히 탐색 할 수 있게 했습니다.

    Space Weather가 주는 영향

    “우주 환경” 혹은 “우주 기상”이라는 용어는 우리가 지구에서 사용하는 기술의 성능에 영향을 미칠 수 있는 태양과 우주에서의 변수 상태를 지칭합니다. 우주 기상은 전선의 극심한 전류를 유도하는 전자기장을 생성하여 전선을 방해하고 광범위한 정전을 일으키기도 합니다. 심각한 우주 기상은 태양 에너지 입자도 생성하여 상업용 통신, 세계 위치 파악, 정보 수집 및 기상 예보에 사용되는 위성을 손상시킬 수 있습니다 다음은 우주 기상의 예시인 오로라가 끼치는 영향을 그림으로 나타낸 것입니다.

    img

    B - Sting

    우주 일기 예보를위한 데이터 기반 오픈 소스 도구로 지자기 장애를 포착하는 Kp 지수를 예측합니다. 데이터 소스로는 지구의 자기장과 태양풍 데이터를 사용합니다. Kp 지수는 매일 3 시간 간격으로 측정 한 지자기 활동 수준의 범위를 나타냅니다.

    img img

    지구의 자기장과 태양풍 데이터를 입력으로 Kp지수를 측정하기 위해서 다음과 같은 두가지 프로젝트를 실시했습니다.

    img

    LSTM RNN 모델

    LSTM유닛은 여러 개의 게이트(gate)가 붙어있는 셀(cell)로 이루어져있으며 이 셀의 정보를 새로 저장/셀의 정보를 불러오기/셀의 정보를 유지하는 기능이 있습니다. 셀은 셀에 연결된 게이트의 값을 보고 무엇을 저장할지, 언제 정보를 내보낼지, 언제 쓰고 언제 지울지를 결정합니다.

    img

    Gradient Boosting 모델

    함께 합쳐지면 손실 함수가 최소화되도록 트리 앙상블을 찾습니다. 각 트리는 전반적인 문제에 대한 솔루션의 추정치입니다. 훈련이 반복 될 때마다 나무에 재사용됩니다. 각 취약한 트리가 전반적인 강력한 솔루션에 기여할 수 있게 하였습니다.

    img

    결론

    다음은 Gradient Boosting 방법을 통해 3시간뒤의 Kp지수를 예측한 값과 실제 값을 비교한 그래프입니다.

    img

    Gradient Boosting 방법을 사용한 결과가 기존에 제시한 방법들보다 95%의 정확성을 보여주면서 뛰어난 성능을 보이고 있습니다.

    img


  • 케라스 단점


    케라스를 다른 분들께 추천을 하려면 장단점을 제대로 알고 소개를 해야 겠다는 생각이 들었습니다. 아래 나열된 단점은 커뮤너티에 올려진 게시물이나 주변에서 말하고나 제가 느낀 점을 정리해봤습니다. 어떤 항목들은 시간이 지나면서 해결되고 있는 부분들도 있습니다. 다른 단점이나 의견이 있으신 분들은 댓글로 달아주세요.

    img


    오류 대처의 어려움

    • 코드에 오류가 발생하였을 경우 케라스 자체 에러일 수도 있고 사용한 백엔드(텐서플로우 등) 문제일 수도 있기에 원인 찾기가 쉽지 않습니다.
    • 오류에 대한 조언을 얻기 위해 커뮤너티를 활용할 경우에도 백엔드(텐서플로우 등) 커뮤너티나 케라스 커뮤너티 모두 도움을 요청해야하는 일이 발생할 수 있습니다.
    • 만약 케라스에 오류가 있거나 지원되지 않는 기능을 직접 수정한다고 했을 때, 케라스 코드를 수정할 수 있습니다만 케라스 인터페이스에 맞추어서 수정하는 것보다 그냥 벡엔드를 익혀서 수정하는 것이 더 빠를 수 있습니다.

    참고할 때가 부족

    • 문서화가 제대로 되어 있지 않습니다. 제공되는 함수 목록은 빨리 업데이트 되는 편이지만 함수에 대한 설명을 찾기란 쉽지 않습니다.
    • 충분한 공식 예제가 없습니다. 케라스로 만든 예제들은 많지만 공식적으로 제공되는 예제는 한정적입니다.
    • 한국에서 사용자가 적어 물어볼 곳이 마땅히 없습니다.

    한정적인 기능 제공

    • 케라스에서 제공하는 텍스트 및 이미지 전처리 기능을 제공하지만 다양한 전처리를 원한다면 다른 패키지(scikit-learn이나 pandas 등)을 사용해야 됩니다.

    단점을 보안하고자 하는 노력들 (한국에서)


  • 한 장 간


    제 마음대로 ‘네트워크’와 ‘모델’을 구분해서 개념 정리를 해본 것을 그림으로 표현해봤습니다.

    img

    이 그림을 그리게 된 계기가 있는데요. 케라스의 GAN 코드를 보다가 엄청 헷갈리는 부분이 있었는데 이것 때문에 개념삽질 좀 했습니다. 그 부분은 바로 “discriminator.trainable = False” 이것입니다. 일단 대부분의 GAN 코드는 다음과 같은 구성을 가지고 있습니다.

    # generator 생성
    generator = Sequential()
    generator.add(...)
    generator.compile(...)
    
    # discriminator 생성
    discriminator = Sequential()
    discriminator.add(...)
    discriminator.compile(...)
    
    # adversarial network 생성
    discriminator.trainable = False ## << 바로 이부분
    gan_in = Input(shape=(randomDim,))
    gan_out = discriminator(generator(gan_in))
    gan = Model(inputs=gan_in, outputs=gan_out)
    gan.compile(...)
    

    discriminator 학습 시킬 때는 참/거짓 데이터를 주고 가중치를 업데이트를 해야되지만, 이 discriminator가 gan 안에서 generator와 같이 학습할 때는 가중치가 고정되어 있어야 합니다. 그래서 gan 모델을 생성하기 전에 discriminator.trainable = False으로 설정하긴 했는데… 여기서 헷갈리기 시작했습니다.

    • discriminator.trainable = False 으로 하면 gan에서는 고정되겠지만 discriminator을 학습할 때도 가중치가 고정되는 것이 아니야?
    • 앞에서 생성한 discriminator과 gan에 삽입할 때의 discriminator는 다른 객체인가?

    등등으로 생각을 했었는데, 알고보니 compile() 함수가 호출될 때 trainable 속성이 모델에 적용되더라구요. 즉 다음과 같습니다.

    • discriminator을 생성한 뒤 compile() 하면 trainable = True로 컴파일 됨
    • discriminator.trainable = False으로 적용하면 일단 trainable 속성만 비활성화된 상태임
    • gan 모델에 discriminator가 삽입됨
    • gan.compile() 하면 gan 모델 안에서 discriminator의 가중치가 업데이트 되지 않음
    • gan.compile()과 discriminator.compile()은 별개이고, discriminator.compile()가 다시 호출 되지 않았으므로, discriminator 모델에서의 trainable 속성은 True임
    • 여기서 하나 알 수 있는 것은 discriminator이라는 네트워크는 discriminator 모델과 gan 모델에 둘 다 사용되고 가중치도 공유되나 discriminator 모델에서는 가중치 갱신이 일어나고, gan 모델에서는 가중치 갱신이 일어나지 않음
    • gan 모델에서의 discriminator 네트워크는 단순 가중치를 가진 네트워크로만 받아들이고 discriminator 모델에 적용된 compile()은 아무 영향을 주지 않음. 즉 gan 모델은 따로 complie()을 해야 함

    배성호교수님의 ‘간은 로스일 뿐이야’라는 말씀을 이제야 이해한 듯 합니다.


    같이 보기


  • 딥브릭(DeepBrick) 이야기


    딥러닝과 케라스를 공부하면서 느낀 점은 층을 쌓고 모델을 만들고 하는 과정들이 블록 쌓는 것과 비슷한 느낌을 많이 받았고, 실제로 딥러닝 모델을 설명할 때 블록 그림을 많이 이용하기도 했습니다. 그러다가 (실제 혹은 웹에서) 블록을 쌓으면 딥러닝 모델까지 자동으로 만들 수 있겠다는 생각이 들었습니다. 그래서 딥브릭(DeepBrick)이란 이름으로 프로젝트를 진행해볼까 합니다.


    유닛

    딥러닝 모델에서의 개념과 우리가 익숙한 블록 간이 연관성이 있다록 매칭하는 작업이 필요했습니다. 지금까지 정리된 컨셉은 다음 그림과 같습니다.

    img

    • 투명한 블록은 입출력을 나타냅니다. 22 블록은 이미지를 의미하고, 12는 두개 이상 값을 가지는 백터, 1*1는 한 개 값을 가지는 벡터입니다.
    • 흰 블록은 모델을 의미합니다. 현재 모델은 CNN, LSTM, FC 이렇게 3가지 구상해봤습니다. 만약 프로그램을 만든다면 이 블록을 우클릭하면 층, 파라미터를 설정하거나 스크립트가 열리는 식이겠죠?
    • 얇은 블록은 출력을 정의합니다. Softmax는 다중분류 문제 사용되고, Sigmoid는 이진분류 또는 회귀문제, Linear는 회귀문제에 사용됩니다.

    동영상 분류 문제

    위에서 정의한 유닛을 이용해서 동영상 분류 문제를 풀기 위해 CNN + LSTM을 이용해서 모델 하나를 만들어봤습니다.

    • 입력은 이미지라서 2D 투명 블록으로,
    • 이미지를 인코딩하기 위해 입력은 CNN 블록으로,
    • 시계열 이미지(동영상, 4 프레임)를 처리하기 위해 LSTM 블록을 위에 얹히고,
    • 마지막 LSTM 블록에 FC 블록을 연결한 다음 Softmax 블록을 쌓았습니다.
    • Softmax 블록 위에 출력 1D 투명 블록을 쌓아서 출력을 얻습니다.
    • 이 출력은 one-hot 벡터입니다.

    img

    이 모델에 해당하는 케라스 코드도 같이 작성해봤습니다.

    model = Sequential()
    
    # CNN
    model.add(TimeDistributed(Conv2D(32, (2, 2), activation='relu'), input_shape=(None, 32, 32, 1)))
    model.add(TimeDistributed(MaxPooling2D(pool_size=(2,2))))
    model.add(TimeDistributed(Flatten()))
    
    # LSTM
    model.add(LSTM(128))
    
    # FC
    model.add(Dense(2, activation='softmax'))
    
    # Compile
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
    

    코드 생성 모듈 개발하시는 분들이 보시기엔 어떻게 느껴지실 지 궁금합니다. ‘할 만 하겠어’라고 생각하시겠죠? 이제(아니 나중에…) 블록만 조립하면 케라스 코드가 자동 생성됩니다.


    블록 이야기

    블록으로 표시하기 위한 고민을 많이 해왔습니다. 처음에는 레고로 조립해서 사진으로 찍었었는데, 원하는 부품을 구하기도 힘들뿐더러 (정확히는 돈이 많이 듭니다) 찍어도 그리 예쁘지가 않았습니다. 그 다음에 고민한 것이 블록 생성 툴을 알아봤었는 데, 원하는 품질이 나오지 않아 구글 프리젠테이션으로 직접 그리게 되었습니다(아래 그림에서 왼쪽). 하나 하나 다 그려야 되서 손이 많이 가긴 했었는데, 나름 편해서 잘 쓰고 있었습니다. 그러다 좀 다양한 블록을 표현하고 싶은데 구글 프리젠테이션으론 더 이상 할 수 없다는 결론을 내리고 다시 툴을 찾기 시작했습니다. 그러다 “Mecabricks”와 “blender” 툴의 조합으로 아래 그림에서 오른쪽으로 표현할 수 있게 되었습니다. 상상 이상의 고퀄이라 부담스러울 정도긴 한데, 손으로 일일이 그리는 것 보단 100배 편해서 사용하기로 결정했습니다. 나중에 알아보니 레고 영화 제작할 때 사용한다고도 하더군요.

    img

    두 개 버전을 비교하면 좀 더 추상화가 되어 간단해졌고, 실사에 가깝게 되었습니다~ 블록 표시하는 것에 대해서는 갈때까지 간 것 같습니다.


    결론

    저는 상상이되는 글, 그림, 코드, 생각 등을 좋아합니다. 이 이야기는 상당히 상상력이 자극되는 것 같습니다. 얼마나 다양한 유닛이 만들어질지, 얼마나 멋진 모델을 조립할 수 있을 지 궁금하네요. 이런 상상도 해봅니다. 어린이들이 딥러닝 블록을 조립한 뒤 학습을 시키면, 그 학습 결과가 가중치 블록에 저장됩니다. 그 가중치 블록을 로봇 등이 꼽기만 하면 동작이 될 수 있겠죠? 망상에 가까울려나요? 여러 사람들의 의견으로 좀 더 직관적이고 재미있는 아이디어가 많이 담긴 딥브릭(DeepBrick) 이야기가 되었으면 합니다.

    img


    같이 보기


  • Relation Networks for Visual QA


    Visual QA 문제에서 관계형 추론(relational reasoning)을 도출하고자 DeepMind가 제안한 신경망 모델인 관계 네트워크(Relation Networks, 이하 RN) 대해서 알아보고자 합니다. 이 모델은 A simple neural network module for relational reasoning이란 논문에서 소개되었고, 컨볼루션 신경망에 RN를 추가하여 어떻게 객체와 그 관계에 대해 추론하는 지 설명되어 있습니다. 시각기반의 질의응답 문제에 대해 탁월한 성능을 보이고 있다고 합니다.


    관계형 추론이란

    관계형 추론(Relational Reasoning)이란 객체와 객체 속성 간의 관계를 추론하는 능력입니다. 아래 그림을 보면 두가지 질문이 있는데, 특정 객체의 속성을 추론하는 것을 비관계형 질문이라고 하고, 객체 간의 관계에 대해서 추론하는 것을 관계형 질문이라고 합니다.

    (Ref, arXiv:1706.01427) paper


    관계 네트워크(Relation Networks, RN)

    DeepMind에서는 이러한 관계형 추론을 할 수 있는 RN을 개발하였습니다. RN은 간단하며, 다른 모델에 쉽게 붙일 수 있고, 유연한 관계형 추론에만 중점을 둘 수 있습니다. RN을 CNN과 LSTM과 결합하여 (본문에서는 RN-augmented architecture라고 표현) visual question answering 문제에 대해서 실험을 하였고, 좋은 결과(기존 모델은 76.6%, 사람이 92.6%, RN 모델 적용한 것이 95.5%)가 나왔다고 합니다.

    (Ref, arXiv:1706.01427) paper


    RN-augmented Visual QA acrhitecture

    RN 모델 자체는 객체 관계만 추론하기 때문에 이미지나 자연어에 대해서는 동작하지 않습니다. 그래서 CNN과 LSTM 등과의 모델에서의 출력을 입력받아 객체를 추출하고 각 객체간의 관계를 추론합니다. 즉 객체를 따로 지정할 필요도 없다고 합니다. 아래는 논문에서 사용한 모델 구성입니다.

    (Ref, arXiv:1706.01427) paper

    입력되는 이미지의 픽셀에서 객체들을 추출하기 위해 CNN이 사용하였습니다. 4개의 컨볼루션 레이어를 통해 크기 d * d의 k개의 feature map이 생성됩니다. k는 최종 컨볼루션 레이어의 커널 수입니다. 총 셀의 개수는 ddk가 되는 데, 각 셀은 RN에 대한 객체로 간주되며, 객체는 배경, 특정 객체, 질감, 연결 등을 정보를 담고 있습니다. 이러한 객체 정보는 인코딩된 질문과 함께 RN 모델의 입력이 됩니다.


    Implementation

    본 스터디에서는 Alan-Lee123 사이트에서 구현된 케라스 코드를 실행시키면서 분석해보겠습니다. 사용된 데이터셋은 Cornell NLVR이라고 불리는 시각기반의 질의응답 데이터셋입니다. 소스 구동하기 위해 아래 몇가지 사안에 대해서 고려해야 합니다.

    • 백그라운드는 Tensorflow를 사용해야 함
    • 버전에 따라 keras.preprocessing.text.text_to_word_sequence 함수를 재정의해야할 필요가 있음

    데이터 전처리

    이미지, 질문 등의 데이터를 처리하기 위한 함수 및 객체를 정의합니다.

    import json
    import numpy as np
    import os
    from PIL import Image
    from keras.layers import Embedding
    from keras.preprocessing.text import Tokenizer
    from keras.preprocessing.sequence import pad_sequences
    
    # text_to_word_sequence 부분에 패치가 필요하여, text_to_word_sequence 함수를 재정의함
    import keras.preprocessing.text
    
    def text_to_word_sequence(text,
                              filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
                              lower=True, split=" "):
        if lower: text = text.lower()
        if type(text) == unicode:
            translate_table = {ord(c): ord(t) for c,t in zip(filters, split*len(filters)) }
        else:
            translate_table = maketrans(filters, split * len(filters))
        text = text.translate(translate_table)
        seq = text.split(split)
        return [i for i in seq if i]
        
    keras.preprocessing.text.text_to_word_sequence = text_to_word_sequence
    
    EMBEDDING_DIM = 50
    tokenizer = Tokenizer()
    
    def load_data(path):
        f = open(path, 'r')
        data = []
        for l in f:
            jn = json.loads(l)
            s = jn['sentence']
            idn = jn['identifier']
            la = int(jn['label'] == 'true')
            data.append([idn, s, la])
        return data
    
    def init_tokenizer(sdata):
        texts = [t[1] for t in sdata]
        tokenizer.fit_on_texts(texts)
    
    def tokenize_data(sdata, mxlen):
        texts = [t[1] for t in sdata]
        seqs = tokenizer.texts_to_sequences(texts)
        seqs = pad_sequences(seqs, mxlen)
        data = {}
        for k in range(len(sdata)):
            data[sdata[k][0]] = [seqs[k], sdata[k][2]]
        return data
    
    def load_images(path, sdata, debug=False):
        data = {}
        cnt = 0
        N = 1000
        for lists in os.listdir(path):
            p = os.path.join(path, lists)
            
            if not os.path.isdir(p): # 자동으로 생성되는 시스템 파일이 있을 경우 오류가 발생하기 때문에, 폴더인지 체크함
                continue
                
            for f in os.listdir(p):
                cnt += 1
                if debug and cnt > N:
                    break
                im_path = os.path.join(p, f)
                im = Image.open(im_path)
                im = im.convert('RGB')
                im = im.resize((200, 50))
                im = np.array(im)
                idf = f[f.find('-') + 1:f.rfind('-')]
                data[f] = [im] + sdata[idf]
        ims, ws, labels = [], [], []
        for key in data:
            ims.append(data[key][0])
            ws.append(data[key][1])
            labels.append(data[key][2])
        data.clear()
        idx = np.arange(0, len(ims), 1)
        np.random.shuffle(idx)
        ims = [ims[t] for t in idx]
        ws = [ws[t] for t in idx]
        labels = [labels[t] for t in idx]
        ims = np.array(ims, dtype=np.float32)
        ws = np.array(ws, dtype=np.float32)
        labels = np.array(labels, dtype=np.float32)
        return ims, ws, labels
    
    def get_embeddings_index():
        embeddings_index = {}
        path = './warehouse/word2vec/glove.6B.50d.txt'
        f = open(path, 'r')#, errors='ignore')
        for line in f:
            values = line.split()
            word = values[0]
            coefs = np.asarray(values[1:], dtype='float32')
            embeddings_index[word] = coefs
        f.close()
        return embeddings_index
    
    
    def get_embedding_matrix(word_index, embeddings_index):
        embedding_matrix = np.zeros((len(word_index) + 1, EMBEDDING_DIM))
        for word, i in word_index.items():
            embedding_vector = embeddings_index.get(word)
            if embedding_vector is not None:
                # words not found in embedding index will be all-zeros.
                embedding_matrix[i] = embedding_vector
        return embedding_matrix
    
    Using TensorFlow backend.
    

    데이터 로딩

    앞서 정의한 전처리 함수를 이용하여 이미지 및 질문 데이터를 로딩합니다.

    import numpy as np
    import keras
    from keras.models import Sequential, Model
    from keras.layers import Dense, Dropout, Activation, Flatten, Input, Embedding, LSTM, Bidirectional, Lambda, Concatenate, Add
    from keras.layers.convolutional import Conv2D, MaxPooling2D, AveragePooling2D
    from keras.layers.normalization import BatchNormalization, regularizers
    from keras.optimizers import Adam, RMSprop
    import gc
    
    import subprocess
    import pickle
    
    mxlen = 32
    embedding_dim = 50
    lstm_unit = 64
    MLP_unit = 128
    epochs = 50
    batch_size = 256
    l2_norm = 0.01
    
    train_json = './warehouse/nlvr/train/train.json'
    train_img_folder = './warehouse/nlvr/train/images'
    test_json = './warehouse/nlvr/dev/dev.json'
    test_img_folder = './warehouse/nlvr/dev/images'
    
    data = load_data(train_json)
    init_tokenizer(data)
    data = tokenize_data(data, mxlen)
    imgs, ws, labels = load_images(train_img_folder, data)
    data.clear()
    
    test_data = load_data(test_json)
    test_data = tokenize_data(test_data, mxlen)
    test_imgs, test_ws, test_labels = load_images(test_img_folder, test_data)
    test_data.clear()
    
    imgs_mean = np.mean(imgs)
    imgs_std = np.std(imgs - imgs_mean)
    imgs = (imgs - imgs_mean) / imgs_std
    
    test_imgs = (test_imgs - imgs_mean) / imgs_std
    

    CNN 및 LSTM 모델 구성

    이미지를 처리하기 위한 CNN과 질문을 처리하기 위한 LSTM 모델을 정의합니다.

    def embedding_layer(word_index, embedding_index, sequence_len):
        embedding_matrix = get_embedding_matrix(word_index, embedding_index)
        return Embedding(len(word_index) + 1,
                         EMBEDDING_DIM,
                         weights=[embedding_matrix],
                         input_length=sequence_len,
                         trainable=False)
    
    def bn_layer(x, conv_unit):
        def f(inputs):
            md = Conv2D(x, (conv_unit, conv_unit), padding='same', kernel_initializer='he_normal')(inputs)
            md = BatchNormalization()(md)
            return Activation('relu')(md)
    
        return f
    
    def conv_net(inputs):
        model = bn_layer(16, 3)(inputs)
        model = MaxPooling2D((4, 4), 4)(model)
        model = bn_layer(16, 3)(model)
        model = MaxPooling2D((3, 3), 3)(model)
        model = bn_layer(16, 3)(model)
        model = MaxPooling2D((2, 2), 2)(model)
        model = bn_layer(32, 3)(model)
        return model
    
    input1 = Input((50, 200, 3))
    input2 = Input((mxlen,))
    cnn_features = conv_net(input1)
    embedding_layer = embedding_layer(tokenizer.word_index, get_embeddings_index(), mxlen)
    embedding = embedding_layer(input2)
    # embedding = Embedding(mxlen, embedding_dim)(input2)
    bi_lstm = Bidirectional(LSTM(lstm_unit, implementation=2, return_sequences=False,
                                 recurrent_regularizer=regularizers.l2(l2_norm), recurrent_dropout=0.25))
    lstm_encode = bi_lstm(embedding)
    shapes = cnn_features.shape
    w, h = shapes[1], shapes[2]
    

    RN 모델 구성

    CNN을 통해서 나온 feature map을 행과 열로 짤라서, Bi-LSTM으로 인코딩된 질문과 관계를 형성한 뒤 이를 dense 레이어로 구성합니다.

    def slice_1(t):
        return t[:, 0, :, :]
    
    def slice_2(t):
        return t[:, 1:, :, :]
    
    def slice_3(t):
        return t[:, 0, :]
    
    def slice_4(t):
        return t[:, 1:, :]
    
    slice_layer1 = Lambda(slice_1)
    slice_layer2 = Lambda(slice_2)
    slice_layer3 = Lambda(slice_3)
    slice_layer4 = Lambda(slice_4)
    
    features = []
    for k1 in range(w):
        features1 = slice_layer1(cnn_features)
        cnn_features = slice_layer2(cnn_features)
        for k2 in range(h):
            features2 = slice_layer3(features1)
            features1 = slice_layer4(features1)
            features.append(features2)
    
    relations = []
    concat = Concatenate()
    for feature1 in features:
        for feature2 in features:
            relations.append(concat([feature1, feature2, lstm_encode]))
    
    def stack_layer(layers):
        def f(x):
            for k in range(len(layers)):
                x = layers[k](x)
            return x
        return f
    
    def get_MLP(n):
        r = []
        for k in range(n):
            s = stack_layer([
                Dense(MLP_unit),
                BatchNormalization(),
                Activation('relu')
            ])
            r.append(s)
        return stack_layer(r)
    
    def bn_dense(x):
        y = Dense(MLP_unit)(x)
        y = BatchNormalization()(y)
        y = Activation('relu')(y)
        y = Dropout(0.5)(y)
        return y
    
    g_MLP = get_MLP(3)
    
    mid_relations = []
    for r in relations:
        mid_relations.append(g_MLP(r))
    combined_relation = Add()(mid_relations)
    
    rn = bn_dense(combined_relation)
    rn = bn_dense(rn)
    pred = Dense(1, activation='sigmoid')(rn)
    

    구성하는 과정이 조금 복잡할 수 있는데, 2017년 2월에 나왔던 아래 논문을 보면 RN에 대해서 좀 더 상세하게 설명되었습니다.

    (Ref, arXiv:1702.05068) paper

    모델 조합

    지금까지 만든 모델을 조합합니다.

    model = Model(inputs=[input1, input2], outputs=pred)
    optimizer = Adam(lr=3e-4)
    model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['accuracy'])
    
    from IPython.display import SVG
    from keras.utils.vis_utils import model_to_dot
    
    %matplotlib inline
    
    SVG(model_to_dot(model, show_shapes=True).create(prog='dot', format='svg'))
    

    아래 그림은 구성된 모델을 도식화 한 것입니다. 잘 확대해서 보시기 바랍니다.

    svg

    모델 학습하기

    구성된 모델을 훈련셋으로 학습합니다. 검증셋은 시험셋으로 사용하였네요.

    model.fit([imgs, ws], labels, validation_data=[[test_imgs, test_ws], test_labels],
              epochs=epochs, batch_size=batch_size)
    
    Train on 74460 samples, validate on 5934 samples
    Epoch 1/50
    74460/74460 [==============================] - 3981s - loss: 1.0313 - acc: 0.5506 - val_loss: 0.7847 - val_acc: 0.5484
    Epoch 2/50
    74460/74460 [==============================] - 1255s - loss: 0.7153 - acc: 0.5630 - val_loss: 0.6877 - val_acc: 0.5425
    Epoch 3/50
    74460/74460 [==============================] - 1027s - loss: 0.6576 - acc: 0.5740 - val_loss: 0.6664 - val_acc: 0.5693
    Epoch 4/50
    74460/74460 [==============================] - 1015s - loss: 0.6421 - acc: 0.5805 - val_loss: 0.6624 - val_acc: 0.5644
    Epoch 5/50
    74460/74460 [==============================] - 1021s - loss: 0.6343 - acc: 0.5920 - val_loss: 0.6584 - val_acc: 0.5797
    ...
    Epoch 46/50
    74460/74460 [==============================] - 1016s - loss: 0.1855 - acc: 0.9210 - val_loss: 3.5557 - val_acc: 0.5121
    Epoch 47/50
    74460/74460 [==============================] - 1018s - loss: 0.1775 - acc: 0.9240 - val_loss: 4.1076 - val_acc: 0.4949
    Epoch 48/50
    74460/74460 [==============================] - 1021s - loss: 0.1716 - acc: 0.9282 - val_loss: 3.0868 - val_acc: 0.5300
    Epoch 49/50
    74460/74460 [==============================] - 1027s - loss: 0.1699 - acc: 0.9279 - val_loss: 3.1258 - val_acc: 0.5153
    Epoch 50/50
    74460/74460 [==============================] - 1020s - loss: 0.1673 - acc: 0.9305 - val_loss: 3.3528 - val_acc: 0.5163
    

    평가

    훈련 정확도는 93%이상이나 시험셋으로 평가했을 때는 51% 정도 나왔습니다.

    ### Test
    scores = model.evaluate([test_imgs, test_ws], test_labels, batch_size=128)
    print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
    
    5934/5934 [==============================] - 40s    
    acc: 51.63%
    

    결론

    상당히 오버피팅이 되었는데, 무슨 이유인지 차근히 살펴봐야겠습니다. 참고로 Pytorch로 구현된 코드도 보입니다. 여기서는 결과가 관계형 질문 정확도가 89%, 비관계형 질문 정확도가 99%이라고 되어있네요.

    같은 시기에 DeepMind에서 Visual Interaction Networks이란 논문도 나왔습니다. 아래 그림을 보시면 6 프레임을 입력하여 200프레임을 예측한 결과인데, 상당히 잘 맞습니다.

    (Ref, DeepMind) gif

    Visual Interaction Network는 시각적 모듈과 물리적 추론 모듈의 두 가지 메커니즘으로 구성되며, 시각적 장면 처리는 물론 미래에 어떤 일이 일어날 지 예측할 수있는 암묵적 시스템 규칙(예를 들어 물리 시스템)을 학습한다고 합니다. 현상만 잘 학습시키면, 딥러닝 기반의 물리 엔진이 만들어질 기세입니다. 다양한 활용 사례를 기대해봅니다.


    같이 보기

    
    

  • 파이썬 패키지 이야기


    딥러닝 모델 개발에 유용한 파이썬 패키지에 대해서 다뤄봅니다.

    Pickle

    users = {'id1':'kim', 'id2':'lee', 'id3':'choi'}
    f = open('users.txt', 'w')
    
    import pickle
    pickle.dump(users, f)
    f.close()
    
    f = open('users.txt')
    new_users = pickle.load(f)
    print(new_users)
    
    {'id2': 'lee', 'id3': 'choi', 'id1': 'kim'}
    

    glob

    import glob
    glob.glob('*.*')
    
    ['2017-1-27-CNN_Layer_Talk.ipynb',
     '2017-1-27-Keras_Talk.ipynb',
     '2017-1-27-LossFuncion_Talk.ipynb',
     '2017-1-27-MLP_Layer_Talk.ipynb',
     '2017-1-27-Optimizer_Talk.ipynb',
     '2017-2-22-Integrating_Keras_and_TensorFlow.ipynb',
     '2017-2-4-AutoEncoder_Getting_Started.ipynb',
     '2017-2-4-BinaryClassification_Example.ipynb',
     '2017-2-4-ImageClassification_Example.ipynb',
     '2017-2-4-MLP_Getting_Started-Copy1.ipynb',
     '2017-2-4-MLP_Getting_Started.ipynb',
     '2017-2-4-MulticlassClassification_Example.ipynb',
     '2017-2-4-ObjectRecognition_Example.ipynb',
     '2017-2-4-Regression_Example.ipynb',
     '2017-2-4-RNN_Getting_Started.ipynb',
     '2017-2-4-TimeSeriesPrediction_Example.ipynb',
     '2017-2-6-First_Keras_Offline_Meeting.ipynb',
     '2017-3-11-To_Use_TensorBoard.ipynb',
     '2017-3-15-Keras_Offline_Install.ipynb',
     '2017-3-25-Dataset_and_Fit_Talk.ipynb',
     '2017-3-8-CNN_Data_Augmentation.ipynb',
     '2017-3-8-CNN_Getting_Started.ipynb',
     '2017-4-9-RNN_Getting_Started_2.ipynb',
     '2017-4-9-RNN_Layer_Talk.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression-Copy1.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression.ipynb',
     '2017-5-21-Conv_LSTM_Example.ipynb',
     '2017-5-22-Evaluation_Talk.ipynb',
     '2017-6-10-Model_Save_Load.ipynb',
     '2017-6-17-Relation_Network.ipynb',
     '2017-7-9-Early_Stopping.ipynb',
     '2017-7-9-Training_Monitoring.ipynb',
     '2017-8-10-Python_Package_Talk.ipynb',
     '2017-8-10-Python_Talk-Copy1.ipynb',
     '2017-8-10-Python_Talk.ipynb',
     '2017-8-4-RNN_Classification.ipynb',
     '2017-8-7-Keras_Install_on_Mac.ipynb',
     '2017-8-9-DeepBrick_Talk.ipynb',
     'Animate.ipynb',
     'cosine_LSTM-Copy1.ipynb',
     'cosine_LSTM-Copy2.ipynb',
     'cosine_LSTM-Copy3.ipynb',
     'cosine_LSTM-Copy4.ipynb',
     'cosine_LSTM-flux.ipynb',
     'cosine_LSTM.ipynb',
     'Data_RNN.zip',
     'exAnimation.gif',
     'FeedPrediction_DeepStackedStatefulLSTM.ipynb',
     'Flare_Flux_Prediction.ipynb',
     'Flux Case 1.ipynb',
     'Flux Case 2.ipynb',
     'Flux_deep_stacked_stateful_LSTM_with_one_sample.ipynb',
     'Flux_Test-Copy1.ipynb',
     'Flux_Test.ipynb',
     'Flux_Test_Stateful.ipynb',
     'FullSizeRender.jpg',
     'HEPFluxPrediction_DeepStackedStatefulLSTM-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200.ipynb',
     'image.png',
     'lecture.ipynb',
     'LSTM.py',
     'model.png',
     'object detector.ipynb',
     'sin_w40_u32_s2_e200.gif',
     'SPE_Prediction.ipynb',
     'stateful RNNs.ipynb',
     'text.txt',
     'tykimos2.txt',
     'Untitled.ipynb',
     'users.txt',
     'w12_u64_s2_e300.gif',
     'w24_u128_s1_e100.gif',
     'w40_u128_s2_e200.gif',
     'w40_u128_s4_e1000.gif',
     'w40_u32_s2_e1.gif']
    
    glob.glob('*.txt')
    
    ['text.txt', 'tykimos2.txt', 'users.txt']
    
    import os.path
    files = glob.glob('*')
    for x in files:
        if os.path.isdir(x):
            print(x)
    
    abstract
    graph
    warehouse
    

    Numpy

    Numpy is the core library for scientific computing in Python. It provides a high-performance multidimensional array object, and tools for working with these arrays. If you are already familiar with MATLAB, you might find this tutorial useful to get started with Numpy.

    To use Numpy, we first need to import the numpy package:

    import numpy as np
    

    Arrays

    A numpy array is a grid of values, all of the same type, and is indexed by a tuple of nonnegative integers. The number of dimensions is the rank of the array; the shape of an array is a tuple of integers giving the size of the array along each dimension.

    We can initialize numpy arrays from nested Python lists, and access elements using square brackets:

    a = np.array([1, 2, 3])  # Create a rank 1 array
    print type(a), a.shape, a[0], a[1], a[2]
    a[0] = 5                 # Change an element of the array
    print a                  
    
    <type 'numpy.ndarray'> (3,) 1 2 3
    [5 2 3]
    
    b = np.array([[1,2,3],[4,5,6]])   # Create a rank 2 array
    print b
    
    [[1 2 3]
     [4 5 6]]
    
    print b.shape                   
    print b[0, 0], b[0, 1], b[1, 0]
    
    (2, 3)
    1 2 4
    

    Numpy also provides many functions to create arrays:

    a = np.zeros((2,2))  # Create an array of all zeros
    print a
    
    [[ 0.  0.]
     [ 0.  0.]]
    
    b = np.ones((1,2))   # Create an array of all ones
    print b
    
    [[ 1.  1.]]
    
    c = np.full((2,2), 7) # Create a constant array
    print c 
    
    [[ 7.  7.]
     [ 7.  7.]]
    
    d = np.eye(2)        # Create a 2x2 identity matrix
    print d
    
    [[ 1.  0.]
     [ 0.  1.]]
    
    e = np.random.random((2,2)) # Create an array filled with random values
    print e
    
    [[ 0.09477679  0.79267634]
     [ 0.78291274  0.38962829]]
    

    Array indexing (지루함)

    Numpy offers several ways to index into arrays.

    Slicing: Similar to Python lists, numpy arrays can be sliced. Since arrays may be multidimensional, you must specify a slice for each dimension of the array:

    import numpy as np
    
    # Create the following rank 2 array with shape (3, 4)
    # [[ 1  2  3  4]
    #  [ 5  6  7  8]
    #  [ 9 10 11 12]]
    a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
    
    # Use slicing to pull out the subarray consisting of the first 2 rows
    # and columns 1 and 2; b is the following array of shape (2, 2):
    # [[2 3]
    #  [6 7]]
    b = a[:2, 1:3]
    print b
    
    [[2 3]
     [6 7]]
    

    A slice of an array is a view into the same data, so modifying it will modify the original array.

    print a[0, 1]  
    b[0, 0] = 77    # b[0, 0] is the same piece of data as a[0, 1]
    print a[0, 1] 
    
    2
    77
    

    You can also mix integer indexing with slice indexing. However, doing so will yield an array of lower rank than the original array. Note that this is quite different from the way that MATLAB handles array slicing:

    import numpy as np
    
    # Create the following rank 2 array with shape (3, 4)
    a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
    print a
    
    [[ 1  2  3  4]
     [ 5  6  7  8]
     [ 9 10 11 12]]
    

    Two ways of accessing the data in the middle row of the array. Mixing integer indexing with slices yields an array of lower rank, while using only slices yields an array of the same rank as the original array:

    row_r1 = a[1, :]    # Rank 1 view of the second row of a  
    row_r2 = a[1:2, :]  # Rank 2 view of the second row of a
    row_r3 = a[[1], :]  # Rank 2 view of the second row of a
    print row_r1, row_r1.shape 
    print row_r2, row_r2.shape
    print row_r3, row_r3.shape
    
    [5 6 7 8] (4,)
    [[5 6 7 8]] (1, 4)
    [[5 6 7 8]] (1, 4)
    
    # We can make the same distinction when accessing columns of an array:
    col_r1 = a[:, 1]
    col_r2 = a[:, 1:2]
    print col_r1, col_r1.shape
    print
    print col_r2, col_r2.shape
    
    [ 2  6 10] (3,)
    
    [[ 2]
     [ 6]
     [10]] (3, 1)
    

    Integer array indexing: When you index into numpy arrays using slicing, the resulting array view will always be a subarray of the original array. In contrast, integer array indexing allows you to construct arbitrary arrays using the data from another array. Here is an example:

    a = np.array([[1,2], [3, 4], [5, 6]])
    
    # An example of integer array indexing.
    # The returned array will have shape (3,) and 
    print a[[0, 1, 2], [0, 1, 0]]
    
    # The above example of integer array indexing is equivalent to this:
    print np.array([a[0, 0], a[1, 1], a[2, 0]])
    
    [1 4 5]
    [1 4 5]
    
    # When using integer array indexing, you can reuse the same
    # element from the source array:
    print a[[0, 0], [1, 1]]
    
    # Equivalent to the previous integer array indexing example
    print np.array([a[0, 1], a[0, 1]])
    
    [2 2]
    [2 2]
    

    One useful trick with integer array indexing is selecting or mutating one element from each row of a matrix:

    # Create a new array from which we will select elements
    a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    print a
    
    [[ 1  2  3]
     [ 4  5  6]
     [ 7  8  9]
     [10 11 12]]
    
    # Create an array of indices
    b = np.array([0, 2, 0, 1])
    
    print(np.arange(4))
    
    # Select one element from each row of a using the indices in b
    print a[np.arange(4), b]  # Prints "[ 1  6  7 11]"
    
    [0 1 2 3]
    [ 1  6  7 11]
    
    # Mutate one element from each row of a using the indices in b
    a[np.arange(4), b] += 10
    print a
    
    [[11  2  3]
     [ 4  5 16]
     [17  8  9]
     [10 21 12]]
    

    Boolean array indexing: Boolean array indexing lets you pick out arbitrary elements of an array. Frequently this type of indexing is used to select the elements of an array that satisfy some condition. Here is an example:

    import numpy as np
    
    a = np.array([[1,2], [3, 4], [5, 6]])
    
    bool_idx = (a > 2)  # Find the elements of a that are bigger than 2;
                        # this returns a numpy array of Booleans of the same
                        # shape as a, where each slot of bool_idx tells
                        # whether that element of a is > 2.
    
    print bool_idx
    
    [[False False]
     [ True  True]
     [ True  True]]
    
    # We use boolean array indexing to construct a rank 1 array
    # consisting of the elements of a corresponding to the True values
    # of bool_idx
    print a[bool_idx]
    
    # We can do all of the above in a single concise statement:
    print a[a > 2]
    
    [3 4 5 6]
    [3 4 5 6]
    

    For brevity we have left out a lot of details about numpy array indexing; if you want to know more you should read the documentation.

    Datatypes

    Every numpy array is a grid of elements of the same type. Numpy provides a large set of numeric datatypes that you can use to construct arrays. Numpy tries to guess a datatype when you create an array, but functions that construct arrays usually also include an optional argument to explicitly specify the datatype. Here is an example:

    x = np.array([1, 2])  # Let numpy choose the datatype
    y = np.array([1.0, 2.0])  # Let numpy choose the datatype
    z = np.array([1, 2], dtype=np.int64)  # Force a particular datatype
    
    print x.dtype, y.dtype, z.dtype
    
    int64 float64 int64
    

    You can read all about numpy datatypes in the documentation.

    Array math

    Basic mathematical functions operate elementwise on arrays, and are available both as operator overloads and as functions in the numpy module:

    x = np.array([[1,2],[3,4]], dtype=np.float64)
    y = np.array([[5,6],[7,8]], dtype=np.float64)
    
    # Elementwise sum; both produce the array
    print x + y
    print np.add(x, y)
    
    [[  6.   8.]
     [ 10.  12.]]
    [[  6.   8.]
     [ 10.  12.]]
    
    # Elementwise difference; both produce the array
    print x - y
    print np.subtract(x, y)
    
    [[-4. -4.]
     [-4. -4.]]
    [[-4. -4.]
     [-4. -4.]]
    
    # Elementwise product; both produce the array
    print x * y
    print np.multiply(x, y)
    
    [[  5.  12.]
     [ 21.  32.]]
    [[  5.  12.]
     [ 21.  32.]]
    
    # Elementwise division; both produce the array
    # [[ 0.2         0.33333333]
    #  [ 0.42857143  0.5       ]]
    print x / y
    print np.divide(x, y)
    
    [[ 0.2         0.33333333]
     [ 0.42857143  0.5       ]]
    [[ 0.2         0.33333333]
     [ 0.42857143  0.5       ]]
    
    # Elementwise square root; produces the array
    # [[ 1.          1.41421356]
    #  [ 1.73205081  2.        ]]
    print np.sqrt(x)
    
    [[ 1.          1.41421356]
     [ 1.73205081  2.        ]]
    

    Note that unlike MATLAB, * is elementwise multiplication, not matrix multiplication. We instead use the dot function to compute inner products of vectors, to multiply a vector by a matrix, and to multiply matrices. dot is available both as a function in the numpy module and as an instance method of array objects:

    x = np.array([[1,2],[3,4]])
    y = np.array([[5,6],[7,8]])
    
    v = np.array([9,10])
    w = np.array([11, 12])
    
    # Inner product of vectors; both produce 219
    print v.dot(w)
    print np.dot(v, w)
    
    219
    219
    
    # Matrix / vector product; both produce the rank 1 array [29 67]
    print x.dot(v)
    print np.dot(x, v)
    
    [29 67]
    [29 67]
    
    # Matrix / matrix product; both produce the rank 2 array
    # [[19 22]
    #  [43 50]]
    print x.dot(y)
    print np.dot(x, y)
    
    [[19 22]
     [43 50]]
    [[19 22]
     [43 50]]
    

    Numpy provides many useful functions for performing computations on arrays; one of the most useful is sum:

    x = np.array([[1,2],[3,4]])
    
    print np.sum(x)  # Compute sum of all elements; prints "10"
    print np.sum(x, axis=0)  # Compute sum of each column; prints "[4 6]"
    print np.sum(x, axis=1)  # Compute sum of each row; prints "[3 7]"
    
    10
    [4 6]
    [3 7]
    

    You can find the full list of mathematical functions provided by numpy in the documentation.

    Apart from computing mathematical functions using arrays, we frequently need to reshape or otherwise manipulate data in arrays. The simplest example of this type of operation is transposing a matrix; to transpose a matrix, simply use the T attribute of an array object:

    print x
    print x.T
    
    [[1 2]
     [3 4]]
    [[1 3]
     [2 4]]
    
    v = np.array([[1,2,3]])
    print v 
    print v.T
    
    [[1 2 3]]
    [[1]
     [2]
     [3]]
    

    Broadcasting

    Broadcasting is a powerful mechanism that allows numpy to work with arrays of different shapes when performing arithmetic operations. Frequently we have a smaller array and a larger array, and we want to use the smaller array multiple times to perform some operation on the larger array.

    For example, suppose that we want to add a constant vector to each row of a matrix. We could do it like this:

    # We will add the vector v to each row of the matrix x,
    # storing the result in the matrix y
    x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    v = np.array([1, 0, 1])
    y = np.empty_like(x)   # Create an empty matrix with the same shape as x
    
    # Add the vector v to each row of the matrix x with an explicit loop
    for i in range(4):
        y[i, :] = x[i, :] + v
    
    print y
    
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    

    This works; however when the matrix x is very large, computing an explicit loop in Python could be slow. Note that adding the vector v to each row of the matrix x is equivalent to forming a matrix vv by stacking multiple copies of v vertically, then performing elementwise summation of x and vv. We could implement this approach like this:

    vv = np.tile(v, (4, 1))  # Stack 4 copies of v on top of each other
    print vv                 # Prints "[[1 0 1]
                             #          [1 0 1]
                             #          [1 0 1]
                             #          [1 0 1]]"
    
    [[1 0 1]
     [1 0 1]
     [1 0 1]
     [1 0 1]]
    
    y = x + vv  # Add x and vv elementwise
    print y
    
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    

    Numpy broadcasting allows us to perform this computation without actually creating multiple copies of v. Consider this version, using broadcasting:

    import numpy as np
    
    # We will add the vector v to each row of the matrix x,
    # storing the result in the matrix y
    x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    v = np.array([1, 0, 1])
    y = x + v  # Add v to each row of x using broadcasting
    print y
    
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    

    The line y = x + v works even though x has shape (4, 3) and v has shape (3,) due to broadcasting; this line works as if v actually had shape (4, 3), where each row was a copy of v, and the sum was performed elementwise.

    Broadcasting two arrays together follows these rules:

    1. If the arrays do not have the same rank, prepend the shape of the lower rank array with 1s until both shapes have the same length.
    2. The two arrays are said to be compatible in a dimension if they have the same size in the dimension, or if one of the arrays has size 1 in that dimension.
    3. The arrays can be broadcast together if they are compatible in all dimensions.
    4. After broadcasting, each array behaves as if it had shape equal to the elementwise maximum of shapes of the two input arrays.
    5. In any dimension where one array had size 1 and the other array had size greater than 1, the first array behaves as if it were copied along that dimension

    If this explanation does not make sense, try reading the explanation from the documentation or this explanation.

    Functions that support broadcasting are known as universal functions. You can find the list of all universal functions in the documentation.

    Here are some applications of broadcasting:

    # Compute outer product of vectors
    v = np.array([1,2,3])  # v has shape (3,)
    w = np.array([4,5])    # w has shape (2,)
    # To compute an outer product, we first reshape v to be a column
    # vector of shape (3, 1); we can then broadcast it against w to yield
    # an output of shape (3, 2), which is the outer product of v and w:
    
    print np.reshape(v, (3, 1)) * w
    
    [[ 4  5]
     [ 8 10]
     [12 15]]
    
    # Add a vector to each row of a matrix
    x = np.array([[1,2,3], [4,5,6]])
    # x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
    # giving the following matrix:
    
    print x + v
    
    [[2 4 6]
     [5 7 9]]
    
    # Add a vector to each column of a matrix
    # x has shape (2, 3) and w has shape (2,).
    # If we transpose x then it has shape (3, 2) and can be broadcast
    # against w to yield a result of shape (3, 2); transposing this result
    # yields the final result of shape (2, 3) which is the matrix x with
    # the vector w added to each column. Gives the following matrix:
    
    print (x.T + w).T
    
    [[ 5  6  7]
     [ 9 10 11]]
    
    # Another solution is to reshape w to be a row vector of shape (2, 1);
    # we can then broadcast it directly against x to produce the same
    # output.
    print x + np.reshape(w, (2, 1))
    
    [[ 5  6  7]
     [ 9 10 11]]
    
    # Multiply a matrix by a constant:
    # x has shape (2, 3). Numpy treats scalars as arrays of shape ();
    # these can be broadcast together to shape (2, 3), producing the
    # following array:
    print x * 2
    
    [[ 2  4  6]
     [ 8 10 12]]
    

    Broadcasting typically makes your code more concise and faster, so you should strive to use it where possible.

    This brief overview has touched on many of the important things that you need to know about numpy, but is far from complete. Check out the numpy reference to find out much more about numpy.

    Matplotlib

    Matplotlib is a plotting library. In this section give a brief introduction to the matplotlib.pyplot module, which provides a plotting system similar to that of MATLAB.

    import matplotlib.pyplot as plt
    

    By running this special iPython command, we will be displaying plots inline:

    %matplotlib inline
    

    Plotting

    The most important function in matplotlib is plot, which allows you to plot 2D data. Here is a simple example:

    # Compute the x and y coordinates for points on a sine curve
    x = np.arange(0, 10, 1)
    y = 2 * x + 1
    
    # Plot the points using matplotlib
    plt.plot(x, y)
    
    [<matplotlib.lines.Line2D at 0x108120e50>]
    

    png

    # Compute the x and y coordinates for points on a sine curve
    x = np.arange(0, 3 * np.pi, 0.1)
    y = np.sin(x)
    
    # Plot the points using matplotlib
    plt.plot(x, y)
    
    [<matplotlib.lines.Line2D at 0x1083a0550>]
    

    png

    With just a little bit of extra work we can easily plot multiple lines at once, and add a title, legend, and axis labels:

    y_cos = np.cos(x)
    y_sin = np.sin(x)
    
    # Plot the points using matplotlib
    plt.plot(x, y_sin)
    plt.plot(x, y_cos)
    plt.xlabel('x axis label')
    plt.ylabel('y axis label')
    plt.title('Sine and Cosine')
    plt.legend(['Sine', 'Cosine'])
    
    <matplotlib.legend.Legend at 0x108501910>
    

    png

    Subplots

    You can plot different things in the same figure using the subplot function. Here is an example:

    # Compute the x and y coordinates for points on sine and cosine curves
    x = np.arange(0, 3 * np.pi, 0.1)
    y_sin = np.sin(x)
    y_cos = np.cos(x)
    
    # Set up a subplot grid that has height 2 and width 1,
    # and set the first such subplot as active.
    plt.subplot(2, 1, 1)
    
    # Make the first plot
    plt.plot(x, y_sin)
    plt.title('Sine')
    
    # Set the second subplot as active, and make the second plot.
    plt.subplot(2, 1, 2)
    plt.plot(x, y_cos)
    plt.title('Cosine')
    
    # Show the figure.
    plt.show()
    

    png

    You can read much more about the subplot function in the documentation.

    pandas

    from pandas import Series, DataFrame
    
    import pandas
    print(pandas.Series)
    
    <class 'pandas.core.series.Series'>
    
    from pandas import Series, DataFrame
    
    kakao = Series([92600, 92400, 92100, 94300, 92300])
    print(kakao)
    
    0    92600
    1    92400
    2    92100
    3    94300
    4    92300
    dtype: int64
    
    print(kakao[0])
    print(kakao[2])
    print(kakao[4])
    
    92600
    92100
    92300
    
    kakao2 = Series([92600, 92400, 92100, 94300, 92300], index=['2016-02-19',
                                                                '2016-02-18',
                                                                '2016-02-17',
                                                                '2016-02-16',
                                                                '2016-02-15'])
    print(kakao2)
    
    2016-02-19    92600
    2016-02-18    92400
    2016-02-17    92100
    2016-02-16    94300
    2016-02-15    92300
    dtype: int64
    
    print(kakao2['2016-02-19'])
    print(kakao2['2016-02-18'])
    
    92600
    92400
    
    for date in kakao2.index:
        print(date)
    
    for ending_price in kakao2.values:
        print(ending_price)
    
    2016-02-19
    2016-02-18
    2016-02-17
    2016-02-16
    2016-02-15
    92600
    92400
    92100
    94300
    92300
    
    from pandas import Series, DataFrame
    
    mine   = Series([10, 20, 30], index=['naver', 'sk', 'kt'])
    friend = Series([10, 30, 20], index=['kt', 'naver', 'sk'])
    
    merge = mine + friend
    print(merge)
    
    kt       40
    naver    40
    sk       40
    dtype: int64
    
    from pandas import Series, DataFrame
    
    mine   = Series([10, 20, 30], index=['naver1', 'sk', 'kt'])
    friend = Series([10, 30, 20], index=['kt', 'naver2', 'sk'])
    
    merge = mine + friend
    print(merge)
    
    kt        40.0
    naver1     NaN
    naver2     NaN
    sk        40.0
    dtype: float64
    
    from pandas import Series, DataFrame
    
    raw_data = {'col0': [1, 2, 3, 4],
                'col1': [10, 20, 30, 40],
                'col2': [100, 200, 300, 400]}
    
    print(raw_data)
    data = DataFrame(raw_data)
    print(data)
    
    {'col2': [100, 200, 300, 400], 'col0': [1, 2, 3, 4], 'col1': [10, 20, 30, 40]}
       col0  col1  col2
    0     1    10   100
    1     2    20   200
    2     3    30   300
    3     4    40   400
    
    data['col0']
    
    0    1
    1    2
    2    3
    3    4
    Name: col0, dtype: int64
    
    from pandas import Series, DataFrame
    
    daeshin = {'open':  [11650, 11100, 11200, 11100, 11000],
               'high':  [12100, 11800, 11200, 11100, 11150],
               'low' :  [11600, 11050, 10900, 10950, 10900],
               'close': [11900, 11600, 11000, 11100, 11050]}
    
    daeshin_day = DataFrame(daeshin)
    print(daeshin_day)
    
       close   high    low   open
    0  11900  12100  11600  11650
    1  11600  11800  11050  11100
    2  11000  11200  10900  11200
    3  11100  11100  10950  11100
    4  11050  11150  10900  11000
    
    daeshin_day = DataFrame(daeshin, columns=['open', 'high', 'low', 'close'])
    print(daeshin_day)
    
        open   high    low  close
    0  11650  12100  11600  11900
    1  11100  11800  11050  11600
    2  11200  11200  10900  11000
    3  11100  11100  10950  11100
    4  11000  11150  10900  11050
    
    date = ['16.02.29', '16.02.26', '16.02.25', '16.02.24', '16.02.23']
    daeshin_day = DataFrame(daeshin, columns=['open', 'high', 'low', 'close'], index=date)
    print(daeshin_day)
    
               open   high    low  close
    16.02.29  11650  12100  11600  11900
    16.02.26  11100  11800  11050  11600
    16.02.25  11200  11200  10900  11000
    16.02.24  11100  11100  10950  11100
    16.02.23  11000  11150  10900  11050
    
    close = daeshin_day['close']
    print(close)
    
    16.02.29    11900
    16.02.26    11600
    16.02.25    11000
    16.02.24    11100
    16.02.23    11050
    Name: close, dtype: int64
    
    print(daeshin_day['16.02.24'])
    
    11100
    
    day_data = daeshin_day.loc['16.02.24']
    print(day_data)
    print(type(day_data))
    
    open     11100
    high     11100
    low      10950
    close    11100
    Name: 16.02.24, dtype: int64
    <class 'pandas.core.series.Series'>
    
    print(daeshin_day.columns)
    print(daeshin_day.index)
    
    
    Index([u'open', u'high', u'low', u'close'], dtype='object')
    Index([u'16.02.29', u'16.02.26', u'16.02.25', u'16.02.24', u'16.02.23'], dtype='object')
    
    
    

  • 파이썬 이야기


    케라스로 딥러닝 모델을 만들고, 데이터를 전처리하기 위해 필요한 최소한의 파이썬 내용을 다루고자 합니다.


    공부할 때 쓰기 좋은 개발환경 - 주피터 노트북

    파이썬을 구동하려면 파이썬 개발환경이 필요합니다. 메모장이나 텍스트편집기를 이용해서 코드를 작성하고, 콘솔 창에서 실행해도 되지만 좀 더 편한 방법들이 많이 있습니다. 그 중 주석을 자유롭게 작성할 수 있고 특정 부분만 실행시킬 수 있는 주피터 노트북에 대해서 알아보겠습니다. 웹 브라우저에서 구동되기 때문에 주피터 노트북만 익혀놓으면, 운영체제와 상관없이 익숙한 환경에서 파이썬 코드를 작성할 수 있습니다.

    파이썬 소개

    파이썬은 간단하고 직관적인 언어이기 때문에, 간단한 문법만 익혀놓으면 남의 코드를 보거나 직접 코드를 작성할 때에도 쉽게 하실 수 있습니다. 그리고 막강한 라이브러리들이 제공하기 때문에 좀 전문적인 기능들은 이 라이브러리에서 쉽게 찾을 수 있습니다. 파이썬 버전은 2.X와 3.X가 있습니다. 3.X가 더 최신 버전이지만 아직 많은 사람들이 2.X을 사용하고 있기 때문에 배울 때 참고할 만한 코드들이 2.X로 되어 있는 것이 많습니다. 따라서 2.X 버전의 파이썬에 대해서 익혀보겠습니다. 3.X가 필요할 시점이 되었을 때, 2.X로 익히신 분이 3.X를 사용하시는 데는 크게 어렵지 않으실 겁니다.

    계산과 화면 출력

    주피터 노트북에서는 현재 실행되는 셀의 마지막 명령의 반환 값이 있을 경우 그 값을 화면에 출력 해줍니다. 이 기능을 이용해서 간단한 계산 및 결과값을 출력해봅시다.

    350 + 27
    
    14 / 3 # 정수 나누기
    
    14.0 / 3.0 # 실수 나누기
    
    3 ** 2 # 제곱
    

    기본형

    변수 선언

    a = 2
    b = 1
    x = 3
    y = a * x + b
    
    y
    

    정수 및 실수

    x = 5
    
    x + 3
    
    x = x + 3
    
    x
    
    x += 5.0
    
    x
    
    x *= 2
    
    x
    

    논리형

    a = True
    b = False
    
    a and b
    
    a or b
    
    not a
    
    a == b
    
    a != b
    

    출력하기

    i = 3
    
    print(i)
    
    print('%d' % i)
    
    print(i + 2)
    
    print(type(i))
    
    j = 0.3
    
    print(type(j))
    

    문자열

    h = 'hello'
    k = "keras"
    
    print(h)
    print(len(h))
    hk = h + ' ' + k
    print(hk)
    print('%s %s %d' % (h, k, 2017))
    print(h + ' ' + k + ' ' + str(2017))
    
    print(h, hk)
    
    msg = 'keras'
    
    print(msg.capitalize())
    print(msg.upper())
    print(msg.replace('ras', 'RAS'))
    
    msg = '  keras  '
    
    print(msg.strip())
    

    자료구조

    배열

    values = [2, 6, 3]
    
    print(values)
    print(values[1])
    print(values[-1])
    
    values[0] = 'first'
    
    print(values)
    
    values.append(5)
    values.append('end')
    
    print(values)
    
    item = values.pop()
    
    print(item, values)
    

    배열 잘라내기

    range(5)
    
    values = range(5)
    
    print(values)
    print(values[2:4])
    print(values[2:])
    print(values[:4])
    print(values[:])
    print(values[:-1])
    
    values[2:4] = [8, 9]
    
    print(values)
    

    반복문

    idx = 0
    
    while idx < 10:
        print(idx)
        idx = idx + 1
    
    for idx in range(10):
        print(idx)
    
    people = ['kim', 'lee', 'choi']
    
    for p in people:
        print(p)
    
    people = ['kim', 'lee', 'choi']
    
    for i, p in enumerate(people):
        print('%d : %s' % (i, p))
    

    연습문제 구구단

    for i in range(9):
        for j in range(9):
            print("%d x %d = %d" % (i+1, j+1, (i+1) * (j+1)))
    

    List comprehensions

    values = [0, 1, 2, 3, 4]
    squares = []
    for v in values:
        squares.append(v ** 2)
    print squares
    
    values = [0, 1, 2, 3, 4]
    squares = [v ** 2 for v in values]
    print squares
    
    values = [0, 1, 2, 3, 4]
    even_squares = [v ** 2 for v in values if v % 2 == 0]
    print even_squares
    
    print([[(i+1)*(j+1) for i in range(9)] for j in range(9)])
    

    딕션러리

    A dictionary stores (key, value) pairs, similar to a Map in Java or an object in Javascript. You can use it like this:

    dic = {}
    dic['물리학과'] = '물리학의 각 분야에 걸친 이론과 응용방법을 심오하게 교수, 연구함으로써 독창적 능력을 함양하고 고도 산업사회를 선도해 갈 지도적 인재를 양성함을 목적으로 한다.'
    dic['우주과학과'] = '우주과학과는 천체 및 우주에서 일어나는 제반 현상을 과학적으로 탐사하고 연구하는 학과이다. 본 학과는 인류의 우주진출이 더욱 활발해 지고 있는 이 시대에 그를 위한 지식과 기술의 개발과 보급을 목적으로 설립되었다. 현대 천문학에서부터 인공위성과 우주선의 활용에 이르는 기초와 응용의 병행 학습을 통하여 21세기 우주 시대가 요구하는 첨단분야에서 국제적인 경쟁력이 있는 인재를 양성하는 데에 우주과학과의 교육 목적이 있다.'
    dic['우주탐사학과'] = '경희대학교 우주탐사학과(School of Space Research /KHU)는 교육과학기술부 제 1유형의 세계수준의 연구중심 대학 육성(WCU)사업에 달궤도 우주 탐사 연구 과제가 선정됨에 따라 설립된 대학원 학과로서 우리나라의 우주탐사를 위하여 본격적으로 전문인력 양성의 기틀을 마련하고자 한다. 한국 정부의 대학 교육 지원 과정의 세계 수준의 연구중심 대학(WCU) 육성사업을 통해 연구 역량이 높은 우수 해외 학자를 유치 활용하여, 국내 대학과 협력하여 핵심 성장 동력을 창출할 수 있는 분야의 연구를 활성화 하는데 그 목적이 있다. 다양한 프로젝트를 통해 국가적 발전을 선도하는 신 성장 동력을 창출하는 기술을 개발하는데 집중하고 있으며, 기초과학, 인문과학, 사회과학의 학제적 통합을 통해 학계 및 사회, 국가적 발전에 기여 할 수 있도록 정부에서 적극적으로 추진하고 있다.'
    
    print(dic['물리학과'])
    
    print(dic['우주과학과'])
    
    print(dic['우주탐사학과'])
    
    
    
    물리학의 각 분야에 걸친 이론과 응용방법을 심오하게 교수, 연구함으로써 독창적 능력을 함양하고 고도 산업사회를 선도해 갈 지도적 인재를 양성함을 목적으로 한다.
    우주과학과는 천체 및 우주에서 일어나는 제반 현상을 과학적으로 탐사하고 연구하는 학과이다. 본 학과는 인류의 우주진출이 더욱 활발해 지고 있는 이 시대에 그를 위한 지식과 기술의 개발과 보급을 목적으로 설립되었다. 현대 천문학에서부터 인공위성과 우주선의 활용에 이르는 기초와 응용의 병행 학습을 통하여 21세기 우주 시대가 요구하는 첨단분야에서 국제적인 경쟁력이 있는 인재를 양성하는 데에 우주과학과의 교육 목적이 있다.
    경희대학교 우주탐사학과(School of Space Research /KHU)는 교육과학기술부 제 1유형의 세계수준의 연구중심 대학 육성(WCU)사업에 달궤도 우주 탐사 연구 과제가 선정됨에 따라 설립된 대학원 학과로서 우리나라의 우주탐사를 위하여 본격적으로 전문인력 양성의 기틀을 마련하고자 한다. 한국 정부의 대학 교육 지원 과정의 세계 수준의 연구중심 대학(WCU) 육성사업을 통해 연구 역량이 높은 우수 해외 학자를 유치 활용하여, 국내 대학과 협력하여 핵심 성장 동력을 창출할 수 있는 분야의 연구를 활성화 하는데 그 목적이 있다. 다양한 프로젝트를 통해 국가적 발전을 선도하는 신 성장 동력을 창출하는 기술을 개발하는데 집중하고 있으며, 기초과학, 인문과학, 사회과학의 학제적 통합을 통해 학계 및 사회, 국가적 발전에 기여 할 수 있도록 정부에서 적극적으로 추진하고 있다.
    
    # -*- coding: utf8 -*-
     
    # 유니코드로 다루기 예제1
    hoo = unicode('한글', 'utf-8')
    print str(hoo.encode('utf-8'))
     
    # 유니코드로 다루기 예제2
    bar = '한글'.decode('utf-8')
    print bar.encode('utf-8')
     
    # 유니코드로 다루기 예제3
    foo = u'한글'
    print str(foo.encode('utf-8'))
    
    for item in dic.keys():
        print(item)
        
    for item in dic.values():
        print(item)
    
    우주탐사학과
    물리학과
    우주과학과
    경희대학교 우주탐사학과(School of Space Research /KHU)는 교육과학기술부 제 1유형의 세계수준의 연구중심 대학 육성(WCU)사업에 달궤도 우주 탐사 연구 과제가 선정됨에 따라 설립된 대학원 학과로서 우리나라의 우주탐사를 위하여 본격적으로 전문인력 양성의 기틀을 마련하고자 한다. 한국 정부의 대학 교육 지원 과정의 세계 수준의 연구중심 대학(WCU) 육성사업을 통해 연구 역량이 높은 우수 해외 학자를 유치 활용하여, 국내 대학과 협력하여 핵심 성장 동력을 창출할 수 있는 분야의 연구를 활성화 하는데 그 목적이 있다. 다양한 프로젝트를 통해 국가적 발전을 선도하는 신 성장 동력을 창출하는 기술을 개발하는데 집중하고 있으며, 기초과학, 인문과학, 사회과학의 학제적 통합을 통해 학계 및 사회, 국가적 발전에 기여 할 수 있도록 정부에서 적극적으로 추진하고 있다.
    물리학의 각 분야에 걸친 이론과 응용방법을 심오하게 교수, 연구함으로써 독창적 능력을 함양하고 고도 산업사회를 선도해 갈 지도적 인재를 양성함을 목적으로 한다.
    우주과학과는 천체 및 우주에서 일어나는 제반 현상을 과학적으로 탐사하고 연구하는 학과이다. 본 학과는 인류의 우주진출이 더욱 활발해 지고 있는 이 시대에 그를 위한 지식과 기술의 개발과 보급을 목적으로 설립되었다. 현대 천문학에서부터 인공위성과 우주선의 활용에 이르는 기초와 응용의 병행 학습을 통하여 21세기 우주 시대가 요구하는 첨단분야에서 국제적인 경쟁력이 있는 인재를 양성하는 데에 우주과학과의 교육 목적이 있다.
    
    '철학과' in dic
    
    False
    
    '우주탐사학과' in dic
    
    True
    
    d = {'cat': 'cute', 'dog': 'furry'}  # Create a new dictionary with some data
    print d['cat']       # Get an entry from a dictionary; prints "cute"
    print 'cat' in d     # Check if a dictionary has a given key; prints "True"
    
    
    
    d['fish'] = 'wet'    # Set an entry in a dictionary
    print d['fish']      # Prints "wet"
    
    print d['monkey']  # KeyError: 'monkey' not a key of d
    
    print d.get('monkey', 'N/A')  # Get an element with a default; prints "N/A"
    print d.get('fish', 'N/A')    # Get an element with a default; prints "wet"
    
    del d['fish']        # Remove an element from a dictionary
    print d.get('fish', 'N/A') # "fish" is no longer a key; prints "N/A"
    

    It is easy to iterate over the keys in a dictionary:

    d = {'person': 2, 'cat': 4, 'spider': 8}
    for animal in d:
        print(animal)
    
    d = {'person': 2, 'cat': 4, 'spider': 8}
    for animal in d:
        legs = d[animal]
        print('A %s has %d legs' % (animal, legs))
    
    d = {'person': 2, 'cat': 4, 'spider': 8}
    for animal, legs in d.iteritems():
        print('A %s has %d legs' % (animal, legs))
    
    nums = [0, 1, 2, 3, 4]
    even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}
    print(even_num_to_square)
    

    Sets

    animals = {'cat', 'dog'}
    print('cat' in animals)   # Check if an element is in a set; prints "True"
    print('fish' in animals)  # prints "False"
    
    
    animals.add('fish')      # Add an element to a set
    print('fish' in animals)
    print(len(animals))       # Number of elements in a set;
    
    animals.add('cat')       # Adding an element that is already in the set does nothing
    print(len(animals))
    animals.remove('cat')    # Remove an element from a set
    print(len(animals))
    

    Loops: Iterating over a set has the same syntax as iterating over a list; however since sets are unordered, you cannot make assumptions about the order in which you visit the elements of the set:

    animals = {'cat', 'dog', 'fish'}
    for idx, animal in enumerate(animals):
        print ('#%d: %s' % (idx + 1, animal))
    # Prints "#1: fish", "#2: dog", "#3: cat"
    

    Set comprehensions: Like lists and dictionaries, we can easily construct sets using set comprehensions:

    from math import sqrt
    
    nums = {int(sqrt(x)) for x in range(30)} 
    
    print(nums)
    

    튜플

    A tuple is an (immutable) ordered list of values. A tuple is in many ways similar to a list; one of the most important differences is that tuples can be used as keys in dictionaries and as elements of sets, while lists cannot. Here is a trivial example:

    a = 3
    b = 7
    
    temp = a
    a = b
    b = temp
    
    print a, b
    
    a = 3
    b = 7
    a, b = b, a
    print a, b
    
    t1 = (1, 3, 5)
    t2 = 2, 4, 6
    
    print(type(t1))
    print(type(t2))
    
    print(t1)
    print(t2)
    
    t3 = ()
    
    print(type(t3))
    print(t3)
    
    t4 = 1,
    t5 = (2)
    t6 = (2,)
    
    print(type(t4))
    print(type(t5))
    print(type(t6))
    print(t4)
    print(t5)
    print(t6)
    
    p = (1, 2, 3)
    print(p[:1])
    print(p[2:])
    q = p[:1] + (5,) + p[2:]
    print(q)
    
    r = p[:1], 5, p[2:]
    print(r)
    
    t = (1, 2, 3)
    print(t)
    l = list(t)
    print(l)
    t2 = tuple(l)
    print(t2)
    
    

    바로 기술적인 차이와 문화적인 차이다.

    둘 다 타입과 상관 없이 일련의 요소(element)를 갖을 수 있다. 두 타입 모두 요소의 순서를 관리한다. (세트(set)나 딕셔너리(dict)와 다르게 말이다.)

    이제 차이점을 보자. 리스트와 튜플의 기술적 차이점은 불변성에 있다. 리스트는 가변적(mutable, 변경 가능)이며 튜플은 불변적(immutable, 변경 불가)이다. 이 특징이 파이썬 언어에서 둘을 구분하는 유일한 차이점이다.

    이 특징은 리스트와 튜플을 구분하는 유일한 기술적 차이점이지만 이 특징이 나타나는 부분은 여럿 존재한다. 예를 들면 리스트에는 .append() 메소드를 사용해서 새로운 요소를 추가할 수 있지만 튜플은 불가능하다.

    튜플은 .append() 메소드가 필요하지 않다. 튜플은 수정할 수 없기 때문이다.

    문화적인 차이점을 살펴보자. 리스트와 튜플을 어떻게 사용하는지에 따른 차이점이 있다. 리스트는 단일 종류의 요소를 갖고 있고 그 일련의 요소가 몇 개나 들어 있는지 명확하지 않은 경우에 주로 사용한다. 튜플은 들어 있는 요소의 수를 사전에 정확히 알고 있을 경우에 사용한다. 동일한 요소가 들어있는 리스트와 달리 튜플에서는 각 요소의 위치가 큰 의미를 갖고 있기 때문이다.

    디렉토리 내에 있는 파일 중 *.py로 끝나는 파일을 찾는 함수를 작성한다고 가정해보자. 이 함수를 사용했을 때는 파일을 몇 개나 찾게 될 지 알 수 없다. 그리고 동일한 규칙으로 찾은 파일이기 때문에 항목 하나 하나가 의미상 동일하다. 그러므로 이 함수는 리스트를 반환할 것이다.

    find_files(“*.py”) [“control.py”, “config.py”, “cmdline.py”, “backward.py”] 다른 예를 확인한다. 기상 관측소의 5가지 정보, 식별번호, 도시, 주, 경도와 위도를 저장한다고 생각해보자. 이런 상황에서는 리스트보다 튜플을 사용하는 것이 적합하다.

    denver = (44, “Denver”, “CO”, 40, 105) denver[1] ‘Denver’ (지금은 클래스를 사용하는 것에 대해서 이야기하지 않을 것이다.) 이 튜플에서 첫 요소는 식별번호, 두 번째는 도시… 순으로 작성했다. 튜플에서의 위치가 담긴 내용이 어떤 정보인지를 나타낸다.

    C 언어에서 이 문화적 차이를 대입해보면 목록은 배열(array) 같고 튜플은 구조체(struct)와 비슷할 것이다.

    때때로 기술적인 고려가 문화적 고려를 덮어쓰는 경우가 있다. 리스트를 딕셔너리에서 키로 사용할 수 없다. 불변 값만 해시를 만들 수 있기 때문에 키에 불변 값만 사용 가능하다. 대신 리스트를 키로 사용하고 싶다면 다음 예처럼 리스트를 튜플로 변경했을 때 사용할 수 있다.

    d = {} nums = [1, 2, 3] d[nums] = “hello” Traceback (most recent call last): File “", line 1, in TypeError: unhashable type: 'list' d[tuple(nums)] = "hello" d {(1, 2, 3): 'hello'} 기술과 문화가 충돌하는 또 다른 예가 있다. 파이썬에서도 리스트가 더 적합한 상황에서 튜플을 사용하는 경우가 있다. *args를 함수에서 정의했을 때, args로 전달되는 인자는 튜플을 사용한다. 함수를 호출할 때 사용한 인자의 순서가 크게 중요하지 않더라도 말이다. 튜플은 불변이고 전달된 값은 변경할 수 없기 때문에 이렇게 구현되었다고 말할 수 있겠지만 그건 문화적 차이보다 기술적 차이에 더 가치를 두고 설명하는 방식이라 볼 수 있다.

    물론 *args에서 위치는 매우 큰 의미를 갖는다. 매개변수는 그 위치에 따라 의미가 크게 달라지기 때문이다. 하지만 함수는 *args를 전달 받고 다른 함수에 전달해준다고만 봤을 때 *args는 단순히 인자 목록이고 각 인자는 별 다른 의미적 차이가 없다고 할 수 있다. 그리고 각 함수에서 함수로 이동할 때마다 그 목록의 길이는 가변적인 것으로 볼 수 있다.

    파이썬이 여기서 튜플을 사용하는 이유는 리스트에 비해서 조금 더 공간 효율적이기 때문이다. 리스트는 요소를 추가하는 동작을 빠르게 수행할 수 있도록 더 많은 공간을 저장해둔다. 이 특징은 파이썬의 실용주의적 측면을 나타낸다. 이런 상황처럼 *args를 두고 리스트인지 튜플인지 언급하기 어려운 애매할 때는 그냥 상황을 쉽게 설명할 수 있도록 자료 구조(data structure)라는 표현을 쓰면 될 것이다.

    대부분의 경우에 리스트를 사용할지, 튜플을 사용할지는 문화적 차이에 기반해서 선택하게 될 것이다. 어떤 의미의 데이터인지 생각해보자. 만약 프로그램이 실제로 다루는 자료가 다른 길이의 데이터를 갖는다면 분명 리스트를 써야 할 것이다. 작성한 코드에서 세 번째 요소에 의미가 있는 경우라면 분명 튜플을 사용해야 할 상황이다.

    반면 함수형 프로그래밍에서는 코드를 어렵게 만들 수 있는 부작용을 피하기 위해서 불변 데이터 구조를 사용하라고 강조한다. 만약 함수형 프로그래밍의 팬이라면 튜플이 제공하는 불변성 때문에라도 분명 튜플을 좋아하게 될 것이다.

    자, 다시 질문해보자. 튜플을 써야 할까, 리스트를 사용해야 할까? 이 질문의 답변은 항상 간단하지 않다.

    d = {(x, x + 1): x for x in range(10)}  # Create a dictionary with tuple keys
    t = (5, 6)       # Create a tuple
    print type(t)
    print d[t]       
    print d[(1, 2)]
    
    t[0] = 1
    

    함수

    def sign(x):
        if x > 0:
            return 'positive'
        elif x < 0:
            return 'negative'
        else:
            return 'zero'
    
    for x in [-1, 0, 1]:
        print sign(x)
    

    We will often define functions to take optional keyword arguments, like this:

    def hello(name, loud=False):
        if loud:
            print 'HELLO, %s' % name.upper()
        else:
            print 'Hello, %s!' % name
    
    hello('Bob')
    hello('Fred', loud=True)
    
    today = '20170811'
    
    def curr_order(idx):
        print(today + ' ' + str(idx))
        
    curr_order(1)
    curr_order(2)
    
    def sum(a, b):
        return a + b
    
    print(sum(1,2))
    
    seed = 3
    
    def updown(mind, guess):
        if mind < guess:
            return 'down'
        elif mind > guess:
            return 'up'
        else:
            return 'correct'
    
    updown(seed, 3)
    
    def tuple_test(a, b, *c):
        print a, b, c
    
    tuple_test(1, 2, 3, 4, 5)
    

    클래스

    The syntax for defining classes in Python is straightforward:

    class Greeter:
    
        # Constructor
        def __init__(self, name):
            self.name = name  # Create an instance variable
    
        # Instance method
        def greet(self, loud=False):
            if loud:
                print 'HELLO, %s!' % self.name.upper()
            else:
                print 'Hello, %s' % self.name
    
    g = Greeter('Fred')  # Construct an instance of the Greeter class
    g.greet()            # Call an instance method; prints "Hello, Fred"
    g.greet(loud=True)   # Call an instance method; prints "HELLO, FRED!"
    
    class USB:
        def poweron(self):
            pass
        
    class FAN(USB):
        def poweron(self):
            print('wing~~')
            
    class Cup(USB):
        def poweron(self):
            print('cool')
            
    class Phone(USB):
        def poweron(self):
            print('charging...')
            
    f = FAN()
    f.poweron()
    
    c = Cup()
    c.poweron()
    
    p = Phone()
    p.poweron()
    
    wing~~
    cool
    charging...
    
    class USBhub(USB):
        
        def __init__(self):
            self.ports = []
            
        def add(self, USB):
            self.ports.append(USB)
        
        def poweron(self):
            for item in self.ports:
                item.poweron()
    
    hub = USBhub()
    hub.add(f)
    hub.add(c)
    hub.add(p)
    hub.poweron()
    
    wing~~
    cool
    charging...
    
    class Man:
        def think(self):
            pass
        
    class Android(Man, USB):
        def think(self):
            print('Who am I?')
            
        def poweron(self):
            print('Hello')
    
    a = Android()
    a.think()
    a.poweron()
    
    Who am I?
    Hello
    
    hub.add(a)
    hub.poweron()
    
    wing~~
    cool
    charging...
    Hello
    
    >>> class ParentOne:
        def func(self):
            print("ParentOne의 함수 호출!")
         
    >>> class ParentTwo:
        def func(self):
            print("ParentTwo의 함수 호출!")
         
    >>> class Child(ParentOne, ParentTwo):
        def childFunc(self):
            ParentOne.func(self)
            ParentTwo.func(self)
             
    >>> objectChild = Child()
    >>> objectChild.childFunc()
    ParentOne의 함수 호출!
    ParentTwo의 함수 호출!
    >>> objectChild.func()
    ParentOne의 함수 호출!
    
    
    출처: http://blog.eairship.kr/286 [누구나가  이해할  있는 프로그래밍 첫걸음]
    

    모듈

    import 모듈 
    from 모듈 import 변수
    from 모듈 import 함수
    
    import 모듈
    
    모듈.함수
    
    from 모듈 import *
    
    함수
    
    함수명이 동일할 때는 곤란
    
    import os
    
    os.getcwd()
    
    '/Users/tykimos/Projects/Keras/_writing'
    
    os.listdir(os.getcwd())
    
    ['.DS_Store',
     '.ipynb_checkpoints',
     '2017-1-27-CNN_Layer_Talk.ipynb',
     '2017-1-27-Keras_Talk.ipynb',
     '2017-1-27-LossFuncion_Talk.ipynb',
     '2017-1-27-MLP_Layer_Talk.ipynb',
     '2017-1-27-Optimizer_Talk.ipynb',
     '2017-2-22-Integrating_Keras_and_TensorFlow.ipynb',
     '2017-2-4-AutoEncoder_Getting_Started.ipynb',
     '2017-2-4-BinaryClassification_Example.ipynb',
     '2017-2-4-ImageClassification_Example.ipynb',
     '2017-2-4-MLP_Getting_Started-Copy1.ipynb',
     '2017-2-4-MLP_Getting_Started.ipynb',
     '2017-2-4-MulticlassClassification_Example.ipynb',
     '2017-2-4-ObjectRecognition_Example.ipynb',
     '2017-2-4-Regression_Example.ipynb',
     '2017-2-4-RNN_Getting_Started.ipynb',
     '2017-2-4-TimeSeriesPrediction_Example.ipynb',
     '2017-2-6-First_Keras_Offline_Meeting.ipynb',
     '2017-3-11-To_Use_TensorBoard.ipynb',
     '2017-3-15-Keras_Offline_Install.ipynb',
     '2017-3-25-Dataset_and_Fit_Talk.ipynb',
     '2017-3-8-CNN_Data_Augmentation.ipynb',
     '2017-3-8-CNN_Getting_Started.ipynb',
     '2017-4-9-RNN_Getting_Started_2.ipynb',
     '2017-4-9-RNN_Layer_Talk.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression-Copy1.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression.ipynb',
     '2017-5-21-Conv_LSTM_Example.ipynb',
     '2017-5-22-Evaluation_Talk.ipynb',
     '2017-6-10-Model_Save_Load.ipynb',
     '2017-6-17-Relation_Network.ipynb',
     '2017-7-9-Early_Stopping.ipynb',
     '2017-7-9-Training_Monitoring.ipynb',
     '2017-8-10-Python_Package_Talk.ipynb',
     '2017-8-10-Python_Talk-Copy1.ipynb',
     '2017-8-10-Python_Talk.ipynb',
     '2017-8-4-RNN_Classification.ipynb',
     '2017-8-7-Keras_Install_on_Mac.ipynb',
     '2017-8-9-DeepBrick_Talk.ipynb',
     'abstract',
     'Animate.ipynb',
     'cosine_LSTM-Copy1.ipynb',
     'cosine_LSTM-Copy2.ipynb',
     'cosine_LSTM-Copy3.ipynb',
     'cosine_LSTM-Copy4.ipynb',
     'cosine_LSTM-flux.ipynb',
     'cosine_LSTM.ipynb',
     'Data_RNN.zip',
     'exAnimation.gif',
     'FeedPrediction_DeepStackedStatefulLSTM.ipynb',
     'Flare_Flux_Prediction.ipynb',
     'Flux Case 1.ipynb',
     'Flux Case 2.ipynb',
     'Flux_deep_stacked_stateful_LSTM_with_one_sample.ipynb',
     'Flux_Test-Copy1.ipynb',
     'Flux_Test.ipynb',
     'Flux_Test_Stateful.ipynb',
     'FullSizeRender.jpg',
     'graph',
     'HEPFluxPrediction_DeepStackedStatefulLSTM-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200.ipynb',
     'image.png',
     'lecture.ipynb',
     'LSTM.py',
     'model.png',
     'object detector.ipynb',
     'sin_w40_u32_s2_e200.gif',
     'SPE_Prediction.ipynb',
     'stateful RNNs.ipynb',
     'tykimos.txt',
     'Untitled.ipynb',
     'w12_u64_s2_e300.gif',
     'w24_u128_s1_e100.gif',
     'w40_u128_s2_e200.gif',
     'w40_u128_s4_e1000.gif',
     'w40_u32_s2_e1.gif',
     'warehouse']
    
    os.rename('tykimos.txt', 'tykimos2.txt')
    
    os.listdir(os.getcwd())
    
    ['.DS_Store',
     '.ipynb_checkpoints',
     '2017-1-27-CNN_Layer_Talk.ipynb',
     '2017-1-27-Keras_Talk.ipynb',
     '2017-1-27-LossFuncion_Talk.ipynb',
     '2017-1-27-MLP_Layer_Talk.ipynb',
     '2017-1-27-Optimizer_Talk.ipynb',
     '2017-2-22-Integrating_Keras_and_TensorFlow.ipynb',
     '2017-2-4-AutoEncoder_Getting_Started.ipynb',
     '2017-2-4-BinaryClassification_Example.ipynb',
     '2017-2-4-ImageClassification_Example.ipynb',
     '2017-2-4-MLP_Getting_Started-Copy1.ipynb',
     '2017-2-4-MLP_Getting_Started.ipynb',
     '2017-2-4-MulticlassClassification_Example.ipynb',
     '2017-2-4-ObjectRecognition_Example.ipynb',
     '2017-2-4-Regression_Example.ipynb',
     '2017-2-4-RNN_Getting_Started.ipynb',
     '2017-2-4-TimeSeriesPrediction_Example.ipynb',
     '2017-2-6-First_Keras_Offline_Meeting.ipynb',
     '2017-3-11-To_Use_TensorBoard.ipynb',
     '2017-3-15-Keras_Offline_Install.ipynb',
     '2017-3-25-Dataset_and_Fit_Talk.ipynb',
     '2017-3-8-CNN_Data_Augmentation.ipynb',
     '2017-3-8-CNN_Getting_Started.ipynb',
     '2017-4-9-RNN_Getting_Started_2.ipynb',
     '2017-4-9-RNN_Layer_Talk.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression-Copy1.ipynb',
     '2017-5-20-LSTM_Example_Feeding_Regression.ipynb',
     '2017-5-21-Conv_LSTM_Example.ipynb',
     '2017-5-22-Evaluation_Talk.ipynb',
     '2017-6-10-Model_Save_Load.ipynb',
     '2017-6-17-Relation_Network.ipynb',
     '2017-7-9-Early_Stopping.ipynb',
     '2017-7-9-Training_Monitoring.ipynb',
     '2017-8-10-Python_Package_Talk.ipynb',
     '2017-8-10-Python_Talk-Copy1.ipynb',
     '2017-8-10-Python_Talk.ipynb',
     '2017-8-4-RNN_Classification.ipynb',
     '2017-8-7-Keras_Install_on_Mac.ipynb',
     '2017-8-9-DeepBrick_Talk.ipynb',
     'abstract',
     'Animate.ipynb',
     'cosine_LSTM-Copy1.ipynb',
     'cosine_LSTM-Copy2.ipynb',
     'cosine_LSTM-Copy3.ipynb',
     'cosine_LSTM-Copy4.ipynb',
     'cosine_LSTM-flux.ipynb',
     'cosine_LSTM.ipynb',
     'Data_RNN.zip',
     'exAnimation.gif',
     'FeedPrediction_DeepStackedStatefulLSTM.ipynb',
     'Flare_Flux_Prediction.ipynb',
     'Flux Case 1.ipynb',
     'Flux Case 2.ipynb',
     'Flux_deep_stacked_stateful_LSTM_with_one_sample.ipynb',
     'Flux_Test-Copy1.ipynb',
     'Flux_Test.ipynb',
     'Flux_Test_Stateful.ipynb',
     'FullSizeRender.jpg',
     'graph',
     'HEPFluxPrediction_DeepStackedStatefulLSTM-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200-Copy1.ipynb',
     'HEPFluxPrediction_DeepStackedStatefulLSTM_v200.ipynb',
     'image.png',
     'lecture.ipynb',
     'LSTM.py',
     'model.png',
     'object detector.ipynb',
     'sin_w40_u32_s2_e200.gif',
     'SPE_Prediction.ipynb',
     'stateful RNNs.ipynb',
     'tykimos2.txt',
     'Untitled.ipynb',
     'w12_u64_s2_e300.gif',
     'w24_u128_s1_e100.gif',
     'w40_u128_s2_e200.gif',
     'w40_u128_s4_e1000.gif',
     'w40_u32_s2_e1.gif',
     'warehouse']
    
    import webbrowser
    url = 'http://www.google.com'
    webbrowser.open(url)
    
    True
    
    ### 랜덤
    
    import random
    
    random.random()
    
    0.5919179034090589
    
    random.randrange(1, 7)
    
    4
    
    range(1, 7)
    
    [1, 2, 3, 4, 5, 6]
    
    abc = ['a', 'b', 'c', 'd', 'e']
    
    random.shuffle(abc)
    
    abc
    
    ['b', 'e', 'c', 'd', 'a']
    
    random.choice(abc)
    
    'b'
    
    random.choice([True, False])
    
    True
    

    파일

    lines = ['1. first\n', '2. second\n', '3. third\n']
    
    f = open('text.txt', 'w')
    f.writelines(lines)
    f.close()
    
    f = open('text.txt')
    print(f.readline())
    print(f.readline())
    print(f.readline())
    f.close()
    
    1. first
    
    2. second
    
    3. third
    
    f = open('text.txt')
    print(f.readlines())
    f.close()
    
    ['1. first\n', '2. second\n', '3. third\n']
    
    f = open('text.txt')
    lines = f.readlines()
    
    import sys
    sys.stdout.writelines(lines)
    
    1. first
    2. second
    3. third
    
    
    

  • 한장간 - 네트워크와 모델


    간(GAN)을 시작하기에 앞서 케라스에서 네트워크와 모델 개념 정립을 먼저 한 후에 간단한 간모델을 만들어보겠습니다. 네트워크와 모델 개념을 레고 사람에 비유를 들어보겠습니다. 초반부는 귀엽겠지만 후반부에는 조금 무서울 수 있으니 노약자나 임산부는 주의해서 보시기 바랍니다.


    간(GAN)보기에 앞서

    간관련 공부를 하다보면 네트워크도 여러개 나오고 모델과 손실함수도 여러개라서 상당히 헷갈렸습니다. 기초적인 딥러닝이나 케라스 개념을 익히셨다면 간보기에 앞서 네트워크와 모델 개념을 분리하고, 모델에서도 손실함수와 최적화기도 분리해서 개념을 정립하면 기본 간 모델은 물론 복잡한 간 모델을 이해하는 데 도움이 많이 될 것 같습니다.


    네트워크

    신경망에서 가장 기본적인 요소가 ‘뉴론’입니다. 이러한 뉴론 여러개가 구성된 것이 ‘레이어’이고 레이어가 여러 층으로 쌓여있는 것을 ‘네트워크’라 합니다. 입력 뉴런과 출력 뉴런 간에 연결선을 시냅스라 부르고 이 연결 강도를 ‘가중치’라고 합니다. 아래 그림은 입력 4개에 출력 3개 뉴런을 가진 전결합층을 표한한 것입니다. (a)에서 보면 학습해야할 녹색 가중치 블록이 12개가 있습니다. 이를 좀 더 간단하게 표시한 것이 (b)인데, 여기서는 가중치가 연결선으로만 표시되어 있습니다. (c)는 (b)를 좀 더 간략하게 표시한 것입니다. (c)의 아래 그림을 보면 ‘3’으로 표기되어 있는 데, 이는 출력 뉴런의 수를 표기한 것입니다. 케라스에서는 입력 뉴런 수는 입력에 따라 정해지기 때문에 입력층이 아닌 은닉층에서는 따로 지정할 필요는 없습니다.

    img

    여러개의 층을 쌓아보자

    img

    from keras.models import Sequential
    from keras.layers.core import Dense
    from keras.layers.advanced_activations import LeakyReLU
    
    generator = Sequential()
    generator.add(Dense(256, input_dim=100))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(512))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(1024))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(784, activation='tanh'))
    

    입출력에 대한 설명.

    img

    import numpy as np
    
    random_latent_vectors = np.random.normal(0, 1, size=[1, 100])
    
    generated_data = generator.predict(random_latent_vectors)
    generated_images = generated_data.reshape(1, 28, 28)
    
    (-0.5, 27.5, 27.5, -0.5)
    

    png

    img

    %matplotlib inline
    import matplotlib.pyplot as plt
            
    plt.imshow(generated_images[0], interpolation='nearest')
    plt.axis('off')
    
    import os
    os.environ["KERAS_BACKEND"] = "tensorflow"
    import numpy as np
    from tqdm import tqdm
    import matplotlib.pyplot as plt
    
    from keras.layers import Input
    from keras.models import Model, Sequential
    from keras.layers.core import Reshape, Dense, Dropout, Flatten
    from keras.layers.advanced_activations import LeakyReLU
    from keras.layers.convolutional import Convolution2D, UpSampling2D
    from keras.layers.normalization import BatchNormalization
    from keras.datasets import mnist
    from keras.optimizers import Adam
    from keras import backend as K
    from keras import initializers
    
    K.set_image_dim_ordering('th')
    
    # Deterministic output.
    # Tired of seeing the same results every time? Remove the line below.
    np.random.seed(1000)
    
    # The results are a little better when the dimensionality of the random vector is only 10.
    # The dimensionality has been left at 100 for consistency with other GAN implementations.
    randomDim = 100
    
    # 1. 데이터셋 생성하기
    
    # Load MNIST data
    (X_train, y_train), (X_test, y_test) = mnist.load_data()
    X_train = (X_train.astype(np.float32) - 127.5)/127.5
    X_train = X_train.reshape(60000, 784)
    
    # 2. 모델 구성하기
    
    # 2.1 생성기 모델
    generator = Sequential()
    generator.add(Dense(256, input_dim=latent_dim))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(512))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(1024))
    generator.add(LeakyReLU(0.2))
    generator.add(Dense(784, activation='tanh'))
    
    # 2.2 판별기 모델
    discriminator = Sequential()
    discriminator.add(Dense(1024, input_dim=784))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))
    discriminator.add(Dense(512))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))
    discriminator.add(Dense(256))
    discriminator.add(LeakyReLU(0.2))
    discriminator.add(Dropout(0.3))
    discriminator.add(Dense(1, activation='sigmoid'))
    
    # 2.3 간 모델
    ganInput = Input(shape=(randomDim,))
    x = generator(ganInput)
    ganOutput = discriminator(x)
    gan = Model(inputs=ganInput, outputs=ganOutput)
    
    # 3. 모델 학습과정 설정하기
    
    # Optimizer
    adam = Adam(lr=0.0002, beta_1=0.5)
    
    # 3.1 판별기 모델 학습과정 설정
    discriminator.compile(loss='binary_crossentropy', optimizer=adam)
    
    # 3.2 간 모델 학습과정 설정
    discriminator.trainable = False
    gan.compile(loss='binary_crossentropy', optimizer=adam)
    
    
    
    dLosses = []
    gLosses = []
    
    # Plot the loss from each batch
    def plotLoss(epoch):
        plt.figure(figsize=(10, 8))
        plt.plot(dLosses, label='Discriminitive loss')
        plt.plot(gLosses, label='Generative loss')
        plt.xlabel('Epoch')
        plt.ylabel('Loss')
        plt.legend()
        plt.savefig('./warehouse/simplegan/images/gan_loss_epoch_%d.png' % epoch)
    
    # Create a wall of generated MNIST images
    def plotGeneratedImages(epoch, examples=100, dim=(10, 10), figsize=(10, 10)):
        noise = np.random.normal(0, 1, size=[examples, randomDim])
        generatedImages = generator.predict(noise)
        generatedImages = generatedImages.reshape(examples, 28, 28)
    
        plt.figure(figsize=figsize)
        for i in range(generatedImages.shape[0]):
            plt.subplot(dim[0], dim[1], i+1)
            plt.imshow(generatedImages[i], interpolation='nearest', cmap='gray_r')
            plt.axis('off')
        plt.tight_layout()
        plt.savefig('./warehouse/simplegan/images/gan_generated_image_epoch_%d.png' % epoch)
    
    # Save the generator and discriminator networks (and weights) for later use
    def saveModels(epoch):
        generator.save('./warehouse/simplegan/models/gan_generator_epoch_%d.h5' % epoch)
        discriminator.save('./warehouse/simplegan/models/gan_discriminator_epoch_%d.h5' % epoch)
    
    def train(epochs=1, batchSize=128):
        batchCount = X_train.shape[0] / batchSize
        print 'Epochs:', epochs
        print 'Batch size:', batchSize
        print 'Batches per epoch:', batchCount
    
        for e in xrange(1, epochs+1):
            print '-'*15, 'Epoch %d' % e, '-'*15
            for _ in tqdm(xrange(batchCount)):
                # Get a random set of input noise and images
                noise = np.random.normal(0, 1, size=[batchSize, randomDim])
                imageBatch = X_train[np.random.randint(0, X_train.shape[0], size=batchSize)]
    
                # Generate fake MNIST images
                generatedImages = generator.predict(noise)
                # print np.shape(imageBatch), np.shape(generatedImages)
                X = np.concatenate([imageBatch, generatedImages])
    
                # Labels for generated and real data
                yDis = np.zeros(2*batchSize)
                # One-sided label smoothing
                yDis[:batchSize] = 0.9
    
                # Train discriminator
                dloss = discriminator.train_on_batch(X, yDis)
    
                # Train generator
                noise = np.random.normal(0, 1, size=[batchSize, randomDim])
                yGen = np.ones(batchSize)
                gloss = gan.train_on_batch(noise, yGen)
    
            # Store loss of most recent batch from this epoch
            dLosses.append(dloss)
            gLosses.append(gloss)
    
            plotGeneratedImages(e)        
            
            if e == 1 or e % 20 == 0:
    
                saveModels(e)
    
        # Plot losses from every epoch
        plotLoss(e)
    
    if __name__ == '__main__':
        train(200, 128)
    

    사소한 변화를 무시해주는 맥스풀링(Max Pooling) 레이어

    컨볼루션 레이어의 출력 이미지에서 주요값만 뽑아 크기가 작은 출력 영상을 만듭니다. 이것은 지역적인 사소한 변화가 영향을 미치지 않도록 합니다.

    MaxPooling2D(pool_size=(2, 2))
    

    주요 인자는 다음과 같습니다.

    • pool_size : 수직, 수평 축소 비율을 지정합니다. (2, 2)이면 출력 영상 크기는 입력 영상 크기의 반으로 줄어듭니다.

    예를 들어, 입력 영상 크기가 4 x 4이고, 풀 크기를 (2, 2)로 했을 때를 도식화하면 다음과 같습니다. 녹색 블록은 입력 영상을 나타내고, 노란색 블록은 풀 크기에 따라 나눈 경계를 표시합니다. 해당 풀에서 가장 큰 값을 선택하여 파란 블록으로 만들면, 그것이 출력 영상이 됩니다. 가장 오른쪽은 맥스풀링 레이어를 약식으로 표시한 것입니다.

    lego_12

    이 레이어는 영상의 작은 변화라던지 사소한 움직임이 특징을 추출할 때 크게 영향을 미치지 않도록 합니다. 영상 내에 특징이 세 개가 있다고 가정했을 때, 아래 그림에서 첫 번째 영상을 기준으로 두 번째 영상은 오른쪽으로 이동하였고, 세 번째 영상은 약간 비틀어 졌고, 네 번째 영상은 조금 확대되었지만, 맥스풀링한 결과는 모두 동일합니다. 얼굴 인식 문제를 예를 들면, 맥스풀링의 역할은 사람마다 눈, 코, 입 위치가 조금씩 다른데 이러한 차이가 사람이라고 인식하는 데 있어서는 큰 영향을 미치지 않게 합니다.

    lego_13


    영상을 일차원으로 바꿔주는 플래튼(Flatten) 레이어

    CNN에서 컨볼루션 레이어나 맥스풀링 레이어를 반복적으로 거치면 주요 특징만 추출되고, 추출된 주요 특징은 전결합층에 전달되어 학습됩니다. 컨볼루션 레이어나 맥스풀링 레이어는 주로 2차원 자료를 다루지만 전결합층에 전달하기 위해선 1차원 자료로 바꿔줘야 합니다. 이 때 사용되는 것이 플래튼 레이어입니다. 사용 예시는 다음과 같습니다.

    Flatten()
    

    이전 레이어의 출력 정보를 이용하여 입력 정보를 자동으로 설정되며, 출력 형태는 입력 형태에 따라 자동으로 계산되기 때문에 별도로 사용자가 파라미터를 지정해주지 않아도 됩니다. 크기가 3 x 3인 영상을 1차원으로 변경했을 때는 도식화하면 다음과 같습니다.

    lego_14


    한 번 쌓아보기

    지금까지 알아본 레이어를 이용해서 간단한 컨볼루션 신경망 모델을 만들어보겠습니다. 먼저 간단한 문제를 정의해봅시다. 손으로 삼각형, 사각형, 원을 손으로 그린 이미지가 있고 이미지 크기가 8 x 8이라고 가정해봅니다. 삼각형, 사각형, 원을 구분하는 3개의 클래스를 분류하는 문제이기 때문에 출력 벡터는 3개여야 합니다. 필요하다고 생각하는 레이어를 구성해봤습니다.

    lego_22

    • 컨볼루션 레이어 : 입력 이미지 크기 8 x 8, 입력 이미지 채널 1개, 필터 크기 3 x 3, 필터 수 2개, 경계 타입 ‘same’, 활성화 함수 ‘relu’

    lego_15

    • 맥스풀링 레이어 : 풀 크기 2 x 2

    lego_16

    • 컨볼루션 레이어 : 입력 이미지 크기 4 x 4, 입력 이미지 채널 2개, 필터 크기 2 x 2, 필터 수 3개, 경계 타입 ‘same’, 활성화 함수 ‘relu’

    lego_17

    • 맥스풀링 레이어 : 풀 크기 2 x 2

    lego_18

    • 플래튼 레이어

    lego_19

    • 댄스 레이어 : 입력 뉴런 수 12개, 출력 뉴런 수 8개, 활성화 함수 ‘relu’

    lego_20

    • 댄스 레이어 : 입력 뉴런 수 8개, 출력 뉴런 수 3개, 활성화 함수 ‘softmax’

    lego_21

    모든 레이어 블록이 준비되었으니 이를 조합해 봅니다. 입출력 크기만 맞으면 블록 끼우듯이 합치면 됩니다. 참고로 케라스 코드에서는 가장 첫번째 레이어를 제외하고는 입력 형태를 자동으로 계산하므로 이 부분은 신경쓰지 않아도 됩니다. 레이어를 조립하니 간단한 컨볼루션 모델이 생성되었습니다. 이 모델에 이미지를 입력하면, 삼각형, 사각형, 원을 나타내는 벡터가 출력됩니다.

    lego_23

    그럼 케라스 코드로 어떻게 구현하는 지 알아봅니다. 먼저 필요한 패키지를 추가하는 과정입니다. 케라스의 레이어는 ‘keras.layers’에 정의되어 있으며, 여기서 필요한 레이어를 추가합니다.

    import numpy
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.layers import Flatten
    from keras.layers.convolutional import Conv2D
    from keras.layers.convolutional import MaxPooling2D
    from keras.utils import np_utils
    
    Using Theano backend.
    

    Sequential 모델을 하나 생성한 뒤 위에서 정의한 레이어를 차례차레 추가하면 컨볼루션 모델이 생성됩니다.

    model = Sequential()
    
    model.add(Conv2D(2, (3, 3), padding='same', activation='relu', input_shape=(8, 8, 1)))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Conv2D(3, (2, 2), padding='same', activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(8, activation='relu'))
    model.add(Dense(3, activation='softmax'))
    

    생성한 모델을 케라스에서 제공하는 함수를 이용하여 가시화 시켜봅니다.

    from IPython.display import SVG
    from keras.utils.vis_utils import model_to_dot
    
    %matplotlib inline
    
    SVG(model_to_dot(model, show_shapes=True).create(prog='dot', format='svg'))
    

    svg

    model


    요약

    컨볼루션 신경망 모델에서 사용되는 주요 레이어의 원리와 역할에 대해서 알아보았고 레이어를 조합하여 간단한 컨볼루션 신경망 모델을 만들어봤습니다.


    같이 보기