{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":53666,"databundleVersionId":6589269,"sourceType":"competition"},{"sourceId":6493496,"sourceType":"datasetVersion","datasetId":3752835},{"sourceId":6503382,"sourceType":"datasetVersion","datasetId":3759460}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install /kaggle/input/psg-utils/psg_utils-0.1.6-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:17:06.800691Z","iopub.execute_input":"2023-10-09T03:17:06.801222Z","iopub.status.idle":"2023-10-09T03:17:42.859800Z","shell.execute_reply.started":"2023-10-09T03:17:06.801193Z","shell.execute_reply":"2023-10-09T03:17:42.858453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n# import cudf\nimport polars as pl\nfrom ydata_profiling import ProfileReport\nimport numpy as np\nfrom tqdm import tqdm\nimport tensorflow as tf\nimport keras\n# train_series = pd.read_parquet('data/train_series.parquet')\n# train_events = pd.read_csv('data/train_events.csv')\n# test_series = pd.read_parquet('data/test_series.parquet')\n# test = pl.scan_parquet('data/test_series.parquet').with_columns(pl.col('awake').cast(pl.Int8), pl.col('timestamp').str.to_datetime())","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-10-09T03:17:42.862523Z","iopub.execute_input":"2023-10-09T03:17:42.862921Z","iopub.status.idle":"2023-10-09T03:17:55.352355Z","shell.execute_reply.started":"2023-10-09T03:17:42.862885Z","shell.execute_reply":"2023-10-09T03:17:55.351222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_test(filenmae, nper=50, return_pd=True):\n    \"\"\"\n    This method prepares secondary features if requested by the user.\n    We use the date time column and rolling statistics from public work\n    \"\"\"\n\n    # Curating date features:-\n    raw = pl.scan_parquet(filenmae).with_columns(pl.col('timestamp').str.to_datetime())\n    df = \\\n    raw.with_columns([\n                    pl.col(\"timestamp\").dt.second().cast(pl.Int8).alias(\"second_hb\"),\n                    pl.col(\"timestamp\").dt.minute().cast(pl.Int8).alias(\"minute_hb\"),\n                    pl.col(\"timestamp\").dt.hour().cast(pl.Int8).alias(\"hour_hb\"),\n                    pl.col(\"timestamp\").dt.day().cast(pl.Int8).alias(\"day_nb\"),\n                    pl.col(\"timestamp\").dt.weekday().cast(pl.Int8).alias(\"weekday_nb\"),\n                    pl.col(\"timestamp\").dt.week().cast(pl.Int8).alias(\"week_nb\"),\n                    pl.col(\"timestamp\").dt.month().cast(pl.Int8).alias(\"month_nb\"),\n                    pl.col(\"timestamp\").dt.year().cast(pl.Int16).alias(\"year_nb\"),\n                    pl.col(\"timestamp\").dt.date().alias(\"date\"),\n                    (pl.col(\"anglez\") * pl.col(\"enmo\")).alias(\"anglez_enmo\")\n                    ])\n    \n\n\n    # Curating rolling features and window results:-\n    df = \\\n    df.\\\n    with_columns([pl.col(\"anglez\").diff(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').alias(\"d_anglez\"),\n                    pl.col(\"enmo\").diff(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').alias(\"d_enmo\"),\n                    pl.col(\"anglez\").rolling_mean(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').fill_null(strategy = 'forward').alias('ma_anglez'),\n                    pl.col(\"enmo\").rolling_mean(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').fill_null(strategy = 'forward').alias('ma_enmo')\n                    ]\n                ).\\\n    with_columns([pl.col('d_anglez').rolling_mean(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').fill_null(strategy = 'forward').alias('ma_d_anglez'),\n                    pl.col('d_enmo').rolling_mean(nper).over(\"series_id\").\\\n                    fill_null(strategy = 'backward').fill_null(strategy = 'forward').alias('ma_d_enmo')\n                    ]\n                )\n    if return_pd:\n        return df.collect().to_pandas(), raw.collect().to_pandas()\n    else:\n        return df.collect(), raw.collect()\n# df = pd.read_parquet('XYtrain.parquet')\n# df, test = read_test('data/test_series.parquet')\n# df, test = read_test('/kaggle/input/child-mind-institute-detect-sleep-states/train_series.parquet', return_pd=False)\ndf, test = read_test('/kaggle/input/child-mind-institute-detect-sleep-states/test_series.parquet', return_pd=False)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:17:55.353671Z","iopub.execute_input":"2023-10-09T03:17:55.354890Z","iopub.status.idle":"2023-10-09T03:17:55.539222Z","shell.execute_reply.started":"2023-10-09T03:17:55.354857Z","shell.execute_reply":"2023-10-09T03:17:55.538220Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# df, test = df[:int(127946340/80)], test[:int(127946340/80)]\nprint(df.shape, test.shape)","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:17:55.540911Z","iopub.execute_input":"2023-10-09T03:17:55.541473Z","iopub.status.idle":"2023-10-09T03:17:55.547915Z","shell.execute_reply.started":"2023-10-09T03:17:55.541446Z","shell.execute_reply":"2023-10-09T03:17:55.547004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import logging\nimport numpy as np\nimport tensorflow as tf\nfrom tensorflow.keras.layers import Input, BatchNormalization, \\\n                                    Concatenate, MaxPooling2D, \\\n                                    UpSampling2D, Conv2D, \\\n                                    AveragePooling2D, Layer\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras import regularizers\nfrom tensorflow_addons import activations as addon_activations\nfrom typing import List\nfrom psg_utils.utils import ensure_list_or_tuple\n\nlogger = logging.getLogger(__name__)\n\n\ndef _get_classes_or_funcs(string_list: list, func_modules: list) -> List[callable]:\n    \"\"\"\n    Helper for 'init_losses' or 'init_metrics'.\n    Please refer to their docstrings.\n\n    Args:\n        string_list:  (list)   List of strings, each giving a name of a metric\n                               or loss to use for training. The name should\n                               refer to a function or class in either tf_funcs\n                               or custom_funcs modules.\n        func_modules: (module or list of modules) A Tensorflow.keras module of losses or metrics,\n                                                  or a list of various modules to look through.\n\n    Returns:\n        A list of len(string_list) of classes/functions of losses/metrics/optimizers/activation functions etc.\n    \"\"\"\n    functions_or_classes = []\n    func_modules = ensure_list_or_tuple(func_modules)\n    for func_or_class_str in ensure_list_or_tuple(string_list):\n        found = False\n        for module in func_modules:\n            found = getattr(module, func_or_class_str, False)\n            if found:\n                logger.info(f\"Found requested class '{func_or_class_str}' in module '{module}'\")\n                functions_or_classes.append(found)  # return the first found\n                break\n        if not found:\n            raise AttributeError(f\"Did not find loss/metric function {func_or_class_str} \"\n                                 f\"in the module(s) '{func_modules}'\")\n    return functions_or_classes\n\ndef get_activation_function(activation_string):\n    \"\"\"\n    Same as 'init_losses', but for optimizers.\n    Please refer to the 'init_losses' docstring.\n    \"\"\"\n    activation = _get_classes_or_funcs(\n        activation_string,\n        func_modules=[tf.keras.activations, addon_activations]\n    )\n    assert len(activation) == 1, f'Received unexpected number of activation functions ({len(activation)}, expected 1)'\n    return activation[0]\n\ndef expand_to_dim(values, dim):\n    expanded = []\n    for v in values:\n        if not isinstance(v, (tuple, list, np.ndarray)):\n            v = [v]\n        if isinstance(v, np.ndarray):\n            v = list(v)\n        if len(v) != dim:\n            v *= dim\n        expanded.append(np.array(v))\n    return expanded\n\n\ndef output_feature_distance(input_feature_distance, stride, dim=2):\n    input_feature_distance, stride = expand_to_dim([input_feature_distance,\n                                                    stride], dim=dim)\n    return input_feature_distance * stride\n\n\ndef output_receptive_field(input_receptive_field, kernel_size,\n                           input_feature_distacne, dim=2):\n    input_receptive_field, kernel_size, \\\n    input_feature_distacne = expand_to_dim([input_receptive_field,\n                                            kernel_size,\n                                            input_feature_distacne],\n                                           dim=dim)\n    return input_receptive_field + (kernel_size - 1) * input_feature_distacne\n\ndef compute_receptive_fields(layers, verbose=False):\n    input_ = layers[0]\n    layers = layers[1:]\n    size = input_.input.get_shape().as_list()[1:-1]\n    dim = len(size)\n\n    # Set first layer parameters\n    receptive_field = 1\n    jump = 1\n\n    # Loop over all layers\n    values = []\n    for i, layer in enumerate(layers):\n        try:\n            kernel_size = layer.kernel_size\n        except AttributeError as e:\n            try:\n                # Pooling layer?\n                kernel_size = layer.pool_size\n            except AttributeError:\n                # Batch norm, flatten etc.\n                continue\n        kernel_size = np.array(kernel_size)\n\n        # Get potential dilation rates\n        try:\n            dilation = np.array(layer.dilation_rate).astype(np.int32)\n        except AttributeError:\n            dilation = np.ones(shape=[dim], dtype=np.int32)\n        if hasattr(layer, \"dilations\"):\n            assert (dilation == 1).all()\n            dilation = np.array(layer.dilations)\n            dilation = dilation[dilation[:, 0].argmax()]\n\n        # Get strides\n        stride = layer.strides\n\n        # Get kernel size taking into account dilation rate\n        ks = kernel_size * dilation\n        m = np.where(dilation > 1)\n        ks[m] -= (dilation[m]-1)\n\n        size = np.array(layer.output.get_shape().as_list()[1:-1])\n        jump = output_feature_distance(jump, stride, dim)\n        receptive_field = output_receptive_field(receptive_field, ks, jump, dim)\n\n        # Add to list\n        values.append((size, jump, receptive_field))\n\n        if verbose:\n            s = \"\\nLayer %i %s(kernel_size=%s, stride=%s, dilation=%s)\" % \\\n                (i+1, layer.__class__.__name__, kernel_size,\n                 stride, tuple(dilation))\n            logger.info(f\"{s}\\n\"\n                        f\"{'-' * (len(s) - 1)}\\n\"\n                        \"Num feature:\".ljust(25) + f\"{size}\\n\" +\n                        \"Feature distance:\".ljust(25) + f\"{jump}\\n\" +\n                        \"Receptive field:\".ljust(25) + f\"{receptive_field}\"\n                        )\n\n    return values\n\n\ndef shape_safe(input, dim=None):\n    if dim is not None:\n        return input.shape[dim] or tf.shape(input)[dim]\n    else:\n        return [shape_safe(input, d) for d in range(len(input.shape))]\n\n\nclass InputReshape(Layer):\n    def __init__(self, seq_length, n_channels, name=None, **kwargs):\n        super(InputReshape, self).__init__(name=name, **kwargs)\n        self.seq_length = seq_length\n        self.n_channels = n_channels\n\n    def get_config(self):\n        config = super().get_config()\n        config.update({\n            \"seq_length\": self.seq_length,\n            \"n_channels\": self.n_channels,\n        })\n        return config\n\n    def call(self, inputs, **kwargs):\n        shape = shape_safe(inputs)\n        inputs_reshaped = tf.reshape(inputs, shape=[shape[0], self.seq_length or shape[1]*shape[2], 1, self.n_channels])\n        return inputs_reshaped\n\n\nclass OutputReshape(Layer):\n    def __init__(self, n_periods, name=None, **kwargs):\n        super(OutputReshape, self).__init__(name=name, **kwargs)\n        self.n_periods = n_periods\n\n    def get_config(self):\n        config = super().get_config()\n        config.update({\n            \"n_periods\": self.n_periods\n        })\n        return config\n\n    def call(self, inputs, **kwargs):\n        shape = shape_safe(inputs)\n        n_pred = int(shape[1] // self.n_periods)\n        shape = [shape[0], self.n_periods or shape[1], n_pred, inputs.shape[-1]]\n        if n_pred == 1:\n            shape.pop(2)\n        return tf.reshape(inputs, shape=shape)\n\n\nclass PadStartToEvenLength(Layer):\n    def __init__(self, name=None, **kwargs):\n        super(PadStartToEvenLength, self).__init__(name=name, **kwargs)\n\n    def call(self, inputs, **kwargs):\n        return tf.pad(inputs,\n                      paddings=[[0, 0], [shape_safe(inputs, 1) % 2, 0], [0, 0], [0, 0]])\n\n\nclass PadToMatch(Layer):\n    def __init__(self, name=None, **kwargs):\n        super(PadToMatch, self).__init__(name=name, **kwargs)\n\n    def call(self, inputs, **kwargs):\n        s = tf.maximum(0, shape_safe(inputs[1], 1) - shape_safe(inputs[0], 1))\n        return tf.pad(inputs[0],\n                      paddings=[[0, 0], [s // 2, s // 2 + (s % 2)], [0, 0], [0, 0]])\n\n\nclass CropToMatch(Layer):\n    def __init__(self, name=None, **kwargs):\n        super(CropToMatch, self).__init__(name=name, **kwargs)\n\n    def call(self, inputs, **kwargs):\n        diff = tf.maximum(0, shape_safe(inputs[0], 1) - shape_safe(inputs[1], 1))\n        start = diff//2 + diff % 2\n        return inputs[0][:, start:start+shape_safe(inputs[1], 1), :, :]\n\n\nclass USleep(Model):\n    \"\"\"\n    OBS: Uses 2D operations internally with a 'dummy' axis, so that a batch\n         of shape [bs, d, c] is processed as [bs, d, 1, c]. These operations\n         are (on our systems, at least) currently significantly faster than\n         their 1D counterparts in tf.keras.\n\n    See also original U-net paper at http://arxiv.org/abs/1505.04597\n    \"\"\"\n    def __init__(self,\n                 n_classes,\n                 batch_shape,\n                 depth=12,\n                 dilation=1,\n                 activation=\"elu\",\n                 dense_classifier_activation=\"tanh\",\n                 kernel_size=9,\n                 transition_window=1,\n                 padding=\"same\",\n                 init_filters=5,\n                 complexity_factor=2,\n                 kernel_initializer=tf.keras.initializers.glorot_uniform,\n                 bias_initializer=tf.keras.initializers.zeros,\n                 l2_reg=None,\n                 data_per_prediction=None,\n                 no_log=False,\n                 name=\"\",\n                 **kwargs):\n        \"\"\"\n        n_classes (int):\n            The number of classes to model, gives the number of filters in the\n            final 1x1 conv layer.\n        batch_shape (list): Giving the shape of one one batch of data,\n                            potentially omitting the zeroth axis (the batch\n                            size dim)\n        depth (int):\n            Number of conv blocks in encoding layer (number of 2x2 max pools)\n            Note: each block doubles the filter count while halving the spatial\n            dimensions of the features.\n        dilation (int):\n            TODO\n        activation (string):\n            Activation function for convolution layers\n        dense_classifier_activation (string):\n            TODO\n        kernel_size (int):\n            Kernel size for convolution layers\n        transition_window (int):\n            TODO\n        padding (string):\n            Padding type ('same' or 'valid')\n        complexity_factor (int/float):\n            Use int(N * sqrt(complexity_factor)) number of filters in each\n            convolution layer instead of default N.\n        l2_reg (float in [0, 1])\n            L2 regularization on conv weights\n        data_per_prediction (int):\n            TODO\n        build (bool):\n            TODO\n        \"\"\"\n        # Set various attributes\n        assert len(batch_shape) == 4\n        self.n_periods = batch_shape[1]\n        self.input_dims = batch_shape[2]\n        self.n_channels = batch_shape[3]\n        self.n_classes = int(n_classes)\n        self.dilation = int(dilation)\n        self.cf = np.sqrt(complexity_factor)\n        self.init_filters = init_filters\n        self.kernel_size = int(kernel_size)\n        self.transition_window = transition_window\n        self.activation = activation\n        self.kernel_initializer = kernel_initializer\n        self.bias_initializer = bias_initializer\n        self.l2_reg = l2_reg\n        self.depth = depth\n        self.padding = padding.lower()\n        if self.padding != \"same\":\n            raise ValueError(\"Currently, must use 'same' padding.\")\n\n        self.dense_classifier_activation = dense_classifier_activation\n        self.data_per_prediction = data_per_prediction or self.input_dims\n        if not isinstance(self.data_per_prediction, (int, np.integer)):\n            raise TypeError(\"data_per_prediction must be an integer value\")\n        if self.input_dims % self.data_per_prediction:\n            raise ValueError(\"'input_dims' ({}) must be evenly divisible by \"\n                             \"'data_per_prediction' ({})\".format(self.input_dims,\n                                                                 self.data_per_prediction))\n\n        # Build model and init base keras Model class\n        super().__init__(*self.init_model(name_prefix=name))\n\n        # Compute receptive field\n        ind = [x.__class__.__name__ for x in self.layers].index(\"UpSampling2D\")\n        self.receptive_field = compute_receptive_fields(self.layers[:ind])[-1][-1]\n\n        # Log the model definition\n        if no_log:\n            self.log()\n\n    @staticmethod\n    def create_encoder(in_,\n                       depth,\n                       filters,\n                       kernel_size,\n                       activation,\n                       dilation,\n                       padding,\n                       complexity_factor,\n                       regularizer=None,\n                       name=\"encoder\",\n                       name_prefix=\"\",\n                       **other_conv_params):\n        name = \"{}{}\".format(name_prefix, name)\n        residual_connections = []\n        for i in range(depth):\n            l_name = name + \"_L%i\" % i\n            conv = Conv2D(int(filters*complexity_factor), (kernel_size, 1),\n                          activation=activation, padding=padding,\n                          kernel_regularizer=regularizer,\n                          bias_regularizer=regularizer,\n                          dilation_rate=dilation,\n                          name=l_name + \"_conv1\", **other_conv_params)(in_)\n            bn = BatchNormalization(name=l_name + \"_BN1\")(conv)\n            bn = PadStartToEvenLength(name=l_name + \"_padding\")(bn)\n            in_ = MaxPooling2D(pool_size=(2, 1), name=l_name + \"_pool\")(bn)\n\n            # add bn layer to list for residual conn.\n            residual_connections.append(bn)\n            filters = int(filters * np.sqrt(2))\n\n        # Bottom\n        name = \"{}bottom\".format(name_prefix)\n        conv = Conv2D(int(filters*complexity_factor), (kernel_size, 1),\n                      activation=activation, padding=padding,\n                      kernel_regularizer=regularizer,\n                      bias_regularizer=regularizer,\n                      dilation_rate=1,\n                      name=name + \"_conv1\", **other_conv_params)(in_)\n        encoded = BatchNormalization(name=name + \"_BN1\")(conv)\n        return encoded, residual_connections, filters\n\n    def create_upsample(self,\n                        in_,\n                        res_conns,\n                        depth,\n                        filters,\n                        kernel_size,\n                        activation,\n                        dilation,  # NOT USED\n                        padding,\n                        complexity_factor,\n                        regularizer=None,\n                        name=\"upsample\",\n                        name_prefix=\"\",\n                        **other_conv_params):\n        name = \"{}{}\".format(name_prefix, name)\n        residual_connections = res_conns[::-1]\n        for i in range(depth):\n            filters = int(np.ceil(filters/np.sqrt(2)))\n            l_name = name + \"_L%i\" % i\n\n            # Up-sampling block\n            up = UpSampling2D(size=(2, 1), name=l_name + \"_up\")(in_)\n            conv = Conv2D(int(filters*complexity_factor), (2, 1),\n                          activation=activation,\n                          padding=padding,\n                          kernel_regularizer=regularizer,\n                          bias_regularizer=regularizer,\n                          name=l_name + \"_conv1\", **other_conv_params)(up)\n            bn = BatchNormalization(name=l_name + \"_BN1\")(conv)\n\n            # Crop and concatenate\n            res_con = residual_connections[i]\n            cropped_bn = CropToMatch(name=l_name + \"_crop\")([bn, res_con])\n            merge = Concatenate(axis=-1, name=l_name + \"_concat\")([res_con, cropped_bn])\n            conv = Conv2D(int(filters*complexity_factor), (kernel_size, 1),\n                          activation=activation, padding=padding,\n                          kernel_regularizer=regularizer,\n                          bias_regularizer=regularizer,\n                          name=l_name + \"_conv2\", **other_conv_params)(merge)\n            in_ = BatchNormalization(name=l_name + \"_BN2\")(conv)\n        return in_\n\n    def create_dense_modeling(self,\n                              in_,\n                              filters,\n                              dense_classifier_activation,\n                              regularizer,\n                              complexity_factor,\n                              name_prefix=\"\",\n                              **other_conv_params):\n        cls = Conv2D(filters=int(filters*complexity_factor),\n                     kernel_size=(1, 1),\n                     kernel_regularizer=regularizer,\n                     bias_regularizer=regularizer,\n                     activation=dense_classifier_activation,\n                     name=\"{}dense_classifier_out\".format(name_prefix),\n                     **other_conv_params)(in_)\n        return cls\n\n    @staticmethod\n    def create_seq_modeling(in_,\n                            input_dims,\n                            data_per_period,\n                            n_periods,\n                            n_classes,\n                            transition_window,\n                            activation,\n                            regularizer=None,\n                            name_prefix=\"\",\n                            **other_conv_params):\n        cls = AveragePooling2D((data_per_period, 1),\n                               name=\"{}average_pool\".format(name_prefix))(in_)\n        out = Conv2D(filters=n_classes,\n                     kernel_size=(transition_window, 1),\n                     activation=activation,\n                     kernel_regularizer=regularizer,\n                     bias_regularizer=regularizer,\n                     padding=\"same\",\n                     name=\"{}sequence_conv_out_1\".format(name_prefix),\n                     **other_conv_params)(cls)\n        out = Conv2D(filters=n_classes,\n                     kernel_size=(transition_window, 1),\n                     activation=\"softmax\",\n                     kernel_regularizer=regularizer,\n                     bias_regularizer=regularizer,\n                     padding=\"same\",\n                     name=\"{}sequence_conv_out_2\".format(name_prefix),\n                     **other_conv_params)(out)\n        out = OutputReshape(n_periods=n_periods, name=\"{}output_reshape\".format(name_prefix))(out)\n        return out\n\n    def init_model(self, inputs=None, name_prefix=\"\"):\n        \"\"\"\n        Build the UNet model with the specified input image shape.\n        \"\"\"\n        seq_length = self.n_periods * self.input_dims if self.n_periods else None\n        if inputs is None:\n            inputs = Input(shape=[self.n_periods, self.input_dims, self.n_channels])\n        inputs_reshaped = InputReshape(seq_length, self.n_channels)(inputs)\n        \n        # Apply regularization if not None or 0\n        regularizer = regularizers.l2(self.l2_reg) if self.l2_reg else None\n\n        # Get activation func from tf or tfa\n        activation = get_activation_function(activation_string=self.activation)\n\n        settings = {\n            \"depth\": self.depth,\n            \"filters\": self.init_filters,\n            \"kernel_size\": self.kernel_size,\n            \"activation\": activation,\n            \"dilation\": self.dilation,\n            \"padding\": self.padding,\n            \"regularizer\": regularizer,\n            \"kernel_initializer\": self.kernel_initializer,\n            \"bias_initializer\": self.bias_initializer,\n            \"name_prefix\": name_prefix,\n            \"complexity_factor\": self.cf\n        }\n\n        \"\"\"\n        Encoding path\n        \"\"\"\n        enc, residual_cons, filters = self.create_encoder(in_=inputs_reshaped,\n                                                          **settings)\n\n        \"\"\"\n        Decoding path\n        \"\"\"\n        settings[\"filters\"] = filters\n        up = self.create_upsample(enc, residual_cons, **settings)\n\n        \"\"\"\n        Dense class modeling layers\n        \"\"\"\n        cls = self.create_dense_modeling(in_=up,\n                                         filters=self.n_classes,\n                                         dense_classifier_activation=self.dense_classifier_activation,\n                                         regularizer=regularizer,\n                                         complexity_factor=self.cf,\n                                         name_prefix=name_prefix)\n\n        \"\"\"\n        Sequence modeling\n        \"\"\"\n        out = self.create_seq_modeling(in_=cls,\n                                       input_dims=self.input_dims,\n                                       data_per_period=self.data_per_prediction,\n                                       n_periods=self.n_periods,\n                                       n_classes=self.n_classes,\n                                       transition_window=self.transition_window,\n                                       activation=self.activation,\n                                       regularizer=regularizer,\n                                       name_prefix=name_prefix)\n\n        return [inputs], [out]","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:17:55.549881Z","iopub.execute_input":"2023-10-09T03:17:55.550416Z","iopub.status.idle":"2023-10-09T03:17:55.756868Z","shell.execute_reply.started":"2023-10-09T03:17:55.550389Z","shell.execute_reply":"2023-10-09T03:17:55.755827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model = tf.keras.models.load_model('/kaggle/input/u-time-first/model.h5')\nmodel = tf.keras.models.load_model('/kaggle/input/17280x1x23-50-and-20e-16d/17280x1x23_50e_16d.keras', custom_objects={'USleep': USleep})","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:17:55.758041Z","iopub.execute_input":"2023-10-09T03:17:55.758300Z","iopub.status.idle":"2023-10-09T03:19:34.302492Z","shell.execute_reply.started":"2023-10-09T03:17:55.758278Z","shell.execute_reply":"2023-10-09T03:19:34.301235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.depth","metadata":{"execution":{"iopub.status.busy":"2023-10-09T03:19:34.451425Z","iopub.execute_input":"2023-10-09T03:19:34.451917Z","iopub.status.idle":"2023-10-09T03:19:34.464709Z","shell.execute_reply.started":"2023-10-09T03:19:34.451889Z","shell.execute_reply":"2023-10-09T03:19:34.463597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pandas.api.types import is_datetime64_ns_dtype\nimport gc\nsignal_awake = dict(zip(range(1440), np.sin(np.linspace(0, np.pi, 1440) + 0.208 * np.pi) ** 24))\nsignal_onset = dict(zip(range(1440), np.sin(np.linspace(0, np.pi, 1440) + 0.555 * np.pi) ** 24))\ndef reduce_mem_usage(df):\n    \n    \"\"\" \n    Iterate through all numeric columns of a dataframe and modify the data type\n    to reduce memory usage.        \n    \"\"\"\n    \n    for col in df.columns:\n        col_type = df[col].dtype\n\n        if col_type != object and not is_datetime64_ns_dtype(df[col]) and not 'category':\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int32)  \n            else:\n\n                df[col] = df[col].astype(np.float16)\n        \n    return df\ndef feat_eng(df):\n\n    df['series_id'] = df['series_id'].astype('category')\n    # df['timestamp'] = pd.to_datetime(df['timestamp']).apply(\n    #     lambda t: t.tz_localize(None))\n\n    # df.sort_values(['timestamp'], inplace=True)\n\n    # df['signal_onset'] = (df.timestamp.dt.hour * 60 +\n    #                       df.timestamp.dt.minute).map(signal_onset).astype(np.float32)\n    # df['signal_awake'] = (df.timestamp.dt.hour * 60 +\n    #                       df.timestamp.dt.minute).map(signal_awake).astype(np.float32)\n    df[\"anglez_diff\"] = df[\"anglez\"].diff()\n    df[\"anglez_diffabs\"] = abs(df[\"anglez_diff\"])\n    df[\"anglezabs\"] = abs(df[\"anglez\"])\n    df['anglez_x_enmo'] = df['anglez'] * df['enmo']\n\n    df.set_index('timestamp', inplace=True)\n\n    df['hour_sin'] = np.sin(2 * np.pi * df['hour_hb'] / 24)\n    df['hour_cos'] = np.cos(2 * np.pi * df['hour_hb'] / 24)\n\n    df['lids'] = np.maximum(0., df['enmo'] - 0.02)\n    df['lids'] = df['lids'].rolling(\n        f'{120*5}s', center=True, min_periods=1).agg('sum')\n    df['lids'] = 100 / (df['lids'] + 1)\n    df['lids'] = df['lids'].rolling(\n        f'{360*5}s', center=True, min_periods=1).agg('mean').astype(np.float32)\n\n    # for col in ['enmo', 'anglez', 'anglez_x_enmo', 'anglezabs', 'anglez_diff', \"anglez_diffabs\"]:\n\n    #     for n in [51]:\n    #         df[f'{col}_diff_{n}'] = df[col].diff(periods=n).astype(np.float32)\n\n    #         rol_args = {'window':f'{n*5}s', 'min_periods':1, 'center':True}\n\n    #         for agg in ['median', 'mean', 'max', 'min', 'std']:\n    #             df[f'{col}_{agg}_{n}'] = df[col].rolling(**rol_args).agg(agg).astype(np.float32).values\n    #             gc.collect()\n\n    #         df[f'{col}_mad_{n}'] = (df[col] - df[f'{col}_median_{n}']).abs()\n    #         df[f'{col}_mad_{n}'] = df[f'{col}_mad_{n}'].rolling(**rol_args).agg('median').astype(np.float32).values\n    # df[f'{col}_amplit_{n}'] = df[f'{col}_max_{n}']-df[f'{col}_min_{n}'].astype(np.float32)\n    # df[f'{col}_diff_{n}_max'] = df[f'{col}_max_{n}'].rolling(**rol_args).max().astype(np.float32)\n    # df[f'{col}_medianxstd_{n}'] = df[f'{col}_median_{n}'] * df[f'{col}_std_{n}']\n\n    # gc.collect()\n\n#         df[f'conv1d_{col}']\n\n    df.reset_index(inplace=True)\n    df.bfill(inplace=True)\n    df.ffill(inplace=True)\n    df.dropna(inplace=True)\n\n    df = reduce_mem_usage(df)\n\n    return df","metadata":{"execution":{"iopub.status.busy":"2023-09-26T11:03:38.059214Z","iopub.execute_input":"2023-09-26T11:03:38.059630Z","iopub.status.idle":"2023-09-26T11:03:38.085699Z","shell.execute_reply.started":"2023-09-26T11:03:38.059597Z","shell.execute_reply":"2023-09-26T11:03:38.084687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def postprocess(arr):\n    # Step 1: 二值化数组\n    arr[arr < 0.5] = 0\n    arr[arr >= 0.5] = 1\n    \n    # Step 2: 找出最长的0子数组\n    max_start = 0\n    max_end = 0\n    max_length = 0\n    \n    cur_start = None\n    cur_end = None\n    \n    for i, val in enumerate(arr):\n        if val == 0:\n            if cur_start is None:  # 开始一个新的0子数组\n                cur_start = i\n            cur_end = i  # 更新当前0子数组的结束位置\n            \n            # 如果到达数组的末尾，检查最后一个0子数组\n            if i == len(arr) - 1:\n                cur_length = cur_end - cur_start + 1\n                if cur_length > max_length:\n                    max_start = cur_start\n                    max_end = cur_end\n                    max_length = cur_length\n            \n        else:\n            if cur_start is not None:  # 0子数组结束\n                cur_length = cur_end - cur_start + 1\n                if cur_length > max_length:  # 检查是否需要更新最长的0子数组\n                    max_start = cur_start\n                    max_end = cur_end\n                    max_length = cur_length\n                cur_start = None  # 重置当前0子数组的起始和结束位置\n                cur_end = None\n    \n    # Step 3: 将其他0设置为1\n    for i in range(len(arr)):\n        if arr[i] == 0 and (i < max_start or i > max_end):\n            arr[i] = 1\n            \n    return arr\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"features = [\n    'anglez', 'enmo', 'anglez_enmo', 'd_anglez', 'd_enmo', \n    'ma_anglez', 'ma_enmo', 'ma_d_anglez', 'ma_d_enmo'\n]\ntime_feat = ['second_hb','minute_hb','hour_hb', 'day_nb', 'weekday_nb', 'week_nb', 'month_nb']\ntarget = ['awake']\nfeats_2b_selected = ['day_nb', 'anglezabs', 'ma_d_anglez',  'd_enmo',  'second_hb', 'anglez', 'enmo', 'd_anglez', 'week_nb', \n                    #  'signal_awake', \n                     'ma_d_enmo',  'ma_enmo', \n                    #  'signal_onset',\n                     'minute_hb', 'ma_anglez',    'anglez_x_enmo', 'weekday_nb',  'hour_hb', 'anglez_diff', 'hour_sin', 'lids',  'anglez_diffabs', 'anglez_enmo',  'month_nb', 'hour_cos']\n\n\ndef is_date_in_list(target_datetime, datetime_list):\n    # 提取目标日期的年、月、日信息\n    # target_date = target_datetime.date()\n    \n    # 遍历datetime列表\n    for dt in datetime_list:\n        # 提取列表中每一个日期的年、月、日信息\n        # dt_date = (dt.year, dt.month, dt.day)\n        \n        # 判断目标日期是否在列表中\n        if target_datetime == dt.date():\n            return True\n    \n    return False\ndef lazyframe_to_array(df):\n    n_classes = 2  # 二分类问题\n    n_periods = 17280  # 一个样本只包含一个周期\n    length_of_each_period = 1  # 一个周期的时间点数量\n    n_channels = 23  # 特征数量\n    \n    ret = []\n    index_arr = []\n    df = df.with_row_count()\n    for name, s in tqdm(df.group_by(['series_id'])):\n        #name = name[0]\n        for _, d in s.group_by(['date']):\n            \n            temp = np.zeros((17280, len(feats_2b_selected)))\n            temp_row = -np.ones((17280, 1))\n            \n            temp_df = d.to_pandas()\n            temp_df = feat_eng(temp_df)\n\n            samp = temp_df[feats_2b_selected].to_numpy()\n            temp[:samp.shape[0], :] = samp\n            pred = model.predict(temp.reshape(-1,n_periods,length_of_each_period,len(feats_2b_selected)),verbose=0)[:,:,-1:]\n#             print(pred.shape)\n            pred = pred.repeat(length_of_each_period, axis=-1).reshape(-1,17280,1)\n#             print(pred.shape)\n            \n            ret.append(pred)\n            \n            samp_row = temp_df[['row_nr']].to_numpy()\n            temp_row[:samp_row.shape[0], :] = samp_row\n            index_arr.append(temp_row)\n#             break\n#         break\n    return np.concatenate(ret, axis=0), np.array(index_arr)\n\narr, index_arr = lazyframe_to_array(df)\nprint(arr.shape)\nprint(index_arr)\npredictions = arr","metadata":{"execution":{"iopub.status.busy":"2023-09-26T11:03:38.087594Z","iopub.execute_input":"2023-09-26T11:03:38.089268Z","iopub.status.idle":"2023-09-26T11:03:59.714048Z","shell.execute_reply.started":"2023-09-26T11:03:38.089195Z","shell.execute_reply":"2023-09-26T11:03:59.712130Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import matplotlib.pyplot as plt\n# plt.plot(predictions[7,:,0])\n# plt.ylim(0, 1.1)\n# plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-26T11:03:59.716785Z","iopub.execute_input":"2023-09-26T11:03:59.717420Z","iopub.status.idle":"2023-09-26T11:04:00.063078Z","shell.execute_reply.started":"2023-09-26T11:03:59.717318Z","shell.execute_reply":"2023-09-26T11:04:00.061047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#input_test = arr.reshape(-1,17280,1,16)\n#predictions = model.predict(input_test, batch_size=16)[:,:,:-1]\n","metadata":{"execution":{"iopub.status.busy":"2023-09-26T08:19:21.746933Z","iopub.execute_input":"2023-09-26T08:19:21.747809Z","iopub.status.idle":"2023-09-26T08:19:21.752863Z","shell.execute_reply.started":"2023-09-26T08:19:21.747773Z","shell.execute_reply":"2023-09-26T08:19:21.751752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-09-26T11:48:22.402504Z","iopub.execute_input":"2023-09-26T11:48:22.402946Z","iopub.status.idle":"2023-09-26T11:48:22.416440Z","shell.execute_reply.started":"2023-09-26T11:48:22.402914Z","shell.execute_reply":"2023-09-26T11:48:22.415272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_val_pred = -np.ones(len(test))\nnum = 0\nfor s_i in range(index_arr.shape[0]):\n    index = index_arr[s_i]\n    pred = predictions[s_i]\n#     print(index.shape,index)\n    vaild = np.where(index != -1)\n    index = index[vaild]\n    pred = pred[vaild]\n#     print(index.shape, index)\n    y_val_pred[int(index.min()):int(index.max())+1] = pred\n    if num > 0:\n        plt.plot(postprocess(pred))\n        plt.ylim(0, 1.1)\n        plt.show()\n        num-=1\n#     print(y_val_pred)\nprint(len(test))\ny_val_pred.shape","metadata":{"execution":{"iopub.status.busy":"2023-09-26T11:48:23.787525Z","iopub.execute_input":"2023-09-26T11:48:23.787970Z","iopub.status.idle":"2023-09-26T11:48:27.503474Z","shell.execute_reply.started":"2023-09-26T11:48:23.787925Z","shell.execute_reply":"2023-09-26T11:48:27.502202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from itertools import groupby\ntest = test.to_pandas()\ntest[\"score\"] = y_val_pred\ntest[\"not_awake\"] = 1-test[\"score\"]\n# smoothing of the predictions\nsmoothing_length = 2*250\ntest[\"smooth\"] = test[\"not_awake\"].rolling(smoothing_length,center=True).mean().fillna(method=\"bfill\").fillna(method=\"ffill\")\n# re-binarize\ntest[\"smooth\"] = test[\"smooth\"].round()\ntest[\"score\"] = test[\"smooth\"]#test[\"awake\"].rolling(smoothing_length,center=True).mean().fillna(method=\"bfill\").fillna(method=\"ffill\")\n\n# https://stackoverflow.com/questions/73777727/how-to-mark-start-end-of-a-series-of-non-null-and-non-0-values-in-a-column-of-a\ndef get_event(df):\n    lstCV = zip(df.series_id, df.smooth)\n    lstPOI = []\n    for (c, v), g in groupby(lstCV, lambda cv:\n                            (cv[0], cv[1]!=0 and not pd.isnull(cv[1]))):\n        llg = sum(1 for item in g)\n        if v is False:\n            lstPOI.extend([0]*llg)\n        else:\n            lstPOI.extend(['onset']+(llg-2)*[0]+['wakeup'] if llg > 1 else [0])\n    return lstPOI\n\ntest[\"event\"] = get_event(test)\nsample_submission = test.loc[test[\"event\"] != 0][[\"series_id\",\"step\",\"event\",\"score\"]].copy().reset_index(drop=True).reset_index(names=\"row_id\")\nsample_submission.to_csv('submission.csv', index=False)\nprint('finished')","metadata":{"execution":{"iopub.status.busy":"2023-09-26T08:19:22.397611Z","iopub.execute_input":"2023-09-26T08:19:22.397995Z","iopub.status.idle":"2023-09-26T08:19:26.607618Z","shell.execute_reply.started":"2023-09-26T08:19:22.397962Z","shell.execute_reply":"2023-09-26T08:19:26.606400Z"},"trusted":true},"execution_count":null,"outputs":[]}]}