오늘 또.. 광고가...

  • 광고 팝업 관련해서 댓글을 달아 주신 내용을 참고삼아 #_enliple 을 검색해 보았더니.. 세상에. 링크의 끝에 #_enliple 이 붙어 있는게 너무 많더라...

어떻게 저 링크가 만들어 질까?

  • 궁금해서 링크가 있는것들을 찾아서 소스코드를 확인해 보니 자주 보였던 mobon.net 이 보인다. 그리고 dreamsearch.or.kr 도 보인다.
  • mobon.net에서 사용되는 javascript는 아래와 같다.
    • 코드를 간단히 설명하면,
      • 해당 사이트에 접근해서 url에 #_enplie라는 hash가 없으면, url 주소의 끝에 #_enplie를 붙여 주고
      • hash가 변경되면(위에서 변경했음), 광고로(adUrl)로 이동한다.
    • 아래의 동영상 확인
  • 즉, 걍 저 스크립트가 페이지에 있으면 무조건 url의 hash 부분을 변경하게 된다.
  • 이후, 사용자들은 페이지를 facebook등에 공유하게 되면 url의 끝에 #_enplie가 붙어 있는 url을 공유하게 되는것이다.
  •  얼마나 링크들이 많이 퍼졌는지를 트래킹하기 위한 정보로 사용하는것인지, 아니면 광고를 잘 처리 했다는 의미로 사용하는것인지는 모르겠다.

오늘은 여기까지. ㅎ.

이런이런.. 또 뜨네?

  • 그래서 이제는 코드까지 좀 뜯어 보기로

코드는?

  • YTN에 페이지에 접근했는데 광고가 또 떴다.
  • 그래서 이제는 코드를 뜯어 보기로...
  • 개발자 도구를 띄웠는데.. 에러가 나있네?

에러난쪽 코드 분석...

  • 에러는 다음의 jquery에서 시작된 것이다.
    • 이 파일을 열어 보면, mobon.net 이라는 사이트에서 jquery를 다시 긁어 오는것을 알 수 있다.
    • mobon.net 사이트에 접근해 보면, 이전에 조사한 사이트인 인라이플라는 회사가 연관되어 있는것을 알 수 있다.
      • 또한, mediacategory 사이트에 접근할때, megadata.co.kr 이라는 사이트에서 javascript를 다운 받는다. 해당 자바스크립트에는 인플라이 광고주 랜딩처리 한다고 적혀 있다.
  • 또한 해당 코드를 확인해보면 의심스러운 몇가지 행동을 하는 코드를 발견할 수 있다.
    • HTML Document에 a tag를 만들어 추가하고, click event를 발생시키는 코드. 이후 추가한 a tag를 제거하고 있다.
    • 빈 새창을 띄우고, focus를 보낸뒤, 창을 닫는 동작
    • 모바일 웹 브라우져면 동작하지 않도록
    • Safari면 동작하지 않도록
    • 볼만한 부분은 아래 부분이다. 계속해서 about:blank popup을 만들고 focus를 주고, close 시키는것을 0.5초마다 반복하도록 한다.

엇...

  • 실수로 창을 닫아 버렸다. -_-;;;
  • 오늘은 여기까지... ;;;
  1. 한수 배우고 싶습니다 2019.06.09 21:05

    수고 많으십니다. 선생님.
    #_enliple"target="_blank'>~~ 요런 해시태그를 캐다 보니 이 홈피까지 와서 많이 배우게 될 거 같은데요
    이 해시태그가 정확히 무얼 의미하는 것인지, 저 광고 회사와 어떤 연관이 있는지 정확하게 좀 알고 싶습니다.

    • 2019.06.26 13:06 신고

      헐... 저도 아직 가끔씩 광고창이 뜨고 있습니다. 크롬 플러그인에서 무언가가 있는지도 확인해 봐야 할 듯 해요.

      저 광고회사랑은 반드시 연관이 있다고 생각하고 있습니다. ^_^

  2. 돈덕후만 2019.06.10 09:30 신고

    감사합니다.
    너무 궁금한데, 실력이 미천하여 추적하지는 못하고 고수님의 글 보고 있습니다.
    막을 수 없더라도 이유는 알고 싶어서 계속 방문하겠습니다.

    • 2019.06.26 13:09 신고

      음.. 아마도 hosts 파일을 변경하는것으로 광고 뜨는것을 막을 수는 있을듯 합니다.

      https://vfxpedia.tistory.com/8

      위 글을 확인해 보시고, 해당 회사의 도메인도 등록해 주시면 동작하지 않을듯 합니다.

      잘 되면 알려 주세요 ^_^

크롬에서 가끔 광고창이 뜬다. 그것도 팝업으로..

  • 요즘에는 웹브라우져에서 기본적으로 팝업을 다 막아 둔다.
  • 그런데도 가끔씩 팝업으로 광고가 뜨는 경우가 있다.
  • 근데 이게 맨날 뜨는건 아니라서, 그냥 참고 쓰고 있었는데...

이거 안되겠다.

  • 궁금하기도 하고 말야... ㅎ.

어떤 경우에 떴었지?

  • 우선 팝업으로 광고창이 뜰 때 상황을 대략 보면
    • 새 탭으로 링크를 열때 주로 뜨더라 ( 내가 거의 모든 창을 새 탭으로 띄워서.. 그렇게 생각 된 것일수도... )
    • 새 탭으로 링크를 열면, 해당 창에서 popup이 blocking 된다는 아이콘이 여러번 나온뒤, 팝업창이 뜨고 광고가 나온다.

어떤 과정을 통해서 뜨지?

  • 크롬에서 팝업이 뜨면, "이전"으로 갈 수 없으므로, 팝업을 띄운 놈을 알기 어려운 문제가 있다.
  • 하지만, 팝업 창에서 F12나, Ctrl+Shift+I를 누르면 나오는 개발자 도구에서 정보를 얻을 수 있는데...
  • 그 중 network 상태를 보면 앞 부분에 appier.net 에 대해 연결 되는것을 볼 수 있다.
  • 그 정보를 분석해 보면
    • 출발지(referer) : www.mediacategory.com
    • URL Request : anylist.c.appier.net
    • 광고할 사이트 : dongwonmall.com

그래서 각 사이트는 뭔가?

  • URL 주소가 몇개가 있는데, 각 사이트는 뭔지 확인해 보자.

    • 광고할 사이트 dongwonmall은... 말 그대로 동원몰 이다.

    • Request를 보내는 appier.net 는 광고 마케팅 업체이다.

    • mediacategory.com 에 접근해서 정보를 보면, 많은양의 cookie 정보를 가지고 있는것을 알 수 있다.

      • mediacategoty.com 의 도메인 정보를 보면 주인이 enliple.com 인것을 알 수 있다.

      • enliple 역시 광고 플랫폼 회사다.

어떻게 크롬 팝업 block을 뚫고 뜨는거지?

  • 이건 아직 모르겠다. 다음번에 팝업 blocker를 뚥고 나올때, 다시 보고 분석하는것으로.. 끝. ㅋ.

결론

  • 광고 업체는 어떻게든.. 먹고 사는구나...
  • 이 업체에 광고를 맡긴 업체에게 뭐라고 해야, 하려나? 이런식의 광고는 사용자에게 나쁜 경험을 준다고?

읽기전

  • 인공지능으로 간단하게 만들어 본게 있는데, Keras(케라스)를 이용해서 만들었다.
  • 여러곳을 참고해 보니, 아예 연구자가 아닌 이상 케라스를 이용하면 왠만한건 할 수 있다는 이야기를 보았다.
  • 물론 간단하게 만들어 본 것 역시 케라스를 이용해서 만들었다.
  • 그래서 케라스 자체를 좀 더 알아 보는게 좋을 것이 생각해서 구매한 책.

기타

  • 보통 책과 관련없는 내용은 아랫쪽에 따로 두기도 하는데..
  • 책 자체에 역자가 많은 주석을 달아 두었다. 그래서 책을 읽기가 좋다.
  • 대부분의 이론들이나, 전망은 걍 생략했다. 이 글을 읽는 사람이 있다면, 자세한 내용은 책을 구매해서 읽으시길...
  • 초급용 책을 뗐다면, 이 책을 읽어 보는것을 추천한다. 참고로 초급용 책은 "모두의 딥러닝"을 추천한다.

책읽기

1부 딥러닝의 기초

  • 이론적인 내용 생략

1장 딥러닝이란 무엇인가?

  • 이론적인 내용 생략

인공지능과 머신 러닝, 딥러닝

  • 인공지능 : 보통의 사람이 수행하는 지능적인 작업을 자동화 하기 위한 연구 활동
  • 머신러닝 시스템은 명시적으로 프로그램 되는 것이 아니라 훈련(training)
  • 데이터 포인트 라는 말이 나오는데, 인공지능 학습에 사용되는 데이터들을 데이터 포인트 라는 용어로 잘 사용하더라. ( 직전에 읽은, 피처 엔지니어링 책에서도 데이터 포인트 라는 용어를 사용했던것 같다. )
  • 표현(representation) : 머신러닝과 딥러닝의 핵심 문제ㄴ,ㄴ 입력 데이터를 기반으로 기대 출력에 가깝게 만드는 유용한 표현을 학습하는것.
    • 핵심은 데이터를 인코딩하거나 묘사하기 위해 데이터를 바라보는 방법
    • 이미지가 RGB 혹은 HSV로 바뀌는것도 표현이 바뀌는것
    • 2차원 데이터 포인트들에서, 좌표를 변환하는것.
    • 시스템적으로 데이터 포인트를 잘 구분할 수 있도록, "학습"시킬 수 있다.
    • 이 과정중 일부는 기계가 "학습"하기 쉽게, 사람이 먼저 "피처 엔지니어링"을 해야 할 수도 있겠다.
  • 뉴럴넷은 뇌구조를 이해하는것에 영감을 만들어 진 것이다. 진짜 사람의 뇌가 그렇게 동작한다는 근거는 없다.

딥러닝 이전: 머신 러닝의 간략한 역사

  • 확률적 모델링
    • 통계학 이론을 데이터 분석에 응용
    • 나이브 베이즈 알고리즘
      • 입력 데이터의 특성이 모두 독립적이다고 가정
      • 고전적인 방법이라, 컴퓨터 등장전에는 수작업으로 적용
    • 로지스틱 회귀
      • 회귀 알고리즘이 아니라, 분류 알고리즘
  • 초창기 신경망

왜 딥러닝일까? 왜 지금일까?

  • 20년 후에도 심층 신경망을 사용하고 있을까요? ... 지금부터 20년 후에는 신경망을 사용하지 않을지도 모르지만, 딥러닝과 딥러닝의 핵심 개념에서 직접 파생된 무엇인가를 사용할 것입니다.

2장 시작하기 전에: 신경망의 수학적 구성 요소

  • 내용 생략

신경망과의 첫 만남

  • 내용 생략

신경망을 위한 데이터 표현

  • 내용 생략

신경망의 톱니바퀴: 텐서 연산

  • 내용 생략

신경망의 엔진: 그랜디언트 기반 최적화

  • 내용 생략

첫 번째 예제 다시 살펴보기

  • 내용 생략

요약

  • 내용 생략

3장 신경망 시작하기

  • 내용 생략

신경망의 구조

  • 내용 생략

케라스 소개

  • 케라스는 MIT 라이선스를 따르므로 상벚거인 프로젝트에도 자유롭게 사용할 수 있습니다.
  • 최근 딥러닝 프레임워크의 순위는 텐서플로우, 케라스 파이토치 순임.
  • 케라스는 고수준 구성 요소를 제공. 백엔드로는 텐서플로우, 씨아노, CNTK 3개의 엔진을 골라서 사용할 수 있음.
  • 케라스로 모델을 만드는 법
    • Sequential 클래스를 이용해서 순차적으로 쌓아 올리는 방법
    • 함수형 API를 사용해서, 임의의 구조를 만들 수 있는 방법

딥러닝 컴퓨터 셋팅

  • 내용 생략

영화 리뷰 분류: 이진 분류 예제

  • 내용 생략

뉴스 기사 분류: 다중 분류 문제

  • one hot encoding되어 있는 데이터라면 loss에 categorical_crossentropy를 사용하면 되고, 그렇지 않고 숫자로 라벨링 되어 있는 경우라면, loss에 sparse_categorical_crossentropy를 사용하면 된다. 굳이 바꿀 필요 없음.
  • 충분히 큰 중간층을 두어야 하는 이유
    • 마지막 출력이 46차원이기 때문에 중간에 히든 유닛이 46개 보다는 많이 적어서는 안된다. 책에서는 중간에 4차원을 두었는데, 이렇게 두어도 아예 안 되진 않지만, 4차원으로는 정보를 충분히 표현할 수 없어 79%에서 71%로 8% 정도 정확도가 감소한다.
    • 4차원에 대부분의 정보를 넣었겠지만, 그래도 다 넣지는 못한 것으로 생각할 수 있다.

주택 가격 예측: 회귀 문제

  • 데이터의 피쳐가 여러 범위를 가지고 있다. 이때는 데이터를 균일한 범위로 맞춰 주는것이 중요하다. 안되지는 않겠지만, 피쳐의 중요도를 떠나, 그냥 숫자가 클 경우 곱셈을 하게 되면 큰 변화량을 가지게 될 것이다. ( 피쳐엔지니어링 책 참고 )

  • 데이터를 정규화하는 방법

    • 피처의 평균을 빼고, 표준편차로 나누는 방식

    • 피처의 중앙이 0 근처에 맞추어지고, 표준편차가 1이 된다.

      mean = train_data.mean(axis=0)
      train_data = train_data - mean
      std = train_data.std(axis=0)
      train_data = train_data/std
      
      test_data = test_data - mean
      test_data = test_data/std
  • 일반적으로 훈련 데이터의 개수가 적을수록 과대적합(오버피팅)이 더 쉽게 일어나므로 작은 모델을 사용하는 것이 과대적합을 피하는 한 방법입니다.

  • 모델의 마지막은 1개의 유닛을 가지고 있고, 활성화 함수가 없음. 전형적인 스칼라 회귀(하나의 연속적인 값을 예측하는 회귀)를 위한 구성.

  • loss = mse : 평균 제곱 오차. 회귀 문제에서 널리 사용되는 손실 함수.

  • metrics = mae: 평균 절대 오차. 예측과 타깃 사이의 거리 절대값. 0.5면 평균적으로 500달러 차이 난다는것.( 1 = $1000 기준 )

  • 데이터량이 너무 작으면, validation set도 아까우니깐, k-겹 검증 적용

    • K-fold cross-validation : 데이터를 4덩이로 나눈다면
    • 0, 1, 2 는 학습용으로, 3은 검증용으로
    • 0, 1, 3 은 학습용으로, 2는 검증용으로
    • 0, 2, 3 은 학습용으로, 1은 검증용으로
    • 1, 2, 3 은 학습용으로, 0은 검증용으로
    • 모두 loop를 돌고 나면 각 검증용으로 사용했던 0, 1, 2, 3 의 결과를 평균내서 검증의 최종 값으로 사용.
    • 중요한건, 각 학습을 할 때 validation set의 데이터를 참고하지 않았다는 점이다.*
    • 하지만, 코드를 따로 짜야하는 불편함이... 그냥 데이터를 많이 만들어 두고 쓰자. ㅎ.

요약

  • 내용 생략

4장 머신 러닝의 기본 요소

머신 러닝의 네 가지 분류

머신 러닝 모델 평가

  • 반복 K-겹 교차 검증 : k-겹 교차 검증과 동일하나, 반복시마다 데이터를 섞은 뒤에 다시 k 개로 나누고 학습 시키는것을 반복한다.
  • 평가 방식을 선택할 때 다음의 사항을 유의 해야 함.
    • 대표성 있는 데이터 : 훈련 세트와, 테스트 세트가 주어진 데이터에 대표성이 있어야 함. 한쪽으로 쏠려 있는 데이터라면 당연히 잘못 훈련이 될 것이고 테스트도 잘못 될 것이다. 일반적으로는 데이터를 무작위로 섞어 쓰는것이 일반적.
    • 시간의 방향 : 과거로부터 미래를 예측한다면, 당연히 데이터를 섞으면 안된다.
    • 데이터 중복 : 같은 데이터가 여러개가 있는 경우, 데이터를 섞어서 훈련 세트와 테스트 세트로 만들게 되면, 훈련 세트에 있는 데이터와 테스트 세트에 있는 데이터가 동일하게 될 수 있다. 그러면 결국 테스트한 데이터가 학습 데이터에 들어 있다는 말이 된다. 그러므로 이걸 섞이지 않도록 해 주는게 중요하다.

데이터 전처리, 특성 공학, 특성 학습

  • 피처 엔지니어링 관련 내용 : 관련 내용은 다른 책을 참고하자. ㅎ
  • 벡터화 : 모든 데이터를 숫자형태(int나 float)로 바꿔야 한다.
  • 값 정규화 : 스케일이 다른 값들을 일정한 범위로 바꿔 줘야 한다. 스케일이 너무 차이나면 문제가 되기 때문이다. 일반적으로 평균을 0, 표준편차를 1로 만들어주는 작업. 대부분 0 ~ 1 사이의 값을 취하도록 한다.
  • 누락된 값 : 데이터가 누락된 경우에는 0이나 평균값, 중간값등으로 처리해도 크게 문제되지 않는다. ( 그 값 자체가 의미가 있지 않다면 말이다. ) 네트워크가 알아서 적당히 처리 할 것이다. (하지만... 확인해 보기 전에는 알 수 없지 않을까??)
  • 특성 공학(피처 엔지니어링) : 데이터를 사용하기 전에 먼저 잘 학습되도록 적당히 바꿔 주는것.
    • 이미지로 시간을 맞추는것을 한다면, 이미지를 바로 사용한다면 CNN같은걸 써야 겠지만, 단순한 이미지 처리로 바늘두개의 각도를 구할 수 있다면 더 쉽게 학습 시킬 수 있을 것이다.
    • 특성을 더 간단한 방식으로 표현하여 문제를 쉽게 만든다. 이럴려면 해당 문제를 아주 잘 이해하고 있어야 한다.
    • 딥러닝 이전에는 매우 중요 했음.
    • 다행히 최근 딥러닝은 대부분 특성 공학이 필요하지 않습니다. 신경망이 자동으로 원본 데이터에 유용한 특성을 추출할 수 있기 때문입니다. 하지만...
      • 좋은 특성은 적은 자원을 사용하여 문제를 더 잘 풀 수 있음. 시계 바늘을 읽는 문제는 굳이 합성곱 신경망(CNN)을 사용할 필요가 없음.
      • 좋은 특성은 더 적은 데이터로 문제를 풀 수 있음. 딥러닝 모델은 특성을 학습할때 많은 양의 데이터가 필요함. 샘플의 갯수가 적다면 특성을 잘 뽑아내 주는게 중요함.

과대적합과 과소적합

  • 과소적합 : 아직 학습할 껀덕지가 있는 상태
  • 과대적합 : 학습 데이터에만 너무 집중되고 있는 상태 ( 자세한건 따로 보셈 ㅋ ). 그러므로 이걸 피해야 한다. 이렇게 피하는걸 규제(regularization)라고 한다.
    • 네트워크 크기 축소
      • 네트워크의 크기가 크면, 외울 수 있는 capacity가 크고, 그러므로 학습한 데이터를 모두 외워 버릴 수 있을 정도가 될 수 있다.
      • 그러므로 일반화 시킬려면 오히려 네트워크를 줄여야 한다.
      • 우리가 필요한것은 학습 데이터를 잘 맞추는게 아니라, 다른것도 잘 맞출 수 있도록 일반화 되어야 하기 때문이다.
      • 하지만, 그렇다고 네트워크 크기를 팍 줄이면, 기억할 공간이 줄어 들기 때문에 학습이 잘 안될 거다... 그러니 절충점을 잘 찾아야 한다... (그게 쉽나.. T_T)
      • 책에 나오는 실제 검증한 그래프를 보면, 네트워크가 크면 더 빨리 과대적합이 나타나게 된다.
    • 가중치 규제(Weight regularization)
      • 오캄의 면도날 : 어떤 것에 대한 두가지 설명이 있다면 더 적은 가정이 필요한 설명이 더 옳을 것이다.
      • 네트워크의 복잡도에 제한을 두어 가중치가 작은 값을 가지도록 강제하는것. 이러면 가중치의 값의 분포가 더 균일하게 된다.
      • L1 규제 : 가중치의 절댓값에 비례하는 비용이 추가 됨(가중치의 L1노름-norm). 이 경우에는 일부 가중치 값이 0이 되는 경우가 생길 수도 있음.
      • L2 규제 : 가중치의 제곱에 비례하는 비용이 추가 됨(가중차의 L2노름) - 가중치의 파라미터를 모두 제곱하여 더한 후 이 값의 제곱근을 추가, 훈련할 때만 해당 값을 추가. 그러므로 테스트의 loss 값보다, 훈련할때의 loss 값이 더 커질 것임.
      • L2 규제를 적용하면 좀 더 과대 적합에 잘 견딤
      • L1 규제와 L2 규제를 같이 쓰는것을 엘라스틱넷(ElasticNet)이라고 부름. L1, L2 모두 기본값은 0.01로 되어 있음. 책에서는 0.001을 사용하고 있음.
    • 드롭아웃
      • 학습시 신경망의 일부를 끄는(출력을 0으로 만듬)것. (자세한것은 생략)

보편적인 머신 러닝 작업 흐름

  • 성공 지표 선택 : "성공이 무엇인가?"를 정의하는게 중요함. 정확도? 정밀도? 재현율? 고객 재방문률? 비즈니스 성공처럼 고수준의 목표와 직접적으로 연결되어 있어야 함.
    • 클래스 분포가 균일한 분류 문제에서는 정확도가 ROC AUC가 일반적인 지표
    • 클래스 분포가 균일하지 않은 문제에서는 정밀도와 재현율을 사용할 수 있음.
    • 랭킹 문제나 다중 레이블 문제에는 평균 정밀도를 사용할 수 있음.
  • 모델에 맞는 마지막 층의 활성화 함수와 손실 함수 선택
    • 문제 유형, 마지막 층의 활성화 함수, 손실 함수
    • 이진 분류, 시그모이드, binary_crossentropy
    • 단일 레이블 다중 분류, 소프트맥스, categorial_crossentropy
    • 다중 레이블 다중 분류, 시그모이드, binary_crossentropy
    • 임의 값에 대한 회귀, 없음, mse
    • 0과 1 사이 값에 대한 회귀, 시그모이드, mse 또는 binary_crossentropy

요약

  • 생략

2부 실전 딥러닝

  • 생략

5장 컴퓨터 비전을 위한 딥러닝

  • 생략

합성곱 신경망 소개

  • 생략

소규모 데이터셋에서 밑바닥부터 컨브넷 훈련하기

  • 데이터가 풍부할때만 작동한다는 말을 들음. 하지만 딥러닝은 특성을 찾는것이다. 그러므로 특성을 쉽게 찾을 수 있다면 많은 데이터가 필요하지 않을 수도 있다.
  • 특성 앱의 깊이는 네트워크에서 점진적으로 증가하지만(32에서 128까지), 특성맵의 크기는 감소합니다. ( 150x150 에서 7x7까지 - padding이 0인 경우로 계산하면 150, 148 -> 74, 72 -> 36, 34 -> 17, 15 -> 7 이 된다.). 이는 거의 모든 컨브넷에서 볼 수 있는 전형적인 패턴입니다.
  • 케라스에는 이미지를 쉽게 처리하기 위한 유틸리티가 존재한다.
    • keras.preprocessing.image
    • keras.preprocessing.image.ImageDataGenerator
    • Generator를 만들때 batch_size를 적어 두면, 전체중 그 갯수 만큼이 반환된다.
    • 나중에 fit_generator 할 때는 step_per_epoch * batch_size 가 전체가 되도록 만들어 주어야 한다.
    • 리스트와 달리 반복자와 제너레이터는 전체 항목을 미리 만들지 않기 때문에 메모리에 효율적입니다.
  • 데이터 증식(data augmentation - 데이터 오그멘테이션)
    • 데이터의 숫자가 너무 작으면 데이터 갯수를 늘려주는것이 좋다.
    • ImageDataGenerator에서 아래 옵션을 주면, 속성에 맞게 이미지를 더 생성한다.
      • rotation_range : 랜덤하게 사진을 회전(0~180)
      • width_shift_range : 이미지를 평행 이동 (1 이하면 비율, 이상이면 pixel)
      • height_shift_range : 이미지를 수직 이동 (1 이하면 비율, 이상이면 pixel)
      • sher_range : 이미지를 비뚤게 회전 시킬 각도 범위
      • zoom_range : 확대할 범위
      • horizontal_flip : 이미지를 수평 대칭 변환 ( 얼굴, 풍경 등, 글자가 있는것은 수평 대칭 변환하면 안됨 )
      • fill_mode : 회전, 가로/세로 이동시 새롭고 생긴 픽셀을 채울 전략
    • 검증 데이터셋은 데이터 증식(data augmentation)을 하면 안됨. 오직 학습 데이터 셋에서만 할 것.

사전 훈련된 컨브넷 사용하기

  • 데이터 셋이 너무 작으면 어차피 잘 안되니깐, 이미 많은 양의 데이터로 만들어진 잘 학습된 모델을 활용해서 해보자는 방법.
  • 많은 양의 데이터로 잘 학습된 모델은, 내가 필요로하는 특성을 정확하게 잘 찍어 낼 순 없겠지만, 일반적인 특성은 잘 찍어 낼 수 있을 것이므로 이걸 활용하는것이 더 좋을 것임.
  • 실제 필요한것과는 다를지라도, 이론적으로는 효율적임.
  • 책에서는 VGG넷을 사용함. VGG16은 최신것도 아니고, 제일 좋은것도 아니지만, 이 모델 구조가 이전에 보았던것과 비슷해 새로운 개념을 도입하지 않고 이해를 쉽게 할 수 있기 때문에 사용.
  • 일반적으로는 합성곱(Convolution)부분만 재사용함.
    • 합성곱 층은 "학습된 표현이 더 일반적이어서 사용 가능" : 아마도, 합성곱층은 이미지 필터를 거치면서 나오는 특징을 그대로 쓰고, 같은 이미지 필터를 여러곳에서 사용할 수 있기 때문이라고 보임.
    • 하위층은 엣지, 색깔, 질감등의 특성을 뽑고,
    • 상위측은 눈이나 귀처럼 추상적인 개념을 추출
    • 만약, 새로운 데이터셋이 학습된 모델의 데이터셋과 많이 다르다면, 하위층만을 사용하는것도 하나의 방법.
    • 재사용시 trainable값을 False로 줘서, 사전 학습된 표현이 업데이트 되지 않도록 하는것이 중요함.
  • 미세 조정(파인튜닝 - fine tuning)
    • 이전에는 학습된 모델의 top만 제거하고, 새로운 layer를 붙여서, 새 layer만 학습하는 방식으로 재활용 했다.
    • 하지만, 동결 시켜 두었던 부분도 일부를 학습 시키는 방법을 쓸 수도 있다.
      • 사전에 훈련된 기반 네트워크 위에 새로운 네트워크 추가
      • 기반 네트워크 동결 후, 새로 추가한 네트워크 훈련
      • 기반 네트워크에서 일부 층을 동결 해제 한 후, 새로 추가한 네트워크와 같이 학습
    • 합성곱의 하위층은 일반적이고, 재사용가능한 특성을 학습하므로 그대로 사용하고, 상위층은 특화된 특성을 인코딩하므로, 이 부분만 다시 학습 시킨다.
  • 손실 곡선이 향상되지 않았으나, 정확도가 높이진 이유?
    • 손실 값 그래프는, 각 손실의 평균이다. 그러므로 전체의 정확도와는 별개이다. 손실 값이 큰것들은 아예 많이 커져 버리고, 나머지는 손실값을 줄이고 잘 맞추게 업데이트 된다면, 손실 값의 평균은 유지 되면서, 정확도는 높아 질 수 있다.

컨브넷 학습 시각화

  • 생략
  • CAM 을 사용하면, 이미지의 어느 위치가 분류에 영향을 미쳤는지 알 수 있다.
  • 생략

요약

  • 생략

6장 텍스트와 시퀀스를 위한 딥러닝

  • 텍스트(단어의 시퀀스), 시계열 또는 이반적인 시퀀스를 처리 할 수 있는 모델을 살펴 볼 것임
  • 시퀀스 데이터를 처리하는 기본적인 모델
    • 순환신경망(recurrent neural network, RNN)
    • 1D 컨브넷(1D convnet)
  • 시퀀스 데이터 형태로 처리하는 것들
    • 문서 분류나 시계열 분류, 글의 주자네 책의 저자 식별
    • 시계열 비교, 두 문서의 관련성, 주식 가격의 관련성
    • 시퀀스-투-시퀀스 학습, 영어 문장을 프랑스어로 번약하기
    • 감성 분석. 트윗이나 영와 리뷰가 긍정적인지 부정적인지 분류하기
    • 시계열 예측. 최근 어떤 지역의 날씨가 주어졌을때, 날씨 예측하기
  • 책에서는 IMDB의 감정분석과, 기온 예측만 집중하여 볼 것임.

텍스트 데이터 다루기

  • 문서 분류, 감성 분석, 저자 식별, (제한된 범위의) 질문 응답 등에 적합

  • 이런 딥 러닝 모델이 사람처럼 진짜 텍스트를 이해하는것은 아님

  • 문자 언어(written language)에 대한 통계적 구조를 만들어 간단한 텍스트 문제를 해결 하는 것임.

  • 컴퓨터 비전이 픽셀에 적용한 패턴인식인 것처럼, 자연어 처리를 위한 딥러닝은 단어, 문장, 문단에 적용한 패턴 인식

  • 텍스트 역시, 그대로 사용하지 못하고 숫자 형태로 바꿔 줘야 함.

  • 텍스트를 숫자 형태로 바꾸는것을 텍스트 벡터화(vectorizing)이라고 함

    • 텍스트를 단어로 나누고, 각 단어를 하나의 벡터로
    • 텍스트를 문자로 나누고, 각 문자를 하나의 벡터로
    • 텍스트에서 단어나 문자 n개를 뽑은 뒤에, 그 조합을 벡터로
    • 텍스트를 일정 기준으로 나눈것을 토큰이라고 함. 이런 토큰을 잘 처리해서 벡터를 만들 수 있음.
  • 원핫인코딩

    • 텍스트도, 단어별로 쪼갠 뒤, 각 단어를 원핫인코딩으로 바꿀 수 있다.
    • 원핫인코딩으로 바꿀때, 텍스트가 아닌 경우를 대비하여 1개를 비워 두는 센스를 발휘하자.
    • keras.preprocessing.text.Tokenizer(num_words=1000)을 사용하면, 가장 빈도가 높은 1000개 단어만 사용하도록 할 수 있음.
    • 원핫해싱이라고, 인덱스를 따로 설정하지 않고, key를 value의 hash 값을 사용하도록 한다. 바로바로 데이터를 찍을 순 있겠지만, hash 된 값이 겹쳐 버리는 문제가 발생할 수 있다.
  • 단어 임베딩(워드 임베딩, word embedding)

    • 책에서는 밀집 단어 벡터(word vector)이라고 적혀 있는데, 전체를 영어로 적으면 dense word vector이다. dense를 보통 밀집이라고 해석하는데, 의미 없이 공간을 차지하는 정보가 없는 정도로 해석하면 좋겠다. 원핫인코딩의 경우 많은 값들이 0 이고, 딱 1개만 1이기 때문에 0은 의미가 없다(이런 애들을 희소(sparse)하다고 한다). 그러므로, 14번째 위치에 1이 있다고 표현하는 ( 14, 1 ) 이라고 표현하면 dense하게 표현되었다고 볼 수 있다.
    • keras.layers.Embedding(1000,64)는, 1000개의 단어를 64차원으로 표현하겠다는 것이다.
    • Embedding을 만들고, dense를 만들어 붙인 후에 데이터를 fit으로 때려 박으면, 알아서 잘 분리한 vector가 만들어 진다.
    • 임베딩 알고리즘에는 Word2Vec나 GloVe 같은게 있다.
    • 당근, 데이터셋이 작다면, 사전 학습된 모델을 읽어와서 재활용하고, 필요한 부분만 덧붙여 쓰는게 좋다.
    • 순환 신경망 이해하기

  • RNN, LSTM 설명, 생략.

순환 신경망의 고급 사용법

  • 순환 드롭아웃 : 순환층에서 과대적합을 방지하기 위해 사용. 케라스에 내장되어 있음. ( GRU나 LSTM에 dropout 값을 줄 수 있음 )
  • 스태킹 순환 층 : 순환층의 마지막 노드의 결과만 내 뱉는게 아니라, 모든 노드의 결과를 연결해 주는 형태 ( return_sequences 값을 이용해서 처리 할 수 있음 )
  • 양방향 순환 층 : 데이터를 a, b, c, d 순으로 입력하던것을 d, c, b, a 순으로도 입력하는 branch 층을 만든다.

컨브넷을 사용한 시퀀스 처리

  • 벡터를 RNN으로 계속 순환 시킬것이 아니라, CNN 1D로 계산하는 방식
  • CNN으로 계산하면 훨씬 속도가 빨라진다.
  • 1D CNN으로 특징을 먼저 뽑아내고, RNN을 돌릴 수도 있다.

7장 딥러닝을 위한 고급 도구

Sequential 모델을 넘어서: 케라스의 함수형 API

  • 기존에는 순차적으로 연결한 모델만 만들 수 있었다.

  • 하지만, 함수형 API를 사용하면, branch를 만들거나, merge 할 수 있다.

  • 일반적인 Sequence Model을 함수형 API로 표현

    input_tensor = Input( shape=(64,) )
    x = layers.Dense(32, activation='relu')(input_tensor)
    x = layers.Dense(64, activation='relu')(x)
    output_tensor = layers.Dense(10, activation='softmax')(x)
    
    model = Model(input_tensor, output_tensor)
  • 2개 이상의 vector을 받아서, 1개의 출력으로 내는 경우

    text_input = Input( shape=(...) )
    embedded_text = layers.Embedding(....)(text_input)
    encoded_text = layers.LSTM(...)(embedded_text)
    
    ques_input = Input( shape=(...) )
    embedded_quest = layers.Embedding(....)(ques_input)
    encoded_ques = layers.LSTM(...)(embedded_ques)
    
    concatenated = layers.concatenate([encoded_text, encoded_ques], axis=-1) 
    
    answer = layers.Dense(64, activation='softmax')(concatenated)
    
    model = Model ( [text_input, ques_input] , answer )
    
    model.compile( optimizer='rmsprop', loss='categorical_crossentropy' ) # 1개의 output이므로 optimizer나 loss 는 1개 만 설정하면 된다. 
    
    model.fit ( [text, ques], answer, ... ) # 2개의 Input과 1개의 Output이다.
  • 2개 이상의 출력을 내는 경우

    # 나머지는 비슷하게 하고, 제일 마지막 출력층에 대한 것만...
    age_predict = layers.Dense(1)(x)
    
    income_predict = layers.Dense(100, activation='sfotmax'(x)
    
    gender_predict = layers.Dense(1, activation='sigmoid')(x)
    
    model = Model ( input, [age_predict, income_redict, gender_predict]) # 1개의 Input과 3개의 Output에 대해서 처리해야 한다.
    model.compile( optimizer='rmsprop', loss = ['mse'm 'categorical_crossentropy', 'binary_crossentropy'] ) # 3개의 Output에 대한 각각의 정보가 필요하다.
    # 필요할 경우 compile 옵션으로 loss_weight=[1.0, 0.25, 10.] 등, loss 값에 가중치를 줄 수도 있다.
    
    model.fit ( posts, [age_targets, income_targets, gender_targets], ... ) # 입력이 1개, 출력이 3개다.
  • 인센셥 모델의 경우 branch를 따고, 합치는 과정이므로, 이 글에서는 따로 설명하지 않고 pass.

  • 잔차연결(residual connection)

    x = layers.Conv2D(...)(x)
    y = layers.Conv2D(...)(x)
    y = lqyers.Conv2D(...)(y)
    
    y = layers.add( [ y, x ] ) # 마지막 y의 특성에 x의 출력 특성을 더한다.
  • 기존의 모델을 layer 처럼 사용 가능

    xception_base = application.Xception(weight=None, include_top=False)
    input = Input(shape=(250, 250, 3))
    features = xeception(input)    

케라스 콜백과 텐서보드를 사용한 딥러닝 모델 검사와 모니터링

  • 콜백 : 콜백을 직접 만들 수도 있지만, 이 글에서는 중요한거만...

    • ModelCheckpoint : epochs 마다 모델을 저장한다.

    • EarlyStopping : validation loss가 일정 횟수 이상, 줄어 들지 않으면 자동으로 멈춘다.

    • ReduceLROnPlateau : validation loss가 향상되지 않으면, 학습률을 작게 할 수 있음.

    • 예제

      callbacks_list = [
      // val_acc 값이 patience 만큼 횟수의 epoch를 돌았는데도, 정확도가 늘지 않으면 멈춘다.
      keras.callbacks.EarlyStopping( monitor='val_acc', patience=1),
      
      // epoch 마다 my_model.h5에 저장한다. 단, val_loss 값이 줄어들지 않으면, 모델을 덮어쓰지 않는다.
      keras.callbacks.ModelCheckpoint(filepath='my_model.h5' , monitor='val_loss', save_best_only=True),
      
      // val_loss 값을 확인해서 10번동안 줄어들지 않으면, 학습률을 1/10 으로 줄인다.
      keras.callbacks.ReduceLROnPlateau( momitor='val_loss',factor=0.1, patience=10 );
      ]
      
      // callback에서 val_loss 값을 사용하기 때문에, metrics에 acc 값이 포함되어 있어야 한다.
      model.compile( optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'] )
      
      // epoch 마다, callbacks_list에 있는 callback들을 호출한다. 이 callback에서 val_acc 값을 사용하기 때문에, 꼭 validation_data 값이 필요하다.
      model.fit( x, y, epochs=10, batch_size=32, callbacks = callbacks_list, validation_data=(x_val, y_val))
  • 텐서보드 : 텐서플로우일때만 사용할 수 있자만 참 유용함

    • TensorBoard : 훈련하는 동안의 지표, 모델 구조 확인, 활성화 출력, 3D 임베딩 등을 쉽게 볼 수 있음

    • 예제

      callbacks = [
        // 학습 로그는 my_log_dir에 남기며, 1 epoch마다, 활성화 출력과 임베딩 데이터를 기록.
        keras.callbacks.TensorBoard( log_dir='my_log_dir', histogram_freq=1, embeddings_freq=1 )
      ]
    • python 코드를 실행 시킨 후 shell에서 tensorboard --logdir=my_log_dir 실행후, http://localhost:6006 에 접속하면 볼 수 있음.

  • 모델 시각화

    • TensorBoard를 사용하면 모델 시각화를 할 수 있지만, tensorflow의 모델 형태로 나오기 때문에 보기가 어렵다.

    • 케라스 모델을 쉽게 볼 수 있게 이미지로 만들 수 있는 방법도 있다.

      from keras.utils import plot_model
      // 케라스 모델인 model을 보기 쉽게 model.png 파일에 이미지로 떨어뜨려 준다.  
      // show_shapes = True, layer의 input과 output의 shape을 같이 보여준다.  
      // show_layers_name = True, layer 이름을 같이 보여 준다.  
      // rankdir = TB | LR, TB면 수직으로, LR 수평으로 그려준다.  
      plot_model ( model, to_file='model.png', show_shapes=True )

모델의 성능을 최대로 끌어올리기

  • 배치 정규화

    • 배치 정규화를 사용하면 더 깊은 네트워크를 구성할 수 있다.

    • BatchNormalization은 일반적으로, 합성곱이나 환전 연결층 다음에 사용함

      conv_model.add( layers.Conv2D(32, 3, activation='relu') )
      conv_model.add( layers.BatchNormalization() )
      
      dense_model.add( layers.Dense(32, activation='relu') )  
      dense_model.add ( layers.BatchNormalization() )  
    • 배치 정규화클래스는 특성 축을 지정할 수 있는 axis 매개 변수가 있음. ( 기본값 -1, 입력텐서의 마지막 축 )

    • data_format을 "channels_last"로 하여, Dense, Conv1D, ENN, Conv2D 층을 사용할 때 맞는 값.

    • data_format이 "channels_first"라면, 특성축이 1이므로, axis=1 로 주어야 함. ( 0번째 축은 "배치"차원 축 )

  • 깊이별 분리 합성곱 ( depthwise separable convolution )

    • Conv2D 보다 가볍고, 빠르다. 성능도 좋다.
    • 적은 데이터로도 좋은 표현을 학습하고, 결국 성능이 더 좋은 모델을 만듬. 제한된 데이터로 작은 모델을 만들때 중요.
    • 예제는 Conv2D를 사용하는곳에 모두 layers.SeparableConv2D를 사용하는 형태로만 바꾸면 됨.
  • 하이퍼 파라미터 최적화

    • 규칙은 없다. 자동으로 하이퍼 파라미터를 찾아주는건 연구되고 있는 과정
    • 관련 라이브러리 : Hyperopt, Hyperas(Hyperopt와 연동하여 keras에서 사용가능), Auto-Keras, auto-sklearn
  • 모델 앙상블(model ensemble)

    • 하나의 목적을 가진 여러가지 모델을 만들고, 각 모델별 예측치를 평균하여 찾는 방법
    • 한가지 모델은 편향되어 있을 수 있지만, 여러가지 편향을 가진 각 모델을 평균내면 오히려 더 잘 동작할 수도 있다.

8장 생성 모델을 위한 딥러닝

LSTM으로 텍스트 생성하기

  • 생략

딥드림

  • 내가 별로 관심이 없어서 생략. ㅎ. 책도 대충 읽고 넘김. ㅎ.

뉴럴 스타일 트랜스퍼

  • 생략

변이형 오토인코더를 사용한 이미지 생성

  • 생략

적대적 생성 신경망 소개

  • GAN(Generative Adversarial Netowkrs)
  • 모델은 크게 두가지로 나뉨. 한쪽에서는 이미지를 생성, 한쪽에서는 생성된 이미지가 진짜/가짜인지 판단
  • 양쪽을 모두 학습 시킨 뒤, 생성 부분만 모델만있으면, 이미지를 생성할 수 있음.
  • 대충은 아니깐, 자세한건 생략.

이하 항목 생략

발단

요즘에 이것저것 한다고, javascript들을 좀 해 보고 있는데, 배열에 여러가지 작업을 쉽게 할 수 있어 좋은 함수들이 있어, 계속 쓰다가, 나중을 위해 정리 하려고 간단하게 기록.

배열을 loop 돌면서 무언가를 하고 싶다면 아래 함수들을 활용하자.

  • forEach : 한개씩 돌면서 무언가 하기, return value는 없음.
  • filter : 조건에 맞는것만 새로운 배열로. return value는 새 배열.
  • map : 한개씩 돌면서 연산한 결과를 새로운 배열로. return value는 새 배열
  • reduce : 한개씩 돌면서 이전 연산한 결과를 조합하여 사용하기. return value는 reuce 함수안에서 설정한 대로.
    • 무슨 말인지 이해가 어려울 수도 있는데... 알면 쉬움... ;;

간단한, forEach, filter, map 부터

  • 이해하기 쉽도록 되도록이면 쉬운 예제를 만들어 보았다.

forEach - 한개씩 돌면서 무언가 하기

["a", "b", "c"].forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 a, b, c 가 출력 된다.

filter - 배열에서 조건에 맞는것만 새로운 배열만들어 반환하기.

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
)
  • 결과 : [ 2, 4 ] 배열이 반환된다.

filter + forEach - 조건에 맞는것만 배열로 만들어, 한개씩 돌면서 무언가 처리 하기

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 2, 4 가 출력 된다.

map - 배열의 각 요소에 무슨짓한 결과를 새 배열로 반환

[ 1, 2, 3, 4, 5].map(
    function(x) {
        return x * 2;
    }
)
  • 결과 : [2, 4, 6, 8, 10] 배열이 반환된다.

map + forEach - 배열의 각 요소에 어떠한 연산을 하고, 그 결과를 하나씩 돌면서 무슨 짓을 하기

[ 1, 2, 3, 4, 5].map(
    function(x) {
        return x * 2;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 2, 4, 6, 8, 10 이 출력 된다.

filter + map + forEach - 배열에서 원하는 요소만 뽑아내고, 그 결과 배열에 어떠한 연산을 하고, 그 결과를 하나씩 돌면서 무슨짓을 하기

[ 1, 2, 3, 4, 5].filter(
    function(x) {
        return x % 2 == 0;
    }
).map(
    function(x) {
        return x * 2;
    }
).forEach ( 
    function(x) {
        console.log(x);
    }
)
  • 결과 : 화면에 4, 8 이 출력 된다.

조금 까다롭지만 활용성이 매우 좋은 reduce

  • reduce는 배열의 순환을 돌면서, 이전 결과를 활용하는 방식이다.
  • forEach, filter, map 과 같이 reduce도 내부에서 함수를 1개 받는데, 파라미터에 여러가지 정보가 들어온다.
  • 함수는 function ( ac, current, index, array ) 4개의 파라미터를 받는다.
    • ac : reduce 호출할때 넘긴 함수의 결과를 보관. 최초 호출될때는 reduce를 호출할때 두번째 넘김 파라미터의 값.
    • current : 배열의 0 번 부터 배열의 마지막까지 순차적으로 전달 됨
    • index : 현재 배열의 몇번째를 loop 돌고 있는지 알려 주는 값
    • array : reduce 함수를 호출한 배열.
  • 긴 설명은 설명이 잘 되어 있는 다른 사이트에서 찾도록 하자.
  • reduce 함수에서 위 4가지 파라미터를 활용하면, filter, map, forEach 를 모두 구현할 수 있다.
  • 즉, reduce 짱짱임.

reduce - 숫자가 들어 있는 배열의 합 구하기

[1, 2].reduce (
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 0 이고,, current는 배열의 0 번째인 1이 들어 있을 것이다.
          // 그러므로 최초 호출 될 때는 return 값이 0 + 1 이므로, 1이 return 될 것이다.
          // 두번째 호출 될 때는 ac는, 첫번째 호출 되었을때, return한 값인 1 값을 가지고, current는 배열의 1번째 2가 들어 있을 것이다.
          // 그리고 두번째 호출 될 때는 return 값이 1 + 2 인 3 이 될 것이다.
          // 더 이상 loop를 돌 아이템이 없으므로, 해당 함수의 리턴값의 3 이 될 것이다.
        ac = ac + current;
        return ac;
    }
,0); // reduce 함수의 두번째 파라미터인 0 은, 위 익명 함수의 ac에 최초 할당 된다.
  • 결과 : 3이 반환 될 것이다.

reduce - string 배열을 순환하면서 모든 배열 item을 1개의 string으로 합치기

[ "안녕", "하세요" ].reduce(
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 "" 값을 가지고, current는 배열의 0 번째 "안녕"의 값이 들어 있을 것이다.
          // 그러므로 최초 호출 될 때는 return 값이 "" + "안녕" 이므로, "안녕"이 return 될 것이다.
          // 두번째 호출 될 때는 ac는 첫번째 호출 되었을때, return한 값인 "안녕" 값을 가지고, current는 배열의 1번째 "하세요"가 들어 있을 것이다.
          // 그리고 두번째 호출 될 때는 return 값이 "안녕"+"하세요"가 될 것이다.
          // 더 이상 돌 item이 없으므로, 결과적으로 해당 함수의 return 값은 "안녕하세요"가 될 것이다.
        return ac + current; 
    }
, "" ) // reduce 함수의 두번째 파라미터인 "" 은, 위 익명 함수의 ac에 최초 할당 된다.
  • 결과 : "안녕하세요" 라는 값이 반환된다.

응? reduce 대신 forEach만 써도 되는거 아닌가?

  • 위 예제들을 사실, forEach만 사용해도 된다.

  • forEach를 사용해서 바로 위의 예제를 구현해 보자.

    let sumString = ""
    ["안녕", "하세요"].forEach(
        function (x) {
            sumString = sumString + x;
        }
    );
  • 위 예제와 주석이 제거된 reduce를 예제를 비교해 보자.

    let sumString = [ "안녕", "하세요" ].reduce(
        function ( ac, current, index, array ) {
           return ac + current; 
        }
    , "");
  • 결과는 동일하지만,

    • forEach는 배열의 loop 결과를 저장하기 위해서, sumString을 선언후 ""를 할당한 뒤 사용해야 했지만,
    • reduce는 배열의 loop 결과를 바로, sumString으로 할당 할 수 있다.

reduce - 배열에서 string type만 Set으로 만들기

[ 1, "안녕", "2", 3].reduce(
    function ( ac, current, index, array ) {
          // 최초 호출될때, ac는 reduce의 두번째 파라미터인 아래에서 넘긴 new Set() 값을 가지고, current는 배열의 0 번째 값인 1이 들어 있을 것이다.
          // 1은 string type이 아니므로, 그냥 ac를 반환한다.
          // 두번째 호출 될 때는 ac는 첫번째 호출 되었을때, return한 값인 new Set()이 그대로 들어 있을 것이고, current는 배열의 1번째 값인 "안녕"이 들어 있을 것이다.
          // "안녕"은 string type이므로, ac.add(current)를 이용해서 Set에 "안녕"을 넣는다. 그리고 ac를 반환한다.
          // 세번째 호출 될 때는 ac는 두번째 호출 되었을때, return한 값인 "안녕"이 들어 있는 Set이 들어 있을 것이고, current는 배열의 2번째 값인 "2"이 들어 있을 것이다.
          // "2"은 string type이므로, ac.add(current)를 이용해서 Set에 "2"을 넣는다. 이제 Set에는 "안녕"과 "2"가 들어 있다. 그리고 ac를 반환한다.
          // 네번째 호출 될 때는 ac는 세번째 호출 되었을때, return한 값인 "안녕"과 "2"가 들어 있는 Set이 들어 있을 것이고, current는 배열의 3번째 값인 3 이 들어 있을 것이다.
          // 3은 string type이 아니므로, "안녕"과 "2"가 들어 있는 ac를 반환한다.
          // 더 이상 돌 item이 없으므로, "안녕"과 "2"가 들어 있는 ac를 최종 반환하고 끝낸다.
        if ( typeof current == "string" ) {
            ac.add(current);
        }
        return ac;
    }
, new Set()); // reduce 함수의 두번째 파라미터인 new Set()은, 위 익명 함수의 ac 에 최초 할당된다.
  • 결과 : "안녕"과 "2"가 들어 있는 Set이 반환된다.

위 예제도, filter와 map 같은걸로 가능할 것 같은데?

  • 당근 가능하다. 위 예제는 Set을 반환했지만, filter + map과 reduce의 비교를 위해, 배열을 반환하도록 코드를 수정하겠다. 그리고 각 배열의 마지막에 "하세요"라는 문자를 추가하도록 하겠다.

  • 우선 filter + map 을 사용해서, 배열에서 string type만 array로 만들어 보자.

    [ 1, "안녕", "미안", 3].filter(
        function ( x ) {
           return typeof x == "string";
        }
    ).map(
        function ( x ) {
           return x + "하세요";
        }
    );
  • 그리고 reduce를 활용해, 배열에서 string type만 array로 만들어 보자..

    [ 1, "안녕", "미안", 3].reduce(
        function ( ac, current, index, array ) {
           if ( typeof current == "string" ) {
               ac.push(current + "하세요");
           }
           return ac;
        }
    , []);
  • 결과는 동일하지만,

    • filter와 map의 조합은 결과를 내기 위해서 배열의 loop를 두번 돌아야 하고, 정확하게는 item 을 6번 가지고 와야 한다. ( filter에서 4번, map에서 2번)
    • reduce는 배열을 한번의 loop를 돌면서 결과를 만들어 낼 수 있다. 정확하게는 item을 4번 가지고 오면 된다.

결론?

  • 처음에는 공부하기도 귀찮고 해서, 안 썼었는데...
  • 다른 강좌를 보다가 예제중에서 이걸 사용하는것들이 있어, 공부를 하게 됐다.
  • 지금은?
    • 거의 모든 배열의 loop는 이 함수들을 이용해서 처리하고 있다.
    • 익숙해 지니깐, 참 편하더라고...

읽기전

  • 데이터를 많이 들여다 보려고 노력하고 있는데, 이거 참 기본이 있어야지...

  • 특히 데이터를 어떻게 들여다 볼 것인가? 에 대한 고민이 필요해서 구매 한 책.

  • 기존 딥러닝 책들은, 이미 잘 정제 되어 있거나, 필요한 값들을 이미 선별해 둔 책이 많다.

  • 하지만, 실제 데이터들은 잘 정제되어 있지도, 어떠한 값을 딥러닝에 넣어야 할지도 모르니....

  • 에라, 모르겠다. 걍 딥러닝에 다 때려 박으면 되지 싶다가도,

    • 그래도 기본은 알아야지.
    • 필요한 것만 때려 박으면 더 잘 되겠지.
  • 싶어서 구매한 책

  • 이 책에 있는 대부분의 예제는 전체 소스코드가 나와 있지 않고, 설명이 생략 된 것도 꽤나 된다.

  • 그러므로 초보자가 읽기에 적당하지 않은듯 하다.

책 읽기

서문

옮긴이의 말

  • 하지만 너무나 다양한 데이터의 종류가 특성에 따라 경험적으로 수행돼 왔을 뿐, 이를 범용적으로 적용하는 방법에 대한 책이나 논문이 거의 없었다.
  • 머신 러닝 입문자들에게는 피처 엔지니어링에 대한 원리를 배우고 실습을 통해 실력을 높일 수 있는 좋은 기회가 될 것이며, 데이터 과학에 종사하는 분들에게는 그동안 경험적으로 수행해 오던 피처 엔지니어링 기법들을 암묵지에서 형식지로 정리하는 계기가 될 것이다.

들어가며

  • 모델은 피처(feature)를 입력으로 사용한다. 피처는 원시 데이터의 숫자적인 표현이다..
  • 피처 엔지니어링은 원시 데이터로부터 피처를 추출하고 이를 머신 러닝 모델에 적합한 형식으로 변환하는 작업이다.
  • 데이터와 모델은 매우 다양하기 때문에 피처 엔지니어링 방법으로 일반화 하기 어렵다.

1장 머신 러닝 파이프라인

데이터

  • 데이터, 모델, 피처, 모델 평가
    • 실제 세계의 현상에 대한 관측 결과
    • 데이터의 각 조각은 현실의 제한된 한 측면에 대한 창을 제공
    • 원시 데이터는 숫자가 아닌 경우가 많다. ( 앨리스가 수요일에 책을 샀다. )
    • 피처는 원시 데이터의 숫자적인 표현이다.
    • 우리가 해결하고자 과제에 적합한 모델에, 잘 들어 맞는 피처를 만들어야 한다.
    • 피처가 적으면 제대로 과제를 수행하지 못하고, 피처가 많아도 필요 없는 피처로 인해 모델의 학습에 많은 비용과 어려움이 있을 수 있다.
  • 원본 소스가 통찰력까지 가기는...
    • 소스 ->(추출 및 통합)-> 원시 데이터 -> (정제 및 변환) -> 피처 -> 모델링 -> 통찰력
    • 여기서 "정제 및 변환" 부분이 피처 엔지니어링 부분이다.

2장 숫자를 위한 멋진 트릭

  • 이미 숫자는 수학적 모델로 처리하기 쉬운 형식.
  • 하지만 좋은 피처는 데이터를 가장 두드러진 특징을 표현할 뿐만 아니라, 모델의 가정에도 맞아야 한다. 그러므로 피처 엔지니어링이 필요.
  • 고려사항
    • 값의 크기 : 양수? 음수?, 구간을 나눠야하나? 숫자가 누적되나?
    • 스케일 : 가장 큰 값, 가장 작은 값, 둘의 차이가 몇자리 수. 출력 값이 커질 수 있나? 출력값이 바이너리면?
    • 숫자 피처의 분포
    • 여러 피처를 조합해 더 복잡한 피처를 만들 수도 있음

스칼라, 벡터, 공간

  • 스칼라(scalar) : 단일 숫자 피처
  • 벡터(vector) : 방향이 있는 스칼라의 리스트, 벡터는 벡터공간내에 위치.
  • 벡터는 공간상의 한 점( 종종 원점에서 그 점까지의 선이나 화살표로 그린다. )

카운트 처리

  • 노래나 영화를 플레이 한 횟수 등 이런 카운트
  • 누군가가 조작하기가 쉬우므로, 그래도 사용할지, 존재 여부만 처리 할지, 몇개의 구간으로 나눌지 등을 고민해야 한다.

바이너리 변환

  • '견고한 척도'(통계 용어에서 "견고함"은 해당 기업이 매우 다양한 조건하에서도 잘 작동함을 말한다. 라는 말이 있는데.. 이걸 이쪽 세상에서는 로버스터(robust)라는 용어를 훨씬 더 많이 사용한다.
  • 데이터의 값이 너무 많이 차이가 나면, 그냥 1 과 0 으로 나눠 주는것도 가능하다.

양자화 또는 비닝

  • 비닝(binning)은 구간화 정도로 생각하면 되겠다.
  • 양자화랑 비슷한 듯.
  • 쉽게 말하면, 값을 구간을 두고 정리 한다는것. ( 10대, 20대, 30대 등 )
  • 고정폭 비닝
    • 나이를 가지고 할 것이라면, 10대, 20대로 할 수도 있지만, 삶의 단계에 맞게, 초등학교, 중학교, 고등학교, 대학교의 나이로 나누는것이 더 좋을 수도 있다.
    • 여러 자리수라면, 0 ~ 9, 10 ~ 100, 100 ~ 1000 등으로 나눌 수도 있다.
  • 분위수(quantile) 비닝
    • 그냥 고정폭 비닝은, 중간에 빈 값이 많으면 데이터가 없는 구간이 너무 많다.
    • 걍 전체 값의 1/2이나 1.4 단위, 혹은 1/10 단위로 나눠서 배치한다.

로그 변환

  • 작은 숫자가 많고, 큰 숫자가 듬성 듬성 적게 데이터가 존재한다면, 작은 숫자들을 좀 더 잘게 쪼개야 하고, 큰 숫자를 좀 더 모아줘야 한다.
  • 이럴때는 로그 변환을 사용하면 된다.
  • log10(x) 는
    • 1 ~ 10 사이의 숫자를 0 ~ 1 사이로 배치
    • 10 ~ 100 사이의 숫자를 1 ~ 2 사이로 배치
    • 100 ~ 1000 사이의 숫자를 2 ~ 3 사이로 배치 할 수 있다.
  • 즉, 큰 수의 변화량을 작은 변화량으로 바꿀 수 있어, 상대적으로 작은 숫자의 변화량을 더 잘 표현할 수 있게 된다.
  • 뒤에 Box-Cox 라는것도 나오는데, 잘 모르겠지만, 결국 데이터를 잘 분산한다는것에 목적이 있는 듯 하다.

피처 스케일링 또는 정규화

  • 위도나 경도는 피처의 숫자 값에 한계가 있음. 하지만 카운트는 한계가 없음.
  • 모델이 입력 피처의 스케일링(값 범위)에 민감하다면, 피처를 적절히 스케일링 해 주어야 한다.
  • 이걸 피처 스케일링, 혹은 피처 정규화(normalizataion)이라고 부른다.

min-max 스케일링

  • 제일 작은 값을 0, 제일 큰 값을 1로 변환
  • min-max scailing

표준화(분산 스케일링)

  • 피처 표준화(standardization) : 모든 데이터 포인트에 대한 피처의 평균을 빼고 분산으로 나눈다.
  • 그래서 분산 스케일링이라고도 부름
  • 스케일링된 피처의 결과는 평균이 0, 분산이 1
  • 즉 0을 중심으로 좌우로 적절히 데이터를 배치한다.

l2 정규화

  • 원본 피처 값을 유클리드 노름(norm)으로 불리는 l2 노름으로 정규화한다.(나눈다)
  • 원본 값 / (모든 데이터에 제곱을 한 뒤, 이를 모두 더하고, 다시 제급근(루트)를 씌워 준다.)
  • 자세한건 나도 모르니깐 통과.
  • 이상과 같은 피처스케일링은, 피처의 분포의 모양을 바꾸지는 않는다. 다만 분포에 대한 스케일만 변경한다.
  • 예를들면 원본 데이터를 이용해서 만든 그래프와, min-max를 이용해서 만들어진 그래프의 모양은 동일하다. 다만, 피처의 스케일만 달라져 있는 것이다.
  • 입력 피처들의 기준이 다를때는 비슷하게 만들어 주는것이 좋다. 방문자 수가 100만명 단위인데, 구매자 수가 100명 단위라면, 균형을 맞춰줄 필요가 있다.
  • 그렇지 않으면 모델 학습 알고리즘에서 수치 안정성 문제를 일으킬 수 있다.

상호작용 피처

  • 한개의 피처만을 사용하는것이 아니라, 두개의 피처를 모두 사용하는 방법.
  • 예를들면, "서울"에서 "30대" 같은것.
  • 고객의 위치만으로 예측하는것, 혹은 고객의 나이만으로 예측하는것 보다는, 둘 다의 값으로 예측하는것이 더 정확
  • 하지만, 더 복잡한 계산이 필요. 어떤 피처들 선택할 것인가도 문제.

피처 선택

  • 필요 없는 피처는 제거하는것이 모델의 복잡성을 줄일 수 있음.
  • 그러면 정확도는 거의 저하시키지 않고, 빠르게 연산 할 수 있을 것임.
  • 어느 피처가 중요한지 알아 내기 위해서, 오히려 전체 학습 시간이 오래 걸릴 수도 있음.

필터링

  • 피처와 목표 변수 사이의 상관관계, 상호 정보량등을 계산해 크게 영향을 미치지 않는것을 걍 제거.
  • 쉽게 할 수 있지만, 내가 필터링 할 피처를 잘못 선택할 수도 있다.
  • 아예 해당 데이터를 사용하지 않을 것이므로, 유용한 필터를 제거 할 수 있으므로, 보수적으로 선택해야 한다.

레퍼메소드

  • 비용은 많이 들지만, 피처의 하위 집합을 시험해 볼 수 있도록 해 줌.
  • 정보량이 많지 않을 수도 있지만, 조합했을 경우 유용한 것일 수 있으므로 실수를 방지 해 줌.

내장 메소드

  • 모델 학습 과정의 일부로서 피처 선택을 수행
  • 의사결정트리는 각 학습 단계에서 트리를 분할하기 위한 피처를 선택하게 되어 있음.
  • 선형 모델 학습에 사용하는 l1 정규화도, 모델 학습 과정의 일부로 피처를 선택하게 되어 있음.
  • 레퍼메소드 방식보다 강력하지 않지만, 비용이 절감
  • 필터링과 비교 했을 때 보다는 모델에 적합한 피쳐를 선택,
  • 필터링과, 내장 메소드 사이의 적절한 균현을 이룸
  • 이 책의 설명 범위가 벗어난다면서, 여기에 대한 설명을 다른곳을 찾아 보라고 함.

요약

  • 일반적인 숫자 피처에 대한 피처 엔지니어링을 설명
  • 통계적인 머신러닝에서 모든 데이터는 결국 숫자 피처로 귀결
  • 결국 몇가지 숫자 피처 엔지니어링 기법이 필요

3장 텍스트 데이터: 플래트닝, 필터링, 청킹

  • 문장이 있다면, 어느 부분을 추출해야 하나?
  • 단어 카운트 총계를 기초로 하는 가장 단순한 표현인 BoW
  • 텍스트와 매우 깊은 연관이 있는 변환 tf-idf

bag-of-x: 자연어 텍스트를 평면 벡터로 변환

  • 결과가 단순하고 해석 가능할때가 가장 좋음, 단순해야 시도해 보기 좋고, 디버깅이 쉽다.
  • 우선 단순하게 시작하고, 필요한 경우 복잡성을 더하도록 하자.
  • 문서를 분류하는 작업은 종종 단어 카운트 통계만으로도 충분함.
  • 특정 단어의 존재 유무가 문서의 주제를 잘 나타내는 지표가 됨.

BoW

  • Bag of word
  • 단어별 단어가 노출되는 갯수를 테이블로 만든것.
  • 이러한 단어별 카운트의 분포에 따라서 문서가 어떠한 특징을 가지는지 알 수 있다.
  • 텍스트는 원래 플랫(flat)한 구조이나, BoW는 단어가 몇번 나오는지만 저장해 둔다.
  • 텍스트는 순서(Sequance)를 가지나, BoW는 순서도 없다. 단어별 계층 구조도 없다.
  • 오직 등장한 횟수만...
  • 이렇게 단어와 등장 횟수를 피처를 만들고, 어떠한 문장을 분석해 보도록 하자.
  • 각 단어가 1개의 차원이 된다. 등장 횟수가 해당 피처의 값이 된다.
    • 특정 문장에서 cute라는 단어와 puppy라는 단어가 각각 몇번 나왔는지를 x, y로 두면 그 문장이 2차원의 어느 위치에 있는지 알 수 있다.
    • 특정 문장에서 cute, puppy, extremely 이라는 단어가 각 몇 번 나왔는지를 x, y, z로 두면 그 문장이 3차원에서 어느 위치에 있는지 알 수 있다.
    • 각 단어와 등장한 횟수가 피처가 되고, 문장이 어느 위치에 있는지 알 수 있다.
  • 반대로 각 문장 자체를 피처로 두고, 단어들을 배치해 볼 수도 있을 것이다. 이러한 것은 bag-of-documents 라고 한다. ( 자세한건 4장에 설명 된다고... )
  • BoW는 문장을 단어로 분해 할 때 의미가 파괴 될 수 있다. not bad의 경우 '나쁘지 않다.'라는 뜻인데, 분해를 해 버리면 둘다 나쁘다라는 의미를 표현하게 된다.
  • 이러한 문제를 일부 해결 하기 위해 bag-of-n-grams를 사용한다.
  • BoW는 유용한 경험적 방법이지만, 텍스트의 정확한 의미를 파악하는것과는 거리가 멀다.

bag-of-n-grams

  • BoW는 단어 당 하는건데, 여기는 n개의 연속된 단어로 하는거다. 1개로 되어 있으면, 1-gram, unigram 이다.
  • 중첩된 시퀀스를 n-gram이라고...
  • "Emma knocked on the door'를 2-gram으로 나타내면
    • Emma knocked
    • knocked on
    • on the
    • the door
  • 로 나타낼 수 있다.
  • 하지만 당연히 BoW 보다 훨씬 더 많은 피처 갯수가 생긴다.

정제된 피처를 위한 필터링

  • 단어를 사용할 때는 필요한 정보(시그널)과 노이즈(필요 없는 정보)를 분리해야 함.

불용어

  • 분류와 검색은 텍스트이 대한 깊은 이해를 요구하지 않음(의미까지 명확하게 파악하지 않아도 된다는 뜻일까?)
  • 분류와 같은 섬세하지 않은 작업에서 대명사, 관사, 전치사의 가치는 그다지 크지 않다.
  • 하지만 섬세한 의미론적 이해를 요구하는 감성 분석에서는 매우 다를 수 있다.
  • 영어의 불용어 리스트는, 파이썬 NLP 패키지인 NLTK에 수 많은 언어에 대해 불용어 리스트를 가지고 있다.

빈도 기반 필터링

  • 얼마나 단어가 나오는지를 확인하면, 상용어를 필터링 하기 쉽다.
  • 빈출 단어
    • 또한 단어가 너무 많이 나와도 의미를 파악하기 어려울 수 있다.
    • 의사 회의록은 'House of Commons(하원)'이라는 단어가 많이 나와서 house라는 단어가 너무 많이 나옴.
    • 이를 어떻게 처리 할 것인가를 정하는게 어렵다. 또한 얼마나 많이 등장 할 때만 의미를 부여/제거 할 것인가? 를 정하는것도 쉽지는 않다.
  • 희귀 단어
    • 잘 알려있지 않은 단어거나, 철자가 틀린 것일 수도 있음.
    • 통계적인 모델에서는, 한 두번 나오는건 잡음(노이즈-noise)에 가깝다.
    • 아주 적은 횟수가 등장하는 단어 때문에, 분류를 잘못 할 수도 있다.
    • 또한, 이러한 단어들을 모두 포함해서 연산을 하게 되면 필요 없는 계산을 많이 해야 한다.
    • 책에서 설명하는 Yelp 데이터 160만개 리뷰는 35만개의 고유 단어가 포함되어 있고, 약 23만개의 단어가 1개 혹은 2개의 리뷰에서만 나온다. 즉, 60%의 단어가 크게 의미를 가지지 않을 수도 있다는 뜻이다.
    • 이러한 피처를 모두 모델을 만들때 추가하게 되면, 계산 비용과 저장 비용이 많이 들게 된다. 그러므로 이러한 단어들을 적절히 제거해 주어야 한다.
    • 텍스트의 문장이 매우 짧은 경우, 통계적 의미를 찾기 어려울 수 있기 때문에, 이러한 문장을 제외해야 할 수도 있다. 하지만 트위터는 짧은 문장만을 가질 수 있으므로, 다른 방식의 기법을 사용해야 한다.
  • 어간 추출
    • 어간(語幹) : 활용어의 활용에서 변하지 않는 부분. '읽는다, 읽느냐, 읽고…' 등에서의 '읽'. 어간에 어미 '-다'를 붙인 것을 기본형이라고 하여 사전의 표제어로 올림. 줄기.
    • 단어를 공백이나 구둣점으로 잘라서 세면, 같은 의미를 가진 단어를 모두 따로 카운트 하게 된다. 'swin', 'swinging'은 의미가 비슷하지만 서로 다르다고 카운트 된다.
    • 통계적인 데이터로 처리 할 때에는 어간(stem)을 추출해서 단어의 기본형으로 변환하여 저장하는것이 좋은 경우가 많다.
    • 하지만, news 와 new는 전혀 다른 의미를 가지지만, 같은 new로 어간 추출이 될 수도 있다. 그러므로 항상 어간 추출을 사용해야 한다는것은 아님을 명심하자.

의미의 단위: n-grams에서 구문까지

파싱과 토큰화

  • 문자열에 의미가 있는 텍스트가 아닌게 많다.
  • 또한, 의미를 구분해 주는것도 있을 것이다. 이메일의 from, to 등.
  • 단어를 쪼갤때, 공백, 구둣점 등으로 나누면 된다.
  • n-grams으로 n개를 쪼갤때는, 문서가 아니라 "문장" 단위로 되어야 한다.
  • 즉, 마침표가 있으면 n-grams를 늘리면 안된다.
  • 하지만, word2vec 과 같이 복잡한 것을 할 때는, 단락에 적용할 수도 있다.
  • 암튼, 그냥 상황에 따라서 잘 나눠서 하면 된다는것 같다.

구문 탐색을 위한 연어 추출

  • 연어. 연달아 적힌 단어가 의미를 가질 수 있다.
  • strong tea는 "진한 차" 인데, 두 단어를 쪼개면, "물리력이 강하다"와 "차"로 나눠진다. 그러므로 의미가 달라진다. 이러한것을 연어라고 한다.
  • 'cute puppy'는 'cute'와 'puppy'의 의미를 합쳤을때 동일한 의미를 가진다. 이런건 연어가 아님.
  • 연어가 꼭 연속되어 나오라는 법도 없고, 모든 연속된 단어가 연어라는 법도 없다.
  • 그래서 너무 어려움. 통계적인 기법을 사용한다.
빈도 기반 방법
  • 많이 나타나는 n-grams을 보는 법. bigrams등의 빈도수를 실제로 확인해 보고, 의미 있는것을 찾을 수 있다.
연어 추출을 위한 가설 검증
  • 책에 나오는 복잡한 내용은 생략...
청킹과 품사 태깅
  • 주제를 찾는 경우에는 명사에 가장 관심이 있을 수 있음.
  • 즉, 품사를 찾아야 함.
  • 걍 형태소 분석을 한다는것으로 보인다. 통과. ㅋㅋㅋ

요약

  • Bag of Word
    • BoW, 단어를 하나씩 Bag에 넣는것
    • 단순 검색에는 좋으나, 문맥이 유지 되지 않아 의미를 파악하기 어려움
  • Bag of n grams
    • n-gram을 Bag에 넣는것, 연속된 단어를 n개 조합해서 저장
    • 하지만 연속된 단어 n개의 조합이 너무 많아서 데이터 양이 너무 많음
    • 데이터 양이 많다면, 의미를 가지는 데이터를 더 찾기 어려울 수 있다.
  • 연어(구문, 상용구) 추출
    • 연속된 구문을 보고 의미가 있고, 없는 것들을 통계적으로 추출할 수 있다.
  • 이 장에서 설명한 문장을 처리하는 방법은, 문장을 쪼개 단어의 bag으로 만들게 된다. 그러므로 이러한 방식으로는 문장의 의미를 구체적으로 파악하기는 어렵다.

4장 피처 스케일링의 효과: BoW에서 tf-idf로

  • BoW 는 필요 없는 단어들이 강조 될 수 있다. "is", "the", "and" 는 문장에서 너무 많이 나올 것이다.
  • 하지만, 문장에서 "happy", "gloomy" 등은 자주 등장하지는 않지만, 문장의 의미를 잘 표현한다. 이러한 것들을 잘 찾아 주는 방법을 찾아야 한다.

tf-idf: BoW 비틀기

  • tf-idf : term frequency-inverse document frequency
  • tf-idf : 용어 빈도 - 역 문서 빈도
    • 각 단어의 카운트를 해당 단어가 나타나는 문서의 수로 나눈 정규화 카운트
    • (하나의 문서에서 해당 단어 카운트)*log((전체 문서 수)/(해당 단어가 나타나는 문서의 수))
    • 전체 문서가 5개 일때, 모든 문서에 'is'가 들어간다고 하면 위 공식의 뒷 부분이 log(5/5) = log(1) = 0이다. 그러므로 위의 공식의 결과는 0 이다.
    • 'is'는 tf-idf 를 이용해서 처리하면 0이 된다. 즉, 모든 문서에 나오는 단어의 의미를 제거할 수 있다.

tf-idf 테스트

  • 자세한 내용은 생략
  • 학습을 시킬때, 데이터 카테고리별 갯수가 차이가 많이 나면 당연히 결과가 좋지 않을 것이다. 그러므로 데이터 카테고리별 갯수를 세고, 작은 쪽에 맞춰 주어야 한다.
  • 테스트셋에 트레이닝셋에 존재하지 않는 정보가 있다면, 당연히 테스트셋의 결과를 제대로 확인 할 수 없을 것이다.
  • 충분히 많은 양의 데이터라면, 테스트셋에만 존재하는 데이터는 "희귀"한 데이터 일 수도 있다. 그러므로 이때는 "그냥 무시"하는 방법을 써도 되는지 검토해 볼 필요가 있다.
  • 이 장에는... 머신러닝 관련되는 이런저런 이야기가 나온다. 난 걍 통과.

심층 분석: 무슨 일이 일어나고 있는가?

  • 생략

요약

  • 피처 스케일링을 통해 정보가 많은 단어는 강조되고, 상용어는 가중치가 낮아진다.

5장 범주형 변수: 로봇닭 시대에 달걀 개수 세기

  • 범주형 변수(categorycal variable)
  • 카테고리나 레이블(label)을 나타내는 방법
  • 범주형인지 아닌지 알아 내는건 쉬움. 연속적인지 아닌지를 판단하면 됨.
    • 주가 10달러와 15달러는 연속적인 값.
    • "정치", "경제", "사회"는 연속적이지 않은 값.
  • 문서 코퍼스(corpus)의 어휘도 각 단어가 구분되므로 커다란 범주형이라고 볼 수 있음.
  • 하지만 같은 단어가 여러번 나타날 수도 있으니, 이를 카운팅 할 수 있음.

범주형 변수 인코딩

  • 범주는 일반적으로 숫자가 아님. 예를 들면 "빨간색","검은색","파란색" 등이다.
  • 제일 쉬운 방법은 숫자를 1씩 증가시키면서 매길 수 있을 거다. 하지만, 이렇게 하면 값의 크기가 의미가 생길 수 있다. 그러므로 다른 방법을 찾아 보자.

원-핫 인코딩

  • 00001000, 1000000, 00100000 와 같이 여러개 중에 한개만 켜지는거(아니깐 생략)

더미 코딩

  • 원-핫 인코딩은 1개는 무조건 1이어야 하나, 더미 코딩은 모두 0 인게 있음.
  • 모두 0 인게 기준 범주.(기준 범주와 다른 애들과의 차이를 쉽게 볼 수 있다.)

이펙트 코딩

  • 더미 코딩의 모두 0 인것이, 모두 -1로 되는 것
  • 뭔 말인지 모르겠으니깐 통과. ㅎ.

범주형 변수 인코딩의 장단점

  • 원-핫 인코딩, 더미 코딩, 이펙트 코딩의 처리 방법은, 범주의 수가 매우 커지면 성능이 급격히 떨어진다. 수가 매우 많은 범주형 변수를 처리하기 위해서는 또 다른 전략 필요.

대규모 범주형 변수 처리

  • 피처 해싱 : 문자열, 숫자등을 해싱해서 변환, 매핑. 단점 : 원본 피처에 대한 정보가 사라져 더 이상 해석하기 어려워짐.
  • 빈 카운팅 : 어려우니깐 생략

요약

  • 책에 잘 정리 되어 있으니, 책 참고.

6장 차원 축소: PCA로 데이터 패케이크 납잡하게 만들기

  • 주성분 분석(PCA, Principal Component Analysis), 피처 차원 축소
  • 어려운건 다 생략하고...

직관

  • 차원 축소 : 핵심 정보는 유지하면서, '쓸모없는 정보'를 제거하기 위한 것
  • 수학적으로 새로운 피처 공간에서 데이터포인트들의 분산이 최대로 되게 한다.

수식 유도

  • 생략

PCA의 활약

  • MNIST 데이터중 8x8 로되어 있는 저해상도 데이터는, 64차원의 데이터를 갖는다.
  • pca_tranformer = PCA(n_componets=0.8)로 하면, 전체 분산의 최소 80%를 설명하는 수준에서 자동 선택.
  • 화면에 출력 결과, 3차원의 데이터만으로 비슷한 숫자들을 가깝게 그룹지은것을 볼 수 있음.

화이트닝과 ZCA

  • 모르겠으니깐 생략.

PCA의 고려사항과 한계

  • 차원 축소를 위해 PCA를 사용할 때는 얼마나 많은 주성분(k)을 사용할 것인지를 확인해야 한다.
  • PCA는 변환이 매우 복잡함. 결과 또한 해석이 어려움. 계산 비용도 많이 듬. 데이터 포인트나 피처의 수가 매우 많다면 수행하지 않는것이 좋다.
  • 데이터가 스트리밍으로 들어오면 PCA를 수행하기 어려움 ( 지금까지의 값으로 분산이 크도록 해 두었는데, 새로 들어온 값이 그것을 깰 수도 있다. )
  • 카운트에 사용하지 않는것이 좋다. 이상치(아웃라이어)들이 있기 때문에, 상관 관계가 쉽게 깨질 수 있다. 사용하고 싶다면, log등을 사용해서 처리하는 방법을 찾거나 하면 된다.

사용 예

  • PCA 변환은 데이터에서 정보를 제거한다. 따라서 이 정보로 모델을 학습할 때는 계산 비용이 적게 들지만, 정확도는 떨어질 수 있다.
  • PCA를 사용한 멋진 애플리케이션 : 시계열 데이터의 이상 탐지, 재무 모델링, 주가의 상관관계 패턴...(모르겠음 ㅋ )

요약

  • PCA에 대해 기억해야 할 두가지 핵심
    • 메커니즘 : 선형 투영
    • 목표 : 투영된 데이터의 분산 최대화
  • PCA는 모델 중심 피처 엔지니어링의 한 예. 분산이 데이터가 가지고 있는 정보를 적절하게 표현한다는것.
  • PCA는 잘 알려진 차원 축소 기법. 하지만 큰 계산 비용이 들고 결과물을 해석할 수 없다는 제약.
  • PCA 특히 피처들 사이의 선형 상관관계가 있을 때 전처리 단계로써 유용.

7장 k-평균 모델 스태킹을 통한 비선형 피처 생성

  • PCA는 데이터가 평평한 팬케이크 모양의 선형 부분 공간에 있을때 유용
  • 데이터가 휘어진 곡면으로 이뤄진(스위스 롤 같은) 경우. 결국은 2D 평면이 둥글레 말려 3D로 된 것임.
  • 피처 엔지니어링의 목적은 피처의 차원을 낮게 만드는것이 목적이 아니라, 과제를 수행하기 적합한 피처를 얻는 것
  • 가까이 있는것들을 모으는 클러스터링 방법을 사용할 수 있다.
  • 클러스터의 수가 원래의 피처 수 보다 작으면, 차원이 축소 되었다고 볼 수 있다.

k-평균 클러스터링

  • 비슷한 공간상에 놓여진 데이터를 그룹화 하는것.
  • 비지도 학습
  • 유클리드 기하학으로 두 점 사이의 거리를 측정 하여 근접성을 측정한다.
  • k-평균은 각 데이터 포인트가 오직 하나의 클러스터에만 할당되는 하드 클러스터링
    from sklearn.cluster import KMeans
    # 10개의 클러스터로 나눈다.
    clusters = KMeans(n_clusters=10, ramdom_state=1).fit_predict(numpy_array);

곡면 분할로서의 클러스터링

  • 스위스 롤 형태의 데이터를 KMeans 클러스터링으로 할때 k가 너무 작으면 클러스터가 잘 나눠지지 않는다.

분류를 위한 k-평균 피처 생성

  • 목표 변수를 사용하면, 그 값을 기준으로 클러스터링을 할 수 있다.(?)
  • 생략

장단점과 몇 가지 사항들

  • 생략

8장 피처 생성 자동화: 이미지 피처 추출과 딥러닝

  • 예전 방식에 대한 설명과, 딥러닝에 대한 설명을 모두 진행

가장 단순한 이미지 피처(그리고 이것이 동작하지 않는 이유)

  • 이미지를 검색하려고 한다마녀, 이미지 데이터 베이스에서 비슷한 이미지를 찾아야 한다.
  • 단순히 이미지에 있는 개별 픽셀 색상 값을 가지고 처리 할 수 없음. 이미지 간의 차이를 어떻게 계산 할 것인지를 결정하는것이 핵심

수동 피처 추출: SIFT와 HOG

  • 이미지 그래디언트(인접픽셀과의 차이)를 활용해서 벡터를 구한다.
  • ... 생략 ...

심층 신경망으로 이미지 피처 학습

  • Fully Connected Network, Convolution, ReLU, Normalization, Max Pooling 설명
  • AlexNet 설명
  • 이 분야에서의 엄청난 발전에도 불구하고 이미지 피처 생성은 아직 과학보다는 예술에 가깝다.
  • 10년 전에 사람들은 이미지 그래디언트, 테두리 탐지, 방향 탐지, 공간 단서, 스무딩, 정규화 등을 사용해 피처 추출을 수작업으로 진행했다.
  • 요즘은 딥러닝 아키텍트가 동일한 아이디어를 캡슐화 하는 모델을 작성하기는 하지만, 파라미터들은 학습용 이미지를 통해 자동으로 학습된다. 마법은 여전히 존재하며, 단지 모델의 더 깊숙한 곳에 추상화돼 숨어있을 뿐이다.

9장 다시 피처로: 학술 논문 추천 시스템 구축

  • 실제 예제를 사용해서 데이터 피처링을 해 보자

항목 기반 협업 필터링

  • 생략

첫 번째 단계: 데이터 가져오기, 정제하기, 피처 파싱하기

  • 단순 두 개의 피처만 사용해서 항목 유사도(코사인유사도)를 구했는데. 시간이 엄청 오래 걸렸다.
  • 데이터 갯수가 너무 많으니 계산하는데 시간이 너무 오래 걸림.
  • 현재의 방식은 반복적인 엔지니어링을 위해서 너무 느리다.

두 번째 단계: 피처 엔지니어링과 더 똑똑한 모델

  • 출간년도를 비닝으로 처리. 10년 단위로 비닝을 해서 피처 공간을 156에서 19로 줄임.
  • 데이터 프레임을 희소 배열로 변환
  • 위와 같이 하면 누락된 데이터가 매우 많을 것이다. 더 많은 정보를 가진 피처를 선택할 수 있는지 살펴 봐야 한다.

세 번째 단계: 추가 피처 = 추가 정보

  • 기존의 피처에서 추가로 초록(abstract)과 저자(authors)를 추가 할 수 있음
  • 초록(abstract)이나 제목의 경우 명사구나 stem(어근)을 구해서 처리 할 수도 있다.

발단

오랜만에 네이버 카페 남궁성의 코드 초보 스터디에 갔는데, 재미난 질문이 있어서 정리를 해 본다.

게시물 및 책 내용

책 내용

  • 책의 일부
    • append를 연결해서 사용하면 메서드 체인이 발생해 메모리 누수가 발생할 가능성이 있다.
  • 위 내용에 대한 설명
    • 모든 메서드가 하나의 체인으로 연결되며 이 메서드에 사용된 모든 인자도 연결되므로 비효율적인 메모리 점유가 발생
    • 하지만 메소드 체인으로 서로 연결된 메서드는 결국 연결된 모든 메소드의 스택이 종료되기 전까지 점유한 메모리를 반환하지 않으며, 메서드에 전달된 인자 또한 모든 메서드가 종료되기 전까지 메모리 상에 유지된다.
    • 나머지 연관된 메서드와 인자가 모두 생존하면서 메모리를 점유할 가능성이 높다.

논란?

  • 우리가 일반적으로 아는 지식을 기반으로 하면, append 메소드가 호출되고, return 되면, append 메소드 안에서 사용한 모든 메모리를 해제 된다.
  • append 메소드 내에서 사용된 Stack 영역의 메모리는 당연히 해제되고, append 메소드 내에서 사용된 heap 영역의 메모리 역시 return 값으로 할당되고 해제 된다.
  • 그런데 왜 책에서는 저렇게 어려운 말을 적었을까? 라는 궁금함이 생겼다.

진짜 다를까? 진짜 확인해 보자.

  • 정확한것을 확인해 보려면, bytecode를 까 보면 되지 않을까? 라는 생각이 들어 실제로 bytecode를 비교해 보기로 했다.

메소드 체인 형태의 bytecode 확인

  • 코드

    Object o1 = new Object();
    Object o2 = new Object();
    // ....
    sb.append("A").append("B").append(o1.toString()).append(o2.toString())... 
  • bytecode

  • bytecode를 분석해 보자.

    1. local variable로 되어 있는 o1 aload로 "메모리의 stack"영역으로 load
    2. invokevirtual로 toString() 메소드를 호출
    3. 그리고 다시 o2에 대해서 위의 1과 2를 반복
    4. 그리고 o3 에 대해서 위의 1과 2를 반복
    5. 그리고 제일 마지막에 pop 를 단 한번만 호출
  • 즉, pop을 딱 한번만 호출

일일이 호출한 경우 bytecode 확인

  • 코드

    Object o1 = new Object();
    Object o2 = new Object();
    // ....
    sb.append("A").append("B")
    sb.append(o1.toString());
    sb.append(o2.toString());
  • bytecode

  • bytecode를 분석해 보자.

    1. aload_1
    2. aload_2
    3. invokevirtual
    4. 로 메모리를 stack에 데이터를 올린뒤, append()가 끝나면 pop으로 데이터 날림
    5. 위 1, 2, 3, 4를 반복
  • 즉, append() 명령이 종료된 시점에 매번 pop을 호출

결론

  • 위 두가지 경우로만 확인해 본다면, 결과적으로 bytecode 상으로는 확연히 다르게 동작한다는것을 알 수 있다.
  • 문제는 메모리의 Stack 영역에 n개의 데이터가 올려져 있다는 것이다.

메소드 체인 형태의 호출에서 비효율적인 메모리 점유가 발생할 수 있나?

  • 맞다. 비효율적인 메모리 점유가 발생할 수 있다.
  • 필요 없는 variable을 stack에 올려 두는것은 비효율적인 메모리 점유가 발생할 수 있다.
  • 우리가 일반적으로 알기에는 method내에 정의된 variable들만 stack 영역에 들어 가는것으로 알고 있다.
  • 하지만, method내에서 호출된 또 다른 메소드의 return값(invokevirtual)도 stack 영역에 보관해야 한다. 그래야 호출한 method에서 그 값을 사용할 수 있을 것이기 때문이다.
  • 그렇기 때문에, 메소드 체인 형태의 호출 방법에서는 pop을 단 한번만 호출하기 때문에, 메소드 체인이 끝나기 전까지, return 값들의 reference count가 여전히 1일 것이다.
  • reference count 가 1이기 때문에 당연히 GC를 할 수 없는 상태가 될 것이므로,
  • 비효율적인 메모리 점유가 발생할 수 있다.

메소드 체인 형태의 호출에서 누수가 발생할 수 있나?

  • 정확하게 말하면 아니다. 누수란 회수 하지 못한 메모리라고 생각한다.
  • 하지만, bytecode에서 발견할 수 있다시피, 해당 Line이 종료되면 pop되므로 메모리는 반드시 회수된다.
  • 누수가 발생할 수 있냐는 질문에는, 아니라고 말하는게 맞을 듯 하다.

메소드 체인 형태의 호출은 성능상 문제가 발생 할 수 있나?

  • 발생할 수도 있다.
  • 코드의 처리 속도
    • 메소드 체인 형태의 호출은 bytecode가 훨씬 더 간결하다.
    • 그렇기 때문에 메소드 체인 형태의 호출이 속도면에서는 훨씬 빠를 것이다.
  • 하지만, GC가 문제가 될 수 있다.
    • pop을 매 함수마다 호출하나, 최종에 한번만 호출하나 어차피 할당되어야 할 객체와 풀여야할 객체다.
    • 하지만, pop이 제일 마지막에 호출 된다면
    • 그 전까지 할당된 메모리를 풀지 않기 때문에
    • 메모리가 부족할 확률이 조금 더 높아진다.
    • 메모리가 부족하면, GC가 동작하게 된다
    • 이로 인해서 성능상 문제가 발생할 수 있다.

메소드 체인 형태의 호출은 "반드시" 성능상 문제가 발생할 수 있나?

  • 아닐 수 있다.
  • 성능에 문제가 발생할 수는 있지만, 반드시 성능에 영향을 미친다고 볼 수 없다.
  • 위의 bytecode만을 본다면, 반드시 성능에 영향을 미친다고 볼 수 있다.
  • 문제는 컴파일러다.
    • JVM은 bytecode를 검토/실행하는 스펙이다.
    • bytecode를 생성하는것은 컴파일러의 몫이다.
    • 컴파일러의 구현은 스펙이 없다.
    • 그러므로 모든 컴파일러가 같은 bytecode를 생성한다는 보장이 없다.
    • 컴파일러의 구현에 따라 어떠한 bytecode가 나올지 알 수 없으므로
    • 반드시 성능 문제가 발생한다고 볼 수는 없다.

너무 오랜만에 Java쪽 자료를 찾아봐서.. 정확한 결론인지는 모르겠다. 하지만 오랜만에 이런거 찾아보고 정리하니 재미있었다. ㅋ.

혹시나 잘못 된 정보가 있다면, 언제든지 지적 부탁드립니다. ^_^

이것저것

공부하기

  • 데이터를 많이 모아 보려고 하고 있다.
  • 데이터를 모으는것은 그냥 모으면 되지만, 이것들을 어떻게 활용 할 것인가에 대한 고민...
    • 데이터를 "처리"하는 부분
    • 데이터를 "분석"하는 부분
    • 데이터를 "활용"하는 부분
  • 으로 나뉘어 질텐데, 우선 텍스트를 쉽게 분석? 할 수 있는 엘라스틱 스택에 대해서 공부 하기로.

읽기

  • 우선 이 책은 초보자를 위한 책은 아님이 확실하다.
  • 엘라스틱 서치의 많은 것을 알려 주기는 하지만, 설명이 장황하고, 구체적이다. 초보가 보기에는 정보가 너무 많아, 너무 어렵게 느껴 질 것으로 판단된다.
  • 이 글에서는, 책의 순서가 뒤죽 박죽이 될 수도 있겠다.

02장 일래스틱서치 시작하기

  • ubuntu 에서 apt로 elasticsearch를 설치하면, 9200 포트에 접근이 되지 않는 경우가 있다.

    • /etc/elasticsearch/elasticsearch.yml 파일에서 network.host 부분을 0.0.0.0으로 변경해 준다.
  • p57 kibana에서 REST API 호출하기

    • GET /라고 입력한 뒤, 초록색 삼각형()을 누르면 해당 쿼리가 실행된다고 한다.
    • 더 쉬운 방법이 있다. 실행하고 싶은 쿼리가 있는 곳으로 커서을 옮긴 뒤, Ctrl + Enter를 입력하면, 커서가 있는 위치의 명령이 수행된다. 이걸 쓰도록 하자.
    • kibana Dev Tools 에서 쿼리를 입력하는 도중 문제가 있으면, 에러 표시()를 해 주므로, 쉽게 사용할 수 있다.
      • 아래는 json의 key 부분인 params"로 감싸지 않아서, 문제가 있다고 알려줌.
      • 단, 모든 에러를 모두 찾아주는건 아니니깐.. 그건 어쩔 수 없음. ㅋ.
  • 엘라스틱 서치에서 REST API의 동작이 ... 뭔가 .. 좀 이해하기 어렵다.

    • 보통 POST는 "추가/생성"의 의미를 가지고, PUT은 "수정(혹은 생성?)"의 의미를 가지는데, 이책의 예제들을 보면, 그게 좀 모호하다.
      • POST
        • id 지정 없이 데이터를 추가하고 싶은 경우(서버가 알아서 id를 할당)
        • id 가 있고, 데이터를 수정하고 싶은 경우 (응???)
      • PUT
        • 인덱스를 새로 만들고 싶은 경우
        • id를 지정해서 도큐먼트(데이터)를 추가하고 싶은 경우
  • p60 가운데 그림

    • 노드 이라고 되어 있는데, 아마도 인덱스가 되어야 할 것이다.
    • 실제 노드에 대한 설명은 64, 64 페이지에 나온다.
  • p78 가운데 업데이트 API 예제

    • POST /catalog/product/1/_update { 에서 마지막 {를 빼야 한다.
    • 다음줄에 {가 또 나오기 때문이다.
    • Kibana에서 입력할 때도 _update뒤에 {가 있으면, 아래와 같이 에러가 발생한다.
  • p 82 인덱스의 매핑을 지정하기 위해서 mappings를 사용하는 부분.

    • mappings로 되어 있어서, 여러개의 type을 넣어 보고 싶어서 시도 했으나, 한개의 인덱스에 여러개의 type을 넣으니 에러가 발생했다. 이상하다, 분명히 인터넷에 여러개의 type을 넣는 예제( [Elasticsearch] Multi types into Index. )도 있는데 말이다.

    • 근데 왜 mappings일까?

      • 한국 엘라스틱에서 올린 글( 미처 못 다한 이야기들 - Elastic{ON} Tour Seoul )에서 이유를 찾을 수 있다.

        • 타입(Type) : 엘라스틱 서치 6.0부터는 타입이 하나로 제한됩니다. 단, 5.x에서 만들어진 인덱스는 6.0으로 업그레이드 했을 때도 그대로 여러 타입을 사용할 수 있습니다.

      • 즉, 이전에는 mappings가 정확한 의미를 잘 표현한 것이고, 6.x에서 달라졌으나, 그 이름을 그대로 활용하는 상태라고 이해된다. 그냥 mapping이라고 하나 추가해도 될 듯 한데...

  • p83 기존 인덱스에 타입 매핑 생성

    • 인덱스를 생성한 후에도 인덱스 타입을 추가할 수 있다.라는 말이 있는데, 이게 상황에 따라 다르다.

    • 이전 페이지인 p 82 에서 이미 catalog에 대해서 my_type이라는 타입을 만들어 두었다.

    • 위에 설명한 mappings에 대한 설명을 적용하면, 한개의 인덱스에서는 두개의 타입을 넣을 수 없다. 그러므로 이미 my_type이라는 타입을 넣어 두었으므로, p 83에서 추가하려고하는 catalog 타입을 넣으려고 하면, 아래와 같이 에러가 발생한다.

    • 그러므로, 정확한 설명은 인덱스를 생성하고, 타입을 추가하지 않은 경우, 나중에 타입을 추가할 수 있다. 라고 되어야 한다. 이를 모두 자세히 나열하면 아래와 같은 것이다.

      • DELETE /catalog로 먼저 생성해둔 catalog 인덱스를 삭제
      • PUT /catalog인덱스만 생성
      • PUT /catalog/_mapping/category { ... }category 라는 타입을 추가하면서 mappings까지 설정
      • GET /catalog/_mapping/을 통해서 category라는 타입mappings가 잘 설정 되었는지 확인.
    • 일반적으로 mapping을 만들때, 전문검색(full text search)할 대상의 typetext 로 주게 된다. 예를들면 뉴스의 내용은 전문검색이 필요하므로 typetext로 설정해야 할 것이다.

  • p88 JSON 응답 형식 부분

    • 기본적으로 모든 요청에 대한 응답은 형식이 없다. .. 어떠한 형식도 지정되지 않는다. 부분의 번역이 언뜻 이해하기 어렵다.
    • 단 한줄로 json응답이 오면 응답 형식이 없는 상태이고, 엔터와 탭으로, 예쁘게 json 응답이 오는것을 응답 형식이 있는 상태라고 해석하고 있다.
    • 아마도, "포맷(format)"을 "형식"이라고 번역했지 않을까 생각해 본다.
    • 기술 서적이라면(적어도, 이정도의 고난이도?? 기술을 다루는 책이라면.. 모든것을 번역할 필요가 있을지 의문이다... )
    • 책에서는 ?pretty=true를 사용했지만, 단순히 ?pretty만 사용해도 json 형태의 응답이 예쁘게 출력 된다.
    • 또한 JSON 형식 뿐만 아니라, yaml 형태로 출력 할 수도 있다. ?format=yaml를 이용해서 쿼리를 날리면 된다.
  • p90 GET /_search의 결과물 부분

    • 책에서는 나오지 않지만, 실제로 쿼리를 실행하면, 우리가 만든 category 뿐만 아니라, 우리가 만들지 않은 .kibana_1이라는 인덱스를 발견할 수 있다.
    • 이건 말 그대로 kibana용 인덱스이다. 언제 이런게 만들어졌나고?
    • kibana를 최초로 실행시키면 아래의 로그를 볼 수 있다.

03장 유사도 검색

  • 이후 부터 용어라는 말이 나오는데, 영어로는 term이다. ( 사실 이미 p73 등에서 등장한 말이다.) 역색인시 사용하는 key 정도로 이해하고 우선 넘어 가면 될 듯 하다. ( key일래스틱 서치와 같이, 여러개의 단어로 이루어져 있을 수도 있을것 같다. - 정확하지 않음.)

  • p94 전문검색 이라는 용어가 나오는데, 全文검색이다. 영어로는 Full Text Search

  • 텍스트 분석기는 아래의 3가지 과정은 순차적으로 거친다

    1. 문자 필터(Character filters) : 0개 이상 - 문자열 치환 등 문자열 처리
    2. 토크나이저(Tokenizer) : 정확히 1개 - 문자열을 쪼개주는 역할, 역색인 만들때 사용
    3. 토큰 필터(Token filters) : 0개 이상 - 쪼개진 문자열을 다시 처리하는 역할, 각 토큰으로 들어온 문자열을 소문자로 바꾸거나, 불용어(The, a, an, is ...)를 없애주는 등의 처리 가능
  • 토크나이저(Tokenizer)는 문자열을 잘라주는 역할인데, 표준분석기, 언어분석기, 공백분석기 등이 있다.

  • 이 중에서 제일 재미난건 언어 분석기인데, 사실상 이 놈의 핵심인것 같다.

  • 재수좋게도, 2018년 8월 24일에 엘라스틱에서 공식 한국어 분석 플러그인 '노리'를 만들었다. 아싸!!

    • 용량이 작다.
    • 속도가 빠르다.
    • 공식지원이니 설치가 편하다.
  • 설치하는 방법과 간단한 사용방법은 Elasticsearch 6.4 기본 한글 형태소 분석기 노리 (nori) 설명 및 사전 추가하기를 방문해서 확인해 보자.

  • REST api로는 아래와 같이 호출해 보면, 아래와 같이 주요 단어를 잘 뽑아 주는것을 확인해 볼 수 있다.

  • 뉴스 관련 데이터로 몇가지 테스트를 해 보았다.

    • 뉴스의 카테고리는 category라는 이름으로 그냥 text로 만들었고, title과 contents는 "nori" 분석기를 달도록 설정했다.

    • 이후 news/article type에 30여개의 document를 추가 했다.

    • 뉴스 데이터 category에 "경제"를 넣어 두고, 검색할때 "category" : "경제" 를 검색하면 아래와 같이 잘 찾아 진다.

    • 하지만 "category" : "경제적"을 검색하면 제대로 찾아 지지 않는다.

    • 이제 contents에도 똑같이 경제를 검색해 보자. "경제"라는 글자가 contents에 있는 경우에는 당연히 잘 검색 된다.

    • 이제 contents에 경제적을 검색해 보자. "nori" 분석기가 잘 동작했다면, "경제적"이라는 전체 단어가 아니라, "경제"라는 단어만 있어도 잘 검색해 줄 것이다. 아래 결과를 보면 "경제"가 들어간 결과 뿐만 아니라, 경제를도 잘 검색 된다는것을 알 수 있다. 즉, 분석기가 글자를 잘 분석해서 역색인 했다는것을 알 수 있다.

구조화된 데이터 검색

  • 반면, 비슷것을 찾아주는게 아니라 정확하게 색인 된 것만 찾으려면 term 을 사용해서 찾으면 된다.

    • match를 사용하는 위의 예제에서는 경제적을 검색어로 써도 경제를 찾거나, 경제를을 찾아준다.하지만 정확하게 색인된 것만 찾으려면 term을 사용하자
    • term을 사용해서 경제적을 찾으며 아무것도 찾아지지 않는다는것을 알 수 있다.
    • 그렇다면 contents에 실제로 있는 경제를이라는 검색어를 term을 사용해서 검색하면 어떻게 될까? 아래와 같이 검색 되지 않는다.
    • term색인된 것만을 검색한다. nori 분석기에서는 경제를을 색인한것이 아니라, 경제만 색인 했기 때문에 term을 사용했을때 경제를이라는 검색어로는 찾아지지 않는것으로 보인다.
    • term을 사용하여 경제를 찾으면 제대로 찾아 지는것을 알 수 있다.
  • title이나 contents 필드는 text 타입으로 설정해 두었다. 그러므로 match로 검색을 하면 nori 분석기를 통해서 비슷한 것도 찾아 준다. 하지만 만약 category 필드와 같이 keyword 타입으로 설정해 두었다면, nori 분석기등을 통하지 않고 "정확한 것"만 검색하도록 된다.

전문 텍스트 검색

  • match검색시 검색어에 오타가 있을 경우를 대비한 fuzziness값을 줄 수도 있다.

    • fuzziness에 1, 2 등의 값을 주면, 몇 글자가 틀려도 알아서 찾아 준다.
    • 예를 들어 경조라고 잘못 검색어를 입력해도,공조, 경찰, 경제등을 찾아 준다.
  • 반면 match에는 여러 검색어에 정확하게 맞는 쿼리를 보내고 싶을 때는 match_phrase를 사용한다. 구글에서 " " 로 감싸서 쿼리하는것과 비슷하다.

    • 단, 검색어에서 순서는 정확하게 맞지만, 일부 단어가 생략되는것을 허용하려면 slop 값을 조정하면 된다.
  • 그외 이것 저것은 생략. 나중에 필요할 때 찾아 보자

04장 일래스틱서치 분석

Metric 집계

  • Aggregation(어그리게이션)을 여기서는 집계라고 부른다. 쉽게 생각하면 걍 숫자 랑 관련되는 통계?를 내는것이라고 생각하자.
  • 숫자 관련 통계는 합계(sum), 평균(avg), 최소(min), 최대(max), 이상의 4개를 모두 한번에 보여 줄 수 있는 통계(stats)가 있다. 아래는 이미지 데이터에서 각 이미지 용량의 합계, 평균, 최소, 최대 값을 출력한 것이다.
  • 제곱, 분산, 표준편차, 표준편차 구간등을 한꺼번에 보여 줄 수 있는 확장통계(extended_stats)도 있다.
  • 만약 데이터를 구성할때, 자식을 가지도록 구성했다면, aggs를 사용할때, nested라는걸 사용해서 처리해야 한다. ... (아.. 어려워... ) 아래는 이미지 데이터에서 각 이미지 해상도의 너비와 높이에 대한 통계 정보를 출력한 것이다.
  • unique한 값의 갯수를 세고 싶을때는 cardinality를 사용하면 된다. 아래는 이미지 데이터에서 unique한 Tag 갯수를 출력한 것이다. 이미지 데이터에 있는 Unique한 Tag 갯수는 약 10만개다.

Bucket 집계

  • 문자열 데이터 버켓팅에서 Terms 집계 : 관련 내용은 아래에 나오는 fielddata 관련 부분을 확인해 보면 예제를 볼 수 있다.
  • 숫자 데이터 버켓팅에서 재미난게 있다. histogram 집계인데, 일정 간격으로 숫자를 쪼개서 갯수를 세어주는게 있다. 아래는 이미지 데이터에서 이미지를 2Mbyte 단위의 용량별로 갯수를 센 결과를 출력한 것이다.
  • 일정 간격이 아니라, 특정 간격으로 나눠서 보고 싶다면, rangeranges, 그리고 from, to를 사용하면 된다. 단, to의 값은 포함하지 않는다. 자세한건 생략.ㅋ. 책을 찾아 보도록 하자. ( 170페이지 참고 )
  • 그 이외에, A이면서 B인 경우 갯수 세기, 시간별로 쪼개서 확인하고, 지리적 위치를 기반으로 쪼개서 확인하기 등이 있다. 자세한건 책으로... ㅋ

05장 로그 데이터 분석 (아직 안 읽음)

로그스태시 아키텍처

  • 로그스태시는, "입력", "필터", "출력"으로 이루어 진다. 즉, 이 세가지로 데이터를 처리 할 수 있다.
  • 로그스태시는 기본적으로 파이프라인 단계별로 이벤트를 버퍼에 담기 위해 인 메모리 바운드 큐를 사용한다. 로그스태시가 불안정한 상태로 종료되면 인메모미레 저장된 이벤트는 손실 된다. 데이터 손실 방지를 위해서 영구 큐를 사용해 실행중인 이벤트를 디스크에 유지할 수도 있다.(LOGSTASH_HOME/config/logstash.yml 파일에서 queue.type:persisted 설정, RAM을 1GB사용하는데 변경하려면 LOGSTATSH+HOME/config/jvm.options에 Xms, Xmx를 변경 가능)
  • p210 윗쪽 예제에서 mutate{ 를 닫아두는 } 가 없다. 그러므로 잘 닫아 주어야 한다.
입력 플러그인(Input Plugin)
  • File
    • p216 각 파일의 모든 변경 사항을 추적하고, 마지막으로 읽은 위치를 기반으로 해당 시점 이후 데이터만 전송한다. ... 각 파일에서 현재 위치는 sincedb라는 별도로 분리한 파일에 기록한다. 따라서 로그스태시를 중지하고 다시 실행해도 로그스태시가 실행되지 않은 순간에 추가된 행을 빠뜨리지 않고 중단된 부분부터 작업을 수행할 수 있다.
    • 여러 파일을 설정할 수도 있고, 각종 옵션을 조정하며, 입력으로 사용할 위치(Line?)도 정할 수 있다.
  • Beat
    • 일래스틱비트에서 발생하는 이벤트를 수신할 수 있음.
  • JDBC
  • IMAP : IMAP 서버에서 이메일을 읽을 수 있음. host, password, user 필수.
출력 플러그인(Output Plugin)
  • Elasticsearch : 권장하는 방법. 자동으로 localhost:9200 사용. 필요하다면 각종 옵션으로 다른곳에 저장 가능.
  • CSV
  • Kafka : 카프카 토픽에 이벤트를 작성할 때 사용. 필수 매개변수는 topic_id
  • PagerDuty : 알림을 보낼 수 있는 서비스에 연동 가능
코텍 플러그인(Codec Plugin)
  • Input전이나, Output후에 변환을 할 수 있는 기능
  • JSON : 입력 플러그인에서 JSON 데이터를 디코딩, 출력 플러그인에서 데이터를 JSON으로 인코딩 할 수 있음. 여러줄로 이루어져 있는 JSON인 경우, json_lines 코덱을 사용
  • rubydebuga
  • Multiline : 여러행에 걸친 데이터를 단일 이벤트로 병합하는데 유용한 플러그인. 여러행에 걸쳐 있는 스택트레이스 또는 단일 이벤트 정보를 처리할 때 매우 편리하다.
인제스트 노드
  • 이전 일래스틱서치에서는 데이터를 사전 변환하려고 하면 별개의 프로그램을 이용해서 처리해 주었어야 했는데, 이제 인제스트 노드라는게 나왔다.
  • 인제스트 노드는 일래스틱서치에서 색인을 생성하기 전에 도큐먼트를 사전 처리하고, 도큐먼트를 풍부하게 해 주는 경량 솔루션.
  • 이 기능 덕분에 로그스태시 필터 부분을 제거하고 자체적으로 로그 데이터를 처리하고 변환할 수 있게 되었다.
  • gsub, grok, convert, remove, rename 등 20개가 넘는 내장 프로세서 보유
  • 내장 프로세서를 조합해서 _ingest/pipline으로 PUT 해서 파이프라인을 정의할 수 있다.
  • 대신 정의된 파이프라인을 사용해서 데이터를 밀어 넣어야 한다. ( .../mytype/1?pipeline=somepipeline { .... })
  • 파이프라인이 잘 동작하는지 확인하기 위해서 시뮬레이트 해 볼 수 있는데, endpoint에 그 정보를 주면 된다. (.../_ingest/pipeline/somepipeline/_simulate { ... } )

06 로그스태시를 활용한 데이터 파이프라인 구축

로그스태시를 사용한 로그 구문 분석 및 강화

필터 플러그인
  • CSV 필터 : CSV 파일을 쪼개고, 컬럼 이름을 정의 하는 등의 작업 가능
  • Mutate 필터 : 필드 변환, 게저, 수정, 이름변경 등
  • Grok 필터 : 불규칙한 데이터를 분석해 구조화하고, 구조화된 데이터를 쉽게 쿼리하고 필터링 하는데 자주 사용되는 강력한 플러그인. 간단히 말해, 특정 행에서 정규식 기반의 패턴이 일치하도록 하는 방법
  • Date 필터 : 시간을 처리(포맷 정의 가능)
  • Geoip 필터
    • ip주소로 위치 정보를 추가하는 필터(GeoLite2 City - Maxmind 회사 제품, CCA ShareAlike 4.0 라이선스 - 데이터베이스 사용)
    • 문자열로 된 IP를 Geoip 필터를 통하면, 위도, 경도, 나라, 도시명 등이 나옴.
  • UserAgent 필터 : 웹브라우저의 UserAgent를 분석

비트 소개

  • 엣지 서버에서 에이전트로 설치되는 경량 데이터 수집기.
  • 립비트라는 라이브러리로 구성되어 있음.
  • 비트는 입력, 출력, 옵션 설정, 이벤트 처리, 로깅 구현이 되어 있고, 데이터를 일래스틱서치, 로그스태시, 레디스, 카프카 등으로 보낼 수 있도록 API를 제공함.
  • 로그스태시와 비트의 차이점
    • 비트는 경량 에이전트로 더 적은 자원 소모(비트는 일반적으로 Go 언어로 작성되어, JVM이 필요 없이 동작 가능)
    • 비트는 엣지 서버에 설치해서 사용하는것이 일반적임
    • 하지만 비트는 이벤트 변환 및 분석, 즉 로그스태시에서 제공하는 강력한 기능은 없음.
    • 로그스태시는 여러 자원에서 데이터를 수집하고 변환하는 가공 및 입력, 필터, 출력 플러그인 제공.
    • 로그스태시는 자원에 더 초점을 두고 있으며, 일래스틱 스택 외에 독립된 제품으로도 사용 가능
    • 로그스태시는 데이터 처리를 위해 이벤트를 수신하는 엣지 서버보다는 전용 서버에 설치하는것이 좋다.
일래스틱비트
  • 파일비트 : 로컬파일에서 로그 수집
  • 메트릭비트 : 운영체제 및 서버에서 실행중인 서비스 메트릭을 주기적으로 수집. 아차피, 몽고DB, 레디스 등 다양항 서비스의 멭릭을 수집. 모니터링하기 좋음.
  • 패킷비트 : 실시간 네트워크 패킷 분석기. 애플리케이션 서버간 네트워크 트래픽을 캡처하거나 HTTP, Mysql, Redis, 맴캐시등의 프로토콜 해석 가능. 요청 응답 상관관계 기록 가능
  • 하트비트 : 서비스 활성 상태 여부, 서비스 가능 여부 모니터링. 주기적으로 실행중인 서비스 상태를 모니터링 가능, ICMP, TCP, HTTP 지원
  • 윈로그비트 : 윈도우 플랫폼에 특화된 비트. 윈도우 API를 사용해 여러 이벤트를 수집.
  • 오디트비트 : 6.0 버젼에 새로 구현. 사용자 활동 모니터링, 니룩스의 auditd를 건드리지 않고 데이터 분석 가능. 실시간으로 변경되는 파일을 설정한 출력으로 보내 잠재적인 보안 정책 위반 행위를 식별하는데 사용 가능.
커뮤니티 비트
  • 스프링부터. 레디스 로그, 엔진엑스 상태, mysql 결과, 몽고DB, 구글애널리틱스, Apache, 아마존 제품 데이터 수집

파일비트

아키텍처
  • Prospectors : 로그를 읽을 파일 목록을 구분하는 역할

  • Harvester : 실제 로그를 읽는 역할, 하나의 Harvester가 개별로 파일을 담당하며 파일을 열고 닫는다. 마지막 읽은 위치를 레지스트리에 관리한다.

  • Spooler : Harvester가 읽은 데이터를 전달 받는다. 이벤트를 집계하고 설정한 출력으로 전달한다.

  • 파일 비트는 이벤트가 지정한 위치로 최소 한 번은 데이터 손실 없이 전달 되도록 보장한다.

  • 파일비트가 일래스틱서치에 저장 될 때는 filebeat-YYYY.MM.DD 패턴의 index에 저장하게 된다.

  • Prospectors 설정

    • input_type, path등을 설정 할 수 있다.
    • 재미난건 exclude_lines 라는 설정을 하면 정규식과 일치하는 행을 제거한다는것이다.
    • 단순히 파일의 선택뿐만 아니라, 내용을 읽어 보고 전달 할지 말지를 전할 수 있다는것이다.
  • 출력 설정 : 일래스틱서치에 넣을때, 정의해 둔 파이프라인을 통해서 넣을 수도 있다.

  • 모듈 : 자주 사용되는 형태의 데이터를 수집, 구문분석하는데 사용된다. ( Apache2, Auditd, MySQL, Nginx, Redis, Icinga, System )

07 키바나를 활용한 데이터 시각화

  • 키바나는 node.js로 실행되는 웹 어플리케이션.
  • 키바나는 일래스틱서치와 같은 버젼을 사용하는 것을 권장. 마이너 버젼도 같은것으로 사용하도록 하자.
  • 기타 생략

08 일래스틱 엑스팩

  • 최근에는 엑스팩이 아니라, Elastic Stack 확장 기능으로 이름을 바꾸었다.
  • 엑스팩은 보안, 알림, 모니터링, 보고서, 머신러닝, 그래프 기능을 제공
  • 기본적인 기능은 무료이나 머신러닝, 그래프 등은 유료
  • 일래스틱서치 클러스터는 일반적으로 여러 노드로 구성되어 있으므로 클러스터에 속한 각 노드의 엑스팩을 설치해야 한다.
  • 키바나에서도 엑스팩을 설치해야 한다.
  • 엘라스틱서치는 내장 보안 기능이 없다. 그러므로 누구나 엘라스틱서치에 접근할 수 있음. 이러한 문제를 해결하기 위해서 일반적으로는 일래스틱서치 앞단에 방화벽을 두거나, 엔진엑스, HAProxy등 리버스 프록시를 사용해서 보안을 강화 한다.
  • 하지만, 엑스팩을 사용하면 사용자 인증 및 권한 관리, 노드 클라이언트의 인증 및 채널 암호화, 감시 등을 지원한다.
  • 키바나에서 사용자 추가/삭제, 권한 관리 가능(심지어 도큐먼트의 필드별로도 권한 관리가 가능하다. )
  • Watcher라는 구성요소는 일래스틱서치에 저장된 데이터의 변경 사항이나 이상징후를 자동으로 감지하고 적절한 조치를 취할 수 있는 기능 제공. 알림 기능을 설치하면 기본적으로 활성화 됨.

09 일래스틱 스택 운영 환경에 적용하기

일래스틱 스택 설정

  • 역색인을 필요로하는 메모리 관련 작업
  • RAM에 저장할 수 있는 데이터가 많아질수록 성능이 좋아진다. 하지만 데이터 타입에따라 연산이 다를 수 있으므로 항상 그러한것은 아니다.
  • 일래스틱서치는 비교적 쉽게 수평 확장 가능
    • 초기에는 CPU 코어 8개, RAM 16GB 혹은 32GB로 사용하는것이 좋다.
    • 어차피 일래스틱서치의 JVM Heap이 32GB 이상 메모리를 잡을 수 없다.
    • 그러므로 64GB 이상의 RAM을 가진 인스턴스를 사용할 필요가 없다.
    • 오히려 무거운 집계 연산을 수행하는 경우에는 SSD를 사용하는것이 좋다.
  • 운영체제는 리눅스를 추천하나, 어느것을 써도 무방하다.
  • 일래스틱서치 노드 설정
    • JVM Heap 크기
      • -Xms-Xmx를 동일하게 설정한다. 힙이 많으면 좋겠지만, 그 만큼 Full GC도 많이 일어난다. Full GC가 일어나면 일래스틱 서치가 잠시 멈출 것이다.
      • 설정할 수 있는 RAM의 최대 크기는 32GB다.
      • 주의사항 : 일래스틱서치의 JVM에 총 메모리 기준 50% 이상을 할당하지 말아야 한다. 아차피 루씬의 파일 시스템 캐시에 충분한 메모리가 필요하기 때문. 궁극적으로 일래스틱서치 노드에 저장되는 데이터를 아파치 루씬 인덱스로 관리.
      • 확장이 필요하다면, 노드를 추가하는 방법을 선택할 것
    • 스와핑 비활성화 : Swapping을 설정하면 OS가 메모리의 내용을 Disk로 옮기는 동작을 하게 됨. 그러므로 동작이 늦어 질 수 있음
    • 파일 디스크립트 : 리눅스 및 맥 OS는 프로세스가 파일을 유지할 수 있는 파일 디스크립터 개수에 제한이 있음. 기본적으로 이 값이 매우 낮기 때문에 변경을 고려해야 한다.
    • 스레드풀 및 가비지 컬렉터 : 색인, 검색, 집계 등 다양한 연산을 할 때 JVM의 Thread Pool을 사용한다. JVM의 Thread Pool 이나 가비지 컬렉터의 설정을 변경하면 일반적으로 악영향을 미치므로, 되도록이면 스레드풀과 가비지 컬렉터 설정을 변경하지 않고 사용하는것이 좋다.
  • 클라우드 환경 사용시 고려사항(대표적으로 AWS)
    • 인스턴스 타입 선택 : 시작하기 적당한 것은 m3.2xlarge(CPU 8core, 30GB RAM, 80GB SSD 2개)
    • 포트(port)를 노출하지 않도록 변경
    • 프록시 요청 : 요청 제어시 엔진엑스 또는 아파치와 같은 리버스 프록시 활용
    • 로컬 주소에 Http 바인딩 : 인스턴스가 VPC 내에 위치 할 것이므로, 클라이언트와 통신할 필요가 없는 노드는 쿼리를 Http를 이용해서 수신.
    • EC2 검색 플러그인 설치 : 같은 네트워크에서 다른 노드를 찾는 방법
    • S3 저장소 플러그인 설치 : 정기적 백업을 위해 저장해 둘 공간
    • 주기적인 스냅숏 저장

인덱스 별칭

  • 원래 만들어 둔 인덱스의 이름을 변경해야 하는 경우, 기존에 배포된 애들이 문제가 될 수가 있다.
  • 이때는 별칭을 생성해서, 기존의 애들은 잘 동작하게 하고, 새로운 이름으로 사용 할 수도 있다.
  • 원본 데이터 이름이 A, B, C 로 3개가 있다고 하면, 별칭은 data라는 이름으로, 원본을 변경해 가면서 작업을 진행할 수도 있을 것이다.

기타

  • 인덱스를 만들고 나면 샤드 갯수를 변경할 수 없음. 처음 만들때 잘 정해야 함.
  • 단일 인덱스에 대규모 데이터를 저장하는것 보다, 시간 기반 인덱스를 여러개 만들어서 보관하는것이 더 편리하다.
    • 1개월씩의 데이터를 각기 다른 인덱스로 만들었을때, 6개월이 지난 데이터를 삭제하는것은, 그냥 6개월이 지난 인덱스를 지우면 되기 때문이다.

10 데이터 분석 애플리케이션 구축

  • 실제 데이터를 가지고 시각화 하는것까지 구축하는 예(생략)

11 서버 인프라 모니터링

  • 매트릭비트 설치 및 운영 방법
  • Mongodb, 시스템메트릭 등에 대한 설명(생략)

기타 정보

실제로 해 보면서 겪었던 문제 정리

  • fielddatatrue로 주게 되면 역색인 정보를 바로 검색해 볼 수 있다.

    • 뉴스에 나오는 용어를 찾기 위해서는 contents의 역색인 정보를 뒤져야 하는데, 이걸 그냥 뒤져 볼 수 있는 방법이 없다.
    • vectorterms 인가 하는 방식을 쓸 수 있는데, 그건 id가 지정된 경우에만 사용할 수 있다.
    • mapping을 생성할때, 에 "fielddata" : true를 주게 되면, 역색인 정보를 바로 검색해서 볼 수 있다.
    • 역색인 정보를 검색하려면 아래와 같이 호출하면 된다.
  • 하지만 fielddatatrue로 주면, 메모리 문제가 부족하다면서 검색이 안되는 경우도 있다.

    • 엘라스틱 서치를 띄울때 메모리를 더 주면 해결 되더라.
    • /etc/elasticsearch/jvm.options 파일에서 -Xms-Xmx 값을 더 늘려 주도록 하자.
    • 내가 설치 했을때는 1g로 되어 있었다. 2g 정도로 주니깐 어느정도는 잘 동작하더라.
  • 20만건 정도의 데이터를 엘라스틱서치에 넣는데는 얼마나 걸릴까?

    • http request의 POST 방식으로 데이터를 하나씩 넣어 보았더니, 668초가 소요되었다.
    • logstash 로 json 파일을, console에 로그를 찍어 가면서 넣어 보았더니, 350초가 소요되었다.
    • logstash 로 json 파일을, console에 로그를 찍지 않고 넣어 보았더니, 70초가 소요되었다.
    • 그러니 나 처럼 무식하게, http POST로 데이터를 밀어 넣지 말고, logstash를 좀 공부하도록 하자.
    • 그리고, console에 log를 찍는것은 생각보다 오랜 시간이 걸린다는것을 알 수 있다. http request POST방식으로 데이터를 넣을때, console에 log를 일일이 출력하면 몇배로 더 늦어진다. 그러니 로그는 필요한 만큼만 찍자.

+ Recent posts