728x90
  1. Ubuntu 서버에 SSH로 접속하기
  2. X11 포워딩 설정
  3. Docker에서 GUI 애플리케이션 실행을 위한 설정
  4. Mac에서 X11 서버 설정

1. Ubuntu 서버에 SSH로 접속하기

먼저, 로컬 컴퓨터(Mac)에서 원격 Ubuntu 서버로 SSH를 통해 접속해야 합니다. 이를 위해 터미널을 열고 다음 명령어를 실행하세요:

bash
코드 복사
ssh -X username@your-ubuntu-server-ip

여기서 -X 옵션은 X11 포워딩을 활성화하여, 원격 서버에서 실행되는 GUI 애플리케이션을 로컬에서 볼 수 있게 합니다. username은 Ubuntu 서버의 사용자 이름이고, your-ubuntu-server-ip는 서버의 IP 주소입니다.

2. X11 포워딩 설정

Ubuntu 서버에서 X11 포워딩이 활성화되어 있는지 확인해야 합니다. SSH 설정 파일을 편집하여 이 기능을 활성화할 수 있습니다.

bash
코드 복사
sudo nano /etc/ssh/sshd_config

여기서 다음 설정들이 활성화되어 있는지 확인하세요:

plaintext
코드 복사
X11Forwarding yes X11DisplayOffset 10 X11UseLocalhost yes

변경 후, SSH 데몬을 재시작하여 설정을 적용합니다:

bash
코드 복사
sudo service ssh restart

3. Docker에서 GUI 애플리케이션 실행을 위한 설정

Docker 컨테이너 내에서 GUI 애플리케이션을 실행하려면 X11 포워딩을 지원하도록 설정해야 합니다.

  1. Docker 이미지 준비
    Dockerfile
    코드 복사
    FROM ubuntu:20.04 RUN apt-get update && apt-get install -y firefox x11-apps CMD ["firefox"]
  2. GUI 애플리케이션을 실행할 Docker 이미지를 준비합니다. 예를 들어, Firefox를 실행하려면 다음과 같은 Dockerfile을 사용할 수 있습니다:
  3. Docker 컨테이너 실행
    bash
    코드 복사
    docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -it your-docker-image-name
    여기서 -e DISPLAY=$DISPLAY와 -v /tmp/.X11-unix:/tmp/.X11-unix 옵션은 Docker 컨테이너가 X11 디스플레이를 사용할 수 있도록 설정합니다.
  4. Docker 컨테이너를 실행할 때 X11 포워딩을 활성화해야 합니다. Mac에서 X11 서버로 전송될 수 있도록 Docker 컨테이너를 다음과 같이 실행합니다:

4. Mac에서 X11 서버 설정

Mac에서는 X11 포워딩을 사용하기 위해 XQuartz라는 X11 서버를 설치해야 합니다. XQuartz는 X11 애플리케이션을 실행할 수 있게 해주는 도구입니다.

  1. XQuartz 설치
  2. XQuartz를 다운로드하고 설치합니다: XQuartz 다운로드 페이지
  3. XQuartz 실행
  4. 설치 후 XQuartz를 실행합니다. XQuartz가 실행 중이어야만 X11 포워딩이 제대로 동작합니다.
  5. X11 Display 환경 변수 설정
    bash
    코드 복사
    export DISPLAY=:0
  6. SSH 접속 시 X11 Display 환경 변수를 설정해야 합니다. 보통은 XQuartz가 자동으로 DISPLAY 변수를 설정해주지만, 필요하다면 수동으로 설정할 수도 있습니다:

요약

  1. Mac에서 Ubuntu 서버에 SSH 접속: ssh -X username@your-ubuntu-server-ip
  2. Ubuntu 서버에서 X11 포워딩 설정: /etc/ssh/sshd_config에서 X11Forwarding 활성화
  3. Docker 컨테이너 실행 시 X11 포워딩 설정: docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix -it your-docker-image-name
  4. Mac에서 XQuartz 설치 및 실행: XQuartz를 설치하고 실행하여 X11 포워딩이 가능하도록 설정
728x90
728x90

배경

회사에서 내부 API 기술 문서화를 위해 리소스가 많이 들지 않으면서 깔끔하게 정리할 수 있는 방법이 있을까 고민하였습니다.

 

사전 조사

검토해봤던 문서화 툴
mkdocs, read the docs, git book, swagger hub

 

선택한 툴: mkdocs

이유: python 에 특화되어 있고 무료이며 read the docs와 같은 mkdocs의 다양한 테마 를 사용하여 커스텀 할 수 있습니다. workflow를 만들면 문서 자동화도 가능하고 URL로 버전 관리도 가능한 것으로 보입니다.

 

Plugin

  • mkdocs-gen-files: auto documentation 기능, mkdocstrings과 같이 사용하여 API 구조의 index.md 파일을 만들어줍니다.
  • mkdocs-section-index: 목차 기능
  • setting-up-versioning: version 관리 기능
  • mkdocstrings: markdown에 아래와 같이 표현만 해주면 알아서 module, class, 함수 등의 documentation을 만들어줍니다.
`::: my_package.my_module`

 

 

MKDocs를 잘 활용한 예시 : yolov5-mkdocs.yml

 

 

Use Case Code

Github Repository 구조

repo_name
├── .github
	└── workflows
    		└── mkdocs_ci.yml
├── package_name
	├── __init__.py
   	└── 	...
├── docs
	└── code_reference
		└── package_name
                    	├──index.md
                    	└─ 	...
├── script
	└── gen_ref_pages.py
└── mkdocs.yml

주의할 점

  • package(디렉토리) 아래에는 무조건 __init__.py를 넣어줘야 합니다. __init__.py가 index.md로 변환됩니다.

 

mkdoc.yml

site_name: docs_name
docs_dir: "docs/"

plugins:
- search
- gen-files:
    scripts:
    - script/gen_ref_pages.py # mkdocs serve할 때 자동으로 md 파일 생성
- literate-nav:
    nav_file: SUMMARY.md # API 구조가 적힌 파일. gen_ref_pages.py로 생성
- section-index
- mkdocstrings:
    handlers:
        python:
            options:
                docstring_style: numpy # 다른 스타일: google, sphinx
theme : material # 다른 테마: readthedocs

nav:
- Code Reference: code_reference/ # documentation의 컨텐츠를 표출하기 위한 md 파일을 지정
# rest of the navigation...
  • plugin을 넣어주지 않으면 코드가 제대로 동작하지 않을 수 있습니다.

 

script/gen_ref_pages.py

"""Generate the code reference pages and navigation."""
from pathlib import Path

import mkdocs_gen_files

nav = mkdocs_gen_files.Nav()

root = Path(__file__).parent.parent
src = root

for path in sorted(src.rglob("*.py")):
    module_path = path.relative_to(src).with_suffix("")
    doc_path = path.relative_to(src).with_suffix(".md")
    full_doc_path = Path("code_reference", doc_path)

    parts = tuple(module_path.parts)
    if parts[0] != 'package_name' or parts[-1] == "__main__" :
        continue
    elif parts[-1] == "__init__":
        parts = parts[:-1]
        doc_path = doc_path.with_name("index.md")
        full_doc_path = full_doc_path.with_name("index.md")


    nav[parts] = doc_path.as_posix()

    with mkdocs_gen_files.open(full_doc_path, "w") as fd:
        ident = ".".join(parts)
        fd.write(f"::: {ident}")

    mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root))

with mkdocs_gen_files.open("code_reference/SUMMARY.md", "w") as nav_file:
    nav_file.writelines(nav.build_literate_nav())
  • python 파일을 실행해보면 docs/code_reference 디렉토리 아래에 package의 구조에 맞춰 f"::: {ident}" 가 적힌 markdown 파일이 생기는 것을 확인할 수 있습니다.
  • SUMMARY.md는 파일의 구조가 적혀있고 navigation할 때 활용합니다. 
  • mkdocs build 명령어를 실행하면 docs 디렉토리에 실제 파일들이 생성되지는 않고 site 디렉토리가 생성됩니다. 

 

mkdocs_ci.yml

name: Build and Deploy MKDocs

permissions:
  id-token: write
  contents: read

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

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::{number}:role/{GithubActionRole}
          aws-region: ap-northeast-2

      - name: Install Dependencies
        run: >
          pip install mkdocs-material mkdocstrings[python] \
            mkdocs-section-index mkdocs-gen-files mkdocs-literate-nav

      - name: Build Static Website
        run: mkdocs build

      - name: Copy files to the production website with the AWS CLI
        run: aws s3 sync ./site s3://docs.package_name.company_name.com --delete --quiet

 

 

Docstring style

numpy

# docstring numpy style 예시
def foo(a, b):
    """Foo.

    Parameters
    ----------
    a
        Here's a.
        Continuation line 1.

        Continuation line 2.
    b
        Here's b.
    """

google

# docstring Google style 예시 
def add(a, b):
    """Compute and return the sum of two numbers.

    Examples:
        >>> add(4.0, 2.0)
        6.0
        >>> add(4, 2)
        6.0

    Args:
        a (float): A number representing the first addend in the addition.
        b (float): A number representing the second addend in the addition.

    Returns:
        float: A number representing the arithmetic sum of `a` and `b`.
    """
    return float(a + b)

 

 

AWS S3 정적 호스팅

Github Pages

  • 처음에는 github pages를 사용하려 했지만 github enterprise 요금제를 써야 웹 페이지의 visibility도 private 설정이 가능하다고 합니다. 그래서 다른 방법을 검색해보았습니다.
     

S3 Static Hosting Web Server

  • 링크를 참고했습니다.
  • 장점: S3 정적 호스팅 웹 서버를 쓰면 페이지를 접속할 때마다 비용이 발생하지 않을까 싶습니다. 코드 업데이트 할 때마다 자동으로 업데이트할 수 있는 workflows를 만들 수 있습니다.

1. 퍼블릭 버킷 만들기: 버킷 이름 을 만들어주고 일단 퍼블릭으로 만들어줍니다. 

 

 

2. 버킷 속성에서 정적 웹 사이트 호스팅을 활성화합니다.

 

3. 버킷의 정책을 특정 IP에서만 접속할 수 있도록 설정해줍니다.

 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::docs.package_name.company_name.com/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "000.000.000.000"
                }
            }
        }
    ]
}

 

 

4. mkdocs build 후에 생기는 site 디렉토리 내부의 컨텐츠를 버킷에 sync 해줍니다.

 

이 때, mkdocs serve를 먼저 실행해서 mkdocs 문서가 localhost:8000에서 잘 나오는지 확인을 하는 것이 필요합니다.

aws s3 sync ./site s3://docs.package_name.company_name.com --delete --quiet

 

5. 최종적으로 링크에 들어가 mkdocs가 잘 되는지 확인합니다.

http://docs.package_name.company_name.com.s3-website.ap-northeast-2.amazonaws.com

 

 

Github Workflow

최종적으로 workflow 코드를 적용하면 코드가 main branch에 업데이트 될때마다 documentation이 업데이트 될 것입니다.

MKDocs-Tutorial (참고)

https://github.com/Kim-jy0819/mkdocs-tutorial

 

코드 실행 결과

 

728x90
728x90

서비스란?

  • 파드가 대체될 때 새로 생긴 파드의 주소를 자동으로 연결해주는 쿠버네티스 리소스
언제 사용하나요?
  • 파드와 파드간 통신할 때
  • 클러스터 외부에서 파드로 요청할 때
  • 파드에서 클러스터 외부로 요청할 때

서비스 리소스를 왜 사용할까요?

  • IP 주소만 있으면 다른 노드에서 실행 중인 파드끼리도 통신이 가능합니다. 하지만 파드가 대체될 때 파드의 IP는 바뀝니다.
  • 서비스 생성 시 쿠버네티스 DNS 서버에 도메인 이름이 서비스 이름으로 저장되며 서비스의 IP가 등록이 됩니다. 서비스는 레이블 셀렉터(label selector)에 등록된 동일한 레이블을 가진 파드를 관리할 수 있습니다.
  • 컨슈머 컴포넌트가 서비스에 요청을 보내면 서비스와 연결된 실제 IP로 요청을 전달합니다.

파드 간 통신

  • 클러스터IP : 가장 기본이 되는 서비스 유형. 클러스터 내부 파드 간 통신할 때 사용하는 리소스입니다.

예시코드

apiVersion: v1
kind: Service
metadata:
  name: foo_api    # 도메인 네임
spec:
  ports:
    - port: 80         # 80번 포트로 요청이 들어오면 파드의 80번 포트로 전달 
  selector:
    app: foo_api
  type: ClusterIP
  • foo_api의 서비스와 연결된 파드를 수동으로 삭제하더라도 디플로이먼트가 foo_api 레이블을 갖는 파드를 새로 생성하고 서비스 foo_api 레이블을 갖는 파드 트래픽을 연결하므로 잘 동작할 수 있습니다.

외부에서 파드로 트래픽 전달하기

  • 로드밸런서 : 외부에서 파드로 들어오는 트래픽을 파드에 전달하는 서비스 유형. 외부 로드밸런서와 함께 동작하며 클러스터 전체 중 레이블 셀렉터와 일치하는 파드로 트래픽을 전달합니다.
  • 로드밸런서 서비스를 배포하면 포트 포워딩을 해주지 않더라도 클러스터 외부의 트래픽을 파드에 전달할 수 있습니다.
apiVersion: v1
kind: Service
metadata:
  name: foo-web
spec:
  ports:
    - port: 8080       # 서비스가 주시하는 포트
      targetPort: 80   # 트래픽이 전달될 파드의 포트
  selector:
    app: foo-web
  type: LoadBalancer  
  • 클러스터 외부에서 8080 포트로 요청이 들어오면 로드밸런서가 감지하여 이를 foo-web 레이블을 갖는 파드의 80번 포트로 요청을 전달합니다.

파드에서 외부로 트래픽 전달하기

  • 익스터널네임 서비스 : 데이터베이스 같은 쿠버네티스 외부에서 동작하는 소프트웨어를 가리키며 도메인 네임 해소에 사용되는 서비스. 익스터널 서비스를 사용하면 로컬 API가 아니라 외부 도메인에 요청을 날릴 수 있습니다.
apiVersion: v1
kind: Service
metadata:
  name: numbers-api     # 도메인 네임
spec:
  type: ExternalName
  externalName: foo.com    # 도메인 네임을 조회하면 쿠버네티스 DNS 서버가 externalName(CNAME)을 반환한다.
  • foo-api 도메인 네임 대신 foo.com이라는 클러스터 외부 도메인으로 요청을 날릴 수 있습니다.

참고 서적

  • 쿠버네티스 교과서
728x90
728x90

데이터와 관련해 취준생, 주니어 분들을 위한 강의를 해달라는 요청을 받았습니다. 사실, 2년차 개발자라 수강생 분들께 유익한 강의를 할 수 있을까, 수강생 분들이 시간 낭비하는게 아닐까 하는 걱정부터 앞섰지만 좋은 기회를 놓치면 안되겠다는 생각이 들었습니다.

 

 

강의 준비

강의 준비 기간까지 약 한달 반 정도가 남았고 12시간 분량의 라이브 수업을 준비해야 했습니다. 네OO AI 교육 과정의 멘토를 맡아본 적은 있었지만 강의를 직접 제작해 본 경험은 없었기에 저에게는 굉장히 챌린징했었습니다. 일단은 닥치는대로 데이터와 관련된 책을 찾아보기 위해 서점을 들락거리기 시작했습니다. 여러 군데의 서점에서 데이터 관련 책들을 살펴보았는데 대부분 기술적인 내용을 다루는 책들이었습니다. 그러다보니 다루는 내용들이 비슷비슷했고 데이터를 다루는 기술에 대해서는 많이들 설명해주고 있었지만 그래서 왜 비즈니스에서 데이터 기반의 의사결정을 해야하는지는 설명해주지 않아습니다. 그러던 중 정말 보석 같은 귀한 책들을 몇 권 발견하였는데요. 

 

 

이 책들에서 공통적으로 이야기하는 점들은 다음과 같았습니다. 

데이터를 통해 사람의 행동을 이끌어내는 것이 데이터를 다뤄야 하는 근본 이유다.

 

보석 같은 책들

위 책들을 통해 제가 알지 못했던 것들을 깨닫게 되고 인사이트를 정말 많이 습득할 수 있었습니다. 한 분야에서 몇년 동안 경험하고 학습하셨던 것들을 한권의 책에 담아 제 시간을 아끼게 해주신 저자분들께 감사의 말씀을 드립니다. 특히, 데이터 드리븐 분석비법 책은 스승과 제자가 대화하는 형태로 글이 작성되어 있어서 무척 재미있게 읽었던 기억이 납니다. 

 

커리큘럼 구성

1회당 3시간, 총 4회를 준비했는데요. 1일차에는 데이터 드리븐 의사결정이 왜 필요한지 배우고 설득력을 높이는 데이터 시각화 기초 이론에 대해 강의를 준비했습니다. 데이터는 책과 마찬가지로 내가 경험해보지 못했던 것들을 간접적으로 경험할 수 있게 해주어 경험, 정보의 폭을 증대할 수 있습니다. 코끼리를 눈을 감고 만질 때 다리만 만져본 사람과 얼굴만 만져본 사람은 코끼리의 부분밖에 모르지만 코끼리를 눈으로 본 사람은 코끼리에 대해 더 잘 알 수 있게 되는 거과 같은 이치입니다. 데이터를 통해 결국에 해야하는 건 사람의 행동(액션)의 변화를 이끌어내는 것이 중요합니다. 따라서 어떻게 하면 데이터에서 유용한 의미를 뽑아 누구나 납득할 수 있는 설득력 있는 데이터 시각화를 하는 방법에 대해 알아야합니다. 독자의 인지부하를 낮추는 시각 속성들, 게슈탈트 원칙 등에 대해서 학습합니다.

 

2일차에는 python의 matplotlib을 활용하여 막대그래프, 선그래프, 산포도를 그리는 방법에 대한 학습 내용을 준비했습니다. 1일차 때 학습했던 기초 이론을 응용하여 실제 데이터 분석에서는 어떤 식으로 표현하는지 파악하고 보다 나은 데이터 시각화에 대해 학습합니다. 무의식적으로 사용하던 시각 속성들을 의식적으로 사용하며 보다 의미 있는 정보를 독자에게 전달할 수 있습니다.

 

3일차에는 seaborn, plotly에 대해 배우며 matplotlib보다 훨씬 편리한 사용법과 다양한 기능들을 소개하였습니다. Interactive 시각화를 통해 독자가 시각화 작품에 직접 마우스 클릭, 도구를 통한 조작 등을 할 수 있게 되면서 정적인 그래프에서는 담지 못했던 여러가지 정보를 깔끔하게 담을 수 있다는 것을 알게 됩니다.

 

4일차에는 지금까지 배웠던 시각화 기초 이론과 코딩을 통해 현업과 비슷한 느낌으로 실전 프로젝트를 수행합니다. 문제 정의, 데이터 수집/정제, 데이터 시각화를 통한 유용한 사실을 파악하고 또 다시 문제 정의의 사이클을 돕니다. 이를 통해 현업에서는 어떤 식으로 데이터 분석을 하는지 감을 잡을 수 있습니다.  

 

 

정규 교육 외 소개했던 내용

데이터 관련 직군에 대한 소개를 하였고 데이터 엔지니어, 데이터 사이언티스트, 데이터 분석가라는 직무가 어떤 일을 수행하는지에 대해 소개하였습니다. 데이터가 중요한 건 알겠는데 어떤 직무가 도대체 무슨 일을 하는지 도통 알기 어렵습니다. 채용 공고를 봐도 이해가 잘 안되는데 이런 부분들에 대해 예시를 들어가며 설명을 했습니다.

 

현업에서 데이터 분석을 하며 겪었던 어려움에 대해 소개하는 시간을 가졌습니다. 수강생 분들께서 현업에서는 어떤 일을 하게 되고 어떤 문제를 해결할까라는 궁금증이 생길텐데 제가 겪었던 문제점에 대해 소개하고 이를 해결하기 위해 어떤 노력을 했었는지 소개했었습니다. 

 

마지막으로는 이력서와 포트폴리오에 관한 작성법과 제 이력서를 예시로 보여드렸는데요. 이력서를 어떻게 작성해야하는지 자주 질문이 들어왔기에 한 번 소개를 하면 좋겠다 생각했었습니다. 포트폴리오 작성을 위해 프로젝트를 권장했고 강의에서 학습했던 내용을 토대로 지원하고자 하는 회사와 관련된 산업 분야의 데이터셋을 찾아보시길 추천드렸습니다.

 

 

강의 피드백

 

챌린지의 난이도(매우 쉬움-1 매우 어려움-7) : 4.04

커리큘럼(주제) 만족도(매우 불만족-1 매우 만족-7) : 5.15

멘토의 세션 진행 적극도(매우 소극적-1 매우 적극적-7) : 5.93

멘토의 세션 진행을 위한 분야 전문성(매우 부족함-1 매우 충분함-7) : 5.76

 

긍정적인 피드백

"지금까지 국비지원으로 들었던 수업과 프로젝트 경험보다 더 알찼던 수업이에요 ㅠㅠ 파이썬 강의도 해주세요~!! 감사합니다"

"시각화 방식, 분석 사례를 꼼꼼하게 잘 알려주셔서 좋았습니다 많은 도움이 된 거 같아요"

"감사합니다 정규수업 외 커리어에 대한 이야기들도 많이 도움이 됐습니다"

"기초적인 부분들이지만 놓치기 쉬운 부분들, 이 데이터가 왜 필요한지를 생각해서 데이터 표현 및 시각화하는 걸 배울 수 있었습니다. 또, 어렵지 않게 차근차근 설명해주셔서, 잘 따라갈 수 있었어요. 감사합니다~"

"질문에 대해 상세하게 답변해주셔서 도움이 많이 됐습니다. 감사합니다."

"실무에서는 어떻게 일을 하는지 알 수 가 없었는데 교육을 통해 대략적인 느낌을 알게 되었습니다."

"꼼꼼히 설명해주시려 하고 피드백도 잘해주셔서 이해하기 수월했습니다. 그동안 감사했습니다!"

 

 

보완이 필요한 피드백

"해당 주 강의 주제 및 수준에 맞는 과제가 있으면 좋을 것 같습니다. ex. 1주(1일차, 2일차) 강의 목적에 부합하는 과제"

"데이터 분석이라하여 스킬적인 것보다는 데이터를 해석하고 의사결정에 적용하는 일련의 과정들에대한 교육을 기대했는데 코드 위주라살짝 아쉬움이 있었어요ㅠㅠ"

"코드 일부분은 시간이 부족해 넘어간 부분이 있습니다. 그래서 코드에 자세한 설명이 적힌 주석이 달리면 좋겠습니다."

"세션 구성 및 중간 과제도 있으면 좋을 것 같아요"

"사전과제말고도 주차별 과제가 있으면 더 좋을꺼같아요!/사전질문을 받는것도 좋은 방법 같아요"

 

KPT(Keep Problem Try)

Keep

사전 과제, 실전 프로젝트, 다양한 수업자료 업로드 등은 많은 분들께서 좋은 피드백을 주셔서 계속 유지하는게 좋을 것 같습니다.

 

강의 난이도는 쉬웠다는 분도 있구 어려웠다는 분도 있었는데 평점을 내보니 거의 가운데였습니다. 수강생들의 편차가 굉장히 크다보니 어쩔 수 없는 부분인 것 같고 그래도 난이도 부분은 평타 친 것 같습니다. 이러한 난이도로 수업을 진행해도 큰 문제 없을 것 같다는 생각이 듭니다.

 

Problem

커리큘럼(주제) 만족도가 조금 아쉬운 부분인 것 같습니다. 아무래도 짧은 시간 내 준비하다보니 더 양질의 내용을 추가하지 못했던 게 아쉬움이 남습니다. 스킬적인 것보다 데이터를 해석하고 의사결정에 적용하는 과정을 기대하셨다는 피드백에 공감하고 있고 다음에도 강의할 기회가 생긴다면 그러한 것들을 체험할 수 있는 실전 프로젝트를 더 많이 포함하는 것이 좋아보입니다. 

 

Try

또 생각 못했던 부분인데 주차별 과제, 사전 질문도 추가하면 좋을 것 같습니다. 학생 분들의 참여도도 많이 높일 수 있을 것 같고 나와있는 예제를 그냥 실행하는 것보다 직접 코드를 짜보고 만들어보면 좋을 것 같다는 생각이 들었습니다. 코딩을 처음 해보시는 초보자 분들은 수업 때 아무리 설명을 하더라도 어려움을 많이 겪고 계셨습니다. 그래서 강의 자료에 좀 더 자세한 주석을 써두어 복습하실 때 도움이 되도록 해야겠습니다.

 

 

 

728x90
728x90

들어가며

요즈음 개발자 뿐 아니라 비개발자인 분들도 SQL을 공부하고 계시는 분들이 많은데요. 사내에서 SQL 세미나를 진행했고 실제로 서비스팀 멤버분들은 QUERY를 날려 필요한 데이터를 직접 export하고 있습니다. 이번 포스팅을 통해 개발자 뿐 아니라 비개발자분들도 DBMS(DataBase Management System)를 이해하고 기본적인 QUERY문을 작성하여 사내의 데이터 베이스가 있다면 실제로 사용해보시면 좋을 것 같습니다. DBMS는 데이터 저장소로 여러 사용자들이 접근하여 데이터를 저장 및 관리할 수 있는 소프트웨어 프로그램을 의미합니다.

MySQL-Server와 MySQL-WorkBench를 설치하셨다는 가정하에 들어가도록 하겠습니다. 계정과 권한 부여 등을 수행하시면 다음과 같은 기본적인 쿼리를 따라하실 수 있습니다.

기본 쿼리

CRUD는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말입니다. 순서대로 기본 쿼리에 대해서 살펴보도록 하겠습니다.

  • 데이터베이스 생성
# CREATE DATABASE 데이터베이스 이름;
CREATE DATABASE nuvilab;

Local에서 MySQL-Server를 실행하면 당연히 사용할 데이터베이스를 생성해주어야 합니다. 저는 nuvilab이라는 이름을 가진 데이터베이스를 생성하겠습니다. WorkBench에서 명령어를 실행하고자 한다면 Ctrl + Enter 단축키를 사용합니다.

참고로 #은 주석을 의미해요! 주석을 해둔 쿼리는 WorkBench가 실행하지 않기 때문에 보통 실행하고 싶지 않은 쿼리나 설명을 주석으로 써둡니다. 또한 세미콜론(;)은 쿼리의 끝을 의미하고 보통은 적어주어야 프로그램이 어디가 끝인지를 인식하고 해당 쿼리를 실행합니다.

  • Default Schema
# USE 데이터베이스 이름;
USE nuvilab;

데이터베이스를 생성했으면 해당 데이터베이스를 사용하기 위하여 Default Schema 로 설정해줍니다.

  • 테이블 생성
# CREATE TABLE `테이블 이름` (
# `컬럼1` 자료형 PRIMARY KEY AUTO_INCREMENT, 
# `컬럼2` 자료형 
# );
CREATE TABLE `users` (
  `id` int PRIMARY KEY AUTO_INCREMENT, # 따옴표가(') 아니라 backtick(`)이에요!
  `full_name` varchar(255),
  `created_at` timestamp,
  `country_code` varchar(255),
);
CREATE TABLE `countries` (
  `code` int PRIMARY KEY AUTO_INCREMENT,
  `country_name` varchar(255),
  `continent_name` varchar(255)
);

nuvilab 데이터베이스 안에 2개의 테이블을 생성하는 쿼리입니다. 테이블에 사용될 컬럼과 그 자료형을 표시해줍니다. id 오른쪽에 쓰여있는 PRIMARY KEY는 아래에서 알아보도록 하겠습니다. ERD(Entity Relationship Diagram)는 테이블간의 관계를 설명해주는 다이어그램입니다. 예를 들어, 생성한 2개의 테이블을 ERD로 표현하면 아래와 같은 그림일 것입니다.

  • 데이터 생성(Create)

데이터를 새로 생성하는 명령어입니다. 어떤 어플리케이션의 사용자가 새로 가입했을 경우에 데이터베이스에 데이터를 추가해주어야 합니다. users 테이블의 각 컬럼에 데이터를 삽입합니다.

# INSERT INTO 테이블 이름 (컬럼1, 컬럼2) values (값1, 값2);
INSERT INTO users (id, full_name, country_code) value (1, ‘홍길동’, 81);
  • 데이터 읽기(Read)

위에서 추가한 데이터가 잘 들어갔는지 확인해봐야겠죠? 테이블의 데이터를 조회하는 명령어입니다.

# SELECT * FROM 테이블 이름;
SELECT * FROM users
  • 데이터 변경(Update)

데이터베이스에 들어간 데이터가 잘못 입력됐거나, 변경사항이 있을 때 데이터를 업데이트하는 명령어입니다.

# UPDATE 테이블 이름 set 컬럼1=값1
UPDATE users set country_code=82 where full_name='홍길동'

UPDATE 문은 보통 조건문과 같이 사용되는데요. 위에서 where~ 이후의 조건문이 없다면 users 테이블에 있는 모든 country_code 컬럼의 값이 82로 변경이 됩니다. 그러면 사용자의 이름이 “홍길동”인 사람 뿐 아니라 다른 모든 사람의 country_code가 82로 변경이 되어 상상하기 싫은 순간이 오게 됩니다. 따라서 데이터를 변경하거나 삭제할 때는 해당 쿼리가 맞는지 dev 데이터베이스에서 테스트 해보는 등 재차 점검하고, 제약조건을 걸어두는 등의 조치를 취해야 합니다.

  • 데이터 삭제(Delete)

사용자가 회원탈퇴를 하는 경우에 데이터베이스에서 데이터를 삭제하는 명령어입니다.

# DELETE FROM 테이블 이름
DELETE FROM users where full_name='홍길동'

마찬가지로 조건문 없이 DELETE 쿼리를 사용한다면 users 테이블의 모든 데이터가 삭제가 되버리는데요. 사용자의 이름이 “홍길동”인 것만 데이터를 제거한다는 조건문을 걸어두도록 합니다.

KEY

Primary Key

  • 정의 : Primary Key는 테이블의 기본키를 의미합니다. null을 허용하지 않고 unique 한 옵션을 포함하며 테이블에서 한개의 필드에만 설정할 수 있습니다.
  • 예를 들어, 위 users 테이블에서 ‘full_name’, ‘country_code’가 중복될 때 각 데이터를 구별해주는 것이 바로 Primary Key인 ‘id’입니다.

 

Foreign Key

  • 정의 : 두 개 이상의 테이블을 연결해주는 값입니다.
  • 필요한 이유 : 한 테이블에 너무 많은 정보가 들어가게 되면 가독성이 떨어지고, 필요없는 정보가 많이 삽입될 수 있습니다. 이를 방지하기 위해 사용합니다.
  • 예를 들면 users 테이블과 countries 테이블은 각각 ‘country_code’와 ‘code’로 연결이 되어있는데요. 만약에 users 테이블에 countries 테이블 컬럼인 ‘name’, ‘continent’까지 들어가게 되면 users 테이블에 2개의 컬럼이 늘어나 데이터가 쌓일 때마다 저장 공간을 더 빠르게 잡아먹을 수 있습니다. 하지만 countries 테이블을 두어 FK를 사용한다면 users 테이블에 데이터가 쌓인다 하더라도 저장 공간을 덜 차지하게 됩니다.

 

Constraint

  • 부모 테이블이 PK이거나 UNIQUE 때만 사용할 수 있습니다.

Restrict

  • 일반적으로 FK를 설정하면 Restrict 제약이 걸리게 됩니다. users의 ‘country_code’ 컬럼에 FK를 설정하면 부모 테이블인 countries 테이블의 PK인 ‘code’ 컬럼을 참조하게 되므로 INSERT, UPDATE, DELETE 할 때 제약이 걸리게 됩니다.
  • users 테이블에 insert를 하게 될 경우 ‘coutry_code’는 null이 될 수 없으며 countries 테이블의 ‘code’ 컬럼을 참조하여 데이터 값이 있는 것만 집어넣을 수 있습니다. 예를 들면 ‘code’ 컬럼에 81,82,83이라는 값만 있다면 users 테이블에 ‘country_code’에도 81, 82, 83만 들어갈 수 있는 식입니다.
  • FK 제약이 걸린 경우에 별도의 옵션이 없다면 users 테이블에서는 ‘country_code’ 컬럼을 UPDATE, DELETE를 할 수 없습니다. 반면, countries 테이블에서는 users 테이블에서 참조하지 않는 값이 있다면 그 값에 대해서는 UPDATE, DELETE가 가능합니다. 예를 들면, countries 테이블에서 ‘code’ 컬럼이 5,6,7 인 row는 users 테이블에서 참조하고 있지 않을 때, UPDATE, DELETE가 가능합니다.

 

Cascade

  • UPDATE와 DELETE를 할 때 각각 Cascade를 설정할 수 있습니다.
  • users 테이블에 FK Cascade 제약을 UPDATE, DELETE 할 때 모두 설정했다고 가정해봅시다. 부모 테이블인 countries 테이블에서 ‘code’가 81인 데이터를 82로 update를 수행하게 되면 users 테이블의 ‘country_code’도 81에서 82로 부모 테이블과 똑같이 변경됩니다. countries 테이블에서 ‘code’가 82인 데이터에 대해 DELETE를 수행한다면 users 테이블에서 ‘country_code’가 82인 데이터 또한 마찬가지로 삭제가 되는것이죠.

 

프로시저

 

장점

  • 여러 쿼리를 한번에 실행할 수 있는 명령어입니다.
  • 미리 구문 분석 및 내부 중간 코드로 변환을 끝내야 하므로 처리 시간이 줄어듭니다.
  • 파이썬 등의 호스트 언어에서 사용할 경우 쿼리를 여러번 호출하기보다 프로시저 한번만 호출할 수 있어 코드 관리에 유용합니다.

단점

  • 업무 변경으로 인해 저장된 프로시저를 변경해야할 때 변경 실수로 서비스 장애가 있을 수 있습니다.
  • 디버깅이 어려워 에러가 발생했을 때 대처하기가 까다롭습니다.

 

프로시저 옵션

  • 본인이 생성한 프로시저를 다른 유저가(해당 유저의 권한으로) 실행할 수 있도록 하는 옵션
SQL SECURITY INVOKER

 

예시 : 회원가입을 했을 경우 full_name, country_code를 받아 users 테이블에 데이터를 입력하는 프로시저

CREATE DEFINER=`jinyoung.kim`@`%` PROCEDURE `signup`(f_name VARCHAR,                                                     c_code INT)       
    SQL SECURITY INVOKER  
BEGIN  
INSERT INTO users (full_name, country_code) value (f_name, c_code); select * from users where full_name=f_name and country_code=c_code;  
END

실무에 사용되는 유용한 꿀팁

누비랩에서 실제로 많이 사용하는 쿼리를 정리해보았는데요. 알고 계시면 두고두고 쓸 수 있을 것이라 생각합니다.

  • Foreign Key를 활용하여 2개 이상 테이블 Join하기
SELECT * FROM users as u
INNER JOIN coutry as c
on c.code = u.country_code
  • ‘k’로 시작하는 나라 검색
SELECT * FROM countries where name like 'k%'
  • 중복 데이터가 있는지 확인
SELECT 
    full_name, 
    country_code,
    COUNT(id) c
FROM
    users
GROUP BY 
    full_name,
    country_code;
having
c>1;
  • 중복 데이터 없애는 쿼리
create table users_temp
LIKE users;
insert into users_temp
select * from users
group by 
full_name, country_code;
drop table users;
alter table users_temp
rename to users;

 

 

참고)

https://www.mysqltutorial.org/mysql-delete-duplicate-rows/

https://ko.wikipedia.org/wiki/저장_프로시저

728x90
728x90

4가지 모델 소개

  • 계층적인 클래스 구조를 가져가기 위해 DB에 저장하는 방식이 여러가지가 있습니다. 총 4가지의 방식이 있고 위의 표에서 각 방식의 장단점을 나타내고 있습니다.

1. Adjacency List

  • Adjacency List는 테이블 1개로 계층적 구조를 나타낼 수 있습니다.

1.1 장점

  • 스키마를 이해하기가 쉽습니다.
    • Parent_id 컬럼을 두어 해당 row의 부모가 어떤 row인지 쉽게 파악이 가능합니다.
    • 예를 들어 comment_id가 2인 row는 parent_id가 1이고 comment_id가 1인 row가 부모인 것을 알 수 있습니다.

1.2 단점

  • 트리의 깊이가 깊어질수록 시간복잡도가 증가한다는 단점이 있습니다.
  • 물론 현재 음식 계층은 3단계로 트리의 깊이가 깊지는 않지만 다른 방식에 비해 데이터가 많아질수록 조회하는데 시간이 오래 걸릴 수 있습니다.
  • 성능이 다른 방식들에 비해 좋지 않습니다.

2. Path Enumeration

  • path 컬럼에 각 계층 구조 경로를 string 형태로 명확하게 적어줌으로써 전체 경로를 빠르게 파악할 수 있습니다. 예를 들어 comment_id가 3인 경우는 path가 “1/2/3”으로 되어있고 comment_id가 2인 row가 부모 노드임을 알 수 있습니다.

2.1 장점

  • path enumeration 방법은 path라는 컬럼을 통해서 전체 계층적인 구조가 어떻게 이루어지고 있는지 명확하게 바로 알 수 있습니다.

2.2 단점

  • 트리가 깊어질수록 path의 string이 길어집니다.
  • 쿼리를 할 때 string parsing이 필요해 큰 데이터셋에서 성능 저하를 일으킬 수 있습니다.
    • • SELECT * FROM mydata WHERE path LIKE ‘windows\system32\%’
  • 참조 완결성이 없는 string 형태이므로 path가 잘못될 경우 어디가 잘못되어있는지 파악하기 힘듭니다.
    • 실제로 119라는 데이터가 없더라도 “1/2/3/119” 라는 데이터가 생성될 수 있습니다.
  • 계층 구조를 변경할 때 cost가 비쌉니다.
    • 1/2/3/4 → 1/5/3/4 로 변경할 때 “1/2/3/”, “1/2/3/4”을 각각 “1/5/3”, “1/5/3/4/”등으로 수정해야하는데 string이라 변경하기가 어렵습니다.
  • 큰 데이터셋에 대해 스케일링하기가 어렵습니다.

3. Nested Sets

  • nested set 모델은 맨 상위부터 아래쪽으로 왼쪽에서 오른쪽으로 순서로 가며 번호를 붙입니다. 예를 들어 맨 위의 계층은 left가 1, right가 14이며 그 자식 노드는 left가 2 right가 5입니다. 자식 노드인지를 확인하는 방법은 자식 노드의 left가 부모 노드의 left와 right 사이에 있는지를 판단하여 그 안에 있으면 자식 노드인 것을 알 수 있습니다.

3.1 장점

  • 트리의 깊이가 3단계 이상인 경우 조인의 오버헤드를 줄여 데이터 검색을 위해 발생하는 쿼리의 수가 매우 줄어듭니다.
  • 매우 크고 동적인 계층 구조라면 Adjacency list보다 훨씬 낫고 다뤄보면 직관적입니다.

3.2 단점

  • 참조 완결성이 없습니다. left와 right는 comment_id를 참조하는 것이 아니라 단지 노드의 숫자를 의미합니다. 따라서 nsleft, nsright가 잘못 들어갈 경우가 생깁니다.
  • left와 right값이 모두 변경되어야 하므로 add/delete/move 에 대한 cost가 큽니다.
  • 구조 상 멀티 쓰레드 환경에서 데이터를 변경할 경우 데이터의 손상이 있을 수 있기 때문에 해당 테이블의 데이터 변경을 여러 사용자가 동시에 진행할 수 없습니다.

4. Closure Table

  • Closure Table은 테이블을 2개를 활용합니다. 왼쪽 테이블의 comment_id를 참조하여 오른쪽 테이블의 ancestor, descendant에 데이터를 삽입합니다. ancestor는 조상 노드, descendant는 후손 노드로 각 노드의 관계를, length 컬럼은 관계를 맺은 노드 간의 깊이 차이를 나타낸 것입니다. 3번 노드의 조상 노드를 찾는다면 descendant가 3인 ancestor를 찾아야 합니다. 2와 3이 있고 length가 1인 2가 부모 노드입니다.

4.1 장점

  • 참조 완결성이 존재하므로 오른쪽 테이블의 ancestor, descendant 컬럼은 왼쪽 테이블의 comment id를 foreign key 로 참조하여 실제 있는 데이터를 참조하도록 설정 할 수 있습니다. path enumeration과 같은 문제점은 발생하지 않습니다.
  • top/middle/leaf node 의 계층 구조에서 middle을 조작하기 쉽습니다.(add, move, delete)
  • sub-tree를 사용하기 쉽습니다.
  • 트리의 깊이가 깊더라도 시간 복잡도 면에서 큰 문제가 없습니다.

4.2 단점

  • 오른쪽의 전체 row가 최악의 경우에 O(n2)으로 증가할 수 있습니다.

참고

Models for hierachical data

comparision between closure table and path enumeration

comparision between adjacency list and nested set model

comparision between adjacency list and nested set model2

728x90

'DevOps > Database' 카테고리의 다른 글

[Database] 비전공자도 쉽게 활용하는 MYSQL  (0) 2023.01.20
728x90

자료형이 중요하다는 것을 다들 아시겠지만 많이 신경쓰지는 못했었는데요. RMSE를 구하면서 값이 낮게 나오길래 디버깅하면서 확인해보았고 540^2이 29456으로 나왔습니다. 자료형이 uint16은 65535가 넘어가면 오버플로우가 발생해 540^2이 291600가 아니라 29456이 나왔습니다. 저와 같은 실수를 하지 않길 바라는 마음에서 공유드립니다~

 

Int16 : 음수 32768에서 양수 32767
uint16 : 0에서 65535
uint32 : 0에서 4294967295
int64 : 음수 9,223,372,036,854,775,808부터 양의 9,223,372,036,854,775,807

728x90
728x90

Abstract

이미지 형성 프로세스를 노이즈를 제거하는 오토인코더 순차적인 어플리캐이션으로 분해하면서 diffusion model은 이미지에서 SOTA 합성 결과를 얻었습니다. 기존에는 픽셀 공간에서 연산을 하여 막대한 GPU 연산이 필요했지만 사전학습된 오토인코더의 latent space를 활용하여 제한된 컴퓨팅 리소스로도 재학습할 수 있게 했습니다. LDM(Latent Diffusion Model)은 pixel 기반의 DM보다 연산량을 상당히 줄이면서, image inpainting, class-conditional image synthesis, 그리고 text-to-image 합성, unconditional image generation, super-resolution과 같은 다양한 분야에서 SOTA를 달성했습니다.

1. Introduction

  • 확산(Diffusion)은 시간이 지남에 따라 분자들이 퍼져나가는 현상을 의미합니다. 이런 현상에 착안하여 이미지에 노이즈를 점차적으로 추가하여 최종적으로 노이즈를 만들고 이를 다시 복원하도록 학습하는 것이 Diffusion Model의 핵심입니다.

2. Related Work

Generated Models for Image Synthesis

  • GAN 모델은 고해상도의 이미지를 좋은 품질로 잘 생성하지만 모델을 최적화하기 어렵고, 데이터 분포를 잘 잡아내는 것이 힘듭니다.
  • 반면 Likelihood 기반의 모델인 VAE(Variational Auto Encoder)나 flow 기반의 모델은 최적화가 잘 이루어지도록 하는 밀도 추정을 잘하지만, GAN보다 성능이 뛰어나지는 않습니다.
  • ARM(Auto Regressive Model)은 밀도 추정에서 좋은 성능을 내지만 저해상도 이미지에서만 사용할 수 있다는 제한이 있습니다.

Diffusion Probabilistic Models

  • DM은 밀도 추정과 샘플의 품질에서 훌륭한 성능을 보여주며 노이즈를 제거하는 과정에서 U-Net이 활용되어 이미지와 같은 데이터에서 inductive bias를 학습할 수 있습니다.
  • DM은 압축 능력과 샘플의 품질이 서로 trade off의 관계를 가지며, pixel 공간에서 모델을 평가하고 최적화하는 것은 추론 속도 저하와 많은 컴퓨팅 비용이 발생합니다.
  • LDM은 이러한 단점들을 해결하며 이미지 품질 저하 없이 연산량을 줄이면서 추론 속도를 높일 수 있습니다.

Two-Stage Image Synthesis

  • two stage 접근을 통해 단점들을 극복하려는 많은 연구들이 있었습니다.
  • VQ-VQE는 이산화된 latent space로 prior를 학습하는 auto regressive model을 사용합니다.
  • dall-e는 VQ-VAE에서 더 나아가 이산화된 image와 text의 representation의 결합 분포를 학습하여 text-to-image를 수행합니다.
  • net2net은 가역 네트워크를 사용하여 다양한 도메인의 latent spaces들 간에 일반적인 transfer를 제공합니다.
  • VQ-VQE와 VQ-GAN은 큰 이미지에 auto regressive transformer를 스케일링하기 위해 first stage로 adversarial과 perceptual objective를 사용합니다.
  • 높은 압축률은 ARM이 학습을 가능하게 하지만 성능에 제한이 생기고, 낮은 압축률은 연산 비용이 매우 커지게 됩니다.
  • LDM은 좋은 품질의 이미지를 생성하는 것을 보장하면서 first stage에서 perceptual한 압축을 너무 많이 하지 않고 강력한 첫 번째 단계 학습 사이를 최적으로 중재하는 압축 수준을 자유롭게 선택할 수 있다.

3. Method

Fig2는 디지털 이미지에서 대부분의 bits가 사람이 인지할 수 없는 것들이라는 것을 나타냅니다. DM이 의미 상 필요 없는 정보를 제거하여 불필요한 계산을 최소화하려 해도 학습이나 추론 시에 모든 픽셀에 대해 평가를 해야 하기 때문에 불필요한 계산을 해야합니다. LDM은 효과적인 생성 모델로, 인간이 지각할 수 없는 영역을 제거하는 압축 단계를 분리합니다.

3.1 Perceptual Image Compression

  • perceptual loss와 patch-based loss adversarial objective로 오토인코더를 학습하여 local realism을 강제하고 L2와 L1 objectives와 같은 픽셀 공간에 의존함으로써 생기는 블러를 피하게 해줍니다.
  • 디코더는 latent로부터 이미지를 재현하고, 인코더는 $2^m$ factor로 이미지를 다양하게 downsample합니다.
  • latent spaces의 고분산을 피하기 위하여 KL-reg를 적용하며, 디코더에서 VQ-reg를 적용합니다.
  • 기존의 DM은 임의의 1차원 latent를 사용하지만 LDM은 2차원의 latent space를 사용하여 가벼운 압축률과 detail한 정보를 보존하여 매우 좋은 재현성을 달성할 수 있었습니다.

3.2 Latent Diffusion Models

Diffusion Models

Diffusion Model은 길이가 T인 fixed Markov Chain의 역과정에 상응하는 정규 분포 변수의 노이즈를 점진적으로 제거하여 원래의 데이터 분포 $p(x)$를 학습하도록 고안된 확률 모델입니다. 이러한 모델들은 노이즈가 있는 $x_t$의 노이즈를 제거하여 원래의 입력값 x를 예측하도록 학습합니다. 이 때, x는 이미지 원본입니다.

Forward diffusion process

원본 이미지에 노이즈를 점진적으로 더해서 최종적으로 노이즈를 만드는 과정

Reverse diffusion process

노이즈로부터 점차 원본 이미지로 되돌리는 과정

그림 출처 :  https://arxiv.org/abs/2006.11239

 

Generative Modeling of Latent Representations

LDM은 high-frequency, imperceptible details를 추상화한 정보가 담긴 저차원의 latent space에 노이즈를 추가하고 복원하는 과정을 거칩니다. LDM은 DM과 비교했을 때 여러가지 장점이 있습니다. 이 과정은 생성 모델에서 사용되는(데이터 분포의 확률을 최대화하는) likelihood에 DM보다 훨씬 적합하고 중요하고 의미가 있는 bits에 집중하며 저차원에서 효과적으로 전체 연산량을 줄일 수 있습니다.

U-Net 구조로 노이즈로부터 이미지를 복원하는 과정을 거치게 됩니다.

3.3 Conditioning Mechanisms

  • cross-attention mechanism을 통해 다양한 modality로 conditioning을 할 수 있게 되어 되었습니다.
  • 텍스트가 conditioning으로 주어지면 $τ_Θ$는 트랜스포머와 같은 도메인별 전문가를 통해 매개변수화할 수 있습니다.
  • Q는 U-Net representation $(z)를 K, V는 conditioning y을 프로젝션한 representation을 활용하여 프로젝션 행렬 W_Q, W_K, W_V를 학습합니다.

  • 최종적인 LDM은 다음과 같은 식을 통해 학습합니다. 노이즈, 반복 횟수 t, condition

4. Experiments

4.1 On Perceptual Compression Tradeoffs

  • NVIDIA A100 1개로 down sampling factor {1,2,4,8,16,32} 실험을 진행하였고 factor가 1인 경우는 pixel-based DMs와 같은 경우로 생각합니다.
  • Fig6는 샘플의 품질을 factor가 1,2인 경우는 학습 시간이 길어지는 반면 계수가 훨씬 더 높은 값들은 학습한 시간이 얼마 지나지 않아 성능의 정체가 오게 됩니다.
  • Fig2에서 보듯이 너무 많은 perceptual compress는 정보의 손실을 야기해 좋은 품질에 대한 제한이 걸립니다.
  • LDM-4 ~ 16 사이가 성능이 가장 좋으며 pixel-based인 LDM-1과 비교할 때 FID가 2M step에서 38의 차이가 납니다.

  • Fig7은 CelebA-HQ와 ImageNet에서 학습한 모델들을 DDIM 샘플러로 다양한 denoise step으로 실험하여 샘플링 속도와 FID를 나타낸 것입니다.
  • LDM 4-8이 가장 좋은 품질을 산출한다는 것을 알 수 있습니다.

4.2 Image Generation with Latent Diffusion

  • Table1에서 보듯이 CelebA-HQ, FFHQ, LSUN-Churches, LSUN-Bedrooms 데이터셋에서 FID, Precision, Recall이 매우 좋은 성능을 내고 있음을 알 수 있다.

4.3 Conditional Latent Diffusion

4.3.1 Transformer Encoders for LDMs

  • text-to-image 모델링은 BERT-Tokenizer를 활용하여 LAION-400M의 Language prompts conditioning으로 14억 5천만 개의 파라미터를 학습합니다.
  • multi-head cross-attention으로 U-Net에 매핑된 latent code를 추론하기 위해 transformer로 $τ_Θ$를 구현합니다.
  • 언어와 비전의 도메인별 전문가 조합은 복잡하고, 사용자 기반의 text prompt를 잘 일반화하여 좋은 결과를 산출할 수 있습니다.
  • Table2는 분류기가 없는 LDM-KL-8-G이 다른 모델들보다 파라미터 수가 적음에도 더 좋은 성능을 낼 수 있는 것을 볼 수 있습니다.

4.3.2 Convolutional Sampling Beyond

  • 공간적인 conditioning 정보를 인코딩 입력 값과 concatenating하여 LDM은 image-to-image 모델링을 설계할 수 있습니다.
  • semantic synthesis, super-resolution, inpainting에 대해 모델들을 학습시킬 수 있습니다.

4.4 Super-Resolution with Latent Diffusion

  • super-resolution 학습을 위해 LDM은 저해상도의 이미지를 concatenation을 통해 conditioning 합니다.
  • Fig 10에서 보듯이, 이미지를 bicubic 방식으로 품질 저하를 시킨 후에 이를 원상 복구시키는 SR3 데이터 처리 파이프라인을 따라 학습을 시킵니다.
  • Table 5에서 보듯이, FID에서는 LDM-SR이 우위이지만, IS에서는 SR3가 우위임을 볼 수 있습니다.

4.5 Inpainting with Latent Diffusion

  • inpainting은 이미지에서 망가지거나 없애고 싶은 영역을 자연스러운 내용으로 대체하는 기술입니다. Fig 11은 LDM의 결과물입니다.
  • pixel 기반의 DM과 latent 기반의 DM은 속도 면에서 최소 2.7배, FID scores 면에서 최소 1.6배의 차이가 나는 것을 알 수 있습니다.

5. Limitations & Societal Impacts

Limitations

  • LDM은 pixel 기반의 DM 보다는 계산 필요량이 상당히 줄어들지만 GAN의 순차적인 샘플링 과정보다는 느립니다.
  • pixel 공간에서 fine-grained 정확도를 요구하는 task들에서는 재현성이 약간 떨어집니다.
  • super-resolution model은 다소 성능에 제한이 있습니다.

Societal Impact

  • 이미지 생성 모델은 양날의 검입니다. 훈련, 추론 비용을 줄여 기술에 대한 접근성이 높아지고 많은 사람들이 연구할 수 있는 반면에 조작된 데이터나 잘못된 정보가 쉽게 퍼져 나갈 수 있습니다.
  • 특히 deep fake와 같은 정교한 이미지 조작과 특히 여성과 관련된 불균형한 영향을 끼칠 수 있습니다.
  • 또한 생성 모델은 민감하거나 개인적인 정보를 노출할 수 있고, 명확한 동의 없이 데이터가 수집될 수 있다는 문제점이 있습니다.
  • 딥러닝 모듈들은 데이터에 담긴 bias를 재생산하거나 가중화시키는 경향이 있습니다.

6. Conclusion

LDM은 품질을 떨어뜨리지 않은 채로 노이즈를 제거하는 간단하고 효율적인 diffusion 방식으로 학습과 샘플링 효율을 향상시켰습니다. 이것들과 cross attention conditioning 방식으로 task-specific한 구조를 갖지 않고도 폭넓은 이미지 합성 분야에서 SOTA 방식들과 비교했을 때 좋은 결과를 성취할 수 있었습니다.

참고 )

https://pitas.tistory.com/9

https://lilianweng.github.io/posts/2021-07-11-diffusion-models/

 

 

Stable Diffusion으로 colab을 이용해 이미지 생성해보는 작업을 해볼 수 있습니다.

https://journey-to-serendipity.tistory.com/34

 

[토이 프로젝트] Stable Diffusion 텍스트로 원하는 이미지 생성해보기(초간단 colab)

stable diffusion은 텍스트로 이미지를 생성하는 모델입니다. 최근 gan을 능가하는 성능을 보이고 있으며, pretrained model이 오픈되어 많은 사람들이 활용해볼 수 있는데요. 토이 프로젝트를 진행하기

journey-to-serendipity.tistory.com

 

728x90
728x90

1. Introduction and Motivating Work

  • 2개의 인코더(텍스트 인코더와 이미지 인코더)가 짝이 맞는 텍스트, 이미지가 유사도가 높아지도록 짝이 맞지 않는 쌍은 유사도가 낮아지도록 사전학습합니다.
  • 예를 들면, 풀을 뜯고 있는 코끼리 이미지와 '코끼리가 풀을 뜯는다'라는 문장은 유사도가 높아지도록 학습을 하고, '비행기가 날아다니고 있다' 라는 문장과는 유사도가 낮아지도록 학습하는 식입니다. 

  • CLIP은 초기에 image captioning baseline을 썼는데 Transformer 기반의 모델보다 zeroshot 성능이 뛰어났습니다.
  • image captioning baseline보다 Contrastive 모델이 훨씬 효율적인 것으로 나타났습니다.

2. Approach

2.1 Natural Language Supervision

  • 자연어로 지도학습하여 모델을 학습.
  • 라벨링할 필요가 없어서 스케일링이 쉬움.
  • zeroshot을 가능하게 함.

2.2 Creating a Sufficiently Large Dataset

  • 주요 멀티 모달 데이터셋 3개
    • MS-COCO →약 10만장
    • Visual Genome → 약 10만장
    • YFCC100M → 약 1억장인데 meta data 정보가 빈약한 데이터가 많아 필터링하면 약 1500만장 정도 활용 가능. 이는 ImageNet과 비슷한 정도
  • 많은 양의 데이터셋을 확보하기 위해서 4억장의 이미지, 텍스트 페어를 인터넷으로부터 수집합니다.

2.3 Selecting an Efficient Pre-Training Method

Contrastive Learning

N개의 이미지, 텍스트 페어가 있을 때 배치 내에서 N * N개의 페어가 만들어질 수 있다. N^2-N 개의 틀린 페어의 코사인 유사도를 최소화하고 N개의 올바른 페어의 코사인 유사도를 최대화하도록 한다.

2.4 Choosing and Scaling a Model

Image Encoder : ResNet-50, Vision Transformer

Text Encoder : Transformer(a 63M-parameter 12-layer 512-wide model with 8 attention heads)

2.5 Training

  • 5 ResNets(ResNet-50, a ResNet-101, EfficientNet-style model scaling 4x, 6x, and 64x the compute of a ResNet-50)
  • 3 Vision Transformers(ViT-B/32, ViT-B/16, ViT-L/14)
  • train 환경 : 32 epochs, the Adam optimizer, cosine schedule

3. Experiments

3.1 Zero-shot Transfer

3.1.4 Prompt Engineering AND ENSEMBLING

  • pretraining은 주로 문장으로 학습하기 때문에 단일한 단어보다는 어느 정도의 문맥을 살린 “A photo of a {label}.”, “A photo of a {label}, a type of pet.”과 같은 prompt 템플릿을 함께 사용하여 예측하는 것이 성능 향상에 좋습니다.
  • “A photo of a big {label}” , “A photo of a small {label}” 과 같은 다른 문맥을 가진 prompt를 활용하여 앙상블을 수행합니다.

3.1.5 Analysis of zeroshot CLIP performance

  • Fig5는 Zeroshot Clip과 각 데이터셋을 지도 학습한 ResNet-50을 비교한 것입니다. 초록색이 Zeroshot CLIP이 더 뛰어난 성능을 보인 데이터셋, 파란색이 ResNet-50이 더 뛰어난 성능을 보인 데이터셋입니다.
  • CLIP은 전문적이고, 복잡하며, 추상적인 TASK(인공위성 이미지 분류, 림프절 종양 검출, 합성 이미지에서 개체 카운트, 자율주행, 가장 가까운 거리의 차 인식)에 대해서는 약하다는 것을 보여줍니다.

  • CLIP의 zeroshot은 few shot 모델보다 훨씬 성능이 좋습니다. CLIP에 Logistic Regression Classifer를 달았을 때 4 shot(클래스당 학습 이미지 개수가 4개)의 성능이 zeroshot과 비슷한 것으로 나옵니다. BiT-M의 경우는 16shot일 때 zeroshot CLIP과 성능이 비슷하게 나옵니다.

  • Fig 7은 CLIP의 zeroshot 성능과 비슷하게 유지하려면 CLIP의 Linear Probe가 필요한 클래스당 라벨링 데이터 개수를 정리해둔 것입니다. FER2013 데이터셋의 경우 zeroshot CLIP과 비슷한 성능이 나오려면 Linear Probe CLIP은 클래스당 184개의 데이터가 필요합니다.
  • 1개 이하인 데이터 셋에서는 zeroshot의 성능보다 Linear Probe CLIP이 1개 이상의 데이터로 fine tuning 했을 때 성능이 더 좋습니다.
  • 클래스당 필요한 라벨링 개수를 1, 2, 4, 8, 16개 등으로 실험하여 log-linear interpolation으로 그래프를 그린 것입니다.

  • Zeroshot이 이상적으로 task-agnostic하려면 Fig8 그래프의 y=x에 수렴하는 직선이 나와야 합니다. 그렇게 되는 데이터셋은 5가지 정도(STL10, CIFAR10, ...)이고 대부분은 Linear Probe일 때 성능이 더 좋은 것으로 나옵니다.

3.2 Representation Learning

  • CLIP의 Linear probe의 성능은 CV SOTA 모델들을 여러 데이터셋에서 비교했을 때 훨씬 뛰어납니다.

  • CLIP의 linear probe는 Noisy Student EfficientNet-L2와 비교했을 때 27개 중 21개의 데이터셋에서 더 뛰어난 성능을 보여줍니다.

3.3 Robustness to Natural Distribution shift

  • ImageNet에서 pretraining한 후 linear probe를 수행한 모델들보다 CLIP의 linear probe가 여러 데이터셋에서 성능이 더 뛰어난 점으로 보아 전자의 모델들은 ImageNet에 과적합 되어있음을 알 수 있습니다.
  • 반면, CLIP은 다양한 TASK에 강건하다는 것을 알 수 있습니다.

  • 강건성을 파악하기 위해 distribution shift가 있는 여러 데이터셋(ImageNetV2, ImageNet-R, ObjectNet, ImageNetSketch, ImageNet-A, Youtube-BB, ImageNetVid)을 평가합니다.
  • 왼쪽 그림에서 dashed line은 이상적인 강건 모델을 뜻합니다. distribution shift가 있는 여러 데이터셋에서 정확도와 ImageNet에서의 정확도가 일치한다는 의미입니다.
  • 오른쪽 표에서 ImageNet 모델인 ResNet101은 ImageNet이 아닌 다른 데이터셋에서 성능 저하를 보이는 반면 zeroshot CLIP은 우수한 성능을 보입니다.
  • zeroshot CLIP은 distribution shift에도 다른 모델에 비해 약 75% 정도 강건함을 보입니다.

4. Comparision to Human Performance

  • zeroshot CLIP은 few shot CLIP보다 성능이 좋고, 강건성이 뛰어납니다. Fig15는 16 shot CLIP 모델과 Zeroshot 모델의 ImageNet에서의 성능이 비슷하지만 강건성 면에서는 zeroshot 모델이 훨씬 뛰어납니다.
  • Table2는 인간은 zeroshot보다 one, two shot에서 훨씬 더 높은 정확도를 보여주는 반면에 CLIP은 zeroshot이 few shot보다 더 뛰어난 것으로 볼 수 있습니다.
  • CLIP이 어려워 애완동물 종류 구분은 인간도 어려워하는 것을 Fig16에서 볼 수 있습니다.

5. Data Overlap Analysis

인터넷으로 받은 큰 데이터셋을 사전 학습하는 것은 평가 데이터셋과 overlap할 수 있는 가능성이 있습니다. 이럴 경우 의미 있는 일반화 평가가 힘들어지는데 4억장의 데이터를 모두 검수하기란 힘들기 때문에 다음과 같은 절차를 통해 overlap이 얼마나 발생하고 그에 따른 성능 차이를 분석합니다.

  1. duplicate detector를 실행하여 유사도가 특정 threshold 이상이면 Overlap 집합에, 그 이하이면 Clean 집합에 포함시킵니다.
  2. All 과 Clean을 metric으로 비교하여 데이터셋이 얼마나 오염되어 있는지를 분석합니다.
  3. overlap 양이 적은 경우가 많기 때문에 Clean에 대한 정확도를 귀무 가설로 사용하고 Overlap 부분 집합에 대한 단일 꼬리(더 큰) p-값을 계산하는 이항 유의성 검정도 실행합니다. 또한 오염도에 대한 99.5% 클로퍼-피어슨 신뢰 구간을 또 다른 검사로 계산합니다.

  • 합성 혹은 특수한 데이터 셋에서의 overlap은 검출되지 않았기 때문에 duplicate detector의 false positive의 비율이 낮다는 것을 알 수 있습니다.
  • 왼쪽 그래프에서 보듯이 정확도 차이가 20% 정도로 분명히 나는 경우가 있지만, 대부분 overlap의 비율이 낮기 때문에 오른쪽 그래프에서 Clean 집합 대비 All 집합의 정확도 상승이 1% 미만임을 알 수 있습니다.
  • Country211은 overlap 비율이 21.5%로 높지만 CLIP이 학습했던 데이터셋과 다릅니다. Country211은 geo-localization을 위한 데이터셋을 측정하는 것으로 학습용 텍스트가 CLIP이 학습한 것과는 다릅니다.

분석의 한계

  • duplicate detector가 완벽하지 않고 4억장의 데이터를 모두 확인해본 것은 아닙니다.
  • Overlap 과 Clean 의 데이터 분포에 차이가 있어 정확한 비교가 어려울 수 있습니다. 예를 들면 Kinetics-700의 overlap에는 검정 화면이 많이 들어있었기에 clean에 비해 정확도 하락이 20%가량 달했습니다.

6. Limitations

  • zeroshot CLIP은 SOTA 모델에 비해 성능이 떨어집니다.
  • task-specific, fine-grained classification(차 종류, 꽃 종류, 비행선 구별), abstract/systematic task(개체 개수 세기), novel task(사진 상에서 가장 가까운 차까지의 거리 분류) 등에서 CLIP은 다소 성능이 떨어집니다.
  • MNIST와 유사한 데이터를 학습한 적이 없지만 Rendered SST2라는 OCR 데이터셋을 학습했습니다. CLIP은 MNIST에서 88%의 정확도가 나오는데 이는 단순한 logistic regression 지도 학습보다 떨어지는 성능입니다. CLIP은 일반화 문제에 취약하다는 것을 나타냅니다.

7.Broader Impacts

7.1 Bias

  • FairFace dataset은 기존의 face dataset에서 백인의 비율을 줄이고 성별과 인종이 고루 분포하도록 수집한 데이터셋입니다.
  • 백인 카테고리에서 LR CLIP(Logistic Regression)은 FairFace Model, Linear Probe Instagram보다 성능이 잘 나왔고, ZL CLIP(Zeroshot CLIP)은 성능이 떨어졌습니다.
  • 다양한 인종을 평가하면서 ZL CLIP은 성능이 상승하였습니다.

  • table 6은 남녀 각각에 7개의 인종, 3개의 범죄 관련 카테고리, 4개의 인간이 아닌 카테고리를 포함해 총 14개의 카테고리로 이미지를 분류하는 작업을 수행할 때 범죄 관련(’thief’, ‘criminal’, ‘suspicious person’) 혹은 인간이 아닌 카테고리(’animal’, ‘chimpanzee’, ‘gorilla’, ‘orangutan’)로 분류된 비율을 나타낸 것입니다.
  • table 7은 table 6을 연령별로 구분하고 child 카테고리를 추가했을 때 범죄 관련 혹은 인간이 아닌 카테고리로 분류된 비율을 비교한 표입니다.
  • Black 이 가장 높은 비율(14.4%)로 인간이 아닌 카테고리에 분류되었고, 남성의 16.5%, 여성의 9.8%가 범죄 관련 카테고리로 분류되었습니다.
  • child 카테고리를 추가했을 때 20세 이하에서 오분류된 비율이 크게 줄어들었다는 점을 볼 수 있습니다.
  • 이는 class design이 모델의 성능과 unwanted bias를 결정하는 중요한 요인임을 알 수 있습니다.

7.3 Future Work

  • 연구 프로세스 초기에 모델의 잠재적으로 유익한 다운스트림 사용을 식별하여 다른 연구자가 응용 프로그램에 대해 생각할 수 있도록 합니다.
  • 상당한 민감성과 정책 입안자들의 개입이 필요할 수 있는 많은 사회적 이해관계자들의 작업 표면화.
  • 모델에서 편견을 더 잘 특성화하여 다른 연구자에게 관심 영역과 개입 영역을 경고합니다.
  • CLIP과 같은 시스템을 평가하기 위한 테스트를 생성하여 개발 주기 초기에 모델 기능을 더 잘 특성화할 것.

9. Conclusion

CLIP은 폭넓은 task에 대해 사전학습을 하고, 자연어 prompting을 통해 많은 데이터셋에 대하여 zeroshot transfer를 가능하게 합니다. 성능 향상이 필요하지만 task specific한 모델들에 견주어 볼만합니다.

# CODE

Evaluation Code

Zeroshot evaluation

import os
import clip
import torch
from torchvision.datasets import CIFAR100

# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)

# Download the dataset
cifar100 = CIFAR100(root=os.path.expanduser("~/.cache"), download=True, train=False)

# Prepare the inputs
image, class_id = cifar100[3637]
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in cifar100.classes]).to(device)

# Calculate features
with torch.no_grad():
    image_features = model.encode_image(image_input)
    text_features = model.encode_text(text_inputs)

# Pick the top 5 most similar labels for the image
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
values, indices = similarity[0].topk(5)

# Print the result
print("\\nTop predictions:\\n")
for value, index in zip(values, indices):
    print(f"{cifar100.classes[index]:>16s}: {100 * value.item():.2f}%")
  • 분류하고자 하는 이미지 한 장을 전처리하고 모든 텍스트에 a photo of prompt를 붙입니다.
  • 모델에 넣어 이미지 피처와 텍스트 피처를 뽑아낸 후 torch.norm 을 사용하여 normalization하고, 행렬 곱을 통해 유사도를 계산합니다.
  • torch.topk 를 통해 유사도가 높은 5개를 뽑아 이미지와 유사한지 살핍니다.

Linear Probe evaluation

import os
import clip
import torch

import numpy as np
from sklearn.linear_model import LogisticRegression
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR100
from tqdm import tqdm

# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device)

# Load the dataset
root = os.path.expanduser("~/.cache")
train = CIFAR100(root, download=True, train=True, transform=preprocess)
test = CIFAR100(root, download=True, train=False, transform=preprocess)

def get_features(dataset):
    all_features = []
    all_labels = []

    with torch.no_grad():
        for images, labels in tqdm(DataLoader(dataset, batch_size=100)):
            features = model.encode_image(images.to(device))

            all_features.append(features)
            all_labels.append(labels)

    return torch.cat(all_features).cpu().numpy(), torch.cat(all_labels).cpu().numpy()

# Calculate the image features
train_features, train_labels = get_features(train)
test_features, test_labels = get_features(test)

# Perform logistic regression
classifier = LogisticRegression(random_state=0, C=0.316, max_iter=1000, verbose=1)
classifier.fit(train_features, train_labels)

# Evaluate using the logistic regression classifier
predictions = classifier.predict(test_features)
accuracy = np.mean((test_labels == predictions).astype(np.float)) * 100.
print(f"Accuracy = {accuracy:.3f}")
  • train과 test 이미지의 피처, 텍스트를 리스트에 각각 저장합니다.
  • Logistic Regression을 만들어 이미지 피처 리스트로 텍스트를 학습합니다.
  • test 이미지로 평가합니다.

 

출처

https://github.com/openai/CLIP

https://arxiv.org/pdf/2103.00020.pdf

728x90
728x90

1. Serverless란?

서버를 올리고 잘 동작하는지 모니터링하는 등 서버를 관리하는데 많은 비용이 들어갑니다. serverless는 그러한 서버를 관리하는데 들어가는 리소스가 필요하지 않습니다. 트래픽이 많아지거나 줄어들 때 자동으로 스케일링해주며 사용한 만큼만 지불할 수 있습니다. AWS에서 관리를 해주기 때문에 보안에 큰 신경을 쓰지 않아도 된다는 장점이 있습니다. 

 

 

2. Serverless Service 종류

Serverless service들

 

AWS에서 제공하는 서비스로는 Lambda, Fargate, S3, Aurora serverless, DynamoDB, API Gateway, SQS, SNS, Kinesis 등이 있습니다.

 

 

3. Lambda 함수

 

3.1 Lambda 함수란?

Lambda 함수는 함수 기반의 실행환경을 제공합니다. 실행환경을 작성할 때 여러 언어(Node.js, Python, Java, C#, Go, Ruby, Runtime API)를 사용할 수 있습니다. 

 

3.2 Lambda 함수 실행 프로세스

Lambda 함수의 실행 프로세스는 아래 이미지에 나온 것과 같습니다. 데이터 상태의 변화, endpoints로의 요청, 리소스 상태의 변화 등을 트리거로 설정하여 이러한 이벤트가 발생할 경우 Lambda 함수를 호출할 수 있습니다. 그 후에 여러 서비스들과 함께 어울려 business logic을 수행합니다. 

 

 

3.3 Handler function

Handler function은 Lambda 함수 1개마다 1개의 handler function이 있어야 합니다. 트리거로 Lambda 함수가 호출됐을 때 handler function으로 요청이 들어오게 됩니다. event 객체는 Lambda 호출 시 들어오는 데이터(s3 트리거 시 해당 파일 이름 등등)가 들어오게 되고, context는 runtime과 관련된 정보(reqeust ID, log group 등)들이 들어있습니다.

 

import json

def lambda_handler(event, context):
	# TODO implement
    return {
    	'statusCode' : 200,
        'body' : json.dumps('Hello World!')
    }

 

3.5 실행환경

Lambda 함수는 한 개당 실행환경 한 개를 가집니다. Lambda 함수가 여러 개가 호출될 경우 여러개의 실행환경이 실행됩니다. 다만, 실행환경은 재사용이 가능해서 초기화와 관련된 함수들은 handler function 밖에 두는 것이 함수의 사용 시간을 줄이는 방법입니다. 

 

3.6 Lambda 설정

1) Power Rating

- 메모리 128MB ~ 10GB 사이에서 선택 가능

- CPU는 메모리에 따라 성능 향상 가능

- CPU, 메모리, 네트워크는 성능에 따라 가격 변동

 

2) Timeout

- 15분까지 설정 가능

- 동기 vs 비동기

- API Gateway timeout은 30초

 

3) Network Access

- VPC로 접근 설정

- 보안 그룹 역할 적용

- VPC는 함수의 보안 향상 X

 

 

3.7 The function lifecycle

1) cold start : Lambda 함수가 처음 호출되어 실행환경을 준비하는 시간으로 코드 다운로드, 실행환경 시작, 런타임 부트스트랩하는 시간을 의미합니다. 이때, 앞단계는 AWS에서 최적화해주는 시간이고, 런타임 부트스트랩은 사용자가 직접 최적화할 수 있습니다. 

2) warm start : cold start 이후로 실제 코드가 실행되는 시간을 의미합니다.  

3) 재사용시 시간을 단축시키는 방법

- handler function을 어떻게 작성하느냐에 따라 Lambda 함수의 실행시간이 크게 단축될 수 있습니다.

 

200-300 ms 실행시간

import json
import boto3

def lambda_handler(event, context):

    print("inside handler")
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('lambda-config')
    response = table.get_item(Key={'pkey':'dynamodb'})['Item']['value']
    return {
    	'statusCode': 200,
        'body: Json.dumps(response)
    }

 

double digit ms 실행시간

import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('lambda-config')
    
def lambda_handler(event, context):
	
    print("inside handler")    
    response = table.get_item(Key={'pkey':'dynamodb'})['Item']['value']
    return {
    	'statusCode': 200,
        'body: Json.dumps(response)
    }

 

4) cold start를 줄이는 방법

- INIT 단계에서 필요한 클래스 로딩

- Java의 경우 Reflection 가급적 피하기

- 패키지 사이즈는 작게

- Memory 사이즈를 크게(비용 고려)

- Lambda Language(Java는 로드하는 시간이 길어서 대체할 수 있는 스크립트 언어가 있다면  대체하는 것이 좋습니다.)

- Provisioned Concurrency

 

 

4. Lambda Concurrency

4.1 concurrency 이해하기

1) 사용자 요청이 들어오면 cold start를 마치면 함수가 실행이 됩니다.

2) 이 때, 사용자의 요청이 끝나기 전까지는 해당 실행환경은 blocking 되므로 새로운 요청이 발생했을 때에는 새로운 실행환경이 생깁니다.

3) request6 생길 당시에 request1의 실행환경이 요청이 끝난 free 상태(=warm 상태)이므로 cold start 없이 warm start를 할 수 있습니다.

4) concurrency count는 시간당 처리한 요청의 수가 아닌 요청을 처리 중인 실행환경의 수를 의미합니다.

 

 

4.2 Lambda function scaling

1) 요청이 들어오면 실행환경들이 빠르게 생성이 되다가 Burst limit에 도달하면 분당 500개의 실행환경들이 새롭게 생성되도록 제한됩니다.

2) 이 때, 실행환경의 생성 개수가 제한됨에 따라 요청량이 실행환경 개수보다 많아 throttling 될 수 있는데 이는 다른 기법을 활용하여 제어할 수 있습니다.

3) concurrency limit보다 많은 요청량이 들어올 경우에도 마찬가지로 throttling이 발생할 수 있습니다. concurrency limit은 region별로 다르며, aws support에 요청하면 상한선을 높일 수 있습니다.

4) 요청량이 줄어듦에 따라 Lambda의 실행환경 수도 같이 줄어듭니다.

5) Provisioned concurrency : cold start 없이 warm 상태인 실행환경을 만들어두어 급격하게 대량의 요청(쇼핑몰 이벤트)이 들어올 때를 대비할 수 있습니다. 

6) Reserved concurrency : 해당 Lambda 함수에 대해서만 사용할 수 있는 pool을 미리 만들어두어 다른 Lambda 함수가 급격하게 호출되더라도 실행환경 할당량을 보장받을 수 있습니다.

 

 

5. Lambda - More Features

1) Lambda Layers  - cold start를 줄일 수 있는 방법 중 하나입니다. 문자 인코딩하는 라이브러리, 크기가 큰 패키지 등을 불러올 때, 빈번하게 잘 바뀌지 않는 코드일 경우 한 번 업로드해놓고 여러 Lambda 함수에서 이를 참조하여 실행환경을 실행할 수 있습니다.

 

2)  Dead-Letter Queue - 비동기 방식으로 요청을 처리할 때 요청이 끊어지거나 예외가 발생할 때 내부적으로 2번 재시도를 한 후 실패하면 버리게 됩니다. 이러한 실패한 요청들을 Dead-Letter Queue에 모아두어 나중에 확인하여 재처리를 할 수 있습니다. Dead-Letter Queue에 알람 설정을 해두어 한건이라도 들어오면 어떤 에러가 발생했는지 어떤 처리를 하다가 발생했는지 알 수 있게 구성할 수 있습니다.

 

3) RDS-Proxy

관계형 DB에서 Lambda 함수를 사용하는 것은 적합하지 않습니다. 1000개의 요청이 들어와 Lambda 함수가 호출되었을 때 1000개의 DB connection을 잡고 있는 상태가 되고 RDS는 이를 효율적으로 관리하는데 적합하지 않습니다. RDS proxy는 Shared connection pool을 사용하여 connection을 줄여주고, secret manager로 간단한 인증을 할 수 있습니다. 

 

4) Versioning, Aliasing

versioning을 통해 쉽게 배포, rollback 등을 할수 있습니다. aliasing을 통해 Lambda 함수에 태그를 달아 참조할 수 있습니다.

 

5) Monitoring and debugging Lambda functions

1) 기본적으로 monitoring을 제공하며 throttling이나 error에 대한 알람 설정을 하는 것이 좋습니다.

 

 

 

출처

AWS에서 Serverless 개발 시작하기 

 

728x90

+ Recent posts