File size: 7,808 Bytes
d6c2e08 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
import pickle
import tensorflow as tf
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import numpy as np
from datetime import datetime
import time
def create_data_on_disk(graph_size, num_samples, is_save=True, filename=None, is_return=False, seed=1234):
"""Generate validation dataset (with SEED) and save
"""
CAPACITIES = {
10: 20.,
20: 30.,
50: 40.,
100: 50.
}
depo, graphs, demand = (tf.random.uniform(minval=0, maxval=1, shape=(num_samples, 2), seed=seed),
tf.random.uniform(minval=0, maxval=1, shape=(num_samples, graph_size, 2), seed=seed),
tf.cast(tf.random.uniform(minval=1, maxval=10, shape=(num_samples, graph_size),
dtype=tf.int32, seed=seed), tf.float32) / tf.cast(CAPACITIES[graph_size], tf.float32)
)
if is_save:
save_to_pickle('Validation_dataset_{}.pkl'.format(filename), (depo, graphs, demand))
if is_return:
return tf.data.Dataset.from_tensor_slices((list(depo), list(graphs), list(demand)))
def save_to_pickle(filename, item):
"""Save to pickle
"""
with open(filename, 'wb') as handle:
pickle.dump(item, handle, protocol=pickle.HIGHEST_PROTOCOL)
def read_from_pickle(path, return_tf_data_set=True, num_samples=None):
"""Read dataset from file (pickle)
"""
objects = []
with (open(path, "rb")) as openfile:
while True:
try:
objects.append(pickle.load(openfile))
except EOFError:
break
objects = objects[0]
if return_tf_data_set:
depo, graphs, demand = objects
if num_samples is not None:
return tf.data.Dataset.from_tensor_slices((list(depo), list(graphs), list(demand))).take(num_samples)
else:
return tf.data.Dataset.from_tensor_slices((list(depo), list(graphs), list(demand)))
else:
return objects
def generate_data_onfly(num_samples=10000, graph_size=20):
"""Generate temp dataset in memory
"""
CAPACITIES = {
10: 20.,
20: 30.,
50: 40.,
100: 50.
}
depo, graphs, demand = (tf.random.uniform(minval=0, maxval=1, shape=(num_samples, 2)),
tf.random.uniform(minval=0, maxval=1, shape=(num_samples, graph_size, 2)),
tf.cast(tf.random.uniform(minval=1, maxval=10, shape=(num_samples, graph_size),
dtype=tf.int32), tf.float32)/tf.cast(CAPACITIES[graph_size], tf.float32)
)
return tf.data.Dataset.from_tensor_slices((list(depo), list(graphs), list(demand)))
def get_results(train_loss_results, train_cost_results, val_cost, save_results=True, filename=None, plots=True):
epochs_num = len(train_loss_results)
df_train = pd.DataFrame(data={'epochs': list(range(epochs_num)),
'loss': train_loss_results,
'cost': train_cost_results,
})
df_test = pd.DataFrame(data={'epochs': list(range(epochs_num)),
'val_сost': val_cost})
if save_results:
df_train.to_excel('train_results_{}.xlsx'.format(filename), index=False)
df_test.to_excel('test_results_{}.xlsx'.format(filename), index=False)
if plots:
plt.figure(figsize=(15, 9))
ax = sns.lineplot(x='epochs', y='loss', data=df_train, color='salmon', label='train loss')
ax2 = ax.twinx()
sns.lineplot(x='epochs', y='cost', data=df_train, color='cornflowerblue', label='train cost', ax=ax2)
sns.lineplot(x='epochs', y='val_сost', data=df_test, palette='darkblue', label='val cost').set(ylabel='cost')
ax.legend(loc=(0.75, 0.90), ncol=1)
ax2.legend(loc=(0.75, 0.95), ncol=2)
ax.grid(axis='x')
ax2.grid(True)
plt.savefig('learning_curve_plot_{}.jpg'.format(filename))
plt.show()
def get_journey(batch, pi, title, ind_in_batch=0):
"""Plots journey of agent
Args:
batch: dataset of graphs
pi: paths of agent obtained from model
ind_in_batch: index of graph in batch to be plotted
"""
# Remove extra zeros
pi_ = get_clean_path(pi[ind_in_batch].numpy())
# Unpack variables
depo_coord = batch[0][ind_in_batch].numpy()
points_coords = batch[1][ind_in_batch].numpy()
demands = batch[2][ind_in_batch].numpy()
node_labels = ['(' + str(x[0]) + ', ' + x[1] + ')' for x in enumerate(demands.round(2).astype(str))]
# Concatenate depot and points
full_coords = np.concatenate((depo_coord.reshape(1, 2), points_coords))
# Get list with agent loops in path
list_of_paths = []
cur_path = []
for idx, node in enumerate(pi_):
cur_path.append(node)
if idx != 0 and node == 0:
if cur_path[0] != 0:
cur_path.insert(0, 0)
list_of_paths.append(cur_path)
cur_path = []
list_of_path_traces = []
for path_counter, path in enumerate(list_of_paths):
coords = full_coords[[int(x) for x in path]]
# Calculate length of each agent loop
lengths = np.sqrt(np.sum(np.diff(coords, axis=0) ** 2, axis=1))
total_length = np.sum(lengths)
list_of_path_traces.append(go.Scatter(x=coords[:, 0],
y=coords[:, 1],
mode="markers+lines",
name=f"path_{path_counter}, length={total_length:.2f}",
opacity=1.0))
trace_points = go.Scatter(x=points_coords[:, 0],
y=points_coords[:, 1],
mode='markers+text',
name='destinations',
text=node_labels,
textposition='top center',
marker=dict(size=7),
opacity=1.0
)
trace_depo = go.Scatter(x=[depo_coord[0]],
y=[depo_coord[1]],
text=['1.0'], textposition='bottom center',
mode='markers+text',
marker=dict(size=15),
name='depot'
)
layout = go.Layout(title='<b>Example: {}</b>'.format(title),
xaxis=dict(title='X coordinate'),
yaxis=dict(title='Y coordinate'),
showlegend=True,
width=1000,
height=1000,
template="plotly_white"
)
data = [trace_points, trace_depo] + list_of_path_traces
print('Current path: ', pi_)
fig = go.Figure(data=data, layout=layout)
fig.show()
def get_cur_time():
"""Returns local time as string
"""
ts = time.time()
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
def get_clean_path(arr):
"""Returns extra zeros from path.
Dynamical model generates duplicated zeros for several graphs when obtaining partial solutions.
"""
p1, p2 = 0, 1
output = []
while p2 < len(arr):
if arr[p1] != arr[p2]:
output.append(arr[p1])
if p2 == len(arr) - 1:
output.append(arr[p2])
p1 += 1
p2 += 1
if output[0] != 0:
output.insert(0, 0.0)
if output[-1] != 0:
output.append(0.0)
return output
|