-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCuDNNLSTM.py
More file actions
320 lines (248 loc) · 10.9 KB
/
Copy pathCuDNNLSTM.py
File metadata and controls
320 lines (248 loc) · 10.9 KB
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# -*- coding: utf-8 -*-
"""
Created on Tue Oct 1 19:42:51 2019
@author: Eric Born
"""
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import Dense, Dropout, LSTM, CuDNNLSTM,\
BatchNormalization, Flatten,\
Embedding, Bidirectional, Attention,\
TimeDistributed
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint,\
TensorBoard, ReduceLROnPlateau
from tensorflow.python.keras.optimizers import RMSprop
from keras.backend.tensorflow_backend import set_session
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn import preprocessing
import pandas as pd
import numpy as np
import os
import time
# removes scientific notation from np prints, prints numbers as floats
np.set_printoptions(suppress=True)
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.90)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
# path to data
path = 'G:/botdata/win/'
# list of all files
files = os.listdir(path)
# object for single array file, which equals a single game
#full_array = np.load(path + files[0], allow_pickle=True)
# column list for all match data
cols = ['minerals','gas','supply_cap', 'supply_army', 'supply_workers',
'nexus', 'c_pylons', 'assimilators', 'gateways', 'cybercore', 'robofac',
'stargate', 'robobay', 'k-structures', 'k-units', 'attack',
'assimilators', 'offensive_force', 'b_pylons', 'workers', 'distribute',
'nothing', 'expand', 'buildings', 'ZEALOT', 'STALKER', 'ADEPT',
'IMMORTAL', 'VOIDRAY', 'COLOSSUS', 'difficulty', 'outcome']
#
# Single array df
#full_df = pd.DataFrame(data=full_array,columns=cols)
# define empty dataframe using columns previously defined
full_df = pd.DataFrame(columns=cols)
# loads each training data file, creates a df and appends to the original df
for file in range(0, len(files)):
#print(np.load(path + files[file], allow_pickle=True))
if len(full_df) == 0:
full_df = pd.DataFrame(data=np.load(path + files[file],
allow_pickle=True),columns=cols)
else:
df2 = pd.DataFrame(data=np.load(path + files[file],
allow_pickle=True),columns=cols)
full_df = full_df.append(df2)
# setup x and y
# x will be the supply_data inputs
# y will be the action that was taken
# create values, the supply stats
x_data = full_df.iloc[:,0:15].values
# create targets, the bot choices
y_data = full_df.iloc[:,15:24].values
# used for a single array load
#supply_array = full_array[:,0:15]
#x_data = full_array[:,0:15]
# setup an array that only includes the action data index 15-23
# 9 outputs
#actions_array = full_array[:,15:24]
#y_data = full_array[:,15:24]
#np.save(r"C:/botdata/{}.npy".format(str(int(time.time()))),
# np.array(self.training_data))
# look at the shape of the array
print(x_data.shape)
print(y_data.shape)
# setup number to split for train/test
num_train = int(0.9 * len(x_data))
# split x train/test
x_train = x_data[0:num_train]
x_test = x_data[num_train:]
len(x_train) + len(x_test)
# split y train/test
y_train = y_data[0:num_train]
y_test = y_data[num_train:]
len(y_train) + len(y_test)
# input columns
num_x_signals = x_data.shape[1]
print(num_x_signals)
# output columns
num_y_signals = y_data.shape[1]
print(num_y_signals)
# Setup scalers for x and y
x_scaler = MinMaxScaler()
x_train_scaled = x_scaler.fit_transform(x_train)
x_test_scaled = x_scaler.fit_transform(x_test)
y_scaler = MinMaxScaler()
y_train_scaled = y_scaler.fit_transform(y_train)
y_test_scaled = y_scaler.fit_transform(y_test)
# check shapes for the scaled sets
print(x_train_scaled.shape)
print(y_train_scaled.shape)
# create a batch generator to feed the data into the NN
def batch_generator(batch_size, sequence_length):
"""
Generator function for creating random batches of training-data.
"""
# Infinite loop.
while True:
# Allocate a new array for the batch of input-signals.
x_shape = (batch_size, sequence_length, num_x_signals)
x_batch = np.zeros(shape=x_shape, dtype=np.float16)
# Allocate a new array for the batch of output-signals.
y_shape = (batch_size, sequence_length, num_y_signals)
y_batch = np.zeros(shape=y_shape, dtype=np.float16)
# Fill the batch with random sequences of data.
for i in range(batch_size):
# Get a random start-index.
# This points somewhere into the training-data.
idx = np.random.randint(num_train - sequence_length)
# Copy the sequences of data starting at this index.
x_batch[i] = x_train_scaled[idx:idx+sequence_length]
y_batch[i] = y_train_scaled[idx:idx+sequence_length]
yield (x_batch, y_batch)
# larger batch size the more is fed to the GPU at once, adjust if there
# are memory issues
batch_size = 200
# length of steps
sequence_length = 300
# create a generator object
generator = batch_generator(batch_size=batch_size,
sequence_length=sequence_length)
# generates a batch for x and y
x_batch, y_batch = next(generator)
#print(x_batch.shape)
#print(y_batch.shape)
# set aside some data for validation purposes
validation_data = (np.expand_dims(x_test_scaled[0:500], axis=0),
np.expand_dims(y_test_scaled[0:500], axis=0))
# start building the NN model
# Sequential allows the model to be build one layer at a time
# with each subsequent layer being added to the first
model = Sequential()
# trying out various different model constructions
#model.add(CuDNNLSTM(units=64, return_sequences=True,
# input_shape=(None, num_x_signals,)))
#model.add(Bidirectional(LSTM(64, dropout=0.4, recurrent_dropout=0.4,
# activation='relu', return_sequences=True)))
#model.add(Bidirectional(CuDNNLSTM(32, return_sequences = True)))
#model.add(Bidirectional(LSTM(64, dropout=0.4, recurrent_dropout=0.4,
# activation='relu', return_sequences=True)))
#model.add(Bidirectional(CuDNNLSTM(64, return_sequences=True)))
# The GRU outputs a batch of sequences of 512 values.
# We want to predict 9 output-signals, so we add a fully-connected (or dense)
# layer maps 512 values down to only 9 values.
#model.add(TimeDistributed(Dense(num_y_signals, activation='sigmoid')))
# 60.5%
model.add(CuDNNLSTM(units=60, return_sequences=True,
input_shape=(None, num_x_signals,)))
model.add(Bidirectional(CuDNNLSTM(units=15, return_sequences=True)))
model.add(TimeDistributed(Dense(num_y_signals, activation='sigmoid')))
# 57%
#model.add(Bidirectional(CuDNNLSTM(units=20, return_sequences=True),
# input_shape=(None, num_x_signals,)))
#model.add(TimeDistributed(Dense(num_y_signals, activation='sigmoid')))
if False:
from tensorflow.python.keras.initializers import RandomUniform
# Maybe use lower init-ranges.
init = RandomUniform(minval=-0.05, maxval=0.05)
model.add(Dense(num_y_signals,
activation='linear',
kernel_initializer=init))
warmup_steps = 50
def loss_mse_warmup(y_true, y_pred):
"""
Calculate the Mean Squared Error between y_true and y_pred,
but ignore the beginning "warmup" part of the sequences.
y_true is the desired output.
y_pred is the model's output.
"""
# The shape of both input tensors are:
# [batch_size, sequence_length, num_y_signals].
# Ignore the "warmup" parts of the sequences
# by taking slices of the tensors.
y_true_slice = y_true[:, warmup_steps:, :]
y_pred_slice = y_pred[:, warmup_steps:, :]
# These sliced tensors both have this shape:
# [batch_size, sequence_length - warmup_steps, num_y_signals]
# Calculate the MSE loss for each value in these tensors.
# This outputs a 3-rank tensor of the same shape.
loss = tf.losses.mean_squared_error(labels=y_true_slice,
predictions=y_pred_slice)
# Keras may reduce this across the first axis (the batch)
# but the semantics are unclear, so to be sure we use
# the loss across the entire tensor, we reduce it to a
# single scalar with the mean function.
loss_mean = tf.reduce_mean(loss)
return loss_mean
optimizer = RMSprop(lr=1e-3)
# original loss and optimizer
#model.compile(loss=loss_mse_warmup, optimizer=optimizer)
# suggested for LSTM
model.compile(loss='categorical_crossentropy', optimizer='adam',
metrics=['categorical_accuracy'])
print(model.summary())
# build writing checkpoints
path_checkpoint = 'CuDNNLSTM_expanded_checkpoint.keras'
callback_checkpoint = ModelCheckpoint(filepath=path_checkpoint,
monitor='val_loss',
verbose=1,
save_weights_only=True,
save_best_only=True)
# set early stop if the performance worsens on validation
callback_early_stopping = EarlyStopping(monitor='val_loss',
patience=5, verbose=1)
# setup tensorboard
callback_tensorboard = TensorBoard(
log_dir=r'C:/Users/TomBrody/Desktop/School/767 ML/SC Bot/NN/logs/CuDNNLSTM',
histogram_freq=0,
write_graph=False)
# setup automatic reduction of learning rate
# TODO
#try with patience at 5
callback_reduce_lr = ReduceLROnPlateau(monitor='val_loss',
factor=0.1,
min_lr=1e-8,
patience=5,
verbose=1)
# setup list to hold all callback info
callbacks = [callback_early_stopping,
callback_checkpoint,
callback_tensorboard,
callback_reduce_lr]
# Run the model for 20 epochs, 100 steps per
model.fit_generator(generator=generator,
epochs=100,
steps_per_epoch=100,
validation_data=validation_data,
callbacks=callbacks)
# load best model
try:
model.load_weights(path_checkpoint)
except Exception as error:
print("Error trying to load checkpoint.")
print(error)
# path to save the model
path = r'C:/Users/TomBrody/Desktop/School/767 ML/SC Bot/NN/model//'
# path plus model and time
model.save(path+'CuDNNLSTM-{}'.format(str(int(time.time())))+'.h5')