NLP Blog

파이썬 디자인 패턴 - 생성 디자인 패턴 - 팩터리 메서드 패턴

|

1-3. 팩터리 메서드 패턴


  • 팩터리 메서트 패턴은 객체 생성을 요청할 때 하위 클래스가 인스턴스화할 클래스를 지정할 수 있게끔 고안된 패턴
  • 생성하려는 클래스가 어떤 것인지 모를 때도 활용할 수 있다.

  • 특정 게임판을 생성하는 하위 클래스의 바탕이 되는 추상 보드 클래스 생성
  • 게임에 따라 각 말이 자체 클래스를 갖게 하고싶음

게임판을 인스턴스화하고 출력하는 최상위 코드

main코드

  • 이 함수는 프로그램 모든 버전에서 동일. 각 게임판을 생성하고 콘솔에 출력

gameboard1.py

AbstractBoard class

  • ___str___() 메서드를 통해 게임판 내부 표현을 문자열로 변환
  • 게임판은 한 글자로 된 문자열 리스트로 표현
    • 말이없는 칸은 None
    • console() 함수는 배경색 위에 배치할 말이 담긴 문자열을 반환
  • AbstractFormBuilder와 마찬가지로 AbstractBoard 클래스에 abc.ABCMeta 메타클래스를 전달해 추상 클래스를 만들 수 있지만, 본 코드에서는 raise NotImplementedError() 를 사용 (하위 클래스에서 implement하지 않으면 에러 발생)

ChechersBoard class

  • AbstractBoard 를 구현한 concrete class인 CheckersBoard() class 는 10x10 국제 규격 체커판을 생성
  • poppulate_board() 메서드는 하드코딩된 클래스(BlackDraought, WhiteDraught)를 활용하기 때문에 팩터리 메서드가 아니다!
  • 이 메서드를 어떻게 팩터리 메서트로 만들지 보여주기 위해서 첨부

ChessBoard class 1

  • ChessBoard 클래스도 마찬가지로 poppulate_board() 메서드가 어떻게 팩터리 메서드로 바뀌는지 보여주기 위해 첨부

Piece class

  • Piece() 클래스는 말에 대한 기반 클래스
  • str 변수만 사용할 수 도 있지만, 그렇게 하면 어떤 객체가 말인지 판단할 수 없음
  • __slots__=()를 사용해 인스턴스가 어떤 데이터도 가실 수 없도록 보장 (2.6에서 살펴볼 예정)

Piece concrete classes

  • 모든 말 클래스가 공통적으로 활용하는 패턴을 볼 수 있음
    • 각 말은 변경 불가능한 Piece의 하위 클래스(자체가 str의 하위 클래스)
    • 각 말을 표현하는 유니코드 글자가 담긴 1글자짜리 문자열로 초기화
  • 소규모 하위 클래스가 14 개가 있음
  • 중복이 굉장히 많다!

gameboard2.py

create_piece using populate_board

  • 위의 gameboard1.py 의 populate_board() 와 다르게 create_piece() 팩터리 메서드를 활용한다.
  • creae_piece() 함수는 인자에 따라 적절한 타입의 객체(BlackDraoughtWhiteDraught 같은)를 반
  • ChessBoard class에도 똑같이 존재 (색깔과 말 이름을 인자로 전달)

create_piece factory method with eval()

  • 팩터리 메서트는 내장 함수인 eval()을 활용해 클래스 인스턴스를 생성
    • ex) 인자가 “knight”, “black”이면 eval("{}Chess{}")~을 통해 BlackChessKnight()가 됨
    • 하지만 eval()은 위험 (어떤것이든 생성 가능)

code generation in gameboard2.py

  • gameboard1.py 의 소규모 하위 클래스 14개를 단 한 블록의 코드로 클래스를 모두 생성했다.
    • itertools.chain() : 하나 이상의 iterable을 받아 전체를 순회할 수 있는 단일 iterable을 반환
    • 여기서는 두 개의 iterable을 전달
      1. 검은색과 하얀색 체커 말의 유니코드 포인트에 대한 2-튜플
      2. 검은색과 하얀색 체스 말에 대한 range 객체
  • 각 유니코드 포인트에 대해 한 글자로 된 문자열을 생성해 이 문자의 유니코드 명칭에 따라 클래스 이름을 생성 (“black chess knight”는 BlackChessKnight가 된다)
  • exec() 을 사용
    • 너무 위험함

gameboard3.py

gameboard3.py tuple decl gameboard3 CheckersBoard class

  • gameboard2.py 의 populate_board() 메서드와는 다르게, 잘못 입력하기 쉬운 문자열 리터럴 대신 상수 값을 사용해 말과 색깔을 지정한다.
  • 각 말을 생성하기 위해 새로운 creae_piece() 팩터리를 활용

gameboard3.py AbstractBoard class

  • 위는 ChessBoardCheckersBoard가 상속 할 추상 클래스이다
    • 두 클래스는 create_piece()를 상속한다.
      • create_piece()는 ~Board 클래스의 __classForPiece dict를 참조하여 kind, color를 받아 말 이름을 반환한다.\
      • gameboard2.py 와 다르게 exec()이나 eval()을 사용하지 않고 안전하게 동적으로 생성할 수 있다.

gameboard3.py code generate

  • gameboard2.py 와 다르게 eval()이나 exec()을 활용하는 대신 안전한 방법 사용
    • 일단 code에서 글자와 그에 대한 명칭을 가지고 있다면 maek_new_method() 메서드를 호출해 해로운 함수 (new())를 생성
    • 내장함수인 type()을 활용해 새로운 클래스를 생성
      • type()을 이용해 클래스를 생성하려면
        • 클래스 타입
        • 기반 클래스들에 대한 튜플 (Piece 하나만 넘김)
        • 클래스 애트리뷰트에 대한 딕셔너리
      • 방금 생성한 new() 함수를 __new__ 메서드로 설정
    • 현재 모듈(sys.modules[__name__])에 새로 생성한 클래스를 name이라는 애트리뷰트로 추가하기 위해 setattr()를 호출
  • make_new_method()new() 함수를 생성
  • super()는 활용 할 수 없음, 왜냐면 new()가 생성될 시기에는 super()가 접근할 클래스가 아직 없기 때문 ***

    gameboard4.py

gameboard4.py

  • gameboard3.py 에서 setattr() 를 사용한 것과 달리, 전역변수가 저장된 딕셔너리의 참조를 얻어, name에 있는 값이 key이고 새로 생성한 Class가 값인 새 아이템을 추가 -> setattr()와 똑같이 동작
  • new() 메서드 생성의 경우에도, lambda를 활용하여 해결
  • create_piece() 가 gameboard4.py 의 팩터리 메서드이다.
    • 사용되는 상수값은 gameboard3.py 와 같지만, 클래스 객체의 dict 대신 내장 함수인 globals()를 통해 얻은 dict에서 해당 클래스를 동적으로 찾는다.
    • 이렇게 얻은 클래스 객체를 바로 호출해서 원하는 말 인스턴스를 얻는다.

Comment  Read more

Python Design Pattern - Builder Pattern

|

1-2. 빌더 패턴


  • 빌더 패턴은 다른 객체를 조합한 복합 객체 (compled object)를 생성하기 위해 고안됐다는 점에서 추상 팩터리 패턴과 비슷하다.
  • 빌더 패턴은 복합 객체를 구축하는 메서드를 제공할뿐더러 전에 복합 객체 자체의 표현을 보유한다는 점에서 팩터리와 구별된다.
  • 이 패턴은 복합 객체가 하나 또는 여러 개의 더 간단한 객체로부터 만들어진다는 점에서 추상 팩터리 패턴과 동일한 조합 방법을 제공한다.
  • 그러나 이 패턴은 특히 복합 객체의 표현을 조합 알고리즘과 별도로 유지해야 할 때 적합하다.

가장먼저 최상위 코드 highest code

  • 각 폼을 생성한 후 파일에 저장
  • 두 경우 모두 동일한 생성함수 create_login_form() 에 적절한 빌더 객체를 인자로 전달해 호출

create_login_form

  • create_login_form()함수는 임의의 HTML이나 Tkinter 폼을 생성할 수 있다. 또는 알맞은 빌더만 있다면 어떤 종류의 폼이든 생성 가능하다.

HtmlFormBuilder와 TkFormBuilder 모두 추상 기반 클래스인 AbstractFormBuilder를 상속한다.

ABSFormBuilder

  • 이 클래스를 상속하는 클래스는 추상 메서드를 모두 구현해야 한다.
  • 참고로 AbstractFormBuilderabc.ABCMeta 메타클래스를 받아 abs 모듈의 @abstractmethod 데코레이터를 사용한다
  • 어떤 클래스에 abc.ABCMeta의 메타클래스를 전달하면 해달 클래스의 인스턴스를 만들 수 없기 때문에 추상 기반 클래스로만 사용해야 한다.
  • 이는 C++ 나 자바에서 이식된 코드에 유의미하나, 실행 시 약간의 비용이 더 든다.
  • 하지만 대다수의 파이썬 프로그래머는 문제가 될 수 있는 더 안일한 방법을 활용 -> 메타클래스를 활용하지 않고, 해당 클래스를 추상 기반 클래스로 사용해야 한다고 문서화 함

HtmlFormBuilder

  • add_title() 메서드는 추상 메서드 이므로 재구현(reimplement)해야 한다. 그러나 원래의 추상 메서드에도 구현 코드가 있으므로, 그 메서드를 호출해 처리한다 (super.add_title) (escape 는 html module에 있는 메서드)

HtmlFormBuilder.form

  • HtmlFormBuilder.form() 메서드는 HTML페이지를 생성한다.

TkFormBuilder

  • 위 코드는 TkFormBuilder 클래스의 일부다.
  • add_label() 메서드의 구조를 add_entry() , add_button()에도 똑같이 활용한다.
    • 메서드는 먼저 위젯의 정식 명칭을 가져온 다음, 문자열 2개를 만든다. ….

Comment  Read more

파이썬 디자인 패턴 - 생성 디자인 패턴 - 추상 팩터리 패턴

|

1장 파이썬 생성 디자인 패턴

  • 생성 디자인 패턴은 객체를 생성하는 방법에 대한 패턴
    • 보통은 객체를 생성할 때 생성자를 활용
    • 생성 디자인 패턴을 활용하면 객체 생성을 유연하게 할 수 있다

1-1. 추상 팩터리 패턴

  • 여러 객체로 구성된 복합 객체를 만들어야 하는데, 포함된 객체가 모두 틀별한 한 계통 일 때 사용 가능.
  • 예를 들어, Mac, Xfce, Window에서 위젯을 만들어주는 3 개의 concrete subclass factory 가 있는 Abstract widget factory가 있다고하자.
    • 세 구상 팩터리 모두 동일한 객체를 생성하는 메서드를 제공하지만, 각 결과물은 플랫폼에 따라 다른 스타일을 띠어야 한다.
    • 이러한 메서드를 활용하면 팩터리 인스턴스를 인자로 받아 해당 인자에 따라 다른 대화상자를 만드는 제네릭함수를 만들 수 있다.

1.1 고전적인 추상 팩터리


동일부분

  • diagram1.py 와 diagram2.py 의 동일 부분을 보자. 공통적으로 txtDiagram과 svgDiagram을 생성하여 save한다.

create-diagram at diagram1.py

  • 위 함수는 diagram factory 만을 받아 이를 활용해 요청받은 다이어그램을 생
  • 다이어그램 팩터리 인터페이스(make_diagram, make_rectangle, make_text…의 def를 지원)를 지원하는 한 어떤 종류의 팩터리를 인자로 받은 관계 없음

DiagramFactory

  • 패턴 이름에 추상이란 단어가 포함돼 있음에도 한 클래스가 인터페이스를 지원하는 기반 클래스이자 그 자체로 구상 클래스인 경우는 흔히 접할 수 있다. (DiagramFactory 클래스가 기반 클래스이지만, 내부에 모든 def가 구현되어 있음) (추상클래스? 구상클래스? 정리본 )

SvgDiagramFactory

  • DiagramFactory의 make_diagram() 과의 유일한 차이점은 SvgDiagram 객체를 반환한다는 것 뿐이다. 나머지 메서에도 동일하다

  • 각 클래스가 동일한 인터페이스를 제공하긴 하지만 (Diagram과 SvgDiagram 모두 동일한 메서드를 가지고 있음) 일반 텍스트 버전의 Diagram, Rectangle, Text 클래스 구현은 Svg버전의 그것과는 근본적으로 다르다.
  • 이는 서로 다른 계열의 클래스 (즉, Rectangle과 SvgText)를 혼합할 수 없음을 의미, 이것이 팩터리 클래스에 자동적으로 적용되는 제약사항
  • 일반 텍스트 다이어그램 객체는 내부데이터를 공백, +, -, | 로 구성된 한 글자짜리 문자열 리스트로 가지고 있다. 그것들을 지정된 위치에 맞춰 생성한다.

1-1-2. 더 파이썬다운 추상 팩터리


  • 위의 diagram1.py의 구현에는 몇가지 미흡한 점이 있다.

    1. 어느 팩터리는 상태 정보를 가지고 있을 필요가 없으므로, 실제 팩터리 인스턴스를 생성할 필요가 없다.
    2. SvgDiagramFactory 코드는 DiagramFactory 코드와 거의 동일하고, 유일한 차이는 Text 대신 SvgText 인스턴스를 돌려준다는 것 뿐이라 불필요한 중복이 존재한다.
    3. 최상위 네임스페이스에 모든 클래스가 모여있다, 하지만 우리는 단지 두개의 팩터리에만 접근하면 된다. 게다가 이름의 충돌을 피하기위해 Svg클래스 이름에 접두어를 붙여야만 했는데 지저분하다.

  • diagram2.py에서 위의 미흡한 부분을 모두 해결할 예정

    1. Diagram, Rectangle, Text 클래스를 DiagramFactory 클래스의 내부 클래스로 만든다. 이렇게 하면 클래스에 DiagramFactory.Diagram 과 같은 식으로 접근 가능하므로, SvgDiagramFactory내에 Diagram 과 같이 이름을 동일하게 만들 수 있다.(클래스 이름 충돌 x)
    2. 최상위 네임스페이스에는 main(), create_diagram(), DiagramFactory(), SvgDiagramFactory() 만이 남는다.

DiagramFactory classmetho

  • make_...() 메서드는 이제 모두 클래스메서드이다.
    • 이는 이 메서드를 호출할 때 (일반 메서드에 self가 전달되는 것과 달리) 첫 번째 인자로 클래스 정보를 전달한다는 것을 의미
    • 따라서 DiagramFactory.make_text()를 호출하면 DiagramFactory가 Class 값으로 전달되 DiagramFactory.Text 객체가 생성되어 반환된다.
  • 이러한 변화 때문에 DiagramFactory를 상속한 하위 클래스인 SvgDiagramFactory에는 더이상 make_...() 메서드가 필요하지 않다.
    • 예를들어 SvgDiagramFactory.make_rectangle() 호출 -> SvgDiagramFactory에 해당 메서드가 없음 -> 상위(기반) 클래스의 DiagramFactory.make_rectangle 메서드를 대신 호출 -> 이때 Class 값에는 SvgDiagramFactory 가 전달 -> SvgDiagramFactory.Rectangle 객체가 생성되어 반환

  • 나머지 코드는 이전과 거의 동일하다. 핵심적인 변경사항은 이제 상수값과 팩터리가 아닌 클래스들이 모두 팩터리 안에 내장됐으므로 앞으로 이것들을 사용하려면 팩터리 이름을 붙여야 한다는 것이다.

SvgText와 SvgDiagramFactory.Text

  • 위와 같이 변경되었다.

Comment  Read more

룰베이스 챗봇만들기 (ChatScript)

|

Comment  Read more

한고원 데이터사전 Word2Vec README

|

Word2Vec

본 코드들을 실행시키기 위해서는 tensorflow-gpunltk설치가 필요합니다.

word2vec repository 내에는 11개의 코드가 존재합니다. 하지만 몇몇개의 코드는 특정 테스트를 위해 생성 된 것이므로, 이 Readme.md 에서는 6개의 코드에 대해서만 설명합니다.

  • word2vec_saram.py
  • word2vec_saram.sh
  • loadpickle.py
  • loadpickle.sh
  • find_topk_sim.py
  • find_topk_sim.sh

모든 코드는 python file과 shell script가 1:1 매칭되어 있습니다. 실행은 shell script로 실행하면 됩니다.

word2vec_saram.py

이 코드는 word2vec의 skip-gram 을 사용하여 word embedding을 수행하는 파이썬3 코드입니다. 본 코드는 크게 3가지 단계로 구성되어 있습니다.

  • 데이터를 불러 온 후 Mini-batch화
  • skip-gram 을 이용한 word embedding
  • word vector visualization 및 결과 저장

skip gram의 세부 알고리즘에 대해서는 다음 논문 을 참고하시면 되겠습니다.

word2vec_saram.py 코드는 사람인 데이터를 기준으로 생성 된 코드 입니다만, input data 형식만 맞춰주면 어느 데이터를 사용하던 작동 할 수 있습니다. 다른 데이터를 사용하려면 line 82filename 변수를 주성 해 주시면 됩니다.

82 filename = 데이터의 디렉터리 위치

그리고 이 코드는 총 7개의 arguments를 입력 받습니다.

  • --log_dir : tensorboard log file과 visualization결과, 그리고 embedding table, dictionary등이 저장되는 위치 지정
  • --embedding_size : word vector의 차원수 설정
  • --batch_size : mini-batch size 설정
  • --skip_window : 양 옆으로 몇개의 단어를 고려할지 설정
  • --num_skips : 양 옆의 고려한 단어들 중에서 몇개를 정답과 맞추어 볼지 설정 (num_skips =< 2 * skip_window)
  • --num_sampled : 중간 결과를 몇개를 볼 지
  • --num_steps : training을 몇 step 만큼 지정 할 지

위 arguments는 word2vec_saram.sh에서 모두 지정되어 있습니다.

결과 image

absolute

word2vec_saram.sh

실행방법: sh word2vec_saram.sh

스크립트 내의 변수를 조정하여 word2vec 다양하게 실행 가능합니다.

loadpickle.py

word2vec_sarma.py에서 산출된 data.pkl, count.pkl, dictionary.pkl, reverse_dictionary.pkl, embedding.pkl 파일을 보는데 필요한 코드입니다.

이 코드 역시 실행은 loadpickle.sh로 하시면 됩니다.

arguments 목록:

  • --pkl_dir = pickle 파일이 존재하는 directory (보통 word2vec_saram.sh을 실행한 log_dir 위치를 입력)

loadpickle.sh

실행방법: sh loadpickle.sh

find_topk_sim.py

word2vec_saram.py에서 산출 된 embedding.pkl, reverse_dictionary.pkl 파일을 이용하여 corpus에서 가장 많이 등장한 단어들의 가장 가까운 cosine similarity를 가진 단어를 출력해 줍니다.

argument:

  • --pkl_dir : pickle 파일이 존재하는 directory (보통 word2vec_saram.sh을 실행한 log_dir 위치를 입력)

find_topk_sim.sh

실행방법: sh find_topk_sim.sh

visual_wordVec.py

word2vec_saram.py 에서 산출되는 visualization 부분을 떼어낸 코드

주의 : scikit learn 설치 필요합니다. 그리고 한글 폰트부분 에러 날 수 있습니다.

실행은 visual_wordVec.sh로 하면 됩니다.

visual_wordVec.py

스크립트 내에 embedding table, reverse dictionary, 결과 figure 이름(png 형식)을 바꾸어 가면서 실행가능 PLOT_ONLY의 경우 plot 내에 찍어주는 dot의 양 조절 가능

주의 : word2vec_saram.py에서는 visualization을 자동으로 해주지만…. 이 코드를 돌리기 위해서는 doc2vec이든 word2vec이든, 결과 embedding table과 reverse dictionary를 pickle 파일로 따로 저장이 되어있어야 합니다.

find_keyvalue.py

reverse_dictionary.pkl, embedding.pkl을 받아서 사용자가 지정한 단어와 가장 가까운 n개의 단어, cosine similiarity를 찾아주고, 다시 그 가까운 단어들의 가까운 n개의 단어와 cosine similiarity를 찾아서 namedtuple pickle, csv 파일로 저장해준다.

Comment  Read more