ASG (Auto Scaling Group) Launch Template 기반으로 EC2를 자동 생성/삭제/관리하는 서비스 Launch Template이란? ASG가 EC2를 만들 때 사용하는 설계도 어떤 OS를 사용할지(Amazon Linux 2023) 어떤 사양인지(t4g.small) 어떤 트래픽을 허용할지(보안 그룹) 어떤 AWS 권한을 가질지(IAM) EC2 시작 시 실행할 스크립트(User Data) 핵심 설정 Desired: 지금 유지하고 싶은 인스턴스 수(인스턴스 장애 시 새 EC2 생성) Min: 최소 인스턴스 수(트래픽 줄면 Min 수준까지 인스턴스 제거) Max: 최대 인스턴스 수(부하 발생 시 Max 범위 내에서 자원 추가)
2026년 9월 15일 TypeSafe AI는 Jev 라는 새로운 AI 모델을 공개했다. Jev는 ChatGPT나 Claude처럼 텍스트를 생성하는 LLM이 아니다. TypeSafe는 Jev를 첫 번째 System One Model 이라고 정의한다. 출처: TypeSafe AI Documentation - Introduction 핵심 아이디어는 간단하다. LLM이 자연어를 생성하는 모델이라면, Jev는 소프트웨어가 바로 사용할 수 있는 결정을 내리는 모델이다. TypeSafe는 Jev를 다음과 같이 표현한다. unstructured state in, typed probabilistic decisions out. 즉, 자연어나 구조화된 상태(state)를 입력하면 타입이 정의된 결정과 그 확률 을 반환한다. 이 글에서는 Jev가 기존 LLM과 무엇이 다른지 살펴보고, Python SDK를 사용해 실제로 호출하는 방법까지 정리한다. 1. 왜 Jev가 등장했을까? LLM은 기본적으로 text generation model 이다. 예를 들어 고객 문의를 분류한다고 해보자. 사용자: 결제가 두 번 됐어요. 환불해주세요. 질문: 이 문의를 담당해야 하는 부서를 JSON으로 반환해줘. 가능한 부서: billing technical sales LLM은 내부적으로 다음과 같이 토큰을 하나씩 생성한다. { "department": "billing" } 이 방식은 사람이 읽는 답변을 만들 때는 매우 유용하다. 하지만 소프트웨어의 의사결정 모듈로 사용하면 약간 어색한 부분이 생긴다. Text ↓ LLM ↓ Generated String ↓ JSON Parsing ↓ Schema Validation ↓ Application Logic 즉 우리가 실제로 원하는 것은 billing 이라는 결정 인데, 모델은 우선 문자열을 생성하고 우리는 다시 그 문자열을 프로그램이 사용할 수 있는 데이터로 변환해야 한다. TypeSafe는 이를 LLM과 software automation 사이의 interface mismatch 라고 본다. Jev는 이 과정을 다음처럼 바꾼다. State ↓ Jev ↓ Typed Decision ↓ Application Logic 텍스트를 생성한 뒤 파싱하는 것이 아니라 처음부터 구조화된 decision 을 반환하는 것이다. 2. Jev는 무엇인가? Jev는 TypeSafe AI가 개발한 첫 번째 System One Model 이다. System One이라는 이름은 Daniel Kahneman의 Thinking, Fast and Slow 에서 등장하는 System 1에서 가져왔다. 빠르고 직관적인 판단을 담당하는 인간의 사고 방식을 모델 설계 철학에 차용한 것이다. Jev가 목표로 하는 것은 다음과 같은 문제다. classification routing scoring ranking verification guardrail branching 예를 들어 고객 문의가 들어왔을 때 다음 질문을 동시에 판단할 수 있다. 어느 부서가 담당해야 하는가? → billing / technical / sales 고객은 얼마나 화가 났는가? → calm / frustrated / angry 긴급한 요청인가? → probability 0~1 여기서 중요한 점은 Jev가 답변을 문장으로 생성하지 않는다는 것 이다. 대신 개발자가 미리 정의한 output space에서 결과를 선택한다. 3. LLM과 Jev의 가장 큰 차이 두 모델의 차이를 간단히 정리하면 다음과 같다. LLM Jev 주요 목적 Text Generation Decision 출력 String / Tokens Typed Value 출력 방식 Autoregressive Parallel Parsing 필요할 수 있음 불필요 후보 공간 사실상 무제한 개발자가 정의 Probability 일반적으로 직접 노출하지 않음 기본 제공 Confidence 별도 추정 필요 Choice/Score에서 제공 적합한 작업 대화, 글쓰기, 코드 생성, reasoning classification, routing, scoring, verification LLM은 다음 토큰을 반복적으로 예측한다. P(x_t | x_1, ..., x_{t-1}) 따라서 문장이 길어질수록 여러 decoding step이 필요하다. 반면 TypeSafe에 따르면 Jev는 여러 decision을 parallel sampling 방식으로 처리하며, 여러 질문을 하나의 요청에 넣더라도 응답시간 증가가 상대적으로 작도록 설계됐다. TypeSafe가 공개한 자료에서는 System One task 기준으로 Jev의 응답 시간이 약 70–500ms 수준이라고 설명한다. 다만 이는 TypeSafe 측 측정값이며 네트워크 위치, 요청 구조, 모델 버전 등에 따라 실제 latency는 달라질 수 있다. 4. Jev의 핵심 구조: State + Questions Jev API를 이해하기 위해 가장 중요한 개념은 단 두 가지다. state questions State state 는 Jev가 판단해야 하는 대상이다. 예를 들어 고객 문의라면 다음 문장이 state가 된다. I've been trying to connect my Stripe account for 3 days. The integration keeps failing and I'm losing sales. Questions questions 는 이 state를 보고 Jev가 판단해야 하는 항목이다. 예를 들어: 어느 부서가 담당해야 하는가? 고객의 frustration 정도는? 긴급한 요청인가? Jev는 이 질문들을 각각 판단한다. 공식 문서에서는 각 question이 동일한 state를 기준으로 독립적으로 평가되며 병렬로 처리된다 고 설명한다. 따라서 하나의 복잡한 질문을 만드는 것보다 판단 기준을 여러 atomic question으로 분리하는 것을 권장한다. 5. Jev의 세 가지 Primitive 현재 TypeSafe API에는 세 가지 핵심 question type이 존재한다. Choice Score Noul 각각 역할이 명확하다. Type 목적 예 Choice 여러 후보 중 하나 선택 어떤 부서로 보낼까? Score 순서가 있는 단계 평가 고객은 얼마나 화났나? Noul Yes/No 명제의 확률 환불을 요청했는가? 6. Choice: 여러 후보 중 하나 선택하기 Choice 는 전형적인 classification 문제에 해당한다. 예를 들어 고객 문의를 세 부서 중 하나로 분류한다고 해보자. from typesafe_sdk import Choice, TypeSafeClient client = TypeSafeClient() response = client.system_one( state="My payment was charged twice. I want a refund.", questions={ "department": Choice( instructions="Which team should handle this request?", criteria={ "billing": "Payment, subscription, invoice, or refund issues", "technical": "Software bugs or technical problems", "sales": "Pricing or purchasing questions", }, ) }, ) answer = response.answers["department"] print(answer.choice) print(answer.probabilities) print(answer.confidence) 결과는 개념적으로 다음과 같다. choice = "billing" probabilities = { "billing": 0.91, "technical": 0.03, "sales": 0.06 } confidence = 0.87 Choice는 단순히 가장 높은 후보만 반환하는 것이 아니다. 전체 후보의 probability distribution 도 함께 받을 수 있다. choice 는 이들 중 가장 높은 확률을 가진 option이다. 따라서 다음과 같은 로직도 만들 수 있다. if answer.confidence < 0.5: send_to_human_review() elif answer.choice == "billing": send_to_billing() elif answer.choice == "technical": send_to_technical() 이 부분이 일반적인 LLM classification과 상당히 다른 지점이다. 모델의 판단을 바로 실행하는 것이 아니라 uncertainty를 application logic에 포함할 수 있다. 7. Noul: Yes / No를 확률로 판단하기 Noul 은 조금 독특한 이름의 primitive다. 역할 자체는 간단하다. 주어진 명제가 참일 확률을 0~1 사이 값으로 반환한다. 예를 들어 다음 고객 문의가 있다고 하자. I have asked three times already. Can I please talk to a real person? 다음과 같이 질문할 수 있다. from typesafe_sdk import Noul, TypeSafeClient client = TypeSafeClient() response = client.system_one( state=""" I have asked three times already. Can I please talk to a real person? """, questions={ "needs_human": Noul( instructions="Is the customer asking for a human agent?" ) }, ) probability = response.answers["needs_human"].noul print(probability) 예를 들어 결과가 0.99 라면 P(customer wants human | state) ≈ 0.99 와 같은 의미로 사용할 수 있다. 공식 문서 예시에서도 실제 해당 문장에 대해 0.99 가 반환된다. 따라서 application에서는 threshold만 설정하면 된다. if probability > 0.9: route_to_human() else: route_to_bot() 물론 실제 production 환경에서는 0.9라는 threshold를 임의로 정하기보다 validation set을 기반으로 조정해야 한다. 특히 false positive와 false negative의 비용이 다르다면 threshold 역시 달라져야 한다. 예를 들어 safety detection이라면 false negative의 비용이 크기 때문에 threshold를 낮추는 것이 합리적일 수 있다. TypeSafe 문서 역시 threshold는 decision error의 비용에 따라 설정해야 한다 고 권장한다. 8. Score: 순서가 있는 정도를 평가하기 Choice가 categorical classification이라면 Score는 ordinal prediction 에 가깝다. 예를 들어 고객의 frustration을 평가할 수 있다. from typesafe_sdk import Score frustration = Score( instructions="How frustrated does the customer appear?", criteria=[ "Calm, simply stating the issue", "Frustrated but still civil", "Very angry or aggressive", ], ) criteria 에는 낮은 수준부터 높은 수준 순서로 description을 작성한다. 공식 문서상 Score에는 최소 2개, 최대 10개의 level을 지정할 수 있다. 결과는 예를 들어 다음과 같이 나온다. score = 1.2 probabilities = { 0: 0.05, 1: 0.70, 2: 0.25 } 여기서 재미있는 점은 Score 값이 반드시 정수일 필요가 없다는 것이다. 두 level 사이의 확률 분포를 기반으로 중간값을 표현할 수도 있다. 9. 여러 질문을 한 번에 요청하기 Jev의 중요한 특징 중 하나는 여러 decision을 하나의 request에 넣을 수 있다는 것이다. 예를 들어 고객 문의 분석 시스템을 다음처럼 구성할 수 있다. from typesafe_sdk import Choice, Noul, Score, TypeSafeClient client = TypeSafeClient() ticket = """ I've been trying to connect my Stripe account for three days. The integration keeps failing and I'm losing sales. Please help ASAP. """ response = client.system_one( state=ticket, questions={ "department": Choice( instructions="Which team should handle this?", criteria={ "billing": "Payment or subscription issues", "technical": "Bugs or integration problems", "sales": "Pricing or purchasing questions", }, ), "frustration": Score( instructions="How frustrated does the customer appear?", criteria=[ "Calm", "Frustrated", "Very angry", ], ), "urgent": Noul( instructions="Does this message express urgency?" ), }, ) 이렇게 하면 department frustration urgent 세 가지 판단을 한 번의 요청으로 얻는다. 공식 문서는 여러 question을 한 request에 넣는 것을 권장한다. 각 question은 같은 state에 대해 독립적으로 평가되며 병렬 처리되기 때문에, question 수를 늘리더라도 latency가 크게 증가하지 않는 것이 Jev 설계의 특징이라고 설명한다. 다만 추가 question 역시 token cost에는 반영된다. 10. Jev 시작하기 Jev를 사용하는 방법은 크게 두 가지다. 가볍게 테스트만 해보고 싶다면 TypeSafe Playground 를 사용할 수 있고, 실제 코드에서 사용하려면 API Key를 발급받아 SDK 또는 REST API로 호출 해야 한다. 공식 문서 역시 먼저 Playground에서 Jev를 시험해본 뒤 API를 사용하는 흐름을 안내한다. Step 0. Playground에서 먼저 사용해보기 처음부터 Python 코드를 작성할 필요는 없다. TypeSafe Console의 Playground에 로그인하면 state 와 question 을 직접 입력해 Jev의 결과를 확인할 수 있다. 예를 들어 state에 다음 내용을 입력한다. Hi, I've been trying to connect my Stripe account for 3 days. The integration keeps failing. I'm losing sales. Please help ASAP. 그리고 Noul question을 하나 추가한다. Does this message express urgency? 그러면 Jev가 해당 명제가 참일 확률을 반환한다. 공식 Quick Start에서는 Jev를 처음 접한다면 이 Playground 방식으로 먼저 Noul , Choice , Score 를 시험해보는 방법을 제시한다. Step 1. TypeSafe 계정 생성 및 API Key 발급 Python SDK나 REST API를 사용하려면 TypeSafe API Key가 필요하다. TypeSafe Console에 로그인한 뒤 Dashboard에서 API Key를 발급한다. 발급받은 키는 다음처럼 생긴 인증 정보이며 외부에 공개하면 안 된다. your-typesafe-api-key 특히 GitHub에 코드를 올릴 때 다음처럼 API Key를 코드에 직접 작성하는 것은 피하는 것이 좋다. # 권장하지 않음 client = TypeSafeClient( api_key="your-api-key" ) 대신 환경 변수로 관리한다. Step 2. API Key를 환경 변수에 등록하기 macOS나 Linux에서는 터미널에서 다음과 같이 설정할 수 있다. export TYPESAFE_API_KEY="your-api-key" Windows PowerShell이라면 다음과 같이 설정할 수 있다. $env:TYPESAFE_API_KEY="your-api-key" Python에서 제대로 등록됐는지 확인하고 싶다면: import os print(os.getenv("TYPESAFE_API_KEY")) 값이 출력된다면 설정된 것이다. 단, 실제 개발 환경에서는 API Key 전체를 로그에 출력하지 않는 것이 좋다. TypeSafe Python SDK의 TypeSafeClient() 는 기본적으로 TYPESAFE_API_KEY 환경 변수를 자동으로 읽는다. 따라서 이후 코드에서 API Key를 매번 전달할 필요가 없다. Step 3. Python SDK 설치 현재 공식 SDK는 Python 3.10 이상을 요구한다. pip를 사용하는 경우: pip install typesafe-sdk uv를 사용한다면: uv add typesafe-sdk Step 4. 가장 간단한 Jev 호출 설치가 끝났다면 다음 코드만으로 Jev를 호출할 수 있다. from typesafe_sdk import Noul, TypeSafeClient client = TypeSafeClient() response = client.system_one( state="The customer wants a refund because they were charged twice.", questions={ "refund_request": Noul( instructions="Is the customer requesting a refund?" ) }, ) print(response.answers["refund_request"].noul) 여기서 client = TypeSafeClient() 에 API Key가 보이지 않는 이유는 SDK가 앞서 설정한 TYPESAFE_API_KEY 환경 변수를 자동으로 읽기 때문이다. 또한 모델을 별도로 지정하지 않으면 현재 공식 문서 기준으로 기본 모델인 jev-latest 가 사용된다. 전체 과정을 정리하면 처음 사용하는 경우 다음 순서만 따르면 된다. 1. TypeSafe Console 가입 및 로그인 ↓ 2. Playground에서 Jev 테스트 ↓ 3. Dashboard에서 API Key 발급 ↓ 4. TYPESAFE_API_KEY 환경 변수 등록 ↓ 5. pip install typesafe-sdk ↓ 6. TypeSafeClient() 생성 ↓ 7. client.system_one() 호출 Playground에서 테스트할 때는 별도의 Python 환경이나 SDK가 필요하지 않다. 반면 실제 애플리케이션에서 Jev를 호출하려면 API Key를 발급받아 인증해야 한다. 공식 REST API에서도 다음과 같이 Bearer 인증을 사용한다. Authorization: Bearer <API_KEY> 공식 API endpoint는 현재 다음과 같다. POST https://api.typesafe.ai/v1/systemone 이제 API Key 설정이 끝났다면 Choice , Score , Noul 을 실제 코드에서 사용할 수 있다. 11. HTTP API로 직접 호출하기 SDK를 사용하지 않고 REST API를 직접 호출하는 것도 가능하다. endpoint는 현재 다음과 같다. POST https://api.typesafe.ai/v1/systemone Authorization header에는 Bearer token을 사용한다. 예를 들어: curl -X POST https://api.typesafe.ai/v1/systemone \ -H "Authorization: Bearer $TYPESAFE_API_KEY" \ -H "Content-Type: application/json" \ -d '{
[머신러닝] 4강 비지도학습: 군집화 (Clustering) 핵심 정리 📌 오늘의 학습 목표 지도학습(분류)과 비지도학습(군집화)의 기본 개념 차이를 구분하고, 군집화의 필요성을 이해한다. K-평균(K-Means) 군집화 알고리즘의 4단계 수행 과정과 주요 특징을 설명할 수 있다. 계층적 군집화(Hierarchical Clustering)의 두 가지 접근 방식(병합적 vs 분할적)과 덴드로그램의 역할을 파악한다. 1. 핵심 개념 요약 0. 비지도학습과 군집화(Clustering)란? 개념 및 필요성 : 입력 데이터 간의 유사성을 기준으로 데이터를 몇 개의 그룹으로 나누는 문제입니다. 목표 출력값(정답 레이블)이 없기 때문에 비지도학습(Unsupervised Learning) 에 속하며, 정답이 없거나 데이터 레이블링에 비용이 많이 드는 경우 유용하게 활용됩니다. 주요 응용 분야 : 영상 데이터 그룹핑, 영상 분할(Image Segmentation) 등에 적용됩니다. 1. K-평균 군집화 (K-Means Clustering) 개념 : 주어진 데이터 집합을 $K$개의 대표 벡터(평균)를 중심으로 $K$개의 그룹으로 묶는 대표적인 군집화 알고리즘입니다. 수행 4단계 과정 : 초기화 (Initialization) : 데이터 집합에서 임의로 $K$개의 초기 대표 벡터 $\mathbf{m}_1, \mathbf{m}_2, \dots, \mathbf{m}_K$를 선택합니다. 데이터 그룹핑 (Data Grouping) : 각 데이터 $\mathbf{x}_j$와 $K$개의 대표 벡터 간 거리 $d(\mathbf{x}_j, \mathbf{m}_k)$를 계산하고, 가장 가까운 대표 벡터를 가진 클러스터 $C_k$에 배정합니다. $$C_k = { \mathbf{x}_j \mid d(\mathbf{x}_j, \mathbf{m}_k) \le d(\mathbf{x}_j, \mathbf{m}_i), , \forall i }$$ 대표 벡터 수정 (Updating Centroids) : 새롭게 형성된 클러스터에 속한 데이터들의 평균을 구해 대표 벡터를 다시 갱신합니다. 반복 여부 결정 (Iteration) : 대표 벡터의 변화가 없거나 수렴할 때까지 2단계와 3단계를 반복합니다. 특징 및 한계 : 반복 과정을 거치며 지역 극소점(Local Minima) 에 도달하는 것을 보장합니다. 초기 대표 벡터 위치 설정에 매우 의존적이며, 적절한 $K$값을 사전에 설정하기 어렵다는 한계가 있습니다. 2. 계층적 군집화 (Hierarchical Clustering) 개념 : 큰 군집이 작은 군집을 포함하는 형태로 계층(트리 구조)을 이루며 군집화를 수행하는 방식입니다. 접근 방식 : 병합적 방법 (Bottom-Up) : 각 데이터를 독립된 개별 군집으로 시작하여, 가장 가까운 군집 쌍을 순차적으로 합쳐 하나의 큰 군집을 만드는 실용적인 방식입니다. 분할적 방법 (Top-Down) : 전체 데이터를 하나의 큰 군집으로 시작하여 점차 쪼개어 나가는 방식으로, 계산량이 많아 다소 비실용적입니다. 군집 간 거리 계산 및 덴드로그램 : 군집 간 거리를 계산할 때 와드(Ward's) 방법 등 다양한 거리 측정 기준을 사용합니다. 계층적 군집화 결과는 트리 형태의 덴드로그램(Dendrogram) 으로 시각화되며, 클러스터 간 거리가 유지되는 지점을 잘라 적합한 군집의 수를 결정합니다. 2. 오늘 배운 내용 요약 군집화는 정답 레이블이 없는 데이터에서 데이터 간 유사도를 측정하여 대표 벡터 기반(K-Means) 또는 계층 구조(Hierarchical) 형태로 의미 있는 그룹을 형성하는 비지도학습 기법입니다.
블로그에 구독 메일을 붙이면서 발송은 Resend라는 서비스에 맡겼습니다. 구독자에게 보이는 발신 주소는 newsletter@wonkooklee.com 이지만, 메일을 실제로 전달하는 것은 Resend의 서버입니다. 저는 메일 서버를 운영하지 않습니다. 그런데도 Gmail은 이 메일이 정말 wonkooklee.com에서 왔는지 판단해야 합니다. 보낸 사람 칸에 적힌 From 은 그 근거가 되지 못합니다. 메일을 만드는 쪽이 적는 값이라, 제 도메인을 사칭하려는 사람도 자기 서버에서 똑같이 적을 수 있습니다. 그래서 수신 서버는 메일 안의 주장과 별개로, 도메인 관리자만 바꿀 수 있는 DNS 설정을 조회해 검사합니다. 글은 구독 메일 한 통을 따라가며 그 검사를 정리합니다. SPF가 확인하는 주소는 화면에 보이는 From이 아니라 배달 실패 알림을 받을 MAIL FROM 입니다 DKIM은 서명의 d= 와 s= 로 DNS에서 공개키를 찾습니다. 그래서 Zoho와 Resend가 한 도메인에 각자 키를 둘 수 있습니다 남의 도메인으로 SPF와 DKIM을 모두 통과한 사칭 메일이 DMARC에서 걸리는 이유: 인증한 도메인과 From의 정렬(alignment) SMTP는 From보다 MAIL FROM 을 먼저 보냅니다. 이 순서 때문에 SPF를 -all 로 끝내면 DKIM으로 DMARC를 통과했을 메일이 From이 도착하기도 전에 거부되고, 집계 보고서에도 남지 않을 수 있습니다 p=none 으로 시작해 집계 보고서( rua )로 놓친 발송 경로를 찾은 뒤 quarantine 이나 reject 를 검토하는 순서 실제로 조회한 wonkooklee.com의 SPF·DKIM·DMARC 설정과, 레코드만 봐서는 알 수 없는 것 Gmail에 발신자 로고를 띄우는 BIMI가 p=none 과 로고 파일만으로는 요건을 채우지 못하는 이유 SPF와 DKIM은 각자 확인해야 할 것을 제대로 확인합니다. 다만 둘 다 독자가 보는 주소까지 확인하지는 않고, 그 연결은 DMARC가 맡습니다. 그리고 DMARC를 통과했다고 메일 내용을 믿어도 되는 것은 아닙니다. 공격자가 자기 도메인으로 보낸 메일도 발신 인증은 정상적으로 통과합니다. 확인되는 것은 보낸 도메인까지이고, 본문과 링크가 안전한지는 그 밖의 문제로 남습니다. 전문은 블로그에서 이어집니다 👇 ▶ 내 도메인에서 보낸 이메일은 어떻게 진짜임을 증명할까 (전문 보기) 다른 글도 블로그에서 이어집니다 · 전체 목차 보기
백트래킹(Backtracking) 1. 백트래킹이란? 백트래킹은 여러 가지 선택지가 존재하는 상황에서 하나를 선택하고, 그 선택을 기반으로 다음 선택을 이어가며 정답을 찾는 방식이다. 탐색을 진행하다가 하나의 경로가 끝나면 이전 상태로 돌아가 다른 선택지를 다시 탐색한다. 즉, 백트래킹의 핵심은 다음과 같다. 선택 → 탐색 → 선택 취소 → 다른 선택 예를 들어 [1, 2, 3] 을 이용해 순열을 만든다고 생각하면, 1 선택 └─ 2 선택 └─ 3 선택 탐색 완료 ↓ 2 선택 취소 ↓ 3 선택 처럼 이전 선택을 취소하고 다른 경우를 다시 탐색한다. 2. 백트래킹과 DFS의 차이 DFS(Depth First Search)는 한 방향으로 최대한 깊게 들어가며 탐색하는 탐색 방식 이다. 백트래킹은 DFS를 이용해 하나의 선택을 탐색한 뒤, 탐색이 끝나면 이전 상태로 되돌아가 다른 선택을 시도하는 문제 해결 방식 이다. DFS = 한 방향으로 깊게 탐색 백트래킹 = 선택 → 깊게 탐색 → 선택 취소 → 다른 선택 DFS 역시 탐색이 끝나면 이전 노드로 돌아온다. 하지만 백트래킹에서는 단순히 탐색 위치만 돌아가는 것이 아니라, 탐색 전에 변경했던 상태까지 원상복구 한다는 점이 중요하다. 3. 가지치기(Pruning) 백트래킹 과정에서 현재 선택이 정답으로 이어질 가능성이 없다고 판단되면, 해당 경로를 더 이상 탐색하지 않을 수 있다. 이것을 가지치기(Pruning) 라고 한다. 현재 경로 ↓ 정답 가능성 없음 ↓ 더 이상 탐색하지 않음 가지치기를 사용하면 모든 경우를 끝까지 확인하지 않아도 되기 때문에 탐색 횟수를 크게 줄일 수 있다. 백트래킹과 가지치기는 같은 개념은 아니다. 백트래킹 = 탐색 후 이전 상태로 돌아가는 것 가지치기 = 가능성이 없는 경로를 탐색하지 않는 것 4. 백트래킹 알고리즘 절차 백트래킹은 일반적으로 다음과 같은 과정으로 진행된다. 상태 공간 트리를 DFS 방식으로 탐색한다. 현재 선택이 유망한지 확인한다. 유망하다면 다음 단계로 탐색한다. 유망하지 않다면 해당 경로의 탐색을 중단한다. 탐색이 끝나면 이전 상태로 돌아가 다른 선택지를 탐색한다. 여기서 유망하다 는 것은 현재 선택을 계속 이어갔을 때 정답이 될 가능성이 있다는 의미이다. 5. 대표 문제 - N-Queen N-Queen은 N × N 체스판에 N개의 퀸을 서로 공격할 수 없도록 배치하는 문제이다. 퀸은 다음 방향으로 이동할 수 있다. 같은 열 왼쪽 대각선 오른쪽 대각선 따라서 새로운 퀸을 놓을 때 이 세 방향에 다른 퀸이 존재하는지 검사해야 한다. 8-Queen N = 8 인 경우 가능한 배치의 개수는 92개 이다. # 입력 8을 줌 n = int(input()) vertical = [0] * n seven = [0] * (2 * n) five = [0] * (2 * n) count = 0 def backtracking(level): global count if level == n: count += 1 return for j in range(n): # 같은 열 확인 if vertical[j] == 1: continue # 대각선 확인 if seven[level + j] == 1 or five[level - j + n] == 1: continue vertical[j] = 1 seven[level + j] = 1 five[level - j + n] = 1 backtracking(level + 1) # 이전 상태로 복구 vertical[j] = 0 seven[level + j] = 0 five[level - j + n] = 0 backtracking(0) print(count) 출력 6. 코드에서 각 개념 구분하기 N-Queen 코드에는 완전탐색, DFS, 가지치기, 백트래킹이 모두 들어 있다. 완전탐색 for j in range(n): 현재 행에서 퀸을 놓을 수 있는 모든 열을 하나씩 확인한다. 즉, 가능한 선택지를 전부 시도한다. DFS backtracking(level + 1) 현재 행에 퀸을 놓은 뒤 다음 행으로 넘어가 깊게 탐색한다. 가지치기 if vertical[j] == 1: continue if seven[level + j] == 1 or five[level - j + n] == 1: continue 이미 다른 퀸의 공격 범위에 있는 위치라면 해당 경우는 정답이 될 수 없으므로 탐색하지 않는다. 백트래킹 vertical[j] = 0 seven[level + j] = 0 five[level - j + n] = 0 현재 선택에 대한 탐색이 끝나면 퀸을 놓기 전 상태로 원상복구한다. 이후 반복문에서 다음 위치를 선택해 다시 탐색한다.
NAT Gateway 프라이빗 서브넷 내의 인스턴스가 외부 인터넷과 통신할 수 있도록 네트워크 주소 변환(NAT)을 수행하는 클라우드 네트워킹 서비스 아웃바운드 전용: 프라이빗 서브넷 내부에서 외부 인터넷을 호출할 수는 있지만, 외부 이넡넷에서 프라이빗 서브넷 내부 인스턴스에 접속할 수는 없다. Zonal Gateway, Regional Gateway Zonal NAT Gateway 기존에 있던 방식 AZ마다 설정해주어야 함 Regional NAT Gateway 최신 버전 Region 전체를 커버하는 NAT Gateway 하나만 만들면 별다른 설정 없이도 AWS가 AZ별로 알아서 확장해줌 ECR에서 Docker Image를 pull하기 위해서 NAT Gateway가 필요하다!