0
votes

I want to train a model to detect eye prescription data from pictures/pdfs. Ex. prescription

I'm thinking of splitting the task into 2:

  1. Define/train a model that will detect where the table on picture is.
  2. Define/train a model that will predict data from the result of previous model.

And I'm stuck at the first model. I started by creating 100k images (ex. https://i.stack.imgur.com/CQJXE.png, https://i.stack.imgur.com/iJHuk.png) with tables in them and tables' coordinates as label. Example of label:

27.38       // top coordinate of 1 table in picture
172.00      // left coordinate of 1 table
459.62      // right coordinate of 1 table
311.00      // bottom coordinate of 1 table
4.00        // number of columns of 1 table
5.00        // number of rows of 1 table
25.00       // top coordinate of 2 table in picture
424.50      // left coordinate of 2 table
462.00      // right coordinate of 2 table
544.50      // bottom coordinate of 2 table
7.00        // number of columns of 2 table
2.00        // number of rows of 2 table

Preparing data

X:

    image = tf.image.decode_png(image_string, channels=3)
    image = tf.image.resize(image,(337, 238), method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
    image = tf.image.rgb_to_grayscale(image,name=None)
    image = tf.image.convert_image_dtype(image, dtype=tf.uint16, saturate=False)
    image_string = tf.image.encode_png(   image ,    compression=-1,    name=None)
    image_string = image_string.numpy()
    image_shape = image.shape

Y:

I just multiply coordinate by 0.4 (because I'm resizing image to 40%), other data from generated label leaving as 0 (at least for now, expect to predict only coordinates) repeated 5 times, because there might be only 5 tables in picture.

Ex:

0.6120000000000001, 24.400000000000002, 193.284, 65.60000000000001, 0, 0, 2.8920000000000003, 97.60000000000001, 189.784, 144.0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0

Training:

Creating dataset:

def parseExample(example):
    features = {
        "image": tf.io.FixedLenFeature([], tf.string),
        "output": tf.io.VarLenFeature(dtype=tf.float32),
        # "output": tf.io.FixedLenFeature([], tf.float32),
        'height': tf.io.FixedLenFeature([], tf.int64),
        'width': tf.io.FixedLenFeature([], tf.int64),
        'depth': tf.io.FixedLenFeature([], tf.int64),
        'name': tf.io.FixedLenFeature([], tf.string)
    }
    parsed = tf.io.parse_single_example(example, features=features)
    image = tf.image.decode_png(parsed['image'], channels=1)
    image = tf.reshape(image,  (parsed['height'], parsed['width'], parsed['depth'])) 
    label = parsed["output"]
    return image, label.values

def make_dataset(dir, dtype, dataSetType, parse_fn):
  dataset = tf.data.TFRecordDataset(tf.data.Dataset.list_files("{}\\{}_{}_*.tfrecord".format(args.records_dir,dataSetType, dtype )))
  dataset = dataset.shuffle(buffer_size=1000)
  dataset = dataset.map(parse_fn)
  dataset = dataset.batch(batch_size=32)
  dataset.cache('E:\\trainingcache')
  return dataset

Model: After a lot of playing around with different layers/activation/optimizers/losses, this is what working out the best.

def getTableModel(shape):
    model = tf.keras.Sequential([
        tf.keras.layers.Conv2D(256,3,3, padding='valid',activation='relu', dilation_rate=(1, 1), use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', input_shape= shape),
        tf.keras.layers.Conv2D(128,3,3, activation='relu'),
        tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(256, activation='relu'),
        tf.keras.layers.Dropout(0.5),
        tf.keras.layers.Dense(128, activation='relu'),
        tf.keras.layers.Dense(64, activation='relu'),
        tf.keras.layers.Dense(30, activation='relu', kernel_initializer='normal')
    ])

    optimizer = tf.keras.optimizers.Adam(learning_rate=0.01, amsgrad=True)

    model.compile(loss='categorical_crossentropy',
                optimizer=optimizer,
                metrics=['mse', 'mae','acc'])
    return model

Training:

def train(model, train,  cppath):
    EPOCHS = 1000
    cbs = [PrintDot()]
    checkpointcb = tf.keras.callbacks.ModelCheckpoint(filepath=cppath,
                                                 save_weights_only=True,
                                                 verbose=1, period=100)


    print(model.summary())
    # The patience parameter is the amount of epochs to check for improvement
    early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)
    history = model.fit(train, epochs=EPOCHS, verbose=0, callbacks=[PrintDot(), checkpointcb])

What am i missing or doing wrong ? Because the best accuracy that I get is ~0.7

Output after training and testing:

625/625 [==============================] - 20s 32ms/step - loss: 1620.7100 - mse: 110371661623007769526272.0000 - mae: 133217427456.0000 - acc: 0.7244 test loss, test acc: [1620.709959765625, 1.1037166e+23, 133217430000.0, 0.7244]

Testing 1 prediction:

Prediction:

[8.52919688e+12 2.94164575e+13 1.72934342e+14 6.60441483e+13 0.00000000e+00 0.00000000e+00 0.00000000e+00 8.95260683e+13 1.73240895e+14 1.32049206e+14 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]

Actual label

[-0.6120000000000001, 24.400000000000002, 193.284, 65.60000000000001, 0, 0, 2.8920000000000003, 97.60000000000001, 189.784, 144.0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

2

2 Answers

0
votes

There are many reasons why your model is stuck in a local minimum (if it is). You can try lowering your learning rate from 0.01 to 0.001.

Try plotting your loss/acc curve to see if the model has converged.

Try using global average pooling instead of flatten

Also have you tried using transfer learning

0
votes

Try using a validation set from your training set and monitor its performance over the epochs. It's possible that you are overfitting.