metaData, meta2, mCounts = bc.load_training_metadata(trainDataPath, balanceViaRemoval=True, verbose=True, 
                                                     normalVsAbnormal=normalVsAbnormal)

# Actually load some representative data for model experimentation
maxData = len(metaData)
X_data, Y_data = bc.load_data(trainDataPath, trainImagePath, 
                              categories=categories,
                              maxData = maxData, 
                              verboseFreq = 50, 
                              imgResize=imgResize, 
                              thesePathos=thesePathos,
                              normalVsAbnormal=normalVsAbnormal)
print X_data.shape
print Y_data.shape

"""
Explanation: Load Training and Test Data
In this section, the training/validation data is loaded. The load_data function pre-balances the data set by removing images from over-represented emotion classes.
Training Data
End of explanation
"""


# Actually load some representative data for model experimentation
maxData = len(metaData)
X_test, Y_test = bc.load_data(testDataPath, imagePath, 
                              categories=categories,
                              maxData = maxData, 
                              verboseFreq = 50, 
                              imgResize=imgResize, 
                              thesePathos=thesePathos,
                              normalVsAbnormal=normalVsAbnormal)
print X_test.shape
print Y_test.shape

"""
Explanation: Load Test Set
End of explanation
"""


imgDataGenCount = 3
transformCount = imgDataGenCount

newImgs = np.zeros([X_data.shape[0] * transformCount, X_data.shape[1], X_data.shape[2]])
newYs = np.zeros([Y_data.shape[0] * transformCount, Y_data.shape[1]], dtype=np.int8)
print newImgs.shape
print newYs.shape

img = X_data[0]
img.shape

ndx = 0
for i in range(X_data.shape[0]):
    img = X_data[i]
   
    for n in range(imgDataGenCount):
            imgX = models.imageDataGenTransform(img, Y_data[i])
            imgX = imgX.reshape(150, 150)
            
            #print imgX.shape
            newImgs[ndx] = imgX
            newYs[ndx] = Y_data[i]
            #misc.imsave("testX.png", imgX)
            ndx += 1    
    
    #break
    
print("Done", str(datetime.datetime.now()))

X_data2 = np.concatenate((X_data, newImgs))
Y_data2 = np.concatenate((Y_data, newYs))
print X_data2.shape
print Y_data2.shape

performedTransforms = True
if performedTransforms:
    X_train = X_data2
    Y_train = Y_data2
else:
    X_train = X_data
    Y_train = Y_data

"""
Explanation: Transformations
In this section, we will apply transformations to the existing images to increase of training data, as well as add a bit of noise in the hopes of improving the overall training activities.
End of explanation
"""


print X_train.shape
print X_test.shape

print Y_train.shape
print Y_test.shape

import collections
def yDist(y):
    bcCounts = collections.defaultdict(int)
    for a in range(0, y.shape[0]):
        bcCounts[y[a][0]] += 1
    return bcCounts

print "Y_train Dist: " + str(yDist(Y_train))
print "Y_test Dist: " + str(yDist(Y_test))


"""
Explanation: Training/Test Set Distribution
The following code segment splits the data into training and test data sets. Currently this is a standard 80/20 split for training and test respectively after performing a random shuffle using the unison_shuffled_copies help method.
End of explanation
"""


# Load the bc array for our count in the model definition
print categories
print len(categories)

del sys.modules['bc_models']

# Construct the model using our help function
import bc_models as models
model = models.bc_model_v03(len(categories), verbose=True, 
                                        input_shape=(1,X_train.shape[1],X_train.shape[2]))

"""
Explanation: Define and Load Trained Model
End of explanation
"""


loadWeights = False
weightsFileName = "dwdii-bc-v03-150-normVsAbnorm-13970-20170510.hdf5"
if loadWeights:
    model.load_weights('weights/' + weightsFileName)

# Reshape to the appropriate shape for the CNN input
testX = X_test.reshape(X_test.shape[0], 1, X_test.shape[1],X_test.shape[2])
trainX = X_train.reshape(X_train.shape[0], 1, X_train.shape[1],X_train.shape[2])

print "Training start: " + str(datetime.datetime.now())
m, losses, acc = models.run_network([trainX, testX, Y_train, Y_test], model, batch=50, epochs=20, verbosity=1)

models.plot_losses(losses, acc)

fileLossesPng = '../../figures/plot_losses-' + weightsFileName + '.png'
plt.savefig(fileLossesPng)

model.save_weights('weights/' + weightsFileName, overwrite=True)

"""
Explanation: Training the Model
The following code segment trains the model using the run_network helper function.
End of explanation
"""


resultsValAcc = {}
#resultsValAcc["1"] = 0.6800
#resultsValAcc["2"] = 0.7260
#resultsValAcc["3"] = 0.6616
#resultsValAcc["03-27-2017"] = 0.6116
#resultsValAcc["04-02-2017"] = 0.4805
#resultsValAcc["04-03-2017"] = 0.5065
#resultsValAcc["04-05-2017"] = 0.5243
resultsValAcc[924] = 0.5628
resultsValAcc[2737] = 0.6326
resultsValAcc[5474] = 0.6138
import dwdii_test as dwdii
#cmp = matplotlib.colors.Colormap("Blues")
dwdii.barChart(resultsValAcc, filename="../../figures/shallowCnn_thresholded_2class_results_valacc.png", title="Shallow CNN - DDSM Data Thresholded 2 Class Test Accuracy", yAxisLabel="Accuracy %")

"""
Explanation: Experiment Results
Raw DDSM Images
Initial results based on "normal" being masked as "benign":
* bc_model_v0 (150x150, 800/200): 182s - loss: 0.0560 - acc: 0.9813 - val_loss: 1.9918 - val_acc: 0.6800
* bc_model_v0 (150x150, 2000/500): 473s - loss: 0.0288 - acc: 0.9925 - val_loss: 1.4040 - val_acc: 0.7260
   * somewhat balanced, Y_train Dist {0: 1223, 1: 777}, Y_test Dist: {0: 321, 1: 179}
Revised with "normal", "benign" and "malignant" labeled seperately:
* bc_model_v0 (150x150, 1311/328): 298s - loss: 0.0411 - acc: 0.9786 - val_loss: 1.3713 - val_acc: 0.6616
After creating fixed "train", "test" and "validate" data sets, using "train" and "test" as well as including the DDSM Benign cases:
* bc_model_v0 (150x150, 1554/363, 03.27.2017): 264s - loss: 0.0512 - acc: 0.9730 - val_loss: 1.3120 - val_acc: 0.6116
* bc_model_v0 (150x150, 2155/539, 04.02.2017): 362s - loss: 0.0600 - acc: 0.9763 - val_loss: 1.5315 - val_acc: 0.4805
bc_model_v01 - categorical_crossentropy
* bc_model_v01 (150x150, 2155/539, 04.03.2017): 361s - loss: 0.0935 - acc: 0.9800 - val_loss: 2.7872 - val_acc: 0.5065
* bc_model_v01 (150x150, 2132/536, 04.05.2017): 369s - loss: 0.0718 - acc: 0.9794 - val_loss: 2.5604 - val_acc: 0.5243
Thresholded Images
Using the "Data_Thresholded" images
* bc_model_v0 (150x150, Thresholded, 661/171, 03.28.2017): 124s - loss: 0.0529 - acc: 0.9743 - val_loss: 1.4331 - val_acc: 0.4971
Simulated Images
Using the "simulated_images" images
* bc_model_v01 (150x150, 7776/536, 04.24.2017): 1250s - loss: 0.5543 - acc: 0.7885 - val_loss: 7.1153 - val_acc: 0.4123
Using the "simulated_images_new" images
* bc_model_v01 (150x150, 7776/536, 04.30.2017): 1242s - loss: 10.1318 - acc: 0.3714 - val_loss: 6.7477 - val_acc: 0.3340
Normal Vs Abnormal
Raw

bc_model_v01 (150x150, 2893/536, 04.25.2017):  496s - loss: 0.0522 - acc: 0.9865 - val_loss: 2.2328 - val_acc: 0.6309
bc_model_v03 (150x150, 11572/726, 05.10.2017, 30 epochs): 2938s - loss: 0.1378 - acc: 0.9468 - val_loss: 1.6165 - val_acc: 0.6061
40 epochs (+10): 2987s - loss: 0.1092 - acc: 0.9615 - val_loss: 2.0735 - val_acc: 0.6157
60 epochs (+20): 3728s - loss: 0.0767 - acc: 0.9766 - val_loss: 2.5044 - val_acc: 0.6074



Data Thresholded

bc_model_v01 (150x150, 924/231,04.26.2017): 154s - loss: 0.0365 - acc: 0.9892 - val_loss: 1.9738 - val_acc: 0.5628
bc_model_v01 (150x150, 2737/694,04.29.2017): 463s - loss: 0.0390 - acc: 0.9898 - val_loss: 2.4042 - val_acc: 0.6326
bc_model_v01 ((150x150, 5474/694,04.30.2017)): 1317s - loss: 0.0552 - acc: 0.9845 - val_loss: 2.8678 - val_acc: 0.6138

Benign Vs Malignant
Raw

bc_model_v01 (150x150, 13970/321, 05.05.2017, 50 epochs): 4376s - loss: 0.0163 - acc: 0.9961 - val_loss: 3.1204 - val_acc: 0.6480
bc_model_v02 (1 dropout, 13970/321, 05.06.2017, 30 epochs): 4678s - loss: 0.0222 - acc: 0.9941 - val_loss: 2.9720 - val_acc: 0.6978
bc_model_v03 (2 dropout, 13970/321, 05.07.2017, 30 epochs): 4771s - loss: 0.0419 - acc: 0.9896 - val_loss: 2.4619 - val_acc: 0.6667
35 Epochs (+5): 5833s - loss: 0.0355 - acc: 0.9911 - val_loss: 2.6903 - val_acc: 0.6667
45 Epochs (+10): 4686s - loss: 0.0355 - acc: 0.9908 - val_loss: 2.7548 - val_acc: 0.7165
End of explanation
"""


predictOutput = model.predict(testX, batch_size=32, verbose=1)

predClass = np.array(predictOutput[0]).argmax()
numBC = bc.reverseDict(categories)
numBC[predClass]

numBC[Y_test[0][0]]

predClasses = []
for i in range(len(predictOutput)):

    arPred = np.array(predictOutput[i])
    predictionProb = arPred.max()
    predictionNdx = arPred.argmax()
    predClassName = numBC[predictionNdx]
    predClasses.append(predictionNdx)

    #print "{0}: {1} ({2})".format(i, predClassName, predictionProb)

"""
Explanation: Analyze Predictions with Test Set
End of explanation
"""


# Use sklearn's helper method to generate the confusion matrix
cnf_matrix = skm.confusion_matrix(Y_test, predClasses)
cnf_matrix

class_names = numBC.values()
print class_names[1:3]
print class_names
np.set_printoptions(precision=2)

# Plot non-normalized confusion matrix
fileCfMatrix = '../../figures/confusion_matrix-' + weightsFileName + '.png'
plt.figure()
bc.plot_confusion_matrix(cnf_matrix, classes=class_names,
                      title='Confusion matrix, without normalization, \n' + weightsFileName)
plt.savefig(fileCfMatrix)

# Load the image we just saved
from IPython.display import Image
Image(filename=fileCfMatrix)

# Plot normalized confusion matrix
fileCfMatrixNorm = '../../figures/confusion_matrix_norm-' + weightsFileName + '.png'
plt.figure()
bc.plot_confusion_matrix(cnf_matrix, classes=class_names, normalize=True,
                      title='Normalized confusion matrix \n' + weightsFileName)
plt.savefig(fileCfMatrixNorm)

# Load the image we just saved
from IPython.display import Image
Image(filename=fileCfMatrixNorm)

"""
Explanation: Confusion Matrix
End of explanation
"""


