<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ha2yong 님의 블로그</title>
    <link>https://ha2yong.tistory.com/</link>
    <description>ha2yong 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Thu, 18 Jun 2026 19:16:42 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ha2yong</managingEditor>
    <item>
      <title>머신러닝 / Pipeline / ColumnTransformer / GridSearchCV</title>
      <link>https://ha2yong.tistory.com/185</link>
      <description>&lt;h1 data-end=&quot;270&quot; data-start=&quot;201&quot;&gt;머신러닝 파이프라인(Pipeline), 컬럼 변환기(ColumnTransformer), GridSearchCV 완전 정리&lt;/h1&gt;
&lt;p data-end=&quot;427&quot; data-start=&quot;272&quot; data-ke-size=&quot;size16&quot;&gt;본 문서는 머신러닝 실무에서 가장 많이 사용되는&lt;br /&gt;&lt;b&gt;Pipeline&lt;/b&gt;, &lt;b&gt;ColumnTransformer&lt;/b&gt;, &lt;b&gt;GridSearchCV&lt;/b&gt;를&lt;br /&gt;정의부터 사용법, 주요 메소드, 실전 예시, 그리고 데이터 전처리 및 모델 학습 팁까지&lt;br /&gt;하나의 문서로 정리한 자료입니다.&lt;/p&gt;
&lt;p data-end=&quot;472&quot; data-start=&quot;429&quot; data-ke-size=&quot;size16&quot;&gt;이 글만 읽으면 머신러닝 워크플로우 전체를 이해하고 바로 적용할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;518&quot; data-start=&quot;474&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;533&quot; data-start=&quot;520&quot;&gt;1. Pipeline&lt;/h1&gt;
&lt;h2 data-end=&quot;554&quot; data-start=&quot;535&quot; data-ke-size=&quot;size26&quot;&gt;1-1. Pipeline이란?&lt;/h2&gt;
&lt;p data-end=&quot;623&quot; data-start=&quot;555&quot; data-ke-size=&quot;size16&quot;&gt;여러 단계의 데이터 전처리와 모델 학습 과정을&lt;br /&gt;하나의 흐름(Workflow)으로 묶어주는 Scikit-Learn 기능.&lt;/p&gt;
&lt;p data-end=&quot;735&quot; data-start=&quot;625&quot; data-ke-size=&quot;size16&quot;&gt;기존 방식(수동으로 전처리 &amp;rarr; 모델 학습)은&lt;br /&gt;GridSearchCV, Cross Validation에 문제를 일으킬 수 있지만&lt;br /&gt;&lt;b&gt;Pipeline은 모든 단계를 일관된 구조로 관리&lt;/b&gt;해준다.&lt;/p&gt;
&lt;h2 data-end=&quot;754&quot; data-start=&quot;737&quot; data-ke-size=&quot;size26&quot;&gt;1-2. 언제 사용하는가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;905&quot; data-start=&quot;755&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;788&quot; data-start=&quot;755&quot;&gt;전처리 + 모델 학습을 하나의 작업으로 묶고 싶을 때&lt;/li&gt;
&lt;li data-end=&quot;838&quot; data-start=&quot;789&quot;&gt;GridSearchCV가 전처리까지 포함하여 교차검증을 수행하도록 만들고 싶을 때&lt;/li&gt;
&lt;li data-end=&quot;873&quot; data-start=&quot;839&quot;&gt;train/test 간 데이터 누수를 방지하고 싶을 때&lt;/li&gt;
&lt;li data-end=&quot;905&quot; data-start=&quot;874&quot;&gt;모델 구성과 파라미터 튜닝을 체계적으로 하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;921&quot; data-start=&quot;907&quot; data-ke-size=&quot;size26&quot;&gt;1-3. 주요 메소드&lt;/h2&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1114&quot; data-start=&quot;922&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;메소드&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;982&quot; data-start=&quot;953&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;967&quot; data-start=&quot;953&quot;&gt;fit(X, y)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;982&quot; data-start=&quot;967&quot;&gt;전체 파이프라인 학습&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1008&quot; data-start=&quot;983&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;998&quot; data-start=&quot;983&quot;&gt;predict(X)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1008&quot; data-start=&quot;998&quot;&gt;예측값 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1042&quot; data-start=&quot;1009&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1030&quot; data-start=&quot;1009&quot;&gt;predict_proba(X)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1042&quot; data-start=&quot;1030&quot;&gt;확률 기반 예측&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1077&quot; data-start=&quot;1043&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1059&quot; data-start=&quot;1043&quot;&gt;named_steps&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1077&quot; data-start=&quot;1059&quot;&gt;파이프라인 내부 단계 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1114&quot; data-start=&quot;1078&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1103&quot; data-start=&quot;1078&quot;&gt;set_params(**kwargs)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1114&quot; data-start=&quot;1103&quot;&gt;파라미터 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1132&quot; data-start=&quot;1116&quot; data-ke-size=&quot;size26&quot;&gt;1-4. 기본 사용 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1763460605539&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

numeric_features = ['lead_time', 'adr']
categorical_features = ['hotel', 'deposit_type']

preprocessor = ColumnTransformer([
    ('num', StandardScaler(), numeric_features),
    ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
])&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1498&quot; data-start=&quot;1454&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;1522&quot; data-start=&quot;1500&quot;&gt;2. ColumnTransformer&lt;/h1&gt;
&lt;h2 data-end=&quot;1551&quot; data-start=&quot;1524&quot; data-ke-size=&quot;size26&quot;&gt;2-1. ColumnTransformer란?&lt;/h2&gt;
&lt;p data-end=&quot;1585&quot; data-start=&quot;1552&quot; data-ke-size=&quot;size16&quot;&gt;컬럼별로 다른 전처리 방법을 적용할 수 있도록 해주는 도구.&lt;/p&gt;
&lt;p data-end=&quot;1589&quot; data-start=&quot;1587&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1660&quot; data-start=&quot;1590&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1619&quot; data-start=&quot;1590&quot;&gt;숫자 컬럼 &amp;rarr; 표준화(StandardScaler)&lt;/li&gt;
&lt;li data-end=&quot;1644&quot; data-start=&quot;1620&quot;&gt;범주형 컬럼 &amp;rarr; OneHotEncoder&lt;/li&gt;
&lt;li data-end=&quot;1660&quot; data-start=&quot;1645&quot;&gt;특정 컬럼만 log 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1675&quot; data-start=&quot;1662&quot; data-ke-size=&quot;size26&quot;&gt;2-2. 주요 기능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1763&quot; data-start=&quot;1676&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1705&quot; data-start=&quot;1676&quot;&gt;컬럼별로 서로 다른 Pipeline 적용 가능&lt;/li&gt;
&lt;li data-end=&quot;1738&quot; data-start=&quot;1706&quot;&gt;수치/카테고리/날짜/특수 컬럼을 자동 분리하여 처리&lt;/li&gt;
&lt;li data-end=&quot;1763&quot; data-start=&quot;1739&quot;&gt;전처리 후 전체 특징 벡터를 하나로 결합&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;1779&quot; data-start=&quot;1765&quot; data-ke-size=&quot;size26&quot;&gt;2-3. 주요 메소드&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1990&quot; data-start=&quot;1780&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;메소드&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1848&quot; data-start=&quot;1811&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1832&quot; data-start=&quot;1811&quot;&gt;fit_transform(X)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1848&quot; data-start=&quot;1832&quot;&gt;컬럼별 전처리 + 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1881&quot; data-start=&quot;1849&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1866&quot; data-start=&quot;1849&quot;&gt;transform(X)&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1881&quot; data-start=&quot;1866&quot;&gt;학습된 전처리로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1943&quot; data-start=&quot;1882&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1910&quot; data-start=&quot;1882&quot;&gt;get_feature_names_out()&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1943&quot; data-start=&quot;1910&quot;&gt;OneHot 후 생성된 전체 feature 이름 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1990&quot; data-start=&quot;1944&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1968&quot; data-start=&quot;1944&quot;&gt;named_transformers_&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1990&quot; data-start=&quot;1968&quot;&gt;내부에 어떤 변환기가 있는지 조회&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2008&quot; data-start=&quot;1992&quot; data-ke-size=&quot;size26&quot;&gt;2-4. 기본 사용 예시&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1763460631027&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

numeric_features = ['lead_time', 'adr']
categorical_features = ['hotel', 'deposit_type']

preprocessor = ColumnTransformer([
    ('num', StandardScaler(), numeric_features),
    ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
])&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2431&quot; data-start=&quot;2387&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;2450&quot; data-start=&quot;2433&quot;&gt;3. GridSearchCV&lt;/h1&gt;
&lt;h2 data-end=&quot;2474&quot; data-start=&quot;2452&quot; data-ke-size=&quot;size26&quot;&gt;3-1. GridSearchCV란?&lt;/h2&gt;
&lt;p data-end=&quot;2501&quot; data-start=&quot;2475&quot; data-ke-size=&quot;size16&quot;&gt;모델의 하이퍼파라미터를 자동으로 탐색하는 기능.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2636&quot; data-start=&quot;2503&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2521&quot; data-start=&quot;2503&quot;&gt;여러 파라미터 조합을 시도&lt;/li&gt;
&lt;li data-end=&quot;2548&quot; data-start=&quot;2522&quot;&gt;Cross Validation 기반 평가&lt;/li&gt;
&lt;li data-end=&quot;2586&quot; data-start=&quot;2549&quot;&gt;가장 성능 좋은 파라미터를 best_params_로 반환&lt;/li&gt;
&lt;li data-end=&quot;2636&quot; data-start=&quot;2587&quot;&gt;해당 파라미터가 적용된 전체 Pipeline을 best_estimator_로 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;2651&quot; data-start=&quot;2638&quot; data-ke-size=&quot;size26&quot;&gt;3-2. 주요 속성&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2826&quot; data-start=&quot;2652&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;속성&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2716&quot; data-start=&quot;2681&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2698&quot; data-start=&quot;2681&quot;&gt;best_params_&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2716&quot; data-start=&quot;2698&quot;&gt;최고 성능의 파라미터 조합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2762&quot; data-start=&quot;2717&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2737&quot; data-start=&quot;2717&quot;&gt;best_estimator_&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2762&quot; data-start=&quot;2737&quot;&gt;최고 성능의 Pipeline 전체 모델&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2791&quot; data-start=&quot;2763&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2779&quot; data-start=&quot;2763&quot;&gt;best_score_&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2791&quot; data-start=&quot;2779&quot;&gt;최고 CV 성능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2826&quot; data-start=&quot;2792&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2808&quot; data-start=&quot;2792&quot;&gt;cv_results_&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2826&quot; data-start=&quot;2808&quot;&gt;모든 조합별 성능 상세결과&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2854&quot; data-start=&quot;2828&quot; data-ke-size=&quot;size26&quot;&gt;3-3. param_grid 키 이름 규칙&lt;/h2&gt;
&lt;p data-end=&quot;2859&quot; data-start=&quot;2856&quot; data-ke-size=&quot;size16&quot;&gt;형식:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1763460657777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'스텝이름__파라미터이름'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2886&quot; data-start=&quot;2884&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1763460669317&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'model__n_estimators'
'preprocess__num__scaler__with_mean'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2971&quot; data-start=&quot;2955&quot; data-ke-size=&quot;size26&quot;&gt;3-4. 기본 사용 예시&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1763460680952&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.model_selection import GridSearchCV

param_grid = {
    'model__n_estimators': [100, 200],
    'model__max_depth': [5, None],
    'model__min_samples_split': [2, 5]
}

grid = GridSearchCV(pipeline, param_grid, cv=5, scoring='roc_auc')
grid.fit(X_train, y_train)

best_model = grid.best_estimator_&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3342&quot; data-start=&quot;3298&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;3398&quot; data-start=&quot;3344&quot;&gt;4. Pipeline + ColumnTransformer + GridSearchCV 종합 예시&lt;/h1&gt;
&lt;p data-end=&quot;3487&quot; data-start=&quot;3400&quot; data-ke-size=&quot;size16&quot;&gt;아래 예시는&lt;br /&gt;숫자/범주형 컬럼 전처리 &amp;rarr; 랜덤포레스트 분류 &amp;rarr; 하이퍼파라미터 탐색&lt;br /&gt;전체 ML Workflow를 하나의 구조로 구현한 실전 예시입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1763460690134&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import roc_auc_score, accuracy_score, f1_score

# 1. 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

# 2. 컬럼 정의
numeric_features = X_train.select_dtypes(include=['int64', 'float64']).columns
categorical_features = X_train.select_dtypes(include=['object', 'bool']).columns

# 3. 컬럼 변환기 정의
preprocessor = ColumnTransformer([
    ('num', StandardScaler(), numeric_features),
    ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
])

# 4. 전체 파이프라인 구성
pipeline = Pipeline([
    ('preprocess', preprocessor),
    ('model', RandomForestClassifier())
])

# 5. 하이퍼파라미터 탐색
param_grid = {
    'model__n_estimators': [100, 200],
    'model__max_depth': [5, None],
    'model__min_samples_split': [2, 5]
}

grid = GridSearchCV(
    pipeline, param_grid, cv=5, scoring='roc_auc', n_jobs=-1)

grid.fit(X_train, y_train)
best_model = grid.best_estimator_

# 6. 테스트 성능 평가
y_pred = best_model.predict(X_test)
y_proba = best_model.predict_proba(X_test)[:, 1]

print(&quot;Test ROC-AUC:&quot;, roc_auc_score(y_test, y_proba))
print(&quot;Test Accuracy:&quot;, accuracy_score(y_test, y_pred))
print(&quot;Test F1:&quot;, f1_score(y_test, y_pred))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5007&quot; data-start=&quot;4963&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;5032&quot; data-start=&quot;5009&quot;&gt;5. 머신러닝 전처리 및 모델 학습 팁&lt;/h1&gt;
&lt;h2 data-end=&quot;5051&quot; data-start=&quot;5034&quot; data-ke-size=&quot;size26&quot;&gt;5-1. 데이터 전처리 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5245&quot; data-start=&quot;5052&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5097&quot; data-start=&quot;5052&quot;&gt;숫자형 컬럼은 StandardScaler 또는 MinMaxScaler 적용&lt;/li&gt;
&lt;li data-end=&quot;5121&quot; data-start=&quot;5098&quot;&gt;범주형은 OneHotEncoding&lt;/li&gt;
&lt;li data-end=&quot;5159&quot; data-start=&quot;5122&quot;&gt;Boolean은 categorical로 처리하는 것이 일반적&lt;/li&gt;
&lt;li data-end=&quot;5188&quot; data-start=&quot;5160&quot;&gt;로그 변환은 음수/0 존재 여부 반드시 확인&lt;/li&gt;
&lt;li data-end=&quot;5245&quot; data-start=&quot;5189&quot;&gt;결측값은 반드시 train/test split 이전에 split하고, Pipeline 안에서 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;5262&quot; data-start=&quot;5247&quot; data-ke-size=&quot;size26&quot;&gt;5-2. 모델 학습 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5477&quot; data-start=&quot;5263&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5354&quot; data-start=&quot;5263&quot;&gt;RandomForest / XGBoost는 scale에 크게 민감하지 않지만&lt;br /&gt;LinearRegression / SVM / KNN은 반드시 표준화 필요&lt;/li&gt;
&lt;li data-end=&quot;5414&quot; data-start=&quot;5355&quot;&gt;분류 문제 평가 지표는 Accuracy만 보면 위험&lt;br /&gt;ROC-AUC, F1을 반드시 함께 확인&lt;/li&gt;
&lt;li data-end=&quot;5477&quot; data-start=&quot;5415&quot;&gt;데이터 누수(Leakage) 방지&lt;br /&gt;Target과 관련된 뒤늦게 알 수 있는 컬럼은 반드시 제거해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;5501&quot; data-start=&quot;5479&quot; data-ke-size=&quot;size26&quot;&gt;5-3. GridSearchCV 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5622&quot; data-start=&quot;5502&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5540&quot; data-start=&quot;5502&quot;&gt;param_grid는 Pipeline 스텝 이름 기반으로 작성&lt;/li&gt;
&lt;li data-end=&quot;5582&quot; data-start=&quot;5541&quot;&gt;scoring='roc_auc'는 이진 분류에서 가장 안정적인 지표&lt;/li&gt;
&lt;li data-end=&quot;5607&quot; data-start=&quot;5583&quot;&gt;n_jobs=-1로 CPU 전체 사용&lt;/li&gt;
&lt;li data-end=&quot;5622&quot; data-start=&quot;5608&quot;&gt;cv=5~10이 안정적&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-end=&quot;5639&quot; data-start=&quot;5624&quot; data-ke-size=&quot;size26&quot;&gt;5-4. 모델 해석 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5822&quot; data-start=&quot;5640&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5694&quot; data-start=&quot;5640&quot;&gt;RandomForest/XGBoost는 feature_importances_로 중요도 확인&lt;/li&gt;
&lt;li data-end=&quot;5759&quot; data-start=&quot;5695&quot;&gt;ColumnTransformer.get_feature_names_out()으로 실제 feature 목록 생성&lt;/li&gt;
&lt;li data-end=&quot;5791&quot; data-start=&quot;5760&quot;&gt;SHAP 값을 통해 개별 데이터의 예측 근거 분석&lt;/li&gt;
&lt;li data-end=&quot;5822&quot; data-start=&quot;5792&quot;&gt;ConfusionMatrix로 FP/FN 패턴 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;5868&quot; data-start=&quot;5824&quot; data-ke-size=&quot;size16&quot;&gt;────────────────────────────────────────────&lt;/p&gt;
&lt;h1 data-end=&quot;5878&quot; data-start=&quot;5870&quot;&gt;6. 마무리&lt;/h1&gt;
&lt;p data-end=&quot;5992&quot; data-start=&quot;5880&quot; data-ke-size=&quot;size16&quot;&gt;Pipeline, ColumnTransformer, GridSearchCV는&lt;br /&gt;전처리부터 모델 학습, 하이퍼파라미터 튜닝까지&lt;br /&gt;전체 머신러닝 과정을 일관된 구조로 자동화할 수 있는 핵심 기술입니다.&lt;/p&gt;
&lt;p data-end=&quot;6085&quot; data-start=&quot;5994&quot; data-ke-size=&quot;size16&quot;&gt;이 세 가지를 자유자재로 활용하면&lt;br /&gt;데이터 분석 프로젝트의 수준이 한 단계 올라가며,&lt;br /&gt;데이터 누수 방지, 안정적 모델 평가, 자동 최적화 구성이 가능해집니다.&lt;/p&gt;</description>
      <category>AI 활용 소프트웨어 개발/AI, 머신러닝, 딥러닝</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/185</guid>
      <comments>https://ha2yong.tistory.com/185#entry185comment</comments>
      <pubDate>Tue, 18 Nov 2025 19:12:45 +0900</pubDate>
    </item>
    <item>
      <title>모델 양자화에 대한 생각</title>
      <link>https://ha2yong.tistory.com/184</link>
      <description>&lt;p data-end=&quot;231&quot; data-start=&quot;157&quot; data-ke-size=&quot;size16&quot;&gt;최근 AI 최적화 기술을 공부하면서 가장 흥미롭게 느끼는 지점이 있다.&lt;br /&gt;바로 양자화(Quantization)라는 개념이다.&lt;/p&gt;
&lt;p data-end=&quot;353&quot; data-start=&quot;233&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 단순히,&lt;br /&gt;&quot;모델을 가볍게 해서 엣지 디바이스에 올리기 위한 기술이겠지&quot; 정도로 생각했다.&lt;br /&gt;스마트폰이나 임베디드 환경에서,&lt;br /&gt;적은 리소스로도 딥러닝 모델을 돌리기 위한 압축&amp;middot;경량화 도구쯤으로 말이다.&lt;/p&gt;
&lt;p data-end=&quot;462&quot; data-start=&quot;355&quot; data-ke-size=&quot;size16&quot;&gt;하지만 공부할수록 이 기술은 단순한 '경량화' 영역이 아니었다.&lt;br /&gt;오히려 &lt;b&gt;AI 모델을 어떻게 더 효율적으로 발전시킬 것인가&lt;/b&gt;에 대한&lt;br /&gt;철학이자 방향성에 가깝다는 생각이 들기 시작했다.&lt;/p&gt;
&lt;hr data-end=&quot;467&quot; data-start=&quot;464&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;486&quot; data-start=&quot;469&quot; data-ke-size=&quot;size26&quot;&gt;&quot;작음 = 약함&quot;일까?&lt;/h2&gt;
&lt;p data-end=&quot;611&quot; data-start=&quot;487&quot; data-ke-size=&quot;size16&quot;&gt;대규모 언어 모델 시대가 열리면서,&lt;br /&gt;&amp;lsquo;큰 모델이 곧 강한 모델&amp;rsquo;이라는 인식이 자연스럽게 자리 잡았다.&lt;br /&gt;실제로 GPT-4, Llama 3, Mistral 등&lt;br /&gt;모든 거대 모델이 매개변수를 키우면서 성능을 끌어올렸다.&lt;/p&gt;
&lt;p data-end=&quot;702&quot; data-start=&quot;613&quot; data-ke-size=&quot;size16&quot;&gt;당연하게도 우리는 그 흐름에 익숙해졌다.&lt;br /&gt;더 크고, 더 많은 파라미터, 더 많은 GPU.&lt;br /&gt;스케일링 법칙이 증명한 것처럼 모델이 커질수록 성능도 비례했다.&lt;/p&gt;
&lt;p data-end=&quot;731&quot; data-start=&quot;704&quot; data-ke-size=&quot;size16&quot;&gt;그런데 여기서 양자화를 보면 다른 질문이 생긴다.&lt;/p&gt;
&lt;blockquote data-end=&quot;764&quot; data-start=&quot;733&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;764&quot; data-start=&quot;735&quot; data-ke-size=&quot;size16&quot;&gt;&quot;정말 모델은 무조건 커져야만 더 똑똑해지는 걸까?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;824&quot; data-start=&quot;766&quot; data-ke-size=&quot;size16&quot;&gt;만약 우리는 4bit, 8bit, 혹은 더 낮은 정밀도에서도&lt;br /&gt;거의 동일한 성능을 유지시킬 수 있다면?&lt;/p&gt;
&lt;p data-end=&quot;902&quot; data-start=&quot;826&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 이는 단순히 &amp;ldquo;작게 만들기&amp;rdquo;를 넘어서,&lt;br /&gt;&lt;b&gt;같은 크기에서 더 많은 표현력을 담을 수 있는 기술&lt;/b&gt;이라는 의미가 되지 않을까.&lt;/p&gt;
&lt;hr data-end=&quot;907&quot; data-start=&quot;904&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;930&quot; data-start=&quot;909&quot; data-ke-size=&quot;size26&quot;&gt;반도체의 미세공정과 닮아 있다&lt;/h2&gt;
&lt;p data-end=&quot;1022&quot; data-start=&quot;931&quot; data-ke-size=&quot;size16&quot;&gt;반도체 세계에서는 나노 공정이 줄어들수록,&lt;br /&gt;같은 면적에 더 많은 트랜지스터를 몰아넣을 수 있다.&lt;br /&gt;즉, &lt;b&gt;공정이 작아질수록 효율과 성능이 모두 증가&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-end=&quot;1044&quot; data-start=&quot;1024&quot; data-ke-size=&quot;size16&quot;&gt;양자화를 보며 비슷한 흐름을 느낀다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1090&quot; data-start=&quot;1046&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1058&quot; data-start=&quot;1046&quot;&gt;같은 연산 자원&lt;/li&gt;
&lt;li data-end=&quot;1072&quot; data-start=&quot;1059&quot;&gt;더 작은 수 표현&lt;/li&gt;
&lt;li data-end=&quot;1090&quot; data-start=&quot;1073&quot;&gt;동일하거나 유사한 성능 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1141&quot; data-start=&quot;1092&quot; data-ke-size=&quot;size16&quot;&gt;이건 단순히 &amp;ldquo;작아진다&amp;rdquo;가 아니라,&lt;br /&gt;&lt;b&gt;밀도를 끌어올리는 과정&lt;/b&gt;이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1194&quot; data-start=&quot;1143&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이 밀도 향상은&lt;br /&gt;현재 AI가 맞이하고 있는 다음 성장 국면의 방향성일지도 모른다.&lt;/p&gt;
&lt;hr data-end=&quot;1199&quot; data-start=&quot;1196&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1218&quot; data-start=&quot;1201&quot; data-ke-size=&quot;size26&quot;&gt;효율이 새로운 성능이다&lt;/h2&gt;
&lt;p data-end=&quot;1274&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;지금까지 AI 산업은 크기 경쟁을 해왔다.&lt;br /&gt;더 많은 GPU, 더 많은 메모리, 더 큰 파라미터.&lt;/p&gt;
&lt;p data-end=&quot;1300&quot; data-start=&quot;1276&quot; data-ke-size=&quot;size16&quot;&gt;하지만 앞으로는 다른 경쟁이 시작될 것이다.&lt;/p&gt;
&lt;p data-end=&quot;1340&quot; data-start=&quot;1302&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동일한 계산 자원에서&lt;br /&gt;얼마나 많은 지능을 담을 수 있는가.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1443&quot; data-start=&quot;1342&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1377&quot; data-start=&quot;1342&quot;&gt;32bit 대신 8bit로도 똑같이 생각할 수 있는 모델&lt;/li&gt;
&lt;li data-end=&quot;1412&quot; data-start=&quot;1378&quot;&gt;4bit로도 기존 16bit 모델에 근접하는 언어 능력&lt;/li&gt;
&lt;li data-end=&quot;1443&quot; data-start=&quot;1413&quot;&gt;더 작지만 실제 환경에서는 더 빠르고 유용한 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1490&quot; data-start=&quot;1445&quot; data-ke-size=&quot;size16&quot;&gt;이건 단순한 &amp;ldquo;압축&amp;rdquo;이 아니라&lt;br /&gt;&lt;b&gt;지능의 효율화를 향한 진화&lt;/b&gt;라고 느껴진다.&lt;/p&gt;
&lt;hr data-end=&quot;1495&quot; data-start=&quot;1492&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1509&quot; data-start=&quot;1497&quot; data-ke-size=&quot;size26&quot;&gt;개인적인 기대&lt;/h2&gt;
&lt;p data-end=&quot;1609&quot; data-start=&quot;1510&quot; data-ke-size=&quot;size16&quot;&gt;양자화와 프루닝, sparsity, distillation 같은 기술들은&lt;br /&gt;지금은 최적화 영역이라 불리지만,&lt;br /&gt;앞으로는 &lt;b&gt;본질적인 AI 아키텍처 발전 축&lt;/b&gt;이 될 것 같다.&lt;/p&gt;
&lt;p data-end=&quot;1648&quot; data-start=&quot;1611&quot; data-ke-size=&quot;size16&quot;&gt;거대 모델 시대가 계속되더라도&lt;br /&gt;결국 우리가 가야할 길은 하나다.&lt;/p&gt;
&lt;blockquote data-end=&quot;1678&quot; data-start=&quot;1650&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1678&quot; data-start=&quot;1652&quot; data-ke-size=&quot;size16&quot;&gt;&quot;적은 자원으로 더 높은 지능을 구현하는 기술&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1755&quot; data-start=&quot;1680&quot; data-ke-size=&quot;size16&quot;&gt;그 방향성 위에서 양자화를 보면,&lt;br /&gt;이 기술이 단순한 엣지 기술이 아니라&lt;br /&gt;&lt;b&gt;AI 발전의 또 하나의 스케일링 전략&lt;/b&gt;으로 보인다.&lt;/p&gt;
&lt;p data-end=&quot;1819&quot; data-start=&quot;1757&quot; data-ke-size=&quot;size16&quot;&gt;체감상&lt;br /&gt;AI의 다음 도약은 단순한 모델 크기 확장보다&lt;br /&gt;이런 &lt;b&gt;효율성 혁신에서 시작될 가능성&lt;/b&gt;이 크다.&lt;/p&gt;
&lt;p data-end=&quot;1859&quot; data-start=&quot;1821&quot; data-ke-size=&quot;size16&quot;&gt;그리고 바로 그 지점이,&lt;br /&gt;내가 이 기술을 흥미롭게 느끼는 이유다.&lt;/p&gt;
&lt;hr data-end=&quot;1864&quot; data-start=&quot;1861&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1874&quot; data-start=&quot;1866&quot; data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-end=&quot;1943&quot; data-start=&quot;1875&quot; data-ke-size=&quot;size16&quot;&gt;더 크고 강한 모델도 중요하다.&lt;br /&gt;하지만 그만큼 중요한 건&lt;br /&gt;&lt;b&gt;더 똑똑하고, 더 효율적이며, 더 우아한 모델&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1976&quot; data-start=&quot;1945&quot; data-ke-size=&quot;size16&quot;&gt;양자화는 그 우아함을 향해 가는 기술이라는 생각이 든다.&lt;/p&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;1978&quot; data-ke-size=&quot;size16&quot;&gt;이제는 단순히 &amp;ldquo;작게 만드는 기술&amp;rdquo;이 아니라,&lt;br /&gt;&lt;b&gt;지능을 더 촘촘하게 담는 기술&lt;/b&gt;이라고 부르고 싶다.&lt;/p&gt;</description>
      <category>잡다한 아이디어</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/184</guid>
      <comments>https://ha2yong.tistory.com/184#entry184comment</comments>
      <pubDate>Wed, 5 Nov 2025 14:16:35 +0900</pubDate>
    </item>
    <item>
      <title>ONNX, TensorRT, 양자화(Quantization) 정리</title>
      <link>https://ha2yong.tistory.com/183</link>
      <description>&lt;p data-end=&quot;306&quot; data-start=&quot;158&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝 모델을 실제 환경(특히 Edge AI, GPU 환경)에서 빠르게 실행하기 위해서는 단순히 학습만 잘한다고 끝이 아니다.&lt;br /&gt;현장에서 어떤 방식으로 모델을 배포하고 최적화해야 하는지 이해하는 과정에서 ONNX, TensorRT, 그리고 양자화 개념을 정리했다.&lt;/p&gt;
&lt;hr data-end=&quot;311&quot; data-start=&quot;308&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;318&quot; data-start=&quot;313&quot; data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;595&quot; data-start=&quot;319&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;335&quot; data-start=&quot;319&quot;&gt;왜 최적화가 필요한가&lt;/li&gt;
&lt;li data-end=&quot;389&quot; data-start=&quot;336&quot;&gt;ONNX란 무엇인가
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;389&quot; data-start=&quot;356&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;362&quot; data-start=&quot;356&quot;&gt;개념&lt;/li&gt;
&lt;li data-end=&quot;378&quot; data-start=&quot;367&quot;&gt;왜 사용하는가&lt;/li&gt;
&lt;li data-end=&quot;389&quot; data-start=&quot;383&quot;&gt;비유&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;445&quot; data-start=&quot;390&quot;&gt;TensorRT란 무엇인가
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;445&quot; data-start=&quot;414&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;420&quot; data-start=&quot;414&quot;&gt;개념&lt;/li&gt;
&lt;li data-end=&quot;434&quot; data-start=&quot;425&quot;&gt;동작 원리&lt;/li&gt;
&lt;li data-end=&quot;445&quot; data-start=&quot;439&quot;&gt;비유&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;530&quot; data-start=&quot;446&quot;&gt;양자화(Quantization)란 무엇인가
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;530&quot; data-start=&quot;479&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;485&quot; data-start=&quot;479&quot;&gt;개념&lt;/li&gt;
&lt;li data-end=&quot;519&quot; data-start=&quot;490&quot;&gt;FP32, FP16, INT8, INT4 비교&lt;/li&gt;
&lt;li data-end=&quot;530&quot; data-start=&quot;524&quot;&gt;비유&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;531&quot;&gt;ONNX &amp;rarr; TensorRT &amp;rarr; Edge 실행 흐름&lt;/li&gt;
&lt;li data-end=&quot;581&quot; data-start=&quot;565&quot;&gt;실제 적용 시 주의점&lt;/li&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;582&quot;&gt;정리 및 느낀점&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;600&quot; data-start=&quot;597&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;621&quot; data-start=&quot;602&quot; data-ke-size=&quot;size26&quot;&gt;1. 왜 최적화가 필요한가&lt;/h2&gt;
&lt;p data-end=&quot;683&quot; data-start=&quot;622&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝 모델은 연구용 환경에서는 GPU가 빠르게 처리해주지만, 실제 현장에서는 다음 문제들이 발생할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;801&quot; data-start=&quot;685&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;707&quot; data-start=&quot;685&quot;&gt;GPU가 없거나 리소스가 제한된 환경&lt;/li&gt;
&lt;li data-end=&quot;737&quot; data-start=&quot;708&quot;&gt;전력 소비 제한(드론, 로봇, 스마트 카메라 등)&lt;/li&gt;
&lt;li data-end=&quot;768&quot; data-start=&quot;738&quot;&gt;실시간 응답 지연 문제(예: 1초 이내 반응 필요)&lt;/li&gt;
&lt;li data-end=&quot;801&quot; data-start=&quot;769&quot;&gt;네트워크 환경이 불안정하여 클라우드 의존이 어려운 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;803&quot; data-ke-size=&quot;size16&quot;&gt;따라서 모델을 &lt;b&gt;가볍게&lt;/b&gt;, &lt;b&gt;빠르게&lt;/b&gt;, &lt;b&gt;안정적으로&lt;/b&gt; 만드는 과정이 필요하다.&lt;/p&gt;
&lt;hr data-end=&quot;857&quot; data-start=&quot;854&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;877&quot; data-start=&quot;859&quot; data-ke-size=&quot;size26&quot;&gt;2. ONNX란 무엇인가&lt;/h2&gt;
&lt;h3 data-end=&quot;887&quot; data-start=&quot;879&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;p data-end=&quot;989&quot; data-start=&quot;888&quot; data-ke-size=&quot;size16&quot;&gt;ONNX(Open Neural Network Exchange)란 서로 다른 AI 프레임워크(PyTorch, TensorFlow 등)를&lt;br /&gt;공통 포맷으로 변환하는 모델 교환 표준이다.&lt;/p&gt;
&lt;p data-end=&quot;1052&quot; data-start=&quot;991&quot; data-ke-size=&quot;size16&quot;&gt;즉, 모델을 특정 프레임워크에 묶어두지 않고&lt;br /&gt;다양한 플랫폼에서 동작하게 하기 위한 통합 파일 형식이다.&lt;/p&gt;
&lt;h3 data-end=&quot;1067&quot; data-start=&quot;1054&quot; data-ke-size=&quot;size23&quot;&gt;왜 사용하는가&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1212&quot; data-start=&quot;1068&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1123&quot; data-start=&quot;1068&quot;&gt;PyTorch에서 만든 모델을 다른 환경(예: C++, TensorRT)에서 사용할 수 있다&lt;/li&gt;
&lt;li data-end=&quot;1164&quot; data-start=&quot;1124&quot;&gt;모델을 동일한 포맷으로 변환함으로써, 호환성과 재사용성이 높아진다&lt;/li&gt;
&lt;li data-end=&quot;1212&quot; data-start=&quot;1165&quot;&gt;Edge AI 보드나 NPU 칩들이 ONNX 포맷을 입력으로 받는 경우가 많다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1222&quot; data-start=&quot;1214&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1313&quot; data-start=&quot;1223&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1273&quot; data-start=&quot;1223&quot;&gt;PyTorch 모델이 한국어라면, ONNX는 전 세계 어디서나 읽히는 번역 문서이다&lt;/li&gt;
&lt;li data-end=&quot;1313&quot; data-start=&quot;1274&quot;&gt;즉, ONNX는 &amp;ldquo;딥러닝 모델의 PDF 파일&amp;rdquo;이라고 볼 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1318&quot; data-start=&quot;1315&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1342&quot; data-start=&quot;1320&quot; data-ke-size=&quot;size26&quot;&gt;3. TensorRT란 무엇인가&lt;/h2&gt;
&lt;h3 data-end=&quot;1352&quot; data-start=&quot;1344&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;p data-end=&quot;1439&quot; data-start=&quot;1353&quot; data-ke-size=&quot;size16&quot;&gt;TensorRT는 NVIDIA가 제공하는 &lt;b&gt;딥러닝 추론 최적화 엔진&lt;/b&gt;이다.&lt;br /&gt;ONNX 모델을 입력받아, GPU에서 가장 빠르게 실행되도록 변환해준다.&lt;/p&gt;
&lt;h3 data-end=&quot;1452&quot; data-start=&quot;1441&quot; data-ke-size=&quot;size23&quot;&gt;동작 방식&lt;/h3&gt;
&lt;p data-end=&quot;1479&quot; data-start=&quot;1453&quot; data-ke-size=&quot;size16&quot;&gt;TensorRT는 다음과 같은 작업을 수행한다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1561&quot; data-start=&quot;1481&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1498&quot; data-start=&quot;1481&quot;&gt;연산 최적화 및 그래프 변환&lt;/li&gt;
&lt;li data-end=&quot;1520&quot; data-start=&quot;1499&quot;&gt;FP16/INT8 기반 정밀도 조정&lt;/li&gt;
&lt;li data-end=&quot;1540&quot; data-start=&quot;1521&quot;&gt;커널 선택 및 실행 경로 최적화&lt;/li&gt;
&lt;li data-end=&quot;1561&quot; data-start=&quot;1541&quot;&gt;불필요 계산 제거 및 레이어 병합&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1571&quot; data-start=&quot;1563&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1659&quot; data-start=&quot;1572&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1589&quot; data-start=&quot;1572&quot;&gt;원본 모델은 기본 자동차&lt;/li&gt;
&lt;li data-end=&quot;1627&quot; data-start=&quot;1590&quot;&gt;TensorRT로 변환하면 엔진 튜닝을 거친 스포츠카가 된다&lt;/li&gt;
&lt;li data-end=&quot;1659&quot; data-start=&quot;1628&quot;&gt;같은 모델이지만 더 빠르고 더 적은 연료로 달린다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1664&quot; data-start=&quot;1661&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1697&quot; data-start=&quot;1666&quot; data-ke-size=&quot;size26&quot;&gt;4. 양자화(Quantization)란 무엇인가&lt;/h2&gt;
&lt;h3 data-end=&quot;1707&quot; data-start=&quot;1699&quot; data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;p data-end=&quot;1767&quot; data-start=&quot;1708&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝 모델이 사용하는 숫자의 정밀도를 낮춰&lt;br /&gt;연산량과 메모리 사용을 줄이고 속도를 높이는 기술이다.&lt;/p&gt;
&lt;p data-end=&quot;1812&quot; data-start=&quot;1769&quot; data-ke-size=&quot;size16&quot;&gt;FP32(32비트) 대신 FP16, INT8, INT4 같은 형식을 사용한다.&lt;/p&gt;
&lt;h3 data-end=&quot;1824&quot; data-start=&quot;1814&quot; data-ke-size=&quot;size23&quot;&gt;정밀도 비교&lt;/h3&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1989&quot; data-start=&quot;1826&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;형식&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;td&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1888&quot; data-start=&quot;1857&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1862&quot; data-start=&quot;1857&quot;&gt;FP32&lt;/td&gt;
&lt;td data-end=&quot;1872&quot; data-start=&quot;1862&quot; data-col-size=&quot;sm&quot;&gt;32비트 실수&lt;/td&gt;
&lt;td data-end=&quot;1888&quot; data-start=&quot;1872&quot; data-col-size=&quot;sm&quot;&gt;가장 정확하지만 무거움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1920&quot; data-start=&quot;1889&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1894&quot; data-start=&quot;1889&quot;&gt;FP16&lt;/td&gt;
&lt;td data-end=&quot;1904&quot; data-start=&quot;1894&quot; data-col-size=&quot;sm&quot;&gt;16비트 실수&lt;/td&gt;
&lt;td data-end=&quot;1920&quot; data-start=&quot;1904&quot; data-col-size=&quot;sm&quot;&gt;절반 크기, 속도 향상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1953&quot; data-start=&quot;1921&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1926&quot; data-start=&quot;1921&quot;&gt;INT8&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1935&quot; data-start=&quot;1926&quot;&gt;8비트 정수&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1953&quot; data-start=&quot;1935&quot;&gt;속도와 효율이 매우 뛰어남&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1989&quot; data-start=&quot;1954&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1959&quot; data-start=&quot;1954&quot;&gt;INT4&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1968&quot; data-start=&quot;1959&quot;&gt;4비트 정수&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1989&quot; data-start=&quot;1968&quot;&gt;매우 빠르지만 정확도 손실 위험&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2004&quot; data-start=&quot;1991&quot; data-ke-size=&quot;size23&quot;&gt;양자화의 효과&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2058&quot; data-start=&quot;2005&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2021&quot; data-start=&quot;2005&quot;&gt;모델 메모리 사용 감소&lt;/li&gt;
&lt;li data-end=&quot;2041&quot; data-start=&quot;2022&quot;&gt;연산량 감소 및 배터리 절약&lt;/li&gt;
&lt;li data-end=&quot;2058&quot; data-start=&quot;2042&quot;&gt;실시간 처리 지연 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2068&quot; data-start=&quot;2060&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2137&quot; data-start=&quot;2069&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2095&quot; data-start=&quot;2069&quot;&gt;고해상도 원본 사진을 압축하는 것과 유사&lt;/li&gt;
&lt;li data-end=&quot;2137&quot; data-start=&quot;2096&quot;&gt;너무 많이 줄이면 화질이 깨지듯, 양자화도 과하면 정확도가 떨어진다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2142&quot; data-start=&quot;2139&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2158&quot; data-start=&quot;2144&quot; data-ke-size=&quot;size26&quot;&gt;5. 배포 흐름 정리&lt;/h2&gt;
&lt;p data-end=&quot;2189&quot; data-start=&quot;2160&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 학습 및 배포 흐름은 아래와 같이 정리된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1762319052568&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PyTorch 모델 (.pt)
&amp;rarr; ONNX 변환 (.onnx)
&amp;rarr; TensorRT 엔진 최적화 (.plan)
&amp;rarr; GPU / Edge 디바이스에서 초고속 실행&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;2291&quot; data-start=&quot;2288&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2307&quot; data-start=&quot;2293&quot; data-ke-size=&quot;size26&quot;&gt;6. 적용 시 주의점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2481&quot; data-start=&quot;2308&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2337&quot; data-start=&quot;2308&quot;&gt;모든 연산이 ONNX로 완벽 변환되지는 않는다&lt;/li&gt;
&lt;li data-end=&quot;2380&quot; data-start=&quot;2338&quot;&gt;TensorRT가 지원하지 않는 연산이 있을 수 있다(플러그인 필요)&lt;/li&gt;
&lt;li data-end=&quot;2410&quot; data-start=&quot;2381&quot;&gt;과도한 양자화는 정확도 저하를 유발할 수 있다&lt;/li&gt;
&lt;li data-end=&quot;2441&quot; data-start=&quot;2411&quot;&gt;테스트 데이터를 이용하여 캘리브레이션이 필요하다&lt;/li&gt;
&lt;li data-end=&quot;2481&quot; data-start=&quot;2442&quot;&gt;입력 사이즈 고정 모델이 더 빠르다 (동적 입력은 성능 저하 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2486&quot; data-start=&quot;2483&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2504&quot; data-start=&quot;2488&quot; data-ke-size=&quot;size26&quot;&gt;7. 정리 및 느낀점&lt;/h2&gt;
&lt;p data-end=&quot;2523&quot; data-start=&quot;2506&quot; data-ke-size=&quot;size16&quot;&gt;이번 내용을 공부하며 느낀 점:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2724&quot; data-start=&quot;2525&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2560&quot; data-start=&quot;2525&quot;&gt;연구용 모델과 실제 서비스용 모델은 완전히 다른 영역이다&lt;/li&gt;
&lt;li data-end=&quot;2590&quot; data-start=&quot;2561&quot;&gt;ONNX는 플랫폼 독립성 확보에 필수적인 구조&lt;/li&gt;
&lt;li data-end=&quot;2628&quot; data-start=&quot;2591&quot;&gt;TensorRT는 NVIDIA 환경에서 필수적인 최적화 도구&lt;/li&gt;
&lt;li data-end=&quot;2657&quot; data-start=&quot;2629&quot;&gt;양자화는 속도와 정확도의 균형을 맞추는 기술&lt;/li&gt;
&lt;li data-end=&quot;2724&quot; data-start=&quot;2658&quot;&gt;결국 실제 제품 수준의 AI는&lt;br /&gt;&quot;정확도 + 속도 + 전력 효율 + 안정성&quot; 이 4개를 모두 고려해야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2804&quot; data-start=&quot;2726&quot; data-ke-size=&quot;size16&quot;&gt;이제 목표는&lt;br /&gt;직접 ONNX로 변환하고 TensorRT 엔진을 만들어보며&lt;br /&gt;FP16, INT8 등 다양한 정밀도 설정을 실험하는 것이다.&lt;/p&gt;
&lt;hr data-end=&quot;2809&quot; data-start=&quot;2806&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;2833&quot; data-start=&quot;2811&quot; data-ke-size=&quot;size16&quot;&gt;필요하면 아래도 같이 만들어줄 수 있다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2974&quot; data-start=&quot;2835&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2878&quot; data-start=&quot;2835&quot;&gt;TensorRT 설치 및 환경 구성 가이드(윈도우/리눅스/Jetson)&lt;/li&gt;
&lt;li data-end=&quot;2903&quot; data-start=&quot;2879&quot;&gt;PyTorch &amp;rarr; ONNX 변환 코드&lt;/li&gt;
&lt;li data-end=&quot;2935&quot; data-start=&quot;2904&quot;&gt;ONNX &amp;rarr; TensorRT 엔진 변환 코드 예제&lt;/li&gt;
&lt;li data-end=&quot;2952&quot; data-start=&quot;2936&quot;&gt;속도 비교 실험 템플릿&lt;/li&gt;
&lt;li data-end=&quot;2974&quot; data-start=&quot;2953&quot;&gt;실제 블로그용 이미지/도식 제작&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>공부/양자화</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/183</guid>
      <comments>https://ha2yong.tistory.com/183#entry183comment</comments>
      <pubDate>Wed, 5 Nov 2025 14:04:28 +0900</pubDate>
    </item>
    <item>
      <title>자유도 높은 오픈월드 게임 AI 모델에 대한 아이디어</title>
      <link>https://ha2yong.tistory.com/182</link>
      <description>&lt;p data-end=&quot;271&quot; data-start=&quot;173&quot; data-ke-size=&quot;size16&quot;&gt;최근 LLM이 문장을 생성하는 방식에서 흥미로운 점을 발견했다.&lt;br /&gt;LLM은 인간의 언어를 토큰 단위로 이해하고,&lt;br /&gt;다음에 올 가장 그럴듯한 단어를 추론하여 문장을 완성한다.&lt;/p&gt;
&lt;p data-end=&quot;282&quot; data-start=&quot;273&quot; data-ke-size=&quot;size16&quot;&gt;핵심은 이것이다:&lt;/p&gt;
&lt;blockquote data-end=&quot;311&quot; data-start=&quot;284&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;311&quot; data-start=&quot;286&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;다음 상태를 확률적으로 예측하고 선택한다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;401&quot; data-start=&quot;313&quot; data-ke-size=&quot;size16&quot;&gt;즉, 모델은 &lt;b&gt;문맥(Context)&lt;/b&gt; 아래에서 &lt;b&gt;미래 상태(Token)&lt;/b&gt; 를 생성한다.&lt;br /&gt;그 구조를 인간 플레이어의 행동 시스템에 대입할 수 있을까?&lt;/p&gt;
&lt;p data-end=&quot;476&quot; data-start=&quot;403&quot; data-ke-size=&quot;size16&quot;&gt;만약 우리가&lt;br /&gt;&amp;ldquo;플레이어 행동을 토큰처럼 보고,&lt;br /&gt;그 행동의 결과(보상/세계 변화/NPC 반응 등)를 학습&amp;rdquo;시킬 수 있다면,&lt;/p&gt;
&lt;p data-end=&quot;526&quot; data-start=&quot;478&quot; data-ke-size=&quot;size16&quot;&gt;언어 대신 &lt;b&gt;행동을 다음 토큰처럼 예측하는 LLM 게임 엔진&lt;/b&gt;이 가능할지도 모른다.&lt;/p&gt;
&lt;hr data-end=&quot;531&quot; data-start=&quot;528&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;545&quot; data-start=&quot;533&quot; data-ke-size=&quot;size26&quot;&gt;아이디어 확장&lt;/h2&gt;
&lt;h3 data-end=&quot;554&quot; data-start=&quot;546&quot; data-ke-size=&quot;size23&quot;&gt;가정&lt;/h3&gt;
&lt;p data-end=&quot;625&quot; data-start=&quot;555&quot; data-ke-size=&quot;size16&quot;&gt;플레이어 행동 = 토큰&lt;br /&gt;게임 월드 변화 = 문장/맥락&lt;br /&gt;NPC 반응/보상/스토리 변화 = 다음 토큰 후보들의 확률적 분포&lt;/p&gt;
&lt;p data-end=&quot;644&quot; data-start=&quot;627&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 아래 구조가 가능하다:&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;842&quot; data-start=&quot;646&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LLM 개념&lt;/td&gt;
&lt;td&gt;게임 AI 대응&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;701&quot; data-start=&quot;678&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;685&quot; data-start=&quot;678&quot;&gt;토큰 시퀀스&lt;/td&gt;
&lt;td data-end=&quot;701&quot; data-start=&quot;685&quot; data-col-size=&quot;sm&quot;&gt;플레이어 행동 히스토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;717&quot; data-start=&quot;702&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;708&quot; data-start=&quot;702&quot;&gt;언어 문맥&lt;/td&gt;
&lt;td data-end=&quot;717&quot; data-start=&quot;708&quot; data-col-size=&quot;sm&quot;&gt;월드 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;759&quot; data-start=&quot;718&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;740&quot; data-start=&quot;718&quot;&gt;Next-token prediction&lt;/td&gt;
&lt;td data-end=&quot;759&quot; data-start=&quot;740&quot; data-col-size=&quot;sm&quot;&gt;다음 가능한 게임 결과 예측&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;797&quot; data-start=&quot;760&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;772&quot; data-start=&quot;760&quot;&gt;Beam Search&lt;/td&gt;
&lt;td data-end=&quot;797&quot; data-start=&quot;772&quot; data-col-size=&quot;sm&quot;&gt;가능한 게임 전개 Top-K 후보 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;842&quot; data-start=&quot;798&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;820&quot; data-start=&quot;798&quot;&gt;Self-regression(자기검증)&lt;/td&gt;
&lt;td data-end=&quot;842&quot; data-start=&quot;820&quot; data-col-size=&quot;sm&quot;&gt;메타 AI가 월드 붕괴 여부 체크&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;847&quot; data-start=&quot;844&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;859&quot; data-start=&quot;849&quot; data-ke-size=&quot;size26&quot;&gt;아이디어 구조&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1445&quot; data-start=&quot;860&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;926&quot; data-start=&quot;860&quot;&gt;&lt;b&gt;행동 &amp;rarr; 결과 세트 학습&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;926&quot; data-start=&quot;884&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;894&quot; data-start=&quot;884&quot;&gt;유저 행동 로그&lt;/li&gt;
&lt;li data-end=&quot;926&quot; data-start=&quot;898&quot;&gt;NPC 반응, 보상, 스토리 브랜치, 월드 변화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1137&quot; data-start=&quot;928&quot;&gt;&lt;b&gt;Beam Search 방식 적용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1137&quot; data-start=&quot;956&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;981&quot; data-start=&quot;956&quot;&gt;&amp;ldquo;다음 가능한 게임 전개&amp;rdquo; Top-K 생성&lt;/li&gt;
&lt;li data-end=&quot;1137&quot; data-start=&quot;985&quot;&gt;예: 플레이어가 왕에게 무기를 던졌다&lt;br /&gt;가능한 후보:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1137&quot; data-start=&quot;1028&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1040&quot; data-start=&quot;1028&quot;&gt;(A) 경비대 체포&lt;/li&gt;
&lt;li data-end=&quot;1065&quot; data-start=&quot;1046&quot;&gt;(B) 왕이 마법 방어 후 위협&lt;/li&gt;
&lt;li data-end=&quot;1086&quot; data-start=&quot;1071&quot;&gt;(C) 왕이 겁먹고 도망&lt;/li&gt;
&lt;li data-end=&quot;1137&quot; data-start=&quot;1092&quot;&gt;(D) 왕이 농담으로 받아들임&lt;br /&gt;(이 때, 확률 분포가 존재할 것)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1298&quot; data-start=&quot;1139&quot;&gt;&lt;b&gt;Self-regression Layer(자기회귀 밸런싱)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1298&quot; data-start=&quot;1181&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1205&quot; data-start=&quot;1181&quot;&gt;위 후보들이 &amp;ldquo;월드를 깨지 않는지&amp;rdquo; 검증&lt;/li&gt;
&lt;li data-end=&quot;1298&quot; data-start=&quot;1209&quot;&gt;밸런싱 모델이 메타 평가:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1298&quot; data-start=&quot;1231&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1243&quot; data-start=&quot;1231&quot;&gt;게임 세계관 유지?&lt;/li&gt;
&lt;li data-end=&quot;1261&quot; data-start=&quot;1249&quot;&gt;난이도 곡선 파괴?&lt;/li&gt;
&lt;li data-end=&quot;1276&quot; data-start=&quot;1267&quot;&gt;몰입도 유지?&lt;/li&gt;
&lt;li data-end=&quot;1298&quot; data-start=&quot;1282&quot;&gt;&amp;ldquo;악용 루프&amp;rdquo; 생성 방지?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1445&quot; data-start=&quot;1300&quot;&gt;&lt;b&gt;Root AI + Sub AI 체계&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1445&quot; data-start=&quot;1330&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1357&quot; data-start=&quot;1330&quot;&gt;Root AI: 전체 월드 규칙, 세계관 유지&lt;/li&gt;
&lt;li data-end=&quot;1383&quot; data-start=&quot;1361&quot;&gt;NPC AI: 개별 캐릭터 동작 모델&lt;/li&gt;
&lt;li data-end=&quot;1412&quot; data-start=&quot;1387&quot;&gt;밸런스 AI: 스토리/경제/전투 균형 감시&lt;/li&gt;
&lt;li data-end=&quot;1445&quot; data-start=&quot;1416&quot;&gt;Physics/Rules AI: 룰 기반 안전장치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;1494&quot; data-start=&quot;1447&quot; data-ke-size=&quot;size16&quot;&gt;구조적으로는 &lt;b&gt;MMORPG 운영팀 + 게임 엔진 + DM(던전마스터)&lt;/b&gt; 합친 느낌&lt;/p&gt;
&lt;hr data-end=&quot;1499&quot; data-start=&quot;1496&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1512&quot; data-start=&quot;1501&quot; data-ke-size=&quot;size26&quot;&gt;필요한 요소&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;과제설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1673&quot; data-start=&quot;1513&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1673&quot; data-start=&quot;1535&quot;&gt;
&lt;tr data-end=&quot;1568&quot; data-start=&quot;1535&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1545&quot; data-start=&quot;1535&quot;&gt;행동-결과 데이터&lt;/td&gt;
&lt;td data-end=&quot;1568&quot; data-start=&quot;1545&quot; data-col-size=&quot;sm&quot;&gt;실제 인간 간 상호작용, 게임 로그&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1599&quot; data-start=&quot;1569&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1576&quot; data-start=&quot;1569&quot;&gt;밸런스 모델&lt;/td&gt;
&lt;td data-end=&quot;1599&quot; data-start=&quot;1576&quot; data-col-size=&quot;sm&quot;&gt;경제, 스토리, 전투, 보상 시스템&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1633&quot; data-start=&quot;1600&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1614&quot; data-start=&quot;1600&quot;&gt;Self-Check AI&lt;/td&gt;
&lt;td data-end=&quot;1633&quot; data-start=&quot;1614&quot; data-col-size=&quot;sm&quot;&gt;세계관 파괴 감시, 논리검증&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1673&quot; data-start=&quot;1634&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1647&quot; data-start=&quot;1634&quot;&gt;Hierarchy AI&lt;/td&gt;
&lt;td data-end=&quot;1673&quot; data-start=&quot;1647&quot; data-col-size=&quot;sm&quot;&gt;루트 월드 &amp;rarr; NPC/퀘스트/경제 세분화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1745&quot; data-start=&quot;1675&quot; data-ke-size=&quot;size16&quot;&gt;이건 사실상&lt;br /&gt;&lt;b&gt;게임 디자인 자동화 시스템&lt;/b&gt;이기도 하고&lt;br /&gt;&lt;b&gt;LLM 에이전트 멀티유니버스 시뮬레이터&lt;/b&gt;와도 닮아 있다.&lt;/p&gt;
&lt;hr data-end=&quot;1750&quot; data-start=&quot;1747&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1770&quot; data-start=&quot;1752&quot; data-ke-size=&quot;size26&quot;&gt;이런 시스템이 가능하면&amp;hellip;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1876&quot; data-start=&quot;1771&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1798&quot; data-start=&quot;1771&quot;&gt;플레이어 행동이 극도로 자유로운 오픈월드 구현&lt;/li&gt;
&lt;li data-end=&quot;1825&quot; data-start=&quot;1799&quot;&gt;NPC는 &amp;ldquo;프리-정해진 스크립트&amp;rdquo; 없이 행동&lt;/li&gt;
&lt;li data-end=&quot;1845&quot; data-start=&quot;1826&quot;&gt;메타-운영자 없이도 세계관 유지&lt;/li&gt;
&lt;li data-end=&quot;1876&quot; data-start=&quot;1846&quot;&gt;완전히 Emergent Gameplay 기반 MMO&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1934&quot; data-start=&quot;1878&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로&lt;br /&gt;&lt;b&gt;게임이 &amp;ldquo;피동적 콘텐츠&amp;rdquo;가 아니라&lt;br /&gt;스스로 성장하는 &amp;ldquo;살아있는 세계&amp;rdquo;가 된다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1939&quot; data-start=&quot;1936&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1958&quot; data-start=&quot;1941&quot; data-ke-size=&quot;size26&quot;&gt;왜 이 생각이 중요한가&lt;/h2&gt;
&lt;p data-end=&quot;2010&quot; data-start=&quot;1959&quot; data-ke-size=&quot;size16&quot;&gt;지금의 오픈월드는 사실 &amp;ldquo;거짓 자유&amp;rdquo;다.&lt;br /&gt;플레이어는 이미 설계된 트랙 위에서만 움직인다.&lt;/p&gt;
&lt;p data-end=&quot;2079&quot; data-start=&quot;2012&quot; data-ke-size=&quot;size16&quot;&gt;반면 이 아이디어는&lt;br /&gt;&amp;ldquo;플레이어 행동이 곧 게임 세계의 입력값이 되어,&lt;br /&gt;AI가 세계를 즉석에서 생성하고 유지한다.&amp;rdquo;&lt;/p&gt;
&lt;p data-end=&quot;2123&quot; data-start=&quot;2081&quot; data-ke-size=&quot;size16&quot;&gt;이는 기존 게임 디자인 모델(선형 설계, 분기형 시나리오)을 깨는 접근이다.&lt;/p&gt;
&lt;p data-end=&quot;2184&quot; data-start=&quot;2125&quot; data-ke-size=&quot;size16&quot;&gt;콘텐츠는 더 이상 &lt;b&gt;디자이너가 전부 만들지 않는다&lt;/b&gt;.&lt;br /&gt;AI가 동작하는 &lt;b&gt;세계 엔진&lt;/b&gt;이 생성한다.&lt;/p&gt;
&lt;hr data-end=&quot;2189&quot; data-start=&quot;2186&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2199&quot; data-start=&quot;2191&quot; data-ke-size=&quot;size26&quot;&gt;맺으며&lt;/h2&gt;
&lt;p data-end=&quot;2265&quot; data-start=&quot;2200&quot; data-ke-size=&quot;size16&quot;&gt;언어 모델이 문장 속 다음 단어를 예측하듯&lt;br /&gt;미래의 오픈월드 AI는 &lt;b&gt;세계 속 다음 사건을 예측&lt;/b&gt;할지도 모른다.&lt;/p&gt;
&lt;p data-end=&quot;2331&quot; data-start=&quot;2267&quot; data-ke-size=&quot;size16&quot;&gt;그 세계에서는&lt;br /&gt;플레이어는 단순한 참가자가 아니라,&lt;br /&gt;모델이 학습하는 &lt;b&gt;새로운 토큰 시퀀스의 원천&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;blockquote data-end=&quot;2372&quot; data-start=&quot;2333&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2372&quot; data-start=&quot;2335&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;언어 모델이 문장을 만들듯,&lt;br /&gt;게임 모델은 세계를 만든다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;2424&quot; data-start=&quot;2374&quot; data-ke-size=&quot;size16&quot;&gt;그때 게임은 더 이상&lt;br /&gt;제작된 세계가 아니라&lt;br /&gt;&lt;b&gt;살아 움직이는 세계&lt;/b&gt;가 될 것이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;아이디어 소스&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;LLM&amp;nbsp;에서&amp;nbsp;다음에&amp;nbsp;나올&amp;nbsp;단어를&amp;nbsp;추론하는&amp;nbsp;방법중에&amp;nbsp;탐욕알고리즘,&amp;nbsp;Beam&amp;nbsp;Search&amp;nbsp;등이&amp;nbsp;있다고&amp;nbsp;한다. &lt;/i&gt;&lt;br /&gt;&lt;i&gt;이때&amp;nbsp;Beam&amp;nbsp;Search는&amp;nbsp;top-k개의&amp;nbsp;후보를&amp;nbsp;유지한채,&amp;nbsp;다음에&amp;nbsp;나올&amp;nbsp;단어로&amp;nbsp;가장&amp;nbsp;적합한&amp;nbsp;후보를&amp;nbsp;선택한다고&amp;nbsp;한다. &lt;/i&gt;&lt;br /&gt;&lt;i&gt;LLM은&amp;nbsp;인간의&amp;nbsp;문맥을&amp;nbsp;토큰단위로&amp;nbsp;학습하여&amp;nbsp;다음&amp;nbsp;나올&amp;nbsp;토큰을&amp;nbsp;선택한다. &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;만약&amp;nbsp;모델이&amp;nbsp;학습하는것이&amp;nbsp;유저의&amp;nbsp;행동에&amp;nbsp;대한&amp;nbsp;결과라면...? &lt;/i&gt;&lt;br /&gt;&lt;i&gt;유저의&amp;nbsp;행동&amp;nbsp;-&amp;gt;&amp;nbsp;결과(보상,&amp;nbsp;퀘스트,&amp;nbsp;npc대응&amp;nbsp;등&amp;nbsp;멀티모달) &lt;/i&gt;&lt;br /&gt;&lt;i&gt;유저의&amp;nbsp;행동과&amp;nbsp;그에&amp;nbsp;따른&amp;nbsp;결과를&amp;nbsp;세트로&amp;nbsp;학습한다면&amp;nbsp;자유도있는&amp;nbsp;오픈월드를&amp;nbsp;구현할&amp;nbsp;수&amp;nbsp;있지&amp;nbsp;않을까?&amp;nbsp;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;아이디어&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;1. 유저 행동에 따른 가능성있는 top-k 후보를 추론하도록 구성한다.&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;2. 그리고 추론결과를 바로 반환하는것이 아니라, 추론 결과가 전체적인 월드를 해치지 않는지 자기회귀(self regression) 하도록 구성한다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;자기회귀에 사용되는 tool을 밸런싱조절 ai 모델로 구성하면 어떨까?&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;필요사항&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;1. 사람과 사람간의 행동-결과 데이터&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;2. 밸런싱 모델(보상 밸런스, 퀘스트 밸런스, 스킬 밸런스)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;3. AI와 AI간의 연결 (모든것을 관장하는 Root AI, 그 안에 다양한 AI 모델들..)&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>잡다한 아이디어</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/182</guid>
      <comments>https://ha2yong.tistory.com/182#entry182comment</comments>
      <pubDate>Tue, 4 Nov 2025 15:11:23 +0900</pubDate>
    </item>
    <item>
      <title>bisect 이진탐색 모듈</title>
      <link>https://ha2yong.tistory.com/181</link>
      <description>&lt;h2 data-end=&quot;152&quot; data-start=&quot;137&quot; data-ke-size=&quot;size26&quot;&gt;  1️⃣ 개념 정리&lt;/h2&gt;
&lt;p data-end=&quot;245&quot; data-start=&quot;154&quot; data-ke-size=&quot;size16&quot;&gt;bisect는 &lt;b&gt;정렬된 리스트(sorted list)&lt;/b&gt; 를 다룰 때,&lt;br /&gt;특정 값이 들어갈 위치를 &lt;b&gt;이진 탐색 방식(O(log N))&lt;/b&gt; 으로 찾아줍니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;292&quot; data-start=&quot;247&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;292&quot; data-start=&quot;249&quot; data-ke-size=&quot;size16&quot;&gt;  핵심 포인트: 리스트를 &amp;ldquo;정렬 상태로 유지한 채로&amp;rdquo; 삽입할 때 매우 유용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;297&quot; data-start=&quot;294&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;315&quot; data-start=&quot;299&quot; data-ke-size=&quot;size26&quot;&gt;  2️⃣ 기본 사용법&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761183035440&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import bisect

nums = [1, 3, 4, 7, 9]
x = 5

# 삽입할 위치 찾기
pos = bisect.bisect(nums, x)
print(pos)   # 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;489&quot; data-start=&quot;435&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 5는 인덱스 3 위치에 들어가야 [1,3,4,5,7,9]가 정렬 상태를 유지합니다.&lt;/p&gt;
&lt;hr data-end=&quot;494&quot; data-start=&quot;491&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;515&quot; data-start=&quot;496&quot; data-ke-size=&quot;size26&quot;&gt;⚙️ 3️⃣ 주요 함수 4가지&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 101px;&quot; border=&quot;1&quot; data-end=&quot;849&quot; data-start=&quot;517&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;함수&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;동작&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;619&quot; data-start=&quot;557&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;579&quot; data-start=&quot;557&quot;&gt;bisect_left(a, x)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;593&quot; data-start=&quot;579&quot; data-col-size=&quot;sm&quot;&gt;왼쪽 기준 삽입 위치&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;619&quot; data-start=&quot;593&quot; data-col-size=&quot;sm&quot;&gt;동일 값이 있을 때 &lt;b&gt;왼쪽&lt;/b&gt;으로 붙음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;703&quot; data-start=&quot;620&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;661&quot; data-start=&quot;620&quot;&gt;bisect_right(a, x) 또는 bisect(a, x)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;676&quot; data-start=&quot;661&quot; data-col-size=&quot;sm&quot;&gt;오른쪽 기준 삽입 위치&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;703&quot; data-start=&quot;676&quot; data-col-size=&quot;sm&quot;&gt;동일 값이 있을 때 &lt;b&gt;오른쪽&lt;/b&gt;으로 붙음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;766&quot; data-start=&quot;704&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;726&quot; data-start=&quot;704&quot;&gt;insort_left(a, x)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;752&quot; data-start=&quot;726&quot; data-col-size=&quot;sm&quot;&gt;실제로 &lt;b&gt;리스트에 삽입&lt;/b&gt; (왼쪽 기준)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;766&quot; data-start=&quot;752&quot; data-col-size=&quot;sm&quot;&gt;자동으로 정렬 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;849&quot; data-start=&quot;767&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;808&quot; data-start=&quot;767&quot;&gt;insort_right(a, x) 또는 insort(a, x)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;835&quot; data-start=&quot;808&quot; data-col-size=&quot;sm&quot;&gt;실제로 &lt;b&gt;리스트에 삽입&lt;/b&gt; (오른쪽 기준)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;849&quot; data-start=&quot;835&quot; data-col-size=&quot;sm&quot;&gt;자동으로 정렬 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;854&quot; data-start=&quot;851&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;874&quot; data-start=&quot;856&quot; data-ke-size=&quot;size26&quot;&gt;  4️⃣ 예시로 이해하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761183067501&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import bisect

arr = [10, 20, 30, 30, 40]

print(bisect.bisect_left(arr, 30))   # 2  &amp;larr; 30 앞에 삽입
print(bisect.bisect_right(arr, 30))  # 4  &amp;larr; 30 뒤에 삽입

bisect.insort(arr, 25)
print(arr)  # [10, 20, 25, 30, 30, 40]&lt;/code&gt;&lt;/pre&gt;
&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;# 4 &amp;larr; 30 뒤에 삽입&lt;/span&gt;&lt;/span&gt;&lt;span&gt; bisect.insort(arr, &lt;/span&gt;&lt;span&gt;&lt;span&gt;25&lt;/span&gt;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;&lt;span&gt;print&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(arr) &lt;/span&gt;&lt;span&gt;&lt;span&gt;# [10, 20, 25, 30, 30, 40]&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1106&quot; data-start=&quot;1103&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1124&quot; data-start=&quot;1108&quot; data-ke-size=&quot;size26&quot;&gt;⏱️ 5️⃣ 시간 복잡도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1282&quot; data-start=&quot;1126&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1206&quot; data-start=&quot;1126&quot;&gt;&lt;b&gt;삽입 위치 찾기 (bisect_left, bisect_right) &amp;rarr; O(log N)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 이진 탐색으로 위치를 찾음&lt;/li&gt;
&lt;li data-end=&quot;1282&quot; data-start=&quot;1207&quot;&gt;&lt;b&gt;실제 삽입 (insort) &amp;rarr; O(N)&lt;/b&gt;&lt;br /&gt;&amp;rarr; 위치 찾기는 빠르지만, &lt;b&gt;리스트는 배열 구조&lt;/b&gt;라 한 칸씩 밀어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1287&quot; data-start=&quot;1284&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1312&quot; data-start=&quot;1289&quot; data-ke-size=&quot;size26&quot;&gt;  6️⃣ 실무에서 어떻게 쓰이나?&lt;/h2&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1568&quot; data-start=&quot;1314&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;상황&lt;/td&gt;
&lt;td&gt;왜 bisect 쓰는가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1416&quot; data-start=&quot;1364&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1395&quot; data-start=&quot;1364&quot;&gt;데이터가 &lt;b&gt;항상 정렬된 상태&lt;/b&gt;로 유지돼야 할 때&lt;/td&gt;
&lt;td data-end=&quot;1416&quot; data-start=&quot;1395&quot; data-col-size=&quot;sm&quot;&gt;매번 sort()보다 효율적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1476&quot; data-start=&quot;1417&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1464&quot; data-start=&quot;1417&quot;&gt;&lt;b&gt;순위(rank)&lt;/b&gt;, &lt;b&gt;중간값(median)&lt;/b&gt;, &lt;b&gt;통계 백분위&lt;/b&gt; 계산&lt;/td&gt;
&lt;td data-end=&quot;1476&quot; data-start=&quot;1464&quot; data-col-size=&quot;sm&quot;&gt;빠른 위치 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1523&quot; data-start=&quot;1477&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1507&quot; data-start=&quot;1477&quot;&gt;&lt;b&gt;시간/점수/가격&lt;/b&gt; 같은 정렬된 이벤트 스트림&lt;/td&gt;
&lt;td data-end=&quot;1523&quot; data-start=&quot;1507&quot; data-col-size=&quot;sm&quot;&gt;새 데이터 실시간 삽입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1568&quot; data-start=&quot;1524&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1545&quot; data-start=&quot;1524&quot;&gt;&lt;b&gt;이진 탐색 기반 조건 검사&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1568&quot; data-start=&quot;1545&quot; data-col-size=&quot;sm&quot;&gt;직접 while 루프 짤 필요 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1573&quot; data-start=&quot;1570&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1603&quot; data-start=&quot;1575&quot; data-ke-size=&quot;size26&quot;&gt;  7️⃣ 예제 &amp;mdash; 정렬된 리스트에 값 삽입&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761183101751&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import bisect

scores = [10, 30, 50, 70, 90]
new_score = 65

idx = bisect.bisect_left(scores, new_score)
scores.insert(idx, new_score)
print(scores)  # [10, 30, 50, 65, 70, 90]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1800&quot; data-start=&quot;1797&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1842&quot; data-start=&quot;1802&quot; data-ke-size=&quot;size26&quot;&gt;  8️⃣ 예제 &amp;mdash; 범위 내 원소 개수 구하기 (이진 탐색 응용)&lt;/h2&gt;
&lt;p data-end=&quot;1903&quot; data-start=&quot;1844&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 [1,3,5,7,9,11,13] 에서 5 &amp;le; x &amp;le; 10 인 원소의 개수를 찾고 싶다면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761183111384&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from bisect import bisect_left, bisect_right

arr = [1,3,5,7,9,11,13]
left = bisect_left(arr, 5)
right = bisect_right(arr, 10)
print(right - left)  # 3 (5,7,9)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2127&quot; data-start=&quot;2080&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;O(log N)&lt;/b&gt; 만에 범위 개수 계산 가능 (리스트 길이에 비례하지 않음)&lt;/p&gt;
&lt;hr data-end=&quot;2132&quot; data-start=&quot;2129&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2145&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-start=&quot;2134&quot; data-end=&quot;2145&quot; data-ke-size=&quot;size26&quot;&gt;9️⃣ 예제 - 정렬된 리스트에서 특정 숫자가 존재하는지 여부&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬된 리스트 arr에서 어떤 값 x가 존재하는지는 이렇게 판단할 수 있어요  &lt;/p&gt;
&lt;pre id=&quot;code_1761183156349&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from bisect import bisect_left

# 1️⃣ 정렬된 상태의 리스트
arr = [1, 3, 4, 7, 9, 11]

# 2️⃣ x가 들어갈 위치를 이진 탐색으로 찾는다
x = 7
idx = bisect_left(arr, x)

# 3️⃣ 그 위치가 리스트 범위 안에 있고 arr[idx] == x 이면 존재
if idx &amp;lt; len(arr) and arr[idx] == x:
    print(&quot;✅ 존재함&quot;)
else:
    print(&quot;❌ 존재하지 않음&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;⏱️ 시간복잡도 비교&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;방법&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;복잡도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;x in arr (list)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;선형탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;bisect_left + 비교&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;O(log N)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;이진탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;x in set&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;평균 O(1)&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;해시 탐색 (정렬 불필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-end=&quot;2145&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;2145&quot; data-start=&quot;2134&quot; data-ke-size=&quot;size26&quot;&gt;9️⃣ 요약&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;항목설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2431&quot; data-start=&quot;2147&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2431&quot; data-start=&quot;2175&quot;&gt;
&lt;tr data-end=&quot;2199&quot; data-start=&quot;2175&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2180&quot; data-start=&quot;2175&quot;&gt;모듈&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2199&quot; data-start=&quot;2180&quot;&gt;import bisect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2232&quot; data-start=&quot;2200&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2208&quot; data-start=&quot;2200&quot;&gt;핵심 기능&lt;/td&gt;
&lt;td data-end=&quot;2232&quot; data-start=&quot;2208&quot; data-col-size=&quot;md&quot;&gt;정렬 리스트 내 빠른 삽입 위치 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2270&quot; data-start=&quot;2233&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2242&quot; data-start=&quot;2233&quot;&gt;시간 복잡도&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2270&quot; data-start=&quot;2242&quot;&gt;O(log N) (탐색), O(N) (삽입)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2343&quot; data-start=&quot;2271&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2279&quot; data-start=&quot;2271&quot;&gt;주요 함수&lt;/td&gt;
&lt;td data-end=&quot;2343&quot; data-start=&quot;2279&quot; data-col-size=&quot;md&quot;&gt;bisect_left, bisect_right, insort_left, insort_right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2389&quot; data-start=&quot;2344&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2356&quot; data-start=&quot;2344&quot;&gt;비슷한 내장 함수&lt;/td&gt;
&lt;td data-end=&quot;2389&quot; data-start=&quot;2356&quot; data-col-size=&quot;md&quot;&gt;list.index() (O(N), 정렬 불필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2431&quot; data-start=&quot;2390&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2401&quot; data-start=&quot;2390&quot;&gt;대표 사용 사례&lt;/td&gt;
&lt;td data-col-size=&quot;md&quot; data-end=&quot;2431&quot; data-start=&quot;2401&quot;&gt;실시간 정렬 유지, 순위 계산, 범위 개수 세기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>공부/자료구조,알고리즘_python</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/181</guid>
      <comments>https://ha2yong.tistory.com/181#entry181comment</comments>
      <pubDate>Thu, 23 Oct 2025 10:33:54 +0900</pubDate>
    </item>
    <item>
      <title>[순차탐색] in 연산자 시간복잡도 비교</title>
      <link>https://ha2yong.tistory.com/180</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wiki.python.org/moin/TimeComplexity&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.python.org/moin/TimeComplexity&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1761181796823&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;TimeComplexity - Python Wiki&quot; data-og-description=&quot;This page documents the time-complexity (aka &amp;quot;Big O&amp;quot; or &amp;quot;Big Oh&amp;quot;) of various operations in current CPython. Other Python implementations (or older or still-under development versions of CPython) may have slightly different performance characteristics. Howe&quot; data-og-host=&quot;wiki.python.org&quot; data-og-source-url=&quot;https://wiki.python.org/moin/TimeComplexity&quot; data-og-url=&quot;https://wiki.python.org/moin/TimeComplexity&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://wiki.python.org/moin/TimeComplexity&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://wiki.python.org/moin/TimeComplexity&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;TimeComplexity - Python Wiki&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This page documents the time-complexity (aka &quot;Big O&quot; or &quot;Big Oh&quot;) of various operations in current CPython. Other Python implementations (or older or still-under development versions of CPython) may have slightly different performance characteristics. Howe&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wiki.python.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;주제: in 연산자는 어떤 자료형을 탐색하느냐에 따라 시간복잡도의 차이가 발생한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;133&quot; data-start=&quot;102&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1) list / tuple / deque&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;369&quot; data-start=&quot;134&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;177&quot; data-start=&quot;134&quot;&gt;&lt;b&gt;구조:&lt;/b&gt; 연속 배열(리스트/튜플), 양방향 연결 버퍼(deque)&lt;/li&gt;
&lt;li data-end=&quot;239&quot; data-start=&quot;178&quot;&gt;&lt;b&gt;동작:&lt;/b&gt; 왼쪽부터 &lt;b&gt;순차 비교(Linear scan)&lt;/b&gt; &amp;rarr; 값이 같을 때까지 하나씩 == 비교&lt;/li&gt;
&lt;li data-end=&quot;265&quot; data-start=&quot;240&quot;&gt;&lt;b&gt;복잡도:&lt;/b&gt; 평균/최악 &lt;b&gt;O(N)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;369&quot; data-start=&quot;266&quot;&gt;&lt;b&gt;비고:&lt;/b&gt; 정렬된 리스트라면 in 대신 &lt;b&gt;이진탐색&lt;/b&gt;(예: bisect)을 쓰면 &lt;b&gt;O(log N)&lt;/b&gt; 로 가능.&lt;br /&gt;단, in 자체는 이진탐색을 쓰지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1761181882521&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;x in [a, b, c, ...]     # O(N)
x in tuple_of_items     # O(N)
x in deque_of_items     # O(N)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;503&quot; data-start=&quot;484&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2) set / dict&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;908&quot; data-start=&quot;504&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;524&quot; data-start=&quot;504&quot;&gt;&lt;b&gt;구조:&lt;/b&gt; &lt;b&gt;해시 테이블&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;565&quot; data-start=&quot;525&quot;&gt;&lt;b&gt;동작:&lt;/b&gt; hash(x)로 버킷을 계산해 해당 버킷에서만 비교&lt;/li&gt;
&lt;li data-end=&quot;647&quot; data-start=&quot;566&quot;&gt;&lt;b&gt;복잡도:&lt;/b&gt; 평균 &lt;b&gt;O(1)&lt;/b&gt;, 최악(충돌 심함) &lt;b&gt;O(N)&lt;/b&gt;&lt;br /&gt;(파이썬은 리사이즈&amp;middot;로드팩터 관리로 평균 O(1)를 잘 유지)&lt;/li&gt;
&lt;li data-end=&quot;734&quot; data-start=&quot;648&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; 원소는 &lt;b&gt;해시 가능(불변&amp;middot;hashable)&lt;/b&gt; 해야 함. list/dict는 안 되고, tuple(내부도 불변이면)는 가능.&lt;/li&gt;
&lt;li data-end=&quot;908&quot; data-start=&quot;735&quot;&gt;&lt;b&gt;딕셔너리의 in:&lt;/b&gt; &lt;b&gt;키&lt;/b&gt;에 대한 멤버십 검사입니다.&lt;br /&gt;x in my_dict &amp;rarr; x in my_dict.keys()와 동일(평균 O(1)).&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;908&quot; data-start=&quot;833&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;908&quot; data-start=&quot;833&quot;&gt;x in my_dict.values() / x in my_dict.items() 는 &lt;b&gt;선형탐색 O(N)&lt;/b&gt; 이라 느립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1761181976437&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;x in {a, b, c}          # 평균 O(1)
key in {&quot;k&quot;: 1}         # 평균 O(1)  (키 검사)
val in {&quot;k&quot;: 1}.values()# O(N)       (값 검사)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1066&quot; data-start=&quot;1045&quot; data-ke-size=&quot;size20&quot;&gt;(해시 기반이 O(1)인 이유)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1248&quot; data-start=&quot;1067&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1134&quot; data-start=&quot;1067&quot;&gt;set/dict는 &lt;b&gt;버킷 배열&lt;/b&gt;을 두고, hash(x) % capacity 로 위치를 바로 찾아갑니다.&lt;/li&gt;
&lt;li data-end=&quot;1203&quot; data-start=&quot;1135&quot;&gt;동일 해시의 원소가 많아지면 충돌 체인을 따라 비교하므로 느려질 수 있어 &lt;b&gt;로드팩터 임계&lt;/b&gt;에서 자동 리사이즈합니다.&lt;/li&gt;
&lt;li data-end=&quot;1248&quot; data-start=&quot;1204&quot;&gt;평균적으로 충돌 길이를 짧게 유지하여 &lt;b&gt;상수 시간&lt;/b&gt;에 가깝게 동작합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1271&quot; data-start=&quot;1255&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3) str (문자열)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1496&quot; data-start=&quot;1272&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1321&quot; data-start=&quot;1272&quot;&gt;&lt;b&gt;단일 문자 검사:&lt;/b&gt; ch in text &amp;rarr; 선형 탐색, 평균 &lt;b&gt;O(N)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1419&quot; data-start=&quot;1322&quot;&gt;&lt;b&gt;부분문자열 검사:&lt;/b&gt; pat in text &amp;rarr; 전통적으론 &lt;b&gt;O(N&amp;middot;M)&lt;/b&gt; 이지만 CPython은 &lt;b&gt;Two-Way&lt;/b&gt; 등 최적화로 평균 O(N)에 가깝게 동작.&lt;/li&gt;
&lt;li data-end=&quot;1496&quot; data-start=&quot;1420&quot;&gt;&lt;b&gt;비고:&lt;/b&gt; 매우 큰 텍스트에서는 re(정규식), find(), index() 등 전용 알고리즘을 쓰는 게 더 낫습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1761182045817&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'a' in 'banana'       # O(N)
'ana' in 'banana'     # ~O(N) (내부 최적화)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;1623&quot; data-start=&quot;1586&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4) 왜 &amp;ldquo;list&amp;rarr;set 변환&amp;rdquo;이 빠를까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-end=&quot;1704&quot; data-start=&quot;1624&quot; data-ke-size=&quot;size16&quot;&gt;멤버십 검사를 &lt;b&gt;여러 번&lt;/b&gt; 할 때는, 한 번의 변환 비용(O(N))을 내고 &lt;b&gt;평균 O(1)&lt;/b&gt; 조회를 반복하는 편이 압도적으로 유리합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1765&quot; data-start=&quot;1706&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1731&quot; data-start=&quot;1706&quot;&gt;리스트에서 M번 검사: &lt;b&gt;O(M&amp;middot;N)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1765&quot; data-start=&quot;1732&quot;&gt;세트로 변환 후 M번 검사: &lt;b&gt;O(N) + O(M)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1893&quot; data-start=&quot;1767&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1893&quot; data-start=&quot;1769&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;의사결정 팁&lt;/b&gt;&lt;br /&gt;&amp;ndash; 한 번만 검사하면: 그냥 리스트에서도 괜찮음&lt;br /&gt;&amp;ndash; 많이 검사하면(M이 크면): &lt;b&gt;set으로 변환&lt;/b&gt;이 유리&lt;br /&gt;&amp;ndash; 이미 키만 검사하면: &lt;b&gt;dict 키 집합&lt;/b&gt;을 그대로 활용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1761182129520&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;menus = ['ramen', 'sushi', 'pasta', ...]   # N개
queries = ['sushi', 'taco', ...]           # M개

# 느린 버전: O(M&amp;middot;N)
for q in queries:
    if q in menus:
        ...

# 빠른 버전: O(N) + O(M)
menu_set = set(menus)
for q in queries:
    if q in menu_set:   # 평균 O(1)
        ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5) 요약 표 &lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 x in container 평균 복잡도 내부 구조 비고&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;컨테이너&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt; x in container 평균 복잡도 &lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt; 내부 구조 &lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;비고&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;list / tuple / deque&lt;/td&gt;
&lt;td&gt;&lt;b&gt;O(N)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;배열/연결버퍼&lt;/td&gt;
&lt;td&gt;선형 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set&lt;/td&gt;
&lt;td&gt;&lt;b&gt;O(1)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;원소는 hashable 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dict&lt;/td&gt;
&lt;td&gt;&lt;b&gt;O(1)&lt;/b&gt; (키)&lt;/td&gt;
&lt;td&gt;해시 테이블&lt;/td&gt;
&lt;td&gt;x in d는 키 검사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dict.values() / .items()&lt;/td&gt;
&lt;td&gt;&lt;b&gt;O(N)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;선형 탐색&lt;/td&gt;
&lt;td&gt;값/쌍 검사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str (문자/부분문자열)&lt;/td&gt;
&lt;td&gt;~&lt;b&gt;O(N)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특화 검색&lt;/td&gt;
&lt;td&gt;내부 최적화 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진탐색시에 문자열 &quot;가나다&quot; 도 크기 비교가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한글을 유니코드값으로 바꿔서 크기를 비교함&lt;/p&gt;</description>
      <category>공부/자료구조,알고리즘_python</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/180</guid>
      <comments>https://ha2yong.tistory.com/180#entry180comment</comments>
      <pubDate>Thu, 23 Oct 2025 10:18:43 +0900</pubDate>
    </item>
    <item>
      <title>2. collections 활용 패턴</title>
      <link>https://ha2yong.tistory.com/179</link>
      <description>&lt;h2 data-end=&quot;258&quot; data-start=&quot;213&quot; data-ke-size=&quot;size26&quot;&gt;1.&amp;nbsp; Counter &amp;mdash; 토큰/클래스 빈도 분석, 통계 기반 전처리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;364&quot; data-start=&quot;275&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;321&quot; data-start=&quot;275&quot;&gt;자연어 처리(NLP)에서 &lt;b&gt;단어 빈도(Word Frequency)&lt;/b&gt; 계산&lt;/li&gt;
&lt;li data-end=&quot;364&quot; data-start=&quot;322&quot;&gt;분류(Classification) 문제에서 &lt;b&gt;클래스 불균형 확인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761108976182&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import Counter

# 예: 토큰 빈도 계산
tokens = [&quot;apple&quot;, &quot;banana&quot;, &quot;apple&quot;, &quot;grape&quot;, &quot;banana&quot;, &quot;apple&quot;]
word_freq = Counter(tokens)

print(word_freq.most_common(2))  # [('apple', 3), ('banana', 2)]

# 예: 데이터셋 클래스 비율 확인
labels = [&quot;cat&quot;, &quot;dog&quot;, &quot;cat&quot;, &quot;bird&quot;, &quot;cat&quot;, &quot;dog&quot;]
label_dist = Counter(labels)

for cls, cnt in label_dist.items():
    print(f&quot;{cls}: {cnt/len(labels):.2%}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;795&quot; data-start=&quot;781&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;918&quot; data-start=&quot;796&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;839&quot; data-start=&quot;796&quot;&gt;토큰 출현 확률(P(word)) 계산 &amp;rarr; 언어 모델 확률분포에 사용&lt;/li&gt;
&lt;li data-end=&quot;888&quot; data-start=&quot;840&quot;&gt;클래스 imbalance 체크 후 &lt;b&gt;가중치(weighted loss)&lt;/b&gt; 조정&lt;/li&gt;
&lt;li data-end=&quot;918&quot; data-start=&quot;889&quot;&gt;TF-IDF 전처리 시 빈도 기반 정규화 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;923&quot; data-start=&quot;920&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;968&quot; data-start=&quot;925&quot; data-ke-size=&quot;size26&quot;&gt;2. deque &amp;mdash; 실시간 데이터 스트림&amp;middot;슬라이딩 윈도우 버퍼&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1066&quot; data-start=&quot;985&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1025&quot; data-start=&quot;985&quot;&gt;영상/음성/센서 데이터를 &lt;b&gt;최근 N개만 유지&lt;/b&gt;하며 스트림 처리&lt;/li&gt;
&lt;li data-end=&quot;1066&quot; data-start=&quot;1026&quot;&gt;실시간 추론에서 FPS 고정 or moving average 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761109006641&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque
import numpy as np

# 최근 30프레임만 유지하는 슬라이딩 윈도우 버퍼
window = deque(maxlen=30)

for frame in stream_generator():  # 예: 실시간 카메라 프레임
    value = model.predict(frame)
    window.append(value)

    # 최근 30프레임 평균값으로 smoothing
    smoothed = np.mean(window)
    print(f&quot;Smoothed output: {smoothed:.2f}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1429&quot; data-start=&quot;1417&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1559&quot; data-start=&quot;1430&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1469&quot; data-start=&quot;1430&quot;&gt;O(1)로 양끝 삽입/삭제 가능 &amp;rarr; FPS 고정 루프에서 효율적&lt;/li&gt;
&lt;li data-end=&quot;1506&quot; data-start=&quot;1470&quot;&gt;LSTM, RNN 등에서 시퀀스 윈도우 관리에 자주 사용됨&lt;/li&gt;
&lt;li data-end=&quot;1559&quot; data-start=&quot;1507&quot;&gt;실시간 anomaly detection에서도 sliding window 기반 통계 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1564&quot; data-start=&quot;1561&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1618&quot; data-start=&quot;1566&quot; data-ke-size=&quot;size26&quot;&gt;3. defaultdict &amp;mdash; 그룹화, 임시 캐시, 파이프라인 중간 결과 저장&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1694&quot; data-start=&quot;1635&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1672&quot; data-start=&quot;1635&quot;&gt;데이터셋을 특정 기준으로 그룹핑 (e.g., 클래스별 샘플)&lt;/li&gt;
&lt;li data-end=&quot;1694&quot; data-start=&quot;1673&quot;&gt;전처리 단계에서 중간 캐시 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761109021212&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import defaultdict

samples = [
    (&quot;cat&quot;, &quot;img001.jpg&quot;),
    (&quot;dog&quot;, &quot;img002.jpg&quot;),
    (&quot;cat&quot;, &quot;img003.jpg&quot;),
    (&quot;bird&quot;, &quot;img004.jpg&quot;),
]

grouped = defaultdict(list)
for label, path in samples:
    grouped[label].append(path)

print(grouped[&quot;cat&quot;])  # ['img001.jpg', 'img003.jpg']&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2037&quot; data-start=&quot;2025&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2152&quot; data-start=&quot;2038&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2080&quot; data-start=&quot;2038&quot;&gt;데이터 로더(DataLoader) 전 단계에서 클래스별 파일 분류&lt;/li&gt;
&lt;li data-end=&quot;2110&quot; data-start=&quot;2081&quot;&gt;학습 로그나 실험 결과를 태그별로 자동 그룹핑&lt;/li&gt;
&lt;li data-end=&quot;2152&quot; data-start=&quot;2111&quot;&gt;json이나 yaml 구성 파싱 시 누락 키에 안전한 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2157&quot; data-start=&quot;2154&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2210&quot; data-start=&quot;2159&quot; data-ke-size=&quot;size26&quot;&gt;4. OrderedDict &amp;mdash; 모델 레이어 순서, LRU 캐시, 설정 트래킹&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2332&quot; data-start=&quot;2227&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2275&quot; data-start=&quot;2227&quot;&gt;PyTorch에서 &lt;b&gt;모델 레이어 순서 보존&lt;/b&gt; (nn.Sequential)&lt;/li&gt;
&lt;li data-end=&quot;2301&quot; data-start=&quot;2276&quot;&gt;&lt;b&gt;최근 사용된 결과 캐싱(LRU)&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2332&quot; data-start=&quot;2302&quot;&gt;실험 설정(config) 순서를 명시적으로 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761109039829&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import OrderedDict
import torch.nn as nn

model = nn.Sequential(OrderedDict([
    ('conv1', nn.Conv2d(3, 16, 3, padding=1)),
    ('relu1', nn.ReLU()),
    ('conv2', nn.Conv2d(16, 32, 3, padding=1)),
    ('relu2', nn.ReLU())
]))

print(model)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2630&quot; data-start=&quot;2618&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2758&quot; data-start=&quot;2631&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2672&quot; data-start=&quot;2631&quot;&gt;모델 정의 순서가 정확히 일치해야 reproducibility 확보&lt;/li&gt;
&lt;li data-end=&quot;2708&quot; data-start=&quot;2673&quot;&gt;학습 로그나 설정 저장 시 &lt;b&gt;순서 보존&lt;/b&gt;이 중요할 때&lt;/li&gt;
&lt;li data-end=&quot;2758&quot; data-start=&quot;2709&quot;&gt;OrderedDict.move_to_end() 활용 &amp;rarr; 캐시, 최근 접근 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2763&quot; data-start=&quot;2760&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2826&quot; data-start=&quot;2765&quot; data-ke-size=&quot;size26&quot;&gt;5. ChainMap &amp;mdash; 다중 설정(environment + config + override)&lt;/h2&gt;
&lt;p data-end=&quot;2936&quot; data-start=&quot;2843&quot; data-ke-size=&quot;size16&quot;&gt;AI 프로젝트는 여러 환경(config) 파일을 계층적으로 관리&lt;br /&gt;(예: defaults.yaml, local.yaml, args, env)&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761109057434&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import ChainMap
import os

defaults = {'batch_size': 32, 'lr': 0.001}
user_cfg = {'lr': 0.0005}
env_cfg = {'batch_size': int(os.getenv('BATCH', 64))}

config = ChainMap(env_cfg, user_cfg, defaults)

print(config['batch_size'])  # 환경 변수 &amp;gt; 사용자 &amp;gt; 기본값 순서&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3243&quot; data-start=&quot;3231&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3336&quot; data-start=&quot;3244&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3264&quot; data-start=&quot;3244&quot;&gt;모델 학습 설정 우선순위 관리&lt;/li&gt;
&lt;li data-end=&quot;3288&quot; data-start=&quot;3265&quot;&gt;실험 파라미터 병합 시 충돌 최소화&lt;/li&gt;
&lt;li data-end=&quot;3336&quot; data-start=&quot;3289&quot;&gt;Hydra, OmegaConf 같은 config 라이브러리의 핵심 개념과 동일&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3341&quot; data-start=&quot;3338&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3402&quot; data-start=&quot;3343&quot; data-ke-size=&quot;size26&quot;&gt;6. namedtuple &amp;mdash; lightweight 데이터 구조 (벡터, 설정, 예측 결과)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3491&quot; data-start=&quot;3419&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3470&quot; data-start=&quot;3419&quot;&gt;딥러닝 inference 결과를 (label, score, bbox) 등으로 관리&lt;/li&gt;
&lt;li data-end=&quot;3491&quot; data-start=&quot;3471&quot;&gt;벡터/포인트 데이터 구조 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1761109077270&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import namedtuple

Prediction = namedtuple('Prediction', ['label', 'score', 'bbox'])
preds = [
    Prediction('cat', 0.97, (10, 20, 100, 200)),
    Prediction('dog', 0.83, (30, 40, 120, 240))
]

for p in preds:
    print(f&quot;{p.label}: {p.score*100:.1f}%&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3802&quot; data-start=&quot;3790&quot; data-ke-size=&quot;size16&quot;&gt;✅ &lt;b&gt;활용 포인트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3914&quot; data-start=&quot;3803&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3833&quot; data-start=&quot;3803&quot;&gt;객체 생성 오버헤드 없이 가벼운 구조체처럼 사용&lt;/li&gt;
&lt;li data-end=&quot;3876&quot; data-start=&quot;3834&quot;&gt;PyTorch Dataset/Batch 내에서 sample 구조 관리&lt;/li&gt;
&lt;li data-end=&quot;3914&quot; data-start=&quot;3877&quot;&gt;불변이므로 멀티프로세싱(shared memory)에서도 안전&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;3919&quot; data-start=&quot;3916&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;3933&quot; data-start=&quot;3921&quot; data-ke-size=&quot;size26&quot;&gt;요약표&lt;/h2&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;4306&quot; data-start=&quot;3935&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;자료구조&lt;/td&gt;
&lt;td&gt;활용 분야&lt;/td&gt;
&lt;td&gt;대표 예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4055&quot; data-start=&quot;4008&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4020&quot; data-start=&quot;4008&quot;&gt;Counter&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4034&quot; data-start=&quot;4020&quot;&gt;NLP, 데이터 통계&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4055&quot; data-start=&quot;4034&quot;&gt;단어/클래스 빈도, TF-IDF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4117&quot; data-start=&quot;4056&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4066&quot; data-start=&quot;4056&quot;&gt;deque&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4085&quot; data-start=&quot;4066&quot;&gt;실시간 처리, 슬라이딩 윈도우&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4117&quot; data-start=&quot;4085&quot;&gt;FPS smoothing, stream buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4162&quot; data-start=&quot;4118&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4134&quot; data-start=&quot;4118&quot;&gt;defaultdict&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4148&quot; data-start=&quot;4134&quot;&gt;데이터 그룹화, 캐시&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4162&quot; data-start=&quot;4148&quot;&gt;클래스별 샘플 분류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4221&quot; data-start=&quot;4163&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4179&quot; data-start=&quot;4163&quot;&gt;OrderedDict&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4191&quot; data-start=&quot;4179&quot;&gt;모델 정의, 캐시&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4221&quot; data-start=&quot;4191&quot;&gt;nn.Sequential, LRU cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4261&quot; data-start=&quot;4222&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4235&quot; data-start=&quot;4222&quot;&gt;ChainMap&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4243&quot; data-start=&quot;4235&quot;&gt;설정 병합&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4261&quot; data-start=&quot;4243&quot;&gt;config/환경변수 통합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;4306&quot; data-start=&quot;4262&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4277&quot; data-start=&quot;4262&quot;&gt;namedtuple&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4289&quot; data-start=&quot;4277&quot;&gt;경량 데이터 구조&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;4306&quot; data-start=&quot;4289&quot;&gt;예측 결과, 좌표, 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>공부/자료구조,알고리즘_python</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/179</guid>
      <comments>https://ha2yong.tistory.com/179#entry179comment</comments>
      <pubDate>Wed, 22 Oct 2025 13:58:38 +0900</pubDate>
    </item>
    <item>
      <title>1. 파이썬 고급 자료구조 collections</title>
      <link>https://ha2yong.tistory.com/178</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 168px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;클래스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;핵심 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;주요 특징/ 사용 예시&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;namedtuple&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;튜플의 필드에 이름 부여&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;불변(immutable) 구조, 클래스처럼 필드 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;deque&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;양쪽에서 빠른 삽입/삭제&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;스택&amp;middot;큐&amp;middot;슬라이딩 윈도우 구현에 최적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;Counter&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;요소 개수 세기&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;리스트/문자열의 빈도 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;defaultdict&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;기본값을 갖는 딕셔너리&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;존재하지 않는 키 접근 시 자동 초기화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;OrderedDict&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;순서가 유지되는 딕셔너리&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;LRU Cache 등 순서 기반 로직 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;ChainMap&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;여러 딕셔너리를 묶어 하나처럼 다룸&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;다중 스코프 환경에서 키 검색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;&lt;b&gt;UserDict, UserList, UserString&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;커스텀 자료형 구현용 Wrapper&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;상속/오버라이드로 사용자 정의 자료구조 만들 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. namedtuple&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜플은 순서로만 접근한다.&lt;br /&gt;하지만 필드 이름으로 접근하면 코드 가독성이 훨씬 좋아진다.&lt;/p&gt;
&lt;pre id=&quot;code_1761107907278&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)

print(p.x, p.y)   # 10 20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 메모리 효율 높음&lt;br /&gt;✅ 클래스보다 가볍고 빠름&lt;br /&gt;✅ 불변(immutable)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. deque &amp;mdash; 양방향 큐 (Double-ended Queue)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트는 중간 삽입/삭제가 느리지만,&lt;br /&gt;deque는 &lt;b&gt;양쪽 끝 삽입/삭제가 모두 O(1)&lt;/b&gt; 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1761107975739&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import deque

dq = deque([1, 2, 3])
dq.append(4)        # 오른쪽 삽입
dq.appendleft(0)    # 왼쪽 삽입
dq.pop()            # 오른쪽 삭제
dq.popleft()        # 왼쪽 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 큐, 스택, 슬라이딩 윈도우 등에 활용&lt;br /&gt;✅ 내부적으로 &lt;b&gt;양방향 링크드리스트&lt;/b&gt; 기반&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Counter &amp;mdash; 항목의 빈도(개수) 계산 &lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1761108062818&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import Counter

cnt = Counter(&quot;banana&quot;)
print(cnt)          # Counter({'a': 3, 'n': 2, 'b': 1})
print(cnt.most_common(2))  # [('a', 3), ('n', 2)]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 문자열, 리스트, 로그 등 &lt;b&gt;빈도 분석&lt;/b&gt;에 강력&lt;br /&gt;✅ 덧셈/뺄셈 연산도 가능&lt;/p&gt;
&lt;pre id=&quot;code_1761108112578&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a = Counter(&quot;hello&quot;)
b = Counter(&quot;world&quot;)
print(a + b)  # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, 'w': 1, 'r': 1, 'd': 1})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. defaultdict &amp;mdash; 기본값이 있는 딕셔너리 &lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1761108217177&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import defaultdict

d = defaultdict(int)  # 기본값 0
d['apple'] += 1
print(d)  # defaultdict(&amp;lt;class 'int'&amp;gt;, {'apple': 1})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 키가 없을 때 자동 초기화 (KeyError 없음)&lt;br /&gt;✅ 기본값 타입은 int, list, set 등 지정 가능&lt;/p&gt;
&lt;pre id=&quot;code_1761108229785&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;words = ['apple', 'banana', 'apple']
group = defaultdict(list)
for w in words:
    group[w[0]].append(w)
# {'a': ['apple', 'apple'], 'b': ['banana']}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 5. OrderedDict &amp;mdash; 순서를 기억하는 딕셔너리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 3.7 이상부터 기본 dict도 순서를 유지하지만,&lt;br /&gt;&lt;b&gt;OrderedDict는 순서 조작 메서드(move_to_end 등)&lt;/b&gt; 이 추가로 제공된다.&lt;/p&gt;
&lt;pre id=&quot;code_1761108291937&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import OrderedDict

od = OrderedDict()
od['a'] = 1
od['b'] = 2
od.move_to_end('a')   # a를 맨 뒤로
print(od)             # OrderedDict([('b', 2), ('a', 1)])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ LRU Cache 구현 시 자주 사용됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 6. ChainMap &amp;mdash; 여러 딕셔너리 묶기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1761108352312&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import ChainMap

defaults = {'theme': 'light', 'lang': 'en'}
user = {'lang': 'ko'}
config = ChainMap(user, defaults)

print(config['lang'])   # ko (user 우선)
print(config['theme'])  # light (defaults에서 가져옴)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 여러 설정 파일, 환경 변수 계층 구조 관리에 유용&lt;br /&gt;✅ 조회 시 앞쪽 딕셔너리부터 탐색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; 7. UserDict, UserList, UserString &amp;mdash; 사용자 정의 확장 &lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1761108386901&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import UserDict

class MyDict(UserDict):
    def __getitem__(self, key):
        print(f&quot;Accessing {key}&quot;)
        return super().__getitem__(key)

d = MyDict({'a': 1})
print(d['a'])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✅ 커스텀 자료형 제작 시 안전하고 직관적&lt;/p&gt;</description>
      <category>공부/자료구조,알고리즘_python</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/178</guid>
      <comments>https://ha2yong.tistory.com/178#entry178comment</comments>
      <pubDate>Wed, 22 Oct 2025 13:55:25 +0900</pubDate>
    </item>
    <item>
      <title>[프로젝트 후일담] Docker 기반 런타임</title>
      <link>https://ha2yong.tistory.com/177</link>
      <description>&lt;h1 data-end=&quot;102&quot; data-start=&quot;80&quot;&gt;요약&lt;/h1&gt;
&lt;p data-end=&quot;135&quot; data-start=&quot;38&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;Docker를 활용하여 리눅스 기반 런타임을 구현하였으며, 서비스별 의존성을 분리하고, 개발환경 차이에 따른 재현성을 높였으며, 추후 배포 시 이식성을 고려하였다.&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;141&quot; data-start=&quot;137&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;312&quot; data-start=&quot;142&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;198&quot; data-start=&quot;142&quot;&gt;&lt;b&gt;리눅스 기반 런타임&lt;/b&gt;: Docker Desktop(WLS2) 위에서 리눅스 컨테이너 실행&lt;/li&gt;
&lt;li data-end=&quot;245&quot; data-start=&quot;199&quot;&gt;&lt;b&gt;의존성 분리&lt;/b&gt;: YOLO, STT, LangGraph 각각 격리된 환경&lt;/li&gt;
&lt;li data-end=&quot;276&quot; data-start=&quot;246&quot;&gt;&lt;b&gt;재현성&lt;/b&gt;: 팀원/환경이 달라도 동일한 결과&lt;/li&gt;
&lt;li data-end=&quot;312&quot; data-start=&quot;277&quot;&gt;&lt;b&gt;이식성&lt;/b&gt;: 로컬 &amp;harr; 서버 배포가 동일 이미지로 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 data-end=&quot;102&quot; data-start=&quot;80&quot;&gt;A-EYE의 Docker 구조 한눈에&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;579&quot; data-start=&quot;103&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;206&quot; data-start=&quot;103&quot;&gt;&lt;b&gt;컨테이너 1: YOLO (객체&amp;middot;세그멘테이션 추론)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;206&quot; data-start=&quot;139&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;206&quot; data-start=&quot;139&quot;&gt;HTTP API (예: POST /infer) 혹은 WebSocket로 프레임/이미지 받음 &amp;rarr; 결과 JSON 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;284&quot; data-start=&quot;207&quot;&gt;&lt;b&gt;컨테이너 2: STT (음성 인식)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;284&quot; data-start=&quot;235&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;284&quot; data-start=&quot;235&quot;&gt;WebSocket(실시간 스트림) 또는 REST(파일 업로드)로 음성 &amp;rarr; 텍스트 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;439&quot; data-start=&quot;285&quot;&gt;&lt;b&gt;컨테이너 3: LangGraph (에이전트/NLP)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;439&quot; data-start=&quot;322&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;439&quot; data-start=&quot;322&quot;&gt;POST /perception/gaze/push, POST /perception/yolo/push, POST /image/push 등으로 이벤트/프레임/검출 JSON 수신 &amp;rarr; 추론/대화/행동 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;579&quot; data-start=&quot;440&quot;&gt;&lt;b&gt;컨테이너 4: FastAPI 백엔드 (허브)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;579&quot; data-start=&quot;473&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;545&quot; data-start=&quot;473&quot;&gt;호스트(사용자/클라이언트)에서 들어오는 요청을 받아 &lt;b&gt;YOLO/STT/LangGraph&lt;/b&gt;와 통신하고 응답을 묶어서 반환&lt;/li&gt;
&lt;li data-end=&quot;579&quot; data-start=&quot;548&quot;&gt;파일 저장소/캐시/인증/라우팅 등 &amp;ldquo;게이트웨이&amp;rdquo; 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;682&quot; data-start=&quot;581&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;682&quot; data-start=&quot;583&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너들은 &lt;b&gt;같은 가상 네트워크&lt;/b&gt;(bridge) 위에서 돌아가며, 컨테이너 이름으로 서로를 참조합니다(예: FastAPI 내부 코드에서 http://yolo:8090).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;687&quot; data-start=&quot;684&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;714&quot; data-start=&quot;689&quot; data-ke-size=&quot;size26&quot;&gt;왜 Docker를 썼나? (요점 4가지)&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;962&quot; data-start=&quot;715&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;770&quot; data-start=&quot;715&quot;&gt;&lt;b&gt;분리&lt;/b&gt;: 모델/런타임/라이브러리를 서비스별로 격리 &amp;rarr; 서로 간 충돌/의존성 꼬임 방지&lt;/li&gt;
&lt;li data-end=&quot;840&quot; data-start=&quot;771&quot;&gt;&lt;b&gt;재현성&lt;/b&gt;: 팀원이 바뀌거나 머신이 바뀌어도 docker run / compose up만으로 동일 환경 재현&lt;/li&gt;
&lt;li data-end=&quot;901&quot; data-start=&quot;841&quot;&gt;&lt;b&gt;이식성&lt;/b&gt;: 로컬(Windows) &amp;harr; 리눅스 서버(온프레/클라우드) &lt;b&gt;동일한 이미지&lt;/b&gt;로 배포&lt;/li&gt;
&lt;li data-end=&quot;962&quot; data-start=&quot;902&quot;&gt;&lt;b&gt;자원제어&lt;/b&gt;: GPU는 &lt;b&gt;YOLO만&lt;/b&gt;, CPU는 &lt;b&gt;STT만&lt;/b&gt; 같은 방식으로 자원 분배가 쉬움&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;967&quot; data-start=&quot;964&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;990&quot; data-start=&quot;969&quot; data-ke-size=&quot;size26&quot;&gt;&amp;ldquo;리눅스 기반 로컬 서버인가요?&amp;rdquo;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1241&quot; data-start=&quot;991&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1185&quot; data-start=&quot;991&quot;&gt;&lt;b&gt;윈도우에서 Docker Desktop&lt;/b&gt;을 쓰면, 내부적으로 &lt;b&gt;WSL2(리눅스 경량 VM)&lt;/b&gt; 위에서 &lt;b&gt;리눅스 컨테이너&lt;/b&gt;가 돌아갑니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1185&quot; data-start=&quot;1078&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1130&quot; data-start=&quot;1078&quot;&gt;즉, 체감상 &amp;ldquo;내 PC에서 로컬 서버&amp;rdquo;지만, &lt;b&gt;런타임은 리눅스&lt;/b&gt;라고 보면 정확해요.&lt;/li&gt;
&lt;li data-end=&quot;1185&quot; data-start=&quot;1133&quot;&gt;포트 매핑 덕분에 **호스트에서는 http://localhost:포트**로 접근합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1241&quot; data-start=&quot;1186&quot;&gt;같은 스택을 &lt;b&gt;리눅스 서버&lt;/b&gt;로 옮겨도 거의 그대로 동작합니다(경로/드라이버만 맞추면 OK).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1246&quot; data-start=&quot;1243&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1260&quot; data-start=&quot;1248&quot; data-ke-size=&quot;size26&quot;&gt;통신 흐름(쉽게)&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1471&quot; data-start=&quot;1261&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1300&quot; data-start=&quot;1261&quot;&gt;&lt;b&gt;클라이언트 &amp;rarr; FastAPI&lt;/b&gt;: 이미지/오디오/명령 요청&lt;/li&gt;
&lt;li data-end=&quot;1347&quot; data-start=&quot;1301&quot;&gt;&lt;b&gt;FastAPI &amp;rarr; YOLO/STT&lt;/b&gt;: 필요한 모델 서비스로 요청 전달&lt;/li&gt;
&lt;li data-end=&quot;1419&quot; data-start=&quot;1348&quot;&gt;&lt;b&gt;FastAPI &amp;rarr; LangGraph&lt;/b&gt;: YOLO 검출 JSON&amp;middot;시선/깊이 이벤트&amp;middot;이미지 프레임을 이벤트로 push&lt;/li&gt;
&lt;li data-end=&quot;1471&quot; data-start=&quot;1420&quot;&gt;&lt;b&gt;LangGraph &amp;rarr; FastAPI&lt;/b&gt;: 의도/답변/행동 반환 &amp;rarr; 클라이언트로 응답&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-end=&quot;1554&quot; data-start=&quot;1473&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1554&quot; data-start=&quot;1475&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너 내부에서는 http://서비스이름:포트로, 호스트(윈도우 브라우저 등)에서는 http://localhost:포트로 접근합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;5199&quot; data-start=&quot;5192&quot; data-ke-size=&quot;size26&quot;&gt;운영 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5568&quot; data-start=&quot;5200&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5288&quot; data-start=&quot;5200&quot;&gt;&lt;b&gt;네트워크&lt;/b&gt;: Compose 기본 bridge 사용. 컨테이너끼리는 http://서비스이름:포트, 호스트는 http://localhost:포트.&lt;/li&gt;
&lt;li data-end=&quot;5353&quot; data-start=&quot;5289&quot;&gt;&lt;b&gt;헬스체크&lt;/b&gt;: /health 같은 간단한 엔드포인트를 모든 서비스에 두면 자동 재시도/의존성 대기 용이.&lt;/li&gt;
&lt;li data-end=&quot;5412&quot; data-start=&quot;5354&quot;&gt;&lt;b&gt;로그/볼륨&lt;/b&gt;: 모델 가중치, 입력/출력 미디어는 볼륨 매핑해서 &lt;b&gt;컨테이너 재시작에도 유지&lt;/b&gt;.&lt;/li&gt;
&lt;li data-end=&quot;5486&quot; data-start=&quot;5413&quot;&gt;&lt;b&gt;자원 분리&lt;/b&gt;: YOLO만 GPU, STT/LangGraph/Backend는 CPU로도 충분한 경우가 많아 비용/발열 절약.&lt;/li&gt;
&lt;li data-end=&quot;5568&quot; data-start=&quot;5487&quot;&gt;&lt;b&gt;배포 전환&lt;/b&gt;: 로컬에서 검증한 compose를 &lt;b&gt;리눅스 서버&lt;/b&gt;에 그대로 가져가도 90% 이상 그대로 동작(경로/포트&amp;middot;보안만 맞추기).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;5573&quot; data-start=&quot;5570&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;5583&quot; data-start=&quot;5575&quot; data-ke-size=&quot;size26&quot;&gt;핵심 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;5805&quot; data-start=&quot;5584&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;5678&quot; data-start=&quot;5584&quot;&gt;A-EYE는 &lt;b&gt;서비스별 컨테이너&lt;/b&gt;(YOLO, STT, LangGraph, FastAPI)로 구성되고, FastAPI가 &lt;b&gt;허브&lt;/b&gt;가 되어 상호 통신을 중재합니다.&lt;/li&gt;
&lt;li data-end=&quot;5746&quot; data-start=&quot;5679&quot;&gt;윈도우에서 돌려도, &lt;b&gt;실제 컨테이너 런타임은 WSL2 리눅스&lt;/b&gt; 위에서 동작합니다(= 로컬 리눅스 서버처럼 동작).&lt;/li&gt;
&lt;li data-end=&quot;5805&quot; data-start=&quot;5747&quot;&gt;같은 이미지를 &lt;b&gt;리눅스 서버에도 그대로 이식&lt;/b&gt; 가능&amp;mdash;이게 Docker 채택의 가장 큰 이점입니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Projects/AI 아이트래킹 모델 프로젝트</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/177</guid>
      <comments>https://ha2yong.tistory.com/177#entry177comment</comments>
      <pubDate>Wed, 1 Oct 2025 14:14:57 +0900</pubDate>
    </item>
    <item>
      <title>[프로젝트] 7. 프로젝트 트러블슈팅 및 향후과제</title>
      <link>https://ha2yong.tistory.com/176</link>
      <description>&lt;p data-end=&quot;208&quot; data-start=&quot;119&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트명:&lt;/b&gt; 시선추적 + 월드깊이맵 + YOLOE 객체탐지 + STT + LLM (LangGraph) 융합 시스템&lt;br /&gt;&lt;b&gt;작성일:&lt;/b&gt; 2025년 9월&lt;/p&gt;
&lt;hr data-end=&quot;213&quot; data-start=&quot;210&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;223&quot; data-start=&quot;215&quot; data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-end=&quot;444&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;본 프로젝트는 시선추적(eye tracking)과 &lt;b&gt;월드카메라 깊이맵 추정&lt;/b&gt;을 결합하고, &lt;b&gt;YOLOE 기반 객체탐지&lt;/b&gt;, &lt;b&gt;Whisper STT&lt;/b&gt;, &lt;b&gt;LangGraph LLM&lt;/b&gt;을 연계하여, 사용자의 &lt;b&gt;응시 기반 인터랙션&lt;/b&gt;을 구현하는 것을 목표로 한다.&lt;br /&gt;개발 과정에서 다양한 기술적 트러블이 발생하였으며, 이를 해결하기 위한 트러블슈팅 결과를 아래와 같이 정리한다.&lt;/p&gt;
&lt;h2 data-end=&quot;471&quot; data-start=&quot;451&quot; data-ke-size=&quot;size26&quot;&gt;2. 주요 트러블 및 해결 방안&lt;/h2&gt;
&lt;h3 data-end=&quot;512&quot; data-start=&quot;473&quot; data-ke-size=&quot;size23&quot;&gt;2.1 멀티 카메라 동기화 및 지연 문제 (&lt;b&gt;최고 중요도&lt;/b&gt;)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;790&quot; data-start=&quot;513&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;576&quot; data-start=&quot;513&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: Eye cam과 World cam 간 타이밍 불일치 및 Wi-Fi 전송 지연(최대 7초).&lt;/li&gt;
&lt;li data-end=&quot;642&quot; data-start=&quot;577&quot;&gt;&lt;b&gt;원인&lt;/b&gt;: 저성능 하드웨어(Raspberry Pi Zero W)와 PyAV/ OpenCV 백엔드의 버퍼링.&lt;/li&gt;
&lt;li data-end=&quot;790&quot; data-start=&quot;643&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;790&quot; data-start=&quot;658&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;712&quot; data-start=&quot;658&quot;&gt;PyAV 백엔드 사용 + stimeout, rtsp_transport=tcp 적용.&lt;/li&gt;
&lt;li data-end=&quot;751&quot; data-start=&quot;715&quot;&gt;해상도/비트레이트 축소 (640&amp;times;480, 1.2Mbps).&lt;/li&gt;
&lt;li data-end=&quot;790&quot; data-start=&quot;754&quot;&gt;cv2.imshow 제거 및 로컬 CPU 부담 최소화.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;795&quot; data-start=&quot;792&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;819&quot; data-start=&quot;797&quot; data-ke-size=&quot;size23&quot;&gt;2.2 시선벡터 추정 정확도 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1024&quot; data-start=&quot;820&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;885&quot; data-start=&quot;820&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: Mediapipe 기반 홍채 평면 법선 추정 시 노이즈가 크고, 두 눈 벡터 교차점이 불안정.&lt;/li&gt;
&lt;li data-end=&quot;1024&quot; data-start=&quot;886&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1024&quot; data-start=&quot;901&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;949&quot; data-start=&quot;901&quot;&gt;EMA(Exponential Moving Average) 적용으로 벡터 스무딩.&lt;/li&gt;
&lt;li data-end=&quot;980&quot; data-start=&quot;952&quot;&gt;두 눈 교차점 대신 중간점(pmid) 활용.&lt;/li&gt;
&lt;li data-end=&quot;1024&quot; data-start=&quot;983&quot;&gt;향후 딥러닝 기반 모델(RT-GENE, Gaze360) 도입 검토.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1029&quot; data-start=&quot;1026&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1051&quot; data-start=&quot;1031&quot; data-ke-size=&quot;size23&quot;&gt;2.3 월드 깊이맵 정합 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1312&quot; data-start=&quot;1052&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1132&quot; data-start=&quot;1052&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: Depth-Anything V2 추정 결과와 Intrinsic/Extrinsic 불일치로 인해 광선&amp;ndash;깊이맵 매칭 불안정.&lt;/li&gt;
&lt;li data-end=&quot;1312&quot; data-start=&quot;1133&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1312&quot; data-start=&quot;1148&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1190&quot; data-start=&quot;1148&quot;&gt;체커보드 기반 &lt;b&gt;eye&amp;rarr;world extrinsic 추정&lt;/b&gt; 적용.&lt;/li&gt;
&lt;li data-end=&quot;1253&quot; data-start=&quot;1193&quot;&gt;ray_depth_intersection_best_of_two() 사용으로 광선 방향 양쪽 탐색.&lt;/li&gt;
&lt;li data-end=&quot;1312&quot; data-start=&quot;1256&quot;&gt;절대 깊이 보정식 도입: &lt;span&gt;&lt;span&gt;Dcorr=a&amp;sdot;Dpred+bD_{corr} = a \cdot D_{pred} + b&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;corr&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&amp;sdot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;D&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;re&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1317&quot; data-start=&quot;1314&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1343&quot; data-start=&quot;1319&quot; data-ke-size=&quot;size23&quot;&gt;2.4 YOLOE 객체탐지 연동 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1535&quot; data-start=&quot;1344&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1400&quot; data-start=&quot;1344&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: YOLO 서버 응답 포맷 불일치로 파싱 오류 및 응시점 근처 객체 탐지 실패.&lt;/li&gt;
&lt;li data-end=&quot;1535&quot; data-start=&quot;1401&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1535&quot; data-start=&quot;1416&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1463&quot; data-start=&quot;1416&quot;&gt;_normalize_detections() 모듈 개발 &amp;rarr; 응답 형식 통일.&lt;/li&gt;
&lt;li data-end=&quot;1501&quot; data-start=&quot;1466&quot;&gt;응시점 좌표 기반 ROI 탐지 및 근접 객체 우선 선택.&lt;/li&gt;
&lt;li data-end=&quot;1535&quot; data-start=&quot;1504&quot;&gt;YOLOE 모델 교체 시에도 API 호환성 유지.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1540&quot; data-start=&quot;1537&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1567&quot; data-start=&quot;1542&quot; data-ke-size=&quot;size23&quot;&gt;2.5 STT 및 웨이크워드 연계 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1790&quot; data-start=&quot;1568&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1620&quot; data-start=&quot;1568&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: Whisper STT의 높은 리소스 소비로 항상 대기 시 과부하 발생.&lt;/li&gt;
&lt;li data-end=&quot;1790&quot; data-start=&quot;1621&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1790&quot; data-start=&quot;1636&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1707&quot; data-start=&quot;1636&quot;&gt;Picovoice Porcupine으로 &lt;b&gt;웨이크워드(Hotword)&lt;/b&gt; 감지 후 Whisper STT 실행 구조 도입.&lt;/li&gt;
&lt;li data-end=&quot;1742&quot; data-start=&quot;1710&quot;&gt;동일 마이크 인덱스를 사용하여 STT 정확도 확보.&lt;/li&gt;
&lt;li data-end=&quot;1790&quot; data-start=&quot;1745&quot;&gt;Whisper 모델 크기(tiny/base 우선) 조정으로 리소스 최적화.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1795&quot; data-start=&quot;1792&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1828&quot; data-start=&quot;1797&quot; data-ke-size=&quot;size23&quot;&gt;2.6 LangGraph LLM 연동 안정성 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2019&quot; data-start=&quot;1829&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1876&quot; data-start=&quot;1829&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: STT 결과 전송 시 HTTP 타임아웃 및 과도한 요청 발생.&lt;/li&gt;
&lt;li data-end=&quot;2019&quot; data-start=&quot;1877&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2019&quot; data-start=&quot;1892&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1950&quot; data-start=&quot;1892&quot;&gt;LGClient.push_gaze()에 요청 간격 제한(throttle_s=0.5) 적용.&lt;/li&gt;
&lt;li data-end=&quot;1988&quot; data-start=&quot;1953&quot;&gt;예외 처리(try/except)를 통한 안정성 확보.&lt;/li&gt;
&lt;li data-end=&quot;2019&quot; data-start=&quot;1991&quot;&gt;세션 ID(alpha) 기반 상태 관리.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2024&quot; data-start=&quot;2021&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2047&quot; data-start=&quot;2026&quot; data-ke-size=&quot;size23&quot;&gt;2.7 시스템 리소스 관리 문제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2280&quot; data-start=&quot;2048&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2114&quot; data-start=&quot;2048&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;: Eye tracking, VDA, YOLO, Whisper 동시 실행 시 OOM 및 성능 저하.&lt;/li&gt;
&lt;li data-end=&quot;2280&quot; data-start=&quot;2115&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2280&quot; data-start=&quot;2130&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2170&quot; data-start=&quot;2130&quot;&gt;VDA 추론 시 max_res, input_size 제한.&lt;/li&gt;
&lt;li data-end=&quot;2222&quot; data-start=&quot;2173&quot;&gt;GPU 환경에서 half precision(torch.autocast) 적용.&lt;/li&gt;
&lt;li data-end=&quot;2280&quot; data-start=&quot;2225&quot;&gt;Whisper 모델 크기 및 GUI 옵션(--no_gui) 조정으로 CPU 사용량 절감.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2285&quot; data-start=&quot;2282&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2295&quot; data-start=&quot;2287&quot; data-ke-size=&quot;size26&quot;&gt;3. 결론&lt;/h2&gt;
&lt;p data-end=&quot;2425&quot; data-start=&quot;2296&quot; data-ke-size=&quot;size16&quot;&gt;본 프로젝트는 초기 단계에서 &lt;b&gt;카메라 동기화&amp;middot;정합 문제&lt;/b&gt;와 &lt;b&gt;시선 추정 정확도 부족&lt;/b&gt;이 가장 큰 난관이었다.&lt;br /&gt;그러나 EMA 기반 스무딩, Extrinsic 캘리브레이션, PyAV 최적화 등을 통해 안정성을 확보하였다.&lt;/p&gt;
&lt;p data-end=&quot;2541&quot; data-start=&quot;2427&quot; data-ke-size=&quot;size16&quot;&gt;STT/웨이크워드 및 YOLOE 연동에서도 파싱/리소스 문제를 해결하여, 현재는 &amp;ldquo;시선 &amp;rarr; 깊이맵 &amp;rarr; 객체탐지 &amp;rarr; STT &amp;rarr; LLM 연계&amp;rdquo;까지 일관된 파이프라인이 동작 가능한 수준에 도달하였다.&lt;/p&gt;
&lt;p data-end=&quot;2647&quot; data-start=&quot;2543&quot; data-ke-size=&quot;size16&quot;&gt;향후 발전 방향은 &lt;b&gt;딥러닝 기반 시선추정 모델 도입&lt;/b&gt;, &lt;b&gt;경량화된 Whisper 대체 모델 적용&lt;/b&gt;, &lt;b&gt;YOLOE의 open-vocabulary 탐지 활용&lt;/b&gt; 등이 될 것이다.&lt;/p&gt;</description>
      <category>Projects/AI 아이트래킹 모델 프로젝트</category>
      <author>ha2yong</author>
      <guid isPermaLink="true">https://ha2yong.tistory.com/176</guid>
      <comments>https://ha2yong.tistory.com/176#entry176comment</comments>
      <pubDate>Wed, 24 Sep 2025 03:37:59 +0900</pubDate>
    </item>
  </channel>
</rss>