https://flyte.org logo
#ask-the-community
Title
# ask-the-community
y

Yubo Wang

02/07/2023, 11:16 PM
Hi community, are there plans on supporting more complicated logic for conditions. As noted on the Flyte documentation:
Copy code
Conditions are limited to certain binary and logical operators and can only be performed on primitive values.
d

Dan Rammer (hamersaw)

02/07/2023, 11:17 PM
Hey Yubo! What kind of conditions did you have in mind?
y

Yubo Wang

02/07/2023, 11:18 PM
I am thinking about non-primitive types, like we define some custom objects and expose a function that conditional can depend on for the evaluation
@Ankit Goyal FYI
a

Ankit Goyal

02/07/2023, 11:20 PM
@Yubo Wang perhaps a specific example would be helpful to share?
d

Dan Rammer (hamersaw)

02/07/2023, 11:21 PM
Can you mock up a python example maybe?
y

Yubo Wang

02/07/2023, 11:21 PM
in a sec
Copy code
@dataclass_json
@dataclass
class TFTrainerConfig(object):
    dataset_config: DatasetLoaderConfig
    hyperparameters: Hyperparameters
    column_names: List[str]
    model_code: str
    batch_size: int
    num_training_steps: int
    num_eval_steps: int
    num_eval_frequency: int
    model_output_names_map: Optional[dict]

@workflow
def tf2_trainer_wf(trainer_config: TFTrainerConfig):
    res = conditonal("batch_size_greater")
          .if_(trainer_config.batch_size > 10)
          .then()
something like this
and also something like this:
Copy code
@workflow
def tf2_trainer_wf(trainer_config: TFTrainerConfig):
    res = conditonal("batch_size_greater")
          .if_(trainer_config.model_output_names_map not None)
          .then()
d

Dan Rammer (hamersaw)

02/07/2023, 11:28 PM
Yeah, so this would be very difficult to do using conditionals. Conditionals are evaluated using BranchNodes within propeller, which are able to be processed interally given the simple boolean logic. For this, you would basically need to spin up a Flyte task to evaluate. It really doesn't fit the current BranchNode setup. I'm wondering if this can be done with dynamic tasks though:
Copy code
@task
def process_success(...):
    # foo

@dynamic
def tf2_trainer_wf(trainer_config: TFTrainerConfig):
    trainer_config.batch_size > 10:
        process_success()
of course this spins up a separate Pod to process this and compiles / injects a new DAG. So there is some level of overhead.
Or you could have a separate task to return the condition variable:
Copy code
@task
def process(...) bool:
    return trainer_config.model_output_names_map == None

@workflow
def tf2_trainer_wf(trainer_config: TFTrainerConfig):
    condition = process(trainer_config)

    res = conditonal("batch_size_greater")
          .if_(condition)
          .then()
which also has some level of overhead obviously.
y

Yubo Wang

02/07/2023, 11:31 PM
thanks for the suggestion, but we were trying to avoid dynamic workflows due to the overhead.
d

Dan Rammer (hamersaw)

02/07/2023, 11:32 PM
sure, makes plenty of sense.
y

Yubo Wang

02/07/2023, 11:32 PM
I am looking into the implementation of BranchNode
a

Ankit Goyal

02/07/2023, 11:35 PM
so is the only thing that doesn't work here is that
trainer_config
is a dataclass? If it was just an int, it would work; right?
y

Yubo Wang

02/07/2023, 11:36 PM
yes, that is what I am doing for now
inputting as flags like
use_model_bundle_creator
interesting, @Dan Rammer (hamersaw) Does condition support chaining? When I put
Copy code
@workflow
def tf2_trainer_wf(use_model_bundle_creator: bool):
    trainer_res = trainer_task()
    res = conditional("use_model_bundle_creator").if_(use_model_bundle_creator.is_true()).then(model_bundle_creator())
    trainer_res >> res
I got
AttributeError: 'Condition' object has no attribute 'ref'
d

Dan Rammer (hamersaw)

02/07/2023, 11:42 PM
@Eduardo Apolinario (eapolinario) how are
dataclasses
stored as literals? If there was some way to encode the specific field of the dataclass in a
Literal
proto then in propeller when we evaluate in the BranchNode you could look up the field and return the primitive value.
re: chaining - another question for eduardo. I handle mostly backend stuff and can't speak for flytekit syntax with any authority 😅 cc @Niels Bantilan
y

Yubo Wang

02/07/2023, 11:45 PM
Thanks Dan!
d

Dan Rammer (hamersaw)

02/07/2023, 11:46 PM
No problem. Let me know if you find anything in BranchNode implementation. I just took a quick look, I think with some changes to Literal if we can parse things our correctly from flytekit the backend may be able to retrieve the primitive value. We would have to have a larger discussion on this, but it could be very useful.
e

Eduardo Apolinario (eapolinario)

02/08/2023, 1:34 AM
@Dan Rammer (hamersaw), sorry for the delay, was afk for a bunch of hours. Regarding how we store
dataclasses
as literals. We lean pretty heavily on protobuf Struct.
y

Yubo Wang

02/08/2023, 1:39 AM
hey @Eduardo Apolinario (eapolinario) thanks for looking at this. so this means that we can actually implement some parsing as long as the input is decorated with @dataclass_json?
e

Eduardo Apolinario (eapolinario)

02/08/2023, 1:42 AM
@Yubo Wang, yeah, I think so. We'd need to change a few things in the implementation of conditionals in propeller, but nothing dramatic AFAIU. Dan to correct me.
y

Yubo Wang

02/08/2023, 1:47 AM
Another question regarding to conditionals, seems to me that the conditionals do not support empty else clause for example:
Copy code
conditional("use_model_bundle_creator").if_(use_model_bundle_creator.is_true()).then(model_bundle_creator()).else_()
s

Samhita Alla

02/08/2023, 5:26 AM
Yeah. Empty
else
isn't supported. I think it makes sense to mandatorily input what needs to be done in case
if
isn't traversed.
y

Yubo Wang

02/08/2023, 7:16 AM
what if I expected nothing to be done for the else clause
s

Samhita Alla

02/08/2023, 8:47 AM
That isn't possible. You either need to call a task or initialize
fail
n

Niels Bantilan

02/08/2023, 3:12 PM
the
conditional
construct is more like
Copy code
x = 0 if cond else 1
as opposed to
Copy code
if cond:
    x = 0
... # technically don't need an else here
i.e. all conditions must be specified. You could use a
noop
task in the else clause to workaround this
y

Yubo Wang

02/08/2023, 5:00 PM
@Niels Bantilan Any example that I can refer to? I can’t seem to find noop task on the official doc or github repos
n

Niels Bantilan

02/08/2023, 5:02 PM
oh, just like:
Copy code
@task
def noop(): ...
y

Yubo Wang

02/08/2023, 5:03 PM
does that require spinning up a container to handle it? I assume it would
Hi @Niels Bantilan I have this question: We have this use case that we would add in some tasks/subflows based on the user inputs by leveraging Flyte’s conditions. As you suggested using a noop task which is at cost of spinning up a container task. I am thinking about if we introduce an
end()
function similar to the use of fail() that allows us to do nothing on a branch.
Do you think the above solution is doable?
s

Samhita Alla

02/12/2023, 10:46 AM
Makes sense. @Niels Bantilan WDYT?
n

Niels Bantilan

02/13/2023, 3:07 PM
yep, this use case makes sense! @Yubo Wang can you create a [flyte-core] issue below 👇 to support the
end()
use case? If I understand correctly, this would be for cases where you don’t want to do any thing in one of the conditional branches, right?
d

Dan Rammer (hamersaw)

02/13/2023, 3:48 PM
@Yubo Wang is this something you might be willing to contribute? It sounds like you already dove through the propeller code a bit, but would be happy to help!
y

Yubo Wang

02/13/2023, 4:17 PM
Sounds good, I will be working on this
7 Views