from google.colab import drive
drive.mount('/content/drive')
import os
os.chdir('/content/drive/Shared drives/Тяжелые проекты/ИАД/intro-to-dl-seminars/hw_4_imgs')
%tensorflow_version 2.x
import pandas as pd
import os
import tensorflow as tf
import tensorflow.keras as keras
import numpy as np
from tensorflow.python.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Activation, Dropout, BatchNormalization
from tensorflow.python.keras.layers.advanced_activations import LeakyReLU
print(tf.__version__)
print(keras.__version__)
Проверяем наличие GPU
tf.test.gpu_device_name()
!ls -l
INPUT_DIR = '.'
data_train = np.load(f"{INPUT_DIR}/train-1.npy", allow_pickle=True)
for i in range(2, 5):
t = np.load(f"{INPUT_DIR}/train-{i}.npy", allow_pickle=True)
data_train = np.concatenate([data_train, t])
test = np.load(f"{INPUT_DIR}/test.npy", allow_pickle=True)
h=[]
w=[]
for i in data_train[:,0]:
h_, w_ = i.shape
h.append(h_)
w.append(w_)
h=np.array(h)
w=np.array(w)
np.percentile(h, 99.9), np.percentile(w, 99.9)
99.9% картинок будут иметь размеры менее 143x128px
val_size=0
u=np.unique(data_train[:,1])
NUM_CLASSES=len(u)
char_to_id=dict(zip(u, range(NUM_CLASSES)))
batch_size=32
RANDOM_SEED=42
HEIGHT=150
WIDTH=130
CHANNELS=1
INIT_LR=5e-3
Во время препроцессинга нормализуем картинку и обрежем ее по установленным размерам.
Для аугментации будем увеличивать изначальный размер картинки с последующим обрезанием.
Как показала практика, излишняя аугментация (небольшой поворот) не улучшает качество.
Так же данная модель не переобучается, поэтому обойдемся без валидации.
def train_gen():
for img, label in data_train:
img = img[..., None]
yield img, char_to_id[label]
def preprocess(x, y):
x = tf.image.resize_with_crop_or_pad(x, HEIGHT, WIDTH)
x = x/127.5 - 1
return x, y
def augmentation(x, y):
x = tf.image.resize_with_crop_or_pad(x, HEIGHT + 20, WIDTH + 20)
x = tf.image.random_crop(x, [HEIGHT, WIDTH, CHANNELS])
return x, y
def test_gen():
for img in test:
img = img[..., None]
yield img
def preprocess_test(x):
x = tf.image.resize_with_crop_or_pad(x, HEIGHT, WIDTH)
x = x/127.5 - 1
return x
ds_train = tf.data.Dataset.from_generator(train_gen,
output_types=(tf.float32, tf.int32),
output_shapes=((None,None,1), ())
).map(preprocess, num_parallel_calls=-1).\
map(augmentation, num_parallel_calls=-1).\
prefetch(-1).shuffle(RANDOM_SEED).\
batch(batch_size).repeat()
ds_test = tf.data.Dataset.from_generator(test_gen,
output_types=(tf.float32),
output_shapes=((None,None,1))
).map(preprocess_test, num_parallel_calls=-1).batch(batch_size)
Возьмем модель из домашнего задания №3 и улучшим полученную модель:
model = tf.keras.models.Sequential()
initializer = tf.keras.initializers.lecun_uniform(seed=RANDOM_SEED)
input_shape = (HEIGHT, WIDTH, 1)
img_input = tf.keras.layers.Input(shape=input_shape)
filters = 64
lrelu = 0.1
dropout = 0.2
model.add(Conv2D(filters=filters, padding='same', kernel_size=(3,3), input_shape=input_shape, kernel_initializer=initializer))
model.add(LeakyReLU(lrelu))
model.add(Conv2D(filters=filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(LeakyReLU(lrelu))
model.add(MaxPooling2D(pool_size=(2,2), padding='same'))
model.add(Dropout(dropout))
model.add(Conv2D(filters=2*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(LeakyReLU(lrelu))
model.add(Conv2D(filters=2*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(LeakyReLU(lrelu))
model.add(MaxPooling2D(pool_size=(2,2), padding='same'))
model.add(Dropout(dropout))
model.add(Conv2D(filters=4*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(LeakyReLU(lrelu))
model.add(Conv2D(filters=4*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(LeakyReLU(lrelu))
model.add(MaxPooling2D(pool_size=(2,2), padding='same'))
model.add(Dropout(dropout))
model.add(Conv2D(filters=8*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(LeakyReLU(lrelu))
model.add(Conv2D(filters=8*filters, padding='same', kernel_size=(3,3), kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(LeakyReLU(lrelu))
model.add(MaxPooling2D(pool_size=(2,2), padding='same'))
model.add(Dropout(dropout))
model.add(Flatten())
model.add(Dense(768,kernel_initializer=initializer))
model.add(BatchNormalization())
model.add(LeakyReLU(lrelu))
model.add(Dropout(0.5))
model.add(Dense(NUM_CLASSES, kernel_initializer=initializer))
model.add(Activation("softmax"))
model.compile(
optimizer=keras.optimizers.Adamax(lr=INIT_LR),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.summary()
TAKE=3 # Порядковый номер решения
model_filename = '{0:02d}_kernel_opt_{{0:02d}}.hdf5'.format(TAKE)
predict_filename = '{0:02d}_kernel_opt_{{0:02d}}.csv'.format(TAKE)
class ModelSaveCallback(keras.callbacks.Callback):
def __init__(self, file_name):
super(ModelSaveCallback, self).__init__()
self.file_name = file_name
def on_epoch_end(self, epoch, logs=None):
filename = self.file_name.format(epoch)
print()
keras.models.save_model(self.model, filename)
class ModelPredictCallback(keras.callbacks.Callback):
def __init__(self, file_name):
super(ModelPredictCallback, self).__init__()
self.file_name = file_name
def on_epoch_end(self, epoch, logs=None):
filename = self.file_name.format(epoch)
result = self.model.predict_classes(ds_test, batch_size=None, verbose=1)
predictions=[]
for i in result:
predictions.append(u[i])
df=pd.DataFrame({'Id': range(len(predictions)), 'Category': predictions}, columns=[ 'Id', 'Category'])
df['Id'] += 1
df.to_csv(filename, index=None)
def lr_scheduler(epoch):
return INIT_LR * 0.9 ** epoch
model.fit(ds_train,
epochs=20,
steps_per_epoch=int(data_train.shape[0]/batch_size),
verbose=2,
callbacks=[
keras.callbacks.LearningRateScheduler(lr_scheduler),
ModelSaveCallback(model_filename),
ModelPredictCallback(predict_filename),
],
)
Качество модели улучшалось после каждой эпохе, аналогичный результат замечен и на публичном лидерборде.
Данную модель можно попытаться улучшить следующими способами: