# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Neural Network Training Proess

# Put these at the top of every notebook, to get automatic reloading and inline plotting
# %reload_ext autoreload
# %autoreload 2
# %matplotlib inline

# **Imports & Global variables list:**  
# A symbolic link is done to import FastAI v0.7 library, the target folder is named "fastai07"  
#
# NAME: nickname for our model, must match the folder name in DL folder  
# INP: Directory where we will read our input file  
# DIR: Directory where we'll save model and export our parameters  
# cat_vars: List of categorical variables in our model  
# cont_vars: List of continous variables in our model  
# QP: Quantization Parameter  
# Layers: Number of neurons per hidden layer in our network  
# Dropouts: Percentage of dropout rate per hidden layer  
# BN_use: Use batch normalization if set to True  

# +
from fastai07.structured import *
from fastai07.column_data import *

NAME='blowing'
INP='./DL'
DIR='./DL/{0}'.format(NAME)
cat_vars = ['Height', 'Width']
cont_vars = ['top_left', 'top_center', 'top_right', 'left', 'center', 'right', 
             'bottom_left', 'bottom_center', 'bottom_right']
maplist = [['top_left', 0], ['top_center', 1], ['top_right', 2], ['left', 3], ['center', 4], ['right', 5], 
         ['bottom_left', 6], ['bottom_center', 7], ['bottom_right', 8]]
QP=22
Layers=[22, 20]
Dropouts=[0.001, 0.01]
BN_use=True


# -

# **Helper Functions**:  
# In FastAI v0.7, there's a proc_df() function that does the following:  
# 1) Splits dependent variable "output" from the dataframe  
# 2) Normalizes the continuous variables  
# 3) Returns a mapper that holds the mean and std for normalization  
# 4) Categorizes the categorical variables  
# 5) Handles missing values  
#
# This function will be used in read_proc() process our data. Note that we don't have any missing values.

# +
# Read, normalize, and process Inputs and Outputs
def read_proc():
    df = pd.read_csv('{0}/SSE_{1}.csv'.format(INP, QP), names=cont_vars+cat_vars+['y'], nrows=200)
    for v in cat_vars: df[v] = df[v].astype('category').cat.as_ordered()
    for v in cont_vars: df[v] = df[v].astype('float32')
    df, y, nas, mapper = proc_df(df, 'y',do_scale=True)
    del nas
    for v in cat_vars: df[v] = df[v].astype('category').cat.as_ordered()
    for v in cont_vars: df[v] = df[v].astype('float32')
    cat_sz = [(c, len(df[c].cat.categories)+1) for c in cat_vars]
    # Rule of Thumb for embedding sizes "taken from FastAI course 2018"
    emb_szs = [(c, min(50, (c+1)//2)) for _,c in cat_sz]
    val_idx = get_cv_idxs(len(df), val_pct=0.2)
    return df, y, mapper, emb_szs, val_idx

# Export the Mean and STDev
# The target folder is: ./$DIR/$QP/
def export_mapper():
    mapper_df = pd.DataFrame(index=['mean', 'std'], columns=cont_vars)
    for column,i in maplist:
        mapper_df[column].loc['mean'] = np.float64(mapper.features[i][1].mean_)
        mapper_df[column].loc['std'] = np.float64(np.sqrt(mapper.features[i][1].var_))

    mapper_df.to_csv('{0}/{1}/mapper_{1}.csv'.format(DIR, QP), index=False, header=None, line_terminator=";\n")
    return

# Process and Save model
# The saved model is in the format: QP{qp}_{name}_{accuracy}
def save_model():
    log_preds, targs = m.predict_with_targs()
    preds = np.argmax(log_preds, axis=1)
    right = 0
    for i in range (len(preds)):
        if(preds[i] == targs[i]):
            right += 1
    acc = (right / len(preds)) * 100
    print("Validation accuracy: ", acc)
    name = "QP{0}_{1}_acc{2}".format(QP, NAME, round(acc, 2))
    m.save(name)
    return

# Export Weights and Biases for each layer
# The target folder is: ./$DIR/$QP/
def export_parameters():
    for i in range(len(m.model.bns)):
        pd.DataFrame(m.model.bns[i].weight.data.numpy()).to_csv('{0}/{1}/bns{2}-weight.csv'.format(DIR, QP, i), 
                                                                index=False, header=None , line_terminator=", ")
        pd.DataFrame(m.model.bns[i].bias.data.numpy()).to_csv('{0}/{1}/bns{2}-bias.csv'.format(DIR, QP, i), 
                                                              index=False, header=None , line_terminator=", ")
    for i in range(len(m.model.lins)):
        pd.DataFrame(m.model.lins[i].weight.data.numpy()).to_csv('{0}/{1}/lins{2}-weight.csv'.format(DIR, QP, i), 
                                                                 index=False, header=None, line_terminator=",\n")
        pd.DataFrame(m.model.lins[i].bias.data.numpy()).to_csv('{0}/{1}/lins{2}-bias.csv'.format(DIR, QP, i), 
                                                               index=False, header=None, line_terminator=", ")
    for i in range(len(m.model.embs)):
        pd.DataFrame(m.model.embs[i].weight.data.numpy()).to_csv('{0}/{1}/emb{2}-weight.csv'.format(DIR, QP, i), 
                                                                index=False, header=None, line_terminator=",\n")
    pd.DataFrame(m.model.outp.weight.data.numpy()).to_csv('{0}/{1}/outp-weight.csv'.format(DIR, QP), 
                                                          index=False, header=None, line_terminator=",\n")
    pd.DataFrame(m.model.outp.bias.data.numpy()).to_csv('{0}/{1}/outp-bias.csv'.format(DIR, QP), index=False, 
                                                        header=None, line_terminator=", ")
    pd.DataFrame(m.model.bn.weight.data.numpy()).to_csv('{0}/{1}/bn-weight.csv'.format(DIR, QP), index=False, 
                                                        header=None, line_terminator=", ")
    return


# -

# ## Deep Learning

# First, we read and process our input:

if 'df' in globals(): del df, y, mapper
df, y, mapper, emb_szs, val_idx = read_proc()
# Optional: export mapper for inference
# export_mapper()

# Create ModelData and Learner objects  
# The problem we're dealing with is a multi-class classification "output is one of 49 fractional locations", so in get_learner() function, we set is_multi= and is_reg= to False  
#

md = ColumnarModelData.from_data_frame(INP, val_idx, df, y, cat_flds=cat_vars, 
                                       bs=1024, is_multi=False, is_reg=False)
m = md.get_learner(emb_szs, len(df.columns) - len(cat_vars),
                   0.001, 49, Layers, Dropouts, use_bn=BN_use)
# Optional: Load previously saved model
# m.load('QP22_blowing_200_train_acc36.51')

# Run learning Rate Finder:  
# Plots the error for each learning rate, we choose the learning rate before the error starts flattening out "in our case, usually learning rate = 1e-3"

m.lr_find()
m.sched.plot()

# Fit the model for a specified number of epochs:

LR = 3e-3
m.fit(LR, 200, metrics=[accuracy])

# Save the model and Export parameters:

save_model()
export_parameters()

# Repeat for other Quantization Parameters:

for QP in [27, 32, 37]:
    if 'df' in globals(): del df, y, mapper
    df, y, mapper, emb_szs, val_idx = read_proc()
    export_mapper()
    md = ColumnarModelData.from_data_frame(INP, val_idx, df, y, cat_flds=cat_vars, 
                                           bs=1024, is_multi=False, is_reg=False)
    m = md.get_learner(emb_szs, len(df.columns) - len(cat_vars),
                       0.001, 49, Layers, Dropouts, use_bn=BN_use)
    m.fit(LR, 200, metrics=[accuracy])
    save_model()
    export_parameters()



StarcoderdataJupyterScriptsDedupFiltered