aiauto-client 0.1.5__py3-none-any.whl → 0.1.7__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.
aiauto/constants.py CHANGED
@@ -9,20 +9,15 @@ RUNTIME_IMAGES = [
9
9
  "ghcr.io/astral-sh/uv:python3.10-bookworm-slim",
10
10
  "ghcr.io/astral-sh/uv:python3.11-bookworm-slim",
11
11
  "ghcr.io/astral-sh/uv:python3.12-bookworm-slim",
12
-
12
+
13
13
  # GPU Images (PyTorch)
14
14
  "pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime",
15
15
  "pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime",
16
16
  "pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime",
17
-
17
+
18
18
  # GPU Images (TensorFlow)
19
19
  "tensorflow/tensorflow:2.15.0-gpu",
20
- "tensorflow/tensorflow:2.15.0-gpu-jupyter",
21
-
22
- # JAX Images
23
- "nvcr.io/nvidia/jax:23.10-py3",
24
- "nvcr.io/nvidia/jax:24.04-py3",
25
-
20
+
26
21
  # Custom/Legacy images
27
- "ghcr.io/01ai/zipline:latest", # Custom zipline trading library
28
- ]
22
+ "registry.gitlab.com/01ai/eng/aiauto/aiauto/zipline-prepared:main-v00.00.01-amd64-11ca2c41-250901",
23
+ ]
aiauto/core.py CHANGED
@@ -25,15 +25,15 @@ class AIAutoController:
25
25
  # EnsureWorkspace 호출해서 journal_grpc_storage_proxy_host_external 받아와서 storage 초기화
26
26
  try:
27
27
  response = self.client.call_rpc("EnsureWorkspace", {})
28
-
28
+
29
29
  # 받아온 journal_grpc_storage_proxy_host_external로 storage 초기화
30
30
  host_external = response.get('journalGrpcStorageProxyHostExternal', '')
31
31
  if not host_external:
32
32
  raise RuntimeError("No storage host returned from EnsureWorkspace")
33
-
33
+
34
34
  host, port = host_external.split(':')
35
35
  self.storage = optuna.storages.GrpcStorageProxy(host=host, port=int(port))
36
-
36
+
37
37
  # Store the internal host for CRD usage (if needed later)
38
38
  self.storage_host_internal = response.get('journalGrpcStorageProxyHostInternal', '')
39
39
  self.dashboard_url = response.get('dashboardUrl', '')
@@ -65,7 +65,7 @@ class AIAutoController:
65
65
  def create_study(
66
66
  self,
67
67
  study_name: str,
68
- direction: Optional[str] = None,
68
+ direction: Optional[str] = 'minimize',
69
69
  directions: Optional[List[str]] = None,
70
70
  sampler: Union[object, dict, None] = None,
71
71
  pruner: Union[object, dict, None] = None
@@ -88,10 +88,10 @@ class AIAutoController:
88
88
  "prunerJson": object_to_json(pruner)
89
89
  }
90
90
  }
91
-
91
+
92
92
  # Call CreateStudy RPC
93
93
  response = self.client.call_rpc("CreateStudy", request_data)
94
-
94
+
95
95
  # Return StudyWrapper
96
96
  return StudyWrapper(
97
97
  study_name=response.get("studyName", study_name),
@@ -184,15 +184,20 @@ class StudyWrapper:
184
184
  def optimize(
185
185
  self,
186
186
  objective: Callable,
187
- n_trials: int,
188
- parallelism: int,
187
+ n_trials: int = 10,
188
+ parallelism: int = 2,
189
189
  requirements_file: Optional[str] = None,
190
190
  requirements_list: Optional[List[str]] = None,
191
- resources_requests: Optional[Dict[str, str]] = None,
192
- resources_limits: Optional[Dict[str, str]] = None,
193
- runtime_image: Optional[str] = None,
191
+ resources_requests: Optional[Dict[str, str]] = {"cpu": "256m", "memory": "256Mi"},
192
+ resources_limits: Optional[Dict[str, str]] = {"cpu": "256m", "memory": "256Mi"},
193
+ runtime_image: Optional[str] = 'ghcr.io/astral-sh/uv:python3.8-bookworm-slim',
194
194
  use_gpu: bool = False
195
195
  ) -> None:
196
+ if runtime_image is None or runtime_image == "":
197
+ if use_gpu:
198
+ runtime_image = "pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime"
199
+ else:
200
+ runtime_image = "ghcr.io/astral-sh/uv:python3.8-bookworm-slim"
196
201
  try:
197
202
  request_data = {
198
203
  "objective": {
@@ -209,7 +214,7 @@ class StudyWrapper:
209
214
  "useGpu": use_gpu
210
215
  }
211
216
  }
212
-
217
+
213
218
  self._controller.client.call_rpc("Optimize", request_data)
214
219
 
215
220
  except Exception as e:
@@ -218,10 +223,10 @@ class StudyWrapper:
218
223
  def get_status(self) -> dict:
219
224
  try:
220
225
  response = self._controller.client.call_rpc(
221
- "GetStatus",
226
+ "GetStatus",
222
227
  {"studyName": self.study_name}
223
228
  )
224
-
229
+
225
230
  # Convert camelCase to snake_case for backward compatibility
226
231
  return {
227
232
  "study_name": response.get("studyName", ""),
@@ -240,4 +245,4 @@ class StudyWrapper:
240
245
  raise RuntimeError(f"Failed to get status: {e}") from e
241
246
 
242
247
  def __repr__(self) -> str:
243
- return f"StudyWrapper(study_name='{self.study_name}', storage={self._storage})"
248
+ return f"StudyWrapper(study_name='{self.study_name}', storage={self._storage})"
aiauto/serializer.py CHANGED
@@ -6,14 +6,24 @@ from typing import Callable, Union, List, Optional
6
6
  def serialize(objective: Callable) -> str:
7
7
  try:
8
8
  return inspect.getsource(objective)
9
- except Exception as e:
10
- raise ValueError("objective는 모듈 최상위 def만 허용합니다(데코레이터/로컬/람다 불가)") from e
9
+ except (OSError, TypeError) as e:
10
+ raise ValueError(
11
+ "Serialize 실패 objective 함수는 파일로 저장되어야 합니다\n"
12
+ "REPL/Jupyter Notebook에서는 %%writefile magic을 사용해서 local 에 file 로 저장하세요\n\n"
13
+ "%%writefile objective.py\n"
14
+ "def objective(trial):\n"
15
+ " # 함수 내용\n"
16
+ " ...\n\n"
17
+ "그 다음:\n"
18
+ "from objective import objective\n"
19
+ "study.optimize(objective, ...)"
20
+ ) from e
11
21
 
12
22
 
13
23
  def build_requirements(file_path: Optional[str] = None, reqs: Optional[List[str]] = None) -> str:
14
24
  if file_path and reqs:
15
25
  raise ValueError("requirements_file과 requirements_list는 동시에 지정할 수 없습니다")
16
-
26
+
17
27
  if file_path:
18
28
  with open(file_path, 'r') as f:
19
29
  return f.read()
@@ -26,20 +36,20 @@ def build_requirements(file_path: Optional[str] = None, reqs: Optional[List[str]
26
36
  def object_to_json(obj: Union[object, dict, None]) -> str:
27
37
  if obj is None:
28
38
  return ""
29
-
39
+
30
40
  if isinstance(obj, dict):
31
41
  return json.dumps(obj)
32
-
42
+
33
43
  cls = type(obj)
34
44
  module_name = cls.__module__
35
45
  class_name = cls.__name__
36
-
46
+
37
47
  if not module_name.startswith('optuna.'):
38
48
  raise ValueError(f"optuna 코어 클래스만 지원합니다: {class_name}")
39
-
49
+
40
50
  sig = inspect.signature(cls)
41
51
  kwargs = {}
42
-
52
+
43
53
  for param_name, param in sig.parameters.items():
44
54
  if param_name == 'self':
45
55
  continue
@@ -47,9 +57,9 @@ def object_to_json(obj: Union[object, dict, None]) -> str:
47
57
  value = getattr(obj, param_name)
48
58
  if param.default != value:
49
59
  kwargs[param_name] = value
50
-
60
+
51
61
  return json.dumps({
52
62
  "module": module_name,
53
63
  "class": class_name,
54
64
  "kwargs": kwargs
55
- })
65
+ })
@@ -0,0 +1,472 @@
1
+ Metadata-Version: 2.1
2
+ Name: aiauto-client
3
+ Version: 0.1.7
4
+ Summary: AI Auto HPO (Hyperparameter Optimization) Client Library
5
+ Author-email: AIAuto Team <ainode@zeroone.ai>
6
+ Project-URL: Homepage, https://dashboard.aiauto.pangyo.ainode.ai
7
+ Project-URL: Repository, https://dashboard.aiauto.pangyo.ainode.ai
8
+ Project-URL: Documentation, https://dashboard.aiauto.pangyo.ainode.ai
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.8
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: optuna>=3.0.0
24
+ Requires-Dist: requests>=2.25.0
25
+ Requires-Dist: grpcio>=1.48.0
26
+ Requires-Dist: grpcio-status>=1.48.0
27
+
28
+ # AIAuto - Hyperparameter Optimization Client Library
29
+
30
+ AIAuto는 Kubernetes 기반의 분산 HPO(Hyperparameter Optimization) 시스템을 위한 클라이언트 라이브러리입니다.
31
+ 사용자 python lib <-> Next.js 서버 사이 Connect RPC (HTTP/1.1) 통신 담당
32
+
33
+ ## 설치
34
+ - `pip install aiauto-client optuna`
35
+
36
+ ## API 레퍼런스
37
+
38
+ ### create_study 파라미터
39
+ - `study_name` (str): Study 이름
40
+ - `direction` (str): 단일 목적 최적화 방향 ("minimize" 또는 "maximize")
41
+ - `directions` (List[str]): 다중 목적 최적화 방향 리스트 (direction과 상호 배타적)
42
+ - `sampler` (object/dict): Optuna sampler 객체 또는 dict (선택적)
43
+ - `pruner` (object/dict): Optuna pruner 객체 또는 dict (선택적)
44
+
45
+ **주의**: `direction`과 `directions`는 둘 중 하나만 지정해야 합니다.
46
+
47
+ ### optimize 파라미터
48
+ - `objective` (Callable): Trial을 인자로 받는 목적 함수
49
+ - `n_trials` (int): 총 trial 수
50
+ - `parallelism` (int): 동시 실행 Pod 수 (기본값: 2)
51
+ - `requirements_file` (str): requirements.txt 파일 경로 (requirements_list와 상호 배타적)
52
+ - `requirements_list` (List[str]): 패키지 리스트 (requirements_file과 상호 배타적)
53
+ - `resources_requests` (Dict[str, str]): 리소스 요청 (기본값: {"cpu": "256m", "memory": "256Mi"})
54
+ - `resources_limits` (Dict[str, str]): 리소스 제한 (기본값: {"cpu": "256m", "memory": "256Mi"})
55
+ - `runtime_image` (str): 커스텀 런타임 이미지 (None이면 자동 선택)
56
+ - `use_gpu` (bool): GPU 사용 여부 (기본값: False)
57
+
58
+ **주의**: `requirements_file`과 `requirements_list`는 둘 중 하나만 지정해야 합니다.
59
+
60
+ ## 지원 런타임 이미지 확인
61
+ ```python
62
+ import aiauto
63
+
64
+ # 사용 가능한 이미지 확인
65
+ for image in aiauto.RUNTIME_IMAGES:
66
+ print(image)
67
+ ```
68
+
69
+ ## 실행 흐름
70
+ ### token 발급 # TODO
71
+ - `https://dashboard.aiauto.pangyo.ainode.ai` 에 접속하여 ainode 에 로그인 한 후
72
+ - `https://dashboard.aiauto.pangyo.ainode.ai/token` 으로 이동하여 aiauto 의 token 을 발급
73
+ - 아래 코드 처럼 발급한 token 을 넣어 AIAutoController singleton 객체를 초기화, OptunaWorkspace 를 활성화 시킨다
74
+ ```python
75
+ import aiauto
76
+
77
+ ac = aiauto.AIAutoController('<token>')
78
+ ```
79
+ - `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 OptunaWorkspace 와 optuna-dashboard 링크를 확인할 수 있음
80
+ - 아래 코드 처럼 study 를 생성하면 `https://dashboard.aiauto.pangyo.ainode.ai/study` 에서 확인할 수 있고 optuna-dashboard 링크에서도 확인 가능
81
+ ```python
82
+ study_wrapper = ac.create_study(
83
+ study_name='test',
84
+ direction='maximize', # or 'minimize'
85
+ )
86
+ ```
87
+ - 아래 코드 처럼 생성한 study 애서 objective 함수를 작성하여 넘겨주면 optimize 를 호출하면 `https://dashboard.aiauto.pangyo.ainode.ai/trialbatch` 에서 확인할 수 있고 optuna-dashboard 링크에서도 확인 가능
88
+ ```python
89
+ study_wrapper.optimize(
90
+ objective=func_with_parameter_trial,
91
+ n_trials=4,
92
+ parallelism=2,
93
+ use_gpu=False,
94
+ runtime_image=aiauto.RUNTIME_IMAGES[0],
95
+ )
96
+ ```
97
+
98
+ ## Jupyter Notebook 사용 시 주의사항
99
+
100
+ Jupyter Notebook이나 Python REPL에서 정의한 함수는 Serialize 할 수 없습니다
101
+ 대신 `%%writefile` magic 울 사용하여 파일로 저장한 후 import 하세요.
102
+
103
+ ### Jupyter에서 objective 함수 작성 방법
104
+ - objective 함수를 파일로 저장
105
+ ```python
106
+ %%writefile my_objective.py
107
+ import aiauto
108
+ import optuna
109
+
110
+ def objective(trial: optuna.trial.Trial):
111
+ """
112
+ 이 함수는 외부 서버에서 실행됩니다.
113
+ 모든 import는 함수 내부에 작성하세요.
114
+ """
115
+ import torch # 함수 내부에서 import
116
+
117
+ x = trial.suggest_float('x', -10, 10)
118
+ y = trial.suggest_float('y', -10, 10)
119
+ return (x - 2) ** 2 + (y - 3) ** 2
120
+ ```
121
+ - 저장한 함수를 import해서 사용
122
+ ```python
123
+ import aiauto
124
+ from my_objective import objective
125
+
126
+ ac = aiauto.AIAutoController('<token>')
127
+ study = ac.create_study('test', 'minimize')
128
+ study.optimize(objective, n_trials=10, parallelism=2)
129
+ ```
130
+
131
+ ## 빠른 시작
132
+
133
+ ### 1. 간단한 예제 (수학 함수 최적화)
134
+
135
+ ```python
136
+ import optuna
137
+ import aiauto
138
+
139
+
140
+ # `https://dashboard.aiauto.pangyo.ainode.ai` 에 접속하여 ainode 에 로그인 한 후 aiauto 의 token 을 발급
141
+ # AIAutoController singleton 객체를 초기화 하여, OptunaWorkspace 를 활성화 시킨다 (토큰은 한 번만 설정)
142
+ ac = aiauto.AIAutoController('<token>')
143
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 OptunaWorkspace 와 optuna-dashboard 링크를 확인할 수 있음
144
+
145
+ # StudyWrapper 생성
146
+ study_wrapper = ac.create_study(
147
+ study_name="simple_optimization",
148
+ direction="minimize"
149
+ # sampler=optuna.samplers.TPESampler(), # optuna 에서 제공하는 sampler 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/samplers/index.html
150
+ )
151
+ # `https://dashboard.aiauto.pangyo.ainode.ai/study` 에서 생성된 study 확인 가능
152
+
153
+ # objective 함수 정의
154
+ def objective(trial: optuna.trial.Trial):
155
+ """실제 실행은 사용자 로컬 컴퓨터가 아닌 서버에서 실행 될 함수"""
156
+ x = trial.suggest_float('x', -10, 10)
157
+ y = trial.suggest_float('y', -10, 10)
158
+ return (x - 2) ** 2 + (y - 3) ** 2
159
+
160
+ # 사용자 모델 학습 or 최적화 실행 (서버에서 병렬 실행)
161
+ study_wrapper.optimize(
162
+ objective,
163
+ n_trials=100,
164
+ parallelism=4 # 동시 실행 Pod 수
165
+ )
166
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 optuna-dashboard 링크에서 결과 확인 가능
167
+ ```
168
+
169
+ ### 2. PyTorch 모델 최적화 (Single Objective)
170
+
171
+ ```python
172
+ import optuna
173
+ import aiauto
174
+
175
+
176
+ # `https://dashboard.aiauto.pangyo.ainode.ai` 에 접속하여 ainode 에 로그인 한 후 aiauto 의 token 을 발급
177
+ # AIAutoController singleton 객체를 초기화 하여, OptunaWorkspace 를 활성화 시킨다 (토큰은 한 번만 설정)
178
+ ac = aiauto.AIAutoController('<token>')
179
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 OptunaWorkspace 와 optuna-dashboard 링크를 확인할 수 있음
180
+
181
+ # StudyWrapper 생성
182
+ study_wrapper = ac.create_study(
183
+ study_name="pytorch_optimization",
184
+ direction="minimize",
185
+ # sampler=optuna.samplers.TPESampler(), # optuna 에서 제공하는 sampler 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/samplers/index.html
186
+ pruner=optuna.pruners.PatientPruner( # optuna 에서 제공하는 pruner 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/pruners.html
187
+ optuna.pruners.MedianPruner(),
188
+ patience=4,
189
+ ),
190
+ )
191
+ # `https://dashboard.aiauto.pangyo.ainode.ai/study` 에서 생성된 study 확인 가능
192
+
193
+ # objective 함수 정의
194
+ # https://docs.pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html 참고
195
+ def objective(trial: optuna.trial.Trial):
196
+ """
197
+ 실제 실행은 사용자 로컬 컴퓨터가 아닌 서버에서 실행 될 함수
198
+ 모든 import는 함수 내부에 존재해야 함
199
+ """
200
+ import torch
201
+ from torch import nn, optim
202
+ from torch.utils.data import DataLoader, random_split, Subset
203
+ from torchvision import transforms, datasets
204
+ import torch.nn.functional as F
205
+
206
+ # 하이퍼파라미터 샘플링
207
+ lr = trial.suggest_float('learning_rate', 1e-5, 1e-1, log=True)
208
+ momentom = trial.suggest_float('momentom', 0.1, 0.99)
209
+ batch_size = trial.suggest_categorical('batch_size', [16, 32, 64, 128])
210
+ epochs = trial.suggest_int('epochs', 10, 100, step=10)
211
+
212
+ # 모델 정의
213
+ class Net(nn.Module):
214
+ def __init__(self):
215
+ super().__init__()
216
+ self.conv1 = nn.Conv2d(3, 6, 5)
217
+ self.pool = nn.MaxPool2d(2, 2)
218
+ self.conv2 = nn.Conv2d(6, 16, 5)
219
+ self.fc1 = nn.Linear(16 * 5 * 5, 120)
220
+ self.fc2 = nn.Linear(120, 84)
221
+ self.fc3 = nn.Linear(84, 10)
222
+
223
+ def forward(self, x):
224
+ x = self.pool(F.relu(self.conv1(x)))
225
+ x = self.pool(F.relu(self.conv2(x)))
226
+ x = torch.flatten(x, 1) # flatten all dimensions except batch
227
+ x = F.relu(self.fc1(x))
228
+ x = F.relu(self.fc2(x))
229
+ x = self.fc3(x)
230
+ return x
231
+
232
+ # 모델 정의 및 학습 (GPU 자동 사용)
233
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
234
+ model = Net().to(device)
235
+ criterion = nn.CrossEntropyLoss()
236
+ optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentom)
237
+
238
+ # 데이터 로드
239
+ train_set = datasets.CIFAR10(
240
+ root="/tmp/cifar10_data", # Pod의 임시 디렉토리 사용
241
+ train=True,
242
+ download=True,
243
+ transform=[
244
+ transforms.ToTensor(),
245
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
246
+ ],
247
+ )
248
+ train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=2)
249
+
250
+ test_set = datasets.CIFAR10(
251
+ root="/tmp/cifar10_data", # Pod의 임시 디렉토리 사용
252
+ train=False,
253
+ download=True,
254
+ transform=[
255
+ transforms.ToTensor(),
256
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
257
+ ],
258
+ )
259
+ test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=True, num_workers=2)
260
+
261
+ # 학습
262
+ min_epochs_for_pruning = max(50, epochs // 5) # 최소 50 epoch 또는 전체의 1/5 후부터 pruning
263
+ total_loss = 0.0
264
+ for epoch in range(epochs): # loop over the dataset multiple times
265
+ running_loss = 0.0
266
+ model.train()
267
+ for i, (inputs, targets) in enumerate(train_loader, 0):
268
+ inputs, targets = inputs.to(device), targets.to(device)
269
+ # zero the parameter gradients
270
+ optimizer.zero_grad()
271
+ # forward + backward + optimize
272
+ outputs = model(inputs)
273
+ loss = criterion(outputs, targets)
274
+ loss.backward()
275
+ optimizer.step()
276
+
277
+ # print statistics
278
+ running_loss += loss.item()
279
+ if i % 2000 == 1999: # print every 2000 mini-batches
280
+ print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')
281
+
282
+ # intermediate result 보고 및 초기 중단 검사 - 최소 epochs 후 부터만 pruning
283
+ trial.report(running_loss, epoch)
284
+ total_loss += running_loss
285
+ if epoch >= min_epochs_for_pruning and trial.should_prune():
286
+ raise optuna.TrialPruned()
287
+
288
+ return total_loss
289
+
290
+ # GPU Pod에서 실행
291
+ study_wrapper.optimize(
292
+ objective,
293
+ n_trials=100,
294
+ parallelism=4,
295
+ use_gpu=True, # GPU 사용
296
+ requirements_list=['torch', 'torchvision'] # Pod에서 자동 설치
297
+ )
298
+ ```
299
+
300
+ ### 3. Multi-Objective 최적화 (Accuracy + FLOPS)
301
+
302
+ ```python
303
+ import optuna
304
+ import aiauto
305
+
306
+
307
+ # `https://dashboard.aiauto.pangyo.ainode.ai` 에 접속하여 ainode 에 로그인 한 후 aiauto 의 token 을 발급
308
+ # AIAutoController singleton 객체를 초기화 하여, OptunaWorkspace 를 활성화 시킨다 (토큰은 한 번만 설정)
309
+ ac = aiauto.AIAutoController('<token>')
310
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 OptunaWorkspace 와 optuna-dashboard 링크를 확인할 수 있음
311
+
312
+ # StudyWrapper 생성
313
+ study_wrapper = ac.create_study(
314
+ study_name="pytorch_multiple_optimization",
315
+ direction=["minimize", "minimize"], # loss minimize, FLOPS minimize
316
+ # sampler=optuna.samplers.TPESampler(), # optuna 에서 제공하는 sampler 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/samplers/index.html
317
+ )
318
+ # `https://dashboard.aiauto.pangyo.ainode.ai/study` 에서 생성된 study 확인 가능
319
+
320
+ # objective 함수 정의
321
+ # https://docs.pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html 참고
322
+ def objective(trial: optuna.trial.Trial):
323
+ """
324
+ 실제 실행은 사용자 로컬 컴퓨터가 아닌 서버에서 실행 될 함수
325
+ 모든 import는 함수 내부에 존재해야 함
326
+ """
327
+ import torch
328
+ from torch import nn, optim
329
+ from torch.utils.data import DataLoader, random_split, Subset
330
+ from torchvision import transforms, datasets
331
+ import torch.nn.functional as F
332
+ from fvcore.nn import FlopCountAnalysis
333
+
334
+ # 하이퍼파라미터 샘플링
335
+ lr = trial.suggest_float('learning_rate', 1e-5, 1e-1, log=True)
336
+ momentom = trial.suggest_float('momentom', 0.1, 0.99)
337
+ batch_size = trial.suggest_categorical('batch_size', [16, 32, 64, 128])
338
+ epochs = trial.suggest_int('epochs', 10, 100, step=10)
339
+
340
+ # 모델 정의
341
+ class Net(nn.Module):
342
+ def __init__(self):
343
+ super().__init__()
344
+ self.conv1 = nn.Conv2d(3, 6, 5)
345
+ self.pool = nn.MaxPool2d(2, 2)
346
+ self.conv2 = nn.Conv2d(6, 16, 5)
347
+ self.fc1 = nn.Linear(16 * 5 * 5, 120)
348
+ self.fc2 = nn.Linear(120, 84)
349
+ self.fc3 = nn.Linear(84, 10)
350
+
351
+ def forward(self, x):
352
+ x = self.pool(F.relu(self.conv1(x)))
353
+ x = self.pool(F.relu(self.conv2(x)))
354
+ x = torch.flatten(x, 1) # flatten all dimensions except batch
355
+ x = F.relu(self.fc1(x))
356
+ x = F.relu(self.fc2(x))
357
+ x = self.fc3(x)
358
+ return x
359
+
360
+ # 모델 정의 및 학습 (GPU 자동 사용)
361
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
362
+ model = Net().to(device)
363
+ criterion = nn.CrossEntropyLoss()
364
+ optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentom)
365
+
366
+ # 데이터 로드
367
+ train_set = datasets.CIFAR10(
368
+ root="/tmp/cifar10_data", # Pod의 임시 디렉토리 사용
369
+ train=True,
370
+ download=True,
371
+ transform=[
372
+ transforms.ToTensor(),
373
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
374
+ ],
375
+ )
376
+ train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=2)
377
+
378
+ test_set = datasets.CIFAR10(
379
+ root="/tmp/cifar10_data", # Pod의 임시 디렉토리 사용
380
+ train=False,
381
+ download=True,
382
+ transform=[
383
+ transforms.ToTensor(),
384
+ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
385
+ ],
386
+ )
387
+ test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=True, num_workers=2)
388
+
389
+ # 학습
390
+ total_loss = 0.0
391
+ # multiple objective 는 pruning 미지원
392
+ for epoch in range(epochs): # loop over the dataset multiple times
393
+ running_loss = 0.0
394
+ model.train()
395
+ for i, (inputs, targets) in enumerate(train_loader, 0):
396
+ inputs, targets = inputs.to(device), targets.to(device)
397
+ # zero the parameter gradients
398
+ optimizer.zero_grad()
399
+ # forward + backward + optimize
400
+ outputs = model(inputs)
401
+ loss = criterion(outputs, targets)
402
+ loss.backward()
403
+ optimizer.step()
404
+
405
+ # print statistics
406
+ running_loss += loss.item()
407
+ if i % 2000 == 1999: # print every 2000 mini-batches
408
+ print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')
409
+
410
+ # multiple objective 는 pruning 미지원
411
+
412
+ # FLOPS 계산
413
+ dummy_input = torch.randn(1, 3, 32, 32).to(device)
414
+ flops = FlopCountAnalysis(model, (dummy_input,)).total()
415
+
416
+ return total_loss, flops
417
+
418
+ # GPU Pod에서 실행
419
+ study_wrapper.optimize(
420
+ objective,
421
+ n_trials=100,
422
+ parallelism=4,
423
+ use_gpu=True, # GPU 사용
424
+ requirements_list=['torch', 'torchvision', 'fvcore'] # Pod에서 자동 설치
425
+ )
426
+ ```
427
+
428
+ ### 4. Ask/Tell 패턴 및 Optuna 자체의 Study
429
+
430
+ ```python
431
+ import optuna
432
+ import aiauto
433
+
434
+ # `https://dashboard.aiauto.pangyo.ainode.ai` 에 접속하여 ainode 에 로그인 한 후 aiauto 의 token 을 발급
435
+ # AIAutoController singleton 객체를 초기화 하여, OptunaWorkspace 를 활성화 시킨다 (토큰은 한 번만 설정)
436
+ ac = aiauto.AIAutoController('<token>')
437
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 OptunaWorkspace 와 optuna-dashboard 링크를 확인할 수 있음
438
+
439
+ # Study 생성
440
+ study_wrapper = ac.create_study(
441
+ study_name="test",
442
+ direction='minimize',
443
+ # sampler=optuna.samplers.TPESampler(), # optuna 에서 제공하는 sampler 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/samplers/index.html
444
+ # pruner=optuna.pruners.PatientPruner( # optuna 에서 제공하는 pruner 그대로 사용 가능, 참고 https://optuna.readthedocs.io/en/stable/reference/pruners.html
445
+ # optuna.pruners.MedianPruner(),
446
+ # patience=4,
447
+ # )
448
+ )
449
+ # `https://dashboard.aiauto.pangyo.ainode.ai/study` 에서 생성된 study 확인 가능
450
+
451
+ # 실제 optuna.Study 객체 획득 (로컬에서 ask/tell 가능)
452
+ study = study_wrapper.get_study()
453
+
454
+ # Ask/Tell 패턴으로 최적화
455
+ trial = study.ask()
456
+
457
+ # 파라미터 최적화
458
+ x = trial.suggest_float('x', -10, 10)
459
+ y = trial.suggest_float('y', -10, 10)
460
+
461
+ # 사용자 모델 학습 or 최적화 실행 (서버에서 병렬 실행)
462
+ ret = (x - 2) ** 2 + (y - 3) ** 2
463
+
464
+ # 결과 보고
465
+ study.tell(trial, ret)
466
+ # `https://dashboard.aiauto.pangyo.ainode.ai/workspace` 에서 생성된 optuna-dashboard 링크에서 결과 확인 가능
467
+ ```
468
+
469
+ # lib build
470
+ ```bash
471
+ make build push
472
+ ```
@@ -0,0 +1,10 @@
1
+ aiauto/__init__.py,sha256=sF7sJaXg7-MqolSYLxsaXAir1dBzARhXLrHo7zLsupg,345
2
+ aiauto/_config.py,sha256=DaRTIZlph9T3iuW-Cy4fkw8i3bXB--gMtW947SLZZNs,159
3
+ aiauto/constants.py,sha256=rBibGOQHHrdkwaai92-3I8-N0cu-B4CoCoQbG9-Cl8k,821
4
+ aiauto/core.py,sha256=DQW9uvVNqP9J9s1IFx969upw10NQLHJMNsudHnauk6A,9840
5
+ aiauto/http_client.py,sha256=t1gxeM5-d5bsVoFWgaNcTrt_WWUXuMuxge9gDlEqhoA,2086
6
+ aiauto/serializer.py,sha256=KqQeH0xp4LQuZE6r8kzXQsWY6QgC3hqn8MSuWTt4QmU,1938
7
+ aiauto_client-0.1.7.dist-info/METADATA,sha256=xy8ZGkJYOwMUgA_8J4ag2mepwBzGZQwsyIOkMgQ8Cpw,18450
8
+ aiauto_client-0.1.7.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
9
+ aiauto_client-0.1.7.dist-info/top_level.txt,sha256=Sk2ctO9_Bf_tAPwq1x6Vfl6OuL29XzwMTO4F_KG6oJE,7
10
+ aiauto_client-0.1.7.dist-info/RECORD,,
@@ -1,102 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: aiauto-client
3
- Version: 0.1.5
4
- Summary: AI Auto HPO (Hyperparameter Optimization) Client Library
5
- Author-email: AIAuto Team <ainode@zeroone.ai>
6
- Project-URL: Homepage, https://aiauto.cloude.ainode.ai
7
- Project-URL: Repository, https://aiauto.cloude.ainode.ai
8
- Project-URL: Documentation, https://aiauto.cloude.ainode.ai
9
- Classifier: Development Status :: 3 - Alpha
10
- Classifier: Intended Audience :: Developers
11
- Classifier: Intended Audience :: Science/Research
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.12
18
- Classifier: Programming Language :: Python :: 3.13
19
- Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
- Requires-Python: >=3.8
22
- Description-Content-Type: text/markdown
23
- Requires-Dist: optuna>=3.0.0
24
- Requires-Dist: requests>=2.25.0
25
- Requires-Dist: grpcio>=1.48.0
26
- Requires-Dist: grpcio-status>=1.48.0
27
-
28
- # AIAuto - Hyperparameter Optimization Client Library
29
-
30
- AIAuto는 Kubernetes 기반의 분산 HPO(Hyperparameter Optimization) 시스템을 위한 클라이언트 라이브러리입니다.
31
- 사용자 python lib <-> Next.js 서버 사이 gRPC 통신 담당
32
-
33
- ## lib build
34
- - `make build push`
35
-
36
- ## 설치
37
- - `uv add aiauto-client`
38
-
39
- ## 빠른 시작
40
-
41
- ### Study 생성 및 Ask/Tell 패턴
42
- ```python
43
- import aiauto
44
-
45
- # StudyWrapper 생성 (JWT 토큰 필요)
46
- studyWrapper = aiauto.create_study(
47
- study_name='my_optimization',
48
- token='your_jwt_token',
49
- direction='maximize'
50
- )
51
-
52
- # 실제 optuna.Study 객체 획득 (로컬에서 ask/tell 가능)
53
- study = studyWrapper.get_study()
54
-
55
- # Ask/Tell 패턴으로 최적화
56
- trial = study.ask()
57
- params = trial.params
58
-
59
- # 사용자 모델 학습
60
- accuracy = train_model(params)
61
-
62
- # 결과 보고
63
- study.tell(trial, accuracy)
64
- ```
65
-
66
- ### 분산 최적화 (Pod 실행)
67
- ```python
68
- import aiauto
69
-
70
- def objective(trial):
71
- tc = aiauto.TrialController(trial)
72
-
73
- # 하이퍼파라미터 샘플링
74
- lr = trial.suggest_float('lr', 1e-5, 1e-1, log=True)
75
- batch_size = trial.suggest_int('batch_size', 16, 128)
76
-
77
- # 모델 학습 로직
78
- accuracy = train_model(lr, batch_size)
79
-
80
- tc.log(f'lr: {lr}, batch_size: {batch_size}, accuracy: {accuracy}')
81
-
82
- return accuracy
83
-
84
- # StudyWrapper 생성
85
- studyWrapper = aiauto.create_study(
86
- study_name='distributed_optimization',
87
- token='your_jwt_token',
88
- direction='maximize'
89
- )
90
-
91
- # 분산 최적화 실행 (Kubernetes Pod에서 실행)
92
- studyWrapper.optimize(
93
- objective=objective,
94
- n_trials=100,
95
- parallelism=4,
96
- requirements_list=['torch==2.0.0', 'torchvision==0.15.0']
97
- )
98
-
99
- # 실시간 상태 모니터링
100
- status = studyWrapper.get_status()
101
- print(f"Active: {status['count_active']}, Completed: {status['count_completed']}")
102
- ```
@@ -1,10 +0,0 @@
1
- aiauto/__init__.py,sha256=sF7sJaXg7-MqolSYLxsaXAir1dBzARhXLrHo7zLsupg,345
2
- aiauto/_config.py,sha256=DaRTIZlph9T3iuW-Cy4fkw8i3bXB--gMtW947SLZZNs,159
3
- aiauto/constants.py,sha256=UhDCLFoPE89XrHB3SEnZR3YUuzajgugMGX80KYx_qc0,939
4
- aiauto/core.py,sha256=BFKEF2wp3mjMFt5V7oGyZ531j_MIQBJNEiiOVhrKmzc,9549
5
- aiauto/http_client.py,sha256=t1gxeM5-d5bsVoFWgaNcTrt_WWUXuMuxge9gDlEqhoA,2086
6
- aiauto/serializer.py,sha256=_iPtEoqW8RTKOZ6UrC7CzOqoangpPYzeL7MQfIdmov8,1568
7
- aiauto_client-0.1.5.dist-info/METADATA,sha256=_tY0xtaoaz-ZimyBJSavhmApFa8p5oT9WuKDyHH7Hi0,3001
8
- aiauto_client-0.1.5.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
9
- aiauto_client-0.1.5.dist-info/top_level.txt,sha256=Sk2ctO9_Bf_tAPwq1x6Vfl6OuL29XzwMTO4F_KG6oJE,7
10
- aiauto_client-0.1.5.dist-info/RECORD,,