diff --git a/README.md b/README.md index 0b8fb951340..99805d91a8a 100644 --- a/README.md +++ b/README.md @@ -159,10 +159,10 @@ kubectl apply -k "github.com/kubeflow/katib.git/manifests/v1beta1/installs/katib ## Release Version -For the specific Katib release (for example `v0.11.1`) run this command: +For the specific Katib release (for example `v0.12.0`) run this command: ``` -kubectl apply -k "github.com/kubeflow/katib.git/manifests/v1beta1/installs/katib-standalone?ref=v0.11.1" +kubectl apply -k "github.com/kubeflow/katib.git/manifests/v1beta1/installs/katib-standalone?ref=v0.12.0" ``` Make sure that all Katib components are running: diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 73bb2f8b89b..052fee5e79f 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -122,10 +122,6 @@ You can find the `cert-generator` source code [here](../cmd/cert-generator/v1bet Please see [new-algorithm-service.md](./new-algorithm-service.md). -## Algorithm settings documentation - -Please see [algorithm-settings.md](./algorithm-settings.md). - ## Katib UI documentation Please see [Katib UI README](https://github.com/kubeflow/katib/tree/master/pkg/ui/v1beta1). diff --git a/pkg/apis/manager/README.md b/pkg/apis/manager/README.md index 755bf21fe2d..b7060cb770a 100644 --- a/pkg/apis/manager/README.md +++ b/pkg/apis/manager/README.md @@ -22,12 +22,3 @@ generate the API docs from `api.proto`. Run `build.sh` to update every file from `api.proto` and generate the docs: - [v1beta1/build.sh](./v1beta1/build.sh) for v1beta1. - -After running `build.sh`, follow these steps to update the docs: - -1. Copy the updated content from your generated file - `pkg/apis/manager//gen-doc/api.md` to the doc page in the - `kubeflow/website` repository: - `kubeflow/website/blob/master/content/docs/reference/katib//katib.md`. -1. Create a PR in the `kubeflow/website` repository. - (See [example PR](https://github.com/kubeflow/website/pull/1531).) diff --git a/pkg/apis/manager/v1beta1/api.pb.go b/pkg/apis/manager/v1beta1/api.pb.go index 31c7c1d449b..576cf00f593 100644 --- a/pkg/apis/manager/v1beta1/api.pb.go +++ b/pkg/apis/manager/v1beta1/api.pb.go @@ -41,6 +41,8 @@ It has these top-level messages: GetEarlyStoppingRulesRequest GetEarlyStoppingRulesReply EarlyStoppingRule + ValidateEarlyStoppingSettingsRequest + ValidateEarlyStoppingSettingsReply SetTrialStatusRequest SetTrialStatusReply */ @@ -1214,6 +1216,36 @@ func (m *EarlyStoppingRule) GetStartStep() int32 { return 0 } +type ValidateEarlyStoppingSettingsRequest struct { + EarlyStopping *EarlyStoppingSpec `protobuf:"bytes,1,opt,name=early_stopping,json=earlyStopping" json:"early_stopping,omitempty"` +} + +func (m *ValidateEarlyStoppingSettingsRequest) Reset() { *m = ValidateEarlyStoppingSettingsRequest{} } +func (m *ValidateEarlyStoppingSettingsRequest) String() string { return proto.CompactTextString(m) } +func (*ValidateEarlyStoppingSettingsRequest) ProtoMessage() {} +func (*ValidateEarlyStoppingSettingsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{33} +} + +func (m *ValidateEarlyStoppingSettingsRequest) GetEarlyStopping() *EarlyStoppingSpec { + if m != nil { + return m.EarlyStopping + } + return nil +} + +// * +// Return INVALID_ARGUMENT Error if Early Stopping Settings are not Valid +type ValidateEarlyStoppingSettingsReply struct { +} + +func (m *ValidateEarlyStoppingSettingsReply) Reset() { *m = ValidateEarlyStoppingSettingsReply{} } +func (m *ValidateEarlyStoppingSettingsReply) String() string { return proto.CompactTextString(m) } +func (*ValidateEarlyStoppingSettingsReply) ProtoMessage() {} +func (*ValidateEarlyStoppingSettingsReply) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{34} +} + type SetTrialStatusRequest struct { TrialName string `protobuf:"bytes,1,opt,name=trial_name,json=trialName" json:"trial_name,omitempty"` } @@ -1221,7 +1253,7 @@ type SetTrialStatusRequest struct { func (m *SetTrialStatusRequest) Reset() { *m = SetTrialStatusRequest{} } func (m *SetTrialStatusRequest) String() string { return proto.CompactTextString(m) } func (*SetTrialStatusRequest) ProtoMessage() {} -func (*SetTrialStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } +func (*SetTrialStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } func (m *SetTrialStatusRequest) GetTrialName() string { if m != nil { @@ -1236,7 +1268,7 @@ type SetTrialStatusReply struct { func (m *SetTrialStatusReply) Reset() { *m = SetTrialStatusReply{} } func (m *SetTrialStatusReply) String() string { return proto.CompactTextString(m) } func (*SetTrialStatusReply) ProtoMessage() {} -func (*SetTrialStatusReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } +func (*SetTrialStatusReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } func init() { proto.RegisterType((*Experiment)(nil), "api.v1.beta1.Experiment") @@ -1277,6 +1309,8 @@ func init() { proto.RegisterType((*GetEarlyStoppingRulesRequest)(nil), "api.v1.beta1.GetEarlyStoppingRulesRequest") proto.RegisterType((*GetEarlyStoppingRulesReply)(nil), "api.v1.beta1.GetEarlyStoppingRulesReply") proto.RegisterType((*EarlyStoppingRule)(nil), "api.v1.beta1.EarlyStoppingRule") + proto.RegisterType((*ValidateEarlyStoppingSettingsRequest)(nil), "api.v1.beta1.ValidateEarlyStoppingSettingsRequest") + proto.RegisterType((*ValidateEarlyStoppingSettingsReply)(nil), "api.v1.beta1.ValidateEarlyStoppingSettingsReply") proto.RegisterType((*SetTrialStatusRequest)(nil), "api.v1.beta1.SetTrialStatusRequest") proto.RegisterType((*SetTrialStatusReply)(nil), "api.v1.beta1.SetTrialStatusReply") proto.RegisterEnum("api.v1.beta1.ParameterType", ParameterType_name, ParameterType_value) @@ -1543,6 +1577,7 @@ var _Suggestion_serviceDesc = grpc.ServiceDesc{ type EarlyStoppingClient interface { GetEarlyStoppingRules(ctx context.Context, in *GetEarlyStoppingRulesRequest, opts ...grpc.CallOption) (*GetEarlyStoppingRulesReply, error) SetTrialStatus(ctx context.Context, in *SetTrialStatusRequest, opts ...grpc.CallOption) (*SetTrialStatusReply, error) + ValidateEarlyStoppingSettings(ctx context.Context, in *ValidateEarlyStoppingSettingsRequest, opts ...grpc.CallOption) (*ValidateEarlyStoppingSettingsReply, error) } type earlyStoppingClient struct { @@ -1571,11 +1606,21 @@ func (c *earlyStoppingClient) SetTrialStatus(ctx context.Context, in *SetTrialSt return out, nil } +func (c *earlyStoppingClient) ValidateEarlyStoppingSettings(ctx context.Context, in *ValidateEarlyStoppingSettingsRequest, opts ...grpc.CallOption) (*ValidateEarlyStoppingSettingsReply, error) { + out := new(ValidateEarlyStoppingSettingsReply) + err := grpc.Invoke(ctx, "/api.v1.beta1.EarlyStopping/ValidateEarlyStoppingSettings", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for EarlyStopping service type EarlyStoppingServer interface { GetEarlyStoppingRules(context.Context, *GetEarlyStoppingRulesRequest) (*GetEarlyStoppingRulesReply, error) SetTrialStatus(context.Context, *SetTrialStatusRequest) (*SetTrialStatusReply, error) + ValidateEarlyStoppingSettings(context.Context, *ValidateEarlyStoppingSettingsRequest) (*ValidateEarlyStoppingSettingsReply, error) } func RegisterEarlyStoppingServer(s *grpc.Server, srv EarlyStoppingServer) { @@ -1618,6 +1663,24 @@ func _EarlyStopping_SetTrialStatus_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _EarlyStopping_ValidateEarlyStoppingSettings_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateEarlyStoppingSettingsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EarlyStoppingServer).ValidateEarlyStoppingSettings(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.v1.beta1.EarlyStopping/ValidateEarlyStoppingSettings", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EarlyStoppingServer).ValidateEarlyStoppingSettings(ctx, req.(*ValidateEarlyStoppingSettingsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _EarlyStopping_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.v1.beta1.EarlyStopping", HandlerType: (*EarlyStoppingServer)(nil), @@ -1630,6 +1693,10 @@ var _EarlyStopping_serviceDesc = grpc.ServiceDesc{ MethodName: "SetTrialStatus", Handler: _EarlyStopping_SetTrialStatus_Handler, }, + { + MethodName: "ValidateEarlyStoppingSettings", + Handler: _EarlyStopping_ValidateEarlyStoppingSettings_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "api.proto", @@ -1638,120 +1705,122 @@ var _EarlyStopping_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("api.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 1826 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x72, 0x1b, 0x49, - 0x15, 0xce, 0xe8, 0xc7, 0xce, 0x1c, 0x59, 0xf2, 0xa4, 0x2d, 0x67, 0x65, 0x67, 0xd9, 0x38, 0x03, - 0x64, 0xb3, 0x49, 0x4a, 0x24, 0x06, 0x52, 0xa1, 0x36, 0x14, 0xc8, 0xd2, 0xc4, 0xa5, 0xac, 0x2c, - 0x39, 0x2d, 0x19, 0xb2, 0x2c, 0x55, 0x53, 0x6d, 0xa9, 0xa3, 0x9d, 0x30, 0x7f, 0xcc, 0xb4, 0x52, - 0x11, 0x5c, 0x52, 0xcb, 0x1d, 0x17, 0x54, 0x71, 0xc5, 0x2b, 0x70, 0xc9, 0x0b, 0x70, 0xc5, 0x03, - 0x50, 0x5c, 0x70, 0xcb, 0x03, 0xf0, 0x0e, 0x54, 0xf7, 0x8c, 0xe6, 0x4f, 0x23, 0xc5, 0xf6, 0xc2, - 0xde, 0x4d, 0x9f, 0xf3, 0x9d, 0xee, 0xf3, 0xd3, 0xe7, 0xa7, 0x07, 0x64, 0xe2, 0x1a, 0x4d, 0xd7, - 0x73, 0x98, 0x83, 0xb6, 0xf8, 0xe7, 0xdb, 0xc7, 0xcd, 0x73, 0xca, 0xc8, 0x63, 0x15, 0x03, 0x68, - 0xef, 0x5c, 0xea, 0x19, 0x16, 0xb5, 0x19, 0x42, 0x50, 0xb2, 0x89, 0x45, 0x1b, 0xd2, 0x81, 0x74, - 0x4f, 0xc6, 0xe2, 0x1b, 0x3d, 0x82, 0x92, 0xef, 0xd2, 0x71, 0xa3, 0x70, 0x20, 0xdd, 0xab, 0x1c, - 0x7e, 0xd8, 0x4c, 0x8a, 0x37, 0x63, 0xd9, 0xa1, 0x4b, 0xc7, 0x58, 0x20, 0xd5, 0xaf, 0x4a, 0x50, - 0x4b, 0x33, 0xd0, 0x08, 0xb6, 0x5d, 0xe2, 0x11, 0x8b, 0x32, 0xea, 0xe9, 0x1c, 0xe4, 0x8b, 0x33, - 0x2a, 0x87, 0x0f, 0xd6, 0xed, 0xd7, 0x3c, 0x5d, 0xc8, 0xf0, 0x95, 0x8f, 0x6b, 0x6e, 0x6a, 0x8d, - 0x7e, 0x04, 0xb2, 0x73, 0xfe, 0x86, 0x8e, 0x99, 0xf1, 0x96, 0x86, 0xfa, 0xdd, 0x4a, 0xef, 0x37, - 0x58, 0xb0, 0x85, 0x7a, 0x31, 0x9a, 0x8b, 0x12, 0x73, 0xea, 0x78, 0x06, 0xfb, 0xd2, 0x6a, 0x14, - 0xf3, 0x44, 0x5b, 0x0b, 0x76, 0x20, 0x1a, 0xa1, 0xd1, 0x73, 0xa8, 0x51, 0xe2, 0x99, 0x73, 0xdd, - 0x67, 0x8e, 0xeb, 0x1a, 0xf6, 0xb4, 0x51, 0x12, 0xf2, 0xb7, 0x33, 0xa6, 0x70, 0xcc, 0x30, 0x84, - 0x88, 0x3d, 0xaa, 0x34, 0x49, 0x42, 0x8f, 0xa0, 0xce, 0xed, 0x31, 0x4d, 0x6a, 0xea, 0xcc, 0x33, - 0x88, 0xa9, 0x8f, 0x9d, 0x99, 0xcd, 0x1a, 0xe5, 0x03, 0xe9, 0x5e, 0x19, 0xa3, 0x05, 0x6f, 0xc4, - 0x59, 0x6d, 0xce, 0x41, 0x77, 0x61, 0xdb, 0x22, 0xef, 0x52, 0xe0, 0x0d, 0x01, 0xae, 0x5a, 0xe4, - 0x5d, 0x02, 0xf7, 0x04, 0xc0, 0x26, 0xbe, 0x3e, 0x76, 0xec, 0xd7, 0xc6, 0xb4, 0xb1, 0x29, 0xb4, - 0xfb, 0x20, 0xad, 0x5d, 0x9f, 0xf8, 0x6d, 0xc1, 0xc6, 0xb2, 0xbd, 0xf8, 0xdc, 0x3f, 0x81, 0x5a, - 0xda, 0xe3, 0xe8, 0x53, 0x80, 0xc8, 0xe7, 0x3c, 0x64, 0xc5, 0x65, 0x3f, 0xa5, 0x24, 0x70, 0x02, - 0xae, 0xfe, 0x45, 0x82, 0x6a, 0x8a, 0x9b, 0x7b, 0xbf, 0x8e, 0x20, 0x0e, 0xab, 0xce, 0xe6, 0x6e, - 0x10, 0xc9, 0xda, 0xca, 0x63, 0x46, 0x73, 0x97, 0xe2, 0xaa, 0x9b, 0x5c, 0xf2, 0x3d, 0x5e, 0x53, - 0xe2, 0x1b, 0xe7, 0x26, 0xd5, 0x7d, 0x97, 0x8c, 0x69, 0x7e, 0x48, 0x9f, 0x87, 0x98, 0x21, 0x87, - 0xe0, 0xea, 0xeb, 0xe4, 0x52, 0xfd, 0x02, 0xaa, 0x29, 0x3e, 0x52, 0xa0, 0x68, 0x91, 0x77, 0xa1, - 0xae, 0xfc, 0x53, 0x50, 0x0c, 0x5b, 0xe8, 0xc7, 0x29, 0x86, 0xcd, 0x0d, 0x32, 0x0d, 0x9f, 0x35, - 0x8a, 0x07, 0x45, 0x6e, 0x10, 0xff, 0xe6, 0x34, 0x9f, 0x51, 0x57, 0xdc, 0x0a, 0x19, 0x8b, 0x6f, - 0xf5, 0x6f, 0x12, 0x54, 0x53, 0x77, 0x11, 0x7d, 0x0f, 0x4a, 0xc2, 0x58, 0x29, 0xcf, 0xd8, 0x08, - 0x2a, 0x8c, 0x15, 0x40, 0xbe, 0xed, 0xd4, 0x21, 0xa6, 0x38, 0x5d, 0xc2, 0xe2, 0x1b, 0x1d, 0xc2, - 0x6e, 0x74, 0xa5, 0x75, 0x8b, 0x32, 0xcf, 0x18, 0xeb, 0xc2, 0xc1, 0x45, 0x71, 0xf6, 0x4e, 0xc4, - 0x3c, 0x11, 0xbc, 0x3e, 0xf7, 0xf7, 0x13, 0xf8, 0x80, 0x4c, 0x26, 0x06, 0x33, 0x1c, 0x9b, 0x98, - 0x49, 0x21, 0xbf, 0x51, 0x12, 0x56, 0xec, 0xc6, 0xec, 0x58, 0xcc, 0x57, 0xbf, 0x92, 0xa0, 0x9a, - 0xca, 0x09, 0xf4, 0x5d, 0xa8, 0x45, 0x59, 0xa1, 0x27, 0xe2, 0x5a, 0x8d, 0xa8, 0xe2, 0xc0, 0x13, - 0x40, 0x31, 0xcc, 0xa7, 0x8c, 0x19, 0xf6, 0xd4, 0x6f, 0x14, 0xc4, 0x5d, 0xfa, 0x68, 0x55, 0xce, - 0x05, 0x30, 0x7c, 0x83, 0x64, 0x28, 0xbe, 0xfa, 0x0c, 0x94, 0x2c, 0x2c, 0xf7, 0x5e, 0xd5, 0xa1, - 0xfc, 0x96, 0x98, 0x33, 0x1a, 0x86, 0x2b, 0x58, 0xa8, 0x7f, 0x90, 0xe0, 0xc6, 0x52, 0x66, 0x5e, - 0xd4, 0x92, 0x97, 0x6b, 0x2c, 0x51, 0xd7, 0x65, 0xff, 0x6a, 0x6b, 0x7e, 0x0a, 0xf5, 0x3c, 0xe8, - 0x25, 0x2c, 0xfa, 0x87, 0x04, 0x72, 0x94, 0xcd, 0xe8, 0x19, 0x6c, 0x4d, 0x3d, 0xe2, 0x7e, 0xb9, - 0x48, 0xfe, 0xa0, 0xca, 0xee, 0xa5, 0x95, 0x3b, 0xe6, 0x88, 0x30, 0xfd, 0x2b, 0xd3, 0x78, 0x81, - 0x8e, 0x00, 0x1c, 0x97, 0x7a, 0x84, 0x47, 0xdf, 0x0f, 0x2b, 0xaa, 0xba, 0xa2, 0x70, 0x34, 0x07, - 0x11, 0x12, 0x27, 0xa4, 0xf6, 0xdb, 0x00, 0x31, 0x07, 0xfd, 0x10, 0xe4, 0x88, 0x17, 0xd6, 0x8f, - 0x4c, 0x25, 0x8a, 0xc0, 0x38, 0x46, 0xaa, 0x2e, 0x54, 0x12, 0x4a, 0xa2, 0x6f, 0x01, 0xd8, 0x33, - 0x4b, 0x37, 0xc9, 0x3c, 0x28, 0x43, 0xbc, 0xe6, 0xc9, 0xf6, 0xcc, 0xea, 0x09, 0x02, 0xba, 0x0d, - 0x15, 0xc3, 0x76, 0x67, 0x4c, 0xf7, 0x8d, 0xdf, 0xd0, 0x20, 0x20, 0x65, 0x0c, 0x82, 0x34, 0xe4, - 0x14, 0x74, 0x07, 0xb6, 0x9c, 0x19, 0x8b, 0x11, 0x45, 0x81, 0xa8, 0x04, 0x34, 0x01, 0x11, 0x6e, - 0x8c, 0x54, 0xe1, 0x17, 0x22, 0x52, 0x46, 0x8f, 0xf2, 0x54, 0xc6, 0xd5, 0x88, 0x2a, 0xea, 0xce, - 0x60, 0xb9, 0xad, 0x05, 0x4e, 0xbb, 0xbb, 0xc2, 0xc6, 0xf7, 0x74, 0xb4, 0xff, 0x75, 0x05, 0xfe, - 0x2d, 0x94, 0x45, 0x5b, 0xc8, 0xbd, 0x4e, 0x0f, 0x52, 0x8d, 0x3d, 0x13, 0x15, 0x21, 0x16, 0xf7, - 0x74, 0xf4, 0x18, 0x36, 0x7c, 0x46, 0xd8, 0xcc, 0x0f, 0x2b, 0xeb, 0x5e, 0x1e, 0x5c, 0x00, 0x70, - 0x08, 0x54, 0x7f, 0x5f, 0x00, 0x39, 0xda, 0xe6, 0xeb, 0xf4, 0x6a, 0x02, 0xbb, 0xb1, 0x97, 0x89, - 0xef, 0x1b, 0x53, 0x9b, 0x4f, 0x08, 0x0b, 0x55, 0x1e, 0xae, 0xd0, 0x3c, 0xf6, 0x4b, 0x2b, 0x96, - 0xc1, 0x75, 0x37, 0x87, 0xba, 0xff, 0x05, 0xd4, 0xf3, 0xd0, 0xa8, 0x0d, 0x95, 0xe4, 0x81, 0x81, - 0xfb, 0xef, 0xac, 0x70, 0x7f, 0x2c, 0x88, 0x93, 0x52, 0xea, 0x4f, 0x60, 0x27, 0x07, 0x73, 0x89, - 0x14, 0xff, 0x67, 0x01, 0x2a, 0x09, 0x0f, 0xf3, 0x74, 0xf0, 0x19, 0xf1, 0x98, 0xce, 0x8c, 0x48, - 0x5e, 0x16, 0x94, 0x91, 0x61, 0x51, 0xf4, 0x31, 0x6c, 0x8f, 0x1d, 0xcb, 0x35, 0x69, 0x70, 0x7b, - 0x39, 0x26, 0xd8, 0xae, 0x16, 0x93, 0x05, 0xf0, 0x05, 0xc8, 0x63, 0xc7, 0x0e, 0x8a, 0xbd, 0x70, - 0x66, 0x2d, 0xdf, 0x99, 0xe2, 0xd4, 0x66, 0x38, 0x60, 0x84, 0x78, 0xd1, 0x99, 0x62, 0x71, 0xf4, - 0x29, 0x54, 0x9c, 0x73, 0x9f, 0x7a, 0x6f, 0x83, 0x54, 0x2f, 0xe5, 0xdd, 0x92, 0x41, 0x0c, 0xc0, - 0x49, 0xb4, 0xca, 0x00, 0x2d, 0xef, 0x8e, 0x2a, 0xb0, 0xd9, 0xc6, 0x5a, 0x6b, 0xa4, 0x75, 0x94, - 0x6b, 0x7c, 0x81, 0xcf, 0xfa, 0xfd, 0x6e, 0xff, 0x58, 0x91, 0x50, 0x15, 0xe4, 0xe1, 0x59, 0xbb, - 0xad, 0x69, 0x1d, 0xad, 0xa3, 0x14, 0x10, 0xc0, 0xc6, 0x67, 0xdd, 0x5e, 0x4f, 0xeb, 0x28, 0x45, - 0xfe, 0xfd, 0xbc, 0xd5, 0xe5, 0xdf, 0x25, 0xa4, 0xc0, 0x96, 0xd6, 0xc2, 0xbd, 0xcf, 0x87, 0xa3, - 0xc1, 0xe9, 0xa9, 0xd6, 0x51, 0xca, 0x7c, 0x97, 0xb3, 0xfe, 0x67, 0xfd, 0xc1, 0xcf, 0xfb, 0xca, - 0x86, 0xfa, 0x63, 0xa8, 0x24, 0x34, 0x42, 0x4d, 0xd8, 0x0c, 0xba, 0xe1, 0x22, 0xce, 0xf5, 0xb4, - 0xf6, 0x41, 0x33, 0xc4, 0x0b, 0x90, 0x7a, 0x08, 0x1b, 0x01, 0xe9, 0x12, 0x91, 0xfc, 0x9d, 0x04, - 0xb7, 0x30, 0x75, 0x1d, 0x8f, 0x25, 0x4e, 0xee, 0x39, 0x53, 0x4c, 0x7f, 0x3d, 0xa3, 0x3e, 0xe3, - 0x91, 0x0d, 0xa6, 0xbb, 0xc4, 0x7e, 0xb2, 0xa0, 0x88, 0x06, 0xa4, 0xc1, 0x76, 0xc2, 0x6d, 0xba, - 0xe9, 0x4c, 0xf3, 0xc7, 0xf2, 0xcc, 0xe6, 0x35, 0x27, 0xb5, 0x56, 0x6f, 0xc1, 0x5e, 0xbe, 0x12, - 0xae, 0x39, 0x57, 0x5f, 0x40, 0x2d, 0x4d, 0x46, 0x4f, 0xa1, 0x12, 0x8e, 0x09, 0xa6, 0x33, 0xf5, - 0xf3, 0xab, 0x78, 0xe0, 0x09, 0xbe, 0x09, 0x58, 0x8b, 0x4f, 0x5f, 0x7d, 0x05, 0x72, 0xc4, 0x10, - 0xb6, 0x19, 0x16, 0xd5, 0x7d, 0x46, 0x2c, 0x37, 0xb2, 0xcd, 0xb0, 0xe8, 0x90, 0x13, 0xd0, 0x43, - 0xd8, 0x08, 0x24, 0x43, 0x93, 0xf2, 0xbd, 0x1f, 0x62, 0xd4, 0x3f, 0x49, 0xd0, 0x38, 0xa6, 0x57, - 0xf3, 0xe2, 0xed, 0xc8, 0x1e, 0xc1, 0x0f, 0x02, 0x14, 0xaa, 0x2d, 0x00, 0xe9, 0xfc, 0x2a, 0x66, - 0xf3, 0x6b, 0x0f, 0xae, 0x53, 0x7b, 0x12, 0x30, 0x83, 0x21, 0x6f, 0x93, 0xda, 0x13, 0xce, 0x52, - 0x75, 0xb8, 0x99, 0xa3, 0x95, 0x6b, 0xce, 0xf3, 0x42, 0x27, 0x5d, 0x21, 0x74, 0xcf, 0xe0, 0x56, - 0x87, 0x9a, 0x94, 0xd1, 0xab, 0x58, 0xce, 0x03, 0x9f, 0x2f, 0xcd, 0x03, 0xff, 0xc7, 0x02, 0xec, - 0x1e, 0x53, 0x36, 0x9c, 0x4d, 0xa7, 0xd4, 0x0f, 0xfa, 0x7a, 0xb8, 0xeb, 0x53, 0x00, 0x1a, 0x3d, - 0xcc, 0x42, 0xb5, 0x1b, 0xab, 0x1e, 0x6e, 0x38, 0x81, 0x45, 0x0f, 0x60, 0x43, 0x9c, 0xbe, 0x98, - 0x92, 0x76, 0x72, 0xca, 0x0b, 0x0e, 0x21, 0xe8, 0x13, 0xa8, 0x79, 0xc1, 0x89, 0xba, 0x3d, 0xb3, - 0xce, 0xa9, 0x27, 0x5c, 0x5f, 0x3e, 0x2a, 0x34, 0x24, 0x5c, 0x0d, 0x39, 0x7d, 0xc1, 0x40, 0x3f, - 0x80, 0x9b, 0xe3, 0x99, 0xe7, 0x51, 0x9b, 0xe9, 0x19, 0x91, 0x92, 0x18, 0x0e, 0xea, 0x21, 0x17, - 0xa7, 0xa4, 0x1e, 0x41, 0x9d, 0x39, 0x8c, 0x98, 0x59, 0x99, 0xf0, 0xc5, 0x25, 0x78, 0x29, 0x09, - 0xf5, 0x3f, 0x05, 0xd8, 0xc9, 0xfa, 0x84, 0x47, 0xf3, 0x57, 0xab, 0x5a, 0x52, 0x90, 0x1c, 0x4f, - 0x32, 0xf3, 0xd6, 0xf2, 0x0e, 0x97, 0x68, 0x4e, 0xe9, 0xb7, 0x6a, 0xe1, 0x52, 0x6f, 0xd5, 0x97, - 0x50, 0x4f, 0xbf, 0x55, 0x75, 0x6f, 0x66, 0x86, 0x03, 0xd0, 0xfa, 0x17, 0x2b, 0x9e, 0x99, 0x14, - 0x23, 0x9a, 0x25, 0xfd, 0x9f, 0x5b, 0xe5, 0x2f, 0xe1, 0xe0, 0x67, 0xc4, 0x34, 0x26, 0x84, 0xd1, - 0xec, 0x90, 0xff, 0xf5, 0x6f, 0xa3, 0x7a, 0x00, 0x1f, 0xad, 0xd9, 0x9d, 0xe7, 0xc0, 0x5f, 0x25, - 0xf8, 0xf0, 0x98, 0xb2, 0x25, 0x4f, 0x7c, 0xd3, 0xa9, 0xf0, 0x10, 0xd0, 0xe4, 0x5c, 0xb7, 0x88, - 0x4d, 0xa6, 0xfc, 0x82, 0x4d, 0x26, 0x1e, 0xf5, 0xfd, 0xb0, 0x12, 0x29, 0x93, 0xf3, 0x93, 0x80, - 0xd1, 0x0a, 0xe8, 0xaa, 0x03, 0xfb, 0x2b, 0x94, 0xe6, 0x77, 0x75, 0xd5, 0x1d, 0x90, 0xae, 0x7c, - 0x07, 0xd4, 0x3f, 0x67, 0x5f, 0x51, 0x9c, 0x7c, 0xf1, 0x36, 0x88, 0x9e, 0x01, 0xf0, 0x51, 0x84, - 0x78, 0x86, 0x1f, 0x4d, 0x1e, 0x99, 0x3a, 0xd8, 0x8e, 0xf8, 0x62, 0xd2, 0x48, 0xe0, 0xe3, 0xf2, - 0x1c, 0x3d, 0xb3, 0xcb, 0x61, 0x79, 0x1e, 0xf2, 0xb7, 0xf6, 0x13, 0xd8, 0x1d, 0x52, 0x96, 0x9c, - 0x48, 0x2f, 0x56, 0x1c, 0x77, 0x61, 0x27, 0x2b, 0xe7, 0x9a, 0xf3, 0xfb, 0x67, 0x89, 0x9f, 0x18, - 0x62, 0x2c, 0x51, 0x60, 0x2b, 0x9c, 0x21, 0xf4, 0xd1, 0xe7, 0xa7, 0x9a, 0x72, 0x8d, 0xcf, 0x1c, - 0x9d, 0xc1, 0xd9, 0x51, 0x4f, 0x53, 0x24, 0xb4, 0x09, 0xc5, 0x6e, 0x7f, 0xa4, 0x14, 0xd0, 0x16, - 0x5c, 0xef, 0x74, 0x87, 0x6d, 0xac, 0x8d, 0x34, 0xa5, 0x88, 0xb6, 0xa1, 0xd2, 0x6e, 0x8d, 0xb4, - 0xe3, 0x01, 0xee, 0xb6, 0x5b, 0x3d, 0xa5, 0x74, 0xff, 0x69, 0xe2, 0x87, 0xc0, 0x62, 0xda, 0x59, - 0x8c, 0x26, 0xd7, 0xb8, 0xf0, 0x49, 0xb7, 0xdf, 0x3d, 0xe9, 0xfe, 0x82, 0xef, 0xc9, 0x57, 0xad, - 0x57, 0xc1, 0xaa, 0x70, 0xff, 0x05, 0xd4, 0xd2, 0xce, 0x41, 0x37, 0x01, 0x2d, 0x34, 0x6a, 0x0f, - 0x4e, 0x4e, 0x5b, 0xb8, 0x3b, 0x1c, 0xf0, 0x5d, 0x64, 0x28, 0x6b, 0x2f, 0xcf, 0x5a, 0x3d, 0x45, - 0x42, 0xd7, 0xa1, 0xd4, 0xd3, 0x86, 0x43, 0xa5, 0xc0, 0xcf, 0x39, 0x16, 0x53, 0x15, 0x56, 0x8a, - 0x87, 0x7f, 0x2f, 0x80, 0xdc, 0x39, 0x0a, 0xaf, 0x13, 0x7a, 0x03, 0xf5, 0xbc, 0xb9, 0x00, 0x7d, - 0x92, 0x0e, 0xcd, 0x9a, 0x01, 0x66, 0xff, 0xe3, 0x8b, 0x40, 0xf9, 0xad, 0x24, 0x70, 0x63, 0xa9, - 0x53, 0xa2, 0xbb, 0x4b, 0x75, 0x33, 0xff, 0x94, 0xef, 0xbc, 0x17, 0xc7, 0x8f, 0x78, 0x03, 0xf5, - 0xbc, 0x6e, 0x97, 0x35, 0x67, 0x4d, 0x3f, 0xcd, 0x9a, 0xb3, 0xb2, 0x79, 0x1e, 0xfe, 0x5b, 0x02, - 0x88, 0x6b, 0x3c, 0x7a, 0x05, 0xb5, 0x74, 0xd1, 0x47, 0xdf, 0x5e, 0xdf, 0x12, 0x82, 0xe3, 0xee, - 0xbc, 0xb7, 0x6f, 0xa0, 0x39, 0xec, 0xad, 0xac, 0x61, 0xa8, 0x99, 0x96, 0x7f, 0x5f, 0x29, 0xdd, - 0x7f, 0x78, 0x61, 0x3c, 0xb7, 0xf1, 0x5f, 0x12, 0x54, 0x53, 0x59, 0x8f, 0x2c, 0x31, 0x31, 0x2c, - 0x17, 0x1e, 0x74, 0x7f, 0xc9, 0x90, 0x95, 0x25, 0x75, 0xff, 0xde, 0x85, 0xb0, 0xdc, 0xf6, 0x57, - 0x50, 0x4b, 0x67, 0x68, 0xd6, 0xab, 0xb9, 0x79, 0x9f, 0xf5, 0x6a, 0x4e, 0x92, 0x9f, 0x6f, 0x88, - 0x7f, 0xe3, 0xdf, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf7, 0xad, 0xf8, 0x9d, 0x28, 0x17, - 0x00, 0x00, + // 1872 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xdb, 0x72, 0x1b, 0x49, + 0x19, 0xce, 0xe8, 0x60, 0x47, 0xbf, 0x2c, 0x79, 0xd2, 0x96, 0xb3, 0xb2, 0xb3, 0xbb, 0x71, 0x86, + 0x90, 0xcd, 0x26, 0x29, 0x91, 0x18, 0x48, 0x85, 0xda, 0x50, 0x20, 0x4b, 0x13, 0x97, 0xb2, 0xb2, + 0xe4, 0xb4, 0x64, 0xc8, 0xb2, 0x54, 0x4d, 0xb5, 0xa5, 0x8e, 0x76, 0xc2, 0x9c, 0x98, 0x69, 0xa5, + 0x2c, 0xb8, 0xa4, 0xc2, 0x1d, 0x17, 0x54, 0x71, 0xc5, 0x2b, 0x70, 0xc9, 0x0b, 0x70, 0xc5, 0x03, + 0x50, 0x3c, 0x00, 0x3c, 0x00, 0xef, 0x40, 0x75, 0xcf, 0x68, 0x4e, 0x1a, 0xc9, 0x87, 0xc0, 0xde, + 0x4d, 0xff, 0xff, 0xf7, 0x77, 0xff, 0x87, 0xfe, 0x0f, 0x2d, 0x41, 0x89, 0x38, 0x7a, 0xc3, 0x71, + 0x6d, 0x66, 0xa3, 0x0d, 0xfe, 0xf9, 0xee, 0x49, 0xe3, 0x94, 0x32, 0xf2, 0x44, 0xc1, 0x00, 0xea, + 0x99, 0x43, 0x5d, 0xdd, 0xa4, 0x16, 0x43, 0x08, 0x0a, 0x16, 0x31, 0x69, 0x5d, 0xda, 0x93, 0xee, + 0x97, 0xb0, 0xf8, 0x46, 0x8f, 0xa1, 0xe0, 0x39, 0x74, 0x54, 0xcf, 0xed, 0x49, 0xf7, 0xcb, 0xfb, + 0x1f, 0x37, 0xe2, 0xe2, 0x8d, 0x48, 0x76, 0xe0, 0xd0, 0x11, 0x16, 0x48, 0xe5, 0x7d, 0x01, 0xaa, + 0x49, 0x06, 0x1a, 0xc2, 0xa6, 0x43, 0x5c, 0x62, 0x52, 0x46, 0x5d, 0x8d, 0x83, 0x3c, 0x71, 0x46, + 0x79, 0xff, 0xe1, 0xaa, 0xfd, 0x1a, 0xc7, 0x73, 0x19, 0xbe, 0xf2, 0x70, 0xd5, 0x49, 0xac, 0xd1, + 0x8f, 0xa0, 0x64, 0x9f, 0xbe, 0xa5, 0x23, 0xa6, 0xbf, 0xa3, 0x81, 0x7e, 0xb7, 0x92, 0xfb, 0xf5, + 0xe7, 0x6c, 0xa1, 0x5e, 0x84, 0xe6, 0xa2, 0xc4, 0x98, 0xd8, 0xae, 0xce, 0xbe, 0x31, 0xeb, 0xf9, + 0x2c, 0xd1, 0xe6, 0x9c, 0xed, 0x8b, 0x86, 0x68, 0xf4, 0x02, 0xaa, 0x94, 0xb8, 0xc6, 0x4c, 0xf3, + 0x98, 0xed, 0x38, 0xba, 0x35, 0xa9, 0x17, 0x84, 0xfc, 0xed, 0x94, 0x29, 0x1c, 0x33, 0x08, 0x20, + 0x62, 0x8f, 0x0a, 0x8d, 0x93, 0xd0, 0x63, 0xa8, 0x71, 0x7b, 0x0c, 0x83, 0x1a, 0x1a, 0x73, 0x75, + 0x62, 0x68, 0x23, 0x7b, 0x6a, 0xb1, 0x7a, 0x71, 0x4f, 0xba, 0x5f, 0xc4, 0x68, 0xce, 0x1b, 0x72, + 0x56, 0x8b, 0x73, 0xd0, 0x3d, 0xd8, 0x34, 0xc9, 0x59, 0x02, 0xbc, 0x26, 0xc0, 0x15, 0x93, 0x9c, + 0xc5, 0x70, 0x4f, 0x01, 0x2c, 0xe2, 0x69, 0x23, 0xdb, 0x7a, 0xa3, 0x4f, 0xea, 0xeb, 0x42, 0xbb, + 0x8f, 0x92, 0xda, 0xf5, 0x88, 0xd7, 0x12, 0x6c, 0x5c, 0xb2, 0xe6, 0x9f, 0xbb, 0x47, 0x50, 0x4d, + 0x7a, 0x1c, 0x7d, 0x01, 0x10, 0xfa, 0x9c, 0x87, 0x2c, 0xbf, 0xe8, 0xa7, 0x84, 0x04, 0x8e, 0xc1, + 0x95, 0xbf, 0x48, 0x50, 0x49, 0x70, 0x33, 0xef, 0xd7, 0x01, 0x44, 0x61, 0xd5, 0xd8, 0xcc, 0xf1, + 0x23, 0x59, 0x5d, 0x7a, 0xcc, 0x70, 0xe6, 0x50, 0x5c, 0x71, 0xe2, 0x4b, 0xbe, 0xc7, 0x1b, 0x4a, + 0x3c, 0xfd, 0xd4, 0xa0, 0x9a, 0xe7, 0x90, 0x11, 0xcd, 0x0e, 0xe9, 0x8b, 0x00, 0x33, 0xe0, 0x10, + 0x5c, 0x79, 0x13, 0x5f, 0x2a, 0x5f, 0x43, 0x25, 0xc1, 0x47, 0x32, 0xe4, 0x4d, 0x72, 0x16, 0xe8, + 0xca, 0x3f, 0x05, 0x45, 0xb7, 0x84, 0x7e, 0x9c, 0xa2, 0x5b, 0xdc, 0x20, 0x43, 0xf7, 0x58, 0x3d, + 0xbf, 0x97, 0xe7, 0x06, 0xf1, 0x6f, 0x4e, 0xf3, 0x18, 0x75, 0xc4, 0xad, 0x28, 0x61, 0xf1, 0xad, + 0xfc, 0x4d, 0x82, 0x4a, 0xe2, 0x2e, 0xa2, 0xef, 0x41, 0x41, 0x18, 0x2b, 0x65, 0x19, 0x1b, 0x42, + 0x85, 0xb1, 0x02, 0xc8, 0xb7, 0x9d, 0xd8, 0xc4, 0x10, 0xa7, 0x4b, 0x58, 0x7c, 0xa3, 0x7d, 0xd8, + 0x0e, 0xaf, 0xb4, 0x66, 0x52, 0xe6, 0xea, 0x23, 0x4d, 0x38, 0x38, 0x2f, 0xce, 0xde, 0x0a, 0x99, + 0x47, 0x82, 0xd7, 0xe3, 0xfe, 0x7e, 0x0a, 0x1f, 0x91, 0xf1, 0x58, 0x67, 0xba, 0x6d, 0x11, 0x23, + 0x2e, 0xe4, 0xd5, 0x0b, 0xc2, 0x8a, 0xed, 0x88, 0x1d, 0x89, 0x79, 0xca, 0x7b, 0x09, 0x2a, 0x89, + 0x9c, 0x40, 0xdf, 0x85, 0x6a, 0x98, 0x15, 0x5a, 0x2c, 0xae, 0x95, 0x90, 0x2a, 0x0e, 0x3c, 0x02, + 0x14, 0xc1, 0x3c, 0xca, 0x98, 0x6e, 0x4d, 0xbc, 0x7a, 0x4e, 0xdc, 0xa5, 0x4f, 0x97, 0xe5, 0x9c, + 0x0f, 0xc3, 0x37, 0x48, 0x8a, 0xe2, 0x29, 0xcf, 0x41, 0x4e, 0xc3, 0x32, 0xef, 0x55, 0x0d, 0x8a, + 0xef, 0x88, 0x31, 0xa5, 0x41, 0xb8, 0xfc, 0x85, 0xf2, 0x07, 0x09, 0x6e, 0x2c, 0x64, 0xe6, 0x45, + 0x2d, 0x79, 0xb5, 0xc2, 0x12, 0x65, 0x55, 0xf6, 0x2f, 0xb7, 0xe6, 0xa7, 0x50, 0xcb, 0x82, 0x5e, + 0xc2, 0xa2, 0x7f, 0x48, 0x50, 0x0a, 0xb3, 0x19, 0x3d, 0x87, 0x8d, 0x89, 0x4b, 0x9c, 0x6f, 0xe6, + 0xc9, 0xef, 0x57, 0xd9, 0x9d, 0xa4, 0x72, 0x87, 0x1c, 0x11, 0xa4, 0x7f, 0x79, 0x12, 0x2d, 0xd0, + 0x01, 0x80, 0xed, 0x50, 0x97, 0xf0, 0xe8, 0x7b, 0x41, 0x45, 0x55, 0x96, 0x14, 0x8e, 0x46, 0x3f, + 0x44, 0xe2, 0x98, 0xd4, 0x6e, 0x0b, 0x20, 0xe2, 0xa0, 0x1f, 0x42, 0x29, 0xe4, 0x05, 0xf5, 0x23, + 0x55, 0x89, 0x42, 0x30, 0x8e, 0x90, 0x8a, 0x03, 0xe5, 0x98, 0x92, 0xe8, 0x13, 0x00, 0x6b, 0x6a, + 0x6a, 0x06, 0x99, 0xf9, 0x65, 0x88, 0xd7, 0xbc, 0x92, 0x35, 0x35, 0xbb, 0x82, 0x80, 0x6e, 0x43, + 0x59, 0xb7, 0x9c, 0x29, 0xd3, 0x3c, 0xfd, 0x37, 0xd4, 0x0f, 0x48, 0x11, 0x83, 0x20, 0x0d, 0x38, + 0x05, 0xdd, 0x81, 0x0d, 0x7b, 0xca, 0x22, 0x44, 0x5e, 0x20, 0xca, 0x3e, 0x4d, 0x40, 0x84, 0x1b, + 0x43, 0x55, 0xf8, 0x85, 0x08, 0x95, 0xd1, 0xc2, 0x3c, 0x2d, 0xe1, 0x4a, 0x48, 0x15, 0x75, 0xa7, + 0xbf, 0xd8, 0xd6, 0x7c, 0xa7, 0xdd, 0x5b, 0x62, 0xe3, 0x39, 0x1d, 0xed, 0x7f, 0x5d, 0x81, 0x7f, + 0x0b, 0x45, 0xd1, 0x16, 0x32, 0xaf, 0xd3, 0xc3, 0x44, 0x63, 0x4f, 0x45, 0x45, 0x88, 0x45, 0x3d, + 0x1d, 0x3d, 0x81, 0x35, 0x8f, 0x11, 0x36, 0xf5, 0x82, 0xca, 0xba, 0x93, 0x05, 0x17, 0x00, 0x1c, + 0x00, 0x95, 0xdf, 0xe7, 0xa0, 0x14, 0x6e, 0xf3, 0x21, 0xbd, 0x9a, 0xc0, 0x76, 0xe4, 0x65, 0xe2, + 0x79, 0xfa, 0xc4, 0xe2, 0x13, 0xc2, 0x5c, 0x95, 0x47, 0x4b, 0x34, 0x8f, 0xfc, 0xd2, 0x8c, 0x64, + 0x70, 0xcd, 0xc9, 0xa0, 0xee, 0x7e, 0x0d, 0xb5, 0x2c, 0x34, 0x6a, 0x41, 0x39, 0x7e, 0xa0, 0xef, + 0xfe, 0x3b, 0x4b, 0xdc, 0x1f, 0x09, 0xe2, 0xb8, 0x94, 0xf2, 0x13, 0xd8, 0xca, 0xc0, 0x5c, 0x22, + 0xc5, 0xff, 0x99, 0x83, 0x72, 0xcc, 0xc3, 0x3c, 0x1d, 0x3c, 0x46, 0x5c, 0xa6, 0x31, 0x3d, 0x94, + 0x2f, 0x09, 0xca, 0x50, 0x37, 0x29, 0xfa, 0x0c, 0x36, 0x47, 0xb6, 0xe9, 0x18, 0xd4, 0xbf, 0xbd, + 0x1c, 0xe3, 0x6f, 0x57, 0x8d, 0xc8, 0x02, 0xf8, 0x12, 0x4a, 0x23, 0xdb, 0xf2, 0x8b, 0xbd, 0x70, + 0x66, 0x35, 0xdb, 0x99, 0xe2, 0xd4, 0x46, 0x30, 0x60, 0x04, 0x78, 0xd1, 0x99, 0x22, 0x71, 0xf4, + 0x05, 0x94, 0xed, 0x53, 0x8f, 0xba, 0xef, 0xfc, 0x54, 0x2f, 0x64, 0xdd, 0x92, 0x7e, 0x04, 0xc0, + 0x71, 0xb4, 0xc2, 0x00, 0x2d, 0xee, 0x8e, 0xca, 0xb0, 0xde, 0xc2, 0x6a, 0x73, 0xa8, 0xb6, 0xe5, + 0x6b, 0x7c, 0x81, 0x4f, 0x7a, 0xbd, 0x4e, 0xef, 0x50, 0x96, 0x50, 0x05, 0x4a, 0x83, 0x93, 0x56, + 0x4b, 0x55, 0xdb, 0x6a, 0x5b, 0xce, 0x21, 0x80, 0xb5, 0x2f, 0x3b, 0xdd, 0xae, 0xda, 0x96, 0xf3, + 0xfc, 0xfb, 0x45, 0xb3, 0xc3, 0xbf, 0x0b, 0x48, 0x86, 0x0d, 0xb5, 0x89, 0xbb, 0x5f, 0x0d, 0x86, + 0xfd, 0xe3, 0x63, 0xb5, 0x2d, 0x17, 0xf9, 0x2e, 0x27, 0xbd, 0x2f, 0x7b, 0xfd, 0x9f, 0xf7, 0xe4, + 0x35, 0xe5, 0xc7, 0x50, 0x8e, 0x69, 0x84, 0x1a, 0xb0, 0xee, 0x77, 0xc3, 0x79, 0x9c, 0x6b, 0x49, + 0xed, 0xfd, 0x66, 0x88, 0xe7, 0x20, 0x65, 0x1f, 0xd6, 0x7c, 0xd2, 0x25, 0x22, 0xf9, 0x3b, 0x09, + 0x6e, 0x61, 0xea, 0xd8, 0x2e, 0x8b, 0x9d, 0xdc, 0xb5, 0x27, 0x98, 0xfe, 0x7a, 0x4a, 0x3d, 0xc6, + 0x23, 0xeb, 0x4f, 0x77, 0xb1, 0xfd, 0x4a, 0x82, 0x22, 0x1a, 0x90, 0x0a, 0x9b, 0x31, 0xb7, 0x69, + 0x86, 0x3d, 0xc9, 0x1e, 0xcb, 0x53, 0x9b, 0x57, 0xed, 0xc4, 0x5a, 0xb9, 0x05, 0x3b, 0xd9, 0x4a, + 0x38, 0xc6, 0x4c, 0x79, 0x09, 0xd5, 0x24, 0x19, 0x3d, 0x83, 0x72, 0x30, 0x26, 0x18, 0xf6, 0xc4, + 0xcb, 0xae, 0xe2, 0xbe, 0x27, 0xf8, 0x26, 0x60, 0xce, 0x3f, 0x3d, 0xe5, 0x35, 0x94, 0x42, 0x86, + 0xb0, 0x4d, 0x37, 0xa9, 0xe6, 0x31, 0x62, 0x3a, 0xa1, 0x6d, 0xba, 0x49, 0x07, 0x9c, 0x80, 0x1e, + 0xc1, 0x9a, 0x2f, 0x19, 0x98, 0x94, 0xed, 0xfd, 0x00, 0xa3, 0xfc, 0x49, 0x82, 0xfa, 0x21, 0xbd, + 0x9a, 0x17, 0x6f, 0x87, 0xf6, 0x08, 0xbe, 0x1f, 0xa0, 0x40, 0x6d, 0x01, 0x48, 0xe6, 0x57, 0x3e, + 0x9d, 0x5f, 0x3b, 0x70, 0x9d, 0x5a, 0x63, 0x9f, 0xe9, 0x0f, 0x79, 0xeb, 0xd4, 0x1a, 0x73, 0x96, + 0xa2, 0xc1, 0xcd, 0x0c, 0xad, 0x1c, 0x63, 0x96, 0x15, 0x3a, 0xe9, 0x0a, 0xa1, 0x7b, 0x0e, 0xb7, + 0xda, 0xd4, 0xa0, 0x8c, 0x5e, 0xc5, 0x72, 0x1e, 0xf8, 0x6c, 0x69, 0x1e, 0xf8, 0x3f, 0xe6, 0x60, + 0xfb, 0x90, 0xb2, 0xc1, 0x74, 0x32, 0xa1, 0x9e, 0xdf, 0xd7, 0x83, 0x5d, 0x9f, 0x01, 0xd0, 0xf0, + 0x61, 0x16, 0xa8, 0x5d, 0x5f, 0xf6, 0x70, 0xc3, 0x31, 0x2c, 0x7a, 0x08, 0x6b, 0xe2, 0xf4, 0xf9, + 0x94, 0xb4, 0x95, 0x51, 0x5e, 0x70, 0x00, 0x41, 0x9f, 0x43, 0xd5, 0xf5, 0x4f, 0xd4, 0xac, 0xa9, + 0x79, 0x4a, 0x5d, 0xe1, 0xfa, 0xe2, 0x41, 0xae, 0x2e, 0xe1, 0x4a, 0xc0, 0xe9, 0x09, 0x06, 0xfa, + 0x01, 0xdc, 0x1c, 0x4d, 0x5d, 0x97, 0x5a, 0x4c, 0x4b, 0x89, 0x14, 0xc4, 0x70, 0x50, 0x0b, 0xb8, + 0x38, 0x21, 0xf5, 0x18, 0x6a, 0xcc, 0x66, 0xc4, 0x48, 0xcb, 0x04, 0x2f, 0x2e, 0xc1, 0x4b, 0x48, + 0x28, 0xff, 0xc9, 0xc1, 0x56, 0xda, 0x27, 0x3c, 0x9a, 0xbf, 0x5a, 0xd6, 0x92, 0xfc, 0xe4, 0x78, + 0x9a, 0x9a, 0xb7, 0x16, 0x77, 0xb8, 0x44, 0x73, 0x4a, 0xbe, 0x55, 0x73, 0x97, 0x7a, 0xab, 0xbe, + 0x82, 0x5a, 0xf2, 0xad, 0xaa, 0xb9, 0x53, 0x23, 0x18, 0x80, 0x56, 0xbf, 0x58, 0xf1, 0xd4, 0xa0, + 0x18, 0xd1, 0x34, 0xe9, 0xff, 0xdc, 0x2a, 0x7f, 0x09, 0x7b, 0x3f, 0x23, 0x86, 0x3e, 0x26, 0x8c, + 0xa6, 0x87, 0xfc, 0x0f, 0xbf, 0x8d, 0xca, 0x1e, 0x7c, 0xba, 0x62, 0x77, 0x9e, 0x03, 0x7f, 0x95, + 0xe0, 0xe3, 0x43, 0xca, 0x16, 0x3c, 0xf1, 0x6d, 0xa7, 0xc2, 0x23, 0x40, 0xe3, 0x53, 0xcd, 0x24, + 0x16, 0x99, 0xf0, 0x0b, 0x36, 0x1e, 0xbb, 0xd4, 0xf3, 0x82, 0x4a, 0x24, 0x8f, 0x4f, 0x8f, 0x7c, + 0x46, 0xd3, 0xa7, 0x2b, 0x36, 0xec, 0x2e, 0x51, 0x9a, 0xdf, 0xd5, 0x65, 0x77, 0x40, 0xba, 0xf2, + 0x1d, 0x50, 0xfe, 0x9c, 0x7e, 0x45, 0x71, 0xf2, 0xc5, 0xdb, 0x20, 0x7a, 0x0e, 0xc0, 0x47, 0x11, + 0xe2, 0xea, 0x5e, 0x38, 0x79, 0xa4, 0xea, 0x60, 0x2b, 0xe4, 0x8b, 0x49, 0x23, 0x86, 0x8f, 0xca, + 0x73, 0xf8, 0xcc, 0x2e, 0x06, 0xe5, 0x79, 0xc0, 0xdf, 0xda, 0x16, 0xdc, 0x9d, 0x47, 0x39, 0xeb, + 0x69, 0x15, 0x86, 0x72, 0xf1, 0x77, 0x1c, 0xe9, 0x2a, 0xbf, 0xe3, 0x28, 0x77, 0x41, 0x39, 0xe7, + 0x3c, 0x7e, 0xb3, 0x9e, 0xc2, 0xf6, 0x80, 0xb2, 0xf8, 0x9c, 0x7c, 0xb1, 0x92, 0xbd, 0x0d, 0x5b, + 0x69, 0x39, 0xc7, 0x98, 0x3d, 0x38, 0x89, 0xfd, 0xb4, 0x22, 0x86, 0x25, 0x19, 0x36, 0x82, 0xc9, + 0x46, 0x1b, 0x7e, 0x75, 0xac, 0xca, 0xd7, 0xf8, 0x24, 0xd4, 0xee, 0x9f, 0x1c, 0x74, 0x55, 0x59, + 0x42, 0xeb, 0x90, 0xef, 0xf4, 0x86, 0x72, 0x0e, 0x6d, 0xc0, 0xf5, 0x76, 0x67, 0xd0, 0xc2, 0xea, + 0x50, 0x95, 0xf3, 0x68, 0x13, 0xca, 0xad, 0xe6, 0x50, 0x3d, 0xec, 0xe3, 0x4e, 0xab, 0xd9, 0x95, + 0x0b, 0x0f, 0x9e, 0xc5, 0x7e, 0xa6, 0x98, 0xcf, 0x60, 0xf3, 0x81, 0xe9, 0x1a, 0x17, 0x3e, 0xea, + 0xf4, 0x3a, 0x47, 0x9d, 0x5f, 0xf0, 0x3d, 0xf9, 0xaa, 0xf9, 0xda, 0x5f, 0xe5, 0x1e, 0xbc, 0x84, + 0x6a, 0x32, 0x64, 0xe8, 0x26, 0xa0, 0xb9, 0x46, 0xad, 0xfe, 0xd1, 0x71, 0x13, 0x77, 0x06, 0x7d, + 0xbe, 0x4b, 0x09, 0x8a, 0xea, 0xab, 0x93, 0x66, 0x57, 0x96, 0xd0, 0x75, 0x28, 0x74, 0xd5, 0xc1, + 0x40, 0xce, 0xf1, 0x73, 0x0e, 0xc5, 0xac, 0x87, 0xe5, 0xfc, 0xfe, 0xdf, 0x73, 0x50, 0x6a, 0x1f, + 0x04, 0x97, 0x1c, 0xbd, 0x85, 0x5a, 0xd6, 0xb4, 0x82, 0x3e, 0x4f, 0xc6, 0x69, 0xc5, 0x58, 0xb5, + 0xfb, 0xd9, 0x45, 0xa0, 0x3c, 0x57, 0x08, 0xdc, 0x58, 0xe8, 0xdf, 0xe8, 0xde, 0x42, 0x35, 0xcf, + 0x3e, 0xe5, 0xee, 0xb9, 0x38, 0x7e, 0xc4, 0x5b, 0xa8, 0x65, 0xf5, 0xe0, 0xb4, 0x39, 0x2b, 0xba, + 0x7c, 0xda, 0x9c, 0xa5, 0x2d, 0x7d, 0xff, 0xdf, 0x12, 0x40, 0xd4, 0x79, 0xd0, 0x6b, 0xa8, 0x26, + 0x5b, 0x11, 0xfa, 0xce, 0xea, 0x46, 0xe5, 0x1f, 0x77, 0xe7, 0xdc, 0x6e, 0x86, 0x66, 0xb0, 0xb3, + 0xb4, 0xb2, 0xa2, 0x46, 0x52, 0xfe, 0xbc, 0x02, 0xbf, 0xfb, 0xe8, 0xc2, 0x78, 0x6e, 0xe3, 0xbf, + 0x72, 0x50, 0x49, 0xe4, 0x1d, 0x32, 0xc5, 0x1c, 0xb3, 0x58, 0x0e, 0xd1, 0x83, 0x05, 0x43, 0x96, + 0x16, 0xfa, 0xdd, 0xfb, 0x17, 0xc2, 0x72, 0xdb, 0x5f, 0x43, 0x35, 0x99, 0xa1, 0x69, 0xaf, 0x66, + 0xe6, 0x7d, 0xda, 0xab, 0x19, 0x49, 0x8e, 0xde, 0x4b, 0xf0, 0xc9, 0xca, 0xd2, 0x82, 0xf6, 0xb3, + 0x5d, 0xb5, 0xaa, 0xee, 0xed, 0x3e, 0xbe, 0x94, 0x8c, 0x63, 0xcc, 0x4e, 0xd7, 0xc4, 0x3f, 0x07, + 0xdf, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0x4d, 0xf6, 0xdf, 0x46, 0x18, 0x00, 0x00, } diff --git a/pkg/apis/manager/v1beta1/api.proto b/pkg/apis/manager/v1beta1/api.proto index 8655cbc6424..09ef98a9f91 100644 --- a/pkg/apis/manager/v1beta1/api.proto +++ b/pkg/apis/manager/v1beta1/api.proto @@ -42,6 +42,7 @@ service Suggestion { service EarlyStopping { rpc GetEarlyStoppingRules(GetEarlyStoppingRulesRequest) returns (GetEarlyStoppingRulesReply); rpc SetTrialStatus(SetTrialStatusRequest) returns (SetTrialStatusReply); + rpc ValidateEarlyStoppingSettings(ValidateEarlyStoppingSettingsRequest) returns (ValidateEarlyStoppingSettingsReply); } /** @@ -339,6 +340,16 @@ message EarlyStoppingRule { int32 start_step = 4; } +message ValidateEarlyStoppingSettingsRequest { + EarlyStoppingSpec early_stopping = 1; +} + +/** + * Return INVALID_ARGUMENT Error if Early Stopping Settings are not Valid + */ +message ValidateEarlyStoppingSettingsReply { +} + enum ComparisonType { UNKNOWN_COMPARISON = 0; // Unknown comparison, not used EQUAL = 1; // Equal comparison, e.g. accuracy = 0.7 diff --git a/pkg/apis/manager/v1beta1/gen-doc/api.md b/pkg/apis/manager/v1beta1/gen-doc/api.md index 7956fb9cfde..1b8303be99d 100644 --- a/pkg/apis/manager/v1beta1/gen-doc/api.md +++ b/pkg/apis/manager/v1beta1/gen-doc/api.md @@ -44,6 +44,8 @@ - [TrialStatus](#api.v1.beta1.TrialStatus) - [ValidateAlgorithmSettingsReply](#api.v1.beta1.ValidateAlgorithmSettingsReply) - [ValidateAlgorithmSettingsRequest](#api.v1.beta1.ValidateAlgorithmSettingsRequest) + - [ValidateEarlyStoppingSettingsReply](#api.v1.beta1.ValidateEarlyStoppingSettingsReply) + - [ValidateEarlyStoppingSettingsRequest](#api.v1.beta1.ValidateEarlyStoppingSettingsRequest) - [ComparisonType](#api.v1.beta1.ComparisonType) - [ObjectiveType](#api.v1.beta1.ObjectiveType) @@ -696,6 +698,31 @@ Return INVALID_ARGUMENT Error if Algorithm Settings are not Valid + + + +### ValidateEarlyStoppingSettingsReply +Return INVALID_ARGUMENT Error if Early Stopping Settings are not Valid + + + + + + + + +### ValidateEarlyStoppingSettingsRequest + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| early_stopping | [EarlyStoppingSpec](#api.v1.beta1.EarlyStoppingSpec) | | | + + + + + @@ -784,6 +811,7 @@ EarlyStopping service defines APIs to manage Katib Early Stopping algorithms | ----------- | ------------ | ------------- | ------------| | GetEarlyStoppingRules | [GetEarlyStoppingRulesRequest](#api.v1.beta1.GetEarlyStoppingRulesRequest) | [GetEarlyStoppingRulesReply](#api.v1.beta1.GetEarlyStoppingRulesReply) | | | SetTrialStatus | [SetTrialStatusRequest](#api.v1.beta1.SetTrialStatusRequest) | [SetTrialStatusReply](#api.v1.beta1.SetTrialStatusReply) | | +| ValidateEarlyStoppingSettings | [ValidateEarlyStoppingSettingsRequest](#api.v1.beta1.ValidateEarlyStoppingSettingsRequest) | [ValidateEarlyStoppingSettingsReply](#api.v1.beta1.ValidateEarlyStoppingSettingsReply) | | diff --git a/pkg/apis/manager/v1beta1/gen-doc/index.html b/pkg/apis/manager/v1beta1/gen-doc/index.html index cda9bbe46d4..223349c04d1 100644 --- a/pkg/apis/manager/v1beta1/gen-doc/index.html +++ b/pkg/apis/manager/v1beta1/gen-doc/index.html @@ -338,6 +338,14 @@

Table of Contents

MValidateAlgorithmSettingsRequest +
  • + MValidateEarlyStoppingSettingsReply +
  • + +
  • + MValidateEarlyStoppingSettingsRequest +
  • +
  • EComparisonType @@ -1630,6 +1638,37 @@

    ValidateAlgorithmSettings +

    ValidateEarlyStoppingSettingsReply

    +

    Return INVALID_ARGUMENT Error if Early Stopping Settings are not Valid

    + + + + + +

    ValidateEarlyStoppingSettingsRequest

    +

    + + + + + + + + + + + + + + + + +
    FieldTypeLabelDescription
    early_stoppingEarlyStoppingSpec

    + + + + +

    ComparisonType

    @@ -1852,6 +1891,13 @@

    EarlyStopping

    + + ValidateEarlyStoppingSettings + ValidateEarlyStoppingSettingsRequest + ValidateEarlyStoppingSettingsReply +

    + + diff --git a/pkg/apis/manager/v1beta1/python/api_pb2.py b/pkg/apis/manager/v1beta1/python/api_pb2.py index 37a89c091b8..98adaa6962d 100644 --- a/pkg/apis/manager/v1beta1/python/api_pb2.py +++ b/pkg/apis/manager/v1beta1/python/api_pb2.py @@ -20,7 +20,7 @@ name='api.proto', package='api.v1.beta1', syntax='proto3', - serialized_pb=_b('\n\tapi.proto\x12\x0c\x61pi.v1.beta1\"F\n\nExperiment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12*\n\x04spec\x18\x02 \x01(\x0b\x32\x1c.api.v1.beta1.ExperimentSpec\"\x96\x03\n\x0e\x45xperimentSpec\x12\x44\n\x0fparameter_specs\x18\x01 \x01(\x0b\x32+.api.v1.beta1.ExperimentSpec.ParameterSpecs\x12.\n\tobjective\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.ObjectiveSpec\x12.\n\talgorithm\x18\x03 \x01(\x0b\x32\x1b.api.v1.beta1.AlgorithmSpec\x12\x37\n\x0e\x65\x61rly_stopping\x18\x04 \x01(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingSpec\x12\x1c\n\x14parallel_trial_count\x18\x05 \x01(\x05\x12\x17\n\x0fmax_trial_count\x18\x06 \x01(\x05\x12+\n\nnas_config\x18\x07 \x01(\x0b\x32\x17.api.v1.beta1.NasConfig\x1a\x41\n\x0eParameterSpecs\x12/\n\nparameters\x18\x01 \x03(\x0b\x32\x1b.api.v1.beta1.ParameterSpec\"\x87\x01\n\rParameterSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x33\n\x0eparameter_type\x18\x02 \x01(\x0e\x32\x1b.api.v1.beta1.ParameterType\x12\x33\n\x0e\x66\x65\x61sible_space\x18\x03 \x01(\x0b\x32\x1b.api.v1.beta1.FeasibleSpace\"E\n\rFeasibleSpace\x12\x0b\n\x03max\x18\x01 \x01(\t\x12\x0b\n\x03min\x18\x02 \x01(\t\x12\x0c\n\x04list\x18\x03 \x03(\t\x12\x0c\n\x04step\x18\x04 \x01(\t\"\x88\x01\n\rObjectiveSpec\x12)\n\x04type\x18\x01 \x01(\x0e\x32\x1b.api.v1.beta1.ObjectiveType\x12\x0c\n\x04goal\x18\x02 \x01(\x01\x12\x1d\n\x15objective_metric_name\x18\x03 \x01(\t\x12\x1f\n\x17\x61\x64\x64itional_metric_names\x18\x04 \x03(\t\"c\n\rAlgorithmSpec\x12\x16\n\x0e\x61lgorithm_name\x18\x01 \x01(\t\x12:\n\x12\x61lgorithm_settings\x18\x02 \x03(\x0b\x32\x1e.api.v1.beta1.AlgorithmSetting\"/\n\x10\x41lgorithmSetting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"k\n\x11\x45\x61rlyStoppingSpec\x12\x16\n\x0e\x61lgorithm_name\x18\x01 \x01(\t\x12>\n\x12\x61lgorithm_settings\x18\x02 \x03(\x0b\x32\".api.v1.beta1.EarlyStoppingSetting\"3\n\x14\x45\x61rlyStoppingSetting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xae\x01\n\tNasConfig\x12/\n\x0cgraph_config\x18\x01 \x01(\x0b\x32\x19.api.v1.beta1.GraphConfig\x12\x36\n\noperations\x18\x02 \x01(\x0b\x32\".api.v1.beta1.NasConfig.Operations\x1a\x38\n\nOperations\x12*\n\toperation\x18\x01 \x03(\x0b\x32\x17.api.v1.beta1.Operation\"L\n\x0bGraphConfig\x12\x12\n\nnum_layers\x18\x01 \x01(\x05\x12\x13\n\x0binput_sizes\x18\x02 \x03(\x05\x12\x14\n\x0coutput_sizes\x18\x03 \x03(\x05\"\xa7\x01\n\tOperation\x12\x16\n\x0eoperation_type\x18\x01 \x01(\t\x12?\n\x0fparameter_specs\x18\x02 \x01(\x0b\x32&.api.v1.beta1.Operation.ParameterSpecs\x1a\x41\n\x0eParameterSpecs\x12/\n\nparameters\x18\x01 \x03(\x0b\x32\x1b.api.v1.beta1.ParameterSpec\"g\n\x05Trial\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x04spec\x18\x02 \x01(\x0b\x32\x17.api.v1.beta1.TrialSpec\x12)\n\x06status\x18\x03 \x01(\x0b\x32\x19.api.v1.beta1.TrialStatus\"\xd8\x01\n\tTrialSpec\x12.\n\tobjective\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.ObjectiveSpec\x12K\n\x15parameter_assignments\x18\x03 \x01(\x0b\x32,.api.v1.beta1.TrialSpec.ParameterAssignments\x1aN\n\x14ParameterAssignments\x12\x36\n\x0b\x61ssignments\x18\x01 \x03(\x0b\x32!.api.v1.beta1.ParameterAssignment\"2\n\x13ParameterAssignment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xa1\x02\n\x0bTrialStatus\x12\x12\n\nstart_time\x18\x01 \x01(\t\x12\x17\n\x0f\x63ompletion_time\x18\x02 \x01(\t\x12?\n\tcondition\x18\x03 \x01(\x0e\x32,.api.v1.beta1.TrialStatus.TrialConditionType\x12.\n\x0bobservation\x18\x04 \x01(\x0b\x32\x19.api.v1.beta1.Observation\"t\n\x12TrialConditionType\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tSUCCEEDED\x10\x02\x12\n\n\x06KILLED\x10\x03\x12\n\n\x06\x46\x41ILED\x10\x04\x12\x10\n\x0c\x45\x41RLYSTOPPED\x10\x05\x12\x0b\n\x07UNKNOWN\x10\x06\"4\n\x0bObservation\x12%\n\x07metrics\x18\x01 \x03(\x0b\x32\x14.api.v1.beta1.Metric\"%\n\x06Metric\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"h\n\x1bReportObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\x12\x35\n\x0fobservation_log\x18\x02 \x01(\x0b\x32\x1c.api.v1.beta1.ObservationLog\"\x1b\n\x19ReportObservationLogReply\">\n\x0eObservationLog\x12,\n\x0bmetric_logs\x18\x01 \x03(\x0b\x32\x17.api.v1.beta1.MetricLog\"E\n\tMetricLog\x12\x12\n\ntime_stamp\x18\x01 \x01(\t\x12$\n\x06metric\x18\x02 \x01(\x0b\x32\x14.api.v1.beta1.Metric\"i\n\x18GetObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\x12\x13\n\x0bmetric_name\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\t\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\t\"O\n\x16GetObservationLogReply\x12\x35\n\x0fobservation_log\x18\x01 \x01(\x0b\x32\x1c.api.v1.beta1.ObservationLog\"1\n\x1b\x44\x65leteObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\"\x1b\n\x19\x44\x65leteObservationLogReply\"\xc4\x01\n\x15GetSuggestionsRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\x12#\n\x06trials\x18\x02 \x03(\x0b\x32\x13.api.v1.beta1.Trial\x12\x1a\n\x0erequest_number\x18\x03 \x01(\x05\x42\x02\x18\x01\x12\x1e\n\x16\x63urrent_request_number\x18\x04 \x01(\x05\x12\x1c\n\x14total_request_number\x18\x05 \x01(\x05\"\xab\x02\n\x13GetSuggestionsReply\x12U\n\x15parameter_assignments\x18\x01 \x03(\x0b\x32\x36.api.v1.beta1.GetSuggestionsReply.ParameterAssignments\x12.\n\talgorithm\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.AlgorithmSpec\x12=\n\x14\x65\x61rly_stopping_rules\x18\x03 \x03(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingRule\x1aN\n\x14ParameterAssignments\x12\x36\n\x0b\x61ssignments\x18\x01 \x03(\x0b\x32!.api.v1.beta1.ParameterAssignment\"P\n ValidateAlgorithmSettingsRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\" \n\x1eValidateAlgorithmSettingsReply\"\x8d\x01\n\x1cGetEarlyStoppingRulesRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\x12#\n\x06trials\x18\x02 \x03(\x0b\x32\x13.api.v1.beta1.Trial\x12\x1a\n\x12\x64\x62_manager_address\x18\x03 \x01(\t\"[\n\x1aGetEarlyStoppingRulesReply\x12=\n\x14\x65\x61rly_stopping_rules\x18\x01 \x03(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingRule\"v\n\x11\x45\x61rlyStoppingRule\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12\x30\n\ncomparison\x18\x03 \x01(\x0e\x32\x1c.api.v1.beta1.ComparisonType\x12\x12\n\nstart_step\x18\x04 \x01(\x05\"+\n\x15SetTrialStatusRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\"\x15\n\x13SetTrialStatusReply*U\n\rParameterType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\n\n\x06\x44OUBLE\x10\x01\x12\x07\n\x03INT\x10\x02\x12\x0c\n\x08\x44ISCRETE\x10\x03\x12\x0f\n\x0b\x43\x41TEGORICAL\x10\x04*8\n\rObjectiveType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0c\n\x08MINIMIZE\x10\x01\x12\x0c\n\x08MAXIMIZE\x10\x02*J\n\x0e\x43omparisonType\x12\x16\n\x12UNKNOWN_COMPARISON\x10\x00\x12\t\n\x05\x45QUAL\x10\x01\x12\x08\n\x04LESS\x10\x02\x12\x0b\n\x07GREATER\x10\x03\x32\xc6\x02\n\tDBManager\x12j\n\x14ReportObservationLog\x12).api.v1.beta1.ReportObservationLogRequest\x1a\'.api.v1.beta1.ReportObservationLogReply\x12\x61\n\x11GetObservationLog\x12&.api.v1.beta1.GetObservationLogRequest\x1a$.api.v1.beta1.GetObservationLogReply\x12j\n\x14\x44\x65leteObservationLog\x12).api.v1.beta1.DeleteObservationLogRequest\x1a\'.api.v1.beta1.DeleteObservationLogReply2\xe1\x01\n\nSuggestion\x12X\n\x0eGetSuggestions\x12#.api.v1.beta1.GetSuggestionsRequest\x1a!.api.v1.beta1.GetSuggestionsReply\x12y\n\x19ValidateAlgorithmSettings\x12..api.v1.beta1.ValidateAlgorithmSettingsRequest\x1a,.api.v1.beta1.ValidateAlgorithmSettingsReply2\xd8\x01\n\rEarlyStopping\x12m\n\x15GetEarlyStoppingRules\x12*.api.v1.beta1.GetEarlyStoppingRulesRequest\x1a(.api.v1.beta1.GetEarlyStoppingRulesReply\x12X\n\x0eSetTrialStatus\x12#.api.v1.beta1.SetTrialStatusRequest\x1a!.api.v1.beta1.SetTrialStatusReplyb\x06proto3') + serialized_pb=_b('\n\tapi.proto\x12\x0c\x61pi.v1.beta1\"F\n\nExperiment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12*\n\x04spec\x18\x02 \x01(\x0b\x32\x1c.api.v1.beta1.ExperimentSpec\"\x96\x03\n\x0e\x45xperimentSpec\x12\x44\n\x0fparameter_specs\x18\x01 \x01(\x0b\x32+.api.v1.beta1.ExperimentSpec.ParameterSpecs\x12.\n\tobjective\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.ObjectiveSpec\x12.\n\talgorithm\x18\x03 \x01(\x0b\x32\x1b.api.v1.beta1.AlgorithmSpec\x12\x37\n\x0e\x65\x61rly_stopping\x18\x04 \x01(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingSpec\x12\x1c\n\x14parallel_trial_count\x18\x05 \x01(\x05\x12\x17\n\x0fmax_trial_count\x18\x06 \x01(\x05\x12+\n\nnas_config\x18\x07 \x01(\x0b\x32\x17.api.v1.beta1.NasConfig\x1a\x41\n\x0eParameterSpecs\x12/\n\nparameters\x18\x01 \x03(\x0b\x32\x1b.api.v1.beta1.ParameterSpec\"\x87\x01\n\rParameterSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x33\n\x0eparameter_type\x18\x02 \x01(\x0e\x32\x1b.api.v1.beta1.ParameterType\x12\x33\n\x0e\x66\x65\x61sible_space\x18\x03 \x01(\x0b\x32\x1b.api.v1.beta1.FeasibleSpace\"E\n\rFeasibleSpace\x12\x0b\n\x03max\x18\x01 \x01(\t\x12\x0b\n\x03min\x18\x02 \x01(\t\x12\x0c\n\x04list\x18\x03 \x03(\t\x12\x0c\n\x04step\x18\x04 \x01(\t\"\x88\x01\n\rObjectiveSpec\x12)\n\x04type\x18\x01 \x01(\x0e\x32\x1b.api.v1.beta1.ObjectiveType\x12\x0c\n\x04goal\x18\x02 \x01(\x01\x12\x1d\n\x15objective_metric_name\x18\x03 \x01(\t\x12\x1f\n\x17\x61\x64\x64itional_metric_names\x18\x04 \x03(\t\"c\n\rAlgorithmSpec\x12\x16\n\x0e\x61lgorithm_name\x18\x01 \x01(\t\x12:\n\x12\x61lgorithm_settings\x18\x02 \x03(\x0b\x32\x1e.api.v1.beta1.AlgorithmSetting\"/\n\x10\x41lgorithmSetting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"k\n\x11\x45\x61rlyStoppingSpec\x12\x16\n\x0e\x61lgorithm_name\x18\x01 \x01(\t\x12>\n\x12\x61lgorithm_settings\x18\x02 \x03(\x0b\x32\".api.v1.beta1.EarlyStoppingSetting\"3\n\x14\x45\x61rlyStoppingSetting\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xae\x01\n\tNasConfig\x12/\n\x0cgraph_config\x18\x01 \x01(\x0b\x32\x19.api.v1.beta1.GraphConfig\x12\x36\n\noperations\x18\x02 \x01(\x0b\x32\".api.v1.beta1.NasConfig.Operations\x1a\x38\n\nOperations\x12*\n\toperation\x18\x01 \x03(\x0b\x32\x17.api.v1.beta1.Operation\"L\n\x0bGraphConfig\x12\x12\n\nnum_layers\x18\x01 \x01(\x05\x12\x13\n\x0binput_sizes\x18\x02 \x03(\x05\x12\x14\n\x0coutput_sizes\x18\x03 \x03(\x05\"\xa7\x01\n\tOperation\x12\x16\n\x0eoperation_type\x18\x01 \x01(\t\x12?\n\x0fparameter_specs\x18\x02 \x01(\x0b\x32&.api.v1.beta1.Operation.ParameterSpecs\x1a\x41\n\x0eParameterSpecs\x12/\n\nparameters\x18\x01 \x03(\x0b\x32\x1b.api.v1.beta1.ParameterSpec\"g\n\x05Trial\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x04spec\x18\x02 \x01(\x0b\x32\x17.api.v1.beta1.TrialSpec\x12)\n\x06status\x18\x03 \x01(\x0b\x32\x19.api.v1.beta1.TrialStatus\"\xd8\x01\n\tTrialSpec\x12.\n\tobjective\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.ObjectiveSpec\x12K\n\x15parameter_assignments\x18\x03 \x01(\x0b\x32,.api.v1.beta1.TrialSpec.ParameterAssignments\x1aN\n\x14ParameterAssignments\x12\x36\n\x0b\x61ssignments\x18\x01 \x03(\x0b\x32!.api.v1.beta1.ParameterAssignment\"2\n\x13ParameterAssignment\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xa1\x02\n\x0bTrialStatus\x12\x12\n\nstart_time\x18\x01 \x01(\t\x12\x17\n\x0f\x63ompletion_time\x18\x02 \x01(\t\x12?\n\tcondition\x18\x03 \x01(\x0e\x32,.api.v1.beta1.TrialStatus.TrialConditionType\x12.\n\x0bobservation\x18\x04 \x01(\x0b\x32\x19.api.v1.beta1.Observation\"t\n\x12TrialConditionType\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tSUCCEEDED\x10\x02\x12\n\n\x06KILLED\x10\x03\x12\n\n\x06\x46\x41ILED\x10\x04\x12\x10\n\x0c\x45\x41RLYSTOPPED\x10\x05\x12\x0b\n\x07UNKNOWN\x10\x06\"4\n\x0bObservation\x12%\n\x07metrics\x18\x01 \x03(\x0b\x32\x14.api.v1.beta1.Metric\"%\n\x06Metric\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"h\n\x1bReportObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\x12\x35\n\x0fobservation_log\x18\x02 \x01(\x0b\x32\x1c.api.v1.beta1.ObservationLog\"\x1b\n\x19ReportObservationLogReply\">\n\x0eObservationLog\x12,\n\x0bmetric_logs\x18\x01 \x03(\x0b\x32\x17.api.v1.beta1.MetricLog\"E\n\tMetricLog\x12\x12\n\ntime_stamp\x18\x01 \x01(\t\x12$\n\x06metric\x18\x02 \x01(\x0b\x32\x14.api.v1.beta1.Metric\"i\n\x18GetObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\x12\x13\n\x0bmetric_name\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x03 \x01(\t\x12\x10\n\x08\x65nd_time\x18\x04 \x01(\t\"O\n\x16GetObservationLogReply\x12\x35\n\x0fobservation_log\x18\x01 \x01(\x0b\x32\x1c.api.v1.beta1.ObservationLog\"1\n\x1b\x44\x65leteObservationLogRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\"\x1b\n\x19\x44\x65leteObservationLogReply\"\xc4\x01\n\x15GetSuggestionsRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\x12#\n\x06trials\x18\x02 \x03(\x0b\x32\x13.api.v1.beta1.Trial\x12\x1a\n\x0erequest_number\x18\x03 \x01(\x05\x42\x02\x18\x01\x12\x1e\n\x16\x63urrent_request_number\x18\x04 \x01(\x05\x12\x1c\n\x14total_request_number\x18\x05 \x01(\x05\"\xab\x02\n\x13GetSuggestionsReply\x12U\n\x15parameter_assignments\x18\x01 \x03(\x0b\x32\x36.api.v1.beta1.GetSuggestionsReply.ParameterAssignments\x12.\n\talgorithm\x18\x02 \x01(\x0b\x32\x1b.api.v1.beta1.AlgorithmSpec\x12=\n\x14\x65\x61rly_stopping_rules\x18\x03 \x03(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingRule\x1aN\n\x14ParameterAssignments\x12\x36\n\x0b\x61ssignments\x18\x01 \x03(\x0b\x32!.api.v1.beta1.ParameterAssignment\"P\n ValidateAlgorithmSettingsRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\" \n\x1eValidateAlgorithmSettingsReply\"\x8d\x01\n\x1cGetEarlyStoppingRulesRequest\x12,\n\nexperiment\x18\x01 \x01(\x0b\x32\x18.api.v1.beta1.Experiment\x12#\n\x06trials\x18\x02 \x03(\x0b\x32\x13.api.v1.beta1.Trial\x12\x1a\n\x12\x64\x62_manager_address\x18\x03 \x01(\t\"[\n\x1aGetEarlyStoppingRulesReply\x12=\n\x14\x65\x61rly_stopping_rules\x18\x01 \x03(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingRule\"v\n\x11\x45\x61rlyStoppingRule\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\x12\x30\n\ncomparison\x18\x03 \x01(\x0e\x32\x1c.api.v1.beta1.ComparisonType\x12\x12\n\nstart_step\x18\x04 \x01(\x05\"_\n$ValidateEarlyStoppingSettingsRequest\x12\x37\n\x0e\x65\x61rly_stopping\x18\x01 \x01(\x0b\x32\x1f.api.v1.beta1.EarlyStoppingSpec\"$\n\"ValidateEarlyStoppingSettingsReply\"+\n\x15SetTrialStatusRequest\x12\x12\n\ntrial_name\x18\x01 \x01(\t\"\x15\n\x13SetTrialStatusReply*U\n\rParameterType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\n\n\x06\x44OUBLE\x10\x01\x12\x07\n\x03INT\x10\x02\x12\x0c\n\x08\x44ISCRETE\x10\x03\x12\x0f\n\x0b\x43\x41TEGORICAL\x10\x04*8\n\rObjectiveType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0c\n\x08MINIMIZE\x10\x01\x12\x0c\n\x08MAXIMIZE\x10\x02*J\n\x0e\x43omparisonType\x12\x16\n\x12UNKNOWN_COMPARISON\x10\x00\x12\t\n\x05\x45QUAL\x10\x01\x12\x08\n\x04LESS\x10\x02\x12\x0b\n\x07GREATER\x10\x03\x32\xc6\x02\n\tDBManager\x12j\n\x14ReportObservationLog\x12).api.v1.beta1.ReportObservationLogRequest\x1a\'.api.v1.beta1.ReportObservationLogReply\x12\x61\n\x11GetObservationLog\x12&.api.v1.beta1.GetObservationLogRequest\x1a$.api.v1.beta1.GetObservationLogReply\x12j\n\x14\x44\x65leteObservationLog\x12).api.v1.beta1.DeleteObservationLogRequest\x1a\'.api.v1.beta1.DeleteObservationLogReply2\xe1\x01\n\nSuggestion\x12X\n\x0eGetSuggestions\x12#.api.v1.beta1.GetSuggestionsRequest\x1a!.api.v1.beta1.GetSuggestionsReply\x12y\n\x19ValidateAlgorithmSettings\x12..api.v1.beta1.ValidateAlgorithmSettingsRequest\x1a,.api.v1.beta1.ValidateAlgorithmSettingsReply2\xe0\x02\n\rEarlyStopping\x12m\n\x15GetEarlyStoppingRules\x12*.api.v1.beta1.GetEarlyStoppingRulesRequest\x1a(.api.v1.beta1.GetEarlyStoppingRulesReply\x12X\n\x0eSetTrialStatus\x12#.api.v1.beta1.SetTrialStatusRequest\x1a!.api.v1.beta1.SetTrialStatusReply\x12\x85\x01\n\x1dValidateEarlyStoppingSettings\x12\x32.api.v1.beta1.ValidateEarlyStoppingSettingsRequest\x1a\x30.api.v1.beta1.ValidateEarlyStoppingSettingsReplyb\x06proto3') ) _PARAMETERTYPE = _descriptor.EnumDescriptor( @@ -52,8 +52,8 @@ ], containing_type=None, options=None, - serialized_start=3934, - serialized_end=4019, + serialized_start=4069, + serialized_end=4154, ) _sym_db.RegisterEnumDescriptor(_PARAMETERTYPE) @@ -79,8 +79,8 @@ ], containing_type=None, options=None, - serialized_start=4021, - serialized_end=4077, + serialized_start=4156, + serialized_end=4212, ) _sym_db.RegisterEnumDescriptor(_OBJECTIVETYPE) @@ -110,8 +110,8 @@ ], containing_type=None, options=None, - serialized_start=4079, - serialized_end=4153, + serialized_start=4214, + serialized_end=4288, ) _sym_db.RegisterEnumDescriptor(_COMPARISONTYPE) @@ -1655,6 +1655,61 @@ ) +_VALIDATEEARLYSTOPPINGSETTINGSREQUEST = _descriptor.Descriptor( + name='ValidateEarlyStoppingSettingsRequest', + full_name='api.v1.beta1.ValidateEarlyStoppingSettingsRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='early_stopping', full_name='api.v1.beta1.ValidateEarlyStoppingSettingsRequest.early_stopping', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3866, + serialized_end=3961, +) + + +_VALIDATEEARLYSTOPPINGSETTINGSREPLY = _descriptor.Descriptor( + name='ValidateEarlyStoppingSettingsReply', + full_name='api.v1.beta1.ValidateEarlyStoppingSettingsReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3963, + serialized_end=3999, +) + + _SETTRIALSTATUSREQUEST = _descriptor.Descriptor( name='SetTrialStatusRequest', full_name='api.v1.beta1.SetTrialStatusRequest', @@ -1681,8 +1736,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3866, - serialized_end=3909, + serialized_start=4001, + serialized_end=4044, ) @@ -1705,8 +1760,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3911, - serialized_end=3932, + serialized_start=4046, + serialized_end=4067, ) _EXPERIMENT.fields_by_name['spec'].message_type = _EXPERIMENTSPEC @@ -1755,6 +1810,7 @@ _GETEARLYSTOPPINGRULESREQUEST.fields_by_name['trials'].message_type = _TRIAL _GETEARLYSTOPPINGRULESREPLY.fields_by_name['early_stopping_rules'].message_type = _EARLYSTOPPINGRULE _EARLYSTOPPINGRULE.fields_by_name['comparison'].enum_type = _COMPARISONTYPE +_VALIDATEEARLYSTOPPINGSETTINGSREQUEST.fields_by_name['early_stopping'].message_type = _EARLYSTOPPINGSPEC DESCRIPTOR.message_types_by_name['Experiment'] = _EXPERIMENT DESCRIPTOR.message_types_by_name['ExperimentSpec'] = _EXPERIMENTSPEC DESCRIPTOR.message_types_by_name['ParameterSpec'] = _PARAMETERSPEC @@ -1788,6 +1844,8 @@ DESCRIPTOR.message_types_by_name['GetEarlyStoppingRulesRequest'] = _GETEARLYSTOPPINGRULESREQUEST DESCRIPTOR.message_types_by_name['GetEarlyStoppingRulesReply'] = _GETEARLYSTOPPINGRULESREPLY DESCRIPTOR.message_types_by_name['EarlyStoppingRule'] = _EARLYSTOPPINGRULE +DESCRIPTOR.message_types_by_name['ValidateEarlyStoppingSettingsRequest'] = _VALIDATEEARLYSTOPPINGSETTINGSREQUEST +DESCRIPTOR.message_types_by_name['ValidateEarlyStoppingSettingsReply'] = _VALIDATEEARLYSTOPPINGSETTINGSREPLY DESCRIPTOR.message_types_by_name['SetTrialStatusRequest'] = _SETTRIALSTATUSREQUEST DESCRIPTOR.message_types_by_name['SetTrialStatusReply'] = _SETTRIALSTATUSREPLY DESCRIPTOR.enum_types_by_name['ParameterType'] = _PARAMETERTYPE @@ -2066,6 +2124,20 @@ )) _sym_db.RegisterMessage(EarlyStoppingRule) +ValidateEarlyStoppingSettingsRequest = _reflection.GeneratedProtocolMessageType('ValidateEarlyStoppingSettingsRequest', (_message.Message,), dict( + DESCRIPTOR = _VALIDATEEARLYSTOPPINGSETTINGSREQUEST, + __module__ = 'api_pb2' + # @@protoc_insertion_point(class_scope:api.v1.beta1.ValidateEarlyStoppingSettingsRequest) + )) +_sym_db.RegisterMessage(ValidateEarlyStoppingSettingsRequest) + +ValidateEarlyStoppingSettingsReply = _reflection.GeneratedProtocolMessageType('ValidateEarlyStoppingSettingsReply', (_message.Message,), dict( + DESCRIPTOR = _VALIDATEEARLYSTOPPINGSETTINGSREPLY, + __module__ = 'api_pb2' + # @@protoc_insertion_point(class_scope:api.v1.beta1.ValidateEarlyStoppingSettingsReply) + )) +_sym_db.RegisterMessage(ValidateEarlyStoppingSettingsReply) + SetTrialStatusRequest = _reflection.GeneratedProtocolMessageType('SetTrialStatusRequest', (_message.Message,), dict( DESCRIPTOR = _SETTRIALSTATUSREQUEST, __module__ = 'api_pb2' @@ -2090,8 +2162,8 @@ file=DESCRIPTOR, index=0, options=None, - serialized_start=4156, - serialized_end=4482, + serialized_start=4291, + serialized_end=4617, methods=[ _descriptor.MethodDescriptor( name='ReportObservationLog', @@ -2132,8 +2204,8 @@ file=DESCRIPTOR, index=1, options=None, - serialized_start=4485, - serialized_end=4710, + serialized_start=4620, + serialized_end=4845, methods=[ _descriptor.MethodDescriptor( name='GetSuggestions', @@ -2165,8 +2237,8 @@ file=DESCRIPTOR, index=2, options=None, - serialized_start=4713, - serialized_end=4929, + serialized_start=4848, + serialized_end=5200, methods=[ _descriptor.MethodDescriptor( name='GetEarlyStoppingRules', @@ -2186,6 +2258,15 @@ output_type=_SETTRIALSTATUSREPLY, options=None, ), + _descriptor.MethodDescriptor( + name='ValidateEarlyStoppingSettings', + full_name='api.v1.beta1.EarlyStopping.ValidateEarlyStoppingSettings', + index=2, + containing_service=None, + input_type=_VALIDATEEARLYSTOPPINGSETTINGSREQUEST, + output_type=_VALIDATEEARLYSTOPPINGSETTINGSREPLY, + options=None, + ), ]) _sym_db.RegisterServiceDescriptor(_EARLYSTOPPING) @@ -2367,6 +2448,11 @@ def __init__(self, channel): request_serializer=SetTrialStatusRequest.SerializeToString, response_deserializer=SetTrialStatusReply.FromString, ) + self.ValidateEarlyStoppingSettings = channel.unary_unary( + '/api.v1.beta1.EarlyStopping/ValidateEarlyStoppingSettings', + request_serializer=ValidateEarlyStoppingSettingsRequest.SerializeToString, + response_deserializer=ValidateEarlyStoppingSettingsReply.FromString, + ) class EarlyStoppingServicer(object): @@ -2388,6 +2474,13 @@ def SetTrialStatus(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ValidateEarlyStoppingSettings(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_EarlyStoppingServicer_to_server(servicer, server): rpc_method_handlers = { @@ -2401,6 +2494,11 @@ def add_EarlyStoppingServicer_to_server(servicer, server): request_deserializer=SetTrialStatusRequest.FromString, response_serializer=SetTrialStatusReply.SerializeToString, ), + 'ValidateEarlyStoppingSettings': grpc.unary_unary_rpc_method_handler( + servicer.ValidateEarlyStoppingSettings, + request_deserializer=ValidateEarlyStoppingSettingsRequest.FromString, + response_serializer=ValidateEarlyStoppingSettingsReply.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'api.v1.beta1.EarlyStopping', rpc_method_handlers) @@ -2619,6 +2717,10 @@ def SetTrialStatus(self, request, context): # missing associated documentation comment in .proto file pass context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def ValidateEarlyStoppingSettings(self, request, context): + # missing associated documentation comment in .proto file + pass + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) class BetaEarlyStoppingStub(object): @@ -2640,6 +2742,11 @@ def SetTrialStatus(self, request, timeout, metadata=None, with_call=False, proto pass raise NotImplementedError() SetTrialStatus.future = None + def ValidateEarlyStoppingSettings(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + # missing associated documentation comment in .proto file + pass + raise NotImplementedError() + ValidateEarlyStoppingSettings.future = None def beta_create_EarlyStopping_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): @@ -2651,14 +2758,17 @@ def beta_create_EarlyStopping_server(servicer, pool=None, pool_size=None, defaul request_deserializers = { ('api.v1.beta1.EarlyStopping', 'GetEarlyStoppingRules'): GetEarlyStoppingRulesRequest.FromString, ('api.v1.beta1.EarlyStopping', 'SetTrialStatus'): SetTrialStatusRequest.FromString, + ('api.v1.beta1.EarlyStopping', 'ValidateEarlyStoppingSettings'): ValidateEarlyStoppingSettingsRequest.FromString, } response_serializers = { ('api.v1.beta1.EarlyStopping', 'GetEarlyStoppingRules'): GetEarlyStoppingRulesReply.SerializeToString, ('api.v1.beta1.EarlyStopping', 'SetTrialStatus'): SetTrialStatusReply.SerializeToString, + ('api.v1.beta1.EarlyStopping', 'ValidateEarlyStoppingSettings'): ValidateEarlyStoppingSettingsReply.SerializeToString, } method_implementations = { ('api.v1.beta1.EarlyStopping', 'GetEarlyStoppingRules'): face_utilities.unary_unary_inline(servicer.GetEarlyStoppingRules), ('api.v1.beta1.EarlyStopping', 'SetTrialStatus'): face_utilities.unary_unary_inline(servicer.SetTrialStatus), + ('api.v1.beta1.EarlyStopping', 'ValidateEarlyStoppingSettings'): face_utilities.unary_unary_inline(servicer.ValidateEarlyStoppingSettings), } server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) return beta_implementations.server(method_implementations, options=server_options) @@ -2673,14 +2783,17 @@ def beta_create_EarlyStopping_stub(channel, host=None, metadata_transformer=None request_serializers = { ('api.v1.beta1.EarlyStopping', 'GetEarlyStoppingRules'): GetEarlyStoppingRulesRequest.SerializeToString, ('api.v1.beta1.EarlyStopping', 'SetTrialStatus'): SetTrialStatusRequest.SerializeToString, + ('api.v1.beta1.EarlyStopping', 'ValidateEarlyStoppingSettings'): ValidateEarlyStoppingSettingsRequest.SerializeToString, } response_deserializers = { ('api.v1.beta1.EarlyStopping', 'GetEarlyStoppingRules'): GetEarlyStoppingRulesReply.FromString, ('api.v1.beta1.EarlyStopping', 'SetTrialStatus'): SetTrialStatusReply.FromString, + ('api.v1.beta1.EarlyStopping', 'ValidateEarlyStoppingSettings'): ValidateEarlyStoppingSettingsReply.FromString, } cardinalities = { 'GetEarlyStoppingRules': cardinality.Cardinality.UNARY_UNARY, 'SetTrialStatus': cardinality.Cardinality.UNARY_UNARY, + 'ValidateEarlyStoppingSettings': cardinality.Cardinality.UNARY_UNARY, } stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) return beta_implementations.dynamic_stub(channel, 'api.v1.beta1.EarlyStopping', cardinalities, options=stub_options) diff --git a/pkg/apis/manager/v1beta1/python/api_pb2_grpc.py b/pkg/apis/manager/v1beta1/python/api_pb2_grpc.py index 59a494edc5a..7d5cbf79006 100644 --- a/pkg/apis/manager/v1beta1/python/api_pb2_grpc.py +++ b/pkg/apis/manager/v1beta1/python/api_pb2_grpc.py @@ -170,6 +170,11 @@ def __init__(self, channel): request_serializer=api__pb2.SetTrialStatusRequest.SerializeToString, response_deserializer=api__pb2.SetTrialStatusReply.FromString, ) + self.ValidateEarlyStoppingSettings = channel.unary_unary( + '/api.v1.beta1.EarlyStopping/ValidateEarlyStoppingSettings', + request_serializer=api__pb2.ValidateEarlyStoppingSettingsRequest.SerializeToString, + response_deserializer=api__pb2.ValidateEarlyStoppingSettingsReply.FromString, + ) class EarlyStoppingServicer(object): @@ -191,6 +196,13 @@ def SetTrialStatus(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ValidateEarlyStoppingSettings(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_EarlyStoppingServicer_to_server(servicer, server): rpc_method_handlers = { @@ -204,6 +216,11 @@ def add_EarlyStoppingServicer_to_server(servicer, server): request_deserializer=api__pb2.SetTrialStatusRequest.FromString, response_serializer=api__pb2.SetTrialStatusReply.SerializeToString, ), + 'ValidateEarlyStoppingSettings': grpc.unary_unary_rpc_method_handler( + servicer.ValidateEarlyStoppingSettings, + request_deserializer=api__pb2.ValidateEarlyStoppingSettingsRequest.FromString, + response_serializer=api__pb2.ValidateEarlyStoppingSettingsReply.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'api.v1.beta1.EarlyStopping', rpc_method_handlers) diff --git a/pkg/controller.v1beta1/experiment/manifest/generator.go b/pkg/controller.v1beta1/experiment/manifest/generator.go index cdad38305c2..762f98c344f 100644 --- a/pkg/controller.v1beta1/experiment/manifest/generator.go +++ b/pkg/controller.v1beta1/experiment/manifest/generator.go @@ -38,6 +38,7 @@ type Generator interface { GetTrialTemplate(instance *experimentsv1beta1.Experiment) (string, error) GetRunSpecWithHyperParameters(experiment *experimentsv1beta1.Experiment, trialName, trialNamespace string, assignments []commonapiv1beta1.ParameterAssignment) (*unstructured.Unstructured, error) GetSuggestionConfigData(algorithmName string) (katibconfig.SuggestionConfig, error) + GetEarlyStoppingConfigData(algorithmName string) (katibconfig.EarlyStoppingConfig, error) GetMetricsCollectorConfigData(cKind commonapiv1beta1.CollectorKind) (katibconfig.MetricsCollectorConfig, error) } @@ -68,6 +69,11 @@ func (g *DefaultGenerator) GetSuggestionConfigData(algorithmName string) (katibc return katibconfig.GetSuggestionConfigData(algorithmName, g.client.GetClient()) } +// GetEarlyStoppingConfigData returns early stopping configuration for a given algorithm. +func (g *DefaultGenerator) GetEarlyStoppingConfigData(algorithmName string) (katibconfig.EarlyStoppingConfig, error) { + return katibconfig.GetEarlyStoppingConfigData(algorithmName, g.client.GetClient()) +} + // GetRunSpecWithHyperParameters returns the specification for trial with hyperparameters. func (g *DefaultGenerator) GetRunSpecWithHyperParameters(experiment *experimentsv1beta1.Experiment, trialName, trialNamespace string, assignments []commonapiv1beta1.ParameterAssignment) (*unstructured.Unstructured, error) { diff --git a/pkg/controller.v1beta1/suggestion/suggestion_controller.go b/pkg/controller.v1beta1/suggestion/suggestion_controller.go index 0c746588161..fec2cb44546 100644 --- a/pkg/controller.v1beta1/suggestion/suggestion_controller.go +++ b/pkg/controller.v1beta1/suggestion/suggestion_controller.go @@ -223,8 +223,7 @@ func (r *ReconcileSuggestion) ReconcileSuggestion(instance *suggestionsv1beta1.S // If early stopping is used, create RBAC. // If controller should reconcile RBAC, // ServiceAccount name must be equal to - - if instance.Spec.EarlyStopping != nil && instance.Spec.EarlyStopping.AlgorithmName != "" && - deploy.Spec.Template.Spec.ServiceAccountName == util.GetSuggestionRBACName(instance) { + if instance.Spec.EarlyStopping != nil && deploy.Spec.Template.Spec.ServiceAccountName == util.GetSuggestionRBACName(instance) { serviceAccount, role, roleBinding, err := r.DesiredRBAC(instance) if err != nil { @@ -275,6 +274,15 @@ func (r *ReconcileSuggestion) ReconcileSuggestion(instance *suggestionsv1beta1.S // return nil since it is a terminal condition return nil } + if instance.Spec.EarlyStopping != nil { + if err = r.ValidateEarlyStoppingSettings(instance, experiment); err != nil { + logger.Error(err, "Marking suggestion failed as early stopping settings validation failed") + msg := fmt.Sprintf("Validation failed: %v", err) + instance.MarkSuggestionStatusFailed(SuggestionFailedReason, msg) + // return nil since it is a terminal condition + return nil + } + } msg := "Suggestion is running" instance.MarkSuggestionStatusRunning(corev1.ConditionTrue, SuggestionRunningReason, msg) } diff --git a/pkg/controller.v1beta1/suggestion/suggestion_controller_test.go b/pkg/controller.v1beta1/suggestion/suggestion_controller_test.go index 4e29636e5ef..75b5bf3c160 100644 --- a/pkg/controller.v1beta1/suggestion/suggestion_controller_test.go +++ b/pkg/controller.v1beta1/suggestion/suggestion_controller_test.go @@ -19,6 +19,8 @@ package suggestion import ( "context" "encoding/json" + "fmt" + "strings" "sync" "testing" "time" @@ -47,12 +49,14 @@ import ( ) const ( - suggestionName = "test-suggestion" - resourceName = "test-suggestion-random" - namespace = "kubeflow" - suggestionImage = "test-image" - katibConfigName = "katib-config" - timeout = time.Second * 40 + suggestionName = "test-suggestion" + resourceName = "test-suggestion-random" + namespace = "kubeflow" + suggestionImage = "test-image" + katibConfigName = "katib-config" + timeout = time.Second * 40 + invalidAlgorithmSettingsSuggestionName = "invalid-algorithm-settings" + invalidEarlyStoppingSettingsSuggestionName = "invalid-earlystopping-settings" ) func init() { @@ -100,7 +104,20 @@ func TestReconcile(t *testing.T) { g.Expect(mgr.Start(context.TODO())).NotTo(gomega.HaveOccurred()) }() - mockSuggestionClient.EXPECT().ValidateAlgorithmSettings(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + mockSuggestionClient.EXPECT().ValidateAlgorithmSettings(gomock.Any(), gomock.Any()).DoAndReturn( + func(instance *suggestionsv1beta1.Suggestion, e *experimentsv1beta1.Experiment) error { + if e.Name == invalidAlgorithmSettingsSuggestionName { + return fmt.Errorf("ValidateAlgorithmSettings Error") + } + return nil + }).AnyTimes() + mockSuggestionClient.EXPECT().ValidateEarlyStoppingSettings(gomock.Any(), gomock.Any()).DoAndReturn( + func(instance *suggestionsv1beta1.Suggestion, e *experimentsv1beta1.Experiment) error { + if e.Name == invalidEarlyStoppingSettingsSuggestionName { + return fmt.Errorf("ValidateEarlyStoppingSettings Error") + } + return nil + }).AnyTimes() mockSuggestionClient.EXPECT().SyncAssignments(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() instance := newFakeInstance() @@ -130,6 +147,7 @@ func TestReconcile(t *testing.T) { Name: namespace, }, } + g.Expect(c.Create(context.TODO(), kubeflowNS)).NotTo(gomega.HaveOccurred()) // Test 1 - Early stopping suggestion run // Create ConfigMap with suggestion and early stopping data. @@ -265,6 +283,123 @@ func TestReconcile(t *testing.T) { // Test 4 - Update status condition for empty experiment g.Expect(r.updateStatusCondition(&suggestionsv1beta1.Suggestion{}, oldS)).To(gomega.HaveOccurred()) + // Delete the experiment + g.Expect(c.Delete(context.TODO(), experiment)).NotTo(gomega.HaveOccurred()) + + // Expect that experiment is deleted + g.Eventually(func() bool { + return errors.IsNotFound(c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: suggestionName}, &experimentsv1beta1.Experiment{})) + }, timeout).Should(gomega.BeTrue()) + + // Test 5 - ValidateAlgorithmSettings returns error + experiment = &experimentsv1beta1.Experiment{ + ObjectMeta: metav1.ObjectMeta{ + Name: invalidAlgorithmSettingsSuggestionName, + Namespace: namespace, + }, + } + instance = newFakeInstance() + instance.Name = invalidAlgorithmSettingsSuggestionName + invalidResourceName := strings.Join([]string{invalidAlgorithmSettingsSuggestionName, "random"}, "-") + suggestionDeploy = &appsv1.Deployment{} + + // Create the suggestion + g.Expect(c.Create(context.TODO(), instance)).NotTo(gomega.HaveOccurred()) + // Create experiment + g.Expect(c.Create(context.TODO(), experiment)).NotTo(gomega.HaveOccurred()) + + // Expect deployment with appropriate name is created + g.Eventually(func() error { + return c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidResourceName}, suggestionDeploy) + }, timeout).Should(gomega.Succeed()) + + // Manually change ready deployment status + suggestionDeploy.Status = appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, + }, + }, + } + + g.Expect(c.Status().Update(context.TODO(), suggestionDeploy)).NotTo(gomega.HaveOccurred()) + + // Expect that suggestion status is failed + suggestion = &suggestionsv1beta1.Suggestion{} + g.Eventually(func() bool { + if err = c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidAlgorithmSettingsSuggestionName}, suggestion); err != nil { + return false + } + return suggestion.IsFailed() + }, timeout).Should(gomega.BeTrue()) + + // Delete the experiment + g.Expect(c.Delete(context.TODO(), experiment)).NotTo(gomega.HaveOccurred()) + + // Expect that experiment is deleted + g.Eventually(func() bool { + return errors.IsNotFound(c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidAlgorithmSettingsSuggestionName}, &experimentsv1beta1.Experiment{})) + }, timeout).Should(gomega.BeTrue()) + + // Delete the suggestion + g.Expect(c.Delete(context.TODO(), instance)).NotTo(gomega.HaveOccurred()) + + // Expect that suggestion is deleted + g.Eventually(func() bool { + return errors.IsNotFound(c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidAlgorithmSettingsSuggestionName}, &suggestionsv1beta1.Suggestion{})) + }, timeout).Should(gomega.BeTrue()) + + // Delete the deployment is deleted + g.Expect(c.Delete(context.TODO(), suggestionDeploy)).NotTo(gomega.HaveOccurred()) + + // Expect that deployment is deleted + g.Eventually(func() bool { + return errors.IsNotFound(c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidResourceName}, &appsv1.Deployment{})) + }, timeout).Should(gomega.BeTrue()) + + // Test 6 - ValidateEarlyStoppingSettings returns error + experiment = &experimentsv1beta1.Experiment{ + ObjectMeta: metav1.ObjectMeta{ + Name: invalidEarlyStoppingSettingsSuggestionName, + Namespace: namespace, + }, + } + instance = newFakeInstance() + instance.Name = invalidEarlyStoppingSettingsSuggestionName + invalidResourceName = strings.Join([]string{invalidEarlyStoppingSettingsSuggestionName, "random"}, "-") + + // Create the suggestion + g.Expect(c.Create(context.TODO(), instance)).NotTo(gomega.HaveOccurred()) + // Create experiment + g.Expect(c.Create(context.TODO(), experiment)).NotTo(gomega.HaveOccurred()) + + // Expect deployment with appropriate name is created + g.Eventually(func() error { + return c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidResourceName}, suggestionDeploy) + }, timeout).Should(gomega.Succeed()) + + // Manually change ready deployment status + suggestionDeploy.Status = appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, + }, + }, + } + + g.Expect(c.Status().Update(context.TODO(), suggestionDeploy)).NotTo(gomega.HaveOccurred()) + + // Expect that suggestion status is failed + suggestion = &suggestionsv1beta1.Suggestion{} + g.Eventually(func() bool { + if err = c.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: invalidEarlyStoppingSettingsSuggestionName}, suggestion); err != nil { + return false + } + return suggestion.IsFailed() + }, timeout).Should(gomega.BeTrue()) + } func newFakeInstance() *suggestionsv1beta1.Suggestion { diff --git a/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient.go b/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient.go index f64c3255227..de161f023f0 100644 --- a/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient.go +++ b/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient.go @@ -52,6 +52,11 @@ var ( getRPCClientEarlyStopping = func(conn *grpc.ClientConn) suggestionapi.EarlyStoppingClient { return suggestionapi.NewEarlyStoppingClient(conn) } + + callValidatorOpts = []grpc_retry.CallOption{ + grpc_retry.WithBackoff(grpc_retry.BackoffLinear(consts.DefaultGRPCRetryPeriod)), + grpc_retry.WithMax(consts.DefaultGRPCRetryAttempts), + } ) // SuggestionClient is the interface to communicate with algorithm services. @@ -60,6 +65,7 @@ type SuggestionClient interface { ts []trialsv1beta1.Trial) error ValidateAlgorithmSettings(instance *suggestionsv1beta1.Suggestion, e *experimentsv1beta1.Experiment) error + ValidateEarlyStoppingSettings(instance *suggestionsv1beta1.Suggestion, e *experimentsv1beta1.Experiment) error } // General is the implementation for SuggestionClient. @@ -124,7 +130,7 @@ func (g *General) SyncAssignments( earlyStoppingRules := []commonapiv1beta1.EarlyStoppingRule{} // If early stopping is set, call GetEarlyStoppingRules after GetSuggestions. - if instance.Spec.EarlyStopping != nil && instance.Spec.EarlyStopping.AlgorithmName != "" { + if instance.Spec.EarlyStopping != nil { endpoint = util.GetEarlyStoppingEndpoint(instance) connEarlyStopping, err := grpc.Dial(endpoint, grpc.WithInsecure()) if err != nil { @@ -184,13 +190,9 @@ func (g *General) ValidateAlgorithmSettings(instance *suggestionsv1beta1.Suggest logger := log.WithValues("Suggestion", types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()}) endpoint := util.GetAlgorithmEndpoint(instance) - callOpts := []grpc_retry.CallOption{ - grpc_retry.WithBackoff(grpc_retry.BackoffLinear(consts.DefaultGRPCRetryPeriod)), - grpc_retry.WithMax(consts.DefaultGRPCRetryAttempts), - } conn, err := grpc.Dial(endpoint, grpc.WithInsecure(), - grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(callOpts...)), - grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(callOpts...)), + grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(callValidatorOpts...)), + grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(callValidatorOpts...)), ) if err != nil { return err @@ -227,7 +229,55 @@ func (g *General) ValidateAlgorithmSettings(instance *suggestionsv1beta1.Suggest logger.Info("Method ValidateAlgorithmSettings not found", "Suggestion service", e.Spec.Algorithm.AlgorithmName) return nil } - logger.Info("Algorithm settings validated") + logger.Info("Algorithm settings are validated") + return nil +} + +// ValidateEarlyStoppingSettings validates if the algorithm specific configurations for early stopping are valid. +func (g *General) ValidateEarlyStoppingSettings(instance *suggestionsv1beta1.Suggestion, e *experimentsv1beta1.Experiment) error { + logger := log.WithValues("EarlyStopping", types.NamespacedName{Name: instance.GetName(), Namespace: instance.GetNamespace()}) + endpoint := util.GetEarlyStoppingEndpoint(instance) + + conn, err := grpc.Dial(endpoint, grpc.WithInsecure(), + grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(callValidatorOpts...)), + grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(callValidatorOpts...)), + ) + if err != nil { + return err + } + defer conn.Close() + + rpcClient := getRPCClientEarlyStopping(conn) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + request := &suggestionapi.ValidateEarlyStoppingSettingsRequest{ + EarlyStopping: g.ConvertExperiment(e).Spec.EarlyStopping, + } + + // See https://github.com/grpc/grpc-go/issues/2636 + // See https://github.com/grpc/grpc-go/pull/2503 + _, err = rpcClient.ValidateEarlyStoppingSettings(ctx, request, grpc.WaitForReady(true)) + statusCode, _ := status.FromError(err) + + // validation error + if statusCode.Code() == codes.InvalidArgument || statusCode.Code() == codes.Unknown { + logger.Error(err, "ValidateEarlyStoppingSettings error") + return fmt.Errorf("ValidateEarlyStoppingSettings Error: %v", statusCode.Message()) + } + + // Connection error + if statusCode.Code() == codes.Unavailable { + logger.Error(err, "Connection to EarlyStopping algorithm service currently unavailable") + return err + } + + // Validate to true as function is not implemented + if statusCode.Code() == codes.Unimplemented { + logger.Info("Method ValidateEarlyStoppingSettings not found", "EarlyStopping service", e.Spec.EarlyStopping.AlgorithmName) + return nil + } + logger.Info("EarlyStopping settings are validated") return nil } diff --git a/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient_test.go b/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient_test.go index 506e82a4274..cf69bcdeda6 100644 --- a/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient_test.go +++ b/pkg/controller.v1beta1/suggestion/suggestionclient/suggestionclient_test.go @@ -330,6 +330,85 @@ func TestValidateAlgorithmSettings(t *testing.T) { } } +func TestValidateEarlyStoppingSettings(t *testing.T) { + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + rpcClientEarlyStopping := suggestionapimock.NewMockEarlyStoppingClient(mockCtrl) + + getRPCClientEarlyStopping = func(conn *grpc.ClientConn) suggestionapi.EarlyStoppingClient { + return rpcClientEarlyStopping + } + + expectedRequest := &suggestionapi.ValidateEarlyStoppingSettingsRequest{ + EarlyStopping: newFakeRequest().Experiment.Spec.EarlyStopping, + } + + validRun := rpcClientEarlyStopping.EXPECT().ValidateEarlyStoppingSettings(gomock.Any(), k8sMatcher{expectedRequest}, gomock.Any()).Return(nil, nil) + + invalidExperiment := rpcClientEarlyStopping.EXPECT().ValidateEarlyStoppingSettings(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, + status.Error(codes.InvalidArgument, "Invalid experiment parameter")) + connectionError := rpcClientEarlyStopping.EXPECT().ValidateEarlyStoppingSettings(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, + status.Error(codes.Unavailable, "Unable to connect")) + unimplementedMethod := rpcClientEarlyStopping.EXPECT().ValidateEarlyStoppingSettings(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, + status.Error(codes.Unimplemented, "Method not implemented")) + + suggestionClient := New() + + exp := newFakeExperiment() + sug := newFakeSuggestion() + + gomock.InOrder( + validRun, + invalidExperiment, + connectionError, + unimplementedMethod) + + tcs := []struct { + Experiment *experimentsv1beta1.Experiment + Suggestion *suggestionsv1beta1.Suggestion + Err bool + TestDescription string + }{ + // validRun case + { + Experiment: exp, + Suggestion: sug, + Err: false, + TestDescription: "ValidateEarlyStoppingSettings valid run", + }, + // invalidExperiment case + { + Experiment: exp, + Suggestion: sug, + Err: true, + TestDescription: "Invalid argument return in Experiment validation", + }, + // connectionError case + { + Experiment: exp, + Suggestion: sug, + Err: true, + TestDescription: "Connection to early stopping service error", + }, + // unimplementedMethod case + { + Experiment: exp, + Suggestion: sug, + Err: false, + TestDescription: "Unimplemented ValidateEarlyStoppingSettings method", + }, + } + for _, tc := range tcs { + err := suggestionClient.ValidateEarlyStoppingSettings(tc.Suggestion, tc.Experiment) + if !tc.Err && err != nil { + t.Errorf("Case: %v failed. Expected nil, got %v", tc.TestDescription, err) + } else if tc.Err && err == nil { + t.Errorf("Case: %v failed. Expected err, got nil", tc.TestDescription) + } + } +} + func TestConvertTrialConditionType(t *testing.T) { tcs := []struct { diff --git a/pkg/earlystopping/v1beta1/medianstop/service.py b/pkg/earlystopping/v1beta1/medianstop/service.py index 0952491b0eb..3d212fbb4e6 100644 --- a/pkg/earlystopping/v1beta1/medianstop/service.py +++ b/pkg/earlystopping/v1beta1/medianstop/service.py @@ -64,6 +64,39 @@ def __init__(self): self.api_instance = client.CustomObjectsApi() + def ValidateEarlyStoppingSettings(self, request, context): + is_valid, message = self.validate_early_stopping_spec(request.early_stopping) + if not is_valid: + context.set_code(grpc.StatusCode.INVALID_ARGUMENT) + context.set_details(message) + logger.error(message) + return api_pb2.ValidateEarlyStoppingSettingsReply() + + def validate_early_stopping_spec(self, early_stopping_spec): + algorithm_name = early_stopping_spec.algorithm_name + if algorithm_name == "medianstop": + return self.validate_medianstop_setting(early_stopping_spec.algorithm_settings) + else: + return False, "unknown algorithm name {}".format(algorithm_name) + + @staticmethod + def validate_medianstop_setting(early_stopping_settings): + for setting in early_stopping_settings: + try: + if setting.name == "min_trials_required": + if not (int(setting.value) > 0): + return False, "min_trials_required must be greater than zero (>0)" + elif setting.name == "start_step": + if not (int(setting.value) >= 1): + return False, "start_step must be greater or equal than one (>=1)" + else: + return False, "unknown setting {} for algorithm medianstop".format(setting.name) + + except Exception as e: + return False, "failed to validate {}({}): {}".format(setting.name, setting.value, e) + + return True, "" + def GetEarlyStoppingRules(self, request, context): logger.info("Get new early stopping rules") @@ -71,7 +104,7 @@ def GetEarlyStoppingRules(self, request, context): if self.is_first_run: self.is_first_run = False # Get early stopping settings. - self.getEarlyStoppingSettings(request.experiment.spec.early_stopping.algorithm_settings) + self.get_early_stopping_settings(request.experiment.spec.early_stopping.algorithm_settings) logger.info("Median stopping settings are: min_trials_required: {}, start_step: {}".format( self.min_trials_required, self.start_step)) @@ -90,7 +123,7 @@ def GetEarlyStoppingRules(self, request, context): early_stopping_rules = [] - median = self.getMedianValue(request.trials) + median = self.get_median_value(request.trials) if median is not None: early_stopping_rules.append(api_pb2.EarlyStoppingRule( name=self.objective_metric, @@ -104,14 +137,14 @@ def GetEarlyStoppingRules(self, request, context): early_stopping_rules=early_stopping_rules ) - def getEarlyStoppingSettings(self, early_stopping_settings): + def get_early_stopping_settings(self, early_stopping_settings): for setting in early_stopping_settings: if setting.name == "min_trials_required": self.min_trials_required = int(setting.value) elif setting.name == "start_step": self.start_step = int(setting.value) - def getMedianValue(self, trials): + def get_median_value(self, trials): for trial in trials: # Get metrics only for the new succeeded Trials. if trial.name not in self.trials_avg_history and trial.status.condition == SUCCEEDED_TRIAL: diff --git a/pkg/mock/v1beta1/api/earlystopping.go b/pkg/mock/v1beta1/api/earlystopping.go index be5eaf77d85..416269d6eaf 100644 --- a/pkg/mock/v1beta1/api/earlystopping.go +++ b/pkg/mock/v1beta1/api/earlystopping.go @@ -75,3 +75,23 @@ func (mr *MockEarlyStoppingClientMockRecorder) SetTrialStatus(arg0, arg1 interfa varargs := append([]interface{}{arg0, arg1}, arg2...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTrialStatus", reflect.TypeOf((*MockEarlyStoppingClient)(nil).SetTrialStatus), varargs...) } + +// ValidateEarlyStoppingSettings mocks base method. +func (m *MockEarlyStoppingClient) ValidateEarlyStoppingSettings(arg0 context.Context, arg1 *api_v1_beta1.ValidateEarlyStoppingSettingsRequest, arg2 ...grpc.CallOption) (*api_v1_beta1.ValidateEarlyStoppingSettingsReply, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ValidateEarlyStoppingSettings", varargs...) + ret0, _ := ret[0].(*api_v1_beta1.ValidateEarlyStoppingSettingsReply) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ValidateEarlyStoppingSettings indicates an expected call of ValidateEarlyStoppingSettings. +func (mr *MockEarlyStoppingClientMockRecorder) ValidateEarlyStoppingSettings(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateEarlyStoppingSettings", reflect.TypeOf((*MockEarlyStoppingClient)(nil).ValidateEarlyStoppingSettings), varargs...) +} diff --git a/pkg/mock/v1beta1/experiment/manifest/generator.go b/pkg/mock/v1beta1/experiment/manifest/generator.go index c4b6b88808a..462a15e58c4 100644 --- a/pkg/mock/v1beta1/experiment/manifest/generator.go +++ b/pkg/mock/v1beta1/experiment/manifest/generator.go @@ -38,6 +38,21 @@ func (m *MockGenerator) EXPECT() *MockGeneratorMockRecorder { return m.recorder } +// GetEarlyStoppingConfigData mocks base method. +func (m *MockGenerator) GetEarlyStoppingConfigData(arg0 string) (katibconfig.EarlyStoppingConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEarlyStoppingConfigData", arg0) + ret0, _ := ret[0].(katibconfig.EarlyStoppingConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEarlyStoppingConfigData indicates an expected call of GetEarlyStoppingConfigData. +func (mr *MockGeneratorMockRecorder) GetEarlyStoppingConfigData(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEarlyStoppingConfigData", reflect.TypeOf((*MockGenerator)(nil).GetEarlyStoppingConfigData), arg0) +} + // GetMetricsCollectorConfigData mocks base method. func (m *MockGenerator) GetMetricsCollectorConfigData(arg0 v1beta1.CollectorKind) (katibconfig.MetricsCollectorConfig, error) { m.ctrl.T.Helper() diff --git a/pkg/mock/v1beta1/suggestion/suggestionclient/suggestionclient.go b/pkg/mock/v1beta1/suggestion/suggestionclient/suggestionclient.go index 400e3740bf5..f6ef886d773 100644 --- a/pkg/mock/v1beta1/suggestion/suggestionclient/suggestionclient.go +++ b/pkg/mock/v1beta1/suggestion/suggestionclient/suggestionclient.go @@ -63,3 +63,17 @@ func (mr *MockSuggestionClientMockRecorder) ValidateAlgorithmSettings(arg0, arg1 mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAlgorithmSettings", reflect.TypeOf((*MockSuggestionClient)(nil).ValidateAlgorithmSettings), arg0, arg1) } + +// ValidateEarlyStoppingSettings mocks base method. +func (m *MockSuggestionClient) ValidateEarlyStoppingSettings(arg0 *v1beta10.Suggestion, arg1 *v1beta1.Experiment) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateEarlyStoppingSettings", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateEarlyStoppingSettings indicates an expected call of ValidateEarlyStoppingSettings. +func (mr *MockSuggestionClientMockRecorder) ValidateEarlyStoppingSettings(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateEarlyStoppingSettings", reflect.TypeOf((*MockSuggestionClient)(nil).ValidateEarlyStoppingSettings), arg0, arg1) +} diff --git a/pkg/webhook/v1beta1/experiment/validator/validator.go b/pkg/webhook/v1beta1/experiment/validator/validator.go index a9e01fa4f34..32a17be2850 100644 --- a/pkg/webhook/v1beta1/experiment/validator/validator.go +++ b/pkg/webhook/v1beta1/experiment/validator/validator.go @@ -116,6 +116,9 @@ func (g *DefaultValidator) ValidateExperiment(instance, oldInst *experimentsv1be if err := g.validateAlgorithm(instance.Spec.Algorithm); err != nil { return err } + if err := g.validateEarlyStopping(instance.Spec.EarlyStopping); err != nil { + return err + } if err := g.validateResumePolicy(instance.Spec.ResumePolicy); err != nil { return err } @@ -172,6 +175,21 @@ func (g *DefaultValidator) validateAlgorithm(ag *commonapiv1beta1.AlgorithmSpec) return nil } +func (g *DefaultValidator) validateEarlyStopping(es *commonapiv1beta1.EarlyStoppingSpec) error { + if es == nil { + return nil + } + if es.AlgorithmName == "" { + return fmt.Errorf("no spec.earlyStopping.algorithmName specified") + } + + if _, err := g.GetEarlyStoppingConfigData(es.AlgorithmName); err != nil { + return fmt.Errorf("unable to get EarlyStopping config data for algorithm %s: %v", es.AlgorithmName, err) + } + + return nil +} + func (g *DefaultValidator) validateResumePolicy(resume experimentsv1beta1.ResumePolicyType) error { validTypes := map[experimentsv1beta1.ResumePolicyType]string{ "": "", diff --git a/pkg/webhook/v1beta1/experiment/validator/validator_test.go b/pkg/webhook/v1beta1/experiment/validator/validator_test.go index b7be4fea557..43930c7835b 100644 --- a/pkg/webhook/v1beta1/experiment/validator/validator_test.go +++ b/pkg/webhook/v1beta1/experiment/validator/validator_test.go @@ -53,9 +53,11 @@ func TestValidateExperiment(t *testing.T) { suggestionConfigData.Image = "algorithmImage" metricsCollectorConfigData := katibconfig.MetricsCollectorConfig{} metricsCollectorConfigData.Image = "metricsCollectorImage" + earlyStoppingConfigData := katibconfig.EarlyStoppingConfig{} p.EXPECT().GetSuggestionConfigData(gomock.Any()).Return(suggestionConfigData, nil).AnyTimes() p.EXPECT().GetMetricsCollectorConfigData(gomock.Any()).Return(metricsCollectorConfigData, nil).AnyTimes() + p.EXPECT().GetEarlyStoppingConfigData(gomock.Any()).Return(earlyStoppingConfigData, nil).AnyTimes() batchJobStr := convertBatchJobToString(newFakeBatchJob()) p.EXPECT().GetTrialTemplate(gomock.Any()).Return(batchJobStr, nil).AnyTimes() @@ -78,7 +80,7 @@ func TestValidateExperiment(t *testing.T) { Err: true, testDescription: "Name is invalid", }, - //Objective + // Objective { Instance: func() *experimentsv1beta1.Experiment { i := newFakeInstance() @@ -106,7 +108,7 @@ func TestValidateExperiment(t *testing.T) { Err: true, testDescription: "Objective metric name is empty", }, - //Algorithm + // Algorithm { Instance: func() *experimentsv1beta1.Experiment { i := newFakeInstance() @@ -125,6 +127,25 @@ func TestValidateExperiment(t *testing.T) { Err: true, testDescription: "Algorithm name is empty", }, + // EarlyStopping + { + Instance: func() *experimentsv1beta1.Experiment { + i := newFakeInstance() + i.Spec.EarlyStopping = nil + return i + }(), + Err: false, + testDescription: "EarlyStopping is nil", + }, + { + Instance: func() *experimentsv1beta1.Experiment { + i := newFakeInstance() + i.Spec.EarlyStopping.AlgorithmName = "" + return i + }(), + Err: true, + testDescription: "EarlyStopping AlgorithmName is empty", + }, // Valid Experiment { Instance: newFakeInstance(), @@ -952,12 +973,20 @@ func TestValidateConfigData(t *testing.T) { suggestionConfigData := katibconfig.SuggestionConfig{} suggestionConfigData.Image = "algorithmImage" - validConfigCall := p.EXPECT().GetSuggestionConfigData(gomock.Any()).Return(suggestionConfigData, nil) + validConfigCall := p.EXPECT().GetSuggestionConfigData(gomock.Any()).Return(suggestionConfigData, nil).Times(2) invalidConfigCall := p.EXPECT().GetSuggestionConfigData(gomock.Any()).Return(katibconfig.SuggestionConfig{}, errors.New("GetSuggestionConfigData failed")) gomock.InOrder( - invalidConfigCall, validConfigCall, + invalidConfigCall, + ) + + validEarlyStoppingConfigCall := p.EXPECT().GetEarlyStoppingConfigData(gomock.Any()).Return(katibconfig.EarlyStoppingConfig{}, nil) + invalidEarlyStoppingConfigCall := p.EXPECT().GetEarlyStoppingConfigData(gomock.Any()).Return(katibconfig.EarlyStoppingConfig{}, errors.New("GetEarlyStoppingConfigData failed")) + + gomock.InOrder( + validEarlyStoppingConfigCall, + invalidEarlyStoppingConfigCall, ) p.EXPECT().GetMetricsCollectorConfigData(gomock.Any()).Return(katibconfig.MetricsCollectorConfig{}, errors.New("GetMetricsCollectorConfigData failed")) @@ -971,11 +1000,15 @@ func TestValidateConfigData(t *testing.T) { }{ { Instance: newFakeInstance(), - testDescription: "Get suggestion config data error", + testDescription: "Get metrics collector config data error", }, { Instance: newFakeInstance(), - testDescription: "Get metrics collector config data error", + testDescription: "Get early stopping config data error", + }, + { + Instance: newFakeInstance(), + testDescription: "Get suggestion config data error", }, } @@ -1017,6 +1050,15 @@ func newFakeInstance() *experimentsv1beta1.Experiment { }, }, }, + EarlyStopping: &commonv1beta1.EarlyStoppingSpec{ + AlgorithmName: "test", + AlgorithmSettings: []commonv1beta1.EarlyStoppingSetting{ + { + Name: "test1", + Value: "value1", + }, + }, + }, Parameters: []experimentsv1beta1.ParameterSpec{ { ParameterType: experimentsv1beta1.ParameterTypeInt, diff --git a/test/unit/v1beta1/earlystopping/test_medianstop_service.py b/test/unit/v1beta1/earlystopping/test_medianstop_service.py index 5da7e00cdc9..640fcf50559 100644 --- a/test/unit/v1beta1/earlystopping/test_medianstop_service.py +++ b/test/unit/v1beta1/earlystopping/test_medianstop_service.py @@ -21,6 +21,8 @@ from pkg.earlystopping.v1beta1.medianstop.service import MedianStopService +import utils + class TestMedianStop(unittest.TestCase): def setUp(self): @@ -37,8 +39,78 @@ def setUp(self): self.test_server = grpc_testing.server_from_dictionary( servicers, grpc_testing.strict_real_time()) - def test_get_earlystopping_rules(self): + def test_validate_early_stopping_settings(self): + # Valid cases + early_stopping = api_pb2.EarlyStoppingSpec( + algorithm_name="medianstop", + algorithm_settings=[ + api_pb2.EarlyStoppingSetting( + name="min_trials_required", + value="2", + ), + api_pb2.EarlyStoppingSetting( + name="start_step", + value="5", + ), + ], + ) + + _, _, code, _ = utils.call_validate(self.test_server, early_stopping) + self.assertEqual(code, grpc.StatusCode.OK) + + # Invalid cases + # Unknown algorithm name + early_stopping = api_pb2.EarlyStoppingSpec(algorithm_name="unknown") + + _, _, code, details = utils.call_validate(self.test_server, early_stopping) + self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT) + self.assertEqual(details, "unknown algorithm name unknown") + + # Unknown config name + early_stopping = api_pb2.EarlyStoppingSpec( + algorithm_name="medianstop", + algorithm_settings=[ + api_pb2.EarlyStoppingSetting( + name="unknown_conf", + value="100", + ), + ], + ) + + _, _, code, details = utils.call_validate(self.test_server, early_stopping) + self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT) + self.assertEqual(details, "unknown setting unknown_conf for algorithm medianstop") + + # Wrong min_trials_required + early_stopping = api_pb2.EarlyStoppingSpec( + algorithm_name="medianstop", + algorithm_settings=[ + api_pb2.EarlyStoppingSetting( + name="min_trials_required", + value="0", + ), + ], + ) + _, _, code, details = utils.call_validate(self.test_server, early_stopping) + self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT) + self.assertEqual(details, "min_trials_required must be greater than zero (>0)") + + # Wrong start_step + early_stopping = api_pb2.EarlyStoppingSpec( + algorithm_name="medianstop", + algorithm_settings=[ + api_pb2.EarlyStoppingSetting( + name="start_step", + value="0", + ), + ], + ) + _, _, code, details = utils.call_validate(self.test_server, early_stopping) + self.assertEqual(code, grpc.StatusCode.INVALID_ARGUMENT) + self.assertEqual(details, "start_step must be greater or equal than one (>=1)") + + def test_get_earlystopping_rules(self): # TODO (andreyvelich): Add more informative tests. trials = [ api_pb2.Trial( @@ -61,8 +133,8 @@ def test_get_earlystopping_rules(self): get_earlystopping_rules = self.test_server.invoke_unary_unary( method_descriptor=(api_pb2.DESCRIPTOR - .services_by_name['EarlyStopping'] - .methods_by_name['GetEarlyStoppingRules']), + .services_by_name['EarlyStopping'] + .methods_by_name['GetEarlyStoppingRules']), invocation_metadata={}, request=request, timeout=1) diff --git a/test/unit/v1beta1/earlystopping/utils.py b/test/unit/v1beta1/earlystopping/utils.py new file mode 100644 index 00000000000..49424b950fe --- /dev/null +++ b/test/unit/v1beta1/earlystopping/utils.py @@ -0,0 +1,15 @@ +from pkg.apis.manager.v1beta1.python import api_pb2 + + +def call_validate(test_server, early_stopping): + request = api_pb2.ValidateEarlyStoppingSettingsRequest(early_stopping=early_stopping) + validate_early_stopping_settings = test_server.invoke_unary_unary( + method_descriptor=(api_pb2.DESCRIPTOR + .services_by_name['EarlyStopping'] + .methods_by_name['ValidateEarlyStoppingSettings']), + invocation_metadata={}, + request=request, timeout=1) + + response, metadata, code, details = validate_early_stopping_settings.termination() + + return response, metadata, code, details