codebuff-agent 2.1.74__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codebuff_agent-2.1.74.data/data/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/package.json +157 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/150.39fa98117cc8ca590465.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/166.386ff9b2c37ac865fdee.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/216.25cf81131bf7274dabf4.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/353.581bd1cb00746399b62e.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/367.575f9621b63c9a641aa9.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/421.11dac223a2c2da1b09f5.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/481.cc2dec9fa869d66f1407.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/487.0796e931d6e651482c14.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/49.d326f554b6f9ccde6580.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/541.26897ea32845659e36be.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/579.e569d3edd8391fd8fbb3.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/666.d9bfdb23f98489d0a188.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/68.26b6f59c8454adb17f20.js +204 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/694.4ac443814260057e68f7.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/791.61affb8d3480d3d60e0d.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/style.js +4 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/third-party-licenses.json +724 -0
- codebuff_agent-2.1.74.dist-info/METADATA +142 -0
- codebuff_agent-2.1.74.dist-info/RECORD +217 -0
- codebuff_agent-2.1.74.dist-info/WHEEL +4 -0
- codebuff_agent-2.1.74.dist-info/licenses/LICENSE +21 -0
- codebuff_core/__init__.py +153 -0
- codebuff_core/codebuff_config_defaults.json +64 -0
- codebuff_core/core/__init__.py +35 -0
- codebuff_core/core/code_validator.py +1238 -0
- codebuff_core/core/error_classifier.py +579 -0
- codebuff_core/core/exceptions.py +49 -0
- codebuff_core/data/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +100256 -0
- codebuff_core/directory_policy.py +32 -0
- codebuff_core/factory.py +155 -0
- codebuff_core/interfaces.py +197 -0
- codebuff_core/knowledge/__init__.py +31 -0
- codebuff_core/knowledge/chunking.py +375 -0
- codebuff_core/knowledge/loader.py +339 -0
- codebuff_core/knowledge/watchdog_service.py +354 -0
- codebuff_core/legacy_paths.py +69 -0
- codebuff_core/llm/__init__.py +13 -0
- codebuff_core/llm/service.py +407 -0
- codebuff_core/managers/__init__.py +22 -0
- codebuff_core/managers/config_manager.py +690 -0
- codebuff_core/managers/remote_config.py +673 -0
- codebuff_core/managers/remote_skills.py +539 -0
- codebuff_core/managers/session_manager.py +255 -0
- codebuff_core/middleware/__init__.py +3 -0
- codebuff_core/middleware/error_recovery.py +394 -0
- codebuff_core/middleware/logging_utils.py +33 -0
- codebuff_core/models/__init__.py +111 -0
- codebuff_core/models/agent.py +306 -0
- codebuff_core/models/chat.py +57 -0
- codebuff_core/models/common.py +82 -0
- codebuff_core/models/rag.py +300 -0
- codebuff_core/platform_rules.py +127 -0
- codebuff_core/prompts/__init__.py +44 -0
- codebuff_core/prompts/auto_agent_prompts.py +1278 -0
- codebuff_core/services/__init__.py +30 -0
- codebuff_core/services/agent_service.py +345 -0
- codebuff_core/services/analytics_aggregate.py +837 -0
- codebuff_core/services/chat_service.py +898 -0
- codebuff_core/services/context_condenser.py +306 -0
- codebuff_core/services/pii_guardrail.py +393 -0
- codebuff_core/services/rag_chat_agent.py +2993 -0
- codebuff_core/services/rag_collections.py +2740 -0
- codebuff_core/services/rag_manager.py +890 -0
- codebuff_core/services/rag_service.py +145 -0
- codebuff_core/services/retriever.py +260 -0
- codebuff_core/services/vllm_embedding_service.py +290 -0
- codebuff_core/tests/__init__.py +1 -0
- codebuff_core/tests/conftest.py +81 -0
- codebuff_core/tests/test_error_recovery.py +647 -0
- codebuff_core/tests/test_factory.py +135 -0
- codebuff_core/tests/test_services.py +150 -0
- jupyter_ext/__init__.py +266 -0
- jupyter_ext/_version.py +4 -0
- jupyter_ext/agent/__init__.py +49 -0
- jupyter_ext/agent/agent_factory.py +2270 -0
- jupyter_ext/agent/ast_tools.py +451 -0
- jupyter_ext/agent/autofix_middleware.py +481 -0
- jupyter_ext/agent/background_procs.py +372 -0
- jupyter_ext/agent/code_history_middleware.py +211 -0
- jupyter_ext/agent/codex_autofix.py +160 -0
- jupyter_ext/agent/codex_bridge.py +3339 -0
- jupyter_ext/agent/codex_hooks.py +320 -0
- jupyter_ext/agent/codex_slash.py +685 -0
- jupyter_ext/agent/codex_threads.py +114 -0
- jupyter_ext/agent/content_injection.py +377 -0
- jupyter_ext/agent/continuation_middleware.py +548 -0
- jupyter_ext/agent/custom_skills.py +335 -0
- jupyter_ext/agent/file_diffs.py +99 -0
- jupyter_ext/agent/git_history.py +188 -0
- jupyter_ext/agent/guardrail_middleware.py +421 -0
- jupyter_ext/agent/json_repair_utils.py +54 -0
- jupyter_ext/agent/langchain_tools.py +2673 -0
- jupyter_ext/agent/mermaid_fixer.py +289 -0
- jupyter_ext/agent/mermaid_middleware.py +135 -0
- jupyter_ext/agent/middleware.py +359 -0
- jupyter_ext/agent/middleware_prompts.py +53 -0
- jupyter_ext/agent/observability.py +334 -0
- jupyter_ext/agent/patch_tool_calls.py +57 -0
- jupyter_ext/agent/prompts.py +112 -0
- jupyter_ext/agent/skill_middleware.py +257 -0
- jupyter_ext/agent/skills/airflow_dag_development.md +36 -0
- jupyter_ext/agent/skills/anomaly_detection.md +12 -0
- jupyter_ext/agent/skills/athena_sql.md +156 -0
- jupyter_ext/agent/skills/bdp_table_search.md +33 -0
- jupyter_ext/agent/skills/bigquery.md +65 -0
- jupyter_ext/agent/skills/bigquery_oracle.md +231 -0
- jupyter_ext/agent/skills/bigquery_tuning.md +307 -0
- jupyter_ext/agent/skills/classification_evaluation.md +11 -0
- jupyter_ext/agent/skills/clustering_analysis.md +12 -0
- jupyter_ext/agent/skills/comprehensive_eda.md +11 -0
- jupyter_ext/agent/skills/data_analysis.md +236 -0
- jupyter_ext/agent/skills/data_cleaning_pipeline.md +12 -0
- jupyter_ext/agent/skills/data_loading.md +158 -0
- jupyter_ext/agent/skills/data_quality_report.md +13 -0
- jupyter_ext/agent/skills/dimensionality_reduction.md +12 -0
- jupyter_ext/agent/skills/emr_script_development.md +17 -0
- jupyter_ext/agent/skills/experiment_tracking.md +13 -0
- jupyter_ext/agent/skills/feature_importance_analysis.md +10 -0
- jupyter_ext/agent/skills/hyperparameter_tuning.md +12 -0
- jupyter_ext/agent/skills/hypothesis_testing.md +12 -0
- jupyter_ext/agent/skills/imbalanced_data_handling.md +12 -0
- jupyter_ext/agent/skills/inference.md +392 -0
- jupyter_ext/agent/skills/lambda_function_development.md +19 -0
- jupyter_ext/agent/skills/model_comparison.md +11 -0
- jupyter_ext/agent/skills/model_explainability.md +12 -0
- jupyter_ext/agent/skills/model_training.md +318 -0
- jupyter_ext/agent/skills/pyspark.md +352 -0
- jupyter_ext/agent/skills/python_code_quality.md +35 -0
- jupyter_ext/agent/skills/regression_evaluation.md +12 -0
- jupyter_ext/agent/skills/spring_java_development.md +35 -0
- jupyter_ext/agent/skills/text_preprocessing.md +12 -0
- jupyter_ext/agent/skills/time_series_analysis.md +13 -0
- jupyter_ext/agent/skills/unit_testing.md +203 -0
- jupyter_ext/agent/todo_prompts.py +57 -0
- jupyter_ext/agent/tool_report.py +45 -0
- jupyter_ext/analytics_ingest.py +599 -0
- jupyter_ext/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- jupyter_ext/handlers/__init__.py +8 -0
- jupyter_ext/handlers/analytics_handler.py +170 -0
- jupyter_ext/handlers/benchmark_handler.py +794 -0
- jupyter_ext/handlers/eda_benchmark_handler.py +1328 -0
- jupyter_ext/handlers/rag_admin_handler.py +689 -0
- jupyter_ext/handlers/websocket.py +497 -0
- jupyter_ext/http_handlers.py +8744 -0
- jupyter_ext/idle_monitor.py +346 -0
- jupyter_ext/labextension/package.json +157 -0
- jupyter_ext/labextension/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- jupyter_ext/labextension/static/150.39fa98117cc8ca590465.js +1 -0
- jupyter_ext/labextension/static/166.386ff9b2c37ac865fdee.js +1 -0
- jupyter_ext/labextension/static/216.25cf81131bf7274dabf4.js +1 -0
- jupyter_ext/labextension/static/353.581bd1cb00746399b62e.js +1 -0
- jupyter_ext/labextension/static/367.575f9621b63c9a641aa9.js +1 -0
- jupyter_ext/labextension/static/421.11dac223a2c2da1b09f5.js +1 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js +2 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/481.cc2dec9fa869d66f1407.js +1 -0
- jupyter_ext/labextension/static/487.0796e931d6e651482c14.js +1 -0
- jupyter_ext/labextension/static/49.d326f554b6f9ccde6580.js +1 -0
- jupyter_ext/labextension/static/541.26897ea32845659e36be.js +1 -0
- jupyter_ext/labextension/static/579.e569d3edd8391fd8fbb3.js +1 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/666.d9bfdb23f98489d0a188.js +1 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js +2 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/68.26b6f59c8454adb17f20.js +204 -0
- jupyter_ext/labextension/static/694.4ac443814260057e68f7.js +1 -0
- jupyter_ext/labextension/static/791.61affb8d3480d3d60e0d.js +1 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js +2 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- jupyter_ext/labextension/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- jupyter_ext/labextension/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- jupyter_ext/labextension/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- jupyter_ext/labextension/static/style.js +4 -0
- jupyter_ext/labextension/static/third-party-licenses.json +724 -0
- jupyter_ext/log_paths.py +113 -0
- jupyter_ext/resource_usage.py +519 -0
- jupyter_ext/secrets_bootstrap.py +116 -0
- jupyter_ext/team_access.py +105 -0
- jupyter_ext/tests/__init__.py +1 -0
- jupyter_ext/tests/test_context.py +234 -0
- jupyter_ext/tests/test_factory.py +563 -0
- jupyter_ext/tests/test_file_finder.py +139 -0
- jupyter_ext/tests/test_handlers.py +58 -0
- jupyter_ext/tests/test_mcp_selftest.py +204 -0
- jupyter_ext/tests/test_mermaid_fixer.py +272 -0
- jupyter_ext/tests/test_resource_tiers.py +298 -0
- jupyter_ext/tools/__init__.py +15 -0
- jupyter_ext/tools/base.py +90 -0
- jupyter_ext/tools/context.py +268 -0
- jupyter_ext/tools/dir_complete.py +86 -0
- jupyter_ext/tools/file_finder.py +303 -0
- jupyter_ext/tools/file_tools.py +244 -0
- jupyter_ext/tools/jupyter_tools.py +296 -0
- jupyter_ext/tools/registry.py +159 -0
- jupyter_ext/tools/search_tools.py +230 -0
- jupyter_ext/tools/security_tools.py +657 -0
- jupyter_ext/tools/shell_tools.py +109 -0
- jupyter_ext/tools/user_tools.py +132 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-training
|
|
3
|
+
description: 모델 훈련 최적화. GPU/CUDA로 모델을 훈련하거나 GPU 메모리 부족, 훈련 속도 개선 시 사용. mixed precision(fp16/bf16), gradient checkpointing, batch size 튜닝, optimizer 최적화 제공.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Model Training Optimization Guide
|
|
7
|
+
|
|
8
|
+
GPU/CPU 환경에서 효율적인 모델 훈련 방법을 안내합니다.
|
|
9
|
+
|
|
10
|
+
## Resource Tiers
|
|
11
|
+
|
|
12
|
+
### TIER_SMALL: GPU < 8GB 또는 CPU only
|
|
13
|
+
- batch_size: 4-16
|
|
14
|
+
- gradient_checkpointing: 필수
|
|
15
|
+
- mixed precision: 권장
|
|
16
|
+
- optimizer: 8-bit Adam
|
|
17
|
+
|
|
18
|
+
### TIER_MEDIUM: GPU 8-24GB (RTX 3090, T4, A10)
|
|
19
|
+
- batch_size: 16-64
|
|
20
|
+
- gradient_checkpointing: 선택
|
|
21
|
+
- mixed precision: fp16/bf16 필수
|
|
22
|
+
- optimizer: AdamW 또는 8-bit Adam
|
|
23
|
+
|
|
24
|
+
### TIER_LARGE: GPU > 24GB (A100, H100)
|
|
25
|
+
- batch_size: 64-256
|
|
26
|
+
- gradient_checkpointing: 불필요
|
|
27
|
+
- mixed precision: bf16 권장
|
|
28
|
+
- optimizer: AdamW, CUDA Graphs 활용
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 1. Mixed Precision Training
|
|
33
|
+
|
|
34
|
+
### PyTorch Native (권장)
|
|
35
|
+
```python
|
|
36
|
+
import torch
|
|
37
|
+
from torch.cuda.amp import autocast, GradScaler
|
|
38
|
+
|
|
39
|
+
model = model.cuda()
|
|
40
|
+
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)
|
|
41
|
+
scaler = GradScaler()
|
|
42
|
+
|
|
43
|
+
for batch in dataloader:
|
|
44
|
+
optimizer.zero_grad()
|
|
45
|
+
|
|
46
|
+
# Mixed precision forward pass
|
|
47
|
+
with autocast():
|
|
48
|
+
outputs = model(batch["input_ids"].cuda())
|
|
49
|
+
loss = criterion(outputs, batch["labels"].cuda())
|
|
50
|
+
|
|
51
|
+
# Scaled backward pass
|
|
52
|
+
scaler.scale(loss).backward()
|
|
53
|
+
scaler.step(optimizer)
|
|
54
|
+
scaler.update()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Hugging Face Transformers
|
|
58
|
+
```python
|
|
59
|
+
from transformers import TrainingArguments, Trainer
|
|
60
|
+
|
|
61
|
+
training_args = TrainingArguments(
|
|
62
|
+
output_dir="./results",
|
|
63
|
+
per_device_train_batch_size=16,
|
|
64
|
+
|
|
65
|
+
# Mixed Precision 선택 (GPU 아키텍처에 따라)
|
|
66
|
+
fp16=True, # Volta, Turing, Ampere
|
|
67
|
+
# bf16=True, # Ampere 이상 권장 (더 안정적)
|
|
68
|
+
)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Data Type 선택 가이드
|
|
72
|
+
|
|
73
|
+
| GPU Architecture | Recommended | Notes |
|
|
74
|
+
|------------------|-------------|-------|
|
|
75
|
+
| Volta (V100) | fp16 | bf16 미지원 |
|
|
76
|
+
| Turing (RTX 20xx, T4) | fp16 | bf16 미지원 |
|
|
77
|
+
| Ampere (A100, RTX 30xx) | bf16 | fp16도 가능, bf16이 더 안정적 |
|
|
78
|
+
| Hopper (H100) | bf16 | FP8도 지원 |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 2. Gradient Checkpointing
|
|
83
|
+
|
|
84
|
+
메모리 50-80% 절약, 훈련 속도 20-30% 감소 트레이드오프.
|
|
85
|
+
|
|
86
|
+
### PyTorch
|
|
87
|
+
```python
|
|
88
|
+
from torch.utils.checkpoint import checkpoint_sequential
|
|
89
|
+
|
|
90
|
+
# 모델 레이어를 청크로 나누어 체크포인팅
|
|
91
|
+
model = nn.Sequential(layer1, layer2, layer3, layer4)
|
|
92
|
+
output = checkpoint_sequential(model, 2, input) # 2개 청크로 분할
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Hugging Face Transformers
|
|
96
|
+
```python
|
|
97
|
+
from transformers import TrainingArguments
|
|
98
|
+
|
|
99
|
+
training_args = TrainingArguments(
|
|
100
|
+
output_dir="./results",
|
|
101
|
+
per_device_train_batch_size=4,
|
|
102
|
+
gradient_checkpointing=True, # 활성화
|
|
103
|
+
gradient_accumulation_steps=16, # effective batch = 4 * 16 = 64
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 언제 사용?
|
|
108
|
+
- GPU 메모리 부족 (OOM)
|
|
109
|
+
- 큰 모델 (7B+ 파라미터)
|
|
110
|
+
- 작은 GPU (< 16GB)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 3. Batch Size & Gradient Accumulation
|
|
115
|
+
|
|
116
|
+
### 최적 Batch Size 찾기
|
|
117
|
+
```python
|
|
118
|
+
# 1. 최대 batch size 찾기 (OOM 직전까지)
|
|
119
|
+
# 2. 2의 거듭제곱 사용 (8, 16, 32, 64, 128)
|
|
120
|
+
# 3. fp16: 8의 배수, A100: 64의 배수
|
|
121
|
+
|
|
122
|
+
# Gradient Accumulation으로 effective batch size 확보
|
|
123
|
+
training_args = TrainingArguments(
|
|
124
|
+
per_device_train_batch_size=4, # GPU에 맞는 최대값
|
|
125
|
+
gradient_accumulation_steps=16, # 4 * 16 = 64 effective
|
|
126
|
+
)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Batch Size 권장표
|
|
130
|
+
|
|
131
|
+
| GPU Memory | Max Batch (fp32) | Max Batch (fp16) | Recommended |
|
|
132
|
+
|------------|------------------|------------------|-------------|
|
|
133
|
+
| 8GB | 4-8 | 8-16 | 8 (fp16) |
|
|
134
|
+
| 16GB | 8-16 | 16-32 | 16 (fp16) |
|
|
135
|
+
| 24GB | 16-32 | 32-64 | 32 (fp16) |
|
|
136
|
+
| 40GB+ | 32-64 | 64-128 | 64 (bf16) |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 4. Optimizer 최적화
|
|
141
|
+
|
|
142
|
+
### 8-bit Adam (메모리 절약)
|
|
143
|
+
```python
|
|
144
|
+
# bitsandbytes 설치 필요: pip install bitsandbytes
|
|
145
|
+
import bitsandbytes as bnb
|
|
146
|
+
|
|
147
|
+
optimizer = bnb.optim.Adam8bit(
|
|
148
|
+
model.parameters(),
|
|
149
|
+
lr=1e-4,
|
|
150
|
+
betas=(0.9, 0.999)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Hugging Face
|
|
154
|
+
training_args = TrainingArguments(
|
|
155
|
+
optim="adamw_bnb_8bit", # 8-bit AdamW
|
|
156
|
+
)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Adafactor (대용량 모델용)
|
|
160
|
+
```python
|
|
161
|
+
from transformers import Adafactor
|
|
162
|
+
|
|
163
|
+
optimizer = Adafactor(
|
|
164
|
+
model.parameters(),
|
|
165
|
+
scale_parameter=True,
|
|
166
|
+
relative_step=True,
|
|
167
|
+
warmup_init=True,
|
|
168
|
+
lr=None # relative_step=True면 자동 조절
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 5. Data Loading 최적화
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from torch.utils.data import DataLoader
|
|
178
|
+
|
|
179
|
+
dataloader = DataLoader(
|
|
180
|
+
dataset,
|
|
181
|
+
batch_size=32,
|
|
182
|
+
shuffle=True,
|
|
183
|
+
num_workers=4, # CPU 코어 수에 맞게
|
|
184
|
+
pin_memory=True, # GPU 전송 가속
|
|
185
|
+
prefetch_factor=2, # 미리 로드할 배치 수
|
|
186
|
+
persistent_workers=True # 워커 재사용
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Hugging Face
|
|
190
|
+
training_args = TrainingArguments(
|
|
191
|
+
dataloader_pin_memory=True,
|
|
192
|
+
dataloader_num_workers=4,
|
|
193
|
+
)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 6. torch.compile (PyTorch 2.0+)
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
import torch
|
|
202
|
+
|
|
203
|
+
# 모델 컴파일 (최대 2x 속도 향상)
|
|
204
|
+
model = torch.compile(model, mode="reduce-overhead")
|
|
205
|
+
|
|
206
|
+
# Hugging Face
|
|
207
|
+
training_args = TrainingArguments(
|
|
208
|
+
torch_compile=True,
|
|
209
|
+
torch_compile_backend="inductor", # 기본값, 최적
|
|
210
|
+
)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 컴파일 모드
|
|
214
|
+
|
|
215
|
+
| Mode | Speed | Memory | Use Case |
|
|
216
|
+
|------|-------|--------|----------|
|
|
217
|
+
| default | Good | Neutral | 일반적인 경우 |
|
|
218
|
+
| reduce-overhead | Best | Slight increase | 긴 훈련 |
|
|
219
|
+
| max-autotune | Best | Neutral | 시간 여유 있을 때 |
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 7. sklearn 모델 최적화
|
|
224
|
+
|
|
225
|
+
### CPU 병렬화
|
|
226
|
+
```python
|
|
227
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
228
|
+
|
|
229
|
+
# n_jobs=-1: 모든 CPU 코어 사용
|
|
230
|
+
model = RandomForestClassifier(
|
|
231
|
+
n_estimators=100,
|
|
232
|
+
n_jobs=-1, # 병렬 처리
|
|
233
|
+
random_state=42
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# GridSearchCV도 병렬화
|
|
237
|
+
from sklearn.model_selection import GridSearchCV
|
|
238
|
+
grid_search = GridSearchCV(
|
|
239
|
+
model, param_grid,
|
|
240
|
+
cv=5,
|
|
241
|
+
n_jobs=-1 # 병렬 교차 검증
|
|
242
|
+
)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 점진적 학습 (대용량 데이터)
|
|
246
|
+
```python
|
|
247
|
+
from sklearn.linear_model import SGDClassifier
|
|
248
|
+
|
|
249
|
+
model = SGDClassifier(warm_start=True)
|
|
250
|
+
|
|
251
|
+
# 청크별 학습
|
|
252
|
+
for chunk in pd.read_csv("large_data.csv", chunksize=10000):
|
|
253
|
+
X, y = chunk.drop("target", axis=1), chunk["target"]
|
|
254
|
+
model.partial_fit(X, y, classes=[0, 1])
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 8. 메모리 모니터링
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
import torch
|
|
263
|
+
|
|
264
|
+
# GPU 메모리 확인
|
|
265
|
+
print(f"Allocated: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")
|
|
266
|
+
print(f"Cached: {torch.cuda.memory_reserved() / 1024**3:.2f} GB")
|
|
267
|
+
|
|
268
|
+
# 메모리 정리
|
|
269
|
+
torch.cuda.empty_cache()
|
|
270
|
+
|
|
271
|
+
# 훈련 중 주기적 정리 (Hugging Face)
|
|
272
|
+
training_args = TrainingArguments(
|
|
273
|
+
torch_empty_cache_steps=4, # 4스텝마다 캐시 정리
|
|
274
|
+
)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Quick Reference: 최적 설정 조합
|
|
280
|
+
|
|
281
|
+
### TIER_SMALL (GPU < 8GB)
|
|
282
|
+
```python
|
|
283
|
+
TrainingArguments(
|
|
284
|
+
per_device_train_batch_size=4,
|
|
285
|
+
gradient_accumulation_steps=16,
|
|
286
|
+
gradient_checkpointing=True,
|
|
287
|
+
fp16=True,
|
|
288
|
+
optim="adamw_bnb_8bit",
|
|
289
|
+
dataloader_num_workers=2,
|
|
290
|
+
)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### TIER_MEDIUM (GPU 8-24GB)
|
|
294
|
+
```python
|
|
295
|
+
TrainingArguments(
|
|
296
|
+
per_device_train_batch_size=16,
|
|
297
|
+
gradient_accumulation_steps=4,
|
|
298
|
+
bf16=True, # or fp16
|
|
299
|
+
optim="adamw_torch",
|
|
300
|
+
dataloader_pin_memory=True,
|
|
301
|
+
dataloader_num_workers=4,
|
|
302
|
+
torch_compile=True,
|
|
303
|
+
)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### TIER_LARGE (GPU > 24GB)
|
|
307
|
+
```python
|
|
308
|
+
TrainingArguments(
|
|
309
|
+
per_device_train_batch_size=64,
|
|
310
|
+
bf16=True,
|
|
311
|
+
optim="adamw_torch",
|
|
312
|
+
dataloader_pin_memory=True,
|
|
313
|
+
dataloader_num_workers=8,
|
|
314
|
+
torch_compile=True,
|
|
315
|
+
torch_compile_backend="inductor",
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pyspark
|
|
3
|
+
description: PySpark 성능 최적화. PySpark·분산 처리 코드를 쓰거나 대용량 데이터 처리 시 셔플링, 메모리 부족, 느린 조인 문제 해결. 파티셔닝, 캐싱, 브로드캐스트 조인, AQE 최적화 제공.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PySpark Optimization Guide
|
|
7
|
+
|
|
8
|
+
대용량 데이터 처리 시 PySpark 성능을 최적화하는 방법을 안내합니다.
|
|
9
|
+
|
|
10
|
+
## Resource Tiers
|
|
11
|
+
|
|
12
|
+
### TIER_SMALL: 데이터 < 10GB, 단일 노드
|
|
13
|
+
- 기본 설정으로 충분
|
|
14
|
+
- 파티션 수: 코어 수 × 2-4
|
|
15
|
+
- 캐싱 선택적
|
|
16
|
+
|
|
17
|
+
### TIER_MEDIUM: 데이터 10GB-100GB
|
|
18
|
+
- 파티셔닝 최적화 필수
|
|
19
|
+
- 브로드캐스트 조인 활용
|
|
20
|
+
- AQE 활성화
|
|
21
|
+
|
|
22
|
+
### TIER_LARGE: 데이터 > 100GB
|
|
23
|
+
- 파티션 튜닝 필수
|
|
24
|
+
- 데이터 스큐 처리
|
|
25
|
+
- 파일 포맷 최적화 (Parquet)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. 파티셔닝 최적화
|
|
30
|
+
|
|
31
|
+
### 파티션 수 가이드라인
|
|
32
|
+
```python
|
|
33
|
+
# 권장: 클러스터 코어 수 × 4
|
|
34
|
+
# 상한선: 작업당 100ms+ 소요되도록
|
|
35
|
+
|
|
36
|
+
# 파티션 수 확인
|
|
37
|
+
print(f"파티션 수: {df.rdd.getNumPartitions()}")
|
|
38
|
+
|
|
39
|
+
# 파티션 수 조정
|
|
40
|
+
# repartition: 셔플 발생 (증가/감소 모두 가능)
|
|
41
|
+
df = df.repartition(200)
|
|
42
|
+
|
|
43
|
+
# coalesce: 셔플 없음 (감소만 가능, 더 효율적)
|
|
44
|
+
df = df.coalesce(100)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 조인 키 기반 파티셔닝
|
|
48
|
+
```python
|
|
49
|
+
# 조인 전 같은 키로 파티셔닝 → 셔플 최소화
|
|
50
|
+
users = users.repartition("user_id")
|
|
51
|
+
orders = orders.repartition("user_id")
|
|
52
|
+
|
|
53
|
+
# 여러 번 조인할 경우 캐싱
|
|
54
|
+
users = users.repartition("user_id").cache()
|
|
55
|
+
orders = orders.repartition("user_id").cache()
|
|
56
|
+
|
|
57
|
+
# 조인 (동일 파티션 키 → 로컬 조인)
|
|
58
|
+
result = users.join(orders, "user_id")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 파티션 크기 권장
|
|
62
|
+
| 파티션당 크기 | 상태 | 조치 |
|
|
63
|
+
|--------------|------|------|
|
|
64
|
+
| < 10MB | 너무 작음 | coalesce로 감소 |
|
|
65
|
+
| 10MB-200MB | 적정 | 유지 |
|
|
66
|
+
| > 200MB | 너무 큼 | repartition으로 증가 |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 2. 캐싱 전략
|
|
71
|
+
|
|
72
|
+
### 캐싱이 효과적인 경우
|
|
73
|
+
```python
|
|
74
|
+
# ✅ 여러 번 사용되는 DataFrame
|
|
75
|
+
df = spark.read.parquet("data.parquet")
|
|
76
|
+
df = df.filter(df.status == "active")
|
|
77
|
+
df.cache() # 또는 df.persist()
|
|
78
|
+
|
|
79
|
+
# 첫 번째 사용
|
|
80
|
+
count1 = df.count()
|
|
81
|
+
|
|
82
|
+
# 두 번째 사용 (캐시에서 읽음 - 빠름)
|
|
83
|
+
count2 = df.groupBy("category").count().collect()
|
|
84
|
+
|
|
85
|
+
# 사용 후 해제
|
|
86
|
+
df.unpersist()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 캐싱이 불필요한 경우
|
|
90
|
+
```python
|
|
91
|
+
# ❌ 한 번만 사용되는 DataFrame
|
|
92
|
+
df = spark.read.parquet("data.parquet")
|
|
93
|
+
result = df.filter(...).groupBy(...).count() # 캐싱 불필요
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 스토리지 레벨 선택
|
|
97
|
+
```python
|
|
98
|
+
from pyspark import StorageLevel
|
|
99
|
+
|
|
100
|
+
# MEMORY_ONLY (기본값) - 메모리에만 저장
|
|
101
|
+
df.cache() # = df.persist(StorageLevel.MEMORY_ONLY)
|
|
102
|
+
|
|
103
|
+
# MEMORY_AND_DISK - 메모리 부족 시 디스크 사용
|
|
104
|
+
df.persist(StorageLevel.MEMORY_AND_DISK)
|
|
105
|
+
|
|
106
|
+
# DISK_ONLY - 디스크에만 저장 (메모리 부족 시)
|
|
107
|
+
df.persist(StorageLevel.DISK_ONLY)
|
|
108
|
+
|
|
109
|
+
# MEMORY_ONLY_SER - 직렬화하여 메모리 절약
|
|
110
|
+
df.persist(StorageLevel.MEMORY_ONLY_SER)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 스토리지 레벨 가이드
|
|
114
|
+
| 레벨 | 메모리 | 속도 | 사용 시기 |
|
|
115
|
+
|------|--------|------|----------|
|
|
116
|
+
| MEMORY_ONLY | 높음 | 가장 빠름 | 메모리 여유 있을 때 |
|
|
117
|
+
| MEMORY_AND_DISK | 중간 | 빠름 | 대부분의 경우 권장 |
|
|
118
|
+
| MEMORY_ONLY_SER | 낮음 | 중간 | 메모리 절약 필요 시 |
|
|
119
|
+
| DISK_ONLY | 없음 | 느림 | 메모리 매우 부족 시 |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 3. 브로드캐스트 조인
|
|
124
|
+
|
|
125
|
+
### 작은 테이블 브로드캐스트
|
|
126
|
+
```python
|
|
127
|
+
from pyspark.sql.functions import broadcast
|
|
128
|
+
|
|
129
|
+
# 작은 테이블을 모든 노드에 복사 → 셔플 제거
|
|
130
|
+
small_df = spark.read.parquet("lookup_table.parquet") # < 100MB
|
|
131
|
+
large_df = spark.read.parquet("transactions.parquet") # 수 GB
|
|
132
|
+
|
|
133
|
+
# 명시적 브로드캐스트
|
|
134
|
+
result = large_df.join(broadcast(small_df), "key")
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### SQL 힌트 사용
|
|
138
|
+
```python
|
|
139
|
+
# SQL에서 브로드캐스트 힌트
|
|
140
|
+
spark.sql("""
|
|
141
|
+
SELECT /*+ BROADCAST(small_table) */
|
|
142
|
+
l.*, s.name
|
|
143
|
+
FROM large_table l
|
|
144
|
+
JOIN small_table s ON l.key = s.key
|
|
145
|
+
""")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 브로드캐스트 임계값 설정
|
|
149
|
+
```python
|
|
150
|
+
# 기본값: 10MB
|
|
151
|
+
# 자동 브로드캐스트 크기 조정
|
|
152
|
+
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", "100m") # 100MB로 증가
|
|
153
|
+
|
|
154
|
+
# 비활성화 (대형 테이블 실수로 브로드캐스트 방지)
|
|
155
|
+
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", "-1")
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 브로드캐스트 주의사항
|
|
159
|
+
| 테이블 크기 | 브로드캐스트 | 권장 |
|
|
160
|
+
|------------|-------------|------|
|
|
161
|
+
| < 10MB | ✅ 안전 | 자동 적용 |
|
|
162
|
+
| 10MB-100MB | ⚠️ 주의 | 명시적 사용 |
|
|
163
|
+
| > 100MB | ❌ 위험 | 사용 금지 (OOM) |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 4. Adaptive Query Execution (AQE)
|
|
168
|
+
|
|
169
|
+
### AQE 활성화 (Spark 3.0+)
|
|
170
|
+
```python
|
|
171
|
+
# AQE 활성화 (Spark 3.2+ 기본값)
|
|
172
|
+
spark.conf.set("spark.sql.adaptive.enabled", "true")
|
|
173
|
+
|
|
174
|
+
# 자동 파티션 병합
|
|
175
|
+
spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled", "true")
|
|
176
|
+
|
|
177
|
+
# 자동 스큐 조인 최적화
|
|
178
|
+
spark.conf.set("spark.sql.adaptive.skewJoin.enabled", "true")
|
|
179
|
+
|
|
180
|
+
# 자동 브로드캐스트 조인 전환
|
|
181
|
+
spark.conf.set("spark.sql.adaptive.localShuffleReader.enabled", "true")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### AQE 효과
|
|
185
|
+
- 런타임에 조인 전략 자동 선택
|
|
186
|
+
- 작은 테이블 감지 시 브로드캐스트로 전환
|
|
187
|
+
- 셔플 파티션 자동 병합
|
|
188
|
+
- 데이터 스큐 자동 처리
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 5. 데이터 스큐 처리
|
|
193
|
+
|
|
194
|
+
### 스큐 감지
|
|
195
|
+
```python
|
|
196
|
+
# 파티션별 레코드 수 확인
|
|
197
|
+
from pyspark.sql.functions import spark_partition_id
|
|
198
|
+
|
|
199
|
+
df.groupBy(spark_partition_id()).count().show()
|
|
200
|
+
|
|
201
|
+
# 키별 분포 확인
|
|
202
|
+
df.groupBy("join_key").count().orderBy("count", ascending=False).show(10)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 솔팅 (Salting) 기법
|
|
206
|
+
```python
|
|
207
|
+
from pyspark.sql.functions import concat, lit, rand, floor
|
|
208
|
+
|
|
209
|
+
# 스큐된 키에 솔트 추가
|
|
210
|
+
SALT_BUCKETS = 10
|
|
211
|
+
|
|
212
|
+
# 큰 테이블: 랜덤 솔트 추가
|
|
213
|
+
large_df = large_df.withColumn(
|
|
214
|
+
"salted_key",
|
|
215
|
+
concat(df["key"], lit("_"), floor(rand() * SALT_BUCKETS).cast("string"))
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# 작은 테이블: 모든 솔트 값으로 복제
|
|
219
|
+
from pyspark.sql.functions import explode, array
|
|
220
|
+
|
|
221
|
+
small_df = small_df.withColumn(
|
|
222
|
+
"salt",
|
|
223
|
+
explode(array([lit(str(i)) for i in range(SALT_BUCKETS)]))
|
|
224
|
+
)
|
|
225
|
+
small_df = small_df.withColumn(
|
|
226
|
+
"salted_key",
|
|
227
|
+
concat(df["key"], lit("_"), df["salt"])
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# 솔티드 키로 조인
|
|
231
|
+
result = large_df.join(small_df, "salted_key")
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 6. 파일 포맷 최적화
|
|
237
|
+
|
|
238
|
+
### Parquet 사용 (권장)
|
|
239
|
+
```python
|
|
240
|
+
# CSV → Parquet 변환 (최초 1회)
|
|
241
|
+
df = spark.read.csv("data.csv", header=True, inferSchema=True)
|
|
242
|
+
df.write.parquet("data.parquet")
|
|
243
|
+
|
|
244
|
+
# Parquet 읽기 (빠름)
|
|
245
|
+
df = spark.read.parquet("data.parquet")
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### 파일 포맷 비교
|
|
249
|
+
| 포맷 | 읽기 속도 | 쓰기 속도 | 압축률 | 컬럼 선택 |
|
|
250
|
+
|------|----------|----------|--------|----------|
|
|
251
|
+
| CSV | 느림 | 느림 | 없음 | ❌ |
|
|
252
|
+
| JSON | 느림 | 느림 | 없음 | ❌ |
|
|
253
|
+
| Parquet | 빠름 | 빠름 | 높음 | ✅ |
|
|
254
|
+
| ORC | 빠름 | 빠름 | 높음 | ✅ |
|
|
255
|
+
|
|
256
|
+
### 컬럼 선택 (Predicate Pushdown)
|
|
257
|
+
```python
|
|
258
|
+
# ✅ 필요한 컬럼만 선택 (Parquet에서 효율적)
|
|
259
|
+
df = spark.read.parquet("data.parquet").select("col1", "col2", "col3")
|
|
260
|
+
|
|
261
|
+
# ✅ 필터 먼저 적용 (Predicate Pushdown)
|
|
262
|
+
df = spark.read.parquet("data.parquet").filter("date > '2024-01-01'")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 7. 조인 전 필터링
|
|
268
|
+
|
|
269
|
+
### 조인 전 데이터 축소
|
|
270
|
+
```python
|
|
271
|
+
# ❌ 나쁜 예: 조인 후 필터
|
|
272
|
+
result = large_df.join(other_df, "key").filter("status = 'active'")
|
|
273
|
+
|
|
274
|
+
# ✅ 좋은 예: 조인 전 필터
|
|
275
|
+
filtered = large_df.filter("status = 'active'")
|
|
276
|
+
result = filtered.join(other_df, "key")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 불필요한 컬럼 제거
|
|
280
|
+
```python
|
|
281
|
+
# ❌ 나쁜 예: 모든 컬럼 조인
|
|
282
|
+
result = df1.join(df2, "key")
|
|
283
|
+
|
|
284
|
+
# ✅ 좋은 예: 필요한 컬럼만 선택 후 조인
|
|
285
|
+
df1_slim = df1.select("key", "needed_col1", "needed_col2")
|
|
286
|
+
df2_slim = df2.select("key", "needed_col3")
|
|
287
|
+
result = df1_slim.join(df2_slim, "key")
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 8. 셔플 최적화
|
|
293
|
+
|
|
294
|
+
### 셔플 파티션 수 조정
|
|
295
|
+
```python
|
|
296
|
+
# 기본값: 200
|
|
297
|
+
# 데이터 크기에 따라 조정
|
|
298
|
+
spark.conf.set("spark.sql.shuffle.partitions", "400") # 대용량
|
|
299
|
+
spark.conf.set("spark.sql.shuffle.partitions", "50") # 소용량
|
|
300
|
+
|
|
301
|
+
# AQE 사용 시 자동 조정됨 (권장)
|
|
302
|
+
spark.conf.set("spark.sql.adaptive.enabled", "true")
|
|
303
|
+
spark.conf.set("spark.sql.adaptive.coalescePartitions.enabled", "true")
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 셔플 줄이기
|
|
307
|
+
```python
|
|
308
|
+
# ❌ 셔플 발생: 여러 번 groupBy
|
|
309
|
+
df.groupBy("col1").agg({"val": "sum"})
|
|
310
|
+
df.groupBy("col1").agg({"val": "avg"})
|
|
311
|
+
|
|
312
|
+
# ✅ 셔플 1회: 한 번에 집계
|
|
313
|
+
from pyspark.sql.functions import sum, avg
|
|
314
|
+
|
|
315
|
+
df.groupBy("col1").agg(
|
|
316
|
+
sum("val").alias("sum_val"),
|
|
317
|
+
avg("val").alias("avg_val")
|
|
318
|
+
)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Quick Reference: 최적화 체크리스트
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
# 1. AQE 활성화 (Spark 3.0+)
|
|
327
|
+
spark.conf.set("spark.sql.adaptive.enabled", "true")
|
|
328
|
+
|
|
329
|
+
# 2. Parquet 사용
|
|
330
|
+
df = spark.read.parquet("data.parquet")
|
|
331
|
+
|
|
332
|
+
# 3. 조인 전 필터링
|
|
333
|
+
df = df.filter(...).select(["필요한", "컬럼만"])
|
|
334
|
+
|
|
335
|
+
# 4. 브로드캐스트 조인 (작은 테이블)
|
|
336
|
+
result = large_df.join(broadcast(small_df), "key")
|
|
337
|
+
|
|
338
|
+
# 5. 반복 사용 DataFrame 캐싱
|
|
339
|
+
df = df.repartition("join_key").cache()
|
|
340
|
+
|
|
341
|
+
# 6. 셔플 파티션 조정
|
|
342
|
+
spark.conf.set("spark.sql.shuffle.partitions", "200")
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### 조인 전략 선택 가이드
|
|
346
|
+
| 상황 | 조인 전략 | 설정 |
|
|
347
|
+
|------|----------|------|
|
|
348
|
+
| 작은 테이블 (< 100MB) | 브로드캐스트 | `broadcast(df)` |
|
|
349
|
+
| 같은 키로 파티셔닝됨 | 소트 머지 | 기본 |
|
|
350
|
+
| 데이터 스큐 있음 | 솔팅 + AQE | `skewJoin.enabled` |
|
|
351
|
+
| 대용량 + 대용량 | 소트 머지 + AQE | 기본 |
|
|
352
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python_code_quality
|
|
3
|
+
description: Python 코드를 쓸 때(데이터 분석·시각화·파일 처리·노트북 셀) 먼저 읽는다. 보안(SQL 파라미터 바인딩·민감 정보·PII 마스킹)·성능(dtypes·usecols·벡터 연산)·코드 품질 원칙과 파일 경로 확인 규칙.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 코드 생성 품질 원칙 (기본 적용)
|
|
7
|
+
생성하는 모든 코드에 아래 원칙을 반영하세요. 코드리뷰에서 지적될 패턴을 처음부터 방지합니다.
|
|
8
|
+
|
|
9
|
+
## 🛡️ 보안 (금융권 기준)
|
|
10
|
+
- SQL 쿼리: 파라미터 바인딩 필수 (f-string 직접 삽입 금지)
|
|
11
|
+
- 파일 경로: os.path.join() 또는 pathlib 사용 (경로 조작 방지)
|
|
12
|
+
- 민감 정보(API 키, 비밀번호, 접속정보): os.environ.get()으로 처리 (하드코딩 금지)
|
|
13
|
+
- DataFrame에 PII 컬럼(주민번호, 계좌번호, 전화번호 등) 존재 시: 마스킹 처리 코드 포함
|
|
14
|
+
- 로깅/출력에 민감 데이터 노출 금지
|
|
15
|
+
|
|
16
|
+
## ⚡ 성능 (인프라 인지형)
|
|
17
|
+
- DataFrame: dtypes 최적화 (object→category, int64→int32 등), 불필요한 .copy() 제거
|
|
18
|
+
- 파일 읽기: usecols로 필요 컬럼만 지정, 대용량 시 chunksize 적용
|
|
19
|
+
- 반복 연산: 벡터 연산 우선 (iterrows/itertuples 대신 apply/vectorized ops)
|
|
20
|
+
- 중복 연산 제거: 동일 계산 결과는 변수에 저장 후 재사용
|
|
21
|
+
|
|
22
|
+
## 🔧 코드 품질
|
|
23
|
+
- 매직 넘버 대신 상단에 명명 상수 정의
|
|
24
|
+
- 에러 가능성 높은 I/O(파일 읽기, API 호출)는 try-except로 감싸고 의미 있는 에러 메시지 출력
|
|
25
|
+
- 반복 사용되는 로직은 함수로 분리 (재현성 확보)
|
|
26
|
+
- 데이터 검증: 처리 전 shape/dtypes/null 비율 확인 코드 포함
|
|
27
|
+
|
|
28
|
+
## 📁 파일 경로
|
|
29
|
+
- 파일 경로가 주어지지 않았으면 os.getcwd()로 현재 디렉토리를 확인하는 코드를 먼저 포함하세요.
|
|
30
|
+
- 파일을 열기 전에 os.path.isfile()로 존재 여부를 확인하고, 없으면 glob으로 검색하는 fallback 코드를 포함하세요.
|
|
31
|
+
|
|
32
|
+
## 📊 그 밖의 규칙
|
|
33
|
+
- Use English labels for plots (required for Korean text rendering issues)
|
|
34
|
+
- Handle large datasets efficiently (use chunking, sampling when needed)
|
|
35
|
+
- Include error handling for file operations
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: regression_evaluation
|
|
3
|
+
description: 'Regression Evaluation Template. 이런 요청에 쓴다: regression, rmse, mae, r2 score, 회귀, 잔차'
|
|
4
|
+
---
|
|
5
|
+
## Regression Evaluation Template
|
|
6
|
+
1. **Predictions**: `y_pred = model.predict(X_test)`
|
|
7
|
+
2. **Metrics**: RMSE, MAE, R², MAPE — `mean_squared_error()`, `mean_absolute_error()`, `r2_score()`
|
|
8
|
+
3. **Residual Plot**: `residuals = y_test - y_pred` → scatter plot vs predicted
|
|
9
|
+
4. **Residual Distribution**: Histogram / Q-Q plot for normality check
|
|
10
|
+
5. **Actual vs Predicted**: 45-degree line scatter plot
|
|
11
|
+
6. **Cross-Validation**: `cross_val_score(scoring='neg_root_mean_squared_error')`
|
|
12
|
+
7. **Feature Coefficients**: For linear models, inspect `model.coef_`
|