no image
[Python] Progress Bar(tqdm)을 깔끔하게 출력하는 방법은 무엇일까?
tqdm을 이용해서 for문이 실행될 때마다 실행결과를 확인하기 위해 print을 실행한다면 VSCode나 Jupyter에서 사진과 같이 출력된다. 이때 깔끔하게 출력하는 방법에 대해 알아보자. tqdm 기초는 여기를 보면 된다.Jupyter와 VSCode에 대해 각각 설명하겠다. 일단 결론부터 말하자면 다음과 같은 코드를 사용하면 된다.from tqdm.auto import tqdm  Jupyter에서 tqdm 사용방법tqdm 라이브러리 내부의 notebook 모듈을 사용하면 간단하게 해결된다. from tqdm.notebook import tqdmimport timefor i in tqdm(range(100)): print(1) time.sleep(0.1) VSCode에서 tqdm 사용방법..
2024.05.30
no image
[Python] decorator(데코레이터)에 대해 알아보자
Python FastAPI를 공부하면서 데코레이터를 알게 되었는데 왜 어떻게 작동하는지 잘 이해가 가지 않아서 공부를 하게 되었고 이에 대해 내가 알게된 점에 대해 소개해보려고 한다. 코드는 여기에서 확인할 수 있다. 데코레이터란 무엇인가?데코레이터는 파이썬의 고급 기능 중 하나로, 함수나 메서드에 코드를 수정하지 않고 기능을 주입하는 방법입니다. 함수를 여러 기능으로 사용해야 하며 코드에 수정을 가하지 않을 때 자주 사용한다. 데코레이터는 함수로 인자를 받고, 함수를 감싸는 래퍼(wrapper)를 정의하여, 함수에 추가적인 기능을 할 수 있도록 한다.  데코레이터를 사용하는 이유는?사용하는데 여러가지 이유가 있다.코드 재사용 : 코드가 중복될 때 함수를 사용하는데 이때 함수를 여러 방법으로 사용하기 위..
2024.05.29
no image
[GCP] GKE(Google Kubernetes Engine)은 무엇일까?
GKE(Google Kubernetes Engine)에 대해 소개해보려고 한다.일단, GKE에 설명하기 이전에 Kubernetes(쿠버네틱스)에 대해 전반적인 소개를 하려고 한다.쿠버네티스(K8S)쿠버네티스를 사용하는 이유여러개의 소프트웨어나 애플리케이션을 관리하는 시스템 관리자는 소프트웨어에 대해 여러가지를 고려해야한다.모든 장비에서 작동하는가?오류 발생시 어떻게 해야하는가?많은 소프트웨어나 애플리케이션을 컨테이너화하면서 컨테이너들을 관리하는 방법이 쿠버네티스(k8s)이다. 여러개의 컨테이너들을 간편하게 관리하기 위해서 쿠버네티스를 사용한다. 쿠버네티스가 좋은 이유여러개의 컨테이너들을 어떻게 사용할지 결정하는 것이 쿠버네티스이다. 쿠버네티스를 이용해 컨테이너의 상태를 모니터링을 통해 컨테이너들이 미리 ..
2024.05.27
no image
[Docker] Docker-Compose에 대해 알아보자
이번에는 Docker-Compose에 대해 정리하려고 합니다.도커 컴포즈란?도커 컴포즈는 여러 도커 컨테이너들을 정의하고 동시에 실행할 수 있도록 하는 도구입니다. 이를 통해서 단일 애플리케이션을 구성하는 여러 컨테이너를 정의하고 한 번에 실행할 수 있도록 관리합니다. 도커 컴포즈를 왜 사용할까?도커 컴포즈를 사용하는 이유는 다음과 같습니다.복잡한 애플리케이션 구성을 위한 컨테이너 관리컨테이너, 서비스, 백과 프론트간의 의존성 관리배포 용이성 도커 컴포즈 설치apt-get install docker-compose# 또는sudo apt-get install docker-compose# 네트워크 설치docker network create nat설치가 완료되면 잘 설치했는지 확인합니다.docker-compos..
2024.05.18
no image
[프로그래머스] [Python] (Level 2) 리코쳇 로봇
https://school.programmers.co.kr/learn/courses/30/lessons/169199 프로그래머스코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.programmers.co.kr문제리코쳇 로봇이라는 보드게임이 있습니다.이 보드게임은 격자모양 게임판 위에서 말을 움직이는 게임으로, 시작 위치에서 목표 위치까지 최소 몇 번만에 도달할 수 있는지 말하는 게임입니다.이 게임에서 말의 움직임은 상, 하, 좌, 우 4방향 중 하나를 선택해서 게임판 위의 장애물이나 맨 끝에 부딪힐 때까지 미끄러져 이동하는 것을 한 번의 이동으로 칩니다.다음은 보드게임판을 나타낸 예시입니다....D..R..
2024.05.12
no image
[Docker] Docker Container SSH 접속하는 방법
오늘은 Docker Container을 SSH로 접속해서 사용할 수 있는 방법에 대해 알려드리려고 합니다. 각자의 포트를 통해 컨테이너에 따로 접속해서 서로 영향을 미치지 않고 사용할 수 있게 됩니다.Dockerfile 작성하기FROM python:3.12RUN apt-get update && apt-get upgrade -y && apt-get install -y vim openssh-server net-tools가장 최소한으로 작성하였습니다. SSH 접속을 할 때, Dockerfile은 크게 고려하지 않으셔도 됩니다. Container를 실행할 때 포트포워딩이 핵심입니다. 이미지 빌드하기docker build -t ssh_image . Container 실행하기# docker run -idt -p 원..
2024.05.03
no image
[Hugging Face] 내가 만든 Dataset을 Hugging Face에 올려보기
오늘은 허깅페이스에 내가 만든 Dataset을 올리는 방법에 대해 소개해드리려고 합니다. 이를 통해 다른 사람들이 업로드한 데이터셋을 사용할 수 있습니다. Dataset을 업로드하려면 허깅페이스 토큰이 필요합니다. 토큰을 발급받지 않은 분들은 여기를 클릭해서 토큰을 발급해주세요데이터셋 저장할 Repo 만들기데이터 만들기데이터 허깅페이스에 업로드하기 코드는 여기에 있습니다. 데이터셋 저장할 Repo 만들기 허깅페이스 홈페이지에 들어갑니다.위의 이미지와 같이 프로필을 누르고 New Dataset 버튼을 누릅니다. 다음과 같이 저장할 Repo 이름을 작성합니다.작성을 하고 Create dataset 버튼을 누릅니다.그러면 다음과 같이 giliit/upload_dataset 이라는 Repo가 생성됩니다. 데이터..
2024.04.30
no image
[Hugging Face] 모델 가져오기(Read), 모델 및 데이터 업로드(Write)를 위한 Token 발급 받는 방법
안녕하세요, 오늘은 허깅페이스에서 특정 모델을 읽거나, 데이터나 모델을 업로드하기 위해 필요한 Token을 발급받는 방법에 대해 알려드리려고 합니다. 글의 목차는 다음과 같습니다.허깅페이스 가입하기토큰 발급받기토큰 삭제하기 허깅페이스 가입하기일단 허깅페이스에 가입하기 위해 허깅페이스 홈페이지를 들어갑니다.https://huggingface.co/ Hugging Face – The AI community building the future.The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the found..
2024.04.28
[Python] pydantic에 대해 알아보자
FastAPI를 공부하면서 pydantic 라이브러리에 대해 알게 되었고, pydantic document를 보게 되면서 공부를 하게되어서 공부하고 깨달은 점에 대해 소개하고자 작성하게 되었습니다. Pydnatic overview Pydantic은 Python의 타입 힌트를 활용하여 데이터 유효성 검사와 설정 관리를 자동화하는 강력한 라이브러리입니다. 개발자가 데이터 모델을 정의할 때 명확한 데이터 타입을 지정함으로써, Pydantic은 이 모델을 기반으로 데이터의 유효성을 자동으로 검증합니다. 이 과정에서 데이터 타입의 불일치나 필드의 누락과 같은 문제를 즉각적으로 식별하고 처리할 수 있습니다 다시말하면, 명시해준 데이터 타입과 입력에 대해 data validation을 진행합니다. 이 때, 타입이 다..
2024.04.21
no image
[Hugging Face] apply_chat_template 함수에 대해 알아보자
안녕하세요, 오늘은 LLM에서 dictionary를 Chat 형식으로 변환하는 apply_chat_template 함수에 대해 알아보려고 합니다. 이 함수는 최근에 Chat Bot, Chat Model이 많아지면서, Chat 형식으로 변환하는 Tokenizer의 필요로 의해 만들어졌습니다. 그래서 이 함수에 대해 자세히 설명해드리려고 합니다. 선언 방법 사용하는 방법은 쉽습니다. Chat(Dialog)에 대해 apply_chat_template()를 사용하면 바로 출력이 나옵니다. from transformers import AutoModelForCausalLM, AutoTokenizer checkpoint = "HuggingFaceH4/zephyr-7b-alpha" tokenizer = AutoToke..
2024.04.20
728x90

tqdm을 이용해서 for문이 실행될 때마다 실행결과를 확인하기 위해 print을 실행한다면 VSCode나 Jupyter에서 사진과 같이 출력된다. 이때 깔끔하게 출력하는 방법에 대해 알아보자. tqdm 기초는 여기를 보면 된다.

Jupyter와 VSCode에서 깔끔하게 출력되지 않음

Jupyter와 VSCode에 대해 각각 설명하겠다. 

일단 결론부터 말하자면 다음과 같은 코드를 사용하면 된다.

from tqdm.auto import tqdm

 

 

Jupyter에서 tqdm 사용방법


tqdm 라이브러리 내부의 notebook 모듈을 사용하면 간단하게 해결된다. 

from tqdm.notebook import tqdm

import time

for i in tqdm(range(100)):
    print(1)
    time.sleep(0.1)

tqdm은 위에 유지하며 출력결과만 밑에 나온다.

 

VSCode에서 tqdm 사용방법


VSCode 같은 경우에도 동일한 코드를 작성하면 된다.

from tqdm.notebook import tqdm

import time

for i in tqdm(range(100)):
    print(1)
    time.sleep(0.1)

 

하지만, tqdm을 바로 실행하면 오류가 생긴다.

ImportError: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html

이 오류에 대해서는 다음 코드를 작성하면 된다.

pip install ipywidgets

설치 이후에는 잘 출력되는 것을 볼 수 있다.

 

 

결론


위의 코드를 보면 항상 tqdm.notebook을 사용하면 괜찮은 것처럼 보이지만 항상 그렇지만은 않다. 그래서 나는 프로그램마다 다른 것을 사용하는데 그에 대해 설명하려고 한다. 

VSCode 사용 시

VSCode를 사용할 땐, tqdm.auto 또는 tqdm을 사용한다.  거의 tqdm.notebook은 사용하지 않는다. 그 이유는 notebook은 jupyter를 위한 모듈이므로 굳이 notebook을 사용하지 않는다.

Jupyter 사용 시

Jupyter을 사용할 땐, tqdm.auto 또는 tqdm.notebook을 사용하며, tqdm은 사용하지 않는다.  그 이유는 tqdm은 기본적으로 VSCode를 위한 모듈이므로 사용하지 않는다. 하지만 tqdm 실행결과를 기록해야 한다면 tqdm을 사용한다. 그 이유는 tqdm.notebook은 kernel을 종료하면 실행결과가 사라진다는 것을 명심해야 한다.

728x90
728x90

Python FastAPI를 공부하면서 데코레이터를 알게 되었는데 왜 어떻게 작동하는지 잘 이해가 가지 않아서 공부를 하게 되었고 이에 대해 내가 알게된 점에 대해 소개해보려고 한다. 코드는 여기에서 확인할 수 있다.

 

데코레이터란 무엇인가?


데코레이터는 파이썬의 고급 기능 중 하나로, 함수나 메서드에 코드를 수정하지 않고 기능을 주입하는 방법입니다. 함수를 여러 기능으로 사용해야 하며 코드에 수정을 가하지 않을 때 자주 사용한다. 데코레이터는 함수로 인자를 받고, 함수를 감싸는 래퍼(wrapper)를 정의하여, 함수에 추가적인 기능을 할 수 있도록 한다. 

 

데코레이터를 사용하는 이유는?


사용하는데 여러가지 이유가 있다.

  • 코드 재사용 : 코드가 중복될 때 함수를 사용하는데 이때 함수를 여러 방법으로 사용하기 위해 데코레이터를 사용한다.
  • 기능 확장 : 기존 코드에 추가적인 기능을 추가하기 위해서 사용한다.
  • 래퍼 함수에 대한 제어 : 데코레이터 내부의 함수를 제어하기 위해 사용한다.

 

데코레이터의 구조


데코레이터 함수

데코레이터의 함수 구조는 다음과 같다.

def simple_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@simple_decorator
def say_hello():
    print("Hello!")

say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''

@인자를 사용하여 표현한 데코레이터이다. 함수를 @로 바꾸어 함수를 간단하게 표현한다. 

데코레이터 함수 내부에는 wrapper함수를 써야한다. 이름은 무관하지만 내부에 함수를 정의해야하며, return값은  내부에 정의한 함수를 써야한다.

위의 코드는 데코레이터를 쓰지 않으면 다음과 같이 표현할 수 있다.

def simple_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_hello():
    print("Hello!")

# 데코레이터를 수동으로 적용
decorated_say_hello = simple_decorator(say_hello)

# 함수 호출
decorated_say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''

 

데코레이터 클래스

데코레이터 클래스 구조는 다음과 같다.

class SimpleDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self):
        print("Something is happening before the function is called.")
        self.func()
        print("Something is happening after the function is called.")

@SimpleDecorator
def say_hello():
    print("Hello!")

say_hello()
'''
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
'''

클래스가 실행되는 것에 대해 설명은 다음과 같다.

  1. SimpleDecorator 클래스는 __init__ 메서드에서 데코레이터가 감싸야 할 함수를 인자로 받아 저장한다.
  2. __call__ 메서드는 데코레이터가 적용된 함수가 호출될 때 실행된다.
  3. @SimpleDecorator를 사용하여 say_hello 함수에 데코레이터를 적용하면, say_hello 함수가 호출될 때 SimpleDecorator 클래스의 __call__ 메서드가 실행된다.

 

데코레이터 예시


여기서는 함수에 대해 예시 3개에 대해 설명한다.

  • 실행시간 측정
  • 파라미터 전달
  • 디버깅

 

실행 시간 측정

데코레이터 사용

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer
def slow_function(delay_time):
    time.sleep(delay_time)

slow_function(1)

'''
slow_function took 1.0007 seconds
'''

데코레이터 없이 사용

import time

def slow_function(delay_time):
    start_time = time.time()
    time.sleep(delay_time)
    end_time = time.time()
    print(f"slow_function took {end_time - start_time:.4f} seconds")
    return "Done"

slow_function(1)
'''
slow_function took 1.0007 seconds
'''

 

파라미터 전달

데코레이터 사용

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello {name}")

greet("Alice")

데코레이터 없이 사용

def repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator_repeat

def greet(name):
    print(f"Hello {name}")

# 데코레이터를 수동으로 적용
decorated_greet = repeat(num_times=3)(greet)

# 함수 호출
decorated_greet("Alice")

 

디버깅

데코레이터 사용

def debug(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"{func.__name__} called with {args}, {kwargs} returned {result}")
        return result
    return wrapper

@debug
def make_greeting(name, age=None):
    greeting = f"Hello {name}"
    if age:
        greeting += f", you are {age} years old!"
    return greeting

make_greeting("Alice", age=30)
'''
make_greeting called with ('Alice',), {'age': 30} returned Hello Alice, you are 30 years old!
'''

데코레이터 없이 사용

def make_greeting(name, age=None):
    greeting = f"Hello {name}"
    if age:
        greeting += f", you are {age} years old!"
    print(f"make_greeting called with ({name}, {age}) returned {greeting}")
    return greeting

make_greeting("Alice", age=30)
'''
make_greeting called with ('Alice',), {'age': 30} returned Hello Alice, you are 30 years old!
'''

 

728x90
728x90

GKE(Google Kubernetes Engine)에 대해 소개해보려고 한다.

일단, GKE에 설명하기 이전에 Kubernetes(쿠버네틱스)에 대해 전반적인 소개를 하려고 한다.

쿠버네티스(K8S)


쿠버네티스를 사용하는 이유

여러개의 소프트웨어나 애플리케이션을 관리하는 시스템 관리자는 소프트웨어에 대해 여러가지를 고려해야한다.

  • 모든 장비에서 작동하는가?
  • 오류 발생시 어떻게 해야하는가?

많은 소프트웨어나 애플리케이션을 컨테이너화하면서 컨테이너들을 관리하는 방법이 쿠버네티스(k8s)이다. 여러개의 컨테이너들을 간편하게 관리하기 위해서 쿠버네티스를 사용한다.

 

쿠버네티스가 좋은 이유

여러개의 컨테이너들을 어떻게 사용할지 결정하는 것이 쿠버네티스이다. 쿠버네티스를 이용해 컨테이너의 상태를 모니터링을 통해 컨테이너들이 미리 설정한 방식대로 하드웨어의 자원을 잘 활용하는지 확인할 수 있어서 좋다. 또한 쿠버네티스는 여러가지 기능을 지원한다.

  • 자동화된 배포와 컨테이너 복제
  • 컨테이너 그룹으로 부하 분산
  • 애플리케이션 컨테이너의 롤링 업그레이드
  • 컨테이너 인스턴스 자가 치유

 

쿠버네티스가 어려운 이유

클러스터를 설치하고 관리하는 방법에 대해 익히는 것이 어렵다. 쿠버네티스 클러스터 단계별 설치 가이드를 확인하면서 다음을 생각해야한다.

  • 클라우드 공급자 또는 베어메탈
  • 머신 준비
  • OS와 컨테이너 런타임
  • 네트워크 구성
  • 보안구성
  • DNS

이러한 것들을 직접 다 갖추어야 하지만 개인이 다루기는 매우 어려울 것이다. 하지만, 이것들을 매우 간편하게 처리해주고 지속적으로 클러스터 관리, 확장 및 유지를 해준다면 좋지 않을까? 그래서 나온 것이 GKE이다.

 

GKE(Google Kubernetes Engine)


 Google 인프라를 사용하여 컨테이너화된 애플리케이션을 대규모로 배포 및 운영하는 데 사용할 수 있는 관리형  Kubernetes 서비스입니다. 확장 가능한 자동화된 관리형 Kubernetes 솔루션을 원하는 플랫폼 관리자를 대상으로 하는 서비스입니다.

 

 

왜 GKE를 써야하는가?

써야하는 여러가지 이유에 대해 나열하겠다. 총 4가지 측면이 있다. 플렛폼 관리, 보안, 비용, 안전성과 가용성

  • 기본 제공 로깅 및 모니터링
  • 노드 자동 복구로 노드 상태 가용성을 유지 관리
  • 무인 Autopilot 모드
  • 보안 상태 대시보드를 사용하는 보안 상황 모니터링 도구 제공
  • 새 GKE 버전으로 자동 업그레이드

 

GKE의  작동 방식

그룹화되어 클러스터를 형성하는 VM의 노드들로 구성됩니다. 노드들을 컨테이너로 패키지화 하여 컨테이너들을 배포합니다. 이 때, 쿠버네티스 API를 사용하여 관리, 확장, 모니터링을 포함하여 상호작용합니다. Google이 노드들을 직접 관리하기에 안정성과 보안을 개선하며, 클러스터의 영구 스토리지에 저장된 데이터의 무결성을 보장합니다.

 

GKE 예시

  • AI 및 ML 작업
  • 규모에 맞는 데이터 처리
  • 확장 가능한 온라인 게임 플랫폼
  • 과부하 발생 시 안정적인 애플리케이션

 

 

출처

728x90
728x90

 

이번에는 Docker-Compose에 대해 정리하려고 합니다.

도커 컴포즈란?


도커 컴포즈는 여러 도커 컨테이너들을 정의하고 동시에 실행할 수 있도록 하는 도구입니다. 이를 통해서 단일 애플리케이션을 구성하는 여러 컨테이너를 정의하고 한 번에 실행할 수 있도록 관리합니다.

 

도커 컴포즈를 왜 사용할까?


도커 컴포즈를 사용하는 이유는 다음과 같습니다.

  • 복잡한 애플리케이션 구성을 위한 컨테이너 관리
  • 컨테이너, 서비스, 백과 프론트간의 의존성 관리
  • 배포 용이성

 

도커 컴포즈 설치


apt-get install docker-compose
# 또는
sudo apt-get install docker-compose

# 네트워크 설치
docker network create nat

설치가 완료되면 잘 설치했는지 확인합니다.

docker-compose -v

 

도커 컴포즈 파일 문법 사용법(docker-compose.yml)


도커 컴포즈 파일은 애플리케이션의 필요한 상태, 컨테이너가 실행 중일 때 어떤 상태여야하는지 기술하는 파일이다. docker container run 명령으로 실행해야할 컨테이너 명령어들을 모여놓은 단순한 형식의 파일(.yml)입니다. 

도커는 docker-compose.yml에 작성된 내용을 통해  container들을 실행합니다. 

YML 또는 YAML 파일을 사용하는 이유 : YAML 문법은 들여쓰기를 통해 간단하게 작성할 수 있으며, JSON형식으로 변환하기 쉬워서 사용합니다.

도커 컴포즈 파일은 다음과 같은 세 개의 최상위 문(statement)으로 구성됩니다.

  • version : 도커 컴포즈 파일 형식의 버전을 가리킵니다.
  • service : 애플리케이션을 구성하는 모든 컨테이너에 대한 정보들을 열거하는 부분입니다.
  • networks : 서비스 컨테이너가 연결된 모든 도커 네트워크를 열거하는 부분입니다.

이에 대해 자세하게 설명해드리겠습니다.

 

version 

version: '3.8' # Compose 파일 버전

Docker Compose 파일의 버전을 지정합니다. 이는 Compose 파일의 형식을 정의하며, 사용할 수 있는 기능과 옵션을 결정합니다.

 

service

도커 컨테이너 생성할 때 사용하는 태그

services:
  container_name:
    image: image_name:latest

image : 컨테이너를 생성할 때 사용하는 Docker hub 또는 로컬 image를 지정합니다.

services:
  container_name:
    build: 
    	context: . #Dockerfile Directory
        dockerfile: Dockerfile

build : 로컬 디렉토리에서 Docker 이미지 빌드하며, 'context'는 Dockrefile의 디렉토리입니다.

services:
  container_name:
    port: 
    	- "80:80"

ports : 호스트와 컨테이너간의 포트 매핑을 지정합니다

services:
  container_name:
    enviorment:
    	a : b

enviroment : 컨테이너에서 사용할 환경 변수를 설정합니다. 변수 a에 b의 값을 설정합니다.

services:
  container_name:
    command: ["python", "-m", "flask", "run"]

command: 컨테이너가 시작될 때 실행할 명령어를 지정합니다.

services:
  container_name:
    depends_on:
      - db

depends_on : 서비스가 시작되기 전에 시작되어야 할 다른 서비스를 지정합니다.

healthcheck: 추후 추가 예정

restart : 추후 추가 예정

labels : 추후 추가 예정

networks : 추후 추가 예정

 

network 

networks:
  network_name:
    external:
      name: nat

external : 외부 네트워크 참조합니다.

 

예시

도커 컴포즈를 사용하면 정리가 잘되어서 시각적으로 잘 확인할 수 있습니다.

docker container run -p 8020:80 --name todo-web --network nat todo-list

위의 명령어를 아래와 같이 작성해서 실행할 수 있습니다.

# docker-compose.yml

version: '3.7'

services:
  
  todo-web:
    image: todo-list
    ports:
      - "8020:80"
    networks:
      - app-net

networks:
  app-net:
    external:
      name: nat

docker-compose.yml 파일을 만들고 명령어를 실행합니다.

docker-compose up

이를 통해 다중 컨테이너 애플리케이션을 손쉽게 정의하고 관리할 수 있습니다. 개발 환경을 환경을 최소화합니다.

 

도커 컴포즈 명령어


docker-compose up
docker-compose up -d

docker-compose up: 포어그라운드에서 모든 로그를 출력하며 실행합니다.
docker-compose up -d: 백그라운드에서 (detach 모드로) 실행합니다.

docker-compose down

docker-compose down:  실행 중인 컨테이너, 네트워크, 볼륨, 이미지 등을 중지하고 제거합니다.

docker-compose stop

docker-compose stop : 실행 중인 컨테이너, 네트워크, 볼륨, 이미지 등을 중지합니다.

docker-compose scale container_name=3

docker-compose scale web=숫자 : 특정 서비스의 컨테이너 수를 조정합니다

 

Reference : https://docs.docker.com/compose/

728x90
728x90

 

https://school.programmers.co.kr/learn/courses/30/lessons/169199

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제

리코쳇 로봇이라는 보드게임이 있습니다.

이 보드게임은 격자모양 게임판 위에서 말을 움직이는 게임으로, 시작 위치에서 목표 위치까지 최소 몇 번만에 도달할 수 있는지 말하는 게임입니다.

이 게임에서 말의 움직임은 상, 하, 좌, 우 4방향 중 하나를 선택해서 게임판 위의 장애물이나 맨 끝에 부딪힐 때까지 미끄러져 이동하는 것을 한 번의 이동으로 칩니다.

다음은 보드게임판을 나타낸 예시입니다.

...D..R
.D.G...
....D.D
D....D.
..D....

여기서 "."은 빈 공간을, "R"은 로봇의 처음 위치를, "D"는 장애물의 위치를, "G"는 목표지점을 나타냅니다.
위 예시에서는 "R" 위치에서 아래, 왼쪽, 위, 왼쪽, 아래, 오른쪽, 위 순서로 움직이면 7번 만에 "G" 위치에 멈춰 설 수 있으며, 이것이 최소 움직임 중 하나입니다.

게임판의 상태를 나타내는 문자열 배열 board가 주어졌을 때, 말이 목표위치에 도달하는데 최소 몇 번 이동해야 하는지 return 하는 solution함수를 완성하세요. 만약 목표위치에 도달할 수 없다면 -1을 return 해주세요.

 

입출력

board result
["...D..R", ".D.G...", "....D.D", "D....D.", "..D...."] 7
[".D.R", "....", ".G..", "...D"] -1

 

제한사항에 대해 보고싶으면 눌러주세요

더보기

제한사항

  • 3 ≤ board의 길이 ≤ 100
    • 3 ≤ board의 원소의 길이 ≤ 100
    • board의 원소의 길이는 모두 동일합니다.
    • 문자열은 ".", "D", "R", "G"로만 구성되어 있으며 각각 빈 공간, 장애물, 로봇의 처음 위치, 목표 지점을 나타냅니다.
    • "R"과 "G"는 한 번씩 등장합니다.

풀이방법

사용한 알고리즘 : BFS

1. board 와 같은 size인 matrix를 생성하고 99999999로 칸을 채웁니다.

-> 99999999로 되어 있는 칸은 방문하지 않은 칸을 의미합니다.

2. R의 위치를 찾고 deq에 위치를 저장합니다.

3. deq에서 popleft한 요소는 현재 위치를 가리킵니다.

  3-1 현재 위치에 G가 있다면 반복문을 탈출하고 현재 cnt를 반환합니다.

4. x, y에 dx[i],dy[i] 를 더해서 다음 위치가 D를 만나지 않거나 좌표 밖으로 나가지 않는다면 더합니다.

5. 만약 좌표 밖이나 D를 만나게 된다면 현재 위치의 cnt + 1 와 matrix에 저장되어있는 수를 비교해서 더 작은 수를 저장합니다.

6. 현재 좌표 nx, ny, cnt + 1 를 deq에 넣고  3번으로 돌아갑니다.

 

코드

from collections import deque


def solution(board):
    answer = 0
    N, M = len(board), len(board[0])
    deq = deque()
    matrix = [[999999999] * M for _ in range(N)]


    # R 찾기
    for i in range(N):
        for j in range(M):
            if board[i][j] == 'R':
                deq.append((i, j, 0))
                matrix[i][j] = 0


    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]

    while deq:
        x, y, cnt = deq.popleft()

        if board[x][y] == 'G':
            return cnt

        for i in range(4):
            nx = x
            ny = y

            while 0 <= nx + dx[i] < N and 0 <= ny + dy[i] < M and board[nx + dx[i]][ny + dy[i]] != 'D':
                nx += dx[i]
                ny += dy[i]

            if matrix[nx][ny] > cnt + 1:
                matrix[nx][ny] = cnt + 1
                deq.append((nx, ny,cnt+1))

    return -1

 

결론

BFS를 이용해서 x, y 에 dx, dy를 더하면서 멈출 때까지 반복하고 cnt를 저장하면 정말 간단하게 풀 수 있는 문제다.

처음에 그래프를 구현할 때 오랜만이라 시간이 걸리기는 했지만 약 1시간을 투자해서 문제를 풀었다. 그래프 문제를 더 열심히 풀어봐야겠다.

그리고 list가 아니라 deque를 넣어 풀어서 시간이 더 단축되었다.

728x90
728x90

오늘은 Docker Container을 SSH로 접속해서 사용할 수 있는 방법에 대해 알려드리려고 합니다. 각자의 포트를 통해 컨테이너에 따로 접속해서 서로 영향을 미치지 않고 사용할 수 있게 됩니다.

Dockerfile 작성하기


FROM python:3.12

RUN apt-get update && apt-get upgrade -y && apt-get install -y vim openssh-server net-tools

가장 최소한으로 작성하였습니다. SSH 접속을 할 때, Dockerfile은 크게 고려하지 않으셔도 됩니다. Container를 실행할 때 포트포워딩이 핵심입니다.

 

이미지 빌드하기


docker build -t ssh_image .

 

Container 실행하기


# docker run -idt -p 원하는포트:22 --name=my_ssh ssh_image
docker run -idt -p 8888:22 --name=my_ssh ssh_image

저는 8888 포트를 이용해 ssh에 접속을 할 것입니다.

이 코드를 통해 외부에서 8888포트로 들어오는 것을 컨테이너의 22번 포트로 들어오게 합니다. 이때 ssh의 기본포트는 22이므로 22로 설정했습니다.

 

Container 접속하기 및 라이브러리 설치


# Container 접속
docker exec -it my_ssh /bin/bash

컨테이너에 접속해서 root의 비밀번호를 설정합니다.

 

# 라이브러리 설치
apt-get update && apt-get upgrade -y && apt-get install -y vim openssh-server net-tools

혹시 다른 이미지를 빌드하신 분은 다음 코드를 입력해서 필요한 라이브러리를 설치합니다.

 

비밀번호 설정


# vi editor을 이용해 RootLogin을 설정합니다.
vi /etc/ssh/sshd_config

#PermitRootLogin prohibit-password를 다음과 같이 변경합니다.

그리고 :wq 입력해서 저장하고 나옵니다.

# 비밀번호 설정
passwd

passwd입력 후 비밀번호를 2번 입력합니다.

 

SSH service 켜기


service ssh start

service ssh status

netstat -ntl

다음과 같이 코드를 3개를 입력하고 출력이 된다면 성공입니다.

현재 22번 포트에 대해 입력을 받는 것을 확인할 수 있습니다.

 

SSH 접속하기


# ssh root@ip주소 -p 포트번호
ssh root@127.0.0.1 -p 8888
-> 비밀번호 입력

다음과 같이 ip주소를 입력하고 포트번호를 입력하고 비밀번호를 입력하면 ssh로 접속이 가능하게 됩니다.

 

 

728x90
728x90

오늘은 허깅페이스에 내가 만든 Dataset을 올리는 방법에 대해 소개해드리려고 합니다. 이를 통해 다른 사람들이 업로드한 데이터셋을 사용할 수 있습니다. Dataset을 업로드하려면 허깅페이스 토큰이 필요합니다. 토큰을 발급받지 않은 분들은 여기를 클릭해서 토큰을 발급해주세요

  1. 데이터셋 저장할 Repo 만들기
  2. 데이터 만들기
  3. 데이터 허깅페이스에 업로드하기

 

코드는 여기에 있습니다.

 

데이터셋 저장할 Repo 만들기


 

허깅페이스 홈페이지에 들어갑니다.

위의 이미지와 같이 프로필을 누르고 New Dataset 버튼을 누릅니다.

 

다음과 같이 저장할 Repo 이름을 작성합니다.

작성을 하고 Create dataset 버튼을 누릅니다.

그러면 다음과 같이 giliit/upload_dataset 이라는 Repo가 생성됩니다.

 

데이터 만들기


데이터셋을 생성

from datasets import Dataset

# Dataset 객체 생성(train)
sample_train = {'first' : '1', 'second' : '2', 'third' : '3'}
sample_train_dataset = Dataset.from_dict(sample_train)

# type과 dataset 내용 확인
print(type(sample_train_dataset))
print(sample_train_dataset)

# Dataset 객체 생성(test)
sample_test = {'first' : '11', 'second' : '22', 'third' : '33'}
sample_test_dataset = Dataset.from_dict(sample_test)

데이터셋을 Dictionary형태로 생성하고 Dataset에서 from_dict 함수를 통해 데이터셋 객체로 변환을 합니다.

데이터셋 train, test 두 개를 생성했습니다. 

 

데이터셋을 담는 데이터셋딕셔너리 생성

from datasets import DatasetDict

# datasetDcit 객체 생성
sample_datasetDict = DatasetDict({"train": sample_train_dataset, "test" : sample_test_dataset})

print(type(sample_datasetDict))
print(sample_datasetDict)

 

데이터셋 허깅페이스에 업로드하기


!huggingface-cli login --token hf_

hf_로 시작하는 토큰을 입력(Write로 써져 있는 Token 발급)

 

sample_datasetDict.push_to_hub('giliit/upload_dataset', token="hf_")

push_to_hub 함수, Repo와 토큰을 입력하고 함수를 실행합니다.

 

from datasets import load_dataset

dataset = load_dataset('giliit/upload_dataset')

print(dataset)

load_dataset 함수를 이용해서 데이터셋을 로드해서 확인합니다.

728x90
728x90

안녕하세요, 오늘은 허깅페이스에서 특정 모델을 읽거나, 데이터나 모델을 업로드하기 위해 필요한 Token을 발급받는 방법에 대해 알려드리려고 합니다. 글의 목차는 다음과 같습니다.

  1. 허깅페이스 가입하기
  2. 토큰 발급받기
  3. 토큰 삭제하기

 

허깅페이스 가입하기


일단 허깅페이스에 가입하기 위해 허깅페이스 홈페이지를 들어갑니다.

https://huggingface.co/

 

Hugging Face – The AI community building the future.

The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the foundation of ML tooling with the community.

huggingface.co

 

허깅페이스 홈페이지

사진을 보게 되면 우상단에 Sign Up 버튼을 눌러주세요

가입할 이메일과 비밀번호를 입력해주시고 Next 버튼을 눌러주세요

여기서 필요한 정보들을 입력해주세요.  UsernameFull name만 입력하셔도 됩니다. 그리고 Create Account 버튼을 눌러주세요. 그러면 가입이 됩니다.

가입이 끝이 아니라 확인 인증 이메일을 받아서 링크를 클릭해야 합니다. 위에 Resend confirmation email 버튼을 누르면 인증 메일이 갑니다.

다음과 같이 이메일 인증이 오는데 링크를 클릭하시면 됩니다!

 

토큰 발급하기


가입하고 홈페이지를 들어가면 다음과 같은 화면이 나오는데 여기서 Setting 버튼을 누릅니다.

 

그리고 오른쪽에 Access Tokens를 누르고, New token을 누릅니다.

Name은 Token 키를 기억하기 위해 작성하는 것이고, Type은 어떤 종류로 사용할 건지 정하는 것입니다.

  • Read : 특정 모델을 불러올 때 사용
  • Write : 내가 만든 모델 또는 데이터셋을 업로드 할 때 사용

생성하면, 다음과 같이 나옵니다. 이때 오른쪽에 Show 버튼을 누르면 Token을 확인할 수 있습니다. 그리고 Hide를 누르면 안보이게 숨길 수 있습니다.

 

토큰 삭제하기


Manage 버튼을 누릅니다. Token을 재생성하려면 위의 키를 누르면 되고, Delete 키를 누르면 키를 삭제합니다.

728x90
728x90

FastAPI를 공부하면서 pydantic 라이브러리에 대해 알게 되었고, pydantic document를 보게 되면서 공부를 하게되어서 공부하고 깨달은 점에 대해 소개하고자 작성하게 되었습니다.

 

Pydnatic overview


Pydantic은 Python의 타입 힌트를 활용하여 데이터 유효성 검사와 설정 관리를 자동화하는 강력한 라이브러리입니다. 개발자가 데이터 모델을 정의할 때 명확한 데이터 타입을 지정함으로써, Pydantic은 이 모델을 기반으로 데이터의 유효성을 자동으로 검증합니다. 이 과정에서 데이터 타입의 불일치나 필드의 누락과 같은 문제를 즉각적으로 식별하고 처리할 수 있습니다  

다시말하면, 명시해준 데이터 타입과 입력에 대해 data validation을 진행합니다. 이 때, 타입이 다르게 되면 오류를 발생시킵니다. 이와 관련되어 pydantic이 안정되고 특화되어 있고 특히 빨라서 사용합니다.

 

Pydantic Install 


파이썬 3.8 버전 이상에서 사용할 수 있습니다. 

pip install pydantic

 

Pydantic Example


예시를 통해 pydnatic에 대해 알아봅시다

Example 1

from datetime import datetime
from pydantic import BaseModel, PositiveInt


class User(BaseModel):
    id: int  # id는 int값을 가져야 함
    signup_ts: datetime | None  # signup_ts는 datetime 또는 None을 가져야 함
    tastes: dict[str, PositiveInt]  # key는 str, value는 PositiveInt를 가져야 함

external_data = {
    'id': 123,
    'signup_ts': '2019-06-01 12:22',  
    'tastes': {
        'wine': 9,
        'cabbage': '1',
    },
}

user = User(**external_data)

print(user)
# id=123 signup_ts=datetime.datetime(2019, 6, 1, 12, 22) tastes={'wine': 9, 'cabbage': 1}

다음과 같이 지정해준 type과 맞는  자료가 들어오면 정상적으로 출력된다.

 

Example 2

from datetime import datetime
from pydantic import BaseModel, ValidationError, PositiveInt 

class User(BaseModel):
    id: int
    name: str = 'John Doe'
    signup_ts: datetime | None
    tastes: dict[str, PositiveInt]

external_data = {'id': 'not an int', 'tastes': {}}  

try:
    User(**external_data)  
except ValidationError as e:
    print(e.errors())
    """
    [
        {
            'type': 'int_parsing',
            'loc': ('id',),
            'msg': 'Input should be a valid integer, unable to parse string as an integer',
            'input': 'not an int',
            'url': 'https://errors.pydantic.dev/2/v/int_parsing',
        },
        {
            'type': 'missing',
            'loc': ('signup_ts',),
            'msg': 'Field required',
            'input': {'id': 'not an int', 'tastes': {}},
            'url': 'https://errors.pydantic.dev/2/v/missing',
        },
    ]
    """

다음은 지정해준 type을 주지 않을때 오류를 발생시킨다. id에서 int형이 아닌 str형을 입력하려고 해서 ValidationError가 발생한다.

  • type : 오류의 유형을 나타냅니다. int_parsing은 정수 파싱 오류를, missing은 필수 필드가 누락됨을 의미합니다.
  • loc : 오류가 발생한 모델의 위치를 튜플로 나타냅니다. ('id',)id 필드에서 오류가 발생했음을 의미합니다.
  • msg : 오류의 세부적인 설명을 제공합니다. 예를 들어, Input should be a valid integer, unable to parse string as an integer는 입력이 유효한 정수여야 하며, 문자열을 정수로 파싱할 수 없다는 것을 알려줍니다.
  • input : 오류가 발생한 때 받은 입력 데이터를 나타냅니다. 'not an int'id 필드에 부적절한 입력이 제공되었음을 보여줍니다.
  • url : 해당 오류 유형에 대한 더 자세한 정보를 제공하는 웹 페이지의 URL입니다.

 

Validtor Example


field_validator을 이용해서 직접 validtor을 만들 수 있습니다. 다음은 그에 대한 예시입니다.

 

Field Example

from pydantic import (
    BaseModel,
    ValidationError,
    ValidationInfo,
    field_validator,
)

class UserModel(BaseModel):
    name: str
    id: int

    @field_validator('name')
    @classmethod
    def name_must_contain_space(cls, v: str) -> str:
        if ' ' not in v:
            raise ValueError('must contain a space')
        return v.title()

    # 다양한 필드들을 추가할 수 있으며, '*' 기호를 사용하면 모든 필드를 추가할 수 있습니다.
    @field_validator('id', 'name')
    @classmethod
    def check_alphanumeric(cls, v: str, info: ValidationInfo) -> str:
        if isinstance(v, str):
            # info.field_name is the name of the field being validated
            is_alphanumeric = v.replace(' ', '').isalnum()
            assert is_alphanumeric, f'{info.field_name} must be alphanumeric'
        return v
    
try:
    UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn2')
except ValidationError as e:
    print(e)
    """
    1 validation error for UserModel
      Value error, passwords do not match [type=value_error, input_value={'username': 'scolvin', '... 'password2': 'zxcvbn2'}, input_type=dict]
    """
  • @field_validators는 "클래스 메소드"이므로, 받는 첫 번째 인자는 UserModel 인스턴스가 아닌 UserModel 클래스입니다. 정확한 타입 검사를 위해 @field_validator 데코레이터 아래에 @classmethod 데코레이터를 사용하는 것을 추천합니다.
  • 두 번째 인자는 검증할 필드 값이며, 원하는 대로 이름을 지정할 수 있습니다.
  • 세 번째 인자는 존재한다면 pydantic.ValidationInfo의 인스턴스입니다.

위와 같은 방식으로 만들 수 있습니다.

 

 

출처 : https://docs.pydantic.dev/latest/

728x90
728x90

안녕하세요, 오늘은 LLM에서 dictionary를 Chat 형식으로 변환하는 apply_chat_template 함수에 대해 알아보려고 합니다. 이 함수는 최근에 Chat Bot, Chat Model이 많아지면서, Chat 형식으로 변환하는 Tokenizer의 필요로 의해 만들어졌습니다. 그래서 이 함수에 대해 자세히 설명해드리려고 합니다.

 

 

선언 방법


사용하는 방법은 쉽습니다. Chat(Dialog)에 대해 apply_chat_template()를 사용하면 바로 출력이 나옵니다. 

from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "HuggingFaceH4/zephyr-7b-alpha"
tokenizer = AutoTokenizer.from_pretrained(checkpoint, cache_dir='/home/hgjeong/hdd1/hub')

messages = [
    {
        "role": "system",
        "content": "You are a friendly chatbot who always responds in the style of a pirate",
    },
    {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
 ]
 
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")

 

매개변수 목록


    • conversation: Union[List[Dict[str, str]], "Conversation"] : 대화내용입니다.
    • add_generation_prompt (bool, optional): 프롬프트의 끝에 모델로부터 응답을 생성하는 데 사용되는 토큰을 추가할지 여부를 결정합니다.
    • tokenize (bool, defaults to True): 출력을 토큰화할지 여부를 결정합니다. False인 경우, 출력은 문자열이 됩니다.
    • padding (bool, defaults to False): 시퀀스를 최대 길이까지 패딩할지 여부를 결정합니다.
    • truncation (bool, defaults to False): 시퀀스를 최대 길이에서 잘라낼지 여부를 결정합니다.
    • max_length (int, optional):패딩에 사용할 최대 길이(토큰 단위)를 지정합니다. 지정되지 않은 경우 토크나이저의 max_length 속성이 기본값으로 사용됩니다.
    • return_tensors (str or ~utils.TensorType, optional): 특정 프레임워크의 텐서를 반환합니다. 

 

사용 예시


더보기

밑의 사용 예시 코드는 위의 이 코드가 동일하게 쓰였다고 생각하시면 됩니다.

from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "HuggingFaceH4/zephyr-7b-alpha"
tokenizer = AutoTokenizer.from_pretrained(checkpoint, cache_dir='/home/hgjeong/hdd1/hub')

messages = [
    {
        "role": "system",
        "content": "You are a friendly chatbot who always responds in the style of a pirate",
    },
    {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
 ]

tokenize 사용 여부


사용하지 않았을 때

tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True, return_tensors="pt")
print(tokenized_chat)

### 실행결과
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>

사용했을 때

tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
print(tokenized_chat)


### 실행결과 
tensor([[  523, 28766,  6574, 28766, 28767,    13,  1976,   460,   264, 10131,
         10706, 10093,   693,  1743,  2603,  3673,   297,   272,  3238,   302,
           264, 17368,   380,     2, 28705,    13, 28789, 28766,  1838, 28766,
         28767,    13,  5660,  1287, 19624,   410,  1532,   541,   264,  2930,
          5310,   297,   624,  6398, 28804,     2, 28705,    13, 28789, 28766,
           489, 11143, 28766, 28767,    13]])

Text가 토큰화된 것을 확인할 수 있습니다.

 

add_generation_prompt 사용 여부


사용하지 않았을 때

tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=False, return_tensors="pt")
print(tokenizer.decode(tokenized_chat[0]))


### 실행결과
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s> 
<|user|>
How many helicopters can a human eat in one sitting?</s>

사용했을 때

ㄷtokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
print(tokenizer.decode(tokenized_chat[0]))

### 실행 결과
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s> 
<|user|>
How many helicopters can a human eat in one sitting?</s> 
<|assistant|>

<| assistant |> 가 추가되어 있는 것을 확인할 수 있습니다.

 

결론


tokenizer에서 apply_chat_template를 이용해서 Chat(Dialog)를 다음과 같이 간편하게 변환할 수 있습니다. 이를 통해서 Chat(Dialog)를 모델에 입력할 때 다음과 같이 사용할 수 있게 있습니다. 감사합니다.

 

출처

 

728x90