Kaggle competition: Global Wheat Detection
<SOS> metric: custom metric Kaggle data source: global-wheat-detection<import_modules>
def load_dataset(root):
csv = pd.read_csv(os.path.join(root, "train.csv"))
data = {}
for i in csv.index:
key = csv["image_id"][i]
bbox = json.loads(csv["bbox"][i])
 bbox = [bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3], 0.0]
if key in data:
data[key].append(bbox)
 else:
data[key] = [bbox]
return sorted(
 [(k, os.path.join(root, "train", k + ".jpg"), v)for k, v in data.items() ],
key=lambda x: x[0] 
)
 def load_image(path):
with open(path, "rb")as f:
buf = f.read()
return mx.image.imdecode(buf)
 def get_batches(dataset, batch_size, width=512, height=512, net=None, ctx=mx.cpu()):
batches = len(dataset)// batch_size
sampler = Sampler(dataset, width, height, net)
 stack_fn = [gcv.data.batchify.Stack() ]
pad_fn = [gcv.data.batchify.Pad(pad_val=-1)]
if net is None:
batchify_fn = gcv.data.batchify.Tuple(*(stack_fn + pad_fn))
else:
batchify_fn = gcv.data.batchify.Tuple(*(stack_fn * 6 + pad_fn))
with Pool(cpu_count() * 2)as p:
for i in range(batches):
start = i * batch_size
samples = p.map(sampler, range(start, start + batch_size))
batch = batchify_fn(samples)
 yield [x.as_in_context(ctx)for x in batch]
def gauss_blur(image, level):
return cv2.blur(image,(level * 2 + 1, level * 2 + 1))
def gauss_noise(image):
for i in range(image.shape[2]):
c = image[:, :, i]
diff = 255 - c.max() ;
noise = np.random.normal(0, random.randint(1, 6), c.shape)
 noise =(noise - noise.min())/(noise.max() - noise.min())
 noise = diff * noise
image[:, :, i] = c + noise.astype(np.uint8)
 return image
class YOLO3TrainTransform:
def __init__(self, width, height, net, mean=(0.485, 0.456, 0.406),
std=(0.229, 0.224, 0.225), **kwargs):
self._width = width
self._height = height
self._mean = mean
self._std = std
self._fake_x = mx.nd.zeros(( 1, 3, height, width))
net = copy.deepcopy(net)
 net.collect_params().reset_ctx(None)
 with mx.autograd.train_mode() :
_, self._anchors, self._offsets, self._feat_maps, _, _, _, _ = net(self._fake_x)
 self._target_generator = gcv.model_zoo.yolo.yolo_target.YOLOV3PrefetchTargetGenerator(
 num_class=len(net.classes), **kwargs)
 def __call__(self, img, label):
if np.random.uniform(0, 1)> 0.5:
img, expand = gcv.data.transforms.image.random_expand(img, max_ratio=1.5, fill=114, keep_ratio=False)
 bbox = gcv.data.transforms.bbox.translate(label, x_offset=expand[0], y_offset=expand[1])
 else:
img, bbox = img, label
h, w, _ = img.shape
bbox, crop = gcv.data.transforms.experimental.bbox.random_crop_with_constraints(bbox,(w, h))
x0, y0, w, h = crop
img = mx.image.fixed_crop(img, x0, y0, w, h)
 h, w, _ = img.shape
interp = np.random.randint(0, 5)
 img = gcv.data.transforms.image.imresize(img, self._width, self._height, interp=interp)
 bbox = gcv.data.transforms.bbox.resize(bbox,(w, h),(self._width, self._height))
h, w, _ = img.shape
img, flips = gcv.data.transforms.image.random_flip(img, px=0.5, py=0.5)
 bbox = gcv.data.transforms.bbox.flip(bbox,(w, h), flip_x=flips[0], flip_y=flips[1])
 img = gcv.data.transforms.experimental.image.random_color_distort(img)
 img = mx.nd.image.to_tensor(img)
 img = mx.nd.image.normalize(img, mean=self._mean, std=self._std)
 gt_bboxes = mx.nd.array(bbox[np.newaxis, :, :4])
 gt_ids = mx.nd.array(bbox[np.newaxis, :, 4:5])
 gt_mixratio = mx.nd.array(bbox[np.newaxis, :, -1:])
 objectness, center_targets, scale_targets, weights, class_targets = self._target_generator(
 self._fake_x, self._feat_maps, self._anchors, self._offsets,
gt_bboxes, gt_ids, gt_mixratio)
 return(img, objectness[0], center_targets[0], scale_targets[0], weights[0],
class_targets[0], gt_bboxes[0])
 class Sampler:
def __init__(self, dataset, width, height, net=None, **kwargs):
self._dataset = dataset
if net is None:
self._training_mode = False
self._transform = gcv.data.transforms.presets.yolo.YOLO3DefaultValTransform(width, height, **kwargs)
 else:
self._training_mode = True
self._transform = YOLO3TrainTransform(width, height, net, **kwargs)
 def __call__(self, idx):
if self._training_mode:
raw, bboxes = self._load_mixup(idx)
 raw = raw.asnumpy()
blur = random.randint(0, 3)
 if blur > 0:
raw = gauss_blur(raw, blur)
 raw = gauss_noise(raw)
 raw = mx.nd.array(raw)
 else:
raw = load_image(self._dataset[idx][1])
 bboxes = np.array(self._dataset[idx][2])
 res = self._transform(raw, bboxes)
 return [mx.nd.array(x)for x in res]
def _load_mixup(self, idx1):
r = random.gauss(0.5, 0.5 / 1.96)
 if r > 0.0:
raw1 = load_image(self._dataset[idx1][1])
 bboxes1 = np.array(self._dataset[idx1][2])
 if r >= 1.0:
return raw1, np.hstack([bboxes1, np.full(( bboxes1.shape[0], 1), 1.0)])
 idx2 = random.randint(0, len(self._dataset)- 1)
 raw2 = load_image(self._dataset[idx2][1])
 bboxes2 = np.array(self._dataset[idx2][2])
 if r <= 0.0:
return raw2, np.hstack([bboxes2, np.full(( bboxes2.shape[0], 1), 1.0)])
 h = max(raw1.shape[0], raw2.shape[0])
 w = max(raw1.shape[1], raw2.shape[1])
 mix_raw = mx.nd.zeros(shape=(h, w, 3), dtype="float32")
 mix_raw[:raw1.shape[0], :raw1.shape[1], :] += raw1.astype("float32")* r
mix_raw[:raw2.shape[0], :raw2.shape[1], :] += raw2.astype("float32")*(1.0 - r)
 mix_bboxes = np.vstack([
np.hstack([bboxes1, np.full(( bboxes1.shape[0], 1), r)]),
np.hstack([bboxes2, np.full(( bboxes2.shape[0], 1), 1.0 - r)])
 ])
 return mix_raw.astype("uint8"), mix_bboxes
import numpy as np
import pandas as pd
import copy
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import FunctionTransformer, LabelEncoder
from sklearn.linear_model import LogisticRegressionCV<find_best_model_class>
def load_model(path, ctx=mx.cpu()):
net = gcv.model_zoo.yolo3_darknet53_custom(["wheat"], pretrained_base=False)
 net.set_nms(post_nms=150)
 net.load_parameters(path, ctx=ctx)
 return net
<load_from_csv><EOS> 
max_epochs = 6
learning_rate = 0.001
batch_size = 8
img_s = 512
threshold = 0.1
context = mx.gpu()
print("Loading model...")
 model = load_model("/kaggle/input/global-wheat-detection-yolo-darknet-weights/global-wheat-yolo3-darknet53.params", ctx=context)
 print("Loading test images...")
 test_images = [ 
(os.path.join(dirname, filename), os.path.splitext(filename)[0])
 for dirname, _, filenames in os.walk('/kaggle/input/global-wheat-detection/test')for filename in filenames
]
print("Pseudo labaling...")
 pseudo_set = []
for path, image_id in test_images:
print(path)
 raw = load_image(path)
 x, _ = gcv.data.transforms.presets.yolo.transform_test(raw, short=img_s)
 classes, scores, bboxes = model(x.as_in_context(context))
bboxes[0, :, 0::2] =(bboxes[0, :, 0::2] / x.shape[3] ).clip(0.0, 1.0)* raw.shape[1]
bboxes[0, :, 1::2] =(bboxes[0, :, 1::2] / x.shape[2] ).clip(0.0, 1.0)* raw.shape[0]
label = [
[round(x)for x in bboxes[0, i].asnumpy().tolist() ] + [0.0] for i in range(classes.shape[1])
 if model.classes[int(classes[0, i].asscalar())] == "wheat" and scores[0, i].asscalar() > threshold
]
if len(label)> 0:
pseudo_set.append(( image_id, path, label))
print("Loading training set...")
 dataset = load_dataset("/kaggle/input/global-wheat-detection")
 split = int(len(dataset)* 0.9)
 training_set = dataset[:split] + pseudo_set
print("Training set: ", len(training_set))
validation_set = dataset[split:]
print("Validation set: ", len(validation_set))
print("Re-training...")
 trainer = mx.gluon.Trainer(model.collect_params() , "Nadam", {
"learning_rate": learning_rate
})
 metrics = [gcv.utils.metrics.VOCMApMetric(iou_thresh=iou)for iou in [0.5, 0.55, 0.6, 0.65, 0.7, 0.75]]
best_score = 0.0
for epoch in range(max_epochs):
ts = time.time()
random.shuffle(training_set)
 training_total_L = 0.0
training_batches = 0
for x, objectness, center_targets, scale_targets, weights, class_targets, gt_bboxes in get_batches(training_set, batch_size, width=img_s, height=img_s, net=model, ctx=context):
training_batches += 1
with mx.autograd.record() :
obj_loss, center_loss, scale_loss, cls_loss = model(x, gt_bboxes, objectness, center_targets, scale_targets, weights, class_targets)
 L = obj_loss + center_loss + scale_loss + cls_loss
L.backward()
trainer.step(x.shape[0])
 training_batch_L = mx.nd.mean(L ).asscalar()
if training_batch_L != training_batch_L:
raise ValueError()
training_total_L += training_batch_L
print("[Epoch %d Batch %d] batch_loss %.10f average_loss %.10f elapsed %.2fs" %(
 epoch, training_batches, training_batch_L, training_total_L / training_batches, time.time() - ts 
))
training_avg_L = training_total_L / training_batches
for metric in metrics:
metric.reset()
for x, label in get_batches(validation_set, batch_size, width=img_s, height=img_s, ctx=context):
classes, scores, bboxes = model(x)
 for metric in metrics:
metric.update(
 bboxes,
classes.reshape(( 0, -1)) ,
scores.reshape(( 0, -1)) ,
label[:, :, :4],
label[:, :, 4:5].reshape(( 0, -1)) 
)
 score = mx.nd.array([metric.get() [1] for metric in metrics], ctx=context ).mean()
print("[Epoch %d] training_loss %.10f validation_score %.10f best_score %.10f duration %.2fs" %(
 epoch + 1, training_avg_L, score.asscalar() , best_score, time.time() - ts 
))
if score.asscalar() > best_score:
best_score = score.asscalar()
model.save_parameters("global-wheat-yolo3-darknet53.params")
 print("Loading re-trained model...")
 model = load_model("global-wheat-yolo3-darknet53.params", ctx=context)
 print("Inference...")
 results = []
for path, image_id in test_images:
print(path)
 raw = load_image(path)
 x, _ = gcv.data.transforms.presets.yolo.transform_test(raw, short=img_s)
 classes, scores, bboxes = model(x.as_in_context(context))
bboxes[0, :, 0::2] =(bboxes[0, :, 0::2] / x.shape[3] ).clip(0.0, 1.0)* raw.shape[1]
bboxes[0, :, 1::2] =(bboxes[0, :, 1::2] / x.shape[2] ).clip(0.0, 1.0)* raw.shape[0]
bboxes[0, :, 2:4] -= bboxes[0, :, 0:2]
results.append({
"image_id": image_id,
"PredictionString": " ".join([
" ".join([str(x)for x in [scores[0, i].asscalar() ] + [round(x)for x in bboxes[0, i].asnumpy().tolist() ]])
 for i in range(classes.shape[1])
 if model.classes[int(classes[0, i].asscalar())] == "wheat" and scores[0, i].asscalar() > threshold
])
 })
 pd.DataFrame(results, columns=['image_id', 'PredictionString'] ).to_csv('submission.csv', index=False)