{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "7765UFHoyGx6"
},
"source": [
"##### Copyright 2020 The TensorFlow Authors."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"cellView": "form",
"execution": {
"iopub.execute_input": "2021-10-09T00:20:49.209371Z",
"iopub.status.busy": "2021-10-09T00:20:49.208727Z",
"iopub.status.idle": "2021-10-09T00:20:49.211181Z",
"shell.execute_reply": "2021-10-09T00:20:49.211537Z"
},
"id": "KsOkK8O69PyT"
},
"outputs": [],
"source": [
"#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
"#\n",
"# https://www.apache.org/licenses/LICENSE-2.0\n",
"#\n",
"# Unless required by applicable law or agreed to in writing, software\n",
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZS8z-_KeywY9"
},
"source": [
"# TFL 레이어로 Keras 모델 만들기"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "r61fkA2i9Y3_"
},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ecLbJCvJSSCd"
},
"source": [
"TFL Keras 레이어를 사용하여 단조 및 기타 형상 제약 조건이 있는 Keras 모델을 구성할 수 있습니다. 이 예제에서는 TFL 레이어를 사용하여 UCI heart 데이터세트에 대해 보정된 격자 모델을 구축하고 훈련합니다.\n",
"\n",
"보정된 격자 모델에서 각 특성은 `tfl.layers.PWLCalibration` 또는 `tfl.layers.CategoricalCalibration` 레이어에 의해 변환되고 결과는 `tfl.layers.Lattice`를 사용하여 비선형적으로 융합됩니다.\n",
"\n",
"보정된 격자 모델에서 각 특성은 `tfl.layers.PWLCalibration` 또는 `tfl.layers.CategoricalCalibration` 레이어에 의해 변환되고 결과는 `tfl.layers.Lattice`를 사용하여 비선형적으로 융합됩니다."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "x769lI12IZXB"
},
"source": [
"## 설정"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fbBVAR6UeRN5"
},
"source": [
"TF Lattice 패키지 설치하기"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:49.221373Z",
"iopub.status.busy": "2021-10-09T00:20:49.218518Z",
"iopub.status.idle": "2021-10-09T00:20:51.209755Z",
"shell.execute_reply": "2021-10-09T00:20:51.210119Z"
},
"id": "bpXjJKpSd3j4"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting tensorflow-lattice\r\n",
" Using cached tensorflow_lattice-2.0.9-py2.py3-none-any.whl (235 kB)\r\n",
"Requirement already satisfied: pydot in /home/kbuilder/.local/lib/python3.7/site-packages (1.4.2)\r\n",
"Requirement already satisfied: absl-py in /home/kbuilder/.local/lib/python3.7/site-packages (from tensorflow-lattice) (0.12.0)\r\n",
"Requirement already satisfied: scikit-learn in /home/kbuilder/.local/lib/python3.7/site-packages (from tensorflow-lattice) (1.0)\r\n",
"Requirement already satisfied: matplotlib in /home/kbuilder/.local/lib/python3.7/site-packages (from tensorflow-lattice) (3.4.3)\r\n",
"Requirement already satisfied: numpy in /tmpfs/src/tf_docs_env/lib/python3.7/site-packages (from tensorflow-lattice) (1.19.5)\r\n",
"Requirement already satisfied: six in /tmpfs/src/tf_docs_env/lib/python3.7/site-packages (from tensorflow-lattice) (1.15.0)\r\n",
"Requirement already satisfied: pandas in /home/kbuilder/.local/lib/python3.7/site-packages (from tensorflow-lattice) (1.3.3)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting dm-sonnet\r\n",
" Using cached dm_sonnet-2.0.0-py3-none-any.whl (254 kB)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting graphviz\r\n",
" Using cached graphviz-0.17-py3-none-any.whl (18 kB)\r\n",
"Requirement already satisfied: pyparsing>=2.1.4 in /home/kbuilder/.local/lib/python3.7/site-packages (from pydot) (2.4.7)\r\n",
"Requirement already satisfied: wrapt>=1.11.1 in /tmpfs/src/tf_docs_env/lib/python3.7/site-packages (from dm-sonnet->tensorflow-lattice) (1.12.1)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting dm-tree>=0.1.1\r\n",
" Using cached dm_tree-0.1.6-cp37-cp37m-manylinux_2_24_x86_64.whl (93 kB)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Collecting tabulate>=0.7.5\r\n",
" Using cached tabulate-0.8.9-py3-none-any.whl (25 kB)\r\n",
"Requirement already satisfied: pillow>=6.2.0 in /home/kbuilder/.local/lib/python3.7/site-packages (from matplotlib->tensorflow-lattice) (8.3.2)\r\n",
"Requirement already satisfied: python-dateutil>=2.7 in /home/kbuilder/.local/lib/python3.7/site-packages (from matplotlib->tensorflow-lattice) (2.8.2)\r\n",
"Requirement already satisfied: cycler>=0.10 in /home/kbuilder/.local/lib/python3.7/site-packages (from matplotlib->tensorflow-lattice) (0.10.0)\r\n",
"Requirement already satisfied: kiwisolver>=1.0.1 in /home/kbuilder/.local/lib/python3.7/site-packages (from matplotlib->tensorflow-lattice) (1.3.2)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: pytz>=2017.3 in /home/kbuilder/.local/lib/python3.7/site-packages (from pandas->tensorflow-lattice) (2021.3)\r\n",
"Requirement already satisfied: joblib>=0.11 in /home/kbuilder/.local/lib/python3.7/site-packages (from scikit-learn->tensorflow-lattice) (1.1.0)\r\n",
"Requirement already satisfied: threadpoolctl>=2.0.0 in /home/kbuilder/.local/lib/python3.7/site-packages (from scikit-learn->tensorflow-lattice) (3.0.0)\r\n",
"Requirement already satisfied: scipy>=1.1.0 in /home/kbuilder/.local/lib/python3.7/site-packages (from scikit-learn->tensorflow-lattice) (1.7.1)\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Installing collected packages: tabulate, dm-tree, graphviz, dm-sonnet, tensorflow-lattice\r\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Successfully installed dm-sonnet-2.0.0 dm-tree-0.1.6 graphviz-0.17 tabulate-0.8.9 tensorflow-lattice-2.0.9\r\n"
]
}
],
"source": [
"#@test {\"skip\": true}\n",
"!pip install tensorflow-lattice pydot"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "jSVl9SHTeSGX"
},
"source": [
"필수 패키지 가져오기"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"cellView": "both",
"execution": {
"iopub.execute_input": "2021-10-09T00:20:51.215157Z",
"iopub.status.busy": "2021-10-09T00:20:51.214558Z",
"iopub.status.idle": "2021-10-09T00:20:53.468100Z",
"shell.execute_reply": "2021-10-09T00:20:53.468525Z"
},
"id": "pm0LD8iyIZXF"
},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"\n",
"import logging\n",
"import numpy as np\n",
"import pandas as pd\n",
"import sys\n",
"import tensorflow_lattice as tfl\n",
"from tensorflow import feature_column as fc\n",
"logging.disable(sys.maxsize)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "svPuM6QNxlrH"
},
"source": [
"UCI Statlog(Heart) 데이터세트 다운로드하기"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"cellView": "both",
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.473688Z",
"iopub.status.busy": "2021-10-09T00:20:53.473137Z",
"iopub.status.idle": "2021-10-09T00:20:53.487604Z",
"shell.execute_reply": "2021-10-09T00:20:53.487169Z"
},
"id": "PG3pFtK-IZXM"
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" age | \n",
" sex | \n",
" cp | \n",
" trestbps | \n",
" chol | \n",
" fbs | \n",
" restecg | \n",
" thalach | \n",
" exang | \n",
" oldpeak | \n",
" slope | \n",
" ca | \n",
" thal | \n",
" target | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 61 | \n",
" 1 | \n",
" 4 | \n",
" 120 | \n",
" 260 | \n",
" 0 | \n",
" 0 | \n",
" 140 | \n",
" 1 | \n",
" 3.6 | \n",
" 2 | \n",
" 1 | \n",
" reversible | \n",
" 1 | \n",
"
\n",
" \n",
" 1 | \n",
" 45 | \n",
" 1 | \n",
" 3 | \n",
" 110 | \n",
" 264 | \n",
" 0 | \n",
" 1 | \n",
" 132 | \n",
" 0 | \n",
" 1.2 | \n",
" 1 | \n",
" 0 | \n",
" normal | \n",
" 0 | \n",
"
\n",
" \n",
" 2 | \n",
" 47 | \n",
" 1 | \n",
" 3 | \n",
" 130 | \n",
" 253 | \n",
" 0 | \n",
" 0 | \n",
" 179 | \n",
" 0 | \n",
" 0.0 | \n",
" 1 | \n",
" 0 | \n",
" normal | \n",
" 0 | \n",
"
\n",
" \n",
" 3 | \n",
" 59 | \n",
" 1 | \n",
" 3 | \n",
" 150 | \n",
" 212 | \n",
" 1 | \n",
" 0 | \n",
" 157 | \n",
" 0 | \n",
" 1.6 | \n",
" 1 | \n",
" 0 | \n",
" normal | \n",
" 0 | \n",
"
\n",
" \n",
" 4 | \n",
" 55 | \n",
" 0 | \n",
" 4 | \n",
" 128 | \n",
" 205 | \n",
" 0 | \n",
" 1 | \n",
" 130 | \n",
" 1 | \n",
" 2.0 | \n",
" 2 | \n",
" 1 | \n",
" reversible | \n",
" 1 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" age sex cp trestbps chol fbs restecg thalach exang oldpeak slope \\\n",
"0 61 1 4 120 260 0 0 140 1 3.6 2 \n",
"1 45 1 3 110 264 0 1 132 0 1.2 1 \n",
"2 47 1 3 130 253 0 0 179 0 0.0 1 \n",
"3 59 1 3 150 212 1 0 157 0 1.6 1 \n",
"4 55 0 4 128 205 0 1 130 1 2.0 2 \n",
"\n",
" ca thal target \n",
"0 1 reversible 1 \n",
"1 0 normal 0 \n",
"2 0 normal 0 \n",
"3 0 normal 0 \n",
"4 1 reversible 1 "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# UCI Statlog (Heart) dataset.\n",
"csv_file = tf.keras.utils.get_file(\n",
" 'heart.csv', 'http://storage.googleapis.com/download.tensorflow.org/data/heart.csv')\n",
"training_data_df = pd.read_csv(csv_file).sample(\n",
" frac=1.0, random_state=41).reset_index(drop=True)\n",
"training_data_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nKkAw12SxvGG"
},
"source": [
"이 가이드에서 훈련에 사용되는 기본값 설정하기"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"cellView": "both",
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.491469Z",
"iopub.status.busy": "2021-10-09T00:20:53.490894Z",
"iopub.status.idle": "2021-10-09T00:20:53.492772Z",
"shell.execute_reply": "2021-10-09T00:20:53.492339Z"
},
"id": "krAJBE-yIZXR"
},
"outputs": [],
"source": [
"LEARNING_RATE = 0.1\n",
"BATCH_SIZE = 128\n",
"NUM_EPOCHS = 100"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0TGfzhPHzpix"
},
"source": [
"## 순차형 Keras 모델\n",
"\n",
"이 예제는 순차형 Keras 모델을 생성하고 TFL 레이어만 사용합니다.\n",
"\n",
"격자 레이어는 `input[i]`이 `[0, lattice_sizes[i] - 1.0]` 내에 있을 것으로 예상하므로 보정 레이어보다 먼저 격자 크기를 정의해야 보정 레이어의 출력 범위를 올바르게 지정할 수 있습니다.\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.496406Z",
"iopub.status.busy": "2021-10-09T00:20:53.495881Z",
"iopub.status.idle": "2021-10-09T00:20:53.497809Z",
"shell.execute_reply": "2021-10-09T00:20:53.497422Z"
},
"id": "nOQWqPAbQS3o"
},
"outputs": [],
"source": [
"# Lattice layer expects input[i] to be within [0, lattice_sizes[i] - 1.0], so\n",
"lattice_sizes = [3, 2, 2, 2, 2, 2, 2]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W3DnEKWvQYXm"
},
"source": [
"`tfl.layers.ParallelCombination` 레이어를 사용하여 순차형 모델을 생성하기 위해 병렬로 실행해야 하는 보정 레이어를 그룹화합니다.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.501378Z",
"iopub.status.busy": "2021-10-09T00:20:53.500853Z",
"iopub.status.idle": "2021-10-09T00:20:53.505804Z",
"shell.execute_reply": "2021-10-09T00:20:53.505419Z"
},
"id": "o_hyk5GkQfl8"
},
"outputs": [],
"source": [
"combined_calibrators = tfl.layers.ParallelCombination()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "BPZsSUZiQiwc"
},
"source": [
"각 특성에 대한 보정 레이어를 만들고 병렬 조합 레이어에 추가합니다. 숫자 특성에는 `tfl.layers.PWLCalibration`을 사용하고 범주형 특성에는 `tfl.layers.CategoricalCalibration`을 사용합니다."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.525871Z",
"iopub.status.busy": "2021-10-09T00:20:53.521909Z",
"iopub.status.idle": "2021-10-09T00:20:53.527792Z",
"shell.execute_reply": "2021-10-09T00:20:53.527406Z"
},
"id": "DXPc6rSGxzFZ"
},
"outputs": [],
"source": [
"# ############### age ###############\n",
"calibrator = tfl.layers.PWLCalibration(\n",
" # Every PWLCalibration layer must have keypoints of piecewise linear\n",
" # function specified. Easiest way to specify them is to uniformly cover\n",
" # entire input range by using numpy.linspace().\n",
" input_keypoints=np.linspace(\n",
" training_data_df['age'].min(), training_data_df['age'].max(), num=5),\n",
" # You need to ensure that input keypoints have same dtype as layer input.\n",
" # You can do it by setting dtype here or by providing keypoints in such\n",
" # format which will be converted to desired tf.dtype by default.\n",
" dtype=tf.float32,\n",
" # Output range must correspond to expected lattice input range.\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[0] - 1.0,\n",
")\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### sex ###############\n",
"# For boolean features simply specify CategoricalCalibration layer with 2\n",
"# buckets.\n",
"calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=2,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[1] - 1.0,\n",
" # Initializes all outputs to (output_min + output_max) / 2.0.\n",
" kernel_initializer='constant')\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### cp ###############\n",
"calibrator = tfl.layers.PWLCalibration(\n",
" # Here instead of specifying dtype of layer we convert keypoints into\n",
" # np.float32.\n",
" input_keypoints=np.linspace(1, 4, num=4, dtype=np.float32),\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[2] - 1.0,\n",
" monotonicity='increasing',\n",
" # You can specify TFL regularizers as a tuple ('regularizer name', l1, l2).\n",
" kernel_regularizer=('hessian', 0.0, 1e-4))\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### trestbps ###############\n",
"calibrator = tfl.layers.PWLCalibration(\n",
" # Alternatively, you might want to use quantiles as keypoints instead of\n",
" # uniform keypoints\n",
" input_keypoints=np.quantile(training_data_df['trestbps'],\n",
" np.linspace(0.0, 1.0, num=5)),\n",
" dtype=tf.float32,\n",
" # Together with quantile keypoints you might want to initialize piecewise\n",
" # linear function to have 'equal_slopes' in order for output of layer\n",
" # after initialization to preserve original distribution.\n",
" kernel_initializer='equal_slopes',\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[3] - 1.0,\n",
" # You might consider clamping extreme inputs of the calibrator to output\n",
" # bounds.\n",
" clamp_min=True,\n",
" clamp_max=True,\n",
" monotonicity='increasing')\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### chol ###############\n",
"calibrator = tfl.layers.PWLCalibration(\n",
" # Explicit input keypoint initialization.\n",
" input_keypoints=[126.0, 210.0, 247.0, 286.0, 564.0],\n",
" dtype=tf.float32,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[4] - 1.0,\n",
" # Monotonicity of calibrator can be decreasing. Note that corresponding\n",
" # lattice dimension must have INCREASING monotonicity regardless of\n",
" # monotonicity direction of calibrator.\n",
" monotonicity='decreasing',\n",
" # Convexity together with decreasing monotonicity result in diminishing\n",
" # return constraint.\n",
" convexity='convex',\n",
" # You can specify list of regularizers. You are not limited to TFL\n",
" # regularizrs. Feel free to use any :)\n",
" kernel_regularizer=[('laplacian', 0.0, 1e-4),\n",
" tf.keras.regularizers.l1_l2(l1=0.001)])\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### fbs ###############\n",
"calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=2,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[5] - 1.0,\n",
" # For categorical calibration layer monotonicity is specified for pairs\n",
" # of indices of categories. Output for first category in pair will be\n",
" # smaller than output for second category.\n",
" #\n",
" # Don't forget to set monotonicity of corresponding dimension of Lattice\n",
" # layer to '1'.\n",
" monotonicities=[(0, 1)],\n",
" # This initializer is identical to default one('uniform'), but has fixed\n",
" # seed in order to simplify experimentation.\n",
" kernel_initializer=tf.keras.initializers.RandomUniform(\n",
" minval=0.0, maxval=lattice_sizes[5] - 1.0, seed=1))\n",
"combined_calibrators.append(calibrator)\n",
"\n",
"# ############### restecg ###############\n",
"calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=3,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[6] - 1.0,\n",
" # Categorical monotonicity can be partial order.\n",
" monotonicities=[(0, 1), (0, 2)],\n",
" # Categorical calibration layer supports standard Keras regularizers.\n",
" kernel_regularizer=tf.keras.regularizers.l1_l2(l1=0.001),\n",
" kernel_initializer='constant')\n",
"combined_calibrators.append(calibrator)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "inyNlSBeQyp7"
},
"source": [
"그런 다음 calibrator의 출력을 비선형적으로 융합하기 위해 격자 레이어를 만듭니다.\n",
"\n",
"필요한 차원에 대해 증가할 격자의 단조를 지정해야 합니다. 보정에서 단조로운 방향의 구성은 단조의 엔드 투 엔드 방향을 올바르게 만듭니다. 여기에는 CategoricalCalibration 레이어의 부분 단조가 포함됩니다."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:53.532943Z",
"iopub.status.busy": "2021-10-09T00:20:53.532369Z",
"iopub.status.idle": "2021-10-09T00:20:53.533948Z",
"shell.execute_reply": "2021-10-09T00:20:53.534284Z"
},
"id": "DNCc9oBTRo6w"
},
"outputs": [],
"source": [
"lattice = tfl.layers.Lattice(\n",
" lattice_sizes=lattice_sizes,\n",
" monotonicities=[\n",
" 'increasing', 'none', 'increasing', 'increasing', 'increasing',\n",
" 'increasing', 'increasing'\n",
" ],\n",
" output_min=0.0,\n",
" output_max=1.0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "T5q2InayRpDr"
},
"source": [
"그런 다음 결합된 calibrator 및 격자 레이어를 사용하여 순차형 모델을 만들 수 있습니다."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:54.753434Z",
"iopub.status.busy": "2021-10-09T00:20:54.186711Z",
"iopub.status.idle": "2021-10-09T00:20:55.042978Z",
"shell.execute_reply": "2021-10-09T00:20:55.043401Z"
},
"id": "xX6lroYZQy3L"
},
"outputs": [],
"source": [
"model = tf.keras.models.Sequential()\n",
"model.add(combined_calibrators)\n",
"model.add(lattice)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W3UFxD3fRzIC"
},
"source": [
"훈련은 다른 Keras 모델과 동일하게 동작합니다."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:20:55.054246Z",
"iopub.status.busy": "2021-10-09T00:20:55.053648Z",
"iopub.status.idle": "2021-10-09T00:21:05.356521Z",
"shell.execute_reply": "2021-10-09T00:21:05.356898Z"
},
"id": "2jz4JvI-RzSj"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
" 1/10 [==>...........................] - ETA: 0s - loss: 0.1265"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r",
"10/10 [==============================] - 0s 2ms/step - loss: 0.1551\n"
]
},
{
"data": {
"text/plain": [
"0.1550564467906952"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"features = training_data_df[[\n",
" 'age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg'\n",
"]].values.astype(np.float32)\n",
"target = training_data_df[['target']].values.astype(np.float32)\n",
"\n",
"model.compile(\n",
" loss=tf.keras.losses.mean_squared_error,\n",
" optimizer=tf.keras.optimizers.Adagrad(learning_rate=LEARNING_RATE))\n",
"model.fit(\n",
" features,\n",
" target,\n",
" batch_size=BATCH_SIZE,\n",
" epochs=NUM_EPOCHS,\n",
" validation_split=0.2,\n",
" shuffle=False,\n",
" verbose=0)\n",
"\n",
"model.evaluate(features, target)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "RTHoW_5lxwT5"
},
"source": [
"## 함수형 Keras 모델\n",
"\n",
"이 예제에서는 Keras 모델 생성을 위한 함수형 API를 사용합니다.\n",
"\n",
"이전 섹션에서 언급했듯이 격자 레이어는 `input[i]`가 `[0, lattice_sizes[i] - 1.0]` 내에 있을 것으로 예상되므로 보정 레이어보다 먼저 격자 크기를 정의해야 보정 레이어의 출력 범위를 적절하게 지정할 수 있습니다."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.360951Z",
"iopub.status.busy": "2021-10-09T00:21:05.360346Z",
"iopub.status.idle": "2021-10-09T00:21:05.362430Z",
"shell.execute_reply": "2021-10-09T00:21:05.362013Z"
},
"id": "gJjUYvBuW1qE"
},
"outputs": [],
"source": [
"# We are going to have 2-d embedding as one of lattice inputs.\n",
"lattice_sizes = [3, 2, 2, 3, 3, 2, 2]"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Z03qY5MYW1yT"
},
"source": [
"각 특성에 대해 입력 레이어와 보정 레이어를 만들어야 합니다. 숫자 특성에는 `tfl.layers.PWLCalibration`을 사용하고 범주형 특성에는 `tfl.layers.CategoricalCalibration`을 사용합니다."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.380857Z",
"iopub.status.busy": "2021-10-09T00:21:05.378613Z",
"iopub.status.idle": "2021-10-09T00:21:05.455080Z",
"shell.execute_reply": "2021-10-09T00:21:05.455451Z"
},
"id": "DCIUz8apzs0l"
},
"outputs": [],
"source": [
"model_inputs = []\n",
"lattice_inputs = []\n",
"# ############### age ###############\n",
"age_input = tf.keras.layers.Input(shape=[1], name='age')\n",
"model_inputs.append(age_input)\n",
"age_calibrator = tfl.layers.PWLCalibration(\n",
" # Every PWLCalibration layer must have keypoints of piecewise linear\n",
" # function specified. Easiest way to specify them is to uniformly cover\n",
" # entire input range by using numpy.linspace().\n",
" input_keypoints=np.linspace(\n",
" training_data_df['age'].min(), training_data_df['age'].max(), num=5),\n",
" # You need to ensure that input keypoints have same dtype as layer input.\n",
" # You can do it by setting dtype here or by providing keypoints in such\n",
" # format which will be converted to desired tf.dtype by default.\n",
" dtype=tf.float32,\n",
" # Output range must correspond to expected lattice input range.\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[0] - 1.0,\n",
" monotonicity='increasing',\n",
" name='age_calib',\n",
")(\n",
" age_input)\n",
"lattice_inputs.append(age_calibrator)\n",
"\n",
"# ############### sex ###############\n",
"# For boolean features simply specify CategoricalCalibration layer with 2\n",
"# buckets.\n",
"sex_input = tf.keras.layers.Input(shape=[1], name='sex')\n",
"model_inputs.append(sex_input)\n",
"sex_calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=2,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[1] - 1.0,\n",
" # Initializes all outputs to (output_min + output_max) / 2.0.\n",
" kernel_initializer='constant',\n",
" name='sex_calib',\n",
")(\n",
" sex_input)\n",
"lattice_inputs.append(sex_calibrator)\n",
"\n",
"# ############### cp ###############\n",
"cp_input = tf.keras.layers.Input(shape=[1], name='cp')\n",
"model_inputs.append(cp_input)\n",
"cp_calibrator = tfl.layers.PWLCalibration(\n",
" # Here instead of specifying dtype of layer we convert keypoints into\n",
" # np.float32.\n",
" input_keypoints=np.linspace(1, 4, num=4, dtype=np.float32),\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[2] - 1.0,\n",
" monotonicity='increasing',\n",
" # You can specify TFL regularizers as tuple ('regularizer name', l1, l2).\n",
" kernel_regularizer=('hessian', 0.0, 1e-4),\n",
" name='cp_calib',\n",
")(\n",
" cp_input)\n",
"lattice_inputs.append(cp_calibrator)\n",
"\n",
"# ############### trestbps ###############\n",
"trestbps_input = tf.keras.layers.Input(shape=[1], name='trestbps')\n",
"model_inputs.append(trestbps_input)\n",
"trestbps_calibrator = tfl.layers.PWLCalibration(\n",
" # Alternatively, you might want to use quantiles as keypoints instead of\n",
" # uniform keypoints\n",
" input_keypoints=np.quantile(training_data_df['trestbps'],\n",
" np.linspace(0.0, 1.0, num=5)),\n",
" dtype=tf.float32,\n",
" # Together with quantile keypoints you might want to initialize piecewise\n",
" # linear function to have 'equal_slopes' in order for output of layer\n",
" # after initialization to preserve original distribution.\n",
" kernel_initializer='equal_slopes',\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[3] - 1.0,\n",
" # You might consider clamping extreme inputs of the calibrator to output\n",
" # bounds.\n",
" clamp_min=True,\n",
" clamp_max=True,\n",
" monotonicity='increasing',\n",
" name='trestbps_calib',\n",
")(\n",
" trestbps_input)\n",
"lattice_inputs.append(trestbps_calibrator)\n",
"\n",
"# ############### chol ###############\n",
"chol_input = tf.keras.layers.Input(shape=[1], name='chol')\n",
"model_inputs.append(chol_input)\n",
"chol_calibrator = tfl.layers.PWLCalibration(\n",
" # Explicit input keypoint initialization.\n",
" input_keypoints=[126.0, 210.0, 247.0, 286.0, 564.0],\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[4] - 1.0,\n",
" # Monotonicity of calibrator can be decreasing. Note that corresponding\n",
" # lattice dimension must have INCREASING monotonicity regardless of\n",
" # monotonicity direction of calibrator.\n",
" monotonicity='decreasing',\n",
" # Convexity together with decreasing monotonicity result in diminishing\n",
" # return constraint.\n",
" convexity='convex',\n",
" # You can specify list of regularizers. You are not limited to TFL\n",
" # regularizrs. Feel free to use any :)\n",
" kernel_regularizer=[('laplacian', 0.0, 1e-4),\n",
" tf.keras.regularizers.l1_l2(l1=0.001)],\n",
" name='chol_calib',\n",
")(\n",
" chol_input)\n",
"lattice_inputs.append(chol_calibrator)\n",
"\n",
"# ############### fbs ###############\n",
"fbs_input = tf.keras.layers.Input(shape=[1], name='fbs')\n",
"model_inputs.append(fbs_input)\n",
"fbs_calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=2,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[5] - 1.0,\n",
" # For categorical calibration layer monotonicity is specified for pairs\n",
" # of indices of categories. Output for first category in pair will be\n",
" # smaller than output for second category.\n",
" #\n",
" # Don't forget to set monotonicity of corresponding dimension of Lattice\n",
" # layer to '1'.\n",
" monotonicities=[(0, 1)],\n",
" # This initializer is identical to default one ('uniform'), but has fixed\n",
" # seed in order to simplify experimentation.\n",
" kernel_initializer=tf.keras.initializers.RandomUniform(\n",
" minval=0.0, maxval=lattice_sizes[5] - 1.0, seed=1),\n",
" name='fbs_calib',\n",
")(\n",
" fbs_input)\n",
"lattice_inputs.append(fbs_calibrator)\n",
"\n",
"# ############### restecg ###############\n",
"restecg_input = tf.keras.layers.Input(shape=[1], name='restecg')\n",
"model_inputs.append(restecg_input)\n",
"restecg_calibrator = tfl.layers.CategoricalCalibration(\n",
" num_buckets=3,\n",
" output_min=0.0,\n",
" output_max=lattice_sizes[6] - 1.0,\n",
" # Categorical monotonicity can be partial order.\n",
" monotonicities=[(0, 1), (0, 2)],\n",
" # Categorical calibration layer supports standard Keras regularizers.\n",
" kernel_regularizer=tf.keras.regularizers.l1_l2(l1=0.001),\n",
" kernel_initializer='constant',\n",
" name='restecg_calib',\n",
")(\n",
" restecg_input)\n",
"lattice_inputs.append(restecg_calibrator)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Fr0k8La_YgQG"
},
"source": [
"그런 다음 calibrator의 출력을 비선형적으로 융합하기 위해 격자 레이어를 만듭니다.\n",
"\n",
"필요한 차원에 대해 증가할 격자의 단조를 지정해야 합니다. 보정에서 단조로운 방향의 구성은 단조의 엔드 투 엔드 방향을 올바르게 만듭니다. 여기에는 `tfl.layers.CategoricalCalibration` 레이어의 부분 단조가 포함됩니다."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.462437Z",
"iopub.status.busy": "2021-10-09T00:21:05.461168Z",
"iopub.status.idle": "2021-10-09T00:21:05.514216Z",
"shell.execute_reply": "2021-10-09T00:21:05.513714Z"
},
"id": "X15RE0NybNbU"
},
"outputs": [],
"source": [
"lattice = tfl.layers.Lattice(\n",
" lattice_sizes=lattice_sizes,\n",
" monotonicities=[\n",
" 'increasing', 'none', 'increasing', 'increasing', 'increasing',\n",
" 'increasing', 'increasing'\n",
" ],\n",
" output_min=0.0,\n",
" output_max=1.0,\n",
" name='lattice',\n",
")(\n",
" lattice_inputs)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "31VzsnMCA9dh"
},
"source": [
"모델에 더 많은 유연성을 추가하기 위해 출력 보정 레이어를 추가합니다."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.521044Z",
"iopub.status.busy": "2021-10-09T00:21:05.520443Z",
"iopub.status.idle": "2021-10-09T00:21:05.530923Z",
"shell.execute_reply": "2021-10-09T00:21:05.531271Z"
},
"id": "efCP3Yx2A9n7"
},
"outputs": [],
"source": [
"model_output = tfl.layers.PWLCalibration(\n",
" input_keypoints=np.linspace(0.0, 1.0, 5),\n",
" name='output_calib',\n",
")(\n",
" lattice)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1SURnNl8bNgw"
},
"source": [
"이제 입력과 출력을 사용하여 모델을 만들 수 있습니다."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.535919Z",
"iopub.status.busy": "2021-10-09T00:21:05.535335Z",
"iopub.status.idle": "2021-10-09T00:21:05.672810Z",
"shell.execute_reply": "2021-10-09T00:21:05.673186Z"
},
"id": "7gY-VXuYbZLa"
},
"outputs": [
{
"data": {
"image/png": "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AGgrUFsCAAAAAABAS6G2BAAA+H/Pnj1jOgIAAEBbhdoSAADg//Xq1cvExMTPz+/u3bv47iUAAECToLYEAAD4f9euXePz+UePHh08eLChoeHixYtv3LhRXV3NdC4AAIA2ALUlAADA/xs5cmRISMjff//98OHDhQsXpqWljRo1SldX193dPS4uDmcyAQAAREBtCQAAUFu/fv18fHzi4uJevHixfPny2NjYESNGGBoaenp6xsXFMZ0OAACgNUJtCQAA0KBu3br5+Pg8fvz44cOH33333aVLl0aMGNG3b9+tW7e+fv2a6XQAAACtCGpLAACAxvXr18/f3z8rKys+Pt7Gxmbz5s1du3adNGnSH3/88enTJ6bTAQAAMA+1JQAAgLhYLNbw4cP37t2bm5t78ODB0tJSBweHLl26/PDDD1lZWUynAwAAYBJqSwAAgCbjcrkuLi4xMTF//fXXokWLzp49a2xsbG9v/8cff2BeWQAA6JhQWwIAADTf559/vnr16mfPnl25coXH402dOvXzzz/39/fPz89nOhoAAIBMobYEAABoKTabPXr06FOnTmVkZEyfPj0kJKRr165z5sx5+PAh09EAAABkhCWNu3WxWKxhw4Z16dJF4muGtiU7OzspKQl3hJOZadOmJSUlDRs2jOkgAG2PZI9XpaWlv/76686dOx8/fjxu3Ljly5fb2tpKZM0AAACtllTOWzo6OqKwBEJIly5dHB0dmU7RgVhYWKCwBGgeyR6vlJWV3dzcHjx4cOXKFTabzefzBw0adOTIkaqqKkltAgAAoLWRynlLAAAAELhz505AQMDZs2eNjIxWrVo1a9YseXl5pkMBAABIGL5vCQAAIF1Dhw49c+ZMZmamra2tu7t73759jxw5gulkAQCgnUFtCQAAIAs9e/bcv3//06dPR44cOXfu3F69eoWHh6PCBACAdgO1JQAAgOwYGhqGhYU9efLEysrKw8PDxMTk7NmzTIcCAACQANSWAAAAstazZ88jR448evTI1NR06tSp1tbWKSkpTIcCAABoEdSWAAAAzOjTp8+JEyeSk5PZbPbQoUOdnJxevHjBdCgAAIBmQm0JAADApMGDB9+8efPMmTP37t3r16+fr6/vhw8fmA4FAADQZLgHCQAAQKvw6dOnPXv2rFu3jsPh7Nixw9nZmelEAAAATYDzlgAAAK2CgoLCkiVL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bWp08uTJoKAgdc2tIerSpcu7d+8yMzOZDkQphw4d2rVrV0pKitaWyGKxwsPDAwMDtbbERsDb23vIkCGBgYGKbzhE6wNQo9GjRxNCTp06xXQgOqqsrGzu3Ln79+9ftGjRL7/8wuFwtB/D9u3bFy9efP/+/S+++EL7SwcAAHlwl2MTtXfv3gULFjAdBdSCHgAWAEBHPH36NDAw8N9///3zzz/pB1+17/3792vXrv3Pf/6DxBIAQNdo+3lLYNCBAwdGjhxZUlKyd+/eDx8+4BIiAAAo78yZMz179mSz2SkpKUwlloSQZcuWcblc8T3VAACgO5BbqkFwcDCLxbp79+6bN29YLBb9QgjddPbsWTMzsz179pw4cQJj84AWsORbtWoV09EBgFLo+2BHjRrl6+sbFxcnNQicNqWlpR04cGDjxo3NmjVjKgYAAJAH2YUaLFy4cOHChUxHUbupU6dOnTqV6SigacFToAAN3ZMnT4KCgl68eHHixImgoCAGIxGJRLNmzerdu/eECRMYDAMAAORBbgkAAAA1O3r06KxZs9q3b5+WltaqVStmg9m/f39ycnJKSgr9ilQAANA1uCcWAAAApBUWFo4bN27SpEnffPNNXFwc44llfn7+8uXL586d6+zszGwkAAAgD65bAgAAwH9JSEgYP358cXFxRETEsGHDmA6HEEL+85//8Hi8n376ielAAABALly3BAAAgP9VVVW1atUqNze3Nm3a3LlzR0cSy7i4uCNHjuzYsQND+AAA6DJctwQAAABCCHn58uX48eNTU1M3b948Z84cHXmssaqqavbs2Z6engEBAUzHAgAAiiC3BAAAaOooijp48OCCBQtat259+/btDh06MB3R/7dly5aMjIyTJ08yHQgAANQC98QCAAA0aW/evBk6dOiMGTO+++67hIQEnUosX79+vXbt2h9++KFt27ZMxwIAALXAdUsAAICm69SpUzNmzDA1NY2Jienfvz/T4UibO3eutbX1kiVLmA4EAABqh+uWAAAATdHbt2/9/f2DgoICAgLu3bung4llRETEX3/9tWvXLgMDA6ZjAQCA2uG6JQAAQJNz4sSJ2bNnN2vW7OrVq0KhkOlwalBUVDRr1qxx48YNHjyY6VgAAEApuG4JAADQhLx+/Xr48OFjx46lL1fqZmJJCFm8eHFpaemWLVuYDgQAAJSF65YAAABN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\n",
"text/plain": [
""
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = tf.keras.models.Model(\n",
" inputs=model_inputs,\n",
" outputs=model_output)\n",
"tf.keras.utils.plot_model(model, rankdir='LR')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tvFJTs94bZXK"
},
"source": [
"훈련은 다른 Keras 모델과 동일하게 동작합니다. 설정에서 입력 특성은 별도의 텐서로 전달됩니다."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"execution": {
"iopub.execute_input": "2021-10-09T00:21:05.685754Z",
"iopub.status.busy": "2021-10-09T00:21:05.685109Z",
"iopub.status.idle": "2021-10-09T00:21:13.713178Z",
"shell.execute_reply": "2021-10-09T00:21:13.712737Z"
},
"id": "vMQTGbFAYgYS"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\r",
" 1/10 [==>...........................] - ETA: 0s - loss: 0.1400"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r",
"10/10 [==============================] - 0s 3ms/step - loss: 0.1591\n"
]
},
{
"data": {
"text/plain": [
"0.15907342731952667"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"feature_names = ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg']\n",
"features = np.split(\n",
" training_data_df[feature_names].values.astype(np.float32),\n",
" indices_or_sections=len(feature_names),\n",
" axis=1)\n",
"target = training_data_df[['target']].values.astype(np.float32)\n",
"\n",
"model.compile(\n",
" loss=tf.keras.losses.mean_squared_error,\n",
" optimizer=tf.keras.optimizers.Adagrad(LEARNING_RATE))\n",
"model.fit(\n",
" features,\n",
" target,\n",
" batch_size=BATCH_SIZE,\n",
" epochs=NUM_EPOCHS,\n",
" validation_split=0.2,\n",
" shuffle=False,\n",
" verbose=0)\n",
"\n",
"model.evaluate(features, target)"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"name": "keras_layers.ipynb",
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
}
},
"nbformat": 4,
"nbformat_minor": 0
}