<jupyter_start><jupyter_text>Chinese Calligraphy Character Recognition  Setup<jupyter_code>!git clone https://github.com/kahxuan/chinese-calligraphy-ocr.git
%cd chinese-calligraphy-ocr
# from google.colab import drive
# drive.mount('/content/drive')
import os
import yaml
import random
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
from tensorflow.keras.preprocessing import image_dataset_from_directory
import matplotlib as mpl
import matplotlib.pyplot as plt
from modules.model import CRModel, load_cr_model

# load config
config_path = 'config.yaml'
with open(config_path) as file:
    config = yaml.safe_load(file)

tf.config.run_functions_eagerly(True)
def load_dataset(data_dir, batch_size, image_size):
    return image_dataset_from_directory(data_dir, 
                                        seed=0,
                                        shuffle=True, 
                                        batch_size=batch_size, 
                                        image_size=image_size, 
                                        label_mode='categorical'
                                        )
    

def show_training_hist(history, fname=None):

    acc = history.history['accuracy']
    val_acc = history.history['val_accuracy']

    loss = history.history['loss']
    val_loss = history.history['val_loss']

    plt.figure(figsize=(16, 4))
    plt.subplot(1, 2, 1)
    plt.plot(acc, label='Training Accuracy')
    plt.plot(val_acc, label='Validation Accuracy')
    plt.legend(loc='lower right')
    plt.ylabel('Accuracy')
    plt.ylim([min(plt.ylim()),1])
    plt.title('Training and Validation Accuracy')

    plt.subplot(1, 2, 2)
    plt.plot(loss, label='Training Loss')
    plt.plot(val_loss, label='Validation Loss')
    plt.legend(loc='upper right')
    plt.ylabel('Cross Entropy')
    plt.ylim([0,2.0])
    plt.title('Training and Validation Loss')
    plt.xlabel('epoch')

    if fname is not None:
    plt.savefig(fname)

    plt.show()
train = load_dataset(config['dataset']['train'], 
                     batch_size=config['model']['batch_size'], 
                     image_size=config['model']['image_size'],
                     )

val = load_dataset(config['dataset']['validation'], 
                     batch_size=config['model']['batch_size'], 
                     image_size=config['model']['image_size'],
                     )

test = load_dataset(config['dataset']['test'], 
                     batch_size=config['model']['batch_size'], 
                     image_size=config['model']['image_size'],
                     )<jupyter_output>Found 15856 files belonging to 100 classes.<jupyter_text>Train<jupyter_code>model = CRModel(num_class=config['dataset']['num_class'])
model.build(input_shape=tuple([None] + config['model']['image_size'] + [3]))

# callback functions
early_stop = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=3, restore_best_weights=True)
rlrop = ReduceLROnPlateau(monitor='val_loss', mode='min', patience=1, factor=0.5, min_lr=1e-5, verbose=1)
if config['train']['optimizer']['name'] == 'adam':
    optimizer = tf.keras.optimizers.Adam(learning_rate=config['train']['optimizer']['lr'])
elif config['train']['optimizer']['name'] == 'rmsprops':
    optimizer = tf.keras.optimizers.RMSprop(learning_rate=config['train']['optimizer']['lr'])
else:
    raise Exception('Invalid optimizer')

model.compile(optimizer=optimizer,
              loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
              metrics=['accuracy']
              )
history = model.fit(train, validation_data=val, epochs=20, callbacks=[early_stop, rlrop])
print('\nTest:')
loss, accuracy = model.evaluate(test)
show_training_hist(history)
# model.save_weights('../drive/MyDrive/CCCR/cccr.h5')<jupyter_output><empty_output><jupyter_text>Evaluation<jupyter_code>weights_path = '../drive/MyDrive/CCCR/cccr.h5'
model = load_cr_model(config['model']['image_size'], weights_path)
# get all predictions
y_true = []
y_pred = []
images = []
data = test.as_numpy_iterator()

for step in range(len(test)):
    X, y = data.next()
    y_true += list(y)
    y_pred += list(model.predict(X))
    images += list(X)

y_true = np.array(y_true)
y_pred = np.array(y_pred)
for k in [1, 3]:
    acc_topk = tf.keras.metrics.top_k_categorical_accuracy(y_true, y_pred, k=k).numpy().mean()
    print('Top {} acc - {}'.format(k, acc_topk))
negative_labs = np.argmax(y_true[np.where(y_pred.argmax(axis=1) != y_true.argmax(axis=1))[0]], axis=1)
df = pd.DataFrame([train.class_names[x] for x in negative_labs], columns=['class'])
df['count'] = 1
df = df.groupby('class').sum()
df['acc'] = 100 - df['count'] / 20 * 100
df[df['count'] > 3].sort_values('acc')
# show misclassfied samples
idx = np.where(y_pred.argmax(axis=1) != y_true.argmax(axis=1))[0]
random.shuffle(idx)
idx = idx[:16]

chinese_font = mpl.font_manager.FontProperties(fname='fonts/heiti.ttf')
plt.figure(figsize=(10, 10))
for i in range(16):
    ax = plt.subplot(4, 4, i + 1)
    plt.imshow(images[idx[i]].astype("uint8"))
    name_pred = train.class_names[np.argmax(y_pred[idx[i], :])]
    name_true = train.class_names[np.argmax(y_true[idx[i], :])]
    title = 'T: {}, P: {}'.format(name_true, name_pred)
    plt.title(title, fontproperties=chinese_font, fontsize=20)
    plt.axis("off")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15139737183046456, 'fraction_numerical': 0.012585600592263557, 'mean_word_length': 3.6626402070750648, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 13, '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': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '315817', 'license': 'MIT', 'n_tokens_mistral': 1866, 'n_tokens_neox': 1769, 'n_words': 299, 'path': 'train.ipynb', 'repo_name': 'kahxuan/chinese-calligraphy-ocr', 'size': '5403'}