Tuner 로 모델 튜닝하기
#
시작하면서이전 장에서 Tuner를 사용할 준비를 마쳤습니다.
이번 장에서는 UI, YAML, SDK 로 Tuner를 사용하는 방법을 배웁니다.
이 튜토리얼은 Notebook과 Tuner에서 진행됩니다.
info
이번 과정은 개발을 위한 준비 챕터에서 만든 handson 노트북서버에서 진행됩니다.
Tuner 사용 준비 에서 작성한 코드를 베이스로 사용할 것입니다.
전체 코드는 아래 링크에서 확인하실 수 있습니다.
06.tuner.ipynb
#
Goal- Tuner UI로 튜닝하기
- YAML을 이용하여 튜닝하기
- SDK를 이용하여 튜닝하기
#
Tuner UI로 튜닝하기Tuner 메뉴로 이동하여 CREATE
버튼을 누릅니다. CAP의 Tuner는 사용자가 순서대로 입력할 수 있게 UI를 제공합니다.
#
1. Metadata 설정Tuner의 이름을 설정합니다. fashion-mnist-tuner라고 정하겠습니다. 나중 리스트에 보여질 이름입니다.
#
2. Trial Thresholds 설정동시에 3개의 탐색을 진행하며, 총 12번의 탐색을 진행합니다. 그리고 탐색이 3번 실패하면 멈추도록 설정하겠습니다.
#
3. 목표 설정
- type : Maximize
- Metric : Validation-accuracy
- Goal : 0.99
- Additional metrics : ➕ 버튼을 눌러 accuracy, loss, Validation-loss 를 적습니다.
- set metrics stargey는 일단 그대로 둡니다.
위처럼 설정 하면 Validation-accuracy 값이 0.99가 되는 것을 목표로 하이퍼파라미터 탐색을 시작합니다.
accuracy, loss, Validaiton-loss와 같은 다른 메트릭도 같이 수집합니다.
tip
만약 탐색 도중 0.99가 된다면 Tuner는 현재 탐색을 종료시킵니다.
만약 종료가 되지 않는다면 0.99에 가장 가까운 값을 Best 로 정합니다.
#
4. 탐색 알고리즘 설정
하이퍼파라미터 튜닝을 선택한 후, 탐색 알고리즘을 Random으로 선택합니다.
이는 하이퍼파라미터의 값을 매 탐색(Trial) 마다 랜덤으로 정하여 진행합니다.
#
5. Early Stopping 설정탐색이 과적합(overfitting)으로 가거나 아니면 비정상적으로 진행될 때 멈추는 기능입니다.
Median Stopping Rule의 기본 세팅으로 설정하겠습니다.
#
6. 하이퍼파라미터 설정MyModel에서 탐색해야할 하이퍼파라미터를 입력합니다.
MyModel에서 argparse
로 입력받기로 했던 항목을 추가합니다.
node_amount : Type 은 Categorical , Value로 64, 128, 256, 512로 설정합니다.
dropout_rate : Type은 Double, Value로 0.1에서 0.9로 설정합니다.
optimizer : Type 은 Categorical, Value로 sgd, adam, nadam, rmsprop 를 추가합니다.
TYPE
하이퍼파라미터의 타입에 따라 넣는 형식이 다릅니다.
Integer, Double : Min, Max 값을 넣어 범위형태로 파라미터를 넣을 수 있습니다.
Categorical : 순서가 상관 없는 범주형 파라미터를 넣어 줍니다.
Discrete : Categorical과 비슷하지만 Numeric 한 파라미터를 넣을 때 사용합니다.
#
7. 로그 수집 방법 설정
Tuner에서 로그 수집하는 방법은 여러가지가 있지만 MyModel 클래스에서 print 함수로 로그를 출력하게 때문에
Standard output 설정인 Stdout으로 설정합니다.
#
8. Trial Template 설정Tuner에서는 탐색을 진행할 Kubernetes Job 기본 템플릿을 제공합니다.
이 템플릿을 복사해서 MyModel에 맞게 수정하겠습니다.
# MyModel Yaml, 이미지 이름을 본인이 만든 이미지 이름과 태그로 바꿔줍니다.apiVersion: batch/v1kind: Jobspec: template: metadata: annotations: sidecar.istio.io/inject: "false" spec: containers: - name: training-container image: yourID/fashion-mnist-tuner:yourTAG # fairing으로 만들어진 자신의 이미지 command: - "python" - "/app/fashion_mnist_tuner.py" - "--node_amount=${trialParameters.node_amount}" - "--dropout_rate=${trialParameters.dropout_rate}" - "--optimizer=${trialParameters.optimizer}" restartPolicy: Never
Source Type을 YAML로 바꾸고 위 템플릿을 복사하여 붙여넣습니다.
- spec.containers.image 필드의 이미지 이름을 본인이 만든 이미지 이름과 태그로 바꿔줍니다.
- argparse로 입력받는 영역과 python 파일로 변환된 fashion_mnist_tuner.py 이 템플릿에 적용되어 있습니다.
마지막 단계에서 템플릿에 입력값으로 들어간 trialParameters.node_amount등의 하이퍼파라미터들을
앞서 입력한 하이퍼파라미터들와 매칭시켜줍니다. 혼동의 여지가 있어서 이름을 다 통일하였습니다.
모든 준비는 끝났습니다. CREATE
버튼을 눌러 Tuner를 실행해봅시다!
Status가 READY
로 변경이 되면 Trials가 실행이 됩니다. 상세 보기로 들어가면 자세한 탐색 내용을 확인할 수 있습니다.
12번의 탐색이 완료 되면, Best trial's params, Best trial performance를 확인할 수 있습니다.
물론 탐색중에서도 확인이 가능합니다.
:🎉: Validation-accuracy가 85%에서 88%로 3퍼센트가 올랐습니다!
#
탐색 범위 변경, epoch도 하이퍼파라미터로 추가하기12번의 탐색결과(trial)에서 기존 85%의 Validation-accuracy에서 좀 더 높은 정확도(88%)를 얻게 되었습니다.
그러면 이제 epoch도 변경할 수 있도록 argparse로 입력을 받게 바꾸고, 탐색횟수도 좀 더 늘려봅시다.
note
TUNER UI를 사용하면 처음부터 모든 설정을 다시 입력해야하는 번거로움이 있습니다.
# from fashion_mnist_model.ipynb ... parser.add_argument('--node_amount', required=False, type=int, default=128) parser.add_argument('--epoch', required=False, type=int, default=10) parser.add_argument('--dropout_rate', required=False, type=float, default=0.2) ...
... validation_data=(x_test, y_test), epochs=args.epoch, callbacks=[LoggingTrain(), ...
- add epoch template
apiVersion: batch/v1kind: Jobspec: template: metadata: annotations: sidecar.istio.io/inject: "false" spec: containers: - name: training-container image: yourID/fashion-mnist-tuner:yourTAG # fairing으로 만들어진 자신의 이미지 command: - "python" - "/app/fashion_mnist_tuner.py" - "--node_amount=${trialParameters.node_amount}" - "--dropout_rate=${trialParameters.dropout_rate}" - "--optimizer=${trialParameters.optimizer}" - "--epoch=${trialParameters.epoch}" restartPolicy: Never
변경이 완료되면 다시 탐색을 시작합시다!
총 30번의 시도에 절반정도가 Ealry Stopping이 적용되었고 미세하게 개선되었음을 알 수 있습니다.
과제
신경망의 층 수와 신경망의 activation 함수도 수정해보며 90%를 넘겨봅시다!
#
YAML을 이용하여 튜닝하기UI를 이용한 튜닝에는 한가지 단점이 있습니다. Tuner를 실행할때 마다 처음부터 새로 입력해야 한다는 점입니다.
간단한 수정사항이 있어도 처음부터 재작성 해야하는 어려움이 있습니다.
이 점을 해결하기 위해 실행한 Tuner의 YAML을 제공합니다.
YAML만을 이용해 UI의 8 Step을 거치지 않고 한번에 실행이 가능합니다.
#
기존의 Tuner 템플릿 가져오기아까 실행한 fashion-mnist-tuner의 상세화면으로 이동해봅시다.
그래프 하단에 YAML tab을 누르면 Tuner의 YAML을 확인할 수 있습니다.
이 YAML을 복사한 후 메모장으로 옮깁니다. YAML의 기본 구조는 4가지의 필드로 구성되어 있습니다.
apiVersion:kind:metadata:spec:
복사해온 YAML에서는 apiVersion, kind가 빠져있기 때문에 아래의 코드를 제일 상단에 추가합니다.
apiVersion: kubeflow.org/v1beta1kind: Experiment
metadata 필드내의 name와 namespace를 제외하고는 기존 Tuner의 상태 정보이기 때문에 삭제합니다.
그리고 status 이하 필드 또한 실행된 Tuner의 상태 정보이기 때문에 지우도록 하겠습니다.
수정된 전체 YAML은 아래와 같습니다.
05.tuner.yaml
apiVersion: kubeflow.org/v1beta1kind: Experimentmetadata: name: fashion-mnist-tuner namespace: cap-devspec: parameters: - name: node_amount parameterType: categorical feasibleSpace: list: - '64' - '128' - '256' - '512' - name: dropout_rate parameterType: double feasibleSpace: max: '0.9' min: '0.1' step: '0.1' - name: optimizer parameterType: categorical feasibleSpace: list: - sgd - adam - nadam - rmsprop objective: type: maximize goal: 0.99 objectiveMetricName: Validation-accuracy additionalMetricNames: - accuracy - loss - Validation-loss metricStrategies: - name: Validation-accuracy value: max - name: accuracy value: max - name: loss value: min - name: Validation-loss value: min algorithm: algorithmName: random trialTemplate: trialSpec: apiVersion: batch/v1 kind: Job spec: template: metadata: annotations: sidecar.istio.io/inject: 'false' spec: containers: - command: - python - /app/fashion_mnist_tuner.py - '--node_amount=${trialParameters.node_amount}' - '--optimizer=${trialParameters.optimizer}' - '--dropout_rate=${trialParameters.dropout_rate}' - '--epoch=${trialParameters.epoch}' image: yourID/fashion-mnist-tuner:yourTAG # 자신의 fairing 이미지 name: training-container restartPolicy: Never trialParameters: - name: node_amount reference: node_amount - name: dropout_rate reference: dropout_rate - name: optimizer reference: optimizer - name: epoch reference: epoch primaryContainerName: training-container successCondition: status.conditions.#(type=="Complete")#|#(status=="True")# failureCondition: status.conditions.#(type=="Failed")#|#(status=="True")# parallelTrialCount: 3 maxTrialCount: 12 maxFailedTrialCount: 3 metricsCollectorSpec: collector: kind: StdOut resumePolicy: LongRunning
#
YAML로 실행하기Tuner 생성 화면 제일 하단에 OPEN YAML이란 버튼이 있습니다. 그 버튼을 누르면 YAML을 편집할 수 있는 편집공간이 나옵니다. 기본 템플릿이 들어있으니, 이전에 작성한 YAML을 이름만 수정해서 넣고 CREATE를 실행하면 똑같은 설정의 다른 이름의 Tuner를 실행할 수 있습니다.
#
노트북에서 SDK를 이용하여 튜닝하기CAP은 노트북에서 Tuner를 사용할 수 있는 SDK를 제공합니다. 먼저 tuner.ipynb라는 이름의 빈 노트북을 생성합니다. CAP에서 제공되는 노트북 이미지에는 기본적으로 SDK가 설치되어 있지만, 만약 설치되어 있지 않다면
!pip install kubeflow-katib
를 명령어로 설치를 진행해주세요.
!pip freeze | grep katibkubeflow-katib==0.11.1 # 이와같이 출력이 되지 않는다면
!pip install kubeflow-katib # <-를 실행합니다.
#
Tuner 리스트 조회해보기SDK를성활용하여 현재 실행된 Tuner를 조회해 보겠습니다. SDK를 사용하기 위해서는 client를 먼저 생성합니다.
from kubeflow import katibfrom kubeflow.katib import KatibClient
kclient = KatibClient()kclient.list_experiments()
아까 실행한 Tuner의 리스트가 나오면 성공입니다.
#
노트북에서 Tuner 상세 정보 조회하기kclient.get_experiment('fashion-mnist-tuner') # 리스트를 조회해서 나온 Tuner의 이름을 넣어주세요
#
노트북에서 Tuner의 결과 조회하기Tuner가 찾은 최적의 결과를 조회합니다.
kclient.get_optimal_hyperparameters('YOUR_TUNER_NAME') # 리스트를 조회해서 나온 Tuner의 이름을 넣어주세요
모든 결과는 dict 형태로 반환됩니다.
#
노트북에서 SDK로 Tuner 생성하기이제 Tuner를 생성해보겠습니다. UI로 만든 fashion-mnist-tuner와 동일한 기능을 하는 코드를 작성하겠습니다.
Tuner SDK는 python 코드를 Tuner YAML변환하여 Tuner를 실행시키기 때문에 코드로 YAML의 필드들을 구현합니다.
YAML의 기본 구조인 api, kind, metadata, spec을 똑같이 python 코드로 구현하겠습니다.
from kubernetes.client import V1ObjectMetafrom kubeflow.katib import V1beta1Experimentfrom kubeflow.katib import V1beta1AlgorithmSpecfrom kubeflow.katib import V1beta1ObjectiveSpecfrom kubeflow.katib import V1beta1FeasibleSpacefrom kubeflow.katib import V1beta1ExperimentSpecfrom kubeflow.katib import V1beta1ObjectiveSpecfrom kubeflow.katib import V1beta1ParameterSpecfrom kubeflow.katib import V1beta1TrialTemplatefrom kubeflow.katib import V1beta1TrialParameterSpec
experiment_name = "fashion-mnist-tuner-sdk"
metadata = V1ObjectMeta( name=experiment_name)
algorithm_spec=V1beta1AlgorithmSpec( algorithm_name="random")
objective_spec=V1beta1ObjectiveSpec( type="maximize", goal= 0.99, objective_metric_name="Validation-accuracy", additional_metric_names=["Validation-loss", "accuracy", "loss"])
parameters=[ V1beta1ParameterSpec( name="node_amount", parameter_type="categorical", feasible_space=V1beta1FeasibleSpace( list=["64", "128", "256", "521"], ), ), V1beta1ParameterSpec( name="dropout_rate", parameter_type="double", feasible_space=V1beta1FeasibleSpace( min="0.1", max="0.9" ), ), V1beta1ParameterSpec( name="optimizer", parameter_type="categorical", feasible_space=V1beta1FeasibleSpace( list=["sgd", "adam", "nadam", "rmsprop"], ), ), V1beta1ParameterSpec( name="epoch", parameter_type="int", feasible_space=V1beta1FeasibleSpace( min="10", max="30" ), ), ]
# JSON template specification for the Trial's Worker Kubernetes Job.trial_spec = { "apiVersion": "batch/v1", "kind": "Job", "spec": { "template": { "metadata": { "annotations": { "sidecar.istio.io/inject": "false" } }, "spec": { "containers": [ { "name": "training-container", "image": "YOURID/fashion-mnist-tuner:YOURTAG", "command": [ "python", "/app/fashion_mnist_tuner.py", "--node_amount=${trialParameters.node_amount}", "--dropout_rate=${trialParameters.dropout_rate}", "--optimizer=${trialParameters.optimizer}", "--epoch=${trialParameters.epoch}" ] } ], "restartPolicy": "Never" } } }}
# Configure parameters for the Trial template.trial_template=V1beta1TrialTemplate( primary_container_name="training-container", trial_spec=trial_spec, trial_parameters=[ V1beta1TrialParameterSpec( name="node_amount", description="Layer neuron amount", reference="node_amount" ), V1beta1TrialParameterSpec( name="dropout_rate", description="dropout_rate for the training model", reference="dropout_rate" ), V1beta1TrialParameterSpec( name="optimizer", description="optimizer for the training model", reference="optimizer" ), V1beta1TrialParameterSpec( name="epoch", description="epoch for the training model", reference="epoch" ) ])
# Experiment object.experiment = V1beta1Experiment( api_version="kubeflow.org/v1beta1", kind="Experiment", metadata=metadata, spec=V1beta1ExperimentSpec( max_trial_count=12, parallel_trial_count=3, max_failed_trial_count=3, algorithm=algorithm_spec, objective=objective_spec, parameters=parameters, trial_template=trial_template, ))
Tuner의 experiment 설정이 완료되면 클라이언트로 실행해보겠습니다.
아래 코드가 오류없이 실행이 되면 노트북에서 Tuner로 이동할 수 있는 링크가 제공됩니다.
kclient.create_experiment(experiment)
#
Tuner 탐색 상태 조회하기fashion-mnist-tuner-sdk 란 이름의 Tuner가 실행되고 있습니다.
SDK를 이용해 현재 Tuner의 상태를 확인하겠습니다.
실행중이라면 Running 정상적으로 탐색을 종료하였다면 Succeeded란 메시지를 출력합니다.
kclient.get_experiment_status("fashion-mnist-tuner-sdk")