diff --git a/main.py b/main.py index 7c5b34c..c5f5dce 100644 --- a/main.py +++ b/main.py @@ -132,7 +132,26 @@ def shuffle_training_data(domain, flow, client, server): def main_paul_best(): - pauls_best_params = models.pauls_networks.best_config + pauls_best_params = best_config = { + "type": "paul", + "batch_size": 64, + "window_size": 10, + "domain_length": 40, + "flow_features": 3, + # + 'dropout': 0.5, + 'domain_features': 32, + 'drop_out': 0.5, + 'embedding_size': 64, + 'filter_main': 512, + 'flow_features': 3, + 'dense_main': 32, + 'filter_embedding': 32, + 'hidden_embedding': 32, + 'kernel_embedding': 8, + 'kernels_main': 8, + 'input_length': 40 + } main_train(pauls_best_params) diff --git a/models/__init__.py b/models/__init__.py index 2cfe9a1..1af6697 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,9 +1,7 @@ -import keras.backend as K from keras.models import Model -from models import deep1 -from models.renes_networks import selu -from . import flat_2, pauls_networks, renes_networks +from . import networks +from .metrics import * def create_model(model, output_type): @@ -13,7 +11,7 @@ def create_model(model, output_type): return Model(inputs=[model.in_domains, model.in_flows], outputs=(model.out_client,)) else: raise Exception("unknown model output") - + def get_models_by_params(params: dict): # decomposing param section @@ -33,36 +31,25 @@ def get_models_by_params(params: dict): kernel_main = params.get("kernel_main") dense_dim = params.get("dense_main") model_output = params.get("model_output", "both") - # create models - if network_depth == "flat1": - networks = pauls_networks - elif network_depth == "flat2": - networks = flat_2 - elif network_depth == "deep1": - networks = deep1 - elif network_depth == "deep2": - networks = renes_networks - else: - raise ValueError("network not found") - - domain_cnn = networks.get_embedding(embedding_size, domain_length, filter_embedding, kernel_embedding, - hidden_embedding, 0.5) + domain_cnn = networks.get_domain_embedding_model(embedding_size, domain_length, filter_embedding, kernel_embedding, + hidden_embedding, 0.5) + if network_type == "final": - model = networks.get_model(0.25, flow_features, window_size, domain_length, - filter_main, kernel_main, dense_dim, domain_cnn) + model = networks.get_final_model(0.25, flow_features, window_size, domain_length, + filter_main, kernel_main, dense_dim, domain_cnn) model = create_model(model, model_output) elif network_type in ("inter", "staggered"): - model = networks.get_new_model(0.25, flow_features, window_size, domain_length, - filter_main, kernel_main, dense_dim, domain_cnn) + model = networks.get_inter_model(0.25, flow_features, window_size, domain_length, + filter_main, kernel_main, dense_dim, domain_cnn) model = create_model(model, model_output) elif network_type == "long": - model = networks.get_new_model2(0.25, flow_features, window_size, domain_length, + model = networks.get_long_model(0.25, flow_features, window_size, domain_length, filter_main, kernel_main, dense_dim, domain_cnn) model = create_model(model, model_output) elif network_type == "soft": - model = networks.get_new_soft(0.25, flow_features, window_size, domain_length, - filter_main, kernel_main, dense_dim, domain_cnn) + model = networks.get_long_model(0.25, flow_features, window_size, domain_length, + filter_main, kernel_main, dense_dim, domain_cnn) model = create_model(model, model_output) conv_server = model.get_layer("conv_server").trainable_weights conv_client = model.get_layer("conv_client").trainable_weights @@ -92,68 +79,9 @@ def get_server_model_by_params(params: dict): flow_features = params.get("flow_features") domain_length = params.get("domain_length") dense_dim = params.get("dense_main") - # create models - if network_depth == "flat1": - networks = pauls_networks - elif network_depth == "flat2": - networks = flat_2 - elif network_depth == "deep1": - networks = deep1 - elif network_depth == "deep2": - networks = renes_networks - else: - raise Exception("network not found") - - embedding_model = networks.get_embedding(embedding_size, input_length, filter_embedding, kernel_embedding, - hidden_embedding, 0.5) + + embedding_model = networks.get_domain_embedding_model(embedding_size, input_length, filter_embedding, + kernel_embedding, + hidden_embedding, 0.5) return networks.get_server_model(flow_features, domain_length, dense_dim, embedding_model) - - -def get_custom_objects(): - return dict([ - ("precision", precision), - ("recall", recall), - ("f1_score", f1_score), - ("selu", selu) - ]) - - -def get_metric_functions(): - return [precision, recall, f1_score] - - -def precision(y_true, y_pred): - # Count positive samples. - true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) - predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1))) - return true_positives / (predicted_positives + K.epsilon()) - - -def recall(y_true, y_pred): - # Count positive samples. - true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) - possible_positives = K.sum(K.round(K.clip(y_true, 0, 1))) - return true_positives / (possible_positives + K.epsilon()) - - -def f1_score(y_true, y_pred): - return f_score(1)(y_true, y_pred) - - -def f05_score(y_true, y_pred): - return f_score(0.5)(y_true, y_pred) - - -def f_score(beta): - def _f(y_true, y_pred): - p = precision(y_true, y_pred) - r = recall(y_true, y_pred) - - bb = beta ** 2 - - fbeta_score = (1 + bb) * (p * r) / (bb * p + r + K.epsilon()) - - return fbeta_score - - return _f diff --git a/models/deep1.py b/models/deep1.py deleted file mode 100644 index 6023c2a..0000000 --- a/models/deep1.py +++ /dev/null @@ -1,70 +0,0 @@ -from collections import namedtuple - -import keras -from keras.engine import Input, Model as KerasModel -from keras.layers import Conv1D, Dense, Dropout, Embedding, GlobalAveragePooling1D, GlobalMaxPooling1D, TimeDistributed - -import dataset - -Model = namedtuple("Model", ["in_domains", "in_flows", "out_client", "out_server"]) - - -def get_embedding(embedding_size, input_length, filter_size, kernel_size, hidden_dims, drop_out=0.5): - x = Input(shape=(input_length,)) - y = Embedding(input_dim=dataset.get_vocab_size(), output_dim=embedding_size)(x) - y = Conv1D(filter_size, kernel_size=kernel_size, activation="relu", padding="same")(y) - y = Conv1D(filter_size, kernel_size=3, activation="relu", padding="same")(y) - y = Conv1D(filter_size, kernel_size=3, activation="relu", padding="same")(y) - y = GlobalAveragePooling1D()(y) - y = Dense(hidden_dims, activation="relu")(y) - return KerasModel(x, y) - - -def get_model(cnnDropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both"): - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - # CNN processing a small slides of flow windows - y = Conv1D(filters=cnn_dims, kernel_size=kernel_size, activation="relu", padding="same", - input_shape=(window_size, domain_features + flow_features))(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(cnnDropout)(y) - y = Dense(dense_dim, activation="relu")(y) - y = Dense(dense_dim, activation="relu")(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - out_server = Dense(1, activation='sigmoid', name="server")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) - - -def get_new_model(dropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both"): - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - y = Dense(dense_dim, activation="relu")(merged) - y = Dense(dense_dim, - activation="relu", - name="dense_server")(y) - out_server = Dense(1, activation="sigmoid", name="server")(y) - merged = keras.layers.concatenate([merged, y], -1) - # CNN processing a small slides of flow windows - y = Conv1D(filters=cnn_dims, - kernel_size=kernel_size, - activation="relu", - padding="same", - input_shape=(window_size, domain_features + flow_features))(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(dropout)(y) - y = Dense(dense_dim, activation="relu")(y) - y = Dense(dense_dim, - activation="relu", - name="dense_client")(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) diff --git a/models/flat_2.py b/models/flat_2.py deleted file mode 100644 index 2136fe6..0000000 --- a/models/flat_2.py +++ /dev/null @@ -1,85 +0,0 @@ -from collections import namedtuple - -import keras -from keras.activations import elu -from keras.engine import Input, Model as KerasModel -from keras.layers import BatchNormalization, Conv1D, Dense, Dropout, Embedding, GlobalAveragePooling1D, \ - GlobalMaxPooling1D, TimeDistributed - -import dataset - - -def selu(x): - """Scaled Exponential Linear Unit. (Klambauer et al., 2017) - # Arguments - x: A tensor or variable to compute the activation function for. - # References - - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) - # copied from keras.io - """ - alpha = 1.6732632423543772848170429916717 - scale = 1.0507009873554804934193349852946 - return scale * elu(x, alpha) - - -Model = namedtuple("Model", ["in_domains", "in_flows", "out_client", "out_server"]) - - -def get_embedding(embedding_size, input_length, filter_size, kernel_size, hidden_dims, drop_out=0.5) -> KerasModel: - x = y = Input(shape=(input_length,)) - y = Embedding(input_dim=dataset.get_vocab_size(), output_dim=embedding_size)(y) - y = Conv1D(filter_size, - kernel_size, - activation=selu)(y) - y = GlobalAveragePooling1D()(y) - y = Dense(hidden_dims, activation=selu)(y) - return KerasModel(x, y) - - -def get_model(cnnDropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both") -> Model: - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - y = BatchNormalization()(ipt_flows) - y = Dense(dense_dim, activation=selu)(y) - merged = keras.layers.concatenate([encoded, y], -1) - # CNN processing a small slides of flow windows - y = Conv1D(cnn_dims, - kernel_size, - activation=selu, - input_shape=(window_size, domain_features + flow_features))(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(cnnDropout)(y) - y = Dense(dense_dim, activation=selu)(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - out_server = Dense(1, activation='sigmoid', name="server")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) - - -def get_new_model(dropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both") -> Model: - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - y = Dense(dense_dim, activation=selu)(merged) - out_server = Dense(1, activation="sigmoid", name="server")(y) - merged = keras.layers.concatenate([merged, y], -1) - # CNN processing a small slides of flow windows - y = Conv1D(filters=cnn_dims, - kernel_size=kernel_size, - activation=selu, - padding="same", - input_shape=(window_size, domain_features + flow_features))(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(dropout)(y) - y = Dense(dense_dim, - activation=selu, - name="dense_client")(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) diff --git a/models/metrics.py b/models/metrics.py new file mode 100644 index 0000000..728461c --- /dev/null +++ b/models/metrics.py @@ -0,0 +1,64 @@ +import keras.backend as K +from keras.activations import elu + + +def get_custom_objects(): + return dict([ + ("precision", precision), + ("recall", recall), + ("f1_score", f1_score), + ("selu", selu) + ]) + + +def selu(x): + """Scaled Exponential Linear Unit. (Klambauer et al., 2017) + # Arguments + x: A tensor or variable to compute the activation function for. + # References + - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) + # copied from keras.io + """ + alpha = 1.6732632423543772848170429916717 + scale = 1.0507009873554804934193349852946 + return scale * elu(x, alpha) + + +def get_metric_functions(): + return [precision, recall, f1_score] + + +def precision(y_true, y_pred): + # Count positive samples. + true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) + predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1))) + return true_positives / (predicted_positives + K.epsilon()) + + +def recall(y_true, y_pred): + # Count positive samples. + true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) + possible_positives = K.sum(K.round(K.clip(y_true, 0, 1))) + return true_positives / (possible_positives + K.epsilon()) + + +def f1_score(y_true, y_pred): + return f_score(1)(y_true, y_pred) + + +def f05_score(y_true, y_pred): + return f_score(0.5)(y_true, y_pred) + + +def f_score(beta): + def _f(y_true, y_pred): + p = precision(y_true, y_pred) + r = recall(y_true, y_pred) + + bb = beta ** 2 + + fbeta_score = (1 + bb) * (p * r) / (bb * p + r + K.epsilon()) + + return fbeta_score + + return _f diff --git a/models/pauls_networks.py b/models/networks.py similarity index 64% rename from models/pauls_networks.py rename to models/networks.py index 9dadc65..f6d3014 100644 --- a/models/pauls_networks.py +++ b/models/networks.py @@ -8,29 +8,9 @@ import dataset Model = namedtuple("Model", ["in_domains", "in_flows", "out_client", "out_server"]) -best_config = { - "type": "paul", - "batch_size": 64, - "window_size": 10, - "domain_length": 40, - "flow_features": 3, - # - 'dropout': 0.5, - 'domain_features': 32, - 'drop_out': 0.5, - 'embedding_size': 64, - 'filter_main': 512, - 'flow_features': 3, - 'dense_main': 32, - 'filter_embedding': 32, - 'hidden_embedding': 32, - 'kernel_embedding': 8, - 'kernels_main': 8, - 'input_length': 40 -} - -def get_embedding(embedding_size, input_length, filter_size, kernel_size, hidden_dims, drop_out=0.5) -> KerasModel: +def get_domain_embedding_model(embedding_size, input_length, filter_size, kernel_size, hidden_dims, + drop_out=0.5) -> KerasModel: x = y = Input(shape=(input_length,)) y = Embedding(input_dim=dataset.get_vocab_size(), output_dim=embedding_size)(y) y = Conv1D(filter_size, @@ -42,8 +22,8 @@ def get_embedding(embedding_size, input_length, filter_size, kernel_size, hidden return KerasModel(x, y) -def get_model(cnnDropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn) -> Model: +def get_final_model(cnnDropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, + dense_dim, cnn) -> Model: ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") @@ -62,8 +42,8 @@ def get_model(cnnDropout, flow_features, window_size, domain_length, cnn_dims, k return Model(ipt_domains, ipt_flows, out_client, out_server) -def get_new_model(dropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn) -> Model: +def get_inter_model(dropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, + dense_dim, cnn) -> Model: ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) @@ -104,7 +84,7 @@ def get_server_model(flow_features, domain_length, dense_dim, cnn): return KerasModel(inputs=[ipt_domains, ipt_flows], outputs=out_server) -def get_new_model2(dropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, +def get_long_model(dropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, dense_dim, cnn) -> Model: ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") @@ -112,7 +92,7 @@ def get_new_model2(dropout, flow_features, window_size, domain_length, cnn_dims, merged = keras.layers.concatenate([encoded, ipt_flows], -1) y = Conv1D(cnn_dims, kernel_size, - activation='relu')(merged) + activation='relu', name="conv_server")(merged) # remove temporal dimension by global max pooling y = GlobalMaxPooling1D()(y) y = Dropout(dropout)(y) @@ -121,39 +101,6 @@ def get_new_model2(dropout, flow_features, window_size, domain_length, cnn_dims, name="dense_server")(y) out_server = Dense(1, activation="sigmoid", name="server")(y) # CNN processing a small slides of flow windows - y = Conv1D(cnn_dims, - kernel_size, - activation='relu')(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(dropout)(y) - y = Dense(dense_dim, - activation='relu', - name="dense_client")(y) - - out_client = Dense(1, activation='sigmoid', name="client")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) - - -def get_new_soft(dropout, flow_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn) -> Model: - - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - y = conv_server = Conv1D(cnn_dims, - kernel_size, - activation='relu', name="conv_server")(merged) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(dropout)(y) - y = dense_server = Dense(dense_dim, - activation="relu", - name="dense_server")(y) - out_server = Dense(1, activation="sigmoid", name="server")(y) - # CNN processing a small slides of flow windows y = Conv1D(cnn_dims, kernel_size, activation='relu', name="conv_client")(merged) diff --git a/models/renes_networks.py b/models/renes_networks.py deleted file mode 100644 index 94f3caf..0000000 --- a/models/renes_networks.py +++ /dev/null @@ -1,103 +0,0 @@ -from collections import namedtuple - -import keras -from keras.activations import elu -from keras.engine import Input, Model as KerasModel -from keras.layers import Conv1D, Dense, Dropout, Embedding, GlobalAveragePooling1D, GlobalMaxPooling1D, MaxPool1D, \ - TimeDistributed - -import dataset - - -def selu(x): - """Scaled Exponential Linear Unit. (Klambauer et al., 2017) - # Arguments - x: A tensor or variable to compute the activation function for. - # References - - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515) - # copied from keras.io - """ - alpha = 1.6732632423543772848170429916717 - scale = 1.0507009873554804934193349852946 - return scale * elu(x, alpha) - - -Model = namedtuple("Model", ["in_domains", "in_flows", "out_client", "out_server"]) - - -def get_embedding(embedding_size, input_length, filter_size, kernel_size, hidden_dims, drop_out=0.5): - x = y = Input(shape=(input_length,)) - y = Embedding(input_dim=dataset.get_vocab_size(), output_dim=embedding_size)(y) - y = Conv1D(filter_size, kernel_size=5, activation=selu)(y) - y = Conv1D(filter_size, kernel_size=3, activation=selu)(y) - y = Conv1D(filter_size, kernel_size=3, activation=selu)(y) - y = GlobalAveragePooling1D()(y) - y = Dense(hidden_dims, activation=selu)(y) - return KerasModel(x, y) - - -def get_model(cnnDropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both"): - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - # CNN processing a small slides of flow windows - y = Conv1D(filters=cnn_dims, kernel_size=kernel_size, activation=selu, padding="same", - input_shape=(window_size, domain_features + flow_features))(merged) - y = MaxPool1D(pool_size=3, strides=1)(y) - y = Conv1D(filters=cnn_dims, kernel_size=kernel_size, activation=selu, padding="same")(y) - y = MaxPool1D(pool_size=3, strides=1)(y) - y = Conv1D(filters=cnn_dims, kernel_size=kernel_size, activation=selu, padding="same")(y) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(cnnDropout)(y) - y = Dense(dense_dim, activation=selu)(y) - y = Dense(dense_dim, activation=selu)(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - out_server = Dense(1, activation='sigmoid', name="server")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) - - -def get_new_model(dropout, flow_features, domain_features, window_size, domain_length, cnn_dims, kernel_size, - dense_dim, cnn, model_output="both"): - ipt_domains = Input(shape=(window_size, domain_length), name="ipt_domains") - ipt_flows = Input(shape=(window_size, flow_features), name="ipt_flows") - encoded = TimeDistributed(cnn, name="domain_cnn")(ipt_domains) - merged = keras.layers.concatenate([encoded, ipt_flows], -1) - y = Dense(dense_dim, activation=selu)(merged) - y = Dense(dense_dim, - activation="relu", - name="dense_server")(y) - out_server = Dense(1, activation="sigmoid", name="server")(y) - merged = keras.layers.concatenate([merged, y], -1) - # CNN processing a small slides of flow windows - y = Conv1D(filters=cnn_dims, - kernel_size=kernel_size, - activation=selu, - padding="same", - input_shape=(window_size, domain_features + flow_features))(merged) - y = MaxPool1D(pool_size=3, - strides=1)(y) - y = Conv1D(filters=cnn_dims, - kernel_size=kernel_size, - activation=selu, - padding="same")(y) - y = MaxPool1D(pool_size=3, - strides=1)(y) - y = Conv1D(filters=cnn_dims, - kernel_size=kernel_size, - activation=selu, - padding="same")(y) - # remove temporal dimension by global max pooling - y = GlobalMaxPooling1D()(y) - y = Dropout(dropout)(y) - y = Dense(dense_dim, activation=selu)(y) - y = Dense(dense_dim, - activation=selu, - name="dense_client")(y) - out_client = Dense(1, activation='sigmoid', name="client")(y) - - return Model(ipt_domains, ipt_flows, out_client, out_server) -