diff --git a/api/v1alpha1/workspace_validation_test.go b/api/v1alpha1/workspace_validation_test.go index 11631e67b..d196beabc 100644 --- a/api/v1alpha1/workspace_validation_test.go +++ b/api/v1alpha1/workspace_validation_test.go @@ -21,8 +21,15 @@ var perGPUMemoryRequirement string type testModel struct{} -func (*testModel) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*testModel) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ + GPUCountRequirement: gpuCountRequirement, + TotalGPUMemoryRequirement: totalGPUMemoryRequirement, + PerGPUMemoryRequirement: perGPUMemoryRequirement, + } +} +func (*testModel) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ GPUCountRequirement: gpuCountRequirement, TotalGPUMemoryRequirement: totalGPUMemoryRequirement, PerGPUMemoryRequirement: perGPUMemoryRequirement, @@ -31,11 +38,22 @@ func (*testModel) GetInferenceParameters() *model.PresetInferenceParam { func (*testModel) SupportDistributedInference() bool { return false } +func (*testModel) SupportTuning() bool { + return true +} type testModelPrivate struct{} -func (*testModelPrivate) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*testModelPrivate) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ + ImageAccessMode: "private", + GPUCountRequirement: gpuCountRequirement, + TotalGPUMemoryRequirement: totalGPUMemoryRequirement, + PerGPUMemoryRequirement: perGPUMemoryRequirement, + } +} +func (*testModelPrivate) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ ImageAccessMode: "private", GPUCountRequirement: gpuCountRequirement, TotalGPUMemoryRequirement: totalGPUMemoryRequirement, @@ -45,6 +63,9 @@ func (*testModelPrivate) GetInferenceParameters() *model.PresetInferenceParam { func (*testModelPrivate) SupportDistributedInference() bool { return false } +func (*testModelPrivate) SupportTuning() bool { + return true +} func RegisterValidationTestModels() { var test testModel diff --git a/examples/fine-tuning/kaito_workspace_tuning_falcon_7b.yaml b/examples/fine-tuning/kaito_workspace_tuning_falcon_7b.yaml new file mode 100644 index 000000000..6d6ed7831 --- /dev/null +++ b/examples/fine-tuning/kaito_workspace_tuning_falcon_7b.yaml @@ -0,0 +1,20 @@ +apiVersion: kaito.sh/v1alpha1 +kind: Workspace +metadata: + name: workspace-tuning-falcon-7b +spec: + resource: + instanceType: "Standard_NC12s_v3" + labelSelector: + matchLabels: + app: tuning-falcon-7b + tuning: + preset: + name: falcon-7b + method: lora + config: tuning-config-map # ConfigMap containing tuning arguments + input: + name: tuning-data + hostPath: /path/to/your/input/data # dataset on node + output: + hostPath: /path/to/store/output # Tuning Output diff --git a/examples/kaito_workspace_falcon_40b-instruct.yaml b/examples/inference/kaito_workspace_falcon_40b-instruct.yaml similarity index 100% rename from examples/kaito_workspace_falcon_40b-instruct.yaml rename to examples/inference/kaito_workspace_falcon_40b-instruct.yaml diff --git a/examples/kaito_workspace_falcon_40b.yaml b/examples/inference/kaito_workspace_falcon_40b.yaml similarity index 100% rename from examples/kaito_workspace_falcon_40b.yaml rename to examples/inference/kaito_workspace_falcon_40b.yaml diff --git a/examples/kaito_workspace_falcon_7b-instruct.yaml b/examples/inference/kaito_workspace_falcon_7b-instruct.yaml similarity index 100% rename from examples/kaito_workspace_falcon_7b-instruct.yaml rename to examples/inference/kaito_workspace_falcon_7b-instruct.yaml diff --git a/examples/kaito_workspace_falcon_7b.yaml b/examples/inference/kaito_workspace_falcon_7b.yaml similarity index 100% rename from examples/kaito_workspace_falcon_7b.yaml rename to examples/inference/kaito_workspace_falcon_7b.yaml diff --git a/examples/kaito_workspace_llama2_13b-chat.yaml b/examples/inference/kaito_workspace_llama2_13b-chat.yaml similarity index 100% rename from examples/kaito_workspace_llama2_13b-chat.yaml rename to examples/inference/kaito_workspace_llama2_13b-chat.yaml diff --git a/examples/kaito_workspace_llama2_13b.yaml b/examples/inference/kaito_workspace_llama2_13b.yaml similarity index 100% rename from examples/kaito_workspace_llama2_13b.yaml rename to examples/inference/kaito_workspace_llama2_13b.yaml diff --git a/examples/kaito_workspace_llama2_70b-chat.yaml b/examples/inference/kaito_workspace_llama2_70b-chat.yaml similarity index 100% rename from examples/kaito_workspace_llama2_70b-chat.yaml rename to examples/inference/kaito_workspace_llama2_70b-chat.yaml diff --git a/examples/kaito_workspace_llama2_70b.yaml b/examples/inference/kaito_workspace_llama2_70b.yaml similarity index 100% rename from examples/kaito_workspace_llama2_70b.yaml rename to examples/inference/kaito_workspace_llama2_70b.yaml diff --git a/examples/kaito_workspace_llama2_7b-chat.yaml b/examples/inference/kaito_workspace_llama2_7b-chat.yaml similarity index 100% rename from examples/kaito_workspace_llama2_7b-chat.yaml rename to examples/inference/kaito_workspace_llama2_7b-chat.yaml diff --git a/examples/kaito_workspace_llama2_7b.yaml b/examples/inference/kaito_workspace_llama2_7b.yaml similarity index 100% rename from examples/kaito_workspace_llama2_7b.yaml rename to examples/inference/kaito_workspace_llama2_7b.yaml diff --git a/examples/kaito_workspace_mistral_7b-instruct.yaml b/examples/inference/kaito_workspace_mistral_7b-instruct.yaml similarity index 100% rename from examples/kaito_workspace_mistral_7b-instruct.yaml rename to examples/inference/kaito_workspace_mistral_7b-instruct.yaml diff --git a/examples/kaito_workspace_mistral_7b.yaml b/examples/inference/kaito_workspace_mistral_7b.yaml similarity index 100% rename from examples/kaito_workspace_mistral_7b.yaml rename to examples/inference/kaito_workspace_mistral_7b.yaml diff --git a/examples/kaito_workspace_phi-2.yaml b/examples/inference/kaito_workspace_phi-2.yaml similarity index 100% rename from examples/kaito_workspace_phi-2.yaml rename to examples/inference/kaito_workspace_phi-2.yaml diff --git a/pkg/controllers/workspace_controller.go b/pkg/controllers/workspace_controller.go index a2e4fc18d..042249f15 100644 --- a/pkg/controllers/workspace_controller.go +++ b/pkg/controllers/workspace_controller.go @@ -9,8 +9,8 @@ import ( "strings" "time" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/utils/clock" + "github.com/azure/kaito/pkg/tuning" + batchv1 "k8s.io/api/batch/v1" "github.com/aws/karpenter-core/pkg/apis/v1alpha5" kaitov1alpha1 "github.com/azure/kaito/api/v1alpha1" @@ -21,6 +21,7 @@ import ( "github.com/azure/kaito/pkg/utils/plugin" "github.com/go-logr/logr" "github.com/samber/lo" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -28,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" + "k8s.io/utils/clock" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -109,16 +111,22 @@ func (c *WorkspaceReconciler) addOrUpdateWorkspace(ctx context.Context, wObj *ka return reconcile.Result{}, err } - if err = c.applyInference(ctx, wObj); err != nil { - if updateErr := c.updateStatusConditionIfNotMatch(ctx, wObj, kaitov1alpha1.WorkspaceConditionTypeReady, metav1.ConditionFalse, - "workspaceFailed", err.Error()); updateErr != nil { - klog.ErrorS(updateErr, "failed to update workspace status", "workspace", klog.KObj(wObj)) - return reconcile.Result{}, updateErr + if wObj.Tuning != nil { + if err = c.applyTuning(ctx, wObj); err != nil { + return reconcile.Result{}, err + } + } + if wObj.Inference != nil { + if err = c.applyInference(ctx, wObj); err != nil { + if updateErr := c.updateStatusConditionIfNotMatch(ctx, wObj, kaitov1alpha1.WorkspaceConditionTypeReady, metav1.ConditionFalse, + "workspaceFailed", err.Error()); updateErr != nil { + klog.ErrorS(updateErr, "failed to update workspace status", "workspace", klog.KObj(wObj)) + return reconcile.Result{}, updateErr + } + return reconcile.Result{}, err } - return reconcile.Result{}, err } - // TODO apply TrainingSpec if err = c.updateStatusConditionIfNotMatch(ctx, wObj, kaitov1alpha1.WorkspaceConditionTypeReady, metav1.ConditionTrue, "workspaceReady", "workspace is ready"); err != nil { klog.ErrorS(err, "failed to update workspace status", "workspace", klog.KObj(wObj)) @@ -423,6 +431,41 @@ func (c *WorkspaceReconciler) ensureService(ctx context.Context, wObj *kaitov1al return nil } +func (c *WorkspaceReconciler) applyTuning(ctx context.Context, wObj *kaitov1alpha1.Workspace) error { + var err error + func() { + if wObj.Tuning.Preset != nil { + presetName := string(wObj.Tuning.Preset.Name) + model := plugin.KaitoModelRegister.MustGet(presetName) + + tuningParam := model.GetTuningParameters() + existingObj := &batchv1.Job{} + if err = resources.GetResource(ctx, wObj.Name, wObj.Namespace, c.Client, existingObj); err == nil { + klog.InfoS("A tuning workload already exists for workspace", "workspace", klog.KObj(wObj)) + if err = resources.CheckResourceStatus(existingObj, c.Client, tuningParam.ReadinessTimeout); err != nil { + return + } + } else if apierrors.IsNotFound(err) { + var workloadObj client.Object + // Need to create a new workload + workloadObj, err = tuning.CreatePresetTuning(ctx, wObj, tuningParam, c.Client) + if err != nil { + return + } + if err = resources.CheckResourceStatus(workloadObj, c.Client, tuningParam.ReadinessTimeout); err != nil { + return + } + } + } + }() + + if err != nil { + return err + } + + return nil +} + // applyInference applies inference spec. func (c *WorkspaceReconciler) applyInference(ctx context.Context, wObj *kaitov1alpha1.Workspace) error { var err error @@ -455,7 +498,7 @@ func (c *WorkspaceReconciler) applyInference(ctx context.Context, wObj *kaitov1a if err = resources.GetResource(ctx, wObj.Name, wObj.Namespace, c.Client, existingObj); err == nil { klog.InfoS("An inference workload already exists for workspace", "workspace", klog.KObj(wObj)) - if err = resources.CheckResourceStatus(existingObj, c.Client, inferenceParam.DeploymentTimeout); err != nil { + if err = resources.CheckResourceStatus(existingObj, c.Client, inferenceParam.ReadinessTimeout); err != nil { return } } else if apierrors.IsNotFound(err) { @@ -465,7 +508,7 @@ func (c *WorkspaceReconciler) applyInference(ctx context.Context, wObj *kaitov1a if err != nil { return } - if err = resources.CheckResourceStatus(workloadObj, c.Client, inferenceParam.DeploymentTimeout); err != nil { + if err = resources.CheckResourceStatus(workloadObj, c.Client, inferenceParam.ReadinessTimeout); err != nil { return } } diff --git a/pkg/inference/preset-inferences.go b/pkg/inference/preset-inferences.go index 9b02012b7..4c4792b54 100644 --- a/pkg/inference/preset-inferences.go +++ b/pkg/inference/preset-inferences.go @@ -67,7 +67,7 @@ var ( } ) -func updateTorchParamsForDistributedInference(ctx context.Context, kubeClient client.Client, wObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetInferenceParam) error { +func updateTorchParamsForDistributedInference(ctx context.Context, kubeClient client.Client, wObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetParam) error { existingService := &corev1.Service{} err := resources.GetResource(ctx, wObj.Name, wObj.Namespace, kubeClient, existingService) if err != nil { @@ -92,7 +92,7 @@ func updateTorchParamsForDistributedInference(ctx context.Context, kubeClient cl return nil } -func GetImageInfo(ctx context.Context, workspaceObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetInferenceParam) (string, []corev1.LocalObjectReference) { +func GetImageInfo(ctx context.Context, workspaceObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetParam) (string, []corev1.LocalObjectReference) { imageName := string(workspaceObj.Inference.Preset.Name) imageTag := inferenceObj.Tag imagePullSecretRefs := []corev1.LocalObjectReference{} @@ -110,7 +110,7 @@ func GetImageInfo(ctx context.Context, workspaceObj *kaitov1alpha1.Workspace, in } func CreatePresetInference(ctx context.Context, workspaceObj *kaitov1alpha1.Workspace, - inferenceObj *model.PresetInferenceParam, supportDistributedInference bool, kubeClient client.Client) (client.Object, error) { + inferenceObj *model.PresetParam, supportDistributedInference bool, kubeClient client.Client) (client.Object, error) { if inferenceObj.TorchRunParams != nil && supportDistributedInference { if err := updateTorchParamsForDistributedInference(ctx, kubeClient, workspaceObj, inferenceObj); err != nil { klog.ErrorS(err, "failed to update torch params", "workspace", workspaceObj) @@ -141,7 +141,7 @@ func CreatePresetInference(ctx context.Context, workspaceObj *kaitov1alpha1.Work // torchrun baseCommand // and sets the GPU resources required for inference. // Returns the command and resource configuration. -func prepareInferenceParameters(ctx context.Context, inferenceObj *model.PresetInferenceParam) ([]string, corev1.ResourceRequirements) { +func prepareInferenceParameters(ctx context.Context, inferenceObj *model.PresetParam) ([]string, corev1.ResourceRequirements) { torchCommand := buildCommandStr(inferenceObj.BaseCommand, inferenceObj.TorchRunParams) torchCommand = buildCommandStr(torchCommand, inferenceObj.TorchRunRdzvParams) modelCommand := buildCommandStr(InferenceFile, inferenceObj.ModelRunParams) @@ -159,7 +159,7 @@ func prepareInferenceParameters(ctx context.Context, inferenceObj *model.PresetI return commands, resourceRequirements } -func configVolume(wObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetInferenceParam) ([]corev1.Volume, []corev1.VolumeMount) { +func configVolume(wObj *kaitov1alpha1.Workspace, inferenceObj *model.PresetParam) ([]corev1.Volume, []corev1.VolumeMount) { volume := []corev1.Volume{} volumeMount := []corev1.VolumeMount{} diff --git a/pkg/inference/preset-inferences_test.go b/pkg/inference/preset-inferences_test.go index cd8df067c..31bf0551e 100644 --- a/pkg/inference/preset-inferences_test.go +++ b/pkg/inference/preset-inferences_test.go @@ -62,7 +62,7 @@ func TestCreatePresetInference(t *testing.T) { useHeadlessSvc := false - var inferenceObj *model.PresetInferenceParam + var inferenceObj *model.PresetParam model := plugin.KaitoModelRegister.MustGet(tc.modelName) inferenceObj = model.GetInferenceParameters() diff --git a/pkg/model/interface.go b/pkg/model/interface.go index 217c1f889..3a054cf25 100644 --- a/pkg/model/interface.go +++ b/pkg/model/interface.go @@ -7,27 +7,29 @@ import ( ) type Model interface { - GetInferenceParameters() *PresetInferenceParam + GetInferenceParameters() *PresetParam + GetTuningParameters() *PresetParam SupportDistributedInference() bool //If true, the model workload will be a StatefulSet, using the torch elastic runtime framework. + SupportTuning() bool } -// PresetInferenceParam defines the preset inference parameters for a model. -type PresetInferenceParam struct { +// PresetParam defines the preset inference parameters for a model. +type PresetParam struct { ModelFamilyName string // The name of the model family. ImageAccessMode string // Defines where the Image is Public or Private. DiskStorageRequirement string // Disk storage requirements for the model. - GPUCountRequirement string // Number of GPUs required for the inference. - TotalGPUMemoryRequirement string // Total GPU memory required for the inference. + GPUCountRequirement string // Number of GPUs required for the Preset. + TotalGPUMemoryRequirement string // Total GPU memory required for the Preset. PerGPUMemoryRequirement string // GPU memory required per GPU. TorchRunParams map[string]string // Parameters for configuring the torchrun command. - TorchRunRdzvParams map[string]string // Optional rendezvous parameters for distributed inference using torchrun (elastic). - ModelRunParams map[string]string // Parameters for running the model inference. - // DeploymentTimeout defines the maximum duration for pulling the Preset image. + TorchRunRdzvParams map[string]string // Optional rendezvous parameters for distributed training/inference using torchrun (elastic). + // BaseCommand is the initial command (e.g., 'torchrun', 'accelerate launch') used in the command line. + BaseCommand string + ModelRunParams map[string]string // Parameters for running the model training/inference. + // ReadinessTimeout defines the maximum duration for creating the workload. // This timeout accommodates the size of the image, ensuring pull completion // even under slower network conditions or unforeseen delays. - DeploymentTimeout time.Duration - // BaseCommand is the initial command (e.g., 'torchrun', 'accelerate launch') used in the command line. - BaseCommand string + ReadinessTimeout time.Duration // WorldSize defines the number of processes required for distributed inference. WorldSize int Tag string // The model image tag diff --git a/pkg/tuning/preset-tuning-types.go b/pkg/tuning/preset-tuning-types.go new file mode 100644 index 000000000..51f36511d --- /dev/null +++ b/pkg/tuning/preset-tuning-types.go @@ -0,0 +1,21 @@ +package tuning + +import corev1 "k8s.io/api/core/v1" + +const ( + DefaultNumProcesses = "1" + DefaultNumMachines = "1" + DefaultMachineRank = "0" + DefaultGPUIds = "all" +) + +var ( + DefaultAccelerateParams = map[string]string{ + "num_processes": DefaultNumProcesses, + "num_machines": DefaultNumMachines, + "machine_rank": DefaultMachineRank, + "gpu_ids": DefaultGPUIds, + } + + DefaultImagePullSecrets = []corev1.LocalObjectReference{} +) diff --git a/pkg/tuning/preset-tuning.go b/pkg/tuning/preset-tuning.go new file mode 100644 index 000000000..d9dfbd477 --- /dev/null +++ b/pkg/tuning/preset-tuning.go @@ -0,0 +1,14 @@ +package tuning + +import ( + "context" + kaitov1alpha1 "github.com/azure/kaito/api/v1alpha1" + "github.com/azure/kaito/pkg/model" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func CreatePresetTuning(ctx context.Context, workspaceObj *kaitov1alpha1.Workspace, + tuningObj *model.PresetParam, kubeClient client.Client) (client.Object, error) { + // TODO + return nil, nil +} diff --git a/pkg/utils/testModel.go b/pkg/utils/testModel.go index 99e3d8aca..5acd05ac5 100644 --- a/pkg/utils/testModel.go +++ b/pkg/utils/testModel.go @@ -12,27 +12,45 @@ import ( type testModel struct{} -func (*testModel) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*testModel) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ GPUCountRequirement: "1", - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, + } +} +func (*testModel) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + GPUCountRequirement: "1", + ReadinessTimeout: time.Duration(30) * time.Minute, } } func (*testModel) SupportDistributedInference() bool { return false } +func (*testModel) SupportTuning() bool { + return true +} type testDistributedModel struct{} -func (*testDistributedModel) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*testDistributedModel) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ GPUCountRequirement: "1", - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, + } +} +func (*testDistributedModel) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + GPUCountRequirement: "1", + ReadinessTimeout: time.Duration(30) * time.Minute, } } func (*testDistributedModel) SupportDistributedInference() bool { return true } +func (*testDistributedModel) SupportTuning() bool { + return true +} func RegisterTestModel() { var test testModel diff --git a/presets/models/falcon/README.md b/presets/models/falcon/README.md index 81a1ced6f..e8cd895e6 100644 --- a/presets/models/falcon/README.md +++ b/presets/models/falcon/README.md @@ -1,10 +1,10 @@ ## Supported Models |Model name| Model source | Sample workspace|Kubernetes Workload|Distributed inference| |----|:----:|:----:| :----: |:----: | -|falcon-7b-instruct |[tiiuae](https://huggingface.co/tiiuae/falcon-7b-instruct)|[link](../../../examples/kaito_workspace_falcon_7b-instruct.yaml)|Deployment| false| -|falcon-7b |[tiiuae](https://huggingface.co/tiiuae/falcon-7b) |[link](../../../examples/kaito_workspace_falcon_7b.yaml)|Deployment| false| -|falcon-40b-instruct|[tiiuae](https://huggingface.co/tiiuae/falcon-40b-instruct) |[link](../../../examples/kaito_workspace_falcon_40b-instruct.yaml)|Deployment| false| -|falcon-40b |[tiiuae](https://huggingface.co/tiiuae/falcon-40b)|[link](../../../examples/kaito_workspace_falcon_40b.yaml)|Deployment| false| +|falcon-7b-instruct |[tiiuae](https://huggingface.co/tiiuae/falcon-7b-instruct)|[link](../../../examples/inference/kaito_workspace_falcon_7b-instruct.yaml)|Deployment| false| +|falcon-7b |[tiiuae](https://huggingface.co/tiiuae/falcon-7b) |[link](../../../examples/inference/kaito_workspace_falcon_7b.yaml)|Deployment| false| +|falcon-40b-instruct|[tiiuae](https://huggingface.co/tiiuae/falcon-40b-instruct) |[link](../../../examples/inference/kaito_workspace_falcon_40b-instruct.yaml)|Deployment| false| +|falcon-40b |[tiiuae](https://huggingface.co/tiiuae/falcon-40b)|[link](../../../examples/inference/kaito_workspace_falcon_40b.yaml)|Deployment| false| ## Image Source - **Public**: Kaito maintainers manage the lifecycle of the inference service images that contain model weights. The images are available in Microsoft Container Registry (MCR). diff --git a/presets/models/falcon/model.go b/presets/models/falcon/model.go index 863a2fb52..bc7f882af 100644 --- a/presets/models/falcon/model.go +++ b/presets/models/falcon/model.go @@ -54,8 +54,8 @@ var falconA falcon7b type falcon7b struct{} -func (*falcon7b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*falcon7b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Falcon", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "50Gi", @@ -64,22 +64,40 @@ func (*falcon7b) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Falcon using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: falconRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetFalcon, Tag: PresetFalconTagMap["Falcon7B"], } - } +func (*falcon7b) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + ModelFamilyName: "Falcon", + ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), + DiskStorageRequirement: "50Gi", + GPUCountRequirement: "2", + TotalGPUMemoryRequirement: "16Gi", + PerGPUMemoryRequirement: "16Gi", + //TorchRunParams: tuning.DefaultAccelerateParams, // TODO + //ModelRunPrams: falconRunTuningParams, // TODO + ReadinessTimeout: time.Duration(30) * time.Minute, + BaseCommand: baseCommandPresetFalcon, + Tag: PresetFalconTagMap["Falcon7B"], + } +} + func (*falcon7b) SupportDistributedInference() bool { return false } +func (*falcon7b) SupportTuning() bool { + return true +} var falconB falcon7bInst type falcon7bInst struct{} -func (*falcon7bInst) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*falcon7bInst) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Falcon", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "50Gi", @@ -88,22 +106,28 @@ func (*falcon7bInst) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Falcon using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: falconRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetFalcon, Tag: PresetFalconTagMap["Falcon7BInstruct"], } } +func (*falcon7bInst) GetTuningParameters() *model.PresetParam { + return nil // It is not recommended/ideal to further fine-tune instruct models - Already been fine-tuned +} func (*falcon7bInst) SupportDistributedInference() bool { return false } +func (*falcon7bInst) SupportTuning() bool { + return false +} var falconC falcon40b type falcon40b struct{} -func (*falcon40b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*falcon40b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Falcon", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "400", @@ -112,22 +136,40 @@ func (*falcon40b) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Falcon using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: falconRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetFalcon, Tag: PresetFalconTagMap["Falcon40B"], } } +func (*falcon40b) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + ModelFamilyName: "Falcon", + ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), + DiskStorageRequirement: "50Gi", + GPUCountRequirement: "2", + TotalGPUMemoryRequirement: "90Gi", + PerGPUMemoryRequirement: "16Gi", + //TorchRunParams: tuning.DefaultAccelerateParams, // TODO + //ModelRunPrams: falconRunTuningParams, // TODO + ReadinessTimeout: time.Duration(30) * time.Minute, + BaseCommand: baseCommandPresetFalcon, + Tag: PresetFalconTagMap["Falcon40B"], + } +} func (*falcon40b) SupportDistributedInference() bool { return false } +func (*falcon40b) SupportTuning() bool { + return true +} var falconD falcon40bInst type falcon40bInst struct{} -func (*falcon40bInst) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*falcon40bInst) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Falcon", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "400", @@ -136,12 +178,17 @@ func (*falcon40bInst) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Falcon using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: falconRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetFalcon, Tag: PresetFalconTagMap["Falcon40BInstruct"], } } - +func (*falcon40bInst) GetTuningParameters() *model.PresetParam { + return nil // It is not recommended/ideal to further fine-tune instruct models - Already been fine-tuned +} func (*falcon40bInst) SupportDistributedInference() bool { return false } +func (*falcon40bInst) SupportTuning() bool { + return false +} diff --git a/presets/models/llama2/README.md b/presets/models/llama2/README.md index e6a40563a..ba2646a2b 100644 --- a/presets/models/llama2/README.md +++ b/presets/models/llama2/README.md @@ -1,9 +1,9 @@ ## Supported Models |Model name| Model source | Sample workspace|Kubernetes Workload|Distributed inference| |----|:----:|:----:| :----: |:----: | -|llama2-7b |[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_7b.yaml)|Deployment| false| -|llama2-13b|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_13b.yaml)|StatefulSet| true| -|llama2-70b|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_70b.yaml)|StatefulSet| true| +|llama2-7b |[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_7b.yaml)|Deployment| false| +|llama2-13b|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_13b.yaml)|StatefulSet| true| +|llama2-70b|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_70b.yaml)|StatefulSet| true| ## Image Source - **Private**: User needs to manage the lifecycle of the inference service images that contain model weights (e.g., managing image tags). The images are available in user's private container registry. diff --git a/presets/models/llama2/model.go b/presets/models/llama2/model.go index 30c97b7fd..6a62a8987 100644 --- a/presets/models/llama2/model.go +++ b/presets/models/llama2/model.go @@ -38,8 +38,8 @@ var llama2A llama2Text7b type llama2Text7b struct{} -func (*llama2Text7b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Text7b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "34Gi", @@ -49,23 +49,29 @@ func (*llama2Text7b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(10) * time.Minute, + ReadinessTimeout: time.Duration(10) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 1, // Tag: llama has private image access mode. The image tag is determined by the user. } } +func (*llama2Text7b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning +} func (*llama2Text7b) SupportDistributedInference() bool { return false } +func (*llama2Text7b) SupportTuning() bool { + return false +} var llama2B llama2Text13b type llama2Text13b struct{} -func (*llama2Text13b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Text13b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "46Gi", @@ -75,22 +81,28 @@ func (*llama2Text13b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(20) * time.Minute, + ReadinessTimeout: time.Duration(20) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 2, // Tag: llama has private image access mode. The image tag is determined by the user. } } +func (*llama2Text13b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning +} func (*llama2Text13b) SupportDistributedInference() bool { return true } +func (*llama2Text13b) SupportTuning() bool { + return false +} var llama2C llama2Text70b type llama2Text70b struct{} -func (*llama2Text70b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Text70b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "158Gi", @@ -100,12 +112,18 @@ func (*llama2Text70b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 8, // Tag: llama has private image access mode. The image tag is determined by the user. } } +func (*llama2Text70b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning +} func (*llama2Text70b) SupportDistributedInference() bool { return true } +func (*llama2Text70b) SupportTuning() bool { + return false +} diff --git a/presets/models/llama2chat/README.md b/presets/models/llama2chat/README.md index 53e241fab..0cf9ec3be 100644 --- a/presets/models/llama2chat/README.md +++ b/presets/models/llama2chat/README.md @@ -1,9 +1,9 @@ ## Supported Models |Model name| Model source | Sample workspace|Kubernetes Workload|Distributed inference| |----|:----:|:----:| :----: |:----: | -|llama2-7b-chat |[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_7b-chat.yaml)|Deployment| false| -|llama2-13b-chat|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_13b-chat.yaml)|StatefulSet| true| -|llama2-70b-chat|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/kaito_workspace_llama2_70b-chat.yaml)|StatefulSet| true| +|llama2-7b-chat |[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_7b-chat.yaml)|Deployment| false| +|llama2-13b-chat|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_13b-chat.yaml)|StatefulSet| true| +|llama2-70b-chat|[meta](https://github.com/facebookresearch/llama/blob/main/MODEL_CARD.md)|[link](../../../examples/inference/kaito_workspace_llama2_70b-chat.yaml)|StatefulSet| true| ## Image Source - **Private**: User needs to manage the lifecycle of the inference service images that contain model weights (e.g., managing image tags). The images are available in user's private container registry. diff --git a/presets/models/llama2chat/model.go b/presets/models/llama2chat/model.go index cc0d8d4c6..89225bef5 100644 --- a/presets/models/llama2chat/model.go +++ b/presets/models/llama2chat/model.go @@ -38,8 +38,8 @@ var llama2chatA llama2Chat7b type llama2Chat7b struct{} -func (*llama2Chat7b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Chat7b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "34Gi", @@ -49,23 +49,28 @@ func (*llama2Chat7b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(10) * time.Minute, + ReadinessTimeout: time.Duration(10) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 1, // Tag: llama has private image access mode. The image tag is determined by the user. } - +} +func (*llama2Chat7b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning } func (*llama2Chat7b) SupportDistributedInference() bool { return false } +func (*llama2Chat7b) SupportTuning() bool { + return false +} var llama2chatB llama2Chat13b type llama2Chat13b struct{} -func (*llama2Chat13b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Chat13b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "46Gi", @@ -75,22 +80,28 @@ func (*llama2Chat13b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(20) * time.Minute, + ReadinessTimeout: time.Duration(20) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 2, // Tag: llama has private image access mode. The image tag is determined by the user. } } +func (*llama2Chat13b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning +} func (*llama2Chat13b) SupportDistributedInference() bool { return true } +func (*llama2Chat13b) SupportTuning() bool { + return false +} var llama2chatC llama2Chat70b type llama2Chat70b struct{} -func (*llama2Chat70b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*llama2Chat70b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "LLaMa2", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePrivate), DiskStorageRequirement: "158Gi", @@ -100,12 +111,18 @@ func (*llama2Chat70b) GetInferenceParameters() *model.PresetInferenceParam { TorchRunParams: inference.DefaultTorchRunParams, TorchRunRdzvParams: inference.DefaultTorchRunRdzvParams, ModelRunParams: llamaRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetLlama, WorldSize: 8, // Tag: llama has private image access mode. The image tag is determined by the user. } } +func (*llama2Chat70b) GetTuningParameters() *model.PresetParam { + return nil // Currently doesn't support fine-tuning +} func (*llama2Chat70b) SupportDistributedInference() bool { return true } +func (*llama2Chat70b) SupportTuning() bool { + return false +} diff --git a/presets/models/mistral/README.md b/presets/models/mistral/README.md index 4d0c56ba6..2d037f7a4 100644 --- a/presets/models/mistral/README.md +++ b/presets/models/mistral/README.md @@ -1,8 +1,8 @@ ## Supported Models |Model name| Model source | Sample workspace|Kubernetes Workload|Distributed inference| |----|:----:|:----:| :----: |:----: | -|mistral-7b-instruct |[mistralai](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2)|[link](../../../examples/kaito_workspace_mistral_7b-instruct.yaml)|Deployment| false| -|mistral-7b |[mistralai](https://huggingface.co/mistralai/Mistral-7B-v0.1) |[link](../../../examples/kaito_workspace_mistral_7b.yaml)|Deployment| false| +|mistral-7b-instruct |[mistralai](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2)|[link](../../../examples/inference/kaito_workspace_mistral_7b-instruct.yaml)|Deployment| false| +|mistral-7b |[mistralai](https://huggingface.co/mistralai/Mistral-7B-v0.1) |[link](../../../examples/inference/kaito_workspace_mistral_7b.yaml)|Deployment| false| ## Image Source diff --git a/presets/models/mistral/model.go b/presets/models/mistral/model.go index 910e2da83..78115e805 100644 --- a/presets/models/mistral/model.go +++ b/presets/models/mistral/model.go @@ -42,8 +42,8 @@ var mistralA mistral7b type mistral7b struct{} -func (*mistral7b) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*mistral7b) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Mistral", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "100Gi", @@ -52,22 +52,41 @@ func (*mistral7b) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Mistral using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: mistralRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetMistral, Tag: PresetMistralTagMap["Mistral7B"], } } +func (*mistral7b) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + ModelFamilyName: "Mistral", + ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), + DiskStorageRequirement: "100Gi", + GPUCountRequirement: "1", + TotalGPUMemoryRequirement: "16Gi", + PerGPUMemoryRequirement: "16Gi", // We run Mistral using native vertical model parallel, no per GPU memory requirement. + //TorchRunParams: tuning.DefaultAccelerateParams, + //ModelRunParams: mistralRunParams, + ReadinessTimeout: time.Duration(30) * time.Minute, + BaseCommand: baseCommandPresetMistral, + Tag: PresetMistralTagMap["Mistral7B"], + } +} + func (*mistral7b) SupportDistributedInference() bool { return false } +func (*mistral7b) SupportTuning() bool { + return true +} var mistralB mistral7bInst type mistral7bInst struct{} -func (*mistral7bInst) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*mistral7bInst) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Mistral", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "100Gi", @@ -76,12 +95,18 @@ func (*mistral7bInst) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run mistral using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: mistralRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetMistral, Tag: PresetMistralTagMap["Mistral7BInstruct"], } } +func (*mistral7bInst) GetTuningParameters() *model.PresetParam { + return nil // It is not recommended/ideal to further fine-tune instruct models - Already been fine-tuned +} func (*mistral7bInst) SupportDistributedInference() bool { return false } +func (*mistral7bInst) SupportTuning() bool { + return false +} diff --git a/presets/models/phi/README.md b/presets/models/phi/README.md index 7caeadb84..1e77252a5 100644 --- a/presets/models/phi/README.md +++ b/presets/models/phi/README.md @@ -1,7 +1,7 @@ ## Supported Models |Model name| Model source | Sample workspace|Kubernetes Workload|Distributed inference| |----|:----:|:----:| :----: |:----: | -|phi-2 |[microsoft](https://huggingface.co/microsoft/phi-2)|[link](../../../examples/kaito_workspace_phi-2.yaml)|Deployment| false| +|phi-2 |[microsoft](https://huggingface.co/microsoft/phi-2)|[link](../../../examples/inference/kaito_workspace_phi-2.yaml)|Deployment| false| ## Image Source diff --git a/presets/models/phi/model.go b/presets/models/phi/model.go index 32df386cc..3f6e8b120 100644 --- a/presets/models/phi/model.go +++ b/presets/models/phi/model.go @@ -36,8 +36,8 @@ var phiA phi2 type phi2 struct{} -func (*phi2) GetInferenceParameters() *model.PresetInferenceParam { - return &model.PresetInferenceParam{ +func (*phi2) GetInferenceParameters() *model.PresetParam { + return &model.PresetParam{ ModelFamilyName: "Phi", ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), DiskStorageRequirement: "50Gi", @@ -46,12 +46,29 @@ func (*phi2) GetInferenceParameters() *model.PresetInferenceParam { PerGPUMemoryRequirement: "0Gi", // We run Phi using native vertical model parallel, no per GPU memory requirement. TorchRunParams: inference.DefaultAccelerateParams, ModelRunParams: phiRunParams, - DeploymentTimeout: time.Duration(30) * time.Minute, + ReadinessTimeout: time.Duration(30) * time.Minute, BaseCommand: baseCommandPresetPhi, Tag: PresetPhiTagMap["Phi2"], } - +} +func (*phi2) GetTuningParameters() *model.PresetParam { + return &model.PresetParam{ + ModelFamilyName: "Phi", + ImageAccessMode: string(kaitov1alpha1.ModelImageAccessModePublic), + DiskStorageRequirement: "50Gi", + GPUCountRequirement: "1", + TotalGPUMemoryRequirement: "16Gi", + PerGPUMemoryRequirement: "16Gi", // We run Phi using native vertical model parallel, no per GPU memory requirement. + // TorchRunParams: inference.DefaultAccelerateParams, + // ModelRunParams: phiRunParams, + ReadinessTimeout: time.Duration(30) * time.Minute, + BaseCommand: baseCommandPresetPhi, + Tag: PresetPhiTagMap["Phi2"], + } } func (*phi2) SupportDistributedInference() bool { return false } +func (*phi2) SupportTuning() bool { + return true +}