<jupyter_start><jupyter_text>Download the pretrained Inception v3 model, with its weights. We need to adjust a few parameters:- input shape of the vector passed as input to the model, in our case are images of 150*150 pixels in greyscale (1 channel) so 150,150,1- include_top=False indicates we want will replace the last layers of the models in order to have a different output from this model- weights=None doesn't load any weights, just the network architectureLater we load the weights from a specific checkpoint (inception_v2.h5) and "Freeze" the weights og all layers, so that they will not bechanged during the training.We retrieve a reference to the last layer of this model that we will keep (we won't use any further layer of the original InceptionV3, but willprovide different layers to adjust the output).<jupyter_code>def download_inception_v3_and_load_weights(input_layer):
    weights_url = "https://storage.googleapis.com/mledu-datasets/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5"
    weights_file = "inception_v3.h5"
    urllib.request.urlretrieve(weights_url, weights_file)

    # Instantiate the model
    pre_trained_model = InceptionV3(input_shape=(300, 300, 3),
                                    include_top=False,
                                    weights=None)

    # load pre-trained weights
    pre_trained_model.load_weights(weights_file)

    # freeze the layers
    for layer in pre_trained_model.layers:
        layer.trainable = False

    #pre_trained_model.summary()

    last_layer = pre_trained_model.get_layer('mixed7')
    #print("input layer shape:", pre_trained_model.input.shape)
    print('last layer output shape: ', last_layer.output_shape)
    last_output = last_layer.output
    return pre_trained_model.input, last_output<jupyter_output><empty_output><jupyter_text>We adjust the model by adding some more layers after the 'mixed7' layer:- we flatten the output of mixed7 layer into a single dimension vector- we add a dense layer with 1024 nodes- we add 7 softmax classification layers, 4 for the numbers and 3 for the letters in the license plateand then we compile the model choosing the optimizer, loss and metric to track during training.<jupyter_code>#def my_loss(y_true, y_pred):
from keras.optimizers import rmsprop_v2

def prepare_model(input_layer):
    pretrained_input, last_output = download_inception_v3_and_load_weights(input_layer)

    # Flatten the output layer to 1 dimension
    x = layers.Flatten()(last_output)

    # Add a fully connected layer with 1,024 hidden units and ReLU activation
    #x = layers.Dense(512, activation='relu', name="last_dense", trainable=True)(x)

    ## We will add 7 sibling output layers, one for each character we want to recognize
    ## EU license plates have 4 numbers (0 to 9) and 3 letters without any vowels
    ## but anyway each node will be equal, producing a number or a letter
    output_number1 = layers.Dense(31, activation="softmax", name="output_number1")(x)
    output_number2 = layers.Dense(31, activation="softmax", name="output_number2")(x)
    output_number3 = layers.Dense(31, activation="softmax", name="output_number3")(x)
    output_number4 = layers.Dense(31, activation="softmax", name="output_number4")(x)
    output_letter1 = layers.Dense(31, activation="softmax", name="output_letter1")(x)
    output_letter2 = layers.Dense(31, activation="softmax", name="output_letter2")(x)
    output_letter3 = layers.Dense(31, activation="softmax", name="output_letter3")(x)
    output = layers.Concatenate()([output_number1, output_number2, output_number3, output_number4,
                                   output_letter1, output_letter2, output_letter3])
    model = Model(inputs=pretrained_input,
                  outputs=output)
    #optimizer = keras.optimizer_v2.gradient_descent.SGD(learning_rate=0.01)
    optimizer = keras.optimizers.RMSprop(learning_rate=0.1)
    model.compile(optimizer=optimizer,
                  loss='categorical_crossentropy',
                  metrics='accuracy')

    #output = layers.Dense(218, activation="softmax", name="output", trainable=True)(x)
    #model = Model(inputs=pretrained_input, outputs=output)
    #optimizer = keras.optimizer_v2.gradient_descent.SGD(learning_rate=0.01)
    #model.compile(optimizer=optimizer,
    #              loss='categorical_crossentropy',
    #              metrics=['accuracy','categorical_accuracy'])

    model.summary()
    print("input layer shape:", pretrained_input.shape)
    print('last layer output shape: ', last_output.shape)

    return model<jupyter_output><empty_output><jupyter_text>We prepare the labels of the dataset<jupyter_code>import numpy as np
import glob
import cv2
import numpy
import common


def code_to_vec(p, code):
    def char_to_vec(c):
        y = numpy.zeros((len(common.CHARS),))
        y[common.CHARS.index(c)] = 1.0
        return y

    c = numpy.vstack([char_to_vec(c) for c in code])
    #print("code_to_vec --> code:",code," produced vector:",c)

    #return numpy.concatenate([[1. if p else 0], c.flatten()])
    return c.flatten()


def read_data(img_glob):
    for fname in sorted(glob.glob(img_glob)):
        #print("fname", fname)
        im = cv2.imread(fname)[:, :, 0].astype(numpy.float32) / 255.
        #im = np.concatenate((im,)*3, axis=-1)
        code = fname.split("/")[1][9:16]
        #print("code:", code)
        p = fname.split("/")[1][17] == '1'
        if p:
            vector = code_to_vec(p, code)
            #print("vector:", vector)
            yield im, vector


def unzip(b):
    xs, ys = zip(*b)
    xs = numpy.array(xs)
    ys = numpy.array(ys)
    return xs, ys


def prepare_dataset():
    test_xs, test_ys = unzip(list(read_data("test/*.png"))[:50])

    # inception expects 3 channels for color images but our plates are greyscale
    # so we'll stack the image 3 times with itself
    test_xs = np.stack((test_xs,) * 3, axis=-1)

    print("test_ys:", test_ys)
    return test_xs, test_ys<jupyter_output><empty_output><jupyter_text>And now we train the model<jupyter_code>model = prepare_model(layers.Input(shape=(300, 300, 3)))

images, labels = prepare_dataset()

print("images.shape:", images.shape)
print("labels[0]", labels[0])
print("labels.shape:", labels.shape)

# train the model
history = model.fit(
    images,
    labels,
    epochs=500,
    batch_size=60,
    verbose=1)

model.save("last_trained_inceptionv3_apnr.h5")

import matplotlib.pyplot as plt

# Plot the results
acc = history.history['accuracy']
loss = history.history['loss']
#val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'r', label='Training accuracy')
plt.plot(epochs, loss, 'b', label='Loss')
plt.title('Training and validation accuracy')
plt.legend(loc=0)
plt.figure()

plt.show()<jupyter_output>last layer output shape:  (None, 17, 17, 768)
{'fraction_non_alphanumeric': 0.10931115002918856, 'fraction_numerical': 0.02291301809690601, 'mean_word_length': 4.016837481698389, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '194451', 'license': 'MIT', 'n_tokens_mistral': 2265, 'n_tokens_neox': 2140, 'n_words': 584, 'path': 'inceptionv3_apnr.ipynb', 'repo_name': 'guillempg/matriculas', 'size': '6852'}