Kaggle competition: Airbus Ship Detection Challenge
<SOS> metric: IntersectionOverUnionObjectSegmentationBeta Kaggle data source: airbus-ship-detection<define_variables>
BATCH_SIZE = 32
EDGE_CROP = 16
GAUSSIAN_NOISE = 0.1
UPSAMPLE_MODE = 'SIMPLE'
NET_SCALING =(1, 1)
 IMG_SCALING =(4, 4)
 VALID_IMG_COUNT = 600
MAX_TRAIN_STEPS = 30
AUGMENT_BRIGHTNESS = False
predictions = [0 if i < 0 else i for i in predictions]<save_to_csv>
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):
labels = label(img)
 if img.ndim > 2:
return [rle_encode(np.sum(labels==k, axis=2)) for k in np.unique(labels[labels>0])]
else:
return [rle_encode(labels==k)for k in np.unique(labels[labels>0])]
def rle_encode(img):

 if np.max(img)< 1e-3:
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)
 channel = 0
for i,mask in enumerate(in_mask_list):
if isinstance(mask, str):
all_masks[:,:] += np.log1p(i+1)* rle_decode(mask)
 return all_masks
output = pd.DataFrame({'datetime': test_data.index,
'count': predictions})
 output.to_csv('submission.csv', index=False )<load_from_csv>
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()
df = pd.read_csv('.. /input/train.csv', parse_dates=[0])
 test = pd.read_csv('.. /input/test.csv', parse_dates=[0] )<rename_columns>
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' )
df.rename(columns={'count': 'rentals'}, inplace=True )<concatenate>
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 )
df = df.append(test, sort=False )<feature_engineering>
train_ids, valid_ids = train_test_split(balanced_train_df,
test_size = 0.3,
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' )
for col in ['rentals', 'registered', 'casual']:
df[col] = np.log(df[col] + 1 )<feature_engineering>
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=[], []
df['year'] = df['datetime'].dt.year
df['month'] = df['datetime'].dt.month
df['day'] = df['datetime'].dt.day
df['dayofweek'] = df['datetime'].dt.dayofweek
df['hour'] = df['datetime'].dt.hour<rename_columns>
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() )
df.set_index('datetime', inplace=True )<sort_values>
%%time
valid_x, valid_y = next(make_image_gen(valid_df, VALID_IMG_COUNT))
print(valid_x.shape, valid_y.shape )
df.sort_index(inplace=True )<feature_engineering>
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 )
df['rolling_temp'] = df['temp'].rolling(4, min_periods=1 ).mean()<split>
gc.collect()
test = df[df['rentals'].isnull() ]
df = df[~df['rentals'].isnull() ]<define_variables>
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()
removed_cols = ['rentals', 'casual', 'registered', 'datetime']
feats = [c for c in df.columns if c not in removed_cols]<split>
def IoU(y_true, y_pred, eps=1e-6):
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)
 def zero_IoU(y_true, y_pred):
return IoU(1-y_true, 1-y_pred)
 def agg_loss(in_gt, in_pred):
return -1e-2 * zero_IoU(in_gt, in_pred)- IoU(in_gt, in_pred)
 seg_model.compile(optimizer=Adam(1e-3, decay=1e-6), loss=agg_loss, metrics=[IoU, zero_IoU, 'binary_accuracy'] )
train, valid = train_test_split(df, random_state=42 )<choose_model_class>
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.2,
patience=1, verbose=1, mode='min',
min_delta=0.0001, cooldown=2, min_lr=1e-7)
 early = EarlyStopping(monitor="val_loss", mode="min", verbose=2,
patience=15)
 callbacks_list = [checkpoint, early, reduceLROnPlat]
rf = RandomForestRegressor(random_state=42, n_estimators=100, n_jobs=-1 )<train_model>
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=10,
validation_data=(valid_x, valid_y),
callbacks=callbacks_list,
workers=1,
max_queue_size = 20,use_multiprocessing=True,verbose=1)]
rf.fit(train[feats], train['rentals'] )<predict_on_test>
seg_model.load_weights(weight_path)
 seg_model.save('seg_model.h5' )
preds = rf.predict(valid[feats] )<compute_test_metric>
pred_y = seg_model.predict(valid_x)
 print(pred_y.shape, pred_y.min() , pred_y.max() , pred_y.mean() )
mean_squared_error(valid['rentals'], preds)**(1/2 )<predict_on_test>
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' )
test['count'] = np.exp(rf.predict(test[feats])) - 1<save_to_csv>
def predict(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]
cur_seg = binary_opening(cur_seg>1e3, np.expand_dims(disk(2), -1))
return cur_seg, c_img
def pred_encode(img):
cur_seg, _ = predict(img)
 cur_rles = rle_encode(cur_seg)
 return [img, cur_rles if len(cur_rles)> 0 else None]
samples = train_df.groupby('grouped_ship_count' ).apply(lambda x: x.sample(1))
fig, m_axs = plt.subplots(samples.shape[0], 3, figsize =(11, samples.shape[0]*4))
[c_ax.axis('off')for c_ax in m_axs.flatten() ]
for(ax1, ax2, ax3), c_img_name in zip(m_axs, samples.ImageId.values):
first_seg, first_img = predict(c_img_name, train_image_dir)
 ax1.imshow(first_img[0])
 ax1.set_title('Image')
 ax2.imshow(first_seg[:, :, 0])
 ax2.set_title('Prediction')
 ground_truth = masks_as_color(masks.query('ImageId=="{}"'.format(c_img_name)) ['EncodedPixels'])
 ax3.imshow(ground_truth)
 ax3.set_title('Ground Truth')
 fig.savefig('predictions.png' )
test[['datetime', 'count']].to_csv('rf1.csv', index=False )<compute_train_metric>
test_paths = np.array(os.listdir(test_image_dir))
print(len(test_paths), 'test images found' )
train, valid = df[df['day'] <= 15], df.query("day > 15")
 rf.fit(train[feats], train['rentals'])
 preds = rf.predict(valid[feats])
 mean_squared_error(valid['rentals'], preds)**(1/2 )<save_to_csv>
%%time
out_pred_rows = []
for c_img_name in tqdm_notebook(test_paths[:30000]):
out_pred_rows += [pred_encode(c_img_name)]
test['count'] = np.exp(rf.predict(test[feats])) - 1
test[['datetime', 'count']].to_csv('rf2.csv', index=False )<train_model>
sub = pd.DataFrame(out_pred_rows)
 sub.columns = ['ImageId', 'EncodedPixels']
sub = sub[sub.EncodedPixels.notnull() ]
sub.head()
<compute_test_metric><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()