InferenceModel CRD - using the .metadata.name field instead of having .spec.modelName field
#872
nirrozenbaum
started this conversation in
General
Replies: 1 comment
-
|
as a reference, I'm adding the func (ds *datastore) ModelSetIfOlder(infModel *v1alpha2.InferenceModel) bool {
ds.poolAndModelsMu.Lock()
defer ds.poolAndModelsMu.Unlock()
// Check first if the existing model is older.
// One exception is if the incoming model object is the same, in which case, we should not
// check for creation timestamp since that means the object was re-created, and so we should override.
existing, exists := ds.models[infModel.Spec.ModelName]
if exists {
diffObj := infModel.Name != existing.Name || infModel.Namespace != existing.Namespace
if diffObj && existing.ObjectMeta.CreationTimestamp.Before(&infModel.ObjectMeta.CreationTimestamp) {
return false
}
}
// Set the model.
ds.models[infModel.Spec.ModelName] = infModel
return true
}
func (ds *datastore) ModelResync(ctx context.Context, c client.Client, modelName string) (bool, error) {
ds.poolAndModelsMu.Lock()
defer ds.poolAndModelsMu.Unlock()
var models v1alpha2.InferenceModelList
if err := c.List(ctx, &models, client.MatchingFields{ModelNameIndexKey: modelName}, client.InNamespace(ds.pool.Namespace)); err != nil {
return false, fmt.Errorf("listing models that match the modelName %s: %w", modelName, err)
}
if len(models.Items) == 0 {
// No other instances of InferenceModels with this ModelName exists.
return false, nil
}
var oldest *v1alpha2.InferenceModel
for i := range models.Items {
m := &models.Items[i]
if m.Spec.ModelName != modelName || // The index should filter those out, but just in case!
m.Spec.PoolRef.Name != v1alpha2.ObjectName(ds.pool.Name) || // We don't care about other pools, we could setup an index on this too!
!m.DeletionTimestamp.IsZero() { // ignore objects marked for deletion
continue
}
if oldest == nil || m.ObjectMeta.CreationTimestamp.Before(&oldest.ObjectMeta.CreationTimestamp) {
oldest = m
}
}
if oldest == nil {
return false, nil
}
ds.models[modelName] = oldest
return true, nil
} |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'd like to discuss the Pros/Cons of having the
.spec.modelNamefield in InferenceModel CRD vs using the.metadata.namefield.why should we have
.spec.modelNamefield in InferenceModel instead of usingmetadata.name?Model names may have characters disallowed by k8s naming.
More specifically, K8s
metadata.namefield must follow the DNS subdomain name format.downsides of using
.spec.modelNamefield:multiple
InferenceModelresources may have the same value of.spec.modeName(in the same pool) and uniqueness is not guaranteed. This opens the door for human errors and undesired issues/bugs.Current logic in EPP in case there are multiple
InferenceModelresources with the same.spec.modelNamewithin the same pool is the following:InferenceModelresource, EPP checks if an older one with the samespec.modelNameexists and keeps only the oldest in datastore.InferenceModelresource, EPP triggers a ModelResync and checks if other resources with the same.spec.modelNameexist in the pool namespace and if so, keeps in datastore the oldest (instead of the one that was deleted).The above behavior is not natural and not intuitive for any k8s user, since the following may happen:
InferenceModeland I expect a request to go to thetargetModelI defined, it may go to a different target (since there was an older model with the same.spec.modelName).InferenceModel, I'm expecting the resource to be deleted, meaning that sending a request to the same ModelName should return 404 (or some similar error) because model should not exist. As explain above, if a differentInferenceModelwith the same.spec.modelNameexist, requests will not fail (it will go the oldest existing model).InferenceModelwith a name that already exist and that it will be ignored (I cannot use it for serving). This is a very bad UX.As a creator of
InferenceModelresources, what UX would you prefer -create InferenceModel that is later ignored but you don't understand why and you need to inspect?
OR
get an appropriate error when creating the resource that the user facing name is taken?
The Alternative - using
metadata.nameas model name and remove thespec.modelNamefield.I must admit that personally it felt really weird to see a field
.spec.modelNamein a resource that is calledInferenceModelwhich can obviously use themetadata.name.As mentioned previously, using
metadata.namecomes with some restrictions on the name. Having said that, this CRD also has thetargetModelsfield which can be used to direct the request to any desired model (using equivalent names to current.spec.modelName). so if one wants to define a model with a model name that is disallowed by k8s restrictions, he can define inmetadata.namethe user facing model name and in thetargetModelfield the "real" model.This is aligned with GIE mental model that
modelNameis the user facing name and in some cases may be identical totargetModel, but if it doesn't, thentargetModelfield can be used.using
metadata.nameensures uniqueness ofmodelNamewithin the same namespace (therefore also within the same pool). This removes the cumbersome existing logic that handles creation of InferenceModel, and more specifically the deletion of InferenceModel, which currently triggers a ModelResync.While some people may say this is a downside (e.g., "what if I want to use the same user facing name in multiple pools on the same namespace?"), I actually think this is an advantage.
Not only this would improve the current UX (it's undesired to be able to create InferenceModel object that is later ignored), but also having uniqueness enforced on
modelNamefield opens the door for multi-pool implementation with the same UX as a single pool. I've prepared an initial design for this which can be shared in a different issue, but at the very high level - sincemodelNameis unique, when an incoming request arrives its pool can be identified uniquely and the request may be directed to the right pool.This cannot be done today (having multi-pool UX similar to a single pool) due to the fact that user facing model names are not unique (e.g., multiple pools on same namespace).
modelNameis guaranteed only within the same namespace (when using.metadata.name), so if one uses different pools on different namespaces, it is possible to use the same model name.To summarize this issue, I believe that using
.metadata.nameis much more intuitive, much more aligned with k8s principles, has a better UX, and keeps the code that handlesInferenceModelresources clean, simple and maintainable.Is it also aligned with GIE mental model of having a user facing model name and a target model name (which can optionally be identical to user facing model name).
it does introduce some restrictions on the USER FACING name only (NOT on target model name), but this is easily solved by using the
targetModelfield. I believe that in the majority of the user facing names selection, the names will anyway be in DNS format (I expect user facing names to be simple, descriptive, etc).would be more than happy to hear your thoughts on this -
cc: @kfswain @smarterclayton @ahg-g @robscott @danehans @shaneutt
Beta Was this translation helpful? Give feedback.
All reactions