Kaggle competition: Airbus Ship Detection Challenge
<SOS> metric: IntersectionOverUnionObjectSegmentationBeta Kaggle data source: airbus-ship-detection<import_modules>
BATCH_SIZE = 48
EDGE_CROP = 16
GAUSSIAN_NOISE = 0.1
UPSAMPLE_MODE = 'SIMPLE'
NET_SCALING =(1, 1)
 IMG_SCALING =(3, 3)
 VALID_IMG_COUNT = 900
MAX_TRAIN_STEPS = 9
MAX_TRAIN_EPOCHS = 99
AUGMENT_BRIGHTNESS = False
from torchvision.models import *<choose_model_class>
montage_rgb = lambda x: np.stack([montage(x[:, :, :, i])for i in range(x.shape[3])], -1)
 ship_dir = '.. /input'
train_image_dir = os.path.join(ship_dir, 'train')
 test_image_dir = os.path.join(ship_dir, 'test')
 def multi_rle_encode(img, **kwargs):

 labels = label(img)
 if img.ndim > 2:
return [rle_encode(np.sum(labels==k, axis=2), **kwargs)for k in np.unique(labels[labels>0])]
else:
return [rle_encode(labels==k, **kwargs)for k in np.unique(labels[labels>0])]
def rle_encode(img, min_max_threshold=1e-3, max_mean_threshold=None):

 if np.max(img)< min_max_threshold:
return ''
if max_mean_threshold and np.mean(img)> max_mean_threshold:
return ''
pixels = img.T.flatten()
pixels = np.concatenate([[0], pixels, [0]])
 runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
runs[1::2] -= runs[::2]
return ' '.join(str(x)for x in runs)
 def rle_decode(mask_rle, shape=(768, 768)) :

 s = mask_rle.split()
starts, lengths = [np.asarray(x, dtype=int)for x in(s[0:][::2], s[1:][::2])]
starts -= 1
ends = starts + lengths
img = np.zeros(shape[0]*shape[1], dtype=np.uint8)
 for lo, hi in zip(starts, ends):
img[lo:hi] = 1
return img.reshape(shape ).T
def masks_as_image(in_mask_list):
all_masks = np.zeros(( 768, 768), dtype = np.uint8)
 for mask in in_mask_list:
if isinstance(mask, str):
all_masks |= rle_decode(mask)
 return all_masks
def masks_as_color(in_mask_list):
all_masks = np.zeros(( 768, 768), dtype = np.float)
 scale = lambda x:(len(in_mask_list)+x+1)/(len(in_mask_list)*2)
 for i,mask in enumerate(in_mask_list):
if isinstance(mask, str):
all_masks[:,:] += scale(i)* rle_decode(mask)
 return all_masks
learn = create_cnn(
 data,
densenet169,
path='.',
metrics=[auc_score],
ps=0.5
)<train_model>
masks = pd.read_csv(os.path.join('.. /input/', 'train_ship_segmentations.csv'))
not_empty = pd.notna(masks.EncodedPixels)
 print(not_empty.sum() , 'masks in', masks[not_empty].ImageId.nunique() , 'images')
 print(( ~not_empty ).sum() , 'empty images in', masks.ImageId.nunique() , 'total images')
 masks.head()
learn.fit_one_cycle(1,3e-2)
 learn.recorder.plot()
learn.recorder.plot_losses()<find_best_params>
fig,(ax1, ax2, ax3, ax4)= plt.subplots(1, 4, figsize =(16, 5))
rle_0 = masks.query('ImageId=="00021ddc3.jpg"')['EncodedPixels']
img_0 = masks_as_image(rle_0)
 ax1.imshow(img_0)
 ax1.set_title('Mask as image')
 rle_1 = multi_rle_encode(img_0)
 img_1 = masks_as_image(rle_1)
 ax2.imshow(img_1)
 ax2.set_title('Re-encoded')
 img_c = masks_as_color(rle_0)
 ax3.imshow(img_c)
 ax3.set_title('Masks in colors')
 img_c = masks_as_color(rle_1)
 ax4.imshow(img_c)
 ax4.set_title('Re-encoded in colors')
 print('Check Decoding->Encoding',
'RLE_0:', len(rle_0), '->',
'RLE_1:', len(rle_1))
print(np.sum(img_0 - img_1), 'error' )
learn.unfreeze()
learn.lr_find()<train_model>
masks['ships'] = masks['EncodedPixels'].map(lambda c_row: 1 if isinstance(c_row, str)else 0)
 unique_img_ids = masks.groupby('ImageId' ).agg({'ships': 'sum'} ).reset_index()
unique_img_ids['has_ship'] = unique_img_ids['ships'].map(lambda x: 1.0 if x>0 else 0.0)
 unique_img_ids['has_ship_vec'] = unique_img_ids['has_ship'].map(lambda x: [x])
 unique_img_ids['file_size_kb'] = unique_img_ids['ImageId'].map(lambda c_img_id:
os.stat(os.path.join(train_image_dir,
c_img_id)).st_size/1024)
 unique_img_ids = unique_img_ids[unique_img_ids['file_size_kb'] > 50]
unique_img_ids['file_size_kb'].hist()
masks.drop(['ships'], axis=1, inplace=True)
 unique_img_ids.sample(7 )
learn.fit_one_cycle(20,slice(1e-4,1e-3))<compute_test_metric>
train_ids, valid_ids = train_test_split(balanced_train_df,
test_size = 0.2,
stratify = balanced_train_df['ships'])
 train_df = pd.merge(masks, train_ids)
 valid_df = pd.merge(masks, valid_ids)
 print(train_df.shape[0], 'training masks')
 print(valid_df.shape[0], 'validation masks' )
preds,y=learn.get_preds()
pred_score=auc_score(preds,y)
 pred_score<compute_test_metric>
def make_image_gen(in_df, batch_size = BATCH_SIZE):
all_batches = list(in_df.groupby('ImageId'))
out_rgb = []
out_mask = []
while True:
np.random.shuffle(all_batches)
 for c_img_id, c_masks in all_batches:
rgb_path = os.path.join(train_image_dir, c_img_id)
 c_img = imread(rgb_path)
 c_mask = np.expand_dims(masks_as_image(c_masks['EncodedPixels'].values), -1)
 if IMG_SCALING is not None:
c_img = c_img[::IMG_SCALING[0], ::IMG_SCALING[1]]
c_mask = c_mask[::IMG_SCALING[0], ::IMG_SCALING[1]]
out_rgb += [c_img]
out_mask += [c_mask]
if len(out_rgb)>=batch_size:
yield np.stack(out_rgb, 0)/255.0, np.stack(out_mask, 0)
 out_rgb, out_mask=[], []
preds,y=learn.TTA()
pred_score_tta=auc_score(preds,y)
 pred_score_tta<predict_on_test>
train_gen = make_image_gen(train_df)
 train_x, train_y = next(train_gen)
 print('x', train_x.shape, train_x.min() , train_x.max())
 print('y', train_y.shape, train_y.min() , train_y.max() )
preds_test,y_test=learn.get_preds(ds_type=DatasetType.Test )<prepare_x_and_y>
%%time
valid_x, valid_y = next(make_image_gen(valid_df, VALID_IMG_COUNT))
print(valid_x.shape, valid_y.shape )
preds_test_tta,y_test_tta=learn.TTA(ds_type=DatasetType.Test )<load_from_csv>
dg_args = dict(featurewise_center = False,
samplewise_center = False,
rotation_range = 45,
width_shift_range = 0.1,
height_shift_range = 0.1,
shear_range = 0.01,
zoom_range = [0.9, 1.25],
horizontal_flip = True,
vertical_flip = True,
fill_mode = 'reflect',
data_format = 'channels_last')
 if AUGMENT_BRIGHTNESS:
dg_args[' brightness_range'] = [0.5, 1.5]
image_gen = ImageDataGenerator(**dg_args)
 if AUGMENT_BRIGHTNESS:
dg_args.pop('brightness_range')
 label_gen = ImageDataGenerator(**dg_args)
 def create_aug_gen(in_gen, seed = None):
np.random.seed(seed if seed is not None else np.random.choice(range(9999)))
 for in_x, in_y in in_gen:
seed = np.random.choice(range(9999))
g_x = image_gen.flow(255*in_x,
batch_size = in_x.shape[0],
seed = seed,
shuffle=True)
 g_y = label_gen.flow(in_y,
batch_size = in_x.shape[0],
seed = seed,
shuffle=True)
 yield next(g_x)/255.0, next(g_y )
sub=pd.read_csv(f'{path}/sample_submission.csv' ).set_index('id')
 sub.head()<data_type_conversions>
gc.collect()
clean_fname=np.vectorize(lambda fname: str(fname ).split('/')[-1].split('.')[0])
 fname_cleaned=clean_fname(data.test_ds.items)
 fname_cleaned=fname_cleaned.astype(str )<save_to_csv>
def upsample_conv(filters, kernel_size, strides, padding):
return layers.Conv2DTranspose(filters, kernel_size, strides=strides, padding=padding)
 def upsample_simple(filters, kernel_size, strides, padding):
return layers.UpSampling2D(strides)
 if UPSAMPLE_MODE=='DECONV':
upsample=upsample_conv
else:
upsample=upsample_simple
input_img = layers.Input(t_x.shape[1:], name = 'RGB_Input')
 pp_in_layer = input_img
if NET_SCALING is not None:
pp_in_layer = layers.AvgPool2D(NET_SCALING )(pp_in_layer)
 pp_in_layer = layers.GaussianNoise(GAUSSIAN_NOISE )(pp_in_layer)
 pp_in_layer = layers.BatchNormalization()(pp_in_layer)
 c1 = layers.Conv2D(8,(3, 3), activation='relu', padding='same' )(pp_in_layer)
 c1 = layers.Conv2D(8,(3, 3), activation='relu', padding='same' )(c1)
 p1 = layers.MaxPooling2D(( 2, 2))(c1)
 c2 = layers.Conv2D(16,(3, 3), activation='relu', padding='same' )(p1)
 c2 = layers.Conv2D(16,(3, 3), activation='relu', padding='same' )(c2)
 p2 = layers.MaxPooling2D(( 2, 2))(c2)
 c3 = layers.Conv2D(32,(3, 3), activation='relu', padding='same' )(p2)
 c3 = layers.Conv2D(32,(3, 3), activation='relu', padding='same' )(c3)
 p3 = layers.MaxPooling2D(( 2, 2))(c3)
 c4 = layers.Conv2D(64,(3, 3), activation='relu', padding='same' )(p3)
 c4 = layers.Conv2D(64,(3, 3), activation='relu', padding='same' )(c4)
 p4 = layers.MaxPooling2D(pool_size=(2, 2))(c4)
 c5 = layers.Conv2D(128,(3, 3), activation='relu', padding='same' )(p4)
 c5 = layers.Conv2D(128,(3, 3), activation='relu', padding='same' )(c5)
 u6 = upsample(64,(2, 2), strides=(2, 2), padding='same' )(c5)
 u6 = layers.concatenate([u6, c4])
 c6 = layers.Conv2D(64,(3, 3), activation='relu', padding='same' )(u6)
 c6 = layers.Conv2D(64,(3, 3), activation='relu', padding='same' )(c6)
 u7 = upsample(32,(2, 2), strides=(2, 2), padding='same' )(c6)
 u7 = layers.concatenate([u7, c3])
 c7 = layers.Conv2D(32,(3, 3), activation='relu', padding='same' )(u7)
 c7 = layers.Conv2D(32,(3, 3), activation='relu', padding='same' )(c7)
 u8 = upsample(16,(2, 2), strides=(2, 2), padding='same' )(c7)
 u8 = layers.concatenate([u8, c2])
 c8 = layers.Conv2D(16,(3, 3), activation='relu', padding='same' )(u8)
 c8 = layers.Conv2D(16,(3, 3), activation='relu', padding='same' )(c8)
 u9 = upsample(8,(2, 2), strides=(2, 2), padding='same' )(c8)
 u9 = layers.concatenate([u9, c1], axis=3)
 c9 = layers.Conv2D(8,(3, 3), activation='relu', padding='same' )(u9)
 c9 = layers.Conv2D(8,(3, 3), activation='relu', padding='same' )(c9)
 d = layers.Conv2D(1,(1, 1), activation='sigmoid' )(c9)
 if NET_SCALING is not None:
d = layers.UpSampling2D(NET_SCALING )(d)
 seg_model = models.Model(inputs=[input_img], outputs=[d])
 seg_model.summary()
sub.loc[fname_cleaned,'label']=to_np(preds_test[:,1])
 sub.to_csv(f'submission_{pred_score}.csv' )<save_to_csv>
def IoU(y_true, y_pred, eps=1e-6):
if np.max(y_true)== 0.0:
return IoU(1-y_true, 1-y_pred)
 intersection = K.sum(y_true * y_pred, axis=[1,2,3])
 union = K.sum(y_true, axis=[1,2,3])+ K.sum(y_pred, axis=[1,2,3])- intersection
return -K.mean(( intersection + eps)/(union + eps), axis=0 )
sub.loc[fname_cleaned,'label']=to_np(preds_test_tta[:,1])
 sub.to_csv(f'submission_{pred_score_tta}.csv' )<import_modules>
weight_path="{}_weights.best.hdf5".format('seg_model')
 checkpoint = ModelCheckpoint(weight_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min', save_weights_only=True)
 reduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.33,
patience=1, verbose=1, mode='min',
min_delta=0.0001, cooldown=0, min_lr=1e-8)
 early = EarlyStopping(monitor="val_loss", mode="min", verbose=2,
patience=20)
 callbacks_list = [checkpoint, early, reduceLROnPlat]
Conv2D, SeparableConv1D, Add, BatchNormalization, Activation, GlobalAveragePooling2D, LeakyReLU, Flatten
Lambda, Multiply, LSTM, Bidirectional, PReLU, MaxPooling1D
print(os.listdir(".. /input")) 
<load_from_csv>
def fit() :
seg_model.compile(optimizer=Adam(1e-3, decay=1e-6), loss=IoU, metrics=['binary_accuracy'])
 step_count = min(MAX_TRAIN_STEPS, train_df.shape[0]//BATCH_SIZE)
 aug_gen = create_aug_gen(make_image_gen(train_df))
loss_history = [seg_model.fit_generator(aug_gen,
steps_per_epoch=step_count,
epochs=MAX_TRAIN_EPOCHS,
validation_data=(valid_x, valid_y),
callbacks=callbacks_list,
workers=1 
)]
return loss_history
while True:
loss_history = fit()
if np.min([mh.history['val_loss'] for mh in loss_history])< -0.2:
break
df_train = pd.read_csv(".. /input/train_labels.csv")
 id_label_map = {k:v for k,v in zip(df_train.id.values, df_train.label.values)}
df_train.head()<define_variables>
seg_model.load_weights(weight_path)
 seg_model.save('seg_model.h5' )
def get_id_from_file_path(file_path):
return file_path.split(os.path.sep)[-1].replace('.tif', '' )<define_variables>
pred_y = seg_model.predict(valid_x)
 print(pred_y.shape, pred_y.min(axis=0 ).max() , pred_y.max(axis=0 ).min() , pred_y.mean() )
labeled_files = glob('.. /input/train/*.tif')
 test_files = glob('.. /input/test/*.tif' )<split>
if IMG_SCALING is not None:
fullres_model = models.Sequential()
fullres_model.add(layers.AvgPool2D(IMG_SCALING, input_shape =(None, None, 3)))
 fullres_model.add(seg_model)
 fullres_model.add(layers.UpSampling2D(IMG_SCALING))
else:
fullres_model = seg_model
fullres_model.save('fullres_model.h5' )
train, val = train_test_split(labeled_files, test_size=0.1, random_state=101010 )<choose_model_class>
def raw_prediction(img, path=test_image_dir):
c_img = imread(os.path.join(path, c_img_name))
c_img = np.expand_dims(c_img, 0)/255.0
cur_seg = fullres_model.predict(c_img)[0]
return cur_seg, c_img[0]
def smooth(cur_seg):
return binary_opening(cur_seg>0.99, np.expand_dims(disk(2), -1))
def predict(img, path=test_image_dir):
cur_seg, c_img = raw_prediction(img, path=path)
 return smooth(cur_seg), c_img
samples = valid_df.groupby('ships' ).apply(lambda x: x.sample(1))
fig, m_axs = plt.subplots(samples.shape[0], 4, figsize =(15, samples.shape[0]*4))
[c_ax.axis('off')for c_ax in m_axs.flatten() ]
for(ax1, ax2, ax3, ax4), c_img_name in zip(m_axs, samples.ImageId.values):
first_seg, first_img = raw_prediction(c_img_name, train_image_dir)
 ax1.imshow(first_img)
 ax1.set_title('Image: ' + c_img_name)
 ax2.imshow(first_seg[:, :, 0], cmap=get_cmap('jet'))
ax2.set_title('Model Prediction')
 reencoded = masks_as_color(multi_rle_encode(smooth(first_seg)[:, :, 0]))
ax3.imshow(reencoded)
 ax3.set_title('Prediction Masks')
 ground_truth = masks_as_color(masks.query('ImageId=="{}"'.format(c_img_name)) ['EncodedPixels'])
 ax4.imshow(ground_truth)
 ax4.set_title('Ground Truth')
 fig.savefig('validation.png' )
def get_model_classif_nasnet() :
inputs = Input(( 96, 96, 3))
base_model = NASNetMobile(include_top=False, input_shape=(96, 96, 3))
x = base_model(inputs)
 out1 = GlobalMaxPooling2D()(x)
 out2 = GlobalAveragePooling2D()(x)
 out3 = Flatten()(x)
 out = Concatenate(axis=-1 )([out1, out2, out3])
 out = Dropout(0.5 )(out)
 out = Dense(1, activation="sigmoid", name="3_" )(out)
 model = Model(inputs, out)
 model.compile(optimizer=Adam(0.0001), loss=binary_crossentropy, metrics=['acc'])
 model.summary()
return model<find_best_params>
test_paths = np.array(os.listdir(test_image_dir))
print(len(test_paths), 'test images found' )
model = get_model_classif_nasnet()<train_model>
def pred_encode(img, **kwargs):
cur_seg, _ = predict(img)
 cur_rles = multi_rle_encode(cur_seg, **kwargs)
 return [[img, rle] for rle in cur_rles if rle is not None]
out_pred_rows = []
for c_img_name in tqdm_notebook(test_paths[:30000]):
out_pred_rows += pred_encode(c_img_name, min_max_threshold=1.0 )
batch_size=32
h5_path = "model.h5"
checkpoint = ModelCheckpoint(h5_path, monitor='val_acc', verbose=1, save_best_only=True, mode='max')
 history = model.fit_generator(
 data_gen(train, id_label_map, batch_size, augment=True),
validation_data=data_gen(val, id_label_map, batch_size),
epochs=2, verbose=1,
callbacks=[checkpoint],
steps_per_epoch=len(train)// batch_size,
validation_steps=len(val)// batch_size)
 batch_size=64
history = model.fit_generator(
 data_gen(train, id_label_map, batch_size, augment=True),
validation_data=data_gen(val, id_label_map, batch_size),
epochs=6, verbose=1,
callbacks=[checkpoint],
steps_per_epoch=len(train)// batch_size,
validation_steps=len(val)// batch_size)
 model.load_weights(h5_path )<define_variables>
sub = pd.DataFrame(out_pred_rows)
 sub.columns = ['ImageId', 'EncodedPixels']
sub = sub[sub.EncodedPixels.notnull() ]
sub.head()
<predict_on_test><EOS> 
sub1 = pd.read_csv('.. /input/sample_submission.csv')
 sub1 = pd.DataFrame(np.setdiff1d(sub1['ImageId'].unique() , sub['ImageId'].unique() , assume_unique=True), columns=['ImageId'])
 sub1['EncodedPixels'] = None
print(len(sub1), len(sub))
sub = pd.concat([sub, sub1])
 print(len(sub))
sub.to_csv('submission.csv', index=False)
 sub.head()