├── README.md ├── requirements.txt ├── Program_to_create_Google_forms ├── Modified_Program_to_create_Google_forms ├── Multimodal_baseline_Functions.py ├── WebScrapping.py └── BiLSTM_VGG16.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # Multimodal Meme Classification: Identifying Offensive Content in Image and Text 2 | 3 | If you are using the code or the dataset for your research work then please cite our paper below: 4 | 5 | @inproceedings{suryawanshi-etal-2020-MultiOFF, 6 | 7 | title = "Multimodal Meme Dataset (MultiOFF) for Identifying Offensive Content in Image and Text", 8 | 9 | author = "Suryawanshi, Shardul and Chakravarthi, Bharathi Raja and Arcan, Mihael and Buitelaar, Paul, 10 | 11 | booktitle = "Proceedings of the Second Workshop on Trolling, Aggression and Cyberbullying ({TRAC}-2020)", 12 | 13 | month = May, 14 | 15 | year = "2020", 16 | 17 | publisher = "Association for Computational Linguistics",} 18 | 19 | This is a document that involves step by step instructions to execute the code 20 | 21 | (Pre-requisite: Conda/python environment should have packages mentioned in requirement.txt file before execution 22 | Glove embedding of 50d has been used can be dowloaded from "http://nlp.stanford.edu/data/glove.6B.zip") 23 | 24 | --> Use google drive link to access the data "https://drive.google.com/drive/folders/1hKLOtpVmF45IoBmJPwojgq6XraLtHmV6?usp=sharing" 25 | 26 | --> Split dataset has train, test and validation data 27 | 28 | --> Labelled Image has memes belonging to each of the above dataset 29 | 30 | --> This data needs to be placed and directory location needs to be changed while reading the data in main code 31 | 32 | --> Once done with the setup mentioned above, one can execute the code in the sequence mentioned as below: 33 | 34 | --> Stacked_LSTM_VGG16.ipynb 35 | --> BiLSTM_VGG16.ipynb 36 | --> CNN_VGG16.ipynb 37 | --> LR_NB_DNN.ipynb 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.7.1 2 | astor==0.8.0 3 | attrs==19.1.0 4 | backcall==0.1.0 5 | bleach==3.1.0 6 | certifi==2019.6.16 7 | colorama==0.4.1 8 | cycler==0.10.0 9 | decorator==4.4.0 10 | defusedxml==0.6.0 11 | entrypoints==0.3 12 | gast==0.2.2 13 | google-pasta==0.1.7 14 | grpcio==1.16.1 15 | h5py==2.9.0 16 | ipykernel==5.1.2 17 | ipython==7.7.0 18 | ipython-genutils==0.2.0 19 | ipywidgets==7.5.1 20 | jedi==0.15.1 21 | Jinja2==2.10.1 22 | joblib==0.13.2 23 | jsonschema==3.0.2 24 | jupyter==1.0.0 25 | jupyter-client==5.3.1 26 | jupyter-console==6.0.0 27 | jupyter-core==4.5.0 28 | Keras==2.2.4 29 | Keras-Applications==1.0.8 30 | Keras-Preprocessing==1.1.0 31 | kiwisolver==1.1.0 32 | Markdown==3.1.1 33 | MarkupSafe==1.1.1 34 | matplotlib==3.1.1 35 | mistune==0.8.4 36 | mkl-fft==1.0.14 37 | mkl-random==1.0.2 38 | mkl-service==2.0.2 39 | nbconvert==5.6.0 40 | nbformat==4.4.0 41 | nltk==3.4.4 42 | notebook==6.0.0 43 | numpy==1.17.0 44 | pandas==0.25.0 45 | pandocfilters==1.4.2 46 | parso==0.5.1 47 | pickleshare==0.7.5 48 | Pillow==6.1.0 49 | prometheus-client==0.7.1 50 | prompt-toolkit==2.0.9 51 | protobuf==3.9.1 52 | pydot==1.4.1 53 | Pygments==2.4.2 54 | pyparsing==2.4.2 55 | pyreadline==2.1 56 | pyrsistent==0.15.4 57 | python-dateutil==2.8.0 58 | pytz==2019.2 59 | pywinpty==0.5.5 60 | PyYAML==5.1.2 61 | pyzmq==18.1.0 62 | qtconsole==4.5.3 63 | scikit-learn==0.21.3 64 | scipy==1.3.1 65 | seaborn==0.9.0 66 | Send2Trash==1.5.0 67 | six==1.12.0 68 | sklearn==0.0 69 | tensorboard==1.14.0 70 | tensorflow==1.14.0 71 | tensorflow-estimator==1.14.0 72 | termcolor==1.1.0 73 | terminado==0.8.2 74 | testpath==0.4.2 75 | tornado==6.0.3 76 | traitlets==4.3.2 77 | wcwidth==0.1.7 78 | webencodings==0.5.1 79 | Werkzeug==0.15.4 80 | widgetsnbextension==3.5.1 81 | wincertstore==0.2 82 | wrapt==1.11.2 83 | -------------------------------------------------------------------------------- /Program_to_create_Google_forms: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | // Creating source and destination directory 3 | var folders_with_given_name = DriveApp.getFoldersByName('Trial_JS'); 4 | var destination_folder=DriveApp.getFoldersByName('Trial_JS') 5 | //var df=destination_folder.getId 6 | while (folders_with_given_name.hasNext()) { 7 | var folder = folders_with_given_name.next(); 8 | } 9 | // Checking whether folder is present 10 | while (destination_folder.hasNext()) { 11 | var d_folder = destination_folder.next(); 12 | } 13 | // Checking csv file on source directory 14 | var files = folder.getFilesByType(MimeType.CSV); 15 | 16 | while (files.hasNext()){ 17 | var file = files.next(); 18 | var filename = file.getName(); 19 | 20 | var spreadsheet = SpreadsheetApp.create(filename); 21 | 22 | var driveFile = DriveApp.getFileById(spreadsheet.getId()); 23 | d_folder.addFile(driveFile) 24 | DriveApp.removeFile(driveFile) 25 | 26 | //var sheet= spreadsheet.insertSheet(); 27 | var csvData = Utilities.parseCsv(file.getBlob().getDataAsString(),'\t'); 28 | for(var row_idx=0;row_idx 2: 142 | uni_label = list(set(labels)) 143 | count_label = [labels.count(lab) for lab in uni_label] 144 | lab_idx = count_label.index(max(count_label)) 145 | label = uni_label[lab_idx] 146 | return label 147 | 148 | # Takes in image and preprocess it 149 | def process_input(img): 150 | # Converting image to array 151 | img_data = image.img_to_array(img) 152 | # Adding one more dimension to array 153 | img_data = np.expand_dims(img_data, axis=0) 154 | # 155 | img_data = preprocess_input(img_data) 156 | return(img_data) 157 | 158 | 159 | # In[134]: 160 | 161 | 162 | # Function to generate the data 163 | def image_generator(files,label_file, batch_size = None): 164 | """ 165 | files: list of image paths 166 | label_file: labels of the observations 167 | batch_size: Number of observations to be selected at a time 168 | 169 | return: generator object of image data 170 | """ 171 | idxs = list(range(len(files))) 172 | idx = 0 173 | while True: 174 | batch_paths = files[idx:idx+batch_size] 175 | # batch_paths = np.random.choice(a = files, size = batch_size) 176 | batch_input = [] # Batch input initialization 177 | batch_output = [] # Batch output initialization 178 | 179 | # Read in each input, perform preprocessing and get labels 180 | for input_path in batch_paths: 181 | input = get_input(input_path ) # Load image 182 | output = get_output(input_path,label_file=label_file ) # Load label of the image 183 | input = process_input(img=input) # Process the image 184 | batch_input.append(input[0]) # Append the image 185 | batch_output.append(output) # Append the label 186 | 187 | # Return a tuple of (input,output) to feed the network 188 | batch_x = np.array( batch_input ) 189 | batch_y = np.array( batch_output ) 190 | if len(batch_x) < batch_size: 191 | idx = 0 192 | else: 193 | yield (batch_x, batch_y) 194 | 195 | 196 | # In[10]: 197 | 198 | 199 | def text_generator(padded_seq, y, batch_size=None): 200 | """ 201 | padded_seq: vectorized padded text sequence 202 | y: label of the text 203 | batch_size: Number of observations to be selected at a time 204 | 205 | return: generator object of text data 206 | """ 207 | idxs = list(range(len(y))) 208 | idx = 0 209 | while True: 210 | batch_idxs = idxs[idx:idx+batch_size] 211 | idx = idx + batch_size 212 | # batch_idxs = np.random.choice(a = list(range(len(padded_seq))), size=batch_size) #Selecting the random batch indexes 213 | batch_input = [] # Initializing batch input 214 | batch_output = [] # Initializing batch output 215 | 216 | # Traversing through the batch indexes 217 | for batch_idx in batch_idxs: 218 | input = padded_seq[batch_idx] # selecting padded sequences from the batch 219 | output = y[batch_idx] # Selecting label 220 | batch_input.append(input) # Appending the input (text vector) 221 | batch_output.append(output) # Appending the label 222 | 223 | # Return a tuple of (input,output) to feed the network 224 | batch_x = np.array( batch_input ) 225 | batch_y = np.array( batch_output ) 226 | if len(batch_x) < batch_size: 227 | idx = 0 228 | else: 229 | yield (batch_x, batch_y) 230 | 231 | 232 | # In[147]: 233 | 234 | 235 | #def img_text_generator(files, padded_seq, y, batch_size=None): 236 | # """ 237 | # padded_seq: vectorized padded text sequence 238 | # y: label of the text 239 | # batch_size: Number of observations to be selected at a time 240 | # 241 | # return: generator object of text data 242 | # """ 243 | # idxs = list(range(len(padded_seq))) 244 | # idx = 0 245 | # while True: 246 | # batch_idxs = idxs[idx:idx+batch_size] 247 | ## batch_idxs = np.random.choice(a = list(range(len(padded_seq))), size=batch_size) #Selecting the random batch indexes 248 | # batch_input_txt = [] # Initializing batch input text 249 | # batch_input_img = [] # Initializing batch input image 250 | # batch_output = [] # Initializing batch output 251 | # 252 | # # Traversing through the batch indexes 253 | # for batch_idx in batch_idxs: 254 | # input_txt = padded_seq[batch_idx] # selecting padded sequences from the batch 255 | # output = y[batch_idx] # Selecting label 256 | # input_img = get_input(files[batch_idx]) 257 | # input_img = process_input(input_img) 258 | # batch_input_txt.append(input_txt) # Appending the input (text vector) 259 | # batch_input_img.append(input_img[0]) 260 | # batch_output.append(output) # Appending the label 261 | # 262 | # # Return a tuple of (input,output) to feed the network 263 | # batch_x1 = np.array( batch_input_img ) 264 | # batch_x2 = np.array( batch_input_txt ) 265 | # batch_y = np.array( batch_output ) 266 | # if (len(batch_x1) < batch_size): 267 | # idx = 0 268 | # else: 269 | # yield ([batch_x1, batch_x2], batch_y) 270 | 271 | 272 | #def image_generator(files,label_file, batch_size = None): 273 | # while True: 274 | # # Select files (paths/indices) for the batch 275 | # batch_paths = np.random.choice(a = files, 276 | # size = batch_size) 277 | # batch_input = [] 278 | # batch_output = [] 279 | # 280 | # # Read in each input, perform preprocessing and get labels 281 | # for input_path in batch_paths: 282 | # input = get_input(input_path ) 283 | # output = get_output(input_path,label_file=label_file ) 284 | ## print(output) 285 | # input = process_input(img=input) 286 | # batch_input.append(input[0]) 287 | # batch_output.append(output) 288 | # # Return a tuple of (input,output) to feed the network 289 | # batch_x = np.array( batch_input ) 290 | # batch_y = np.array( batch_output ) 291 | # 292 | # yield( batch_x, batch_y ) 293 | 294 | def img_text_generator(files, padded_seq, y, batch_size=None): 295 | """ 296 | padded_seq: vectorized padded text sequence 297 | y: label of the text 298 | batch_size: Number of observations to be selected at a time 299 | 300 | return: generator object of text data 301 | """ 302 | while True: 303 | batch_idxs = np.random.choice(a = list(range(len(padded_seq))), size=batch_size) #Selecting the random batch indexes 304 | batch_input_txt = [] # Initializing batch input text 305 | batch_input_img = [] # Initializing batch input image 306 | batch_output = [] # Initializing batch output 307 | 308 | # Traversing through the batch indexes 309 | for batch_idx in batch_idxs: 310 | input_txt = padded_seq[batch_idx] # selecting padded sequences from the batch 311 | output = y[batch_idx] # Selecting label 312 | input_img = get_input(files[batch_idx]) 313 | input_img = process_input(input_img) 314 | batch_input_txt.append(input_txt) # Appending the input (text vector) 315 | batch_input_img.append(input_img[0]) 316 | batch_output.append(output) # Appending the label 317 | 318 | # Return a tuple of (input,output) to feed the network 319 | batch_x1 = np.array( batch_input_img ) 320 | batch_x2 = np.array( batch_input_txt ) 321 | batch_y = np.array( batch_output ) 322 | yield ([batch_x1, batch_x2], batch_y) 323 | -------------------------------------------------------------------------------- /WebScrapping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | # In[29]: 5 | 6 | 7 | #Importing necessary libraries 8 | import urllib, re 9 | #Selenium libraries 10 | from selenium import webdriver 11 | import os 12 | import urllib.request 13 | 14 | 15 | # In[125]: 16 | 17 | 18 | #Defining function to check if image is present on url 19 | def url_status(url): 20 | try: 21 | r = urllib.request.urlopen(url) 22 | return r.code 23 | except urllib.request.HTTPError as e: 24 | r = e 25 | return r.code 26 | except urllib.request.URLError as e: 27 | r=e 28 | return e.args 29 | 30 | 31 | # In[99]: 32 | 33 | 34 | # Testing 35 | # Uncomment only if needs to be tested 36 | # url_status('http://imgur.com/a/IazT5') 37 | 38 | 39 | # In[3]: 40 | 41 | 42 | # Function to get image urls from imgur 43 | def scrap_imgur(url, filename): 44 | url += '.png' 45 | filename += '.png' 46 | work_dir = os.getcwd() + '\\Meme Data\\imgur\\' 47 | # urllib.request.urlretrieve(url, work_dir + filename) 48 | return url 49 | 50 | 51 | # In[4]: 52 | 53 | 54 | # Testing 55 | # Uncomment if needs to be tested 56 | # scrap_imgur('http://imgur.com/LgPKrP1', 'filename') 57 | 58 | 59 | # In[5]: 60 | 61 | 62 | # Importing headless selenium driver to deal FB images 63 | from selenium.webdriver.chrome.options import Options 64 | from selenium import webdriver 65 | import pandas as pd 66 | 67 | 68 | # In[6]: 69 | 70 | 71 | # Headless drivers 72 | chrome_options = Options() 73 | chrome_options.add_argument("--headless") 74 | chrome_options.add_argument("--window-size=1920x1080") 75 | driver = webdriver.Chrome(options=chrome_options) 76 | 77 | 78 | # In[7]: 79 | 80 | 81 | #Function to scrap FB images 82 | def scrap_fb(url, filename): 83 | driver.get(url) 84 | images = driver.find_elements_by_class_name("scaledImageFitWidth") 85 | # Importing image url from page 86 | filename += '.png' 87 | work_dir = os.getcwd() + '\\Meme Data\\FB\\' 88 | try: 89 | url = images[1].get_attribute('data-src') 90 | # urllib.request.urlretrieve(url, work_dir + filename) 91 | # Avoiding index error 92 | except IndexError: 93 | url = 'null' 94 | # urllib.request.urlretrieve(url, work_dir + filename) 95 | return url 96 | 97 | 98 | # In[8]: 99 | 100 | 101 | # Testing 102 | # Uncomment if needs to tested 103 | # scrap_fb('https://facebook.com/1667496210185013/posts/1757866207814679', 'filename') 104 | 105 | 106 | # In[9]: 107 | 108 | 109 | # Importing beautiful soup to take out twitter data 110 | from bs4 import BeautifulSoup as Soup 111 | from urllib.request import urlopen as ure 112 | 113 | 114 | # In[10]: 115 | 116 | 117 | # Function to scrap images from twitter url 118 | def scrap_twitter(url, filename): 119 | soup = ure(url) 120 | temp_soup = Soup(soup) 121 | try: 122 | url = temp_soup.find_all('div', {'class':"AdaptiveMedia-photoContainer"})[0].find('img').get('src') 123 | except IndexError: 124 | url = 'null' 125 | #Importing image url from page 126 | filename += '.png' 127 | work_dir = os.getcwd() + '\\Meme Data\\Twitter\\' 128 | # urllib.request.urlretrieve(url, work_dir + filename) 129 | return url 130 | 131 | 132 | # In[11]: 133 | 134 | 135 | # Importing random for random sampling 136 | import random 137 | # Importing numpy to carry out array operations 138 | import numpy as np 139 | 140 | 141 | # In[12]: 142 | 143 | 144 | # Importing re for regex 145 | import re 146 | 147 | 148 | # In[13]: 149 | 150 | 151 | # Removing longer captions from the data 152 | def count_lines(line): 153 | split_sent = line.split('\\n') 154 | match_words = [re.match(' [0-9]*:[0-9]* PM',i) for i in split_sent] 155 | boo_list = [i is None for i in match_words] 156 | PreList = [a*b for a,b in zip(split_sent,boo_list)] 157 | PreList = [i for i in PreList if i != ''] 158 | return len(PreList) 159 | 160 | 161 | # In[15]: 162 | 163 | 164 | # Function to process dataframe 165 | def preprocess_data(dirct): 166 | # df_data = pd.read_csv(dirct, engine = 'python', sep = '\t') 167 | df_data = pd.read_csv(dirct, engine = 'python') 168 | # Selecting required columns 169 | df_data = df_data[['id','link','caption', 'network']] 170 | # Removing data related to instagram 171 | df_data = df_data[df_data['network'] != 'instagram'] 172 | # Creating empty column named status to keep check on the status of the urls i.e. modified 173 | df_data['status'] = "" 174 | # Creating cap_len column to store number of lines in an observation 175 | df_data['cap_len'] = [count_lines(sent) for sent in df_data['caption']] 176 | # Subsetting dataframe as per cap_len 177 | df_data = df_data[df_data['cap_len'] < 20] 178 | # Taking out all the id 179 | id_list = df_data['id'] 180 | # Making list of ids 181 | list_id = [ID for ID in id_list] 182 | random.seed(99) 183 | if len(id_list) > 500: 184 | # Taking out 500 random ids 185 | rand_ids = random.sample(list_id, 500) 186 | else: 187 | rand_ids = list_id 188 | # Creating new data frame according to ids 189 | df_new = pd.DataFrame() 190 | for i in range(len(rand_ids)): 191 | df_new = df_new.append(df_data[df_data['id'] == rand_ids[i]]) 192 | # Checking url 193 | true_urls = [(df_new.index[i], link) for i,link in enumerate(df_new['link']) if url_status(link) in (200, 401)] 194 | # Empty DataFrame to append the rows with working urls 195 | df_final = pd.DataFrame() 196 | # Comparing the url index of working urls with preprocessed dataframe earlier 197 | for i in range(len(true_urls)): 198 | df_final = df_final.append(df_new[df_new.index == true_urls[i][0]]) 199 | return df_final 200 | 201 | 202 | # In[17]: 203 | 204 | 205 | # Testing 206 | # Uncomment if needs to be tested 207 | # test_df = preprocess_data("E:\\MSc DA\\Sem 2\\Project\\2016electionmemes\\Feel_the_Bern.csv") 208 | 209 | 210 | # In[21]: 211 | 212 | 213 | # Storing base directory in variable 214 | base_dir = 'E:\\MSc DA\\Sem 2\\Project\\2016electionmemes' 215 | 216 | 217 | # In[22]: 218 | 219 | 220 | # Creating list of csv files 221 | for root, dirs, files in os.walk(base_dir): 222 | paths_dir = [root + '\\' + name for name in files if name.endswith((".csv"))] 223 | 224 | 225 | # In[24]: 226 | 227 | 228 | # Testing 229 | # Uncomment if needs to be tested 230 | # paths_dir 231 | 232 | 233 | # In[26]: 234 | 235 | 236 | # Function to create url collection 237 | def url_collection(DF): 238 | # As index is not aligned 239 | df_idx = DF.index 240 | # Looping over the DataFrame to replace the existing urls with image urls 241 | for i in range(len(DF)): 242 | # Reading out ID as file name which later could be used to save the image with same name 243 | filename = str(DF.iloc[[i]]['id'][df_idx[i]]) 244 | # Storing url in 'url' to provide it to function that extracts image url from the url provided 245 | url = DF.iloc[[i]]['link'][df_idx[i]] 246 | status = DF['status'][df_idx[i]] 247 | # Putting if condition to avoid rewriting the url 248 | # if (not(url.endswith('.png'))): 249 | if status != 'modified': 250 | # Replacing the 'imgur' url with image url 251 | if (DF.iloc[[i]]['network'][df_idx[i]] == 'imgur'): 252 | DF.at[df_idx[i], 'link'] = scrap_imgur(url, filename) 253 | DF['status'][df_idx[i]] = 'modified' 254 | # Replacing the 'Facebook' url with image url 255 | elif (DF.iloc[[i]]['network'][df_idx[i]] == 'facebook'): 256 | DF.at[df_idx[i], 'link'] = scrap_fb(url, filename) 257 | DF['status'][df_idx[i]] = 'modified' 258 | # Replacing the 'Twitter' url with image url 259 | else: 260 | DF.at[df_idx[i], 'link'] = scrap_twitter(url, filename) 261 | DF['status'][df_idx[i]] = 'modified' 262 | else: 263 | DF.at[df_idx[i], 'link'] = url 264 | return DF 265 | 266 | 267 | # In[27]: 268 | 269 | 270 | # Storing images on local and creating working csv with image urls 271 | def creating_op(dirct): 272 | # Processing Dataframe 273 | processed_df = preprocess_data(dirct) 274 | # Collecting true urls 275 | refined_df = url_collection(processed_df) 276 | # Removing the null urls 277 | refined_df = refined_df[refined_df['link'] != 'null'] 278 | # Defining ouptup directory 279 | op_dir = dirct.replace('2016electionmemes\\', '2016electionmemes\\Refined\\') 280 | # Writing file at above location 281 | refined_df.to_csv(op_dir, sep='\t', encoding='utf-8') 282 | 283 | 284 | # In[202]: 285 | 286 | 287 | # Uncomment only if needs to be run 288 | # for path in paths_dir: 289 | # creating_op(path) 290 | 291 | 292 | # In[63]: 293 | 294 | 295 | # Creating output directory 296 | base_dir = "E:\\MSc DA\\Sem 2\\Project\\2016electionmemes\\Refined" 297 | for root, dirs, files in os.walk(base_dir): 298 | op_dir = [root + '\\' + name for name in files if name.endswith((".csv"))] 299 | 300 | 301 | # In[64]: 302 | 303 | 304 | count_per_file_op = [len(pd.read_csv(j, engine = 'python', sep='\t')) for j in op_dir] 305 | # len(pd.read_csv(op_dir[0], engine='python', sep='\t')) 306 | 307 | 308 | # In[203]: 309 | 310 | 311 | # Printing the max number of tokens 312 | # sum(count_per_file_op) 313 | 314 | 315 | # In[67]: 316 | 317 | 318 | # Taking in all the dataframes in single list 319 | combined_DF = [pd.read_csv(i, sep= '\t', encoding = 'utf-8') for i in op_dir] 320 | 321 | 322 | # In[204]: 323 | 324 | 325 | # Checking if all the files are part of the list 326 | # len(combined_DF) 327 | 328 | 329 | # In[69]: 330 | 331 | 332 | # appending all the lengths 333 | Caption_len = [] 334 | for DF in combined_DF: 335 | Caption_len.append([count_lines(i) for i in DF['caption']]) 336 | 337 | 338 | # In[72]: 339 | 340 | 341 | # taking guess of lengths in the data 342 | New_cap_len = [i for i in Caption_len if i != []] 343 | # Maximum caption lengths in each file 344 | [max(cap_len) for cap_len in New_cap_len] 345 | 346 | 347 | # In[73]: 348 | 349 | 350 | # concatenating all the dataframes 351 | con_Df = pd.concat(combined_DF) 352 | # con_Df['cap_len'] = [count_lines(i) for i in con_Df['caption']] 353 | 354 | 355 | # In[205]: 356 | 357 | 358 | # Number of rows in new Dataframe 359 | # Keeping caption lenght lower than 20 360 | len(con_Df[con_Df['cap_len'] < 20]) 361 | 362 | 363 | # In[126]: 364 | 365 | 366 | # Adding new column URL_status to the existing dataframe to store status of URL (200,404, 401) 367 | con_Df['URL_status'] = [url_status(con_Df.iloc[i]['link']) for i in range(len(con_Df['link']))] 368 | 369 | 370 | # In[165]: 371 | 372 | 373 | # url_status(con_Df['link'][0]) 374 | con_Df = con_Df[con_Df['URL_status'] != 404] 375 | 376 | 377 | # In[167]: 378 | 379 | 380 | # Writing csv output 381 | con_Df.to_csv("E:\MSc DA\\Sem 2\\Project\\2016electionmemes\\Refined\\Combined_Df.csv", sep='\t', encoding='utf-8') 382 | 383 | 384 | # In[143]: 385 | 386 | 387 | # Defining function to make list of dataframe 388 | def chunks(DF, n): 389 | n = max(1, n) 390 | return (DF.iloc[i:i+n, :] for i in range(0, len(DF), n)) 391 | 392 | 393 | # In[157]: 394 | 395 | 396 | # List of dataframe by using chunks() function 397 | list_con_Df = [i for i in chunks(con_Df,30)] 398 | 399 | 400 | # In[168]: 401 | 402 | 403 | # Writing csvs in the form 404 | for i in range(len(list_con_Df)): 405 | Filename = 'Memes_Data_Survey_'+ str(i) + '.csv' 406 | list_con_Df[i].to_csv('E:\\MSc DA\\Sem 2\\Project\\2016electionmemes\\Form csvs\\' + Filename, sep='\t', encoding='utf-8') 407 | 408 | 409 | # In[182]: 410 | 411 | 412 | # Creating directory of the forms 413 | form_dir = 'E:\\MSc DA\\Sem 2\\Project\\2016electionmemes\\Form csvs\\Forms\\' 414 | 415 | 416 | # In[208]: 417 | 418 | 419 | # form_dir 420 | 421 | 422 | # In[199]: 423 | 424 | 425 | # Creating csv compatible for google forms 426 | def comp_DF(DF_list): 427 | for i in range(len(DF_list)): 428 | with open(form_dir + 'Memes_Data_Survey_' + str(i) + '.csv','w',encoding='utf-8') as k: 429 | for index, row in DF_list[i].iterrows(): 430 | if (index % 10 )==0: 431 | print('IMAGE\t Choose the option\t',row.iloc[3],'\t', 432 | row.iloc[2]+'\t','offensive\t Non-offensiv', file=k) 433 | # Adding Page to limit the number of images on the page 434 | print('PAGE',file=k) 435 | else: 436 | print('IMAGE\t Choose the option\t',row.iloc[3],'\t', 437 | row.iloc[2]+'\t','offensive\t Non-offensiv', file=k) 438 | 439 | 440 | # In[201]: 441 | 442 | 443 | # Using function created above 444 | # Uncomment only if needs to executed 445 | # comp_DF(list_con_Df) 446 | 447 | -------------------------------------------------------------------------------- /BiLSTM_VGG16.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "scrolled": true 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stderr", 12 | "output_type": "stream", 13 | "text": [ 14 | "Using TensorFlow backend.\n" 15 | ] 16 | } 17 | ], 18 | "source": [ 19 | "# Importing necessary libraries\n", 20 | "import keras\n", 21 | "import h5py\n", 22 | "from keras import optimizers\n", 23 | "from keras.models import load_model\n", 24 | "from keras.layers import Bidirectional\n", 25 | "from Multimodal_baseline_Functions import *\n", 26 | "from keras.layers.core import Reshape, Dropout\n", 27 | "from keras.utils.vis_utils import plot_model\n", 28 | "import os\n", 29 | "# import keras_metrics\n", 30 | "import matplotlib.pyplot as plt\n", 31 | "from keras.layers import Conv1D, MaxPooling1D, Flatten, GlobalAveragePooling3D\n", 32 | "from keras import regularizers\n", 33 | "import seaborn as sns\n", 34 | "import matplotlib.pyplot as plt \n", 35 | "from sklearn.metrics import confusion_matrix\n", 36 | "from keras import regularizers \n", 37 | "from keras.applications.inception_v3 import InceptionV3" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 2, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "class_weight = {1: 1.4,\n", 47 | " 0: 1.}" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 3, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "GLOVE_DIR = \"E:\\MSc DA\\Sem 2\\Project\\Code and Docmentation\\glove.6B\"\n", 57 | "EMBEDDING_DIM = 50" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 4, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "# Defining model with Adam optimizer\n", 67 | "adam = keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)\n", 68 | "sgd = optimizers.SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)\n", 69 | "adadelta = optimizers.Adadelta(lr=1.0, rho=0.95, epsilon=None, decay=0.0)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 5, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "def Image_model(base_model):\n", 79 | " # Freezing all the trainable layers\n", 80 | " for layer in base_model.layers:\n", 81 | " layer.trainable = False\n", 82 | "\n", 83 | " # Creating output layer\n", 84 | " x = base_model.output\n", 85 | " # Adding pooling layer before the output\n", 86 | " x = GlobalAveragePooling2D()(x) \n", 87 | " return x" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 6, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [ 96 | "def read_data(file_name):\n", 97 | " #Opening file\n", 98 | " with open(file_name,'r', encoding=\"utf8\") as f:\n", 99 | " #Creating empty set and dictonary for vocab and word respectively\n", 100 | " word_vocab = set() \n", 101 | " word2vector = {}\n", 102 | " #Iterating over each line of file\n", 103 | " for line in f:\n", 104 | " #Spliting lines\n", 105 | " line_ = line.strip() \n", 106 | " #Splitting words\n", 107 | " words_Vec = line_.split() \n", 108 | " word_vocab.add(words_Vec[0])\n", 109 | " word2vector[words_Vec[0]] = np.array(words_Vec[1:],dtype=float)\n", 110 | " print(\"Total Words in DataSet:\",len(word_vocab))\n", 111 | " return word_vocab,word2vector" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 7, 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "# Dividing data in test, train, validation\n", 121 | "training_DF, testing_DF, validation_DF = preprocess_text(Training_path,Validation_path, Testing_path)" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 8, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "# Processing image and text for each set\n", 131 | "# Creating train, test and validation image path\n", 132 | "train_img_path = create_img_path(training_DF,'image_name', img_dir)\n", 133 | "test_img_path = create_img_path(testing_DF,'image_name', img_dir)\n", 134 | "val_img_path = create_img_path(validation_DF,'image_name', img_dir)\n", 135 | "\n", 136 | "# Processing the text\n", 137 | "training_DF['sentence'] = training_DF['sentence'].apply(clean_text)\n", 138 | "testing_DF['sentence'] = testing_DF['sentence'].apply(clean_text)\n", 139 | "validation_DF['sentence'] = validation_DF['sentence'].apply(clean_text)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 9, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "# Vectorising text\n", 149 | "# process the whole observation into single list\n", 150 | "train_text_list=list(training_DF['sentence'])\n", 151 | "test_text_list = list(testing_DF['sentence'])\n", 152 | "val_text_list = list(validation_DF['sentence'])\n", 153 | "\n", 154 | "# Creating vectors for train, test, validation\n", 155 | "tokenizer = Tokenizer(num_words=1000)\n", 156 | "tokenizer.fit_on_texts(train_text_list)\n", 157 | "sequences_train = tokenizer.texts_to_sequences(train_text_list)\n", 158 | "sequences_test = tokenizer.texts_to_sequences(test_text_list)\n", 159 | "sequences_val = tokenizer.texts_to_sequences(val_text_list)\n", 160 | "\n", 161 | "x_train = preprocessing.sequence.pad_sequences(sequences_train, maxlen=maxlen)\n", 162 | "x_test = preprocessing.sequence.pad_sequences(sequences_test, maxlen=maxlen)\n", 163 | "x_val = preprocessing.sequence.pad_sequences(sequences_val, maxlen=maxlen)\n", 164 | "\n", 165 | "# encoding all the labels \n", 166 | "y_test = testing_DF['label']\n", 167 | "y_train = training_DF['label']\n", 168 | "y_val = validation_DF['label']" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 10, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "# Creating train, test, val, generator for meme\n", 178 | "img_txt_gen_train = img_text_generator(train_img_path, x_train, y_train, batch_size=32)\n", 179 | "img_txt_gen_test = img_text_generator(test_img_path, x_test, y_test, batch_size=1)\n", 180 | "img_txt_gen_val = img_text_generator(val_img_path, x_val, y_val, batch_size=1)\n", 181 | "\n", 182 | "# Creating train, test, val, generator for text\n", 183 | "txt_gen_train = text_generator(x_train, y_train, batch_size=32)\n", 184 | "txt_gen_test = text_generator(x_test, y_test, batch_size=1)\n", 185 | "txt_gen_val = text_generator(x_val, y_val, batch_size=1)\n", 186 | "\n", 187 | "# Creating train, test, val, generator for image\n", 188 | "img_gen_train = image_generator(train_img_path, training_DF, batch_size=32)\n", 189 | "img_gen_test = image_generator(test_img_path, testing_DF, batch_size=1)\n", 190 | "img_gen_val = image_generator(val_img_path, validation_DF, batch_size=1)" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 11, 196 | "metadata": {}, 197 | "outputs": [ 198 | { 199 | "name": "stdout", 200 | "output_type": "stream", 201 | "text": [ 202 | "Total Words in DataSet: 400000\n" 203 | ] 204 | } 205 | ], 206 | "source": [ 207 | "vocab, w2v = read_data(os.path.join(GLOVE_DIR, \"glove.6B.50d.txt\"))" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 12, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "word_index = tokenizer.word_index\n", 217 | "num_tokens = len(word_index)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": 13, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "#Creating embeddding weight matrix\n", 227 | "embedding_matrix = np.zeros((num_tokens + 1, EMBEDDING_DIM))\n", 228 | "\n", 229 | "for word, i in word_index.items():\n", 230 | " embedding_vector = w2v.get(word)\n", 231 | " if embedding_vector is not None:\n", 232 | " embedding_matrix[i] = embedding_vector" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 14, 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "name": "stderr", 242 | "output_type": "stream", 243 | "text": [ 244 | "WARNING: Logging before flag parsing goes to stderr.\n", 245 | "W0819 19:54:07.820795 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", 246 | "\n" 247 | ] 248 | } 249 | ], 250 | "source": [ 251 | "#Creating embedded layer using embedded matrix as weight matrix\n", 252 | "embedding_layer = Embedding(num_tokens + 1, EMBEDDING_DIM, weights=[embedding_matrix], trainable = False)" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 15, 258 | "metadata": {}, 259 | "outputs": [ 260 | { 261 | "name": "stderr", 262 | "output_type": "stream", 263 | "text": [ 264 | "W0819 19:54:07.921015 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", 265 | "\n", 266 | "W0819 19:54:07.923027 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", 267 | "\n", 268 | "W0819 19:54:07.952036 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:174: The name tf.get_default_session is deprecated. Please use tf.compat.v1.get_default_session instead.\n", 269 | "\n", 270 | "W0819 19:54:07.953037 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:181: The name tf.ConfigProto is deprecated. Please use tf.compat.v1.ConfigProto instead.\n", 271 | "\n" 272 | ] 273 | } 274 | ], 275 | "source": [ 276 | "# Defining input layer\n", 277 | "main_input = Input(shape=(maxlen,), dtype='int32', name='main_input')\n", 278 | "\n", 279 | "# Defining embedding layer which will encode the input sequence\n", 280 | "embedded_sequences = embedding_layer(main_input)\n", 281 | "# x = Embedding(output_dim=512, input_dim=10000, input_length=maxlen)(main_input)\n", 282 | "\n", 283 | "# A LSTM will transform the vector sequence into a single vector,\n", 284 | "# containing information about the entire sequence\n", 285 | "lstm_out = (Bidirectional(LSTM(32)))(embedded_sequences)\n", 286 | "\n", 287 | "# Output of text model\n", 288 | "txt_out = Dense(1, activation='sigmoid')(lstm_out)" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": 16, 294 | "metadata": {}, 295 | "outputs": [], 296 | "source": [ 297 | "txt_model = Model(inputs = [main_input], outputs=txt_out)" 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": 17, 303 | "metadata": { 304 | "scrolled": true 305 | }, 306 | "outputs": [ 307 | { 308 | "name": "stderr", 309 | "output_type": "stream", 310 | "text": [ 311 | "W0819 19:54:08.737271 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", 312 | "\n", 313 | "W0819 19:54:08.748280 8196 deprecation.py:323] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\tensorflow\\python\\ops\\nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", 314 | "Instructions for updating:\n", 315 | "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "txt_model.compile(loss='binary_crossentropy', optimizer=adam, metrics = [\"accuracy\"])" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": 18, 326 | "metadata": {}, 327 | "outputs": [], 328 | "source": [ 329 | "plot_model(txt_model, to_file='BiLSTM_txt_model.png', show_shapes=True, show_layer_names=True)" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 19, 335 | "metadata": {}, 336 | "outputs": [ 337 | { 338 | "name": "stdout", 339 | "output_type": "stream", 340 | "text": [ 341 | "Epoch 1/7\n", 342 | "2/2 [==============================] - 27s 13s/step - loss: 0.8108 - acc: 0.5625 - val_loss: 0.7017 - val_acc: 0.4295\n", 343 | "Epoch 2/7\n", 344 | "2/2 [==============================] - 22s 11s/step - loss: 0.7976 - acc: 0.5156 - val_loss: 0.6986 - val_acc: 0.4497\n", 345 | "Epoch 3/7\n", 346 | "2/2 [==============================] - 23s 11s/step - loss: 0.7674 - acc: 0.6094 - val_loss: 0.6936 - val_acc: 0.4899\n", 347 | "Epoch 4/7\n", 348 | "2/2 [==============================] - 29s 15s/step - loss: 0.8249 - acc: 0.5469 - val_loss: 0.6906 - val_acc: 0.5503\n", 349 | "Epoch 5/7\n", 350 | "2/2 [==============================] - 30s 15s/step - loss: 0.8028 - acc: 0.5938 - val_loss: 0.6889 - val_acc: 0.5503\n", 351 | "Epoch 6/7\n", 352 | "2/2 [==============================] - 27s 13s/step - loss: 0.8064 - acc: 0.5312 - val_loss: 0.6875 - val_acc: 0.5638\n", 353 | "Epoch 7/7\n", 354 | "2/2 [==============================] - 29s 14s/step - loss: 0.8393 - acc: 0.5000 - val_loss: 0.6891 - val_acc: 0.5705\n" 355 | ] 356 | }, 357 | { 358 | "data": { 359 | "text/plain": [ 360 | "" 361 | ] 362 | }, 363 | "execution_count": 19, 364 | "metadata": {}, 365 | "output_type": "execute_result" 366 | } 367 | ], 368 | "source": [ 369 | "# Training text model\n", 370 | "txt_model.fit_generator(txt_gen_train, epochs=7, validation_steps = 149, steps_per_epoch=2, validation_data=txt_gen_val, shuffle = False, class_weight=class_weight)" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": 20, 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "txt_model.save('BiLSTM_txt_model.h5')" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 21, 385 | "metadata": {}, 386 | "outputs": [], 387 | "source": [ 388 | "y_pred_txt = (txt_model.predict_generator(txt_gen_test,steps = 149))\n", 389 | "y_pred_txt = np.round(list(itertools.chain(*y_pred_txt)))\n", 390 | "y_true = y_test.values" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 22, 396 | "metadata": {}, 397 | "outputs": [ 398 | { 399 | "data": { 400 | "image/png": "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\n", 401 | "text/plain": [ 402 | "
" 403 | ] 404 | }, 405 | "metadata": { 406 | "needs_background": "light" 407 | }, 408 | "output_type": "display_data" 409 | } 410 | ], 411 | "source": [ 412 | "labels = [1,0]\n", 413 | "cm = confusion_matrix(y_true, y_pred_txt, labels)\n", 414 | "ax= plt.subplot()\n", 415 | "sns.heatmap(cm, annot=True, ax = ax); #annot=True to annotate cells\n", 416 | "\n", 417 | "# labels, title and ticks\n", 418 | "ax.set_xlabel('Predicted labels');ax.set_ylabel('True labels'); \n", 419 | "ax.set_title('Confusion Matrix'); \n", 420 | "ax.xaxis.set_ticklabels(['offensive', 'non-offensive']); ax.yaxis.set_ticklabels(['offensive', 'non-offensive']);" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 27, 426 | "metadata": {}, 427 | "outputs": [ 428 | { 429 | "name": "stderr", 430 | "output_type": "stream", 431 | "text": [ 432 | "W0819 19:57:44.541557 8196 deprecation_wrapper.py:119] From f:\\anaconda\\envs\\exp_env\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:3976: The name tf.nn.max_pool is deprecated. Please use tf.nn.max_pool2d instead.\n", 433 | "\n" 434 | ] 435 | } 436 | ], 437 | "source": [ 438 | "# Loading pretrained image model from previous experiment\n", 439 | "img_model = load_model('VGG16_img_model.h5')" 440 | ] 441 | }, 442 | { 443 | "cell_type": "code", 444 | "execution_count": 29, 445 | "metadata": {}, 446 | "outputs": [], 447 | "source": [ 448 | "# Compiling model\n", 449 | "img_model.compile(loss='binary_crossentropy', optimizer=adam, metrics = [\"accuracy\"])" 450 | ] 451 | }, 452 | { 453 | "cell_type": "code", 454 | "execution_count": 30, 455 | "metadata": {}, 456 | "outputs": [], 457 | "source": [ 458 | "# Concatenating the output\n", 459 | "con_layer = keras.layers.concatenate([txt_model.output, img_model.output])\n", 460 | "out = Dense(1,activation='sigmoid')(con_layer)" 461 | ] 462 | }, 463 | { 464 | "cell_type": "code", 465 | "execution_count": 31, 466 | "metadata": {}, 467 | "outputs": [], 468 | "source": [ 469 | "# Defining model input and output\n", 470 | "com_model = Model(inputs = [img_model.input, txt_model.input], outputs=out)" 471 | ] 472 | }, 473 | { 474 | "cell_type": "code", 475 | "execution_count": 32, 476 | "metadata": {}, 477 | "outputs": [], 478 | "source": [ 479 | "# Using Stochastic gradient descent with optimizer\n", 480 | "sgd = optimizers.SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)\n", 481 | "com_model.compile(loss='binary_crossentropy', optimizer=adam, metrics = [\"accuracy\"])" 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": 33, 487 | "metadata": {}, 488 | "outputs": [], 489 | "source": [ 490 | "# Plot the model\n", 491 | "plot_model(com_model, to_file='BiLSTM_VGG_mul_model.png', show_shapes=True, show_layer_names=True)" 492 | ] 493 | }, 494 | { 495 | "cell_type": "code", 496 | "execution_count": 34, 497 | "metadata": { 498 | "scrolled": true 499 | }, 500 | "outputs": [ 501 | { 502 | "name": "stdout", 503 | "output_type": "stream", 504 | "text": [ 505 | "Epoch 1/7\n", 506 | "2/2 [==============================] - 259s 129s/step - loss: 0.7969 - acc: 0.4062 - val_loss: 0.6986 - val_acc: 0.4765\n", 507 | "Epoch 2/7\n", 508 | "2/2 [==============================] - 251s 125s/step - loss: 0.7927 - acc: 0.5156 - val_loss: 0.6956 - val_acc: 0.5302\n", 509 | "Epoch 3/7\n", 510 | "2/2 [==============================] - 252s 126s/step - loss: 0.8089 - acc: 0.4688 - val_loss: 0.6950 - val_acc: 0.4497\n", 511 | "Epoch 4/7\n", 512 | "2/2 [==============================] - 253s 127s/step - loss: 0.8190 - acc: 0.4531 - val_loss: 0.6943 - val_acc: 0.5034\n", 513 | "Epoch 5/7\n", 514 | "2/2 [==============================] - 244s 122s/step - loss: 0.7993 - acc: 0.5000 - val_loss: 0.6937 - val_acc: 0.5503\n", 515 | "Epoch 6/7\n", 516 | "2/2 [==============================] - 246s 123s/step - loss: 0.8074 - acc: 0.4844 - val_loss: 0.6953 - val_acc: 0.4966\n", 517 | "Epoch 7/7\n", 518 | "2/2 [==============================] - 251s 125s/step - loss: 0.8170 - acc: 0.6094 - val_loss: 0.6927 - val_acc: 0.5302\n" 519 | ] 520 | }, 521 | { 522 | "data": { 523 | "text/plain": [ 524 | "" 525 | ] 526 | }, 527 | "execution_count": 34, 528 | "metadata": {}, 529 | "output_type": "execute_result" 530 | } 531 | ], 532 | "source": [ 533 | "# Training model\n", 534 | "com_model.fit_generator(img_txt_gen_train, epochs=7, validation_steps = 149, steps_per_epoch=2, validation_data=img_txt_gen_val, shuffle=False, class_weight=class_weight)" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": 35, 540 | "metadata": {}, 541 | "outputs": [], 542 | "source": [ 543 | "# Saving the text model\n", 544 | "com_model.save('BiLSTM_VGG_mul_model.h5')" 545 | ] 546 | }, 547 | { 548 | "cell_type": "code", 549 | "execution_count": 36, 550 | "metadata": {}, 551 | "outputs": [], 552 | "source": [ 553 | "# Predicting the label using combined model\n", 554 | "y_pred_com = (com_model.predict_generator(img_txt_gen_test,steps = 149))\n", 555 | "y_pred_com = np.round(list(itertools.chain(*y_pred_com)))" 556 | ] 557 | }, 558 | { 559 | "cell_type": "code", 560 | "execution_count": 37, 561 | "metadata": {}, 562 | "outputs": [ 563 | { 564 | "data": { 565 | "image/png": "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\n", 566 | "text/plain": [ 567 | "
" 568 | ] 569 | }, 570 | "metadata": { 571 | "needs_background": "light" 572 | }, 573 | "output_type": "display_data" 574 | } 575 | ], 576 | "source": [ 577 | "# Block for confusion matrix\n", 578 | "labels = [1,0]\n", 579 | "cm = confusion_matrix(y_true, y_pred_com, labels)\n", 580 | "ax= plt.subplot()\n", 581 | "sns.heatmap(cm, annot=True, ax = ax); #annot=True to annotate cells\n", 582 | "\n", 583 | "# labels, title and ticks\n", 584 | "ax.set_xlabel('Predicted labels');ax.set_ylabel('True labels'); \n", 585 | "ax.set_title('Confusion Matrix'); \n", 586 | "ax.xaxis.set_ticklabels(['offensive', 'non-offensive']); ax.yaxis.set_ticklabels(['offensive', 'non-offensive']);" 587 | ] 588 | }, 589 | { 590 | "cell_type": "code", 591 | "execution_count": 38, 592 | "metadata": { 593 | "scrolled": true 594 | }, 595 | "outputs": [ 596 | { 597 | "data": { 598 | "image/png": "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G/v5AK8A2602JwJPKqWaAEOB8GyHPauUam55mDZoAHy/6STpGZm89LBeFlbTnCU6Opo///nP7N27l8OHDzN79mw2bdrE559/zscffwzARx99RJcuXdi5cydr167lzTffvP2Ldf/+/cyePZsdO3bwt7/9jVKlSrF7927atWvHzJkzARg5ciRfffUVkZGRfP7554wZM8ZmLMePH2fZsmUsXryY5557js6dO7Nv3z5KlizJsmXLSE5OZtiwYcybN+/2QDBx4kSSk5N58cUXWbp0KRs3buT8+fO3z5lT7LYEBASwcuVKdu3axbx583jllVcA+PXXX1m0aBHbt29nz549/PWvfwXg2WefZezYsezZs4ctW7ZQpUqV+/rv4cwrjlAgWil1AkBE5gK9gIPZ9vsAGA+8kbVBKbXb6vUDQAkR8VZKpTgx3jy7cjONH7bG8HjTBwjyK2127BZCggAAEMJJREFUOJrmdDldGThTUFAQTZo0AaBRo0Z07doVEaFJkyacOnUKgN9//50lS5bw+eefA0Ya8enTpwHo3LkzPj4++Pj4UK5cOZ588kkAmjRpwt69e7l+/Tpbtmyhf//+t98zJcX2r5sePXpQrFgxmjRpQkZGBmFhYbfPderUKY4cOUJQUBD16tUDYOjQoUyYMIFOnToRFBRE3bp1AXjuueeYNGlSrrHbkpaWxssvv0xUVBSenp4cPXoUgFWrVjF8+HBKlSoFgK+vL9euXePMmTM89dRTgFHsd7+cOXBUBWKtnscBbax3EJEWQHWl1C8i8ga29QV2Zxs0polIBvAj8KGysXC6iIwERgLUqOGcuooZW09xIzWDMZ301YamOZO3t/ftnz08PG4/9/DwID09HTAK2X788Ufq169/17Hbt2/P9fjMzEzKly9PVFSU3bF4eHhQrFix26msWeey8evotnulvd4r9gsXLtjc/4svvqBSpUrs2bOHzMzM24OBUuoP75FTPPnlzJvjtv6Gbn8CEfEAvgBev+cJRBoBnwIvWW1+1jKF9aDlMdjWsUqpSUqpEKVUiL+/fz7Cz9mNlHSmbj5J1+AAGlQp6/Dza5qWN927d+err766/Yty9+7duRxxR9myZQkKCmLBggWA8ct2z549+YojODiYU6dOER0dDUB4eDgPP/wwwcHBnDx5kuPHjwMwZ86cfMd+5coVqlSpgoeHB+Hh4WRk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\n", 599 | "text/plain": [ 600 | "
" 601 | ] 602 | }, 603 | "metadata": { 604 | "needs_background": "light" 605 | }, 606 | "output_type": "display_data" 607 | } 608 | ], 609 | "source": [ 610 | "# training accuracy\n", 611 | "plt.plot(com_model.history.epoch, com_model.history.history['acc'])\n", 612 | "plt.plot(txt_model.history.epoch, txt_model.history.history['acc'])\n", 613 | "plt.gca().legend(('meme model acc', 'image model acc', 'text model acc'))\n", 614 | "plt.xlabel('epoch')\n", 615 | "plt.ylabel('training accuracy')\n", 616 | "plt.show()" 617 | ] 618 | }, 619 | { 620 | "cell_type": "code", 621 | "execution_count": 39, 622 | "metadata": { 623 | "scrolled": true 624 | }, 625 | "outputs": [ 626 | { 627 | "data": { 628 | "image/png": "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\n", 629 | "text/plain": [ 630 | "
" 631 | ] 632 | }, 633 | "metadata": { 634 | "needs_background": "light" 635 | }, 636 | "output_type": "display_data" 637 | } 638 | ], 639 | "source": [ 640 | "# Validation Accuracy\n", 641 | "plt.plot(com_model.history.epoch, com_model.history.history['val_acc'])\n", 642 | "plt.plot(txt_model.history.epoch, txt_model.history.history['val_acc'])\n", 643 | "plt.gca().legend(('meme model validation acc', 'image model validation acc', 'text model validation acc'))\n", 644 | "plt.show()" 645 | ] 646 | }, 647 | { 648 | "cell_type": "code", 649 | "execution_count": 40, 650 | "metadata": {}, 651 | "outputs": [ 652 | { 653 | "data": { 654 | "text/plain": [ 655 | "['loss', 'acc']" 656 | ] 657 | }, 658 | "execution_count": 40, 659 | "metadata": {}, 660 | "output_type": "execute_result" 661 | } 662 | ], 663 | "source": [ 664 | "com_model.metrics_names" 665 | ] 666 | }, 667 | { 668 | "cell_type": "code", 669 | "execution_count": 41, 670 | "metadata": {}, 671 | "outputs": [ 672 | { 673 | "data": { 674 | "text/plain": [ 675 | "[0.706167459487915, 0.0]" 676 | ] 677 | }, 678 | "execution_count": 41, 679 | "metadata": {}, 680 | "output_type": "execute_result" 681 | } 682 | ], 683 | "source": [ 684 | "com_model.evaluate_generator(img_txt_gen_test, steps=5)" 685 | ] 686 | }, 687 | { 688 | "cell_type": "code", 689 | "execution_count": 42, 690 | "metadata": {}, 691 | "outputs": [ 692 | { 693 | "data": { 694 | "text/plain": [ 695 | "[0.024448825046420097, 1.0]" 696 | ] 697 | }, 698 | "execution_count": 42, 699 | "metadata": {}, 700 | "output_type": "execute_result" 701 | } 702 | ], 703 | "source": [ 704 | "img_model.evaluate_generator(img_gen_test, steps=5)" 705 | ] 706 | }, 707 | { 708 | "cell_type": "code", 709 | "execution_count": 43, 710 | "metadata": {}, 711 | "outputs": [ 712 | { 713 | "data": { 714 | "text/plain": [ 715 | "[0.7561434626579284, 0.0]" 716 | ] 717 | }, 718 | "execution_count": 43, 719 | "metadata": {}, 720 | "output_type": "execute_result" 721 | } 722 | ], 723 | "source": [ 724 | "txt_model.evaluate_generator(txt_gen_test, steps=5)" 725 | ] 726 | }, 727 | { 728 | "cell_type": "code", 729 | "execution_count": 44, 730 | "metadata": {}, 731 | "outputs": [], 732 | "source": [ 733 | "from sklearn.metrics import precision_recall_fscore_support" 734 | ] 735 | }, 736 | { 737 | "cell_type": "code", 738 | "execution_count": 45, 739 | "metadata": {}, 740 | "outputs": [ 741 | { 742 | "data": { 743 | "text/plain": [ 744 | "(array([0.61206897, 0.42424242]),\n", 745 | " array([0.78888889, 0.23728814]),\n", 746 | " array([0.68932039, 0.30434783]),\n", 747 | " array([90, 59], dtype=int64))" 748 | ] 749 | }, 750 | "execution_count": 45, 751 | "metadata": {}, 752 | "output_type": "execute_result" 753 | } 754 | ], 755 | "source": [ 756 | "# for txt\n", 757 | "precision_recall_fscore_support(y_true, y_pred_txt, beta=1.0, labels=None, pos_label=1, average=None)" 758 | ] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": 46, 763 | "metadata": {}, 764 | "outputs": [ 765 | { 766 | "data": { 767 | "text/plain": [ 768 | "(array([0.60714286, 0.4 ]),\n", 769 | " array([0.56666667, 0.44067797]),\n", 770 | " array([0.5862069 , 0.41935484]),\n", 771 | " array([90, 59], dtype=int64))" 772 | ] 773 | }, 774 | "execution_count": 46, 775 | "metadata": {}, 776 | "output_type": "execute_result" 777 | } 778 | ], 779 | "source": [ 780 | "# com model\n", 781 | "precision_recall_fscore_support(y_true, y_pred_com, beta=1.0, labels=None, pos_label=1, average=None)" 782 | ] 783 | } 784 | ], 785 | "metadata": { 786 | "kernelspec": { 787 | "display_name": "Python 3", 788 | "language": "python", 789 | "name": "python3" 790 | }, 791 | "language_info": { 792 | "codemirror_mode": { 793 | "name": "ipython", 794 | "version": 3 795 | }, 796 | "file_extension": ".py", 797 | "mimetype": "text/x-python", 798 | "name": "python", 799 | "nbconvert_exporter": "python", 800 | "pygments_lexer": "ipython3", 801 | "version": "3.7.4" 802 | } 803 | }, 804 | "nbformat": 4, 805 | "nbformat_minor": 2 806 | } 807 | --------------------------------------------------------------------------------