from IPython.display import YouTubeVideo
YouTubeVideo('kQmHaI5Jw1c', width=800, height=450)

"""
Explanation: A Deeper Understanding of Deep Learning
Time for another mini-movie!
In this video, Dan introduces stochastic gradient descent (SGD) and back-propagation and explains how they are used to set the weights in a deep learning model.
End of explanation
"""


from IPython.display import YouTubeVideo
YouTubeVideo('YbNE3zhtsoo', width=800, height=450)

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from tensorflow.python import keras
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Flatten, Conv2D, Dropout

img_rows, img_cols = 28, 28
num_classes = 10

def data_prep(raw):
    out_y = keras.utils.to_categorical(raw.label, num_classes)
    num_images = raw.shape[0]
    x_as_array = raw.values[:, 1:]
    x_shaped_array = x_as_array.reshape(num_images, img_rows, img_cols, 1)
    out_x = x_shaped_array / 255
    return out_x, out_y

train_file = 'inputs/digit_recognizer/train.csv'
raw_data = pd.read_csv(train_file)
x, y = data_prep(raw_data)
print(x[0], y[0])

"""
Explanation: Here is the ReLU activation function link that Dan mentioned.
Now, get ready to train your own models from scratch.
Deep Learning From Scratch
End of explanation
"""


model = Sequential()
model.add(Conv2D(20, kernel_size=(3, 3),
                activation='relu',
                input_shape=(img_rows, img_cols, 1)))
model.add(Conv2D(20, kernel_size=(3, 3), activation='relu'))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

"""
Explanation: Let's build our model:
End of explanation
"""


model.compile(loss=keras.losses.categorical_crossentropy,
             optimizer='adam',
             metrics=['accuracy'])

model.fit(x, y,
         batch_size=128,
         epochs=2,
         validation_split=0.2)

"""
Explanation: Compile and fit:
End of explanation
"""


import numpy as np
from sklearn.model_selection import train_test_split
from tensorflow.python import keras

img_rows, img_cols = 28, 28
num_classes = 10

def prep_data(raw, train_size, val_size):
    y = raw[:, 0]
    out_y = keras.utils.to_categorical(y, num_classes)
    x = raw[:, 1:]
    num_images = raw.shape[0]
    out_x = x.reshape(num_images, img_rows, img_cols, 1)
    out_x = out_x / 255
    return out_x, out_y

fashion_file = 'inputs/fashionmnist/train.csv'
fashion_data = np.loadtxt(fashion_file, skiprows=1, delimiter=',')
x, y = prep_data(fashion_data, train_size=50000, val_size=5000)

"""
Explanation: You know the drill, practice makes perfect!
Exercise: Modeling from Scratch
You have seen how to build a model from scratch to identify handwritten digits.
Now it's time to build a model that can identify different types of clothing.
To make models that can be trained quickly, we'll work with low-resolution (and therefore small) images.
For example, the model will identify the image below as a shoe:

Data Preparation
End of explanation
"""


from tensorflow.python import keras
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Flatten, Conv2D

fashion_model = Sequential()
fashion_model.add(Conv2D(12, kernel_size = (3, 3),
                        activation='relu',
                        input_shape=(img_rows, img_cols, 1)))
fashion_model.add(Conv2D(12, kernel_size=(3,3), activation='relu'))
fashion_model.add(Conv2D(12, kernel_size=(3,3), activation='relu'))
fashion_model.add(Flatten())
fashion_model.add(Dense(100, activation='relu'))
fashion_model.add(Dense(num_classes, activation='softmax'))
fashion_model

"""
Explanation: Specify Model
STEPS:
1. Create a Sequential model. Call it fashion_model.
2. Add 3 Conv2D layers to fashion_model. Give each layer 12 filters, and specify a kernel_size of 3 and a relu activation. You will need to specify the input_shape for the first Conv2D layer. The input shape in this case is (img_rows, img_cols, 1).
3. Add a Flatten layer to fashion_model after the last Conv2D layer.
4. Add a Dense layer with 100 neurons to fashion_model after the Flatten layer.
5. Add your prediction layer to fashion_model. This is a Dense layer. We alrady have a variable called num_classes. Use this variable when specifying the number of nodes in this layer. The activation should be softmax (or you will have problems later).
End of explanation
"""


fashion_model.compile(loss=keras.losses.categorical_crossentropy,
                     optimizer='adam',
                     metrics=['accuracy'])

"""
Explanation: Compile Model
Run the command fashion_model.compile.
Specify the following arguments:
1. loss = keras.losses.categorical_crossentropy
2. optimizer = 'adam'
3. metrics = ['accuracy']
End of explanation
"""


fashion_model.fit(x, y,
                 batch_size=100,
                 epochs=4,
                 validation_split=0.2)

"""
Explanation: Fit Model
Run the command fashion_model.fit.
The arguments you will use are:
1. The first two are arguments are the data used to fit the model, which are x and y respectively.
2. batch_size = 100
3. epochs = 4
4. validation_split = 0.2  
When you run this command, you can watch your model start improving.
You will see validation accuracies after each epoch.
Go get 'em tiger. Roar!
End of explanation
"""


