"""
# $\color{ORANGE}{\text{U-NET IN STEEL   }}$

![maninsteel](https://wallpapercave.com/wp/Me1VNXE.jpg)
"""
#Libraries mostly torch
import os
import json

import cv2
import keras
from keras import backend as K
from keras.models import Model
from keras.layers import Input
from keras.layers.convolutional import Conv2D, Conv2DTranspose
from keras.layers.pooling import MaxPooling2D
from keras.layers.merge import concatenate
from keras.losses import binary_crossentropy
from keras.callbacks import Callback, ModelCheckpoint
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from tqdm import tqdm
from sklearn.model_selection import train_test_split
from glob import glob

%matplotlib inline
import numpy as np
import pandas as pd
import cv2
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import os
import keras
from keras.preprocessing.image import ImageDataGenerator
from keras import backend as K
from keras.layers import GlobalAveragePooling2D, Dense, Conv2D, BatchNormalization, Dropout
from keras.models import Model, load_model 
import gc
!pip install segmentation-models
!pip install git+https://github.com/qubvel/segmentation_models

trainImgPath = "/kaggle/input/severstal-steel-defect-detection/train_images/"
trainCsv = "/kaggle/input/severstal-steel-defect-detection/train.csv"
data=pd.read_csv(trainCsv)
data.ClassId=data.ClassId.astype(int)

train_Img_Id = []
train_class_Id = []
for i in os.listdir(trainImgPath):
    for j in range(1,5):
        train_Img_Id.append(i)
        train_class_Id.append(j)
train_Imgs = pd.DataFrame({'ImageId':train_Img_Id,'ClassId':train_class_Id})
train_Imgs.head(10)
 
train_data = pd.merge(train_Imgs,data ,how='outer', on=['ImageId','ClassId']) 
train_data = train_data.fillna('') 
train_data
train_data = pd.pivot_table(train_data, values='EncodedPixels', index='ImageId',columns='ClassId', aggfunc=np.sum).astype(str)
train_data = train_data.reset_index() # add Index column to one level with classID   
train_data.columns = ['ImageId','Defect_1','Defect_2','Defect_3','Defect_4'] 
has_defect = []
stratify = []
for index,row in train_data.iterrows():
    if row.Defect_1 or row.Defect_2 or row.Defect_3 or row.Defect_4: 
        has_defect.append(1)
    else:
        has_defect.append(0) 
    if row.Defect_1 != '':
        stratify.append(1)
    elif row.Defect_2 != '':
        stratify.append(2)
    elif row.Defect_3:
        stratify.append(3)
    elif row.Defect_4:
        stratify.append(4)
    else:
        stratify.append(0)
        
train_data["has_defect"] = has_defect 
train_data["stratify"] = stratify 

train_data.head(5) 
WIDTH=288
HEIGHT=288
TRAINING_SIZE=7095

x_train, x_test = train_test_split(train_data, test_size = 0.1, stratify=train_data['stratify'], random_state=42)
x_train, x_val = train_test_split(x_train, test_size = 0.2, stratify = x_train['stratify'], random_state=42)
print(x_train.shape, x_val.shape, x_test.shape) 
x_train_classification = x_train[['ImageId','has_defect']]
x_val_classification = x_val[['ImageId','has_defect']]
x_test_classification = x_test[['ImageId','has_defect']] 
print(x_train_classification.shape , x_val_classification.shape,x_test_classification.shape)
x_train_classification.head()
from keras.preprocessing.image import ImageDataGenerator 
train_datagen = ImageDataGenerator(rescale=1./255., shear_range=0.2, zoom_range=0.05, rotation_range=5,
                           width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True, vertical_flip=True)

test_datagen = ImageDataGenerator(rescale=1./255)

train_data_generator = train_datagen.flow_from_dataframe(
        dataframe=x_train_classification.astype(str),
        directory=trainImgPath,
        x_col="ImageId",
        y_col="has_defect",
        target_size=(WIDTH,HEIGHT),
        batch_size=16,
        class_mode='binary') 

valid_data_generator = test_datagen.flow_from_dataframe(
        dataframe=x_val_classification.astype(str),
        directory=trainImgPath,
        x_col="ImageId",
        y_col="has_defect",
        target_size=(WIDTH,HEIGHT),
        batch_size=16,
        class_mode='binary') 
"""
The UNET was developed by Olaf Ronneberger et al.[1] for Bio Medical Image Segmentation. The architecture contains two paths. First path is the contraction path (also called as the encoder) which is used to capture the context in the image. The encoder is just a traditional stack of convolutional and max pooling layers. The second path is the symmetric expanding path (also called as the decoder) which is used to enable precise localization using transposed convolutions. Thus it is an end-to-end fully convolutional network. it only contains Convolutional layers and does not contain any Dense layer because of which it can accept image of any size. 

*[1]Ronneberger, O., Fischer, P., & Brox, T. (2015, October). U-net: Convolutional networks for biomedical image segmentation. In International Conference on Medical image computing and computer-assisted intervention (pp. 234-241). Springer, Cham.*

![unet](https://pubs.rsc.org/image/article/2020/ra/c9ra05877j/c9ra05877j-f1_hi-res.gif)
"""
Classification_Model = keras.applications.xception.Xception(include_top = False, input_shape = (HEIGHT,WIDTH,3))

layer = Classification_Model.output
layer = GlobalAveragePooling2D()(layer)

layer = Dense(1024, activation='relu')(layer)
layer = BatchNormalization()(layer)
layer = Dropout(0.3)(layer)

layer = Dense(512, activation='relu')(layer)
layer = BatchNormalization()(layer)
layer = Dropout(0.3)(layer)

layer = Dense(64, activation='relu')(layer)
predictions = Dense(1, activation='sigmoid')(layer)
model = Model(inputs=Classification_Model.input, outputs=predictions)
model.summary()
model.compile(optimizer='adam', loss='binary_crossentropy',metrics=['accuracy'])
Training = model.fit_generator(train_data_generator, validation_data = valid_data_generator, epochs = 30, verbose=1)