This is based on a kaggle dataset where we are going to analyze a set of sat images.
In that each image is classified with multiple lables. So, we need to identify them properly.
For that we need to install the kaggle API download data like this:
First of all, we also need to install 7z support.
sudo apt-get -y install p7zip-full unzip
mkdir -p ~/data/planet
cd ~/data/planet
kaggle competitions download -c planet-understanding-the-amazon-from-space -f train_v2.csv
kaggle competitions download -c planet-understanding-the-amazon-from-space -f train-jpg.tar.7z
unzip train_v2.csv
7z e train-jpg.tar.7z
tar xf train-jpg.tar
%reload_ext autoreload
%autoreload 2
%matplotlib inline
from fastai import *
from fastai.vision import *
Now we symlink this data directory this directory.
So, we can inspect it.
PATH = Path('data/planet'); PATH.ls()
train_csv_path=PATH/'train_v2.csv'
!head {train_csv_path}
Each images has multiple tags.
Now let's have a look some image files.
train_image_path = PATH/'train-jpg'
train_fnames = train_image_path.ls()
train_fnames[:5]
Now we've some idea of our data. So, based on that, we can create a DataBunch object and use that inside the learner.
# This is a set of transformation which is pretty good for sat images
tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)
data = (
ImageItemList
.from_csv(PATH, 'train_v2.csv', folder="train-jpg", suffix=".jpg")
.random_split_by_pct(0.2)
.label_from_df(sep=' ')
.transform(tfms, size=128)
.databunch()
.normalize(imagenet_stats)
)
data.show_batch(rows=3, figsize=(10, 12))
Now let's try to build our model.
# First of all, we need to find some metrics
# Basically these are just for printing only.
# Since this is a multi classification problem, we need to use a threshold for the
# accuracy.
def p_accuracy(pred, act, **kwargs):
return accuracy_thresh(pred, act, thresh=0.2, **kwargs)
learn = create_cnn(data, models.resnet50, metrics=[p_accuracy])
learn.lr_find()
learn.recorder.plot()
lr = 0.01
learn.fit_one_cycle(5, slice(lr))
learn.save('l3-planet-base-freeze')
This kaggle competition uses f2 score for the final eval. So we should use that as well.
def f2_score(pred, act, **kwargs):
return fbeta(pred, act, beta=2, thresh=0.2, **kwargs)
# Let's add that as an metric
learn.metrics = [p_accuracy, f2_score]
learn.unfreeze()
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(5, slice(1e-6, 1e-4))
This is a pretty good result and we are on top 10% by default.
learn.save('l3-planet-base-freeze')
Here we've used the image size of 128px in the initial model.
That's simply because we want to try it out very quickly.
Now let's try to use the whole model.
learn.data = (
ImageItemList
.from_csv(PATH, 'train_v2.csv', folder="train-jpg", suffix=".jpg")
.random_split_by_pct(0.2)
.label_from_df(sep=' ')
.transform(tfms, size=256)
.databunch()
.normalize(imagenet_stats)
)
learn.freeze()
See now we are using transfer learning. Instead of training from the beginning, we just start from model we trained with smaller images.
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(5, slice(1e-3))
learn.save('l3-planet-fullsize-freeze')
learn.unfreeze();
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(5, slice(1e-6, 1e-5))
learn.save('l3-planet-fullsize-unfreeze')
This is a pretty amazing model with the very little things we did.
Use kaggle to download the test dataset.
Go to the data/planet
directory and run following commands:
kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg.tar.7z
7z e test-jpg.tar.7z
tar xf test-jpg.tar
kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg-additional.tar.7z
7z e test-jpg-additional.tar.7z
tar xf test-jpg.tar
mv test-jpg-additional/* test-jpg
# learn.load('l3-planet-fullsize-unfreeze');
data = (
ImageItemList
.from_csv(PATH, 'train_v2.csv', folder="train-jpg", suffix=".jpg")
.random_split_by_pct(0.2)
.label_from_df(sep=' ')
.add_test_folder('test-jpg')
.transform(tfms, size=256)
.databunch()
.normalize(imagenet_stats)
)
learn = create_cnn(data, models.resnet50, metrics=[p_accuracy, f2_score])
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(5, slice(1e-1))
learn.unfreeze()
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(5, slice(1e-6, 1e-5))
learn.save('l3-planet-fullsize-unfreeze-from-scratch')
!ls data/planet/test-jpg | wc
len(learn.data.test_ds)
predictions = learn.get_preds(ds_type=DatasetType.Test)
len(predictions[0])
def find_tags(pred, thresh):
classes = ""
for idx, val in enumerate(pred):
if val > thresh:
classes = f'{classes} {learn.data.classes[idx]}'
return classes.strip()
def predict(idx):
pred_vals = predictions[0][idx]
tags = find_tags(pred_vals, 0.2)
print(tags)
img = learn.data.test_ds[idx][0]
return img
predict(0)
def get_row(idx):
pred = predictions[0][idx]
tags = find_tags(pred, 0.2)
image_path = learn.data.test_ds.x.items[idx]
image_name = re.search(r'([^/]+)$', f'{image_path}')[0].replace('.jpg', '')
return image_name, tags
get_row(4)
df = pd.DataFrame(columns=['image_name', 'tags'])
for idx in range(len(predictions[0])):
if idx % 5000 == 0:
print(f"Completed: {idx}")
image_name, tags = get_row(idx)
df.loc[idx] = [image_name, tags]
df.head()
submission_path = f'{PATH}/submission-train-unfreezed-256-size.csv'
df.to_csv(submission_path, index=False)
!head {submission_path}
You can use the following command to upload our submission to kaggle.
kaggle competitions submit -c planet-understanding-the-amazon-from-space -f submission.csv -m "Message"