web-dev-qa-db-fra.com

Comment utiliser l'exemple d'OCR Keras?

J'ai trouvé examples/image_ocr.py qui semble pour OCR. Il devrait donc être possible de donner une image au modèle et de recevoir du texte. Cependant, je ne sais pas comment faire. Comment nourrir le modèle avec une nouvelle image? Quel type de prétraitement est nécessaire? 

Ce que j'ai fait

Installer les dépendances:

  • Installer cairocffi : Sudo apt-get install python-cairocffi
  • Installez editdistance: Sudo -H pip install editdistance
  • Modifiez train pour renvoyer le modèle et enregistrez le modèle formé.
  • Exécutez le script pour former le modèle.

Maintenant, j'ai un model.h5. Et après?

Voir https://github.com/MartinThoma/algorithms/tree/master/ML/ocr/keras pour le code actuel. Je sais comment charger le modèle (voir ci-dessous) et cela semble fonctionner. Le problème est que je ne sais pas comment alimenter de nouvelles numérisations d'images avec du texte dans le modèle.

Questions connexes

  • Qu'est-ce que la CCT? Classification temporelle connexionniste ?
  • Existe-t-il des algorithmes permettant de détecter de manière fiable la rotation d'un document?
  • Existe-t-il des algorithmes détectant de manière fiable les lignes/blocs de texte/tableaux/images (permettant ainsi une segmentation raisonnable)? Je suppose que la détection des contours avec lissage et histogrammes par lignes fonctionne déjà assez bien pour cela?

Ce que j'ai essayé

#!/usr/bin/env python

from keras import backend as K
import keras
from keras.models import load_model
import os

from image_ocr import ctc_lambda_func, create_model, TextImageGenerator
from keras.layers import Lambda
from keras.utils.data_utils import get_file
import scipy.ndimage
import numpy

img_h = 64
img_w = 512
pool_size = 2
words_per_Epoch = 16000
val_split = 0.2
val_words = int(words_per_Epoch * (val_split))
if K.image_data_format() == 'channels_first':
    input_shape = (1, img_w, img_h)
else:
    input_shape = (img_w, img_h, 1)

fdir = os.path.dirname(get_file('wordlists.tgz',
                                Origin='http://www.mythic-ai.com/datasets/wordlists.tgz', untar=True))

img_gen = TextImageGenerator(monogram_file=os.path.join(fdir, 'wordlist_mono_clean.txt'),
                             bigram_file=os.path.join(fdir, 'wordlist_bi_clean.txt'),
                             minibatch_size=32,
                             img_w=img_w,
                             img_h=img_h,
                             downsample_factor=(pool_size ** 2),
                             val_split=words_per_Epoch - val_words
                             )
print("Input shape: {}".format(input_shape))
model, _, _ = create_model(input_shape, img_gen, pool_size, img_w, img_h)

model.load_weights("my_model.h5")

x = scipy.ndimage.imread('example.png', mode='L').transpose()
x = x.reshape(x.shape + (1,))

# Does not work
print(model.predict(x))

cela donne

2017-07-05 22:07:58.695665: I tensorflow/core/common_runtime/gpu/gpu_device.cc:996] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN Black, pci bus id: 0000:01:00.0)
Traceback (most recent call last):
  File "eval_example.py", line 45, in <module>
    print(model.predict(x))
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1567, in predict
    check_batch_axis=False)
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 106, in _standardize_input_data
    'Found: array with shape ' + str(data.shape))
ValueError: The model expects 4 arrays, but only received one array. Found: array with shape (512, 64, 1)
18
Martin Thoma

Ici, vous avez créé un modèle qui nécessite 4 entrées:

model = Model(inputs=[input_data, labels, input_length, label_length], outputs=loss_out)

En revanche, votre tentative de prédiction consiste à ne charger qu'une image.
D'où le message: Le modèle attend 4 tableaux, mais n'a reçu qu'un tableau

À partir de votre code, les entrées nécessaires sont les suivantes: 

input_data = Input(name='the_input', shape=input_shape, dtype='float32')
labels = Input(name='the_labels', shape=[img_gen.absolute_max_string_len],dtype='float32')
input_length = Input(name='input_length', shape=[1], dtype='int64')
label_length = Input(name='label_length', shape=[1], dtype='int64')

Le code d'origine et votre formation fonctionnent car ils utilisent la variable TextImageGenerator. Ce générateur se charge de vous fournir les quatre entrées nécessaires pour le modèle. 

Donc, ce que vous devez faire est de prédire en utilisant le générateur. Comme vous disposez de la méthode fit_generator() pour vous entraîner au générateur, vous disposez également de la méthode predict_generator () pour la prédiction avec le générateur. 


Maintenant, pour une réponse complète et une solution, je devrais étudier votre générateur et voir comment il fonctionne (ce qui me prendrait un peu de temps). Mais maintenant que vous savez ce qu'il faut faire, vous pouvez probablement le comprendre. 

Vous pouvez utiliser le générateur tel quel et prévoir probablement beaucoup de données, ou vous pouvez essayer de répliquer un générateur qui ne produira qu'une ou plusieurs images avec les étiquettes, la longueur et la longueur d'étiquette nécessaires. 

Ou peut-être, si possible, créez simplement les 3 tableaux restants manuellement, mais en vous assurant qu'ils ont les mêmes formes (à l'exception du premier, qui est la taille du lot) que les sorties du générateur. 

La seule chose que vous devez affirmer, cependant, est la suivante: disposez de 4 tableaux ayant les mêmes formes que les sorties du générateur, à l’exception de la première dimension. 

4
Daniel Möller

Eh bien, je vais essayer de répondre à tout ce que vous avez demandé ici:

Comme indiqué dans le code OCR, Keras ne prend pas en charge les pertes avec plusieurs paramètres. Il a donc calculé la perte NN dans une couche lambda. Qu'est-ce que cela signifie dans ce cas?

Le réseau de neurones peut sembler déroutant car il utilise 4 entrées ([input_data, labels, input_length, label_length]) et loss_out en sortie. Outre input_data, tout le reste est une information utilisée uniquement pour calculer la perte, cela signifie qu'elle n'est utilisée que pour la formation. Nous désirons quelque chose comme à la ligne 468 du code original:

Model(inputs=input_data, outputs=y_pred).summary()

ce qui signifie "j'ai une image en entrée, dites-moi s'il vous plaît ce qui est écrit ici". Alors, comment y arriver?

1) Conservez le code de formation original tel quel, faites la formation normalement;

2) Après l’entraînement, enregistrez ce modèle Model(inputs=input_data, outputs=y_pred)dans un fichier .h5 qui sera chargé où vous voulez;

3) Faites la prédiction: si vous regardez le code, l’image d’entrée est inversée et traduite, vous pouvez donc utiliser ce code pour simplifier:

from scipy.misc import imread, imresize
#use width and height from your neural network here.

def load_for_nn(img_file):
    image = imread(img_file, flatten=True)
    image = imresize(image,(height, width))
    image = image.T

    images = np.ones((1,width,height)) #change 1 to any number of images you want to predict, here I just want to predict one
    images[0] = image
    images = images[:,:,:,np.newaxis]
    images /= 255

    return images

Avec l'image chargée, faisons la prédiction:

def predict_image(image_path): #insert the path of your image 
    image = load_for_nn(image_path) #load from the snippet code
    raw_Word = model.predict(image) #do the prediction with the neural network
    final_Word = decode_output(raw_Word)[0] #the output of our neural network is only numbers. Use decode_output from image_ocr.py to get the desirable string.
    return final_Word

Cela devrait suffire. D'après mon expérience, les images utilisées lors de la formation ne sont pas suffisantes pour faire de bonnes prédictions. Je publierai un code à l'aide d'autres jeux de données qui amélioreront mes résultats ultérieurement si nécessaire.

Répondre aux questions liées:

C'est une technique utilisée pour améliorer la classification des séquences. Le document original prouve qu'il améliore les résultats de la découverte de ce qui est dit en audio. Dans ce cas, c'est une séquence de caractères. L'explication est un peu compliquée mais vous pouvez en trouver un bon ici.

  • Existe-t-il des algorithmes permettant de détecter de manière fiable la rotation d'un document?

Je ne suis pas sûr, mais vous pouvez jeter un coup d'œil au mécanisme d'attention dans les réseaux de neurones. Je n'ai plus aucun lien, mais je sais que cela pourrait être le cas.

  • Existe-t-il des algorithmes détectant de manière fiable les lignes/blocs de texte/tableaux/images (permettant ainsi une segmentation raisonnable)? Je suppose que la détection des contours avec lissage et histogrammes par lignes fonctionne déjà assez bien pour cela?

OpenCV implémente les régions extrêmes à stabilité maximale (connues sous le nom de MSER). J'aime beaucoup les résultats de cet algorithme, il est rapide et était assez bon pour moi quand j'en avais besoin. 

Comme je l'ai déjà dit, je publierai bientôt un code. Lorsque je le ferai, je modifierai la question avec le référentiel, mais j'estime que les informations fournies sont suffisantes pour que l'exemple soit exécuté.

4
Claudio

Maintenant, j'ai un model.h5. Et après?

Tout d'abord, je dois dire que le model.h5 contient les poids de votre réseau. Si vous souhaitez enregistrer le architecture de votre réseau, vous devez également l'enregistrer sous la forme d'une json comme dans l'exemple suivant:

model_json = model_json = model.to_json()
with open("model_Arch.json", "w") as json_file:
    json_file.write(model_json)

Maintenant, une fois que vous avez votre modèle et ses poids, vous pouvez les charger à la demande en procédant comme suit:

json_file = open('model_Arch.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
# if you already have a loaded model and dont need to save start from here
loaded_model.load_weights("model.h5")    
# compile loaded model with certain specifications
sgd = SGD(lr=0.01)
loaded_model.compile(loss="binary_crossentropy", optimizer=sgd, metrics=["accuracy"])

Ensuite, avec ce loaded_module, vous pouvez continuer à prédire la classification de certaines entrées comme ceci:

prediction = loaded_model.predict(some_input, batch_size=20, verbose=0)

Ce qui retournera le classement de cette entrée.

À propos des questions secondaires:

  1. CTC semble être un terme qu’ils définissent dans l’article que vous avez cité, dont il est extrait:

Dans ce qui suit, nous nous référons à la tâche d'étiquetage un - séquences de données segmentées en tant que classification temporelle (Kadous, 2002), et à notre utilisation des RNN à cette fin. poser comme classification temporelle connexionniste (CTC).

  1. Pour compenser la rotation d'un document, d'images ou similaire, vous pouvez générer davantage de données de votre document actuel en appliquant de telles transformations (consultez this billet de blog qui explique une façon de le faire), ou vous pouvez utiliser une approche Réseau de neurones convolutifs , qui correspond également à ce que cet exemple Keras que vous utilisez, comme nous pouvons le constater à partir de cela git :

Cet exemple utilise une pile convolutional suivie d'une pile récurrente et une fonction logloss CTC pour effectuer la reconnaissance optique de caractères d'images de texte générées. 

Vous pouvez vérifier this tutoriel qui est lié à ce que vous faites et où ils expliquent également davantage les réseaux de neurones convolutionnels.

  1. C'est une question générale, mais pour détecter les lignes, vous pouvez utiliser le Transformation de ligne de Hough , ou aussi Détection de bord Canny pourrait être une bonne option.

Edit: L'erreur que vous obtenez est due au fait qu'il est attendu plus de paramètres au lieu de 1, à partir des keras docs nous pouvons voir:

predict(self, x, batch_size=32, verbose=0)

Lève ValueError: en cas de discordance entre les données d'entrée fournies et les attentes du modèle, ou si un modèle avec état reçoit un nombre d'échantillons différent de la taille du lot.

2
DarkCygnus