In [1]:
# Import libraries for simulation
import tensorflow as tf
import numpy as np
import random as r
import datetime as dt
In [2]:
dimensions = (16,16)
mineProbability = 0.2 # Probability that a square contain a mine
missingProbability = 0.5 # Probability that a square is missing adjacency info
In [3]:
# This is a matrix that maps mine board vectors to mine count vectors
def minesweepMatrix(dimensions):
rows,cols = dimensions
size = rows * cols
A = np.zeros([size,size],dtype=int)
for rA in range(size):
for cA in range(size):
inRow, inCol = divmod(rA,cols)
outRow, outCol = divmod(cA,cols)
A[rA,cA] = abs(inRow-outRow) <= 1 and abs(inCol-outCol) <= 1
return(A)
In [4]:
# Converts a board of mines into a board of mine counts
def boardMineCounts(board):
return(minesweepMatrix(board.shape).dot(board.flatten()).reshape(board.shape))
In [5]:
# This takes a mine board and gives a mine count with mines removed, and other random squares removed
def boardPartialMineCounts(board):
result = boardMineCounts(board)
for index, x in np.ndenumerate(board):
if x: result[index] = -1
elif r.uniform(0, 1) < missingProbability: result[index] = -1
return result
In [6]:
# Generates a random training batch of size at most n
def next_training_batch(n):
batch_xs = []
batch_ys = []
for _ in range(n):
board = np.random.random(dimensions) < mineProbability
counts = boardPartialMineCounts(board)
frees = (1 - board).flatten().astype(float)
freesSum = sum(frees)
if freesSum > 0:
batch_xs.append(counts.flatten())
batch_ys.append(frees / freesSum)
return (np.asarray(batch_xs), np.asarray(batch_ys))
In [7]:
# Create the model
rows, cols = dimensions
size = rows*cols
mineCounts = tf.placeholder(tf.int32, [None, size], name="mineCounts")
mineCountsOneHot = tf.reshape(tf.one_hot(mineCounts+1,10), [-1, size*10])
W = tf.Variable(tf.random_normal([size*10, size], stddev=0.01), name="W")
b = tf.Variable(tf.random_normal([size], stddev=0.01), name="b")
y = tf.matmul(mineCountsOneHot, W) + b
In [8]:
mineFreeAverages = tf.placeholder(tf.float32, [None, size], name="mineFreeAverages")
In [9]:
# Loss function
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=mineFreeAverages, logits=y))
In [10]:
# Summaries for tensorboard
with tf.name_scope('W_reshape'):
image_shaped_W = tf.reshape(W, [-1, size*10, size, 1])
tf.summary.image('W', image_shaped_W, 1000)
with tf.name_scope('b_reshape'):
image_shaped_b = tf.reshape(b, [-1, rows, cols, 1])
tf.summary.image('b', image_shaped_b, 1000)
_ = tf.summary.scalar('accuracy', cross_entropy)
In [11]:
# Optimiser
train_step = tf.train.AdamOptimizer().minimize(cross_entropy)
In [12]:
# Create session and initialise or restore stuff
savePath = './saves.tf.Mines3/' + str(dimensions) + '/'
saver = tf.train.Saver()
sess = tf.InteractiveSession()
merged = tf.summary.merge_all()
writer = tf.summary.FileWriter('.', sess.graph)
In [13]:
tf.global_variables_initializer().run()
In [14]:
# Restore model?
#saver.restore(sess, savePath + "model-10000")
In [15]:
# Train
for iteration in range(10001):
batch_xs, batch_ys = next_training_batch(100)
if iteration % 10 == 0:
summary, loss, _ = sess.run([merged, cross_entropy, train_step],
feed_dict={mineCounts: batch_xs, mineFreeAverages: batch_ys})
writer.add_summary(summary, iteration)
print('%s: Loss at step %s: %s' % (dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), iteration, loss))
else:
_ = sess.run(train_step, feed_dict={mineCounts: batch_xs, mineFreeAverages: batch_ys})
if iteration % 1000 == 0:
save_path = saver.save(sess, savePath + 'model', global_step=iteration)
print("Model saved in file: %s" % save_path)
In [16]:
# Test trained model on larger batch size
batch_xs, batch_ys = next_training_batch(1000)
print(sess.run(cross_entropy, feed_dict={mineCounts: batch_xs, mineFreeAverages: batch_ys}))
In [18]:
# Run a test
batchSize = 10000
batch_xs, batch_ys = next_training_batch(batchSize)
predictions = sess.run(tf.nn.softmax(y), feed_dict={mineCounts: batch_xs, mineFreeAverages: batch_ys})
bestSquares = [pred.argmax() for pred in predictions]
board = (batch_ys == 0).astype(int)
frees = [board[i][bestSquares[i]] for i in range(batchSize)]
print("Number of errors for batch size of ", batchSize)
print(sum(frees))
In [ ]: