Kaggle competition: Bengali.AI Handwritten Grapheme Classification
<SOS> metric: WeightedCategorizationAccuracy Kaggle data source: bengali.ai-handwritten-grapheme-classification<prepare_x_and_y>
NUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)
 train_dataset = get_training_dataset_preview(ordered=True)
 y_train = next(iter(train_dataset.unbatch().map(lambda image, label: label ).batch(NUM_TRAINING_IMAGES)) ).numpy()
print('Number of training images %d' % NUM_TRAINING_IMAGES)
 NUM_VALIDATION_IMAGES = count_data_items(VALIDATION_FILENAMES)
 valid_dataset = get_validation_dataset(ordered=True)
 y_valid = next(iter(valid_dataset.unbatch().map(lambda image, label: label ).batch(NUM_VALIDATION_IMAGES)) ).numpy()
print('Number of validation images %d' % NUM_VALIDATION_IMAGES)
 NUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)
 print('Number of test images %d' % NUM_TEST_IMAGES)
 test_dataset = get_test_dataset(ordered=True )<define_variables>
!pip install '.. /input/kerasefficientnetb3/efficientnet-1.0.0-py3-none-any.whl'
display_batch_of_images(next(iter(train_dataset.unbatch().batch(20))))<define_variables>
HEIGHT = 137
WIDTH = 236
FACTOR = 0.70
HEIGHT_NEW = int(HEIGHT * FACTOR)
 WIDTH_NEW = int(WIDTH * FACTOR)
 CHANNELS = 3
BATCH_SIZE = 16
DIR = '.. /input/bengaliai-cv19'
display_batch_of_images(next(iter(valid_dataset.unbatch().batch(20))))<define_variables>
SIZE = 128
TRAIN = ['/kaggle/input/bengaliai-cv19/train_image_data_0.parquet',
'/kaggle/input/bengaliai-cv19/train_image_data_1.parquet',
'/kaggle/input/bengaliai-cv19/train_image_data_2.parquet',
'/kaggle/input/bengaliai-cv19/train_image_data_3.parquet']
OUT_TRAIN = 'train.zip'
def bbox(img):
rows = np.any(img, axis=1)
 cols = np.any(img, axis=0)
 rmin, rmax = np.where(rows)[0][[0, -1]]
cmin, cmax = np.where(cols)[0][[0, -1]]
return rmin, rmax, cmin, cmax
def crop_resize(img0, size=SIZE, pad=16):
ymin,ymax,xmin,xmax = bbox(img0[5:-5,5:-5] > 80)
 xmin = xmin - 13 if(xmin > 13)else 0
ymin = ymin - 10 if(ymin > 10)else 0
xmax = xmax + 13 if(xmax < WIDTH - 13)else WIDTH
ymax = ymax + 10 if(ymax < HEIGHT - 10)else HEIGHT
img = img0[ymin:ymax,xmin:xmax]
img[img < 28] = 0
lx, ly = xmax-xmin,ymax-ymin
l = max(lx,ly)+ pad
img = np.pad(img, [(( l-ly)//2,),(( l-lx)//2,)], mode='constant')
 return cv2.resize(img,(size,size))
df = pd.read_parquet(TRAIN[0])
 n_imgs = 8
fig, axs = plt.subplots(n_imgs, 2, figsize=(10, 5*n_imgs))
for idx in range(n_imgs):
img0 = 255 - df.iloc[idx, 1:].values.reshape(HEIGHT, WIDTH ).astype(np.uint8)
 img =(img0*(255.0/img0.max())).astype(np.uint8)
 img = crop_resize(img)
 axs[idx,0].imshow(img0)
 axs[idx,0].set_title('Original image')
 axs[idx,0].axis('off')
 axs[idx,1].imshow(img)
 axs[idx,1].set_title('Crop & resize')
 axs[idx,1].axis('off' )
display_batch_of_images(next(iter(test_dataset.unbatch().batch(20))))<choose_model_class>
print(HEIGHT_NEW)
 print(WIDTH_NEW)
 def resize_image(img, WIDTH_NEW, HEIGHT_NEW):
img = 255 - img
img =(img *(255.0 / img.max())).astype(np.uint8)
 img = img.reshape(HEIGHT, WIDTH)
 image_resized = cv2.resize(img,(WIDTH_NEW, HEIGHT_NEW), interpolation = cv2.INTER_AREA)
 return image_resized.reshape(-1 )
def create_model(input_shape, N_CLASSES):
base_model = applications.DenseNet201(weights='imagenet',
include_top=False,
input_shape=input_shape)
 base_model.trainable = False
model = tf.keras.Sequential([
base_model,
layers.GlobalAveragePooling2D() ,
layers.Dense(N_CLASSES, activation='softmax')
 ])
 return model<choose_model_class>
gm_exp = tf.Variable(3.0, dtype = tf.float32)
 def generalized_mean_pool_2d(X):
pool =(tf.reduce_mean(tf.abs(X**(gm_exp)) ,
axis = [1, 2],
keepdims = False)+ 1.e-7)**(1./gm_exp)
 return pool
with strategy.scope() :
model = create_model(( None, None, CHANNELS), N_CLASSES)
 metric_list = ['sparse_categorical_accuracy']
optimizer = optimizers.Adam(lr=WARMUP_LEARNING_RATE)
 model.compile(optimizer=optimizer,
loss = 'sparse_categorical_crossentropy',
metrics=metric_list)
 model.summary()<train_model>
def create_model(input_shape):
input = Input(shape = input_shape)
 x_model = efn.EfficientNetB3(weights = None, include_top = False, input_tensor = input, pooling = None, classes = None)
 for layer in x_model.layers:
layer.trainable = True
lambda_layer = Lambda(generalized_mean_pool_2d)
 lambda_layer.trainable_weights.extend([gm_exp])
 x = lambda_layer(x_model.output)
 grapheme_root = Dense(168, activation = 'softmax', name = 'root' )(x)
 vowel_diacritic = Dense(11, activation = 'softmax', name = 'vowel' )(x)
 consonant_diacritic = Dense(7, activation = 'softmax', name = 'consonant' )(x)
 model = Model(inputs = x_model.input, outputs = [grapheme_root, vowel_diacritic, consonant_diacritic])
 return model
STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE
warmup_history = model.fit(x=get_training_dataset() ,
steps_per_epoch = STEPS_PER_EPOCH,
validation_data = get_validation_dataset() ,
epochs=WARMUP_EPOCHS,
verbose=2 ).history<choose_model_class>
model1 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model2 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model3 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model4 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model5 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model6 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model7 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
model8 = create_model(input_shape =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
LR_START = 0.00000001
LR_MIN = 0.000001
LR_MAX = LEARNING_RATE
LR_RAMPUP_EPOCHS = 3
LR_SUSTAIN_EPOCHS = 0
LR_EXP_DECAY =.8
def lrfn(epoch):
if epoch < LR_RAMPUP_EPOCHS:
lr =(LR_MAX - LR_START)/ LR_RAMPUP_EPOCHS * epoch + LR_START
elif epoch < LR_RAMPUP_EPOCHS + LR_SUSTAIN_EPOCHS:
lr = LR_MAX
else:
lr =(LR_MAX - LR_MIN)* LR_EXP_DECAY**(epoch - LR_RAMPUP_EPOCHS - LR_SUSTAIN_EPOCHS)+ LR_MIN
return lr
rng = [i for i in range(EPOCHS)]
y = [lrfn(x)for x in rng]
sns.set(style='whitegrid')
 fig, ax = plt.subplots(figsize=(20, 6))
plt.plot(rng, y)
 print("Learning rate shcedule: {:.3g} to {:.3g} to {:.3g}".format(y[0], max(y), y[-1]))<choose_model_class>
model1.load_weights('.. /input/kerasefficientnetb3/Train1_model_59.h5')
 model2.load_weights('.. /input/kerasefficientnetb3/Train1_model_66.h5')
 model3.load_weights('.. /input/kerasefficientnetb3/Train1_model_68.h5')
 model4.load_weights('.. /input/mode4weight/model4.h5')
 model5.load_weights('.. /input/models-weights/model5.h5')
 model6.load_weights('.. /input/kerasefficientnetb3/Train1_model_64.h5')
 model7.load_weights('.. /input/kerasefficientnetb3/Train1_model_70.h5')
 model8.load_weights('.. /input/kerasefficientnetb3/Train1_model_57.h5' )
for layer in model.layers:
layer.trainable = True
checkpoint = ModelCheckpoint(model_path, monitor='val_loss', mode='min', save_best_only=True)
 es = EarlyStopping(monitor='val_loss', mode='min', patience=ES_PATIENCE,
restore_best_weights=True, verbose=1)
 lr_callback = LearningRateScheduler(lrfn, verbose=1)
 callback_list = [checkpoint, es, lr_callback]
optimizer = optimizers.Adam(lr=LEARNING_RATE)
 model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=metric_list)
 model.summary()<train_model>
class TestDataGenerator(keras.utils.Sequence):
def __init__(self, X, batch_size = 16, img_size =(512, 512, 3), *args, **kwargs):
self.X = X
self.indices = np.arange(len(self.X))
self.batch_size = batch_size
self.img_size = img_size
def __len__(self):
return int(ceil(len(self.X)/ self.batch_size))
def __getitem__(self, index):
indices = self.indices[index*self.batch_size:(index+1)*self.batch_size]
X = self.__data_generation(indices)
 return X
def __data_generation(self, indices):
X = np.empty(( self.batch_size, *self.img_size))
for i, index in enumerate(indices):
image = self.X[index]
image = np.stack(( image,)*CHANNELS, axis=-1)
 image = image.reshape(-1, HEIGHT_NEW, WIDTH_NEW, CHANNELS)
 X[i,] = image
return X
history = model.fit(x=get_training_dataset() ,
steps_per_epoch=STEPS_PER_EPOCH,
validation_data=get_validation_dataset() ,
callbacks=callback_list,
epochs=EPOCHS,
verbose=2 ).history<predict_on_test>
tgt_cols = ['grapheme_root','vowel_diacritic','consonant_diacritic']
row_ids, targets = [], []
for i in range(0, 4):
test_files = []
df = pd.read_parquet(os.path.join(DIR, 'test_image_data_'+str(i)+'.parquet'))
image_ids = df['image_id'].values
df = df.drop(['image_id'], axis = 1)
 X = []
for image_id, index in zip(image_ids, range(df.shape[0])) :
test_files.append(image_id)
 X.append(resize_image(df.loc[df.index[index]].values, WIDTH_NEW, HEIGHT_NEW))
data_generator_test = TestDataGenerator(X, batch_size = BATCH_SIZE, img_size =(HEIGHT_NEW, WIDTH_NEW, CHANNELS))
preds1 = model1.predict_generator(data_generator_test, verbose = 1)
 preds2 = model2.predict_generator(data_generator_test, verbose = 1)
 preds3 = model3.predict_generator(data_generator_test, verbose = 1)
 preds4 = model4.predict_generator(data_generator_test, verbose = 1)
 preds5 = model5.predict_generator(data_generator_test, verbose = 1)
 preds6 = model6.predict_generator(data_generator_test, verbose = 1)
 preds7 = model7.predict_generator(data_generator_test, verbose = 1)
 preds8 = model8.predict_generator(data_generator_test, verbose = 1)
 for i, image_id in zip(range(len(test_files)) , test_files):
for subi, col in zip(range(len(preds1)) , tgt_cols):
sub_preds1 = preds1[subi]
sub_preds2 = preds2[subi]
sub_preds3 = preds3[subi]
sub_preds4 = preds4[subi]
sub_preds5 = preds5[subi]
sub_preds6 = preds6[subi]
sub_preds7 = preds7[subi]
sub_preds8 = preds8[subi]
row_ids.append(str(image_id)+'_'+col)
 sub_pred_value = np.argmax(( sub_preds1[i] + sub_preds2[i] + sub_preds3[i] + sub_preds4[i] + sub_preds5[i]+sub_preds6[i]+sub_preds7[i]+sub_preds8[i])/ 8)
 targets.append(sub_pred_value)
 del df
gc.collect()
x_train = train_dataset.map(lambda image, label : image)
 train_preds = model.predict(x_train)
 train_preds = np.argmax(train_preds, axis=-1)
 print(classification_report(y_train, train_preds, target_names=CLASSES))<predict_on_test>
submit_df = pd.DataFrame({'row_id':row_ids,'target':targets}, columns = ['row_id','target'])
 submit_df.to_csv('submission.csv', index = False)
 print(submit_df.head(40))
<predict_on_test><EOS> 
model1.save("model1.h5")
 model2.save("model2.h5")
 model3.save("model3.h5")
 model4.save("model4.h5")
 model5.save("model5.h5" )