├── compare.png
├── paper.png
├── requirements.txt
├── output_11_2.png
├── output_4_2.png
├── model.py
├── train.py
├── data_preparation.py
├── README.md
└── result.ipynb
/compare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmjayAhn/SuperTML-pytorch/HEAD/compare.png
--------------------------------------------------------------------------------
/paper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmjayAhn/SuperTML-pytorch/HEAD/paper.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | scikit-learn
3 | torch
4 | torchvision
5 | Pillow
6 |
--------------------------------------------------------------------------------
/output_11_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmjayAhn/SuperTML-pytorch/HEAD/output_11_2.png
--------------------------------------------------------------------------------
/output_4_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmjayAhn/SuperTML-pytorch/HEAD/output_4_2.png
--------------------------------------------------------------------------------
/model.py:
--------------------------------------------------------------------------------
1 | import torch.nn as nn
2 | from torchvision import models
3 |
4 | model_res = models.resnet18(pretrained=True)
5 | num_features = model_res.fc.in_features
6 | model_res.fc = nn.Linear(num_features, 3)
7 |
--------------------------------------------------------------------------------
/train.py:
--------------------------------------------------------------------------------
1 | import copy
2 | import time
3 |
4 | import torch
5 |
6 | def train_model(model, dataloaders, dataset_sizes, criterion, optimizer, device, epochs=20):
7 | start = time.time()
8 |
9 | best_model_weights = copy.deepcopy(model.state_dict())
10 | best_acc = 0.0
11 |
12 | for epoch in range(epochs):
13 | print("EPOCH {} / {}: ".format(epoch+1, epochs))
14 | print("-" * 10)
15 |
16 | for phase in ['train', 'val']:
17 | if phase == 'train':
18 | model.train()
19 | else:
20 | model.eval()
21 |
22 | batch_loss = 0.0
23 | batch_corrects = 0
24 |
25 | for inputs, labels in dataloaders[phase]:
26 | inputs = inputs.to(device)
27 | labels = labels.to(device)
28 |
29 | optimizer.zero_grad()
30 |
31 | with torch.set_grad_enabled(phase =='train'):
32 | outputs = model(inputs)
33 | _, preds = torch.max(outputs, 1)
34 | loss = criterion(outputs, labels)
35 |
36 | if phase == 'train':
37 | loss.backward()
38 | optimizer.step()
39 | batch_loss += loss.item() * inputs.size(0)
40 | batch_corrects += torch.sum(preds == labels.data)
41 |
42 | epoch_loss = batch_loss / dataset_sizes[phase]
43 | epoch_acc = batch_corrects.double() / dataset_sizes[phase]
44 |
45 | print("{} Loss: {:.4f} Acc: {: .4f}".format(phase, epoch_loss, epoch_acc))
46 |
47 | if phase == 'val' and epoch_acc > best_acc:
48 | best_acc = epoch_acc
49 | best_model_weights = copy.deepcopy(model.state_dict())
50 |
51 | end = time.time()
52 | elapsed_time = end - start
53 | print("Training COMPLETED: {:.0f}m {:.0f}s".format(elapsed_time // 60, elapsed_time % 60))
54 | print("BEST VALIDATION ACCURACY: {:4f}".format(best_acc))
55 |
56 | model.load_state_dict(best_model_weights)
57 | return model
--------------------------------------------------------------------------------
/data_preparation.py:
--------------------------------------------------------------------------------
1 | from PIL import Image, ImageDraw, ImageFont
2 | import numpy as np
3 |
4 | def show_column_position(dat):
5 | font = ImageFont.truetype("Arial.ttf", size=20)
6 | background = np.array([[0 for _ in range(255)] for _ in range(255)], dtype='uint8')
7 | image = Image.fromarray(background)
8 | draw = ImageDraw.Draw(image)
9 | draw.text((32, 32), str(dat[0][:12]), fill='white', font=font)
10 | draw.text((32, 160), str(dat[1][:11]), fill='white', font=font)
11 | draw.text((160, 32), str(dat[2][:11]), fill='white', font=font)
12 | draw.text((160, 160), str(dat[3][:11]), fill='white', font=font)
13 | rgb = [np.array(image, dtype='uint8') for _ in range(3)]
14 | return np.array(rgb)
15 |
16 | def show_column_position_another(dat):
17 | font = ImageFont.truetype("Arial.ttf", size=20)
18 | background = np.array([[0 for _ in range(255)] for _ in range(255)], dtype='uint8')
19 | image = Image.fromarray(background)
20 | draw = ImageDraw.Draw(image)
21 | draw.text((32, 32), str(dat[2][:12]), fill='white', font=font)
22 | draw.text((32, 160), str(dat[3][:11]), fill='white', font=font)
23 | draw.text((160, 32), str(dat[1][:11]), fill='white', font=font)
24 | draw.text((160, 160), str(dat[0][:11]), fill='white', font=font)
25 | rgb = [np.array(image, dtype='uint8') for _ in range(3)]
26 | return np.array(rgb)
27 |
28 | def data_to_image(data):
29 | data_images = []
30 | font = ImageFont.truetype("Arial.ttf", size=50)
31 | for dat in data:
32 | background = np.array([[0 for _ in range(255)] for _ in range(255)], dtype='uint8')
33 | image = Image.fromarray(background)
34 | draw = ImageDraw.Draw(image)
35 | draw.text((32, 32), str(dat[0]), fill='white', font=font)
36 | draw.text((32, 160), str(dat[1]), fill='white', font=font)
37 | draw.text((160, 32), str(dat[2]), fill='white', font=font)
38 | draw.text((160, 160), str(dat[3]), fill='white', font=font)
39 | rgb = [np.array(image, dtype='uint8') for _ in range(3)]
40 | data_images.append(rgb)
41 | return np.array(data_images) / 255
42 |
43 | def data_to_image_another(data):
44 | data_images = []
45 | font = ImageFont.truetype("Arial.ttf", size=50)
46 | for dat in data:
47 | background = np.array([[0 for _ in range(255)] for _ in range(255)], dtype='uint8')
48 | image = Image.fromarray(background)
49 | draw = ImageDraw.Draw(image)
50 | draw.text((32, 32), str(dat[2]), fill='white', font=font)
51 | draw.text((32, 160), str(dat[3]), fill='white', font=font)
52 | draw.text((160, 32), str(dat[1]), fill='white', font=font)
53 | draw.text((160, 160), str(dat[0]), fill='white', font=font)
54 | rgb = [np.array(image, dtype='uint8') for _ in range(3)]
55 | data_images.append(rgb)
56 | return np.array(data_images) / 255
57 |
58 |
59 | if __name__ == '__main__':
60 | from sklearn.datasets import load_iris
61 | data = load_iris()
62 | img_array = data_to_image(data.data)
63 | img = Image.fromarray(img_array)
64 | img.show()
65 |
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Super TML
3 | ---
4 | Pytorch Implementation [Super TML: Two-Dimensional Word Embedding for the Precognition on Structured Tabular Data](https://arxiv.org/abs/1903.06246) with iris data.
5 | I was very interested in its core idea which is tabular data can be embedded to 2 dimension-matrix. I just wondered "IT IS WORK REALLY??" so let me check, let's code!
6 | 
7 |
8 | ### Prerequisites
9 | - Python 3+
10 | - Pytorch (including torchvision)
11 | - Pillow
12 | - Scikit Learn (for downloading data)
13 |
14 | - Also can run on `./result.ipynb` notebook
15 |
16 | ### Imports & Settings
17 |
18 |
19 | ```python
20 | import warnings
21 | import numpy as np
22 | import matplotlib.pyplot as plt
23 |
24 | from sklearn.model_selection import train_test_split
25 | from sklearn.datasets import load_iris
26 |
27 | import torch
28 | import torch.nn as nn
29 | import torch.optim as optim
30 | from torch.utils.data import DataLoader, TensorDataset
31 |
32 | from data_preparation import data_to_image
33 | from model import model_res
34 | from train import train_model
35 |
36 | torch.backends.cudnn.enabled = False
37 | device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
38 |
39 | %load_ext autoreload
40 | %autoreload 2
41 | %matplotlib inline
42 | warnings.filterwarnings("ignore")
43 | %config InlineBackend.figure_format = 'retina'
44 | ```
45 |
46 | ### Data Preparation
47 |
48 |
49 | ```python
50 | iris_data = load_iris()
51 |
52 | X_train, X_val, y_train, y_val = train_test_split(iris_data.data, iris_data.target, stratify=iris_data.target, test_size=0.2, random_state=0)
53 |
54 | train_images = data_to_image(X_train)
55 | val_images = data_to_image(X_val)
56 |
57 | print(train_images.shape)
58 | print(val_images.shape)
59 | plt.grid()
60 | plt.imshow(train_images[0][0, :, :])
61 | ```
62 |
63 | (120, 3, 255, 255)
64 | (30, 3, 255, 255)
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 
76 |
77 |
78 |
79 | ```python
80 | X_train = torch.from_numpy(train_images).float()
81 | y_train = torch.from_numpy(y_train).long()
82 | X_val = torch.from_numpy(val_images).float()
83 | y_val = torch.from_numpy(y_val).long()
84 |
85 | train_dataset = TensorDataset(X_train, y_train)
86 | val_dataset = TensorDataset(X_val, y_val)
87 |
88 | dataloaders = {'train': DataLoader(train_dataset, batch_size=16, shuffle=True),
89 | 'val': DataLoader(val_dataset)}
90 |
91 | dataset_sizes = {'train': len(X_train),
92 | 'val': len(X_val)}
93 | ```
94 |
95 | ### Modeling
96 | - Transfer Learning from Resnet
97 | - I changed just fully connect layer at the end to 3 outputs
98 |
99 |
100 | ```python
101 | model = model_res.to(device)
102 |
103 | criterion = nn.CrossEntropyLoss()
104 | optimizer = optim.Adam(model.parameters())
105 |
106 | ```
107 |
108 | > Actually IT WORKS!!
109 |
110 |
111 | ```python
112 | best_model = train_model(model, dataloaders, dataset_sizes, criterion, optimizer, device, epochs=20)
113 | ```
114 |
115 | EPOCH 1 / 20:
116 | ----------
117 | val Loss: 5.3997 Acc: 0.3333
118 | EPOCH 2 / 20:
119 | ----------
120 | val Loss: 0.6481 Acc: 0.8333
121 | EPOCH 3 / 20:
122 | ----------
123 | val Loss: 0.9328 Acc: 0.7667
124 | EPOCH 4 / 20:
125 | ----------
126 | val Loss: 0.3546 Acc: 0.9333
127 | EPOCH 5 / 20:
128 | ----------
129 | val Loss: 0.4566 Acc: 0.9333
130 | EPOCH 6 / 20:
131 | ----------
132 | val Loss: 0.2912 Acc: 0.8667
133 | EPOCH 7 / 20:
134 | ----------
135 | val Loss: 0.2331 Acc: 0.9333
136 | EPOCH 8 / 20:
137 | ----------
138 | val Loss: 0.4565 Acc: 0.9333
139 | EPOCH 9 / 20:
140 | ----------
141 | val Loss: 0.3249 Acc: 0.9667
142 | EPOCH 10 / 20:
143 | ----------
144 | val Loss: 0.4116 Acc: 0.9000
145 | EPOCH 11 / 20:
146 | ----------
147 | val Loss: 0.3704 Acc: 0.9333
148 | EPOCH 12 / 20:
149 | ----------
150 | val Loss: 0.3225 Acc: 0.9333
151 | EPOCH 13 / 20:
152 | ----------
153 | val Loss: 0.6221 Acc: 0.9333
154 | EPOCH 14 / 20:
155 | ----------
156 | val Loss: 0.8669 Acc: 0.8667
157 | EPOCH 15 / 20:
158 | ----------
159 | val Loss: 0.3086 Acc: 0.9333
160 | EPOCH 16 / 20:
161 | ----------
162 | val Loss: 0.3501 Acc: 0.9333
163 | EPOCH 17 / 20:
164 | ----------
165 | val Loss: 0.1983 Acc: 0.9333
166 | EPOCH 18 / 20:
167 | ----------
168 | val Loss: 0.1258 Acc: 0.9667
169 | EPOCH 19 / 20:
170 | ----------
171 | val Loss: 4.1496 Acc: 0.4000
172 | EPOCH 20 / 20:
173 | ----------
174 | val Loss: 2.8034 Acc: 0.5667
175 | Training COMPLETED: 0m 27s
176 | BEST VALIDATION ACCURACY: 0.966667
177 |
178 |
179 | ### Further Experiments
180 | One of my study group members was curious if the performance could be affected by the columns' positions. Let's check! I will change its position like below left to right and the other conditions are all same.
181 |
182 | 
183 |
184 | result: Their Location doesn't matter with model performance
185 |
186 |
187 | ```python
188 | from data_preparation import data_to_image_another
189 |
190 | iris_data = load_iris()
191 |
192 | X_train, X_val, y_train, y_val = train_test_split(iris_data.data, iris_data.target, stratify=iris_data.target, test_size=0.2, random_state=0)
193 |
194 | train_images = data_to_image_another(X_train)
195 | val_images = data_to_image_another(X_val)
196 |
197 | print(train_images.shape)
198 | print(val_images.shape)
199 | plt.grid()
200 | plt.imshow(train_images[0][0, :, :])
201 | ```
202 |
203 | (120, 3, 255, 255)
204 | (30, 3, 255, 255)
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 | 
216 |
217 |
218 |
219 | ```python
220 | X_train = torch.from_numpy(train_images).float()
221 | y_train = torch.from_numpy(y_train).long()
222 | X_val = torch.from_numpy(val_images).float()
223 | y_val = torch.from_numpy(y_val).long()
224 |
225 | train_dataset = TensorDataset(X_train, y_train)
226 | val_dataset = TensorDataset(X_val, y_val)
227 |
228 | dataloaders = {'train': DataLoader(train_dataset, batch_size=16, shuffle=True),
229 | 'val': DataLoader(val_dataset)}
230 |
231 | dataset_sizes = {'train': len(X_train),
232 | 'val': len(X_val)}
233 |
234 | model_another = model_res.to(device)
235 |
236 | criterion = nn.CrossEntropyLoss()
237 | optimizer = optim.Adam(model_another.parameters())
238 |
239 | best_model = train_model(model_another, dataloaders, dataset_sizes, criterion, optimizer, device, epochs=20)
240 | ```
241 |
242 | EPOCH 1 / 20:
243 | ----------
244 | val Loss: 4.3803 Acc: 0.6667
245 | EPOCH 2 / 20:
246 | ----------
247 | val Loss: 49.4471 Acc: 0.3333
248 | EPOCH 3 / 20:
249 | ----------
250 | val Loss: 1.4664 Acc: 0.7000
251 | EPOCH 4 / 20:
252 | ----------
253 | val Loss: 0.7917 Acc: 0.8667
254 | EPOCH 5 / 20:
255 | ----------
256 | val Loss: 1.6323 Acc: 0.8333
257 | EPOCH 6 / 20:
258 | ----------
259 | val Loss: 1.8395 Acc: 0.6667
260 | EPOCH 7 / 20:
261 | ----------
262 | val Loss: 0.4488 Acc: 0.9333
263 | EPOCH 8 / 20:
264 | ----------
265 | val Loss: 0.2794 Acc: 0.9333
266 | EPOCH 9 / 20:
267 | ----------
268 | val Loss: 0.1849 Acc: 0.9667
269 | EPOCH 10 / 20:
270 | ----------
271 | val Loss: 0.1331 Acc: 0.9667
272 | EPOCH 11 / 20:
273 | ----------
274 | val Loss: 0.1345 Acc: 0.9667
275 | EPOCH 12 / 20:
276 | ----------
277 | val Loss: 0.3936 Acc: 0.9333
278 | EPOCH 13 / 20:
279 | ----------
280 | val Loss: 0.1830 Acc: 0.9333
281 | EPOCH 14 / 20:
282 | ----------
283 | val Loss: 0.1597 Acc: 0.9667
284 | EPOCH 15 / 20:
285 | ----------
286 | val Loss: 0.1071 Acc: 0.9667
287 | EPOCH 16 / 20:
288 | ----------
289 | val Loss: 0.3240 Acc: 0.8667
290 | EPOCH 17 / 20:
291 | ----------
292 | val Loss: 0.2489 Acc: 0.9333
293 | EPOCH 18 / 20:
294 | ----------
295 | val Loss: 0.2280 Acc: 0.9333
296 | EPOCH 19 / 20:
297 | ----------
298 | val Loss: 0.2546 Acc: 0.9667
299 | EPOCH 20 / 20:
300 | ----------
301 | val Loss: 0.2007 Acc: 0.9667
302 | Training COMPLETED: 0m 27s
303 | BEST VALIDATION ACCURACY: 0.966667
304 |
305 |
306 | ---
307 | I just coded for fun and curiosity, but this simple implementation gives very new insights of relation between tabular data and embeddings.
308 |
--------------------------------------------------------------------------------
/result.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "attachments": {},
5 | "cell_type": "markdown",
6 | "metadata": {},
7 | "source": [
8 | "# Super TML\n",
9 | "---\n",
10 | "Pytorch Implementation [Super TML: Two-Dimensional Word Embedding for the Precognition on Structured Tabular Data](https://arxiv.org/abs/1903.06246) with iris data.\n",
11 | "I was very interested in its core idea which is tabular data can be embedded to 2 dimension-matrix. I just wondered \"IT IS WORK REALLY??\" so let me check, let's code!\n",
12 | ""
13 | ]
14 | },
15 | {
16 | "cell_type": "markdown",
17 | "metadata": {},
18 | "source": [
19 | "## Imports & Settings"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 1,
25 | "metadata": {
26 | "scrolled": true
27 | },
28 | "outputs": [],
29 | "source": [
30 | "import warnings\n",
31 | "import numpy as np\n",
32 | "import matplotlib.pyplot as plt\n",
33 | "\n",
34 | "from sklearn.model_selection import train_test_split\n",
35 | "from sklearn.datasets import load_iris\n",
36 | "\n",
37 | "import torch\n",
38 | "import torch.nn as nn\n",
39 | "import torch.optim as optim\n",
40 | "from torch.utils.data import DataLoader, TensorDataset\n",
41 | "\n",
42 | "from data_preparation import data_to_image\n",
43 | "from model import model_res\n",
44 | "from train import train_model\n",
45 | "\n",
46 | "torch.backends.cudnn.enabled = False\n",
47 | "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
48 | "\n",
49 | "%load_ext autoreload\n",
50 | "%autoreload 2\n",
51 | "%matplotlib inline\n",
52 | "warnings.filterwarnings(\"ignore\")\n",
53 | "%config InlineBackend.figure_format = 'retina'"
54 | ]
55 | },
56 | {
57 | "cell_type": "markdown",
58 | "metadata": {},
59 | "source": [
60 | "## Data Preparation"
61 | ]
62 | },
63 | {
64 | "cell_type": "code",
65 | "execution_count": 2,
66 | "metadata": {
67 | "scrolled": true
68 | },
69 | "outputs": [
70 | {
71 | "name": "stdout",
72 | "output_type": "stream",
73 | "text": [
74 | "(120, 3, 255, 255)\n",
75 | "(30, 3, 255, 255)\n"
76 | ]
77 | },
78 | {
79 | "data": {
80 | "text/plain": [
81 | ""
82 | ]
83 | },
84 | "execution_count": 2,
85 | "metadata": {},
86 | "output_type": "execute_result"
87 | },
88 | {
89 | "data": {
90 | "image/png": "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\n",
91 | "text/plain": [
92 | ""
93 | ]
94 | },
95 | "metadata": {
96 | "image/png": {
97 | "height": 251,
98 | "width": 263
99 | },
100 | "needs_background": "light"
101 | },
102 | "output_type": "display_data"
103 | }
104 | ],
105 | "source": [
106 | "iris_data = load_iris()\n",
107 | "\n",
108 | "X_train, X_val, y_train, y_val = train_test_split(iris_data.data, iris_data.target, stratify=iris_data.target, test_size=0.2, random_state=0)\n",
109 | "\n",
110 | "train_images = data_to_image(X_train)\n",
111 | "val_images = data_to_image(X_val)\n",
112 | "\n",
113 | "print(train_images.shape)\n",
114 | "print(val_images.shape)\n",
115 | "plt.grid()\n",
116 | "plt.imshow(train_images[0][0, :, :])"
117 | ]
118 | },
119 | {
120 | "cell_type": "code",
121 | "execution_count": 3,
122 | "metadata": {},
123 | "outputs": [],
124 | "source": [
125 | "X_train = torch.from_numpy(train_images).float()\n",
126 | "y_train = torch.from_numpy(y_train).long()\n",
127 | "X_val = torch.from_numpy(val_images).float()\n",
128 | "y_val = torch.from_numpy(y_val).long()\n",
129 | "\n",
130 | "train_dataset = TensorDataset(X_train, y_train)\n",
131 | "val_dataset = TensorDataset(X_val, y_val)\n",
132 | "\n",
133 | "dataloaders = {'train': DataLoader(train_dataset, batch_size=16, shuffle=True),\n",
134 | " 'val': DataLoader(val_dataset)}\n",
135 | "\n",
136 | "dataset_sizes = {'train': len(X_train),\n",
137 | " 'val': len(X_val)}"
138 | ]
139 | },
140 | {
141 | "cell_type": "markdown",
142 | "metadata": {},
143 | "source": [
144 | "## Modeling\n",
145 | "- Transfer Learning from Resnet\n",
146 | "- I changed just fully connect layer at the end to 3 outputs"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 4,
152 | "metadata": {},
153 | "outputs": [],
154 | "source": [
155 | "model = model_res.to(device)\n",
156 | "\n",
157 | "criterion = nn.CrossEntropyLoss()\n",
158 | "optimizer = optim.Adam(model.parameters())\n"
159 | ]
160 | },
161 | {
162 | "cell_type": "markdown",
163 | "metadata": {},
164 | "source": [
165 | "> Actually IT WORKS!!"
166 | ]
167 | },
168 | {
169 | "cell_type": "code",
170 | "execution_count": 5,
171 | "metadata": {},
172 | "outputs": [
173 | {
174 | "name": "stdout",
175 | "output_type": "stream",
176 | "text": [
177 | "EPOCH 1 / 20: \n",
178 | "----------\n",
179 | "val Loss: 5.3997 Acc: 0.3333\n",
180 | "EPOCH 2 / 20: \n",
181 | "----------\n",
182 | "val Loss: 0.6481 Acc: 0.8333\n",
183 | "EPOCH 3 / 20: \n",
184 | "----------\n",
185 | "val Loss: 0.9328 Acc: 0.7667\n",
186 | "EPOCH 4 / 20: \n",
187 | "----------\n",
188 | "val Loss: 0.3546 Acc: 0.9333\n",
189 | "EPOCH 5 / 20: \n",
190 | "----------\n",
191 | "val Loss: 0.4566 Acc: 0.9333\n",
192 | "EPOCH 6 / 20: \n",
193 | "----------\n",
194 | "val Loss: 0.2912 Acc: 0.8667\n",
195 | "EPOCH 7 / 20: \n",
196 | "----------\n",
197 | "val Loss: 0.2331 Acc: 0.9333\n",
198 | "EPOCH 8 / 20: \n",
199 | "----------\n",
200 | "val Loss: 0.4565 Acc: 0.9333\n",
201 | "EPOCH 9 / 20: \n",
202 | "----------\n",
203 | "val Loss: 0.3249 Acc: 0.9667\n",
204 | "EPOCH 10 / 20: \n",
205 | "----------\n",
206 | "val Loss: 0.4116 Acc: 0.9000\n",
207 | "EPOCH 11 / 20: \n",
208 | "----------\n",
209 | "val Loss: 0.3704 Acc: 0.9333\n",
210 | "EPOCH 12 / 20: \n",
211 | "----------\n",
212 | "val Loss: 0.3225 Acc: 0.9333\n",
213 | "EPOCH 13 / 20: \n",
214 | "----------\n",
215 | "val Loss: 0.6221 Acc: 0.9333\n",
216 | "EPOCH 14 / 20: \n",
217 | "----------\n",
218 | "val Loss: 0.8669 Acc: 0.8667\n",
219 | "EPOCH 15 / 20: \n",
220 | "----------\n",
221 | "val Loss: 0.3086 Acc: 0.9333\n",
222 | "EPOCH 16 / 20: \n",
223 | "----------\n",
224 | "val Loss: 0.3501 Acc: 0.9333\n",
225 | "EPOCH 17 / 20: \n",
226 | "----------\n",
227 | "val Loss: 0.1983 Acc: 0.9333\n",
228 | "EPOCH 18 / 20: \n",
229 | "----------\n",
230 | "val Loss: 0.1258 Acc: 0.9667\n",
231 | "EPOCH 19 / 20: \n",
232 | "----------\n",
233 | "val Loss: 4.1496 Acc: 0.4000\n",
234 | "EPOCH 20 / 20: \n",
235 | "----------\n",
236 | "val Loss: 2.8034 Acc: 0.5667\n",
237 | "Training COMPLETED: 0m 27s\n",
238 | "BEST VALIDATION ACCURACY: 0.966667\n"
239 | ]
240 | }
241 | ],
242 | "source": [
243 | "best_model = train_model(model, dataloaders, dataset_sizes, criterion, optimizer, device, epochs=20)"
244 | ]
245 | },
246 | {
247 | "attachments": {},
248 | "cell_type": "markdown",
249 | "metadata": {},
250 | "source": [
251 | "## Further Experiments\n",
252 | "One of my study group members was curious if the performance could be affected by the columns' positions. Let's check! I will change its position like below left to right and the other conditions are all same.\n",
253 | "\n",
254 | "\n",
255 | "\n",
256 | "result: Their Location doesn't matter with model performance"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "execution_count": 6,
262 | "metadata": {},
263 | "outputs": [
264 | {
265 | "name": "stdout",
266 | "output_type": "stream",
267 | "text": [
268 | "(120, 3, 255, 255)\n",
269 | "(30, 3, 255, 255)\n"
270 | ]
271 | },
272 | {
273 | "data": {
274 | "text/plain": [
275 | ""
276 | ]
277 | },
278 | "execution_count": 6,
279 | "metadata": {},
280 | "output_type": "execute_result"
281 | },
282 | {
283 | "data": {
284 | "image/png": "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\n",
285 | "text/plain": [
286 | ""
287 | ]
288 | },
289 | "metadata": {
290 | "image/png": {
291 | "height": 251,
292 | "width": 263
293 | },
294 | "needs_background": "light"
295 | },
296 | "output_type": "display_data"
297 | }
298 | ],
299 | "source": [
300 | "from data_preparation import data_to_image_another\n",
301 | "\n",
302 | "iris_data = load_iris()\n",
303 | "\n",
304 | "X_train, X_val, y_train, y_val = train_test_split(iris_data.data, iris_data.target, stratify=iris_data.target, test_size=0.2, random_state=0)\n",
305 | "\n",
306 | "train_images = data_to_image_another(X_train)\n",
307 | "val_images = data_to_image_another(X_val)\n",
308 | "\n",
309 | "print(train_images.shape)\n",
310 | "print(val_images.shape)\n",
311 | "plt.grid()\n",
312 | "plt.imshow(train_images[0][0, :, :])"
313 | ]
314 | },
315 | {
316 | "cell_type": "code",
317 | "execution_count": 7,
318 | "metadata": {},
319 | "outputs": [
320 | {
321 | "name": "stdout",
322 | "output_type": "stream",
323 | "text": [
324 | "EPOCH 1 / 20: \n",
325 | "----------\n",
326 | "val Loss: 4.3803 Acc: 0.6667\n",
327 | "EPOCH 2 / 20: \n",
328 | "----------\n",
329 | "val Loss: 49.4471 Acc: 0.3333\n",
330 | "EPOCH 3 / 20: \n",
331 | "----------\n",
332 | "val Loss: 1.4664 Acc: 0.7000\n",
333 | "EPOCH 4 / 20: \n",
334 | "----------\n",
335 | "val Loss: 0.7917 Acc: 0.8667\n",
336 | "EPOCH 5 / 20: \n",
337 | "----------\n",
338 | "val Loss: 1.6323 Acc: 0.8333\n",
339 | "EPOCH 6 / 20: \n",
340 | "----------\n",
341 | "val Loss: 1.8395 Acc: 0.6667\n",
342 | "EPOCH 7 / 20: \n",
343 | "----------\n",
344 | "val Loss: 0.4488 Acc: 0.9333\n",
345 | "EPOCH 8 / 20: \n",
346 | "----------\n",
347 | "val Loss: 0.2794 Acc: 0.9333\n",
348 | "EPOCH 9 / 20: \n",
349 | "----------\n",
350 | "val Loss: 0.1849 Acc: 0.9667\n",
351 | "EPOCH 10 / 20: \n",
352 | "----------\n",
353 | "val Loss: 0.1331 Acc: 0.9667\n",
354 | "EPOCH 11 / 20: \n",
355 | "----------\n",
356 | "val Loss: 0.1345 Acc: 0.9667\n",
357 | "EPOCH 12 / 20: \n",
358 | "----------\n",
359 | "val Loss: 0.3936 Acc: 0.9333\n",
360 | "EPOCH 13 / 20: \n",
361 | "----------\n",
362 | "val Loss: 0.1830 Acc: 0.9333\n",
363 | "EPOCH 14 / 20: \n",
364 | "----------\n",
365 | "val Loss: 0.1597 Acc: 0.9667\n",
366 | "EPOCH 15 / 20: \n",
367 | "----------\n",
368 | "val Loss: 0.1071 Acc: 0.9667\n",
369 | "EPOCH 16 / 20: \n",
370 | "----------\n",
371 | "val Loss: 0.3240 Acc: 0.8667\n",
372 | "EPOCH 17 / 20: \n",
373 | "----------\n",
374 | "val Loss: 0.2489 Acc: 0.9333\n",
375 | "EPOCH 18 / 20: \n",
376 | "----------\n",
377 | "val Loss: 0.2280 Acc: 0.9333\n",
378 | "EPOCH 19 / 20: \n",
379 | "----------\n",
380 | "val Loss: 0.2546 Acc: 0.9667\n",
381 | "EPOCH 20 / 20: \n",
382 | "----------\n",
383 | "val Loss: 0.2007 Acc: 0.9667\n",
384 | "Training COMPLETED: 0m 27s\n",
385 | "BEST VALIDATION ACCURACY: 0.966667\n"
386 | ]
387 | }
388 | ],
389 | "source": [
390 | "X_train = torch.from_numpy(train_images).float()\n",
391 | "y_train = torch.from_numpy(y_train).long()\n",
392 | "X_val = torch.from_numpy(val_images).float()\n",
393 | "y_val = torch.from_numpy(y_val).long()\n",
394 | "\n",
395 | "train_dataset = TensorDataset(X_train, y_train)\n",
396 | "val_dataset = TensorDataset(X_val, y_val)\n",
397 | "\n",
398 | "dataloaders = {'train': DataLoader(train_dataset, batch_size=16, shuffle=True),\n",
399 | " 'val': DataLoader(val_dataset)}\n",
400 | "\n",
401 | "dataset_sizes = {'train': len(X_train),\n",
402 | " 'val': len(X_val)}\n",
403 | "\n",
404 | "model_another = model_res.to(device)\n",
405 | "\n",
406 | "criterion = nn.CrossEntropyLoss()\n",
407 | "optimizer = optim.Adam(model_another.parameters())\n",
408 | "\n",
409 | "best_model = train_model(model_another, dataloaders, dataset_sizes, criterion, optimizer, device, epochs=20)"
410 | ]
411 | },
412 | {
413 | "cell_type": "markdown",
414 | "metadata": {},
415 | "source": [
416 | "---\n",
417 | "I just coded for fun and curiosity, but this simple implementation gives very new insights of relation between tabular data and embeddings."
418 | ]
419 | }
420 | ],
421 | "metadata": {
422 | "kernelspec": {
423 | "display_name": "Python 3",
424 | "language": "python",
425 | "name": "python3"
426 | },
427 | "language_info": {
428 | "codemirror_mode": {
429 | "name": "ipython",
430 | "version": 3
431 | },
432 | "file_extension": ".py",
433 | "mimetype": "text/x-python",
434 | "name": "python",
435 | "nbconvert_exporter": "python",
436 | "pygments_lexer": "ipython3",
437 | "version": "3.6.0"
438 | }
439 | },
440 | "nbformat": 4,
441 | "nbformat_minor": 4
442 | }
443 |
--------------------------------------------------------------------------------