Y Tech Blog search

BART 논문 설명(BART - Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension)

|

이 글에서는 Facebook AI에서 발표한 BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension 논문을 간략하게 정리한다.


BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension

논문 링크: BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension

  • 2019년 10월(Arxiv)
  • Mike Lewis, Yinhan Liu, Naman Goyal et al.

Abstract

seq-to-seq 모델을 사전학습시키기 위한 denoising autoencoder인 BART를 제안한다. BART의 학습은

  1. 임의의 noising function으로 텍스트를 변형시킨 것과
  2. 이를 원래대로 복원하도록 모델을 학습시키는 것으로 이루어진다.

BART는 Transformer 기반 표준 NMT 구조를 가지며 BERTGPT 및 많은 사전학습 schemes를 일반화한 모델이라 할 수 있다.
본 논문에서는 많은 noising 기법들을 평가하여 문장의 순서를 임의로 섞는 것과 in-filling scheme(spans of text가 하나의 mask token으로 치환됨)을 사용할 때 가장 성능이 좋음을 발견하였다. BART는 특히 텍스트 생성에 대해 fine-tuned되었을 때 효율적이지만 이해력 테스트에서도 잘 작동한다. GLUE와 SQuAD에서 RoBERTa 이상의 성능을, 6 ROUGE score을 더 높게 얻고 abstractive dialogue, question answering, and summarization tasks에서 SOTA를 달성하는 등 성과가 좋다.

또한 ablation 실험 등을 진행하여 모델의 성능 등을 입증한다.


1. Introduction

Self-supervised 접근법은 NLP task에서 괄목할 만한 성과를 많이 내었다. 가장 성공적인 방법은 MLM 및 그 변형들이었다. 그러나 이러한 방법들은 특정 task에만 집중하여 일반화하기 어려웠다.

본 노문에서는 아주 넓은 범위에 사용할 수 있는, seq-to-seq 모델로 만든 denoising autoencoder인 Bidirectional and Auto-Regressive Transformers, BART를 제안한다. 초록에서 말한 것처럼 BERT, GPT 등의 학습 방법을 일반화한 방식을 사용했음을 아래 그림에서 볼 수 있다.

이 방식의 이점은 noising할 떄 별 제약없이 다양한 function을 사용할 수 있다는 것이다.

(초록과 같은 내용이라 일부 생략)

BART는 fine-tuning에 대해 새로운 방식을 생각할 수 있게 한다. Machine Translation에 대해 새로운 scheme을 제안하는데 BART는 몇 개의 추가적인 transformer layer 위에 놓인다. 이 layer들은 특히 외국어를 noised 영어로 번역하도록 학습되고 이는 BART에 전해지고, 따라서 BART를 pre-trained target-side language model로 사용하게 된다. 이 접근법은 WMT Romanian-English benchmark에서 강력한 back-translation MT baseline을 1.1 BLEU score만큼 앞지른다.


2. Model

BART는 임의로 변형된 문서를 원래대로 되돌리는 denoising autoencoder이다. 구현은 corrupted text에 대한 bidirectional encoder와 left-to-right autoregresisve decoder로 구성된 seq-to-seq 모델로 이루어졌다. 사전학습을 위해서는 원본 문서에 대한 NLL loss를 사용하였다.

2.1 Architecture

표준 seq-to-seq Transformer을 기반으로 하되 OpenAI GPT처럼 ReLU를 GeLU($\mathcal{N}(0, 0.02)$)로 바꿔 사용하였다. base 모델은 6 layer encoder, large 모델은 12개를 사용하였다.

구조는 BERT와 비슷하지만, 차이점은

  1. decoder의 각 layer는 encoder의 final hidden layer와 cross-attention을 수행한다.
  2. BERT는 word-prediction을 위해 추가적인 feedforward net을 사용하지만 BART는 그렇지 않다.

전체적으로 BART는 BERT보다 10% 정도 더 많은 pamameter를 갖는다.

2.2 Pre-training BART

Corrupted document를 원복하는 방식으로 사전학습을 진행하는데 reconstruction loss는 decoder의 출력과 원본 문서 간 cross-entropy를 쓴다.

사전학습에 사용한 방법은 다음 5가지이다.

  1. Token Masking: BERT의 것과 같다.
  2. Token Deletion: token을 [MASK] token으로 바꾸는 대신 아예 없애버리는 것으로 모델은 사라진 위치를 찾아야 한다.
  3. Text Infilling: 그 길이가 $\lambda=3$ poisson 분포를 따르는 여러 개의 text spans를 뽑는다. 각 span은 하나의 [MASK]으로 대체된다. SpanBERT에서 제안된 방식이지만, 다른 점은 SpanBERT에서는 다른 분포에서 샘플링을 하며 정확히 같은 길이의 [MASK] token으로 대체한다. Text infilling은 모델이 span에서 얼마나 많은 token이 사라졌는지 예측해야 한다.
  4. Sentence Permutation: 문서를 여러 부분으로 나누어 임의로 섞는다. 모델은 원래 순서를 맞춰야 한다.
  5. Document Rotation: 특정 지점을 잘라서 문서를 그 지점부터 시작하도록 변형한다. 모델은 원래 시작점을 찾아야 한다.

3. Fine-tuning BART

BART가 생성한 representation은 downstream applications에서 여러 방식으로 사용될 수 있다.

3.1 Sequence Classification Tasks

같은 입력이 encoder와 decoder 모두에 주어지고, final decoder token의 final hidden state는 새로운 multi-class linear classifier에 입력으로 주어진다. 이는 BERT의 CLS token과 연관되어 있지만 BART에서는 이 추가적인 token을 에 추가하여 decoder에서 token의 representation이 decoder states를 처리할 수 있게 했다. (그림 3.a)

3.2 Token Classification Tasks

SQuAD의 answer endpoint classification와 같이 전체 문서를 encoder와 decoder에 주고 decoder의 top hidden state를 각 단어의 representation으로 사용하였다. 이 representation은 token을 분류하는 데 사용된다.

3.3 Sequence Generation Tasks

BART는 autoregressive decoder를 갖고 있으므로 abstractive question answering나 summarization와 같은 생성 task에 바로 적용할 수 있다. 둘 모두 정보를 입력에서 변형된 상태로 복사되며 이는 denoising pre-training objective와 긴밀한 연관이 있다. 여기서 encoder 입력은 input sequence, decoder는 출력을 autoregressive하게 생성한다.

3.4 Machine Translation

BART 모델 전체를 하나의 encoder처럼 생각해서 MT에도 적용할 수 있게 하였다. (그림 3.b)

정확히는, BART의 encoder embedding layer를 랜덤초기화된 새로운 encoder로 교체하였다. 모델은 end-to-end로 학습되며 새로운 encoder가 외국어 단어를 BART아 de-noise할 수 있는 영어 입력으로 mapping하도록 학습된다. 새로운 encoder는 원래 BART 모델와 다른 vocab을 쓸 수 있다.

source encoder는 2단계로 학습하는데 둘 모두에서 BART 모델의 출력의 cross-entropy loss를 backpropagate한다.

  1. BART를 freeze하고 새로운 encoder, BART positional embeddings, BART encoder의 첫 layer의 self-attention input projection matrix만 update한다.
  2. 이후 반복횟수를 조금만 하여 전체를 update한다.

4. Comparing Pre-training Objectives

목적함수 비교, 데이터셋 및 Task 설명이다.

4.1 Comparison Objectives

여러 pre-training objectives를 최대한 동일하고 공정한 환경에 놓고 비교를 진행했다고 한다.

비교대상: Language Model, Permuted Language Model, Masked Language Model, Multitask Masked Language Model, Masked Seq-to-Seq

4.2 Tasks

  • SQuAD: Wikipedia paragraphs을 사용하는 extractive question answering task이다. 정답은 주어진 document context에서 추출된 text spans이다.
  • MNLI: 한 문장이 다른 문장을 수반하는지 아닌지를 판단하는 bitext classifitation task
  • ELI5: long-form abstractive question answering dataset
  • XSum: 매우 추상적인 요약문을 포함하는 news summarization dataset
  • ConvAI2: context와 persona 조건을 갖는 dialogue response generation task
  • CNN/DM: news summarization dataset로 요약은 보통 source sentence와 깊은 연관이 있다.

4.3 Results

task에 따라 편차가 있지만, 전체적으로 봤을 때 BART + text infilling(혹은 여기에 Sentence shuffling까지) 방식이 좋다는 것을 확인하였다.


5. Large-scale Pre-training Experiments

최근 연구들을 보면 모델 크기가 클수록 성능이 좋아진다. BART도 비교 실험을 진행하였고, RoBERTa와 같은 크기로 맞추어 실험하였다.

5.1 Experimental Setup

  • 12 layer encoder/decoder
  • hidden size 1024
  • RoBERTa와 비슷하게 batch size는 8000, 반복수는 50만
  • Documents는 GPT-2와 같이 same byte-pair encoding 사용
  • text infilling과 sentence permutation을 사전학습 scheme으로 사용
  • 학습단계에서 10%를 dropout
  • 학습 데이터로 160GB 분량의 news, books, stories, web text 사용

5.2 Discriminative Tasks

표 2는 BART의 성능을 SQuAD, GLUE task에서 다른 모델과 비교한 결과이다. 전반적으로 RoBERTa와 비슷하다.

5.3 Generation Tasks

생성 task에서도 비교 실험을 진행하였다.

Summarization

  • CNN / DailyMail의 요약은 source sentences들과 비슷한 경향이 있다. Extractive 모델은 특히 이를 잘 다루지만 BART가 더 우세하다.
  • 이에 반해 XSum은 매우 추상적이며 extractive 모델은 여기서 힘을 쓰지 못한다. BART는 점수 수치상 매우 크게 앞선다.

Dialogue

모델은 이전 context와 텍스트로 명시된 persona에 기반해서 응답을 생성해야 하는 task이다.

Abstractive QA

장문의 자유형식 응답 문장을 생성하는 task에서도 기존 모델과 비교한 결과인데 3가지 metric 모두에서 앞서는 결과를 보여준다. 그러나 데이터셋 자체는 challenging한데 answers는 질문에 의해 weakly specified하기 때문이라 한다.

5.4 Translation


6. Qualitative Analysis

표 7에서 BART의 결과를 볼 수 있다.

  • WikiNews 기사에서 가져온 예시들로 모델의 학습 데이터에 있을 가능성을 제거한 상태이다.
  • 첫 문장은 대체로 기사를 요약하는 내용이므로 이를 빼고 진행하였다.
  • 모델의 출력은 꽤 유창하고 문법적으로 별 문제가 없다. 그러나 상당히 추상적이며 일부 구절은 그대로 가져온 부분이 있다.
  • 조금 부족하기는 하나 BART의 사전학습 방식이 자연어 이해와 생성을 꽤 잘 한다는 결과라 볼 수 있다고 저자들은 주장하고 있다.

  • Transformer, ELMo, OpenAI GPT, BERT
  • UniLM은 BERT를 mask의 ensemble로 fine-tune한 것으로 일부는 오직 왼쪽방향 context만 허용되었다. BART와 같이, UniLM은 generative task와 discriminative task 모두에 사용될 수 있다. 차이점은 UniLM의 예측은 조건부 독립이지만 BART는 autoregressive하게 진행된다.
  • MASS는 아마도 BART와 가장 비슷한 모델이다. 연속된 span of token이 maked되고 이를 추론하는 사전학습 방식으로 진행되지만 token들이 전혀 겹치지 않게 encoder와 decoder에 들어가 discriminative task에 약하다.
  • XL-Net은 순서가 섞인 masked token을 auto-regressive하게 예측하는 방식으로 BERT를 확장했다. 이는 왼쪽과 오른쪽 context를 모두 고려할 수 있게 한다. 이에 반해 BART의 decoder는 왼쪽에서 오른쪽 방향만 사전학습 단계에서 고려한다.

8. Conclusions

Corrupted documents를 원래대로 복원하는 사전학습 방식을 가진 BART를 제안하였다. Discriminative task에서 RoBERTa와 비슷한 성능을 보이면서도 text generation task에서는 SOTA를 달성하였다. 추후 연구에서는 또 새로운 사전학습 방식을 탐구할 예정이라 한다.


Comment  Read more

Python 프로젝트 생성하기

|

이번 글에서는 새로운 파이썬 프로젝트를 진행하기 위한 환경을 쉽고 빠르게 구축하는 방법에 대해 서술해보겠습니다.
본 글은 윈도우를 기준으로 설명합니다.


Python 프로젝트 생성하기

1. Poetry 설명

poetry는 의존성 관리와 빌드를 책임지는 라이브러리입니다.

poetry를 설치한 후, 아래 명령어를 입력합니다.

# 새로운 프로젝트를 만들 경우
poetry new my-project

# 기존 프로젝트를 활용할 경우
poetry init

이제 pyproject.toml 파일이 생성되었을 것입니다.

새로 가상 환경을 만든다고 할 때, 프로젝트의 root directory 아래에 virtualenv 가 있는 것이 편합니다. 만약 새로 만드는 것이 싫다면 아래와 같이 설정합니다.

poetry config virtualenvs.create false # 기본 값은 true

이 링크를 참조하셔도 좋습니다.

프로젝트 내부에 .venv 폴더를 생성하는 옵션은 아래와 같습니다.

poetry config virtualenvs.in-project true # 기본 값은 None

의존성은 위 파일의 [tool.poetry.dependencies][tool.poetry.dev-dependencies]에서 관리하고 있습니다. add 서브 커맨드를 통해 의존성을 추가할 수 있습니다.

poetry add numpy

이 때 poetry.lock 파일이 생성됩니다.

다음 명령어를 실행하면 전체적으로 업데이트가 가능합니다.

poetry update

현재 프로젝트의 pyproject.toml 파일을 읽어 의존성 패키지를 실행하고 싶을 때는 아래 명령어를 실행합니다.

poetry install

설치된 패키지 목록은 show를 통해 알아 볼 수 있습니다.

# 설치된 모든 패키지
poetry show

# 개발환경용은 제외
poetry show --no-dev

# 세부 내용
poetry show django

# 최신 버전
poetry show --latest (-l)

# 업데이트가 필요한 패키지
poetry show --outdate (-o)

# 의존성 트리
poetry show --tree

가상 환경에 대한 정보는 아래 명령어로 확인할 수 있습니다.

# 가상 환경 정보 확인
poetry env info

# 가상환경 리스트 확인
poetry env list

2. Github Action 설명

Github Action은 github에서 제공하는 CI/CD 도구이며, 소프트웨어 개발의 workflow를 자동화해줍니다.

Github Action에는 반드시 알아야 할 개념들이 있습니다. 이 문서를 확인하는 것이 가장 정확합니다.

가장 기본적인 설명은 이러합니다.

PR 생성과 같이 repository에 특정 event가 발생하면 트리거되는 Github Action workflow를 구성할 수 있습니다. workflow는 순차적 혹은 병렬적으로 동작하는 1개 이상의 job을 갖고 있습니다. 각각의 job은 할당된 가상 머신 runner 내부 혹은 container 내부에서 동작하며 action 혹은 script를 실행하도록 되어 있습니다.

workflow

  • 1개 이상의 job을 실행시키는 자동화된 프로세스
  • yaml 파일로 정의함
  • repository 내에 .github/workflows 디렉토리 안에서 정의됨
  • 하나의 repository는 복수의 workflow를 정의할 수 있음

events

  • workflow run을 트리거하는 특정 행동

jobs

  • 동일한 runner 내에서 실행되는 여러 step
  • 각 step은 shell script이거나 동작할 action

action

  • workflow의 가장 작은 블록
  • 재사용이 가능한 component

runner

  • github action runner 어플리케이션이 설치된 머신
  • workflow가 실행될 인스턴스

action 개념에 대해 추가 설명이 필요하다면 이 블로그를 참고하셔도 좋겠습니다.

이제 실제로 workflow를 작성해 보겠습니다. 앞서 소개한 여기를 참고해주세요. workflow 구문에 대해 자세히 알고 싶다면 여기를 참고하면 됩니다.

workflow는 yaml 파일에 기반하여 구성됩니다. name은 workflow의 이름을 의미하며, 이 name이 repository의 action 페이지에 표시될 것입니다. on은 workflow가 작동하도록 트리거하는 event를 정의합니다. 대표적으로 push, pull_request 등을 생각해 볼 수 있을 텐데, 모든 조건에 대해 알고 싶다면 여기를 확인해 주세요.

특정 event의 경우 filter가 필요한 경우가 있습니다. 예를 들어 push가 어떤 branch에 발생했는지에 따라 트리거하고 싶을 수도 있고 아닐 수도 있습니다. 공식 문서의 설명은 여기에 있습니다.

지금까지 설명한 내용의 예시는 아래와 같습니다.

name: CI

on:
  pull_request:
    branches: [main]

이제 job을 정의해 보겠습니다. 복수의 job을 정의할 경우 기본적으로 병렬 동작하게 됩니다. 따라서 순차적으로 실행되길 원한다면 반드시 jobs.<job_id>.needs 키워드를 통해 의존 관계를 정의해야 합니다. 각 jobruns-on으로 명시된 runner environment에서 실행됩니다. environment에 대해서는 여기를 확인하면 됩니다.

아래 예시에서 my_first_job과 my_second_job이 job_id에 해당한다는 점을 알아두세요. My first job과 My second job은 jobs.<job_id>.name (name) 이며 github UI에 표시됩니다.

jobs:
  my_first_job:
    name: My first job
  my_second_job:
    name: My second job

needs를 통해 반드시 이전 job이 성공적으로 끝나야만 다음 job이 실행되도록 정의할 수 있습니다. 물론 조건을 추가해서 꼭 성공하지 않더라도 실행되도록 작성할 수도 있습니다.

jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]

앞서 job 내에는 연속된 task로 구성된 steps가 존재한다고 설명했습니다. jobs.<job_id>.steps는 명령어를 실행하거나 setup task를 수행하거나 특정한 action을 실행할 수 있습니다.

steps 아래에 if 조건을 추가하게 되면 반드시 이전의 조건이 만족되어야 연속적으로 실행되도록 만들 수 있습니다. context를 이용한다면 아래 예시를 보면 됩니다.

steps:
 - name: My first step
   if: $
   run: echo This event is a pull request that had an assignee removed.

status check function을 이용해 보겠습니다. My backup step이라는 task는 오직 이전 task가 실패해야만 실행될 것입니다.

steps:
  - name: My first step
    uses: octo-org/action-name@main
  - name: My backup step
    if: $
    uses: actions/heroku@1.0.0

steps의 구성 요소를 좀 더 살펴보겠습니다. jobs.<job_id>.steps[*].name은 github UI에 표시될 name을 의미합니다.

jobs.<job_id>.steps[*].uses는 어떠한 action을 실행할지를 의미합니다. 이는 같은 repository나 public repository 혹은 published docker container image에서 정의될 수 있습니다.

다양한 예시가 존재합니다. versioned action, public action, public action in a subdirectory, same repository 내의 action 및 docker hub action 등을 이용할 수 있습니다. 이에 대한 공식 문서 설명은 여기를 확인해 주세요.

여러 action 중 가장 많이 사용되는 action은 checkout인데, repository로부터 코드를 다운로드 받기 위해 사용됩니다. 이 checkout을 github action의 입장에서 바라보면 github의 repository에 올려 둔 코드를 CI 서버로 내려받은 후 특정 branch로 전환하는 작업으로 이해할 수 있다고 합니다. (참고 블로그 인용) 실제로 이 action을 직접 수행하려면 번거로운 작업들이 선행되어야 하지만, github action은 이를 편하게 묶어서 action으로 제공하고 있습니다.

workflow yaml 파일에서 steps.uses 키워드에 사용하고자 하는 action의 위치를 {소유자}/{저장소명}@참조자 형태로 명시해야 한다고 합니다. 예시는 아래와 같습니다.

steps:
  - name: Checkout
      uses: actions/checkout@v3

내부적으로는 git init/config/fetch/checkout/log 등의 명령어를 수행한다고 합니다. 가장 최신 버전의 checkout action에 대해서는 이 repository에서 확인할 수 있습니다.

python으로 개발을 하는 사용자라면 파이썬을 설치하는 setup-python 또한 자주 사용하게 될 것입니다. repo는 여기입니다. 이 action을 통해 CI 서버에 python을 설치할 수 있으며 특정 버전이 필요할 경우 아래와 같이 작성하면 됩니다.

steps:
    - name: Set up Python
        uses: actions/setup-python@v3
        with:
            python-version: 3.9

jobs.<job_id>.steps[*].run은 운영체제의 shell을 이용하여 command-line 프로그램을 실행시킨다. 아래와 같이 single-line command를 입력할 수도 있고,

- name: Install Dependencies
  run: npm install

multi-line command로 입력할 수도 있습니다.

- name: Clean install dependencies and build
  run: |
    npm ci
    npm run build

예시는 여기를 참고해 주세요. 파이썬 스크립트 예시 하나는 기록해 둡니다.

steps:
  - name: Display the path
    run: |
      import os
      print(os.environ['PATH'])
    shell: python

jobs.<job_id>.steps[*].with는 action에 의해 정의된 input 파라미터들의 map을 의밓바니다. 각 input 파라미터는 key/valu 쌍으로 이루어져있으며, input 파라미터들은 환경 변수들의 집합에 해당합니다.

그 외에도 steps 아래에는 args, entrypoint, env 등 여러 속성을 정의할 수 있습니다.


3. 정리

이번 chapter에서는 위 내용과 더불어 publishing까지 전체 flow 진행에 대해 알아보겠습니다.

pycharm을 이용한다면 다음과 같이 처음부터 poetry를 이용해서 편리하게 프로젝트를 시작할 수 있습니다.

이전에 init 을 통해 생성되었던 poetry.lockpyproject.toml 파일이 생성되었을 것입니다.

사용하는 library 들을 poetry add {library} 를 통해 추가해줍니다.

이제 github action을 이용하여 CI/CD 환경을 구축해줄 차례입니다. 아래와 같이 .github 디렉토리 아래에 2개의 yaml 파일을 생성해 줍니다.

먼저 CI 부분부터 살펴보겠습니다. 아래는 ci.yaml 파일의 예시입니다.

name: CI

on:
  pull_request:
    branches: [main]

jobs:
  ci-test:
    name: ci-test
    runs-on: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v3
        with:
          python-version: 3.9
      - name: Install dev-dependencies
        run: pip3 install -r requirements-dev.txt
      - name: Lint
        run: make check

조건은 간단합니다. main branch에 PR이 생성되었을 경우 make check 명령문을 실행하게 됩니다. 이 부분은 아래와 같이 작성하였습니다.
(pylint, isort, black 모두 poetry add를 통해 의존성 추가를 해주어야 합니다.)

.PHONY: init format check requirements

init:
		pip install poetry
		poetry install

format:
		isort --profile black -l 119 {library} lint.py
		black -S -l 119 {library} lint.py

check:
		isort --check-only --profile black -l 119 {library}
		black -S -l 119 --check {library}

requirements:
		poetry export -f requirements.txt -o requirements.txt --without-hashes
		poetry export --dev -f requirements.txt -o requirements-dev.txt --without-hashes

참고로 Windows 환경에서 Makefile을 작성하기 위한 방법은 이 곳에 잘 설명되어 있습니다.

위 파일 작성을 마쳤다면, PR을 생성하기 이전에 코드 정리가 잘 되어 있는지, requirements 파일은 생성했는지 확인해 주면 됩니다.

PR이 closed 되었을 때, CD 구조가 진행되도록 해보겠습니다. 아래는 publish.yaml 파일의 예시입니다.

name: PUBLISH LIBRARY

on:
  pull_request:
    branches: [main]
    types: [closed]

jobs:
  build:
    name: build-library
    runs-on: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v3
        with:
          python-version: 3.9
      - name: Install requirements
        run: pip3 install poetry
      - name: Bump version
        run: poetry version patch
      - name: Publish library
        env:
          PYPI_TOKEN: $
        run: |
          poetry build
          poetry publish --username $ --password $  

Install requirements 까지는 추가적인 설명이 필요하지 않아 보입니다.

Bump version은 패키징하고자 하는 library의 version을 자동적으로 upgrade하는 부분입니다. library를 0.1.0에서 0.1.1로 올릴지, 0.2.0으로 올릴지, 1.0.0으로 올릴지 선택할 수 있습니다.
이 곳을 참고하면 자세한 정보를 확인할 수 있습니다.

다음은 여러 token을 읽고 build -> publish까지 이어지는 부분입니다. 일단 secrets가 무엇인지부터 확인해 보겠습니다. github repository의 Actions Secrets은 환경 변수를 암호화해서 저장할 수 있는 기능입니다. Settings-Security-Secrets를 통해 접근할 수 있습니다.

PYPI 홈페이지에서 본인의 repository에서 사용할 token을 추가해줍니다. 그리고 생성한 값을 복사한 뒤, PYPI_TOKEN secrets에 저장해줍니다. 마찬가지로 PYPI_USERNAMEPYPI_PASSWORD도 추가해줍니다.

이렇게 추가된 token들은 인증과정에 사용됩니다.

이제 CI/CD 구축은 끝났습니다. library 코드를 정리하고, PR 과정을 정상적으로 거치면 프로젝트 생성부터 패키징, 배포까지 편리하게 진행할 수 있습니다.

References

Comment  Read more

Resnet 계열 image classification 모델 설명

|

이번 글에서는 Resnet을 기반으로 한 여러 image classification 네트워크 들에 대해 정리해보겠습니다.

그 대상은 아래와 같습니다.

본 글에서는 핵심적인 부분에 대해서만 살펴보겠습니다.


ResNeXt 설명

ResNext에서는 cardinality라고 하는 개념이 등장합니다. transformation 작업의 크기 혹은 종류라고 생각하면 되는데, 이 hyper-parameter만 잘 조절해도 depth나 channel을 크게 증가시키지 않으면서도 성능 향상을 이끌어 낸다고 합니다.

왼쪽은 ResNet에 등장했던 bottleneck layer의 구조입니다. 오른쪽은 ResNeXt에서 제안된 구조인데, cardinality를 32개로 설정, 즉 path를 32개로 만든 뒤, 이를 average 하여 병합하는 것을 알 수 있습니다. shortcut 구조는 동일합니다.

ResNet-50과 ResNeXt-50 with 32x4d 구조를 보면, parameter 수나 FLOPs의 경우 유사함을 알 수 있습니다.

실제로 같은 연산이지만 표현 방식은 아래와 같이 다양합니다.


ResNeSt 설명

1. 핵심 내용

feature map attention과 multi-path representation이 visual recognition에서 중요하다는 사실은 잘 알려진 사실입니다. ResNeXt에서는 다른 network branch에 대하여 channel-wise attention을 적용함으로써 cross-feature interaction을 포착하고 다양한 representation을 학습하는 데에 있어 효과적인 방법론을 제시합니다.

위에서 소개하였던 ResNeXt에서 cardinality (K) hyperparameter를 이야기 하였는데요, 이 값은 곧 featuremap group의 수를 의미합니다. 본 논문에서는 이 featuremap groupcardinal group이라고 부릅니다. 그리고 이 cardinal group을 또 나눈 (split) 수를 의미하는 $R$ = radix hyper-parameter 라는 개념을 추가합니다. 즉 모든 feature group의 수는 아래와 같이 표현할 수 있습니다.

[G = K R]

  • $G$ = feature group 총 수
  • $K$ = # cardinality
  • $R$ = # splits within cardinal group

즉, input feature의 채널이 $C$ 개 있다고 할 때 이를 $K$ 개의 cardinality group으로 나누고, 이를 다시 $R$ 개로 split 하는 것입니다.

$k$ 번째 cardinality group의 representation은 아래와 같이 표현됩니다.

[\hat{U}^k = \Sigma_{j = R(k-1) + 1}^{RK} U_j]

[k \in 1, 2, .,,, K]

[\hat{U}^k \in \mathbb{R}^{H, W, C/K}]

k=1 일 때, j=1~R
k=2 일 때, j=R+1 ~ 2R 이 됩니다.

위 그림의 split-attention 과정까지 합쳐서 shape이 변화하는 과정을 나타내면 아래와 같습니다.

이렇게 구해진 $s_c^k$ 는 일종의 attention score의 역할을 수행하게 되고, 최종적으로 cardinal group representation의 가중 결합은 channel-wise soft attention을 통해 이루어지게 됩니다.

[V_c^k = \Sigma_{i=1}^R a_i^k(c) U_{R(k-1)} + i]

지금까지 설명한 것은 사실 cardinality-major 구현 방식인데, 실제로 이 방식으로 표준 CNN을 구성하는 것은 기술적으로 어렵습니다. 따라서 실제 코드로 구현해서 사용할 때는 radix-major 구현 방식을 이용한다고 합니다.

자세한 학습 방식과 실험 결과는 논문을 참조하길 바랍니다. 몇 가지만 메모를 하자면,

  • 네트워크의 마지막 2단계에서 DropBlock layer를 사용했습니다.
  • conv, fc layer에만 weight decay를 적용하였습니다.
  • 본 네트워크는 ResNet-D에 기반하였는데, 몇 가지 layer 구성 방식이 다릅니다. 자세한 사항은 논문 5페이지를 참조하면 됩니다.
  • auto augmentation, mixup, large crop 등의 기법을 통해 성능을 향상시켰습니다.

Res2Net 설명


ReXNet 설명

Comment  Read more

STAR benchmark 논문 설명(STAR - A Benchmark for Situated Reasoning in Real-World Videos)

|

이 글에서는 MIT 등 연구자들이 STAR benchmark 논문을 간략하게 정리한다.


STAR: A Benchmark for Situated Reasoning in Real-World Videos

논문 링크: STAR: A Benchmark for Situated Reasoning in Real-World Videos

Repo: http://star.csail.mit.edu/#repo Github: https://github.com/csbobby/STAR_Benchmark

  • NIPS 2021
  • Bo Wu(MIT-IBM) et al.

Abstract

  • 주변의 상황으로부터 지식을 얻고 그에 따라 추론하는 것은 매우 중요하고 또한 도전적인 과제이다.
  • 이 논문에서는 실세계 영상에 대해 situation abstraction, logic-graounded 질답을 통해 situated 추론 능력을 평가하는 새로운 benchmark를 제시한다.
  • STAR(Situated Reasoning in Real-World Videos)
    • 이는 사람의 행동, 상호작용 등과 연관된 실세계 영상에 기반하여 만들어진 것으로 naturally dynamic, compositional, logical한 특성을 가진다.
    • 4가지 형태의 질문(interaction, sequence, prediction, and feasibility)을 포함한다.
    • 이 실세계 영상의 situations은 추출한 단위 entity와 relation을 연결한 hyper-graph로 구성된다.
    • 질문과 답변은 절차적으로 생성되었다.
  • 여러 영상 추론 모델을 이 데이터셋에 적용하여 보았을 때 상황 추론 task에서 어려움을 겪는 것을 발견하였다.
  • Diagnostic neuro-symbolic 모델을 제시하며, 이 benchmark의 challenge를 이해하기 위한 이 모델은 visual perception, situation abstraction, language understanding, and functional reasoning을 disentable할 수 있다.

1. Introduction

그림 1과 같은 (실세계) 상황에서 우리(사람)는 어떻게 행동할지, 현실적인 결정응 무의식적으로 내릴 수 있다. 그러나 기계한테는 주어진 문맥과 상황을 모두 고려하여 결정을 내린다는 것은 꽤 어려운 문제이다.

  • 상황을 formulae의 집합으로 두고 가능한 logic 규칙을 만들어 이해하려는 시도가 있었으나 모든 가능한 logic rule을 만드는 것은 불가능하며 현실성이 떨어진다.

현존하는 비디오 이해 모델들을 도전적인 task에서 테스트한 결과 성능이 매우 낮아짐을 확인하였다. 이 모델들은 추론 자체보다는 시각적인 내용과 질답 간 연관성을 leverage하는 데에 집중하고 있었다.

이 논문에서는 STAR benchmark를 제안한다.

  • 4종류의 질문을 포함한다: interaction question, sequence question, prediction question, and feasibility question.
    • 각 질문은 다양한 장면과 장소에서 얻어진 action-centered situation과 연관되어 있으며 각 situation은 여러 action과 연관되어 있다.
  • 현존하는 지식과 상황에 따라 유동적으로 변화하는 지식을 표현하기 위해 entity와 relation으로 구조화된 표현으로 추상화하였다(situation hypergraphs).
  • 시각적 추론 능력에 집중하기 위해 (자연어) 질문은 간결한 형태의 template에 맞춰 생성되었다.
  • 보조 용도로, (더욱 어려운) 사람이 만든 질문을 포함하는 STAR-Humans도 같이 제공한다.
  • 다른 데이터셋과 비교한 결과는 Table 1에 있다.

또한, Neuro-Symbolic Situated Reasoning (NS-SR)라는, 실세계 situated 추론을 위한 neural-symbolic 구조를 갖는 diagnostic model을 제안한다. 이는 질문에 답변하기 위해 구조화된 situation graph와 situation으로부터 얻은 dynamic clues를 활용한다.

이 논문이 기여한 바는,

  • interaction, sequence, prediction, and feasibility questions에 집중하여, 실세계 영상에서 situated reasoning 문제를 형식화했다.
  • situated reasoning을 위해 잘 설계된 benchmark인 STAR을 구성하였다.
    • 3가지 측면(visual perception, situation abstraction and logic reasoning)에서 annotation이 설계되었다.
    • 각 영상은 siatuatino hyper-graph로 grounded되어 있으며 각 질문은 functional program으로 연관되어 있다.
  • 여러 SOTA 방법을 STAR로 테스트해 보았고 사람에게는 자명한 상황에서 모델은 실수가 많음을 보였다.
  • Diagnostic neuro-symbolic framework을 설계하였고 더욱 강력한 추론 모델을 위한 연구 방향을 제시하였다.

  • Visual Question Answering
  • Visual Reasoning

모델의 추론 능력을 진단하기 위한 여러 데이터셋이 있다: CLEVR, GQA, MarioQA, COG, CATER, CLEVRER, etc.

  • Situation Formalism

3. Situated Reasoning Benchmark

situations abstraction과 logical reasoning을 결합하였고, 아래 3가지 가이드라인을 따라 benchmark를 구축했다.

  1. 추상화를 위한 bottom-up anotations에 기반한 계층적 graph로 표현되는 situations
  2. situated reasoning을 위한 질문과 선택지 생성은 정형화된 질문, functional programs, 공통 situation data types에 grouded됨
  3. situated reasoning이 situation graphs에 대해 반복적으로 수행할 수 있음
  • 60K개의 situated reasoning 질의
  • 240K개의 선택지
  • 22K개의 trimmed situation video clip으로 구성된다.
  • 144K개의 situation hypergraph(structured situation abstraction)
  • 111 action predicates
  • 28 objects
  • 24 relationships
  • train/val/test = 6:1:1
  • 더 자세한 내용은 부록 2, 3 참조

3.1. Situation Abstraction

Situations

Situation은 핵심 컨셉으로 entity, event, moment, environment를 기술한다.

Situation Hypergraph

3.2. Questions and Answers Designing

Question Generation

Answer Generation

Distractor Generation

Debiasing and Balancing Strategies

Grammar Correctness and Correlation

Rationality and Consistency


4. Baseline Evaluation

4.1. Comparison Analysis


5. Diagnostic Model Evaluation

5.1. Model Design

Video Parser

Transformers-based Action Transition Model

Language Parser

Program Executor

5.2. Result Analysis

Situation Abstraction Visual Perception Language Understanding Without Ground-Truths


6. Conclusion

한정된 자원을 갖고 있는 상황에서 Depth, Width, Resolution을 어떻게 적절히 조절하여 모델의 크기와 연산량을 줄이면서도 성능은 높일 수 있는지에 대한 연구를 훌륭하게 수행하였다.


Comment  Read more

Python glob, os, platform, shutil 사용법(Python os 다루기)

|

이 글에서는 Python 라이브러리인 os와 platform에 대해 알아본다. 가끔 쓰는데 막상 쓰려면 언제 봐도 헷갈리는 라이브러리 중 하나인 듯 하다.


Import

import glob
import os
import platform

glob

특정 경로에 존재하는 파일 or 디렉토리의 리스트를 불러온다.

현재 디렉토리의 구조가 다음과 같다고 하자.

current
├── .gitignore
├── readme.md
├── data
|   ├── 1.jpg
|   ├── 2.jpg
|   ├── 3.png
|   ├── 4.png
├── model
|   ├── faster_rcnn_r50_1.pth
|   ├── faster_rcnn_r50_2.pth

아주 중요한 문자가 있다.

  • *: 임의의 문자열과 매치된다.
  • /: 특정 디렉토리를 경로로 지정할 때 사용한다.
  • **: 재귀적으로 디렉토리 전체를 탐색할 때 사용한다.
  • ?: 하나의 임의의 문자와 매치된다.
  • []: 대괄호 내의 문자들 중 하나와 매치된다.

자세한 설명은 정규표현식을 살펴보면 된다.

사용법은 아래 예시를 보면 쉽게 알 수 있다.

glob.glob

print(glob.glob('data/*.jpg')
# ['data/1.jpg', 'data/2.jpg']
print(glob.glob('./data/*.jpg')
# ['./data/1.jpg', './data/2.jpg']

glob.glob('./[0-9].*')처럼 사용할 수도 있다. 파일 이름이 숫자 한개인 파일들과 매치된다.

glob으로 가져오는 경로는 사용자가 지정한 디렉토리 경로 전체도 같이 가져오므로 “파일명”만 갖고 싶을 때에는 .split() 함수 등으로 쪼개서 가져와야 한다.
윈도우에서는 / 대신 \\\로 표시될 수 있다.

glob.iglob

glob.glob 함수와 거의 동일한데 리스트가 아닌 반복가능한(iterable) 형태로만 나온다. 파일이 매우 많다면 이쪽을 쓰는 것이 메모리 등에서 좋다.

for filename in glob.glob('data/*.png'):
    print(filename)
    
# data/3.png
# data/4.png

glob.glob(‘*/.jpg’, recursive=True)

glob은 기본적으로 특정 디렉토리 하나의 파일만을 탐색한다. 그래서 재귀적으로 디렉토리 내부에 존재하는 모든 디렉토리들을 포함해서 탐색하고 싶으면 ** 문자와 recursive 옵션을 써야 한다.

for filename in glob.glob('**/*', recursive=True):
    print(filename)

# data
# model
# readme.md
# data/1.jpg
# data/2.jpg
# data/3.png
# data/4.png
# model/faster_rcnn_r50_1.pth
# model/faster_rcnn_r50_2.pth

특정 확장자만 모든 디렉토리 내에서 찾고 싶다면 glob.glob('**/*.png', recursive=True)와 같이 쓰면 된다.

glob.escape

모든 특수 문자(?, * [)를 이스케이프 처리한다. glob과 비슷하지만 특수문자가 들어있는 파일명을 처리하고 싶을 때 사용한다.


os

working directory

os.getcwd()

현재 working directory 경로를 반환한다.

print(os.getcwd())

# result
'C:\\Users\\gorio\\Documents\\current'

os.chdir()

working directory를 변경한다.

os.chdir('./data)'

파일 탐색

os.walk(path)

파일이나 디렉토리의 목록을 iterable 형태로 얼을 수 있다.

# 현재 디렉토리 안에 있는 모든 파일 탐색
for curDir, dirs, files in os.walk('.'):
     for f in files:
        print(os.path.join(curDir, f))


# result
./.gitignore
./readme.md
./data/1.jpg
./data/2.jpg
./data/3.png
./data/4.png
./model/faster_rcnn_r50_1.pth
./model/faster_rcnn_r50_2.pth

os.listdir()

지정한 디렉토리의 하위 파일 및 디렉토리만 반환한다. 디렉토리 내부의 파일은 탐색하지 않는다.

os.listdir('.')

# result
['.gitignore', 'data', 'model', 'readme.md']

os.path

파일이나 디렉토리의 존재를 확인하거나 경로를 얻거나, 경로와 파일명을 결합하는 등의 함수를 포함한다.

os.path.isfile('readme.md')
os.path.split('./data/1.jpg')
os.path.splitext('./data/1.jpg')
# result
True
('./data', '1.jpg')
('./data/1', '.jpg')
함수명 설명
basename(path) path에서 앞의 디렉토리 경로는 다 떼고 파일명만 반환
dirname(path) path에서 파일명은 떼고 디렉토리 경로만 반환
isdir(path) 주어진 경로가 디렉토리이면 True를 반환
isfile(path) 주어진 경로가 파일이면 True를 반환
split(path) 주어진 경로를 디렉토리 경로와 파일명으로 분리한 tuple 반환
splitext(path) 주어진 경로를 확장자와 나머지로 분리한 (경로, 확장자) tuple 반환

shutil

shutil.copy(src, dst, *, follow_symlinks=True)

src 경로의 파일을 dst 경로로 복사한다. dst가 디렉토리 경로이면 해당 디렉토리에 파일을 복사하고, 파일명까지 포함되어 있으면 해당 파일명으로 변경하며 복사한다.

shutil.copy('1.jpg', 'data/')

참고로,

  • follow_symlinks가 False이고 src가 심볼릭 링크이면, dst는 심볼릭 링크로 만들어진다.
  • follow_symlinks가 True이고 src가 심볼릭 링크이면, dstsrc가 참조하는 파일의 사본으로 만들어진다.

shutil.copy2(src, dst, *, follow_symlinks=True)

파일 메타 데이터를 보존한다는 것을 빼면 shutil.copy와 동일하다.

shutil.copyfile(src, dst, *, follow_symlinks=True)

dst는 디렉토리로 지정할 수 없다. 이외에는 사실상 동일하다.

shutil.move(src, dst, copy_function=copy2)

파일이나 디렉토리를 (재귀적으로) 이동시킨다.

shutil.copytree

shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False)

특정 경로 하위에 있는 모든 파일와 디렉토리를 원하는 위치에 복사할 수 있다.

from distutils.dir_util import copy_tree
copy_tree("./test1", "./test2")

shutil.rmtree(path, ignore_errors=False, onerror=None)

전체 디렉토리 tree를 삭제한다.

실질적으로 잘 안쓰지만 이런 함수들도 있다.

  • shutil.copymode: src의 권한 bit를 dst로 복사한다. linux에서 w,r 등의 옵션을 가리킨다.
  • shutil.copystat: 권한 bit, 마지막 액세스 시간, 마지막 수정 시간 및 flag를 복사한다.
  • shutil.disk_usage(path): 지정한 경로의 디스크 사용량 통계를 (total, used, free) attribute를 갖는 named tuple로 반환한다.

platform

시스템 정보를 확인하는 모듈이다.

기본적으로 값을 판별할 수 없으면 빈 문자열을 반환한다.

platform.system()

현재 구동되고 있는 OS(Operating System)의 종류를 알려준다.

platform.system()

# result
'Windows'

기타 플랫폼 관련 함수

platform.node()

네트워크 이름 또는 사용자명을 반환한다.

platform.node()

# result
'gorio'

platform.release()

릴리즈 번호를 반환한다.

platform.release()

# result
'10'

platform.machine()

기계 유형을 반환한다. 어디선가 본 듯한 amd64, i386 등이 반환된다.

platform.machine()

# result
'AMD64'

python 버전 관련

예시만 보면 바로 사용법을 알 수 있다.

>>> platform.python_implementation()
'CPython'
>>> platform.python_version()
'3.9.10'
>>> platform.python_version_tuple()
('3', '9', '10')

>>> platform.python_build()
('tags/v3.9.10:f2f3f53', 'Jan 17 2022 15:14:21')
>>> platform.python_compiler()
'MSC v.1929 64 bit (AMD64)'
>>> platform.python_branch()
'tags/v3.9.10'

References

Comment  Read more