Assignment #2

Deep Learning / Fall 1398, Iran University of Science and Technology


Please pay attention to these notes:


  • Assignment Due: 1398/9/23 23:59
  • If you need any additional information, please review the assignment page on the course website.
  • We always recommend co-operation and discussion in groups for assignments. However, each student has to finish all the questions by himself/herself. If our matching system identifies any sort of copying, you'll be responsible for consequences. So, please mention his/her name if you have a team-mate.
  • Students who audit this course should submit their assignments like other students to be qualified for attending the rest of the sessions.
  • Finding any sort of copying will zero down that assignment grade and also will be counted as two negative assignment for your final score.
  • When you are ready to submit, please follow the instructions at the end of this notebook.
  • If you have any questions about this assignment, feel free to drop us a line. You may also post your questions on the course Forum page.
  • You must run this notebook on Google Colab platform, it depends on Google Colab VM for some of its dependencies.
  • Before starting to work on the assignment Please fill your name in the next section AND Remember to RUN the cell.


Assignment Page: https://iust-deep-learning.github.io/981/assignments/02_image_task_and_visualization

Course Forum: https://groups.google.com/forum/#!forum/dl981/


Fill your information here & run the cell

In [0]:
#@title Enter your information & "RUN the cell!!" { run: "auto" }
student_id = 0 #@param {type:"integer"}
student_name = "" #@param {type:"string"}
Your_Github_account_Email = "" #@param {type:"string"}

print("your student id:", student_id)
print("your name:", student_name)


from pathlib import Path

ASSIGNMENT_PATH = Path('asg02')
ASSIGNMENT_PATH.mkdir(parents=True, exist_ok=True)

1. Special Bus Line

Consider the public transport bus service. It has many gates on roads in the city and a particular lane for bus transportation.

This lane is also used for the transportation of emergency vehicles like ambulances, police cars and fire trucks, and private cars are banned from using it.

Your task is to create a system to classify these two classes of vehicles.

Dataset


In this task, you should build your dataset based on an arbitrary approach. Of course, we suggest having a look at this link if you do not have any idea about making the dataset.

Please explain your dataset making method.

$\color{red}{\text{Write your answer here}}$

In [0]:
! pip install google_images_download
! apt install chromium-chromedriver
! googleimagesdownload -k "front bus" -l 600 -o allowed -n -t photo -cd '/usr/lib/chromium-browser/chromedriver'
! googleimagesdownload -k "front car" -l 600 -o "not-allowed" -n -t photo -cd '/usr/lib/chromium-browser/chromedriver'

Implementation


You can use from Keras in this assignment.

Preprocess your data in this cell.

In [0]:
import os
import shutil
from random import shuffle
import cv2

def train_test_split():
  all_allowed = os.listdir('allowed')
  all_nallowed = os.listdir('not-allowed')
  shuffle(all_allowed)
  shuffle(all_nallowed)
  tr_allowed = all_allowed[:int(0.8 * len(all_allowed))]
  tr_nallowed = all_nallowed[:int(0.8 * len(all_nallowed))]
  te_allowed = all_allowed[int(0.8 * len(all_allowed)):]
  te_nallowed = all_nallowed[int(0.8 * len(all_nallowed)):]
  os.makedirs('DS/train/allowed')
  os.makedirs('DS/test/allowed')
  os.makedirs('DS/train/not-allowed')
  os.makedirs('DS/test/not-allowed')
  for f in tr_allowed:
    img = cv2.imread(os.path.join('allowed', f))
    try:
      resized_image =  cv2.resize(img,(150,150),interpolation = cv2.INTER_AREA)
      shutil.copyfile(os.path.join('allowed', f), os.path.join('DS/train/allowed', f))
    except Exception:
      continue
  for f in tr_nallowed:
    img = cv2.imread(os.path.join('allowed', f))
    try:
      resized_image =  cv2.resize(img,(150,150),interpolation = cv2.INTER_AREA)
      shutil.copyfile(os.path.join('not-allowed', f), os.path.join('DS/train/not-allowed', f))
    except Exception:
      continue
  for f in te_allowed:
    img = cv2.imread(os.path.join('allowed', f))
    try:
      resized_image =  cv2.resize(img,(150,150),interpolation = cv2.INTER_AREA)
      shutil.copyfile(os.path.join('allowed', f), os.path.join('DS/test/allowed', f))
    except Exception:
      continue
  for f in te_nallowed:
    img = cv2.imread(os.path.join('allowed', f))
    try:
      resized_image =  cv2.resize(img,(150,150),interpolation = cv2.INTER_AREA)
      shutil.copyfile(os.path.join('not-allowed', f), os.path.join('DS/test/not-allowed', f))
    except Exception:
      continue


if not os.path.exists('DS'):
  os.makedirs('DS/train')
  os.makedirs('DS/test')
  train_test_split()
else:
  shutil.rmtree('DS')
  os.makedirs('DS/train')
  os.makedirs('DS/test')
  train_test_split()

Build and train your model in the following cell.

Use generator and augmentation in order to feed data to the network.

In [0]:
from keras.optimizers import Adam
from keras import backend as K

def recall(y_true, y_pred):
    """
    Recall metric.

    Only computes a batch-wise average of recall.

    Computes the recall, a metric for multi-label classification of
    how many relevant items are selected.
    """
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
    recall = true_positives / (possible_positives + K.epsilon())
    return recall


def precision(y_true, y_pred):
    """
    Precision metric.

    Only computes a batch-wise average of precision.

    Computes the precision, a metric for multi-label classification of
    how many selected items are relevant.

    Source
    ------
    https://github.com/fchollet/keras/issues/5400#issuecomment-314747992
    """
    true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
    predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
    precision = true_positives / (predicted_positives + K.epsilon())
    return precision


def f1(y_true, y_pred):
    """Calculate the F1 score."""
    p = precision(y_true, y_pred)
    r = recall(y_true, y_pred)
    return 2 * ((p * r) / (p + r))
In [0]:
from keras.preprocessing.image import ImageDataGenerator
from keras import models
from keras import layers
from keras.applications.imagenet_utils import preprocess_input
from keras import optimizers

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(layers.Conv2D(128, (3, 3), activation='relu', name='last_conv_layer'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

train_datagen = ImageDataGenerator(
      preprocessing_function=preprocess_input,
      rotation_range=30,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.1,
      zoom_range=0.1)

test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)

train_generator = train_datagen.flow_from_directory(
      'DS/train',
      target_size=(150, 150),
      batch_size=20,
      classes=['allowed','not-allowed'],
      class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
      'DS/test',
      target_size=(150, 150),
      batch_size=20,
      classes=['allowed','not-allowed'],
      class_mode='binary')

model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=2e-5),
              metrics=["accuracy", f1, recall, precision])

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=50,
      validation_data=validation_generator,
      validation_steps=50)

Now, test your model, report the f1-score, recall and precision, and then save the model in a file with path 'ASSIGNMENT_PATH / 'my_model.h5''.

Plot loss and accuracy.

In [0]:
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

model.save(ASSIGNMENT_PATH / 'my_model.h5')
model.summary()

Please explain that what type of loss and accuracy you set for training your model and why?

$\color{red}{\text{Write your answer here}}$

Visualize some layers and analyze them.

In [0]:
from keras.preprocessing import image
from keras import backend as K
import numpy as np

img = image.load_img('allowed/15.image.jpg', target_size=(150, 150))
plt.imshow(img)
plt.show()

x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
predict = model.predict(x)
print(predict)

car_output = model.output[:, 0]
conv_layer = model.get_layer('last_conv_layer')
grads = K.gradients(car_output, conv_layer.output)[0]
pooled_grads = K.mean(grads, axis=(0, 1, 2))
iterate = K.function([model.input],[pooled_grads, conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([x])
for i in range(64):
  conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
heatmap = np.mean(conv_layer_output_value, axis=-1)

%matplotlib inline
import matplotlib.pyplot as plt

heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)
plt.matshow(heatmap)
In [0]:
def deprocess_image(x):
  x -= x.mean()
  x /= (x.std() + 1e-5)
  x *= 0.1
  
  x += 0.5
  x = np.clip(x, 0, 1)
  
  x *= 255
  x = np.clip(x, 0, 255).astype('uint8')
  return x
In [0]:
import numpy as np

def generate_pattern(layer_name, filter_index, size=150):
  layer_output = model.get_layer(layer_name).output
  loss = K.mean(layer_output[:, :, :, filter_index])

  grads = K.gradients(loss, model.input)[0]
  grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)

  iterate = K.function([model.input], [loss, grads])
  input_img_data = np.random.random((1, size, size, 3)) * 20 + 128.
  
  step = 1.
  for i in range(40):
    loss_value, grads_value = iterate([input_img_data])
    input_img_data += grads_value * step
  
  img = input_img_data[0]
  return deprocess_image(img)
In [0]:
layer_name = 'last_conv_layer'
size = 64
margin = 5

results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3))

for i in range(8):
  for j in range(8):
    filter_img = generate_pattern(layer_name, i + (j * 8), size=size)
    
    horizontal_start = i * size + i * margin
    horizontal_end = horizontal_start + size
    vertical_start = j * size + j * margin
    vertical_end = vertical_start + size
    results[horizontal_start:horizontal_end,
            vertical_start:vertical_end] = filter_img/255

plt.figure(figsize=(20, 20))
plt.imshow(results)

$\color{red}{\text{Write your answer here}}$

Submission

Congratulations! You finished the assignment & you're ready to submit your work. Please follow the instruction:

  1. Check and review your answers. Make sure all of the cell outputs are what you want.
  2. Select File > Save.
  3. Run Create Submission cell, It may take several minutes and it may ask you for your credential.
  4. Run Download Submission cell to obtain your submission as a zip file.
  5. Grab downloaded file (dl_asg02__xx__xx.zip) and submit it via https://forms.gle/Fb7gvVJHp8RePvo6A.

Note: We need your Github token to create (if doesn't exist previously) new repository to store learned model data. Also Google Drive token enables us to download the current notebook & create a submission. If you are interested feel free to check our code.

Create Submission (Run the cell)

In [0]:
#@title
! pip install -U --quiet PyDrive > /dev/null
! wget -q https://github.com/github/hub/releases/download/v2.10.0/hub-linux-amd64-2.10.0.tgz 
  
import os
import time
import yaml
import json

from google.colab import files
from IPython.display import Javascript
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

asg_name = 'assignment_02'
script_save = '''
require(["base/js/namespace"],function(Jupyter) {
    Jupyter.notebook.save_checkpoint();
});
'''
repo_name = 'iust-deep-learning-assignments'
submission_file_name = 'dl_asg02__%s__%s.zip'%(student_id, student_name.lower().replace(' ',  '_'))

! tar xf hub-linux-amd64-2.10.0.tgz
! cd hub-linux-amd64-2.10.0/ && chmod a+x install && ./install
! hub config --global hub.protocol https
! hub config --global user.email "$Your_Github_account_Email"
! hub config --global user.name "$student_name"
! hub api --flat -X GET /user
! hub api -F affiliation=owner -X GET /user/repos > repos.json

repos = json.load(open('repos.json'))
repo_names = [r['name'] for r in repos]
has_repository = repo_name in repo_names
if not has_repository:
  get_ipython().system_raw('! hub api -X POST -F name=%s /user/repos > repo_info.json' % repo_name)
  repo_info = json.load(open('repo_info.json')) 
  repo_url = repo_info['clone_url']
else:
  for r in repos:
    if r['name'] == repo_name:
      repo_url = r['clone_url']
  
stream = open("/root/.config/hub", "r")
token = list(yaml.load_all(stream))[0]['github.com'][0]['oauth_token']
repo_url_with_token = 'https://'+token+"@" +repo_url.split('https://')[1]

! git clone "$repo_url_with_token"
! cp -r "$ASSIGNMENT_PATH" "$repo_name"/
! cd "$repo_name" && git add -A
! cd "$repo_name" && git commit -m "Add assignment 02 results"
! cd "$repo_name" && git push -u origin master

sub_info = {
    'student_id': student_id,
    'student_name': student_name, 
    'repo_url': repo_url,
    'asg_dir_contents': os.listdir(str(ASSIGNMENT_PATH)),
    'dateime': str(time.time()),
    'asg_name': asg_name
}
json.dump(sub_info, open('info.json', 'w'))

Javascript(script_save)

auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
file_id = drive.ListFile({'q':"title='%s.ipynb'"%asg_name}).GetList()[0]['id']
downloaded = drive.CreateFile({'id': file_id})
downloaded.GetContentFile('%s.ipynb'%asg_name) 

! jupyter nbconvert --to script "$asg_name".ipynb > /dev/null
! jupyter nbconvert --to html "$asg_name".ipynb > /dev/null
! zip "$submission_file_name" "$asg_name".ipynb "$asg_name".html "$asg_name".txt info.json > /dev/null

print("##########################################")
print("Done! Submisson created, Please download using the bellow cell!")

Download Submission (Run the cell)

In [0]:
#@title
files.download(submission_file_name)

If that cell makes an error when running you can download file dl_asg02_your_struden_id_your_name.zip from left panel and files section by right-clicking on it and choosing download button.

Special Thanks

Special thanks to Amirhossein Kazemnejad and Kiamehr Razaee for creating the template of deep learning course assignments.