Programmatically generating training datasets

Link to Github source code

Previously I built the training data by manually taking several screenshots of the starter board on lichess using different themes, and upscaling/downscaling the screen view in chrome. Then using tensorflow_chessbot.py to split up these images into tiles with the known starter configuration for labels. This is not covering the space very well. With that data we built a basic model that is around 98% accurate for a few lichess boards in the starter configuration.

Though the tiles shouldn't care where on the board they are, it may introduce image artifacts that could confuse the final neural network. To solve this, we need to generate training data in several configurations.

Ideally we'd like to generate our own FEN, and get an actual website board screenshot from it. Since a FEN provides the piece locations, we have our labels and our real data. We can use our same computer vision algorithm to split up the screenshots into tiles which will be fed into our neural network as training data.

In [110]:
# Imports
import numpy as np
import PIL
import os
from IPython.display import Image, display
import helper_webkit2png # Contains screenshot helpers and our wrapper ChessScreenshotServer
helper_webkit2png = reload(helper_webkit2png)
import tensorflow_chessbot # For generating tilesets from chessboard screenshots

# reload(helper_webkit2png.webkit2png)
# reload(tensorflow_chessbot)

# Load chess screenshot server (wrapper for qt gui)
chessServer = helper_webkit2png.ChessScreenshotServer()
QApplication has already been instantiated.
Ignoring given arguments and returning existing QApplication.

Generating random FENs

FEN stands for Forsyth-Edwards Notation, which is a dead simple way of encoding a single board layout. It's a string containing 8 sections divided by a / corresponding to descending files, and each section contains a character signifying the piece on that rank's square. A number signifies the number of empty spaces between pieces, so say 5p1Q means 5 spaces, a black pawn, 1 space, and a white queen along that file.

Since there are 12 pieces and a space, and there are 64 squares, to enumerate all possible FEN strings (a subset of which is legal chessboard layouts, but not a requirement here) we'd need $12^{64}=1168422057627266461843148138873451659428421700563161428957815831003136$ strings, roughly 1e69 configurations, so that's not an option.

Another way to look at it is to ignore the overall board layout, each tile only needs to have the piece on it once.

There are some smart things we could do to try and get an optimal distribution of pieces near the edge, near other pieces, etc., but we can also just take a reasonable large random sampling of the configuration space and gain a majority of the useful information needed. Since we're training based on tiles and not overall board layout (for another day), the chessboard doesn't need to have a valid layout.

In [108]:
def getRandomFEN():
    fen_chars = list('1KQRBNPkqrbnp')
    pieces = np.random.choice(fen_chars, 64)
    fen = '/'.join([''.join(pieces[i*8:(i+1)*8]) for i in range(8)])
    # can append ' w' or ' b' for white/black to play, defaults to white
    return fen

fen = getRandomFEN()
print fen + ' w KQkq - 0 1'
print fen.replace('/','-')
prk1Bpnq/nQPpRbQP/qPnp1Q11/qBn1KPNN/rB1RqrPq/R1RrRPBq/NRQQQBbK/bqqPkbk1 w KQkq - 0 1
tiles_chess__prk1Bpnq-nQPpRbQP-qPnp1Q11-qBn1KPNN-rB1RqrPq-R1RrRPBq-NRQQQBbK-bqqPkbk1

Generating screenshots of the FEN

This seemingly daunting task is actually not too bad thanks to the help of several others. One way is to programmatically load a url and get a render is to use pythonwebkit2png.

In our case we will use several websites eventually, but this notebook shows just lichess. Lichess provides a RESTful protocol www.lichess.org/editor/<FEN-STRING> which loads a page with the board in the FEN configuration.

In [47]:
# Set up URL and output image filename for this run
url = "http://en.lichess.org/editor/%s" % getRandomFEN()
output_filename = "testA.png"

status = chessServer.takeScreenshot(url,output_filename)
if status == 0:
    print "Success"
else:
    print "Failed on %s -> %s" % (url, output_filename)
	Saved screenshot to 'testA.png'
Success

Great! Let's see what it looks like

In [49]:
print "FEN:",url
display(Image("testA.png"))
 FEN: http://en.lichess.org/editor/KRQ1nbrP/BNKbbpbR/PBNpQnRB/n11QbPBb/pKknrpPn/K1BBbqkq/NRrBKNqn/pk1RKN1R

Awesome! Since every render will have the same layout we can crop the picture after the fact to hold just the board.

In [50]:
# Crop boundaries
# 218,141
# 737,658
im = PIL.Image.open("testA.png")
im = im.crop([218,141,737,658])
im.save("testA_crop.png")
display(Image("testA_crop.png"))

Looks good, now that we can get tight fit images, let's generate a set of images with the FEN encoded in the filename, this will make it easy to generate training data and labels in one go with the computer vision script. This will create a ton of duplicate tiles, since technically there should only be 26 different tiles with all else being equal. However, this sets the stage for loading different themes for board and pieces. It also allows for training for some image boundary bleed-over when tiles are on the edges of the board. Finally, we'll be able to use this for some other sites like chess.com and PGN viewers, etc.

In [51]:
# Number of random screenshots to generate
N = 1

out_folder = 'train_gen_lichess'
if not os.path.exists(out_folder):
    os.makeoutput_tile_folders(out_folder)

output_filenameA = "testA.png"
output_filenameB = "testB.png"
output_filenames = [output_filenameA, output_filenameB]
for i in range(N):
    # Generate random FEN
    fen = getRandomFEN()
    
    print "#%d : %s" % (i,fen)
    output_filename = "%s/lichess%04d__%s.png" % (out_folder, i, fen.replace('/','-'))
    
    # Render webpage and save screenshot
    status = chessServer.takeChessScreenshot(fen,output_filename)
    
    if status == 0:
        print "\t...Success"
    else:
        print "\tFailed on %s -> %s" % (fen, output_filename)
        break
    
    # Load image, crop and overwrite file
    im = PIL.Image.open(output_filename).crop([218,141,737,658]).save(output_filename)
#0 : PKrQqrrN/nqBqnppb/RqpP1bkr/QnB1kqQn/QqRPRK1k/BQnQpRrp/bkqNbrnq/q1qqrbpr
	Saved screenshot to 'train_gen_lichess/lichess0000__PKrQqrrN-nqBqnppb-RqpP1bkr-QnB1kqQn-QqRPRK1k-BQnQpRrp-bkqNbrnq-q1qqrbpr.png'
	...Success

Themes and Graphic Sets

In addition to loading a screenshot of a random board configuration, there are several themes and sets that change the graphics.

Several themes are available:

["blue", "blue2", "blue3", "canvas", "wood", "wood2", "wood3", "maple", "green", "marble", "brown", "leather", "grey", "metal", "olive", "purple", "Black-White-Aluminium", "Brushed-Aluminium", "China-Blue", "China-Green", "China-Grey", "China-Scarlet", "Classic-Blue", "Gold-Silver", "Light-Wood", "Power-Coated", "Rosewood", "Marble", "Wax", "Jade", "Woodi"]

Which I got by running the following javascript (minus leading slash) in a console on the lichess site:

\$('.theme').map(function(x) { return $(this).attr('data-theme');})

And piece graphic sets:

["cburnett", "merida", "alpha", "pirouetti", "chessnut", "chess7", "reillycraig", "companion", "fantasy", "spatial", "shapes", "Basic", "Wood", "Metal", "RedVBlue", "ModernJade", "ModernWood", "Glass", "Trimmed", "Experimental"]

using

\$('.no-square').map(function(x) { return $(this).attr('data-set');})

There's also 3 backgrounds

["light", "dark", "transp"]

which I just identified manually with the chrome inspection tool.

In [52]:
themes = ["blue", "blue2", "blue3", "canvas", "wood", "wood2", "wood3", "maple", "green", "marble", "brown", "leather", "grey", "metal", "olive", "purple", "Black-White-Aluminium", "Brushed-Aluminium", "China-Blue", "China-Green", "China-Grey", "China-Scarlet", "Classic-Blue", "Gold-Silver", "Light-Wood", "Power-Coated", "Rosewood", "Marble", "Wax", "Jade", "Woodi"]
pieceSets = ["cburnett", "merida", "alpha", "pirouetti", "chessnut", "chess7", "reillycraig", "companion", "fantasy", "spatial", "shapes", "Basic", "Wood", "Metal", "RedVBlue", "ModernJade", "ModernWood", "Glass", "Trimmed", "Experimental"]
backgrounds = ["light", "dark", "transp"]
print "%d themes, %d sets, %d backgrounds = %d combinations" % (len(themes), len(pieceSets), len(backgrounds), len(themes)*len(pieceSets)*len(backgrounds))
31 themes, 20 sets, 3 backgrounds = 1860 combinations

So there are 1860 combinations of themes and piece sets. Lets say we want 5 random boards per combination, with random pieces on each tile. This comes out to $1860*5*64=595,200$ tiles. That should be a decent amount for training such a simple neural network.

Note: specifically for lichess screenshots, with some dubious ability to handle random screenshots from other sites

To take a screenshot with the right theme, we need to pass a cookie with the information included. I went on the lichess site in an incognito window and looked at the cookie it stores:

lila2=cf31a05a7b738a4c89d5bddf16dbde0d3c57082d-sid=JSWp1JBD&theme=blue&bg=dark&pieceSet=alpha

The session id and previous value is generated whenever you go to the browser, so you'll probably need to create your own manually since they expire. It looks like there are 3 keys which contain our theme, background and pieceSet, which we will modify and pass in a cookie.

NOTE: Unfortunately need unique session tokens, WIP, manually getting cookie, and then autogenerating several random layouts

In [35]:
# Number of random screenshots to generate
N = 5
out_folder = 'train_images'
if not os.path.exists(out_folder):
    os.makeoutput_tile_folders(out_folder)
#
code = '4eecbbd0982b8d26060c17c3de8f5602ae335290-sid=JSWp1JBD&theme=wood&bg=dark&pieceSet=cburnett'
code = '67193ee101f00274ea7d6bc77143486a3dde571f-sid=JSWp1JBD&theme=wood3&bg=dark&pieceSet=cburnett'
code = 'b7d9a7cae17ff905547e70fb8f6d0a50c12bd374-sid=JSWp1JBD&theme=leather&bg=dark&pieceSet=cburnett'
code = 'f7a1bab2c73cdf316f8bf5dc1d8edc251acc0f2f-sid=JSWp1JBD&theme=canvas&bg=dark&pieceSet=cburnett'
code = 'cf31a05a7b738a4c89d5bddf16dbde0d3c57082d-sid=JSWp1JBD&theme=blue&bg=dark&pieceSet=alpha'
code = '07c1a977da8b8eae5678a79e79e210cbd4580010-sid=JSWp1JBD&theme=wood&bg=dark&pieceSet=alpha'
code = 'f7fb62b208d088c9adc20482f68bff20d622ffc4-sid=JSWp1JBD&theme=leather&bg=dark&pieceSet=alpha'
code = 'ca778a1d8b8680824d6501f68e6db721351fea0a-sid=JSWp1JBD&theme=wood3&bg=dark&pieceSet=alpha'
code = 'a526bbcc9c4e1e00889474b70b53101f4087a0eb-sid=JSWp1JBD&theme=canvas&bg=dark&pieceSet=merida'
code = 'fc8d4d2042dcea51baee213c62eae8405fc9bcee-sid=JSWp1JBD&theme=canvas&bg=dark&pieceSet=pirouetti'
code = 'b257e599862eeb99bcbed10c2aeaa784d25e345d-sid=JSWp1JBD&theme=canvas&bg=dark&pieceSet=chessnut'
code = 'a6b8c83fd2f311060dbad47693d344758f6f5e24-sid=JSWp1JBD&theme=blue3&bg=dark&pieceSet=chess7'
code = 'd5e79b290d1073e0b86978e97c9af6f81d0b0e9e-sid=JSWp1JBD&theme=blue3&bg=dark&pieceSet=reillycraig'
code = '85f4f0f8f80804683c8ddd719e6c9dd9ffb697e9-sid=JSWp1JBD&theme=blue3&bg=dark&pieceSet=merida'
code = '21cc203f3087b359862644ee20cc549420d9549d-sid=JSWp1JBD&theme=blue3&bg=dark&pieceSet=cburnett'
code = '4c333906715a33b5d48908f44603508b8c767a10-sid=JSWp1JBD&theme=blue3&bg=dark&pieceSet=alpha'
for i in range(N):
    # Generate random FEN
    fen = getRandomFEN()
    
    print "#%d : %s" % (i,fen)
    output_filename = "%s/lichess%04d__%s.png" % (out_folder, i, fen.replace('/','-'))
    
    # Render webpage and save screenshot
    # Unfortunately have to generate cookie manually
    theme,bg,pieceSet = themes[2],"dark",pieceSets[0]
    
    cookie = 'lila2=%s'%code
    
    status = chessServer.takeChessScreenshot(fen,output_filename,cookie)
    
    if status == 0:
        print "\t...Success"
    else:
        print "\tFailed on %s -> %s" % (fen, output_filename)
        break
    
    # Load image, crop and overwrite file
    im = PIL.Image.open(output_filename).crop([218,141,737,658]).save(output_filename)
#0 : qNBRrPKp/brRRqbQp/1prrRbRk/bknPkbqn/QrnpNPpb/QbQkKQnk/Rqr1NrbB/rnkkkBbR
	Saved screenshot to 'train_images/lichess0000__qNBRrPKp-brRRqbQp-1prrRbRk-bknPkbqn-QrnpNPpb-QbQkKQnk-Rqr1NrbB-rnkkkBbR.png'
	...Success
#1 : kQRBKkNb/qRKNbkk1/kRPPqKKP/BbBQnBkb/qbqRKPQN/RpBNqNQn/rq1nkqrk/KrrqBNN1
	Saved screenshot to 'train_images/lichess0001__kQRBKkNb-qRKNbkk1-kRPPqKKP-BbBQnBkb-qbqRKPQN-RpBNqNQn-rq1nkqrk-KrrqBNN1.png'
	...Success
#2 : bRnnRbKN/Bbbk1Q1R/QpbQPqrb/PRRNqPBQ/QKB1rRpr/r1Pq1qrb/nnppqb1P/1nnRBPrk
	Saved screenshot to 'train_images/lichess0002__bRnnRbKN-Bbbk1Q1R-QpbQPqrb-PRRNqPBQ-QKB1rRpr-r1Pq1qrb-nnppqb1P-1nnRBPrk.png'
	...Success
#3 : p1kPNrkP/knqn1BRn/p1bRQnnr/1qnrp1BQ/rRPQbQkN/qQQ1bpKB/kkrPbbrP/RNBRbKnk
	Saved screenshot to 'train_images/lichess0003__p1kPNrkP-knqn1BRn-p1bRQnnr-1qnrp1BQ-rRPQbQkN-qQQ1bpKB-kkrPbbrP-RNBRbKnk.png'
	...Success
#4 : BrbrKqqR/1NqBbQRn/NNpQNNKP/RK1P1PqB/1kBQ1nKn/NBnn1bBb/kkkkqNrb/KrKQRQn1
	Saved screenshot to 'train_images/lichess0004__BrbrKqqR-1NqBbQRn-NNpQNNKP-RK1P1PqB-1kBQ1nKn-NBnn1bBb-kkkkqNrb-KrKQRQn1.png'
	...Success

Generating from FEN diagram generators

We can create images directly from online FEN chess diagram generators, much quicker. Let's add a couple of those.

http://www.jinchess.com/chessboard/?p=rnbqkbnrpppppppp----------P----------------R----PP-PPPPPRNBQKBNR

http://www.apronus.com/chess/stilldiagram.php?d=DRNBQKBNRPP_PPPPP__P______P___________p_____k____pppQp_pprnbq_bnr0

In [101]:
import urllib, cStringIO
def generateRandomBoards(n, outfolder, img_url_template, fen_chars='1KQRBNPkqrbnp'):
    """Given chess diagram template url, generate n random FEN diagrams from url and save images to outfolder"""
    # http://www.jinchess.com/chessboard/?p=rnbqkbnrpppppppp----------P----------------R----PP-PPPPPRNBQKBNR
    # http://www.apronus.com/chess/stilldiagram.php?d=DRNBQKBNRPP_PPPPP__P______P___________p_____k____pppQp_pprnbq_bnr0
    # No / separators for either choice
    
    # Create output folder as needed
    if not os.path.exists(outfolder):
        os.makedirs(outfolder)
    
    for i in range(n):
        fen_chars = list(fen_chars)
        fen_arr = np.random.choice(fen_chars, 64)
        fen = ''.join(fen_arr)
        img_url = img_url_template % fen
        img = PIL.Image.open(cStringIO.StringIO(urllib.urlopen(img_url).read()))
        if 'apronus' in img_url_template:
            # need to flip FEN file order since the are 1-8 vs 8-1 of normal FEN.
            fen_arr = np.hstack(np.split(fen_arr,8)[::-1])
        
        # Replace - or _ with 1 to be consistent with actual FEN notation
        fen_arr[fen_arr == fen_chars[0]] = '1'
        
        # Add - between sets of 8 to be consistent with saved file format (later converted to / again for analysis link)
        fen = '-'.join(map(''.join, np.split(fen_arr, 8)))
        
        img.save(os.path.join(outfolder, fen+'.png'))
#
generateRandomBoards(20,'chessboards/train_images', "http://www.jinchess.com/chessboard/?p=%s", '-KQRBNPkqrbnp')
generateRandomBoards(20,'chessboards/train_images', "http://www.apronus.com/chess/stilldiagram.php?d=_%s", '_KQRBNPkqrbnp')

Generate Tile images from screenshots

Great, now that we have several boards, let's generate the tiles for them.

In [109]:
# Directory structure
input_chessboard_folder = 'chessboards/train_images'
output_tile_folder = 'tiles/train_tiles_C'

tensorflow_chessbot.generateTileset(input_chessboard_folder, output_tile_folder)
#  1/151 : chessboards/train_images/lichess0000__kpp1QBpR-RpbPQkQn-nQbBrBQk-K1bPNpRP-qbkQppbP-rPbRBnNK-Ppr1rpKP-pRBbnkKK.png
	Skipping existing
#  2/151 : chessboards/train_images/b1KpkNQk-qRrBrPnb-KqqRqRqK-qPPRnnkr-nqrKqpNR-bnpkNRk1-nBnbkqkq-Qk1kN1pq.png
	Skipping existing
#  3/151 : chessboards/train_images/NKNkkbBp-PBBbKNKn-rr1NPbNp-BRpRknbq-qnbPRRrK-NPRnrbRP-BK1QNBrn-PqkkpkBb.png
	Skipping existing
#  4/151 : chessboards/train_images/1qpqQRRb-1NPR1pBn-nQNnknRp-kBQQB1bK-pQNr1Qb1-qKq1RrbN-KknQBPPp-BqpkNKpk.png
	Skipping existing
#  5/151 : chessboards/train_images/lichess0002__1qbq11BB-111BPrRr-bnnPrk1k-bNQ1BprK-NbbbQkpn-nnbqNPkQ-1NPQ1NBr-1nQKrrpP.png
	Skipping existing
#  6/151 : chessboards/train_images/lichess0004__BrbrKqqR-1NqBbQRn-NNpQNNKP-RK1P1PqB-1kBQ1nKn-NBnn1bBb-kkkkqNrb-KrKQRQn1.png
	Skipping existing
#  7/151 : chessboards/train_images/lichess0004__pRrKRQqq-1BQRBrQB-PBNQkBbP-pprQQbqB-1qbKRbqB-NbnRNKRr-QrQnQBNq-rBQBkPbb.png
	Skipping existing
#  8/151 : chessboards/train_images/lichess0000__pNKpNNnr-PprNkkkR-KKqQPqrR-n1KkqbnP-NPKnPKnB-rnrrNnPp-BrNnQbQq-kqnqnBrq.png
---
Loading chessboards/train_images/lichess0000__pNKpNNnr-PprNkkkR-KKqQPqrR-n1KkqbnP-NPKnPKnB-rnrrNnPp-BrNnQbQq-kqnqnBrq.png...
	Generating tiles for lichess0000__pNKpNNnr-PprNkkkR-KKqQPqrR-n1KkqbnP-NPKnPKnB-rnrrNnPp-BrNnQbQq-kqnqnBrq...
	No Match, lines found (dx/dy): [] []
	No Match, skipping
#  9/151 : chessboards/train_images/lichess0000__1QN1kB1k-BqqrBNbQ-pRpPkkrb-qN1qrbrk-KP1qBbKn-PRBQqqNB-QQNqr111-PQbKqpQK.png
	Skipping existing
# 10/151 : chessboards/train_images/pBrQPKK1-bKNprRn1-bKnbknkq-bPPRrRkQ-qB1RnnqB-QPRrkBRp-NRrbpPQr-nBRRpbnp.png
	Skipping existing
# 11/151 : chessboards/train_images/lichess0002__Rbr1RKqp-pBNBP11P-qnPnk1pB-BPrpnnB1-RqnRnBrr-BRnbrbQn-nbQRKpq1-RBPrqrKK.png
	Skipping existing
# 12/151 : chessboards/train_images/lichess0000__NNQKKBrn-bnrbkknp-kNkQBRnp-rPpNPKQR-BnBQknKB-KPQNnkbr-rNqqPqPP-QqkBRPBR.png
	Skipping existing
# 13/151 : chessboards/train_images/K1NRbrqQ-PQkBRn1N-Bk1PrpBr-PrPPpRpb-rRnrPknB-KKPrKkKP-1BrNrqK1-kbr1K1Rk.png
	Skipping existing
# 14/151 : chessboards/train_images/kBQQnnKb-nkQbqRrR-B1BPrQBK-rRBnQkqr-pbNp1rkQ-brk1bqqQ-pqKBbrRK-qnrQPbqN.png
	Skipping existing
# 15/151 : chessboards/train_images/kBKkrPnB-qBpKnRbN-nRk1BQnb-PbNNnqQb-QQpQnkp1-nrBnKkKR-Q1BBN1B1-PrRqnBn1.png
	Skipping existing
# 16/151 : chessboards/train_images/lichess0001__qB1nbrbN-bBQrrBb1-QrBkknQb-KQbQbbNr-bRQBqPKb-KBbqQPBN-bQKKrQqK-rkr1BBQn.png
	Skipping existing
# 17/151 : chessboards/train_images/lichess0004__rbNpnpKQ-bQpbr1kb-kkqQPknQ-KRkqBnNN-NP1RRPrp-kqPq1RnN-kbRKBPBP-kbPRk1KQ.png
	Skipping existing
# 18/151 : chessboards/train_images/lichess0004__rPQqRPqN-bbNKNnb1-N1KRNB1B-qP1QnQPp-K1NqRBPK-PPPBqNRN-1kNBkrQQ-qbRRknNK.png
	Skipping existing
# 19/151 : chessboards/train_images/KrNRKpQn-RRPnQrnr-BRQrNPqk-1knpBKPQ-1qBRbRpn-kBrQnKnr-pRQrrknp-1brrbpKp.png
	Skipping existing
# 20/151 : chessboards/train_images/lichess0000__qBRR1RRR-kK1rprkk-11nq1nn1-pKbrnnR1-pBBqBbQB-NRPRkBNk-pRKkkbKP-KnBQbbqR.png
	Skipping existing
# 21/151 : chessboards/train_images/BkKrnqpq-pqqKpnpK-1BkpRKqB-RBpP11bK-NnkQq1Rn-rqNKKnPP-BR1Rbbqp-K1bBPkPp.png
	Skipping existing
# 22/151 : chessboards/train_images/qnpqKnNQ-KPRNr1NQ-PRRNKR1q-Qbbr1NkN-nnRkNnrN-nPNrKkRB-NnkPPpkk-bppk1qrN.png
	Skipping existing
# 23/151 : chessboards/train_images/1KprRNKk-pbpBRbQr-nbPqbKrk-nNr1QRKN-pkPkBNNK-QpQkPRQ1-nqN1nPrB-knpbqknr.png
	Skipping existing
# 24/151 : chessboards/train_images/lichess0000__nnkqkPKq-PKbpr1RR-PpnBpPPp-QpN1nR1k-knqnkK1Q-pKqp1BQR-NrnQRNRb-PPBkkPnq.png
	Skipping existing
# 25/151 : chessboards/train_images/rkPkrQPN-1rqKbR1q-KPpNK1Pr-PBbkn1Qq-Knr1pNPp-PBNrKpBN-pn1pPnp1-brBbn1QB.png
	Skipping existing
# 26/151 : chessboards/train_images/N1Qq1RNB-RPpRpRPQ-BrQQkkQk-BpKQ11rQ-PKKbPrkP-nkrN1r1R-RQrkqrPn-PBP11QBb.png
	Skipping existing
# 27/151 : chessboards/train_images/RqrbpBrB-QpkbbNbQ-QnRPBR1r-kpkbprNq-QPP1PrRP-QPnnPPqk-nrQBKqk1-1rBBKNPB.png
	Skipping existing
# 28/151 : chessboards/train_images/lichess0000__Bk1p1rrb-bN1NnnQp-q1QkrqNr-npPnRbrK-bb1Pnbrq-RKQbPbnN-rRKRPkQk-1RbqpkQR.png
	Skipping existing
# 29/151 : chessboards/train_images/lichess0003__RKRRpPkR-Bp1kRbpk-BBQnNqRR-brqbrqrq-rPNQkrRP-kBpp1qrQ-PRnQbKbB-QNBrBPNP.png
	Skipping existing
# 30/151 : chessboards/train_images/lichess0002__BP1QqKrp-nb1bBnQR-RrPQ1kk1-KrBqPbrk-NQB1Rb1Q-pkr1rQbR-RNkBbKKP-RNB1ppPK.png
	Skipping existing
# 31/151 : chessboards/train_images/prk1Bpnq-nQPpRbQP-qPnp1Q11-qBn1KPNN-rB1RqrPq-R1RrRPBq-NRQQQBbK-bqqPkbk1.png
---
Loading chessboards/train_images/prk1Bpnq-nQPpRbQP-qPnp1Q11-qBn1KPNN-rB1RqrPq-R1RrRPBq-NRQQQBbK-bqqPkbk1.png...
	Generating tiles for prk1Bpnq-nQPpRbQP-qPnp1Q11-qBn1KPNN-rB1RqrPq-R1RrRPBq-NRQQQBbK-bqqPkbk1...
	Saving tiles prk1Bpnq-nQPpRbQP-qPnp1Q11-qBn1KPNN-rB1RqrPq-R1RrRPBq-NRQQQBbK-bqqPkbk1
# 32/151 : chessboards/train_images/lichess0003__q1KPPn11-N1bnnKKn-KBn1QbKB-qBbRRK1r-QnPBkkn1-Nq1RrpBp-nQBNkk1B-bRPrq1kn.png
	Skipping existing
# 33/151 : chessboards/train_images/QrqnnN1p-PrQqQNrb-K1nq1pQr-nQPBb11q-NpBRkRbR-pb1PNPPN-krq1Kn1K-PqRpbbPb.png
	Skipping existing
# 34/151 : chessboards/train_images/QRnPQPRn-nBnRrqnq-KRrQBNRb-p1nqqQP1-PBN1RBpn-1qqRRqNK-k1b1qkNB-nrNRrrQR.png
---
Loading chessboards/train_images/QRnPQPRn-nBnRrqnq-KRrQBNRb-p1nqqQP1-PBN1RBpn-1qqRRqNK-k1b1qkNB-nrNRrrQR.png...
	Generating tiles for QRnPQPRn-nBnRrqnq-KRrQBNRb-p1nqqQP1-PBN1RBpn-1qqRRqNK-k1b1qkNB-nrNRrrQR...
	Saving tiles QRnPQPRn-nBnRrqnq-KRrQBNRb-p1nqqQP1-PBN1RBpn-1qqRRqNK-k1b1qkNB-nrNRrrQR
# 35/151 : chessboards/train_images/lichess0002__PPQBKRrp-QrNN1qkB-nk1kb1bb-pRNrBNQN-N1KkrkK1-pB1pqpBR-RNBnqR1R-nKbQqkBK.png
	Skipping existing
# 36/151 : chessboards/train_images/lichess0004__BKkpKqqk-QrbqBqbN-QRbqNnRQ-qNppQQP1-NkKbPbpB-NprrnrPR-nrPNrRkK-prK1QPrP.png
	Skipping existing
# 37/151 : chessboards/train_images/lichess0000__qNBRrPKp-brRRqbQp-1prrRbRk-bknPkbqn-QrnpNPpb-QbQkKQnk-Rqr1NrbB-rnkkkBbR.png
	Skipping existing
# 38/151 : chessboards/train_images/lichess0003__1BpQqqNQ-RrrK1BPR-bPBBk1KR-RkkrBBkk-RpQNNPPQ-BRKbKKbQ-RnPRRP1B-Pb1KPPBk.png
	Skipping existing
# 39/151 : chessboards/train_images/lichess0001__rkbRRr1Q-rBNk1BPK-NR1BpnNQ-kbnPbnpQ-bNnQ1bqq-1bqNPRNN-PppKBnnb-bnNKqR1k.png
	Skipping existing
# 40/151 : chessboards/train_images/lichess0004__nk1RpnqQ-rRnprqqP-nRqBPRnQ-KPrNQPpn-rRbBqb1K-bkBQQRqk-RRQRNNRk-p1RqqRKB.png
	Skipping existing
# 41/151 : chessboards/train_images/lichess0001__kNbQpqNR-BqRk1bnr-rN1R1qKn-BbRkqbkN-1nNNRqkn-nQkpkQkB-qbqBrBRQ-NKBrrPB1.png
	Skipping existing
# 42/151 : chessboards/train_images/lichess0003__QPqkQqQp-QBbRrRbr-PPbB1qKb-NBnKBBQp-p1QNNRkR-bqrrk11b-qpnPKrQr-BKb1NKPq.png
	Skipping existing
# 43/151 : chessboards/train_images/kRkBKrRq-Pn1R1qrq-krRqBRNK-QbNPnQRP-KpBqnbkB-1PrnbPNR-PNqrPbP1-rQpQRkNQ.png
	Skipping existing
# 44/151 : chessboards/train_images/lichess0002__qnkb1RBN-bkBK1NPp-qbBpPBKN-bBpQqNkP-pKnKBbnP-KQnBRRK1-KkpRBKpB-RNKnkkpQ.png
---
Loading chessboards/train_images/lichess0002__qnkb1RBN-bkBK1NPp-qbBpPBKN-bBpQqNkP-pKnKBbnP-KQnBRRK1-KkpRBKpB-RNKnkkpQ.png...
	Generating tiles for lichess0002__qnkb1RBN-bkBK1NPp-qbBpPBKN-bBpQqNkP-pKnKBbnP-KQnBRRK1-KkpRBKpB-RNKnkkpQ...
	No Match, lines found (dx/dy): [] []
	No Match, skipping
# 45/151 : chessboards/train_images/nqrppNbn-n1QKpRK1-QqqbqNKB-rqrBKqnn-PPPbKPkr-BrkQpPk1-pBpPkKQk-Q1pbpKNB.png
	Skipping existing
# 46/151 : chessboards/train_images/lichess0000__qpnQp1qB-rPBb11Nq-KPrKKBKN-pRbkkQ1N-nRQBQkpp-bQ1nnqqk-RNRbBNnr-rbQn1RK1.png
	Skipping existing
# 47/151 : chessboards/train_images/lichess0002__rrbnq1kb-qNBPPrkn-Nn1bkkrK-nPpPQ1Nn-bPNKqbKK-PqnNKRpb-qpPNKNnq-QbKnqk1k.png
	Skipping existing
# 48/151 : chessboards/train_images/lichess0003__B1kPNqPp-KnnbqKpB-brqqNkbN-p1b1QKp1-prKRkn1B-nRrpBBqB-RKrRNRKN-pbPPqbbQ.png
	Skipping existing
# 49/151 : chessboards/train_images/lichess0000__BR1QKkrk-pNKbkBKB-b1k1qKnN-rKnKKK11-b1QPrrbr-1bRRrqQK-P1rpnQKN-nPbrBpPr.png
	Skipping existing
# 50/151 : chessboards/train_images/Rn1qNpq1-KpKbP1bK-Nq1RRrKB-1NpQNkkQ-Rp1BPkRp-BkRnkkQP-BbBqpbkB-nQkrB1kQ.png
	Skipping existing
# 51/151 : chessboards/train_images/lichess0000__qNnb1PkK-kqrqBQbK-RNrppRnk-KKp1pqRp-Kb1QNnr1-QRQkpNPq-RQbNKpR1-RqppkKkB.png
	Skipping existing
# 52/151 : chessboards/train_images/lichess0001__kKRkB1Pp-bnNnNRbB-KPrqR1PN-RKkpnB1N-rpNppQPP-QBQpNBNQ-qPnRnRQQ-QPPbB11k.png
	Skipping existing
# 53/151 : chessboards/train_images/lichess0004__pRbRqpKq-pbNKrBBK-1BnNNn1K-bBQNPNqR-bNK1kKBQ-Rr1BbPKN-RRn1KqNR-RrPRBn1n.png
---
Loading chessboards/train_images/lichess0004__pRbRqpKq-pbNKrBBK-1BnNNn1K-bBQNPNqR-bNK1kKBQ-Rr1BbPKN-RRn1KqNR-RrPRBn1n.png...
	Generating tiles for lichess0004__pRbRqpKq-pbNKrBBK-1BnNNn1K-bBQNPNqR-bNK1kKBQ-Rr1BbPKN-RRn1KqNR-RrPRBn1n...
	No Match, lines found (dx/dy): [] []
	No Match, skipping
# 54/151 : chessboards/train_images/lichess0000__1QkkqNr1-pqbQrBnB-R1BrKKKq-bqkrNpRq-BPbrkqnn-RkbkkrNP-Bb1pnrKq-PB1bbQpr.png
	Skipping existing
# 55/151 : chessboards/train_images/lichess0001__RkqKbqnk-nnnBPqqn-NrbrrbRk-111k1QPQ-Pbp1bBrQ-PnpN11bp-RNQ1p1Qn-RnqrbNkR.png
---
Loading chessboards/train_images/lichess0001__RkqKbqnk-nnnBPqqn-NrbrrbRk-111k1QPQ-Pbp1bBrQ-PnpN11bp-RNQ1p1Qn-RnqrbNkR.png...
	Generating tiles for lichess0001__RkqKbqnk-nnnBPqqn-NrbrrbRk-111k1QPQ-Pbp1bBrQ-PnpN11bp-RNQ1p1Qn-RnqrbNkR...
	No Match, lines found (dx/dy): [ 69 133 197 261 325 389 453] []
	No Match, skipping
# 56/151 : chessboards/train_images/pNbnNB1B-qRq11KpR-qrrBrKQP-nBRk1Rnb-pnRBK1kk-bBKPqrnR-P1bN1Pqp-KpPNKrr1.png
	Skipping existing
# 57/151 : chessboards/train_images/PknkBKpK-pKrbn1Bq-RBbkBBRP-qPNbRpqp-KRPKKBkk-1rkBkpR1-PNrK1kkR-RQQqNQRK.png
	Skipping existing
# 58/151 : chessboards/train_images/lichess0002__qRpQQrNK-bnnrKkrk-kKBqpBnB-pnkkkkRQ-RRpNpbKR-pQPQQPbK-KPNrRNKn-rn1ppnkB.png
	Skipping existing
# 59/151 : chessboards/train_images/RBBkrN11-BprQpkrQ-q1pNP1bN-bBQpqPPn-PBrqrBBN-PnRn1PQ1-BrrPpQnk-N1RnrPQn.png
	Skipping existing
# 60/151 : chessboards/train_images/lichess0001__bpRrQbBK-brKRqrKr-B1nbnRQ1-rQQQBBRQ-1P111pRn-BpNpqKrB-Q1RrkQnb-kQpbRbBq.png
	Skipping existing
# 61/151 : chessboards/train_images/lichess0004__pppkBkrQ-N1BNQqkr-qqKBPpR1-RPkn1KBp-kKRKbpNN-pQqBPNkq-1QPppkpb-knNbrNrr.png
	Skipping existing
# 62/151 : chessboards/train_images/lichess0001__bpPNKkrb-nQRnPbPp-qkqKQRBk-kb1KR1qB-kP1Qr1kB-nRPbRKpn-kQR1pqnR-1RNPBpNP.png
	Skipping existing
# 63/151 : chessboards/train_images/PQbrrpQq-qpRqKPqp-QBNbn1nP-kqBQ1BQr-RQQ1rRnn-QNRkpkpN-NK1KkpNK-pKnQKP1r.png
	Skipping existing
# 64/151 : chessboards/train_images/lichess0003__qrpKbbKQ-k1QNkbQK-NbNQKbNP-QNbqNKkK-nq1qRQnk-1rrpNp1Q-QprPbRPP-1bpkBNbP.png
	Skipping existing
# 65/151 : chessboards/train_images/lichess0003__knpnqbRR-pbQKqKQN-1kBnn1k1-nKnKprnn-NpbRNNrb-NRBRrPNP-kkPnkbRn-qqPKbpRp.png
	Skipping existing
# 66/151 : chessboards/train_images/lichess0001__QqbQKBRn-QPkr1pB1-NpbQkNbp-NP1qKN1n-QQbbrqQ1-KrpBpRQn-bpPR1bKb-RBB1QNQ1.png
	Skipping existing
# 67/151 : chessboards/train_images/lichess0002__NnrnKNpp-1Q1Qb11p-r1QqkqQP-Pq1KQQbb-krRRRb1K-bKr1pkQR-NrpKBRrn-nnRpr1kR.png
	Skipping existing
# 68/151 : chessboards/train_images/qqN1nnqB-BkqqRbkk-kkQrPn11-n1RnPnNB-1k1PK1pp-QQNpRbBN-ppNNPQr1-rbBKprNp.png
	Skipping existing
# 69/151 : chessboards/train_images/lichess0000__bBBBKknq-1NqbBbKN-kQknKnKR-QNp1NKQk-nQbNPRNb-1KNnQBPk-brbnbQ1b-krpRpqKQ.png
	Skipping existing
# 70/151 : chessboards/train_images/lichess0002__bRnnRbKN-Bbbk1Q1R-QpbQPqrb-PRRNqPBQ-QKB1rRpr-r1Pq1qrb-nnppqb1P-1nnRBPrk.png
	Skipping existing
# 71/151 : chessboards/train_images/b1KnpBqb-BppNnQkK-pbBPRbqp-nQNbnRPN-BqQKpNPK-nRpQpNBb-R1rkPKpB-pKnNRnnq.png
	Skipping existing
# 72/151 : chessboards/train_images/lichess0004__RQRBKNrq-qrQK1BqP-rn11nkQp-pnK1Bnnq-QrP1rqPQ-Qb1prKNQ-rB1nBbR1-KNpQ1NnK.png
	Skipping existing
# 73/151 : chessboards/train_images/KQqRBbrK-R1NrKPkn-kNbBPNnb-brBPRbkk-kbRpprpp-Q1PPrNNQ-pNNpKqRR-NKknn111.png
	Skipping existing
# 74/151 : chessboards/train_images/QnpQrqrB-RBnqknBp-kk1PB1bn-rQbrqKNR-Rq1bR1bK-nqKpkQrq-nqbbqbbN-qrNnnbkR.png
	Skipping existing
# 75/151 : chessboards/train_images/rqNBBkKp-QqrpqP1P-PkKPkrQk-R1qkbQRk-NRKkp1qQ-nKqQ1pbQ-NbQPn1Qq-PnRbBpqN.png
---
Loading chessboards/train_images/rqNBBkKp-QqrpqP1P-PkKPkrQk-R1qkbQRk-NRKkp1qQ-nKqQ1pbQ-NbQPn1Qq-PnRbBpqN.png...
	Generating tiles for rqNBBkKp-QqrpqP1P-PkKPkrQk-R1qkbQRk-NRKkp1qQ-nKqQ1pbQ-NbQPn1Qq-PnRbBpqN...
	Saving tiles rqNBBkKp-QqrpqP1P-PkKPkrQk-R1qkbQRk-NRKkp1qQ-nKqQ1pbQ-NbQPn1Qq-PnRbBpqN
# 76/151 : chessboards/train_images/r1k1Q1qn-kPpbRN1Q-RQpnNPNP-Nbnpp1bp-PBkqRQBr-ppBqbPKB-bnNPnbnr-BpnPrpkK.png
	Skipping existing
# 77/151 : chessboards/train_images/lichess0004__QknRbNNn-kQrKRBbK-npPBpQ1b-npbpPPk1-pNqqQknq-PKPrR1Bn-bNR1RnRK-Prbnbrbq.png
	Skipping existing
# 78/151 : chessboards/train_images/lichess0001__qqnQQK1N-krrnQr1n-NkQQPBPk-KkqpRqPr-QqprNkRB-KRKrpQR1-Nq1nqqRN-B1QQnbqk.png
	Skipping existing
# 79/151 : chessboards/train_images/NrQPKrrP-bn1rPRrK-PPbqQnQP-PRNnKKQk-1KkNKNrB-bkNBqBpb-KqNkNkNP-rnk1bNnB.png
	Skipping existing
# 80/151 : chessboards/train_images/1kNnPNbk-PqrbQB1n-BKBqrbkb-b1pnQpKk-BkKRbqQR-nqppNqbb-RrBRqn1n-rbQnKkbB.png
	Skipping existing
# 81/151 : chessboards/train_images/QRQRnNRR-pNNQNPkN-nNRPRrQB-1PKqkKKk-BqRrbPKp-bkKrnRnK-bp1bk1nR-kqQPNqQr.png
---
Loading chessboards/train_images/QRQRnNRR-pNNQNPkN-nNRPRrQB-1PKqkKKk-BqRrbPKp-bkKrnRnK-bp1bk1nR-kqQPNqQr.png...
	Generating tiles for QRQRnNRR-pNNQNPkN-nNRPRrQB-1PKqkKKk-BqRrbPKp-bkKrnRnK-bp1bk1nR-kqQPNqQr...
	No Match, lines found (dx/dy): [ 36  72 108 144 180 216 252] []
	No Match, skipping
# 82/151 : chessboards/train_images/KnkkN1RB-1kRbRbkq-BnpkpQKN-Kn1pkBnP-pbqRPqkp-NbkqKp1P-bQrRqQK1-qBbn1BQR.png
	Skipping existing
# 83/151 : chessboards/train_images/QBnQrBpk-1KNrrkrn-pRPNbKPq-PrqRnnB1-bB1QrppB-nPp1RRKn-bqbQbBpB-PpQRqRNK.png
	Skipping existing
# 84/151 : chessboards/train_images/lichess0004__kPKkNPkK-prbnBNq1-kb1rNkqR-B1q11nQ1-QBRbkknK-PNPKKPBr-pk1KnqnR-p1RrNrBb.png
	Skipping existing
# 85/151 : chessboards/train_images/KqrKqQkp-P1Pn1pbN-rPnKPkRn-PbQPqPpn-QnPRBnBB-kkrN1KQR-nbQkPKQp-QRPqRnKP.png
	Skipping existing
# 86/151 : chessboards/train_images/lichess0002__RprKPqkk-NqQppbPB-QkNnRqNb-ppPbbbbk-KQRkPNPq-pKnpkpBr-bprB1NbN-pKnKQqkQ.png
	Skipping existing
# 87/151 : chessboards/train_images/lichess0001__rQbBpPPr-1b1nPBKB-rkpNNrQq-QRKQbqB1-n1PrrN1q-Q1kQQk1N-PqnkrkqR-rK1bkbrK.png
	Skipping existing
# 88/151 : chessboards/train_images/NnKkBb1B-rbPPqPbn-pNprPNnK-nqqprnqn-p1PrQBQQ-PQ1NB1pr-bnQQqQKb-11PKKBkQ.png
	Skipping existing
# 89/151 : chessboards/train_images/lichess0003__KqNBpkqN-b11NKpKP-KbB1knqk-RNrnRQnq-QqrqBkB1-BRnp1K1N-pNBqNbQq-nbPNrN1R.png
	Skipping existing
# 90/151 : chessboards/train_images/pr1NKnnb-qkNnKKKP-rPbQnKP1-bnKnrQkq-B1nnrKQb-PNNpRBPB-RNbR1nkN-PknNBQkR.png
---
Loading chessboards/train_images/pr1NKnnb-qkNnKKKP-rPbQnKP1-bnKnrQkq-B1nnrKQb-PNNpRBPB-RNbR1nkN-PknNBQkR.png...
	Generating tiles for pr1NKnnb-qkNnKKKP-rPbQnKP1-bnKnrQkq-B1nnrKQb-PNNpRBPB-RNbR1nkN-PknNBQkR...
	No Match, lines found (dx/dy): [] []
	No Match, skipping
# 91/151 : chessboards/train_images/nrNnQbQQ-pkPRppQ1-bnpk1nQN-1Q1QNbpk-bnRrpnrp-KqrkQbrP-1NkkPn1B-pbkbpqKk.png
	Skipping existing
# 92/151 : chessboards/train_images/lichess0001__kQRBKkNb-qRKNbkk1-kRPPqKKP-BbBQnBkb-qbqRKPQN-RpBNqNQn-rq1nkqrk-KrrqBNN1.png
	Skipping existing
# 93/151 : chessboards/train_images/qnRBkpbb-ppNPbnNP-KBr1BPpP-pBRPRnRp-kkbRRPrR-RB1qBNNr-bNkbbBqp-npRkPbKp.png
	Skipping existing
# 94/151 : chessboards/train_images/KQQbbbN1-BQBpqqBN-nRrQQkNN-kk1QNnPn-BpbRBpNb-KbrRrBb1-kqKqPPBN-QqPNQnPp.png
	Skipping existing
# 95/151 : chessboards/train_images/11qnpPNp-kNPrPBqn-NKNpQRNp-BNKknRkB-pBk1QPKN-BnPNQPrQ-qbpBQRrr-rqNQRRrQ.png
	Skipping existing
# 96/151 : chessboards/train_images/lichess0001__NbpB1QRK-BnNRbQp1-QPpKkPRB-bKpQKPnQ-bpqkq1rQ-nRKBpBbR-bnPpqQQP-nBkNnnqb.png
	Skipping existing
# 97/151 : chessboards/train_images/lichess0003__rr1QNNkK-bnbPNnrQ-pRqPkbpR-bBrQ1qPk-pbNbK1rQ-KbQRkRBn-KnN1pqbp-1rnpBKBp.png
	Skipping existing
# 98/151 : chessboards/train_images/lichess0002__b1RKPRnn-Q1KrkPbR-ppBBprqK-nKqbrpBK-pKNqqRNq-QRqpk1bN-QRKb1BnR-rnbKRRB1.png
	Skipping existing
# 99/151 : chessboards/train_images/lichess0002__kNBqq1kb-nQ1nNpRP-B1PQRq1K-NbkkPNrr-qNkPkknR-KqRpnrkB-PkP1rpnr-bQpRQRnn.png
	Skipping existing
# 100/151 : chessboards/train_images/lichess0001__1KqbRKqr-Q11nr1pq-bKkpQRnk-pkprBPpK-KnQKQqRb-1QbPBbNn-RNpR1Bnn-bBbQ1Pnq.png
	Skipping existing
# 101/151 : chessboards/train_images/NKrpKBQN-BKbPrNrR-PrPNqqpR-BRkKPqkp-kRKr11Pk-nqNrpnQk-qKqr11PB-kkPbrRrB.png
	Skipping existing
# 102/151 : chessboards/train_images/lichess0002__pKrKKNNr-Rn11B1bN-BrQb11pn-KQkbPpqb-NrqB1kNb-NpBBKQNB-pKqQPrQR-BPnKPQNr.png
	Skipping existing
# 103/151 : chessboards/train_images/nR1pnbQQ-QRkRbBnR-bNPQrQnb-Rpqp1bNB-bppKBnbN-nPK1P1BQ-BPKKQRbB-BrKRPppP.png
	Skipping existing
# 104/151 : chessboards/train_images/r1nbqQRN-1Rbq1QBK-qQkQNbKP-bNKNpNpp-NnbBQKNn-qKBbRrnQ-R1R1qnnK-NNrnbPpB.png
	Skipping existing
# 105/151 : chessboards/train_images/lichess0003__rpppNrb1-prkkPKnB-QKrPBkRK-BPnpBPBK-NpnB1nBq-rbn1kqkB-pQnkkrRb-bQb1nNPq.png
	Skipping existing
# 106/151 : chessboards/train_images/lichess0003__qBKnkBQr-BNKkqR11-BQRBbqBq-qnrKNpqn-qPbK1bbK-QQrbNRKQ-BRPkbbrr-BPNkQrK1.png
	Skipping existing
# 107/151 : chessboards/train_images/R1nqnKQb-Pbk1pkpK-B1kkkK1r-1nPKRrbB-nrR1PbNK-qPKnpbKP-kRrRqpBr-pbbNQb1Q.png
	Skipping existing
# 108/151 : chessboards/train_images/NQqP1pbk-PpBNqqPk-pNkPrRNP-1KN1QQrn-PQpkKqNb-B1Qn1qnq-bnKp1knp-NBbBpNRk.png
	Skipping existing
# 109/151 : chessboards/train_images/lichess0004__nn1kBbPp-kQbNkR11-KQpbRQ1N-Rn1qkN1N-R1kbKpnQ-nPRrpBRb-BKbKbKrq-bbp11RNN.png
	Skipping existing
# 110/151 : chessboards/train_images/lichess0001__QnrQBKRp-n1rNQrKb-NrKnprqK-NQrn1npp-Kq1nPrQP-KNqkQBPN-krKnnppR-Rn1BrbkR.png
	Skipping existing
# 111/151 : chessboards/train_images/lichess0001__NpkbbnRp-BbQQBKNP-pRNrrKQK-nqKbr1Np-bK1qnb1Q-rQKpKkPq-qQ1KKBqb-PbBQ1rQn.png
	Skipping existing
# 112/151 : chessboards/train_images/RKnpBRRQ-BPkRbP1K-bbk1nKQP-QbnNpBnq-BkQp1rRK-pBPRkKkB-rqrkKNkP-kqqRBbbB.png
	Skipping existing
# 113/151 : chessboards/train_images/lichess0002__rBnNpn1k-PKbknBkR-rqn1kb1b-PrrBqBB1-PPNRNNrr-1qrRprbq-1bPkbpkK-RBbBpQRQ.png
	Skipping existing
# 114/151 : chessboards/train_images/lichess0002__KrRqPN1k-qnnbRqBQ-RRKBqQkQ-krBPKRqR-PbnBpqBp-nnPqrNn1-bkqqKbbB-kKKNr1bb.png
	Skipping existing
# 115/151 : chessboards/train_images/kBKnrQNb-NRbNRPnR-NQP1PkkP-bNBKNBBr-1KRpRQkK-RKkBkRQn-KnpKKrKq-RnkNpnpQ.png
	Skipping existing
# 116/151 : chessboards/train_images/QbBPnkkN-bkKPpknr-npkrrPqQ-PRqKnpbr-rRppBprp-bQnnKqbn-BkPNBQrq-bnBKRrrP.png
---
Loading chessboards/train_images/QbBPnkkN-bkKPpknr-npkrrPqQ-PRqKnpbr-rRppBprp-bQnnKqbn-BkPNBQrq-bnBKRrrP.png...
	Generating tiles for QbBPnkkN-bkKPpknr-npkrrPqQ-PRqKnpbr-rRppBprp-bQnnKqbn-BkPNBQrq-bnBKRrrP...
	Saving tiles QbBPnkkN-bkKPpknr-npkrrPqQ-PRqKnpbr-rRppBprp-bQnnKqbn-BkPNBQrq-bnBKRrrP
# 117/151 : chessboards/train_images/lichess0004__nnnNQPQk-nKBpqnqN-qprRKkbK-n1pKQnRB-BbkBq1Pk-p1rpnqPp-KPNBBrnN-NNqrNbrr.png
	Skipping existing
# 118/151 : chessboards/train_images/KKqKrnrP-nrBkQRNp-kq1rpPRp-kpnbP1nN-bN1pbqqq-PkrnbPPr-kKnQqRPq-RQbKb1r1.png
	Skipping existing
# 119/151 : chessboards/train_images/RQkQBBkN-pBPBKkQN-pbPkkBkk-rpqnnq1K-qrBQbbBP-rnNQrRnp-QbRkbQk1-BqRNKPNK.png
	Skipping existing
# 120/151 : chessboards/train_images/KKR1Kk1r-rNN1Kkbn-rQqKk1bq-BnKbPBqN-RbRpKRBP-rKBkNk1n-BKPnQbkQ-BNkBrpqQ.png
	Skipping existing
# 121/151 : chessboards/train_images/krB1K1bk-n1QKRPNN-PbP1r1qP-RQb1qQQn-kRBPnpP1-pKrN1Bkq-NRrbPBPK-kKNPbnpB.png
	Skipping existing
# 122/151 : chessboards/train_images/knQ1rKQb-PpQP1rPN-RR1nkQrb-kBN11BBR-bRppkPBN-q1RKKrPN-1p1kQrRP-QBBKrpRN.png
	Skipping existing
# 123/151 : chessboards/train_images/PPNKpbQq-NBkpPpkQ-NRQBpnRp-npQnBbR1-rPn1NBKN-K1nQPBkN-NPRBbqpN-bpbrrBQP.png
	Skipping existing
# 124/151 : chessboards/train_images/lichess0003__kqqPkrqP-R1RKBqbK-NkBNKRnR-BPKNN1Bq-NbkknbbB-bnBpprNp-k1knqnQr-QpNnqnNN.png
	Skipping existing
# 125/151 : chessboards/train_images/lichess0004__KBqbNPPp-qqn1Kbkn-BRrQ1rnb-KR1bBPNq-PNbrKPrQ-N1q1BBNR-BNn1Qr1q-KkRRKpRk.png
	Skipping existing
# 126/151 : chessboards/train_images/1kBRq1K1-rBnnnQNp-pQpPQbp1-Nbrpqb1p-nKn1nkkb-nQpKpqkR-bBqnkQBN-BP1nr1nQ.png
	Skipping existing
# 127/151 : chessboards/train_images/lichess0004__N1PpnQKp-pNqpnNqK-kpnQnrQB-NPbqQpqN-KpRbKbPB-kPKppkpR-rBqpkNNQ-bprKqkRb.png
	Skipping existing
# 128/151 : chessboards/train_images/lichess0000__QBnb1RkR-r1nQnrpB-pkRnBPkQ-PrRbrKN1-rnqKPrRq-1RrkP1kP-pBnKq1QK-1qNPRQKn.png
	Skipping existing
# 129/151 : chessboards/train_images/nrP1nkQP-KqqpprqB-KRRrkbkr-KqnnrQbB-KqRkprrN-bbN1Qpbk-1K1BpBnp-QPrbrqpp.png
	Skipping existing
# 130/151 : chessboards/train_images/pKNQqn1q-nbrQqQkb-rpqbq1rQ-1NRKq1Bq-KBbqkRNK-pnpkQq1r-BpqRKQ1B-kNqrqn1N.png
	Skipping existing
# 131/151 : chessboards/train_images/lichess0004__QkkqnPBQ-PrrpbBnK-NbPnqbqB-1QrNnN1B-rKrQN1Kr-nNPRqpQB-QpkBPqNP-KqqRkbrK.png
	Skipping existing
# 132/151 : chessboards/train_images/11npKPkb-KRrkqQ1Q-Q1qQRp1R-rbbP1NNN-RQKPbb11-1rbPP1pr-KKPbbKQB-nK1bbRrK.png
	Skipping existing
# 133/151 : chessboards/train_images/lichess0002__b1BqqpNn-KprKNbQr-rPRkRrrb-npRrkqBn-KrRBrPRB-BbBbRpPK-QnpnQBBP-nB1RkP1k.png
	Skipping existing
# 134/151 : chessboards/train_images/lichess0001__PpbNnrnp-nQPQQpBQ-qNQbNNpK-pN11nBRN-RKnkQNBb-pNPqnbPQ-KqknBNpk-1bRbnNNB.png
	Skipping existing
# 135/151 : chessboards/train_images/lichess0003__PnQrPqnn-BkPRbQQq-BNrrKkrR-rkQPKbPN-bRnB1k11-qkqRPBpq-1NBKkbr1-PPpp1PrB.png
	Skipping existing
# 136/151 : chessboards/train_images/lichess0003__p1kPNrkP-knqn1BRn-p1bRQnnr-1qnrp1BQ-rRPQbQkN-qQQ1bpKB-kkrPbbrP-RNBRbKnk.png
	Skipping existing
# 137/151 : chessboards/train_images/PRBRQ1QR-NNnbBRNn-nPRPqrkB-RQbBbq1q-bb1BbBrr-kknNQNpr-KPrqpkqn-NkbBbnBK.png
	Skipping existing
# 138/151 : chessboards/train_images/lichess0001__rppRKqNR-BPpBrN1n-NbNQ1nNB-q1PrBqnr-bnQnQ1Rr-Nb1qQrnK-KBkkBQ1N-1NBpqQNQ.png
	Skipping existing
# 139/151 : chessboards/train_images/lichess0000__kkBKbBrk-nKbqnPKK-N1NKrPBk-BqqqqPBQ-r1RpPBnr-qRQRQ1Br-Qbk11bnr-rQrKkQkp.png
	Skipping existing
# 140/151 : chessboards/train_images/bBrPNbkN-rbrBNKN1-nPbnbRQp-RQkNNqp1-KQkRQQkb-qqKpNP1n-NbNnnRKk-qkbkrbnR.png
---
Loading chessboards/train_images/bBrPNbkN-rbrBNKN1-nPbnbRQp-RQkNNqp1-KQkRQQkb-qqKpNP1n-NbNnnRKk-qkbkrbnR.png...
	Generating tiles for bBrPNbkN-rbrBNKN1-nPbnbRQp-RQkNNqp1-KQkRQQkb-qqKpNP1n-NbNnnRKk-qkbkrbnR...
	Saving tiles bBrPNbkN-rbrBNKN1-nPbnbRQp-RQkNNqp1-KQkRQQkb-qqKpNP1n-NbNnnRKk-qkbkrbnR
# 141/151 : chessboards/train_images/lichess0002__kPpkNKqq-QprqRpNq-RnkKP1Kp-nbq1PkRr-QKNBNk1b-QKbbKpnk-BKrqqp1p-krRNnNBK.png
	Skipping existing
# 142/151 : chessboards/train_images/KRNQbn1b-bQp1NrkN-PbqNPKBN-prQBnNBk-1QkqkbQN-RpkRPKbp-BKKPr1Kb-kNrkQRKQ.png
	Skipping existing
# 143/151 : chessboards/train_images/lichess0003__rr1Q1KNN-NRNK1NRk-rnNbrrpp-PKKnpbbn-pQnNqQKq-BKpN1Kbk-bNKrpN1n-bNKBKPqp.png
---
Loading chessboards/train_images/lichess0003__rr1Q1KNN-NRNK1NRk-rnNbrrpp-PKKnpbbn-pQnNqQKq-BKpN1Kbk-bNKrpN1n-bNKBKPqp.png...
	Generating tiles for lichess0003__rr1Q1KNN-NRNK1NRk-rnNbrrpp-PKKnpbbn-pQnNqQKq-BKpN1Kbk-bNKrpN1n-bNKBKPqp...
	No Match, lines found (dx/dy): [] []
	No Match, skipping
# 144/151 : chessboards/train_images/lichess0003__RQQrNPqr-rqrRpNN1-BpBNKQpR-PBKQRBKK-QQqq11Qq-KRqBrp1P-qbQRpRNk-1PB1qbQb.png
	Skipping existing
# 145/151 : chessboards/train_images/lichess0003__KrQP1QQR-RBQnPqbp-PpRPBpPR-qKqbKnpP-BqQBp11p-nbBkq1NN-RRqrbnQP-rQ1NPQNK.png
	Skipping existing
# 146/151 : chessboards/train_images/RrBrBqRB-BrBQBPQk-pbPkBPbq-rqNQNpQK-bK1bnRKp-KRk11rpN-BRNKRbqk-Q1NPQpQ1.png
	Skipping existing
# 147/151 : chessboards/train_images/lichess0000__qP1BK1rB-RKPBKrr1-nKqbK1Qp-qQNpBnrN-pRPqk1R1-qnbbqN1r-PPPkKkRn-BQnkkkrp.png
	Skipping existing
# 148/151 : chessboards/train_images/NQqnKbPQ-kQkbQpBB-rrKPbq1k-nK1nBpRq-bQkNbbNR-Rrpbnnkp-rqNBrBbr-nQKrQRN1.png
	Skipping existing
# 149/151 : chessboards/train_images/QQBkPkpb-Q1kPKpBk-rnNRRrKq-qpbbrqPq-1KPQpbN1-1bPnbbqq-qprNpB1q-QnBBQbBq.png
	Skipping existing
# 150/151 : chessboards/train_images/lichess0000__1r1NNbQp-PrpNPBQb-QbbNqrR1-kqnqnBpb-rkkbpqKb-bkNQPRbB-PpQBBnbK-rQbrQbKP.png
	Skipping existing
# 151/151 : chessboards/train_images/lichess0004__rkkbr1pk-kpqQ1PNb-qQBKbN1B-PbpnRbnb-NnqrRNbR-qNRbrrbq-qRrQrPnR-NppQKNB1.png
	Skipping existing
	5/12 generated, 7 failures, 139 skipped.

Alright, with 150 boards, we have 9600 tiles with the format <FEN>_<RANK><FILE>.png

For example PkqrBBKq-RKbRpN1q-rKQRpPNN-PQNNPqBQ-Pqr1bbbp-pRbqnbBn-P1qbQQRr-rpBqRQNk_B6.png

This gives us all the information we need to load a tile and determine it's label within an image.