#!/usr/bin/python3
"""
Author : "Ammar Qammaz"
Copyright : "2022 Foundation of Research and Technology, Computer Science Department Greece, See license.txt"
License : "FORTH"
"""
import os
import sys
import gc
import time
import json
import tensorflow as tf
from tensorflow import keras
#from tensorflow.keras.backend.tensorflow_backend import set_session
#from tensorflow.keras import backend as K
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import model_from_json
from tensorflow.keras.utils import plot_model
import tensorflow.keras.callbacks
import numpy as np
from numba import njit #Test
from tools import bcolors,checkIfFileExists
def printTrainingVersion():
print("""
███╗ ███╗ ██████╗ ██████╗ █████╗ ██████╗ ███╗ ██╗███████╗████████╗
████╗ ████║██╔═══██╗██╔════╝██╔══██╗██╔══██╗████╗ ██║██╔════╝╚══██╔══╝
██╔████╔██║██║ ██║██║ ███████║██████╔╝██╔██╗ ██║█████╗ ██║
██║╚██╔╝██║██║ ██║██║ ██╔══██║██╔═══╝ ██║╚██╗██║██╔══╝ ██║
██║ ╚═╝ ██║╚██████╔╝╚██████╗██║ ██║██║ ██║ ╚████║███████╗ ██║
╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
""")
#-----------------------------
#BMVC 21 paper was submitted with Keras 2.2.4/Tensorflow 1.14/Numpy 1.16.2
#-----------------------------
print("")
print("Tensorflow version : ",tf.__version__)
#print("Keras version : ",keras.__version__) <- no longer available in TF-2.13
print("Numpy version : ",np.__version__)
#-----------------------------
from tensorflow.python.platform import build_info as tf_build_info
print("TF/CUDA version : ",tf_build_info.build_info['cuda_version'])
print("TF/CUDNN version : ",tf_build_info.build_info['cudnn_version'])
#-----------------------------
print("")
#-----------------------------
def forceCPU():
print(bcolors.WARNING,"User selected to use CPU mode",bcolors.ENDC)
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" # see issue #152
os.environ["CUDA_VISIBLE_DEVICES"] = ""
def limitGPUMemory():
print("Limiting GPU memory usage for multiple instances..\n")
config = tf.compat.v1.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.2
config.gpu_options.visible_device_list = "0"
set_session(tf.compat.v1.Session(config=config))
def setTensorflowBackendToHalfFloats():
dtype='float16'
#WARNING:tensorflow:Mixed precision compatibility check (mixed_float16): WARNING
#Your GPU may run slowly with dtype policy mixed_float16 because it does not have compute capability
#of at least 7.0. Your GPU: Quadro P6000, compute capability 6.1
from tensorflow.keras.mixed_precision import experimental as mixed_precision
policy = mixed_precision.Policy('mixed_float16')
mixed_precision.set_policy(policy)
tf.keras.backend.set_floatx(dtype)
# default is 1e-7 which is too small for float16. Without adjusting the epsilon, we will get NaN predictions because of divide by zero problems
tf.keras.backend.set_epsilon(1e-4)
print('Compute dtype: %s' % policy.compute_dtype)
print('Variable dtype: %s' % policy.variable_dtype)
print("\nUsing Half-Floats for training ")
def getRSquared(groundTruth, neuralNetworkOutput):
"""
Computes the R-squared metric.
https://en.wikipedia.org/wiki/Coefficient_of_determination
Parameters:
-- groundTruth (numpy.ndarray): 1D array representing the ground truth.
-- neuralNetworkOutput (numpy.ndarray): 1D array representing the neural network output.
Returns:
-- float: R-squared metric.
"""
# Compute the mean of the ground truth
mean_ground_truth = np.mean(groundTruth)
# Compute the sum of squares of the residuals
ss_residuals = np.sum((groundTruth - neuralNetworkOutput) ** 2)
# Compute the sum of squares of the total variation
ss_total = np.sum((groundTruth - mean_ground_truth) ** 2)
# Compute the R-squared metric
r_squared = 1 - (ss_residuals / ss_total)
return r_squared
@njit
def getRSquaredInPlace(groundTruth,mean_ground_truth,N,neuralNetworkOutput):
"""
Computes the R-squared metric.
https://en.wikipedia.org/wiki/Coefficient_of_determination
Parameters:
-- groundTruth (numpy.ndarray): 1D array representing the ground truth.
-- neuralNetworkOutput (numpy.ndarray): 1D array representing the neural network output.
Returns:
-- float: R-squared metric.
"""
#N = groundTruth.shape[0]
if N == 0:
return np.NAN
# Compute the mean of the ground truth
#mean_ground_truth = np.mean(groundTruth)
ss_residuals = np.float32(0.0)
ss_total = np.float32(0.0)
for i in range(N):
#--------------------------------------
gt = np.float32(groundTruth[i][0]) #groundTruth is a tensorflow array so each element is also an array -> thus we need [0]
nn_out = np.float32(neuralNetworkOutput[i][0]) #neuralNetworkOutput is a tensorflow array so each element is also an array -> thus we need [0]
#--------------------------------------
delta = gt - nn_out
ss_residuals += delta ** 2
#--------------------------------------
delta = gt - mean_ground_truth
ss_total += delta ** 2
# Compute the R-squared metric
r_squared = np.float32(1 - (ss_residuals / ss_total))
return r_squared
def getRSquaredForNeuralNetwork(mocapNETNetwork,networkInput,groundtruthOutput):
import time
startAt = time.time()
#-----------------------------------------------------
try:
print("Extracting R² : Getting neural network response..")
predictions = mocapNETNetwork.predict(networkInput)
#Since the groundtruth is very large and the machines I use don't have
#enough RAM this is an in place R^2 calculation to make sure the computer doesn't enter a page swapping
#loop that makes training grind to a halt..!
print("Extracting R² : Calculating..")
mean_ground_truth = np.float32(np.mean(groundtruthOutput))
#print("groundtruthOutput: ",groundtruthOutput)
rSQ = getRSquaredInPlace(groundtruthOutput,mean_ground_truth,groundtruthOutput.shape[0],predictions)
#This is faster (if you have spare memory..)
#rSQ = getRSquared(groundtruthOutput,predictions)
del predictions
#except:
except Exception as e:
print("Failed to extract R² ..")
print("Error was : ",e)
rSQ = np.NAN
#-----------------------------------------------------
#-----------------------------------------------------
endAt = time.time()
print("R² = ",rSQ," it took ",(endAt-startAt)/60," mins to compute")
return rSQ
def logTrainingResults(
filename,
configuration,
outputType,
outputName,
history,
metrics
):
if (outputType==0):
numberOfModelParametersStr="?"
if 'modelParameters' in configuration:
numberOfModelParametersStr="%u" % int(configuration['modelParameters'])
#First record - Start of File
inputProcessing=""
if (configuration['eNSRM']):
inputProcessing=inputProcessing+" eNSRM"
if ('NSRMNormalizeAngles' in configuration) and (configuration['NSRMNormalizeAngles']):
if (configuration['NSRMNormalizeAngles']==1):
inputProcessing=inputProcessing+" NSRMNormalizeAngles" #Half
elif (configuration['NSRMNormalizeAngles']==2):
inputProcessing=inputProcessing+" NSRMNormalizeAnglesFull"
else:
inputProcessing=inputProcessing+" NSRMNormalizeAnglesUNKNOWN"
if (configuration['EDM']):
inputProcessing=inputProcessing+" EDM"
if (configuration['eigenPoses']):
inputProcessing=inputProcessing+" eigenPoses"
if (configuration['autobuilder']):
inputProcessing=inputProcessing+" autobuilder"
if ( (configuration['decompositionType']!="") and (configuration['doPCA']!="") and ( int(configuration['PCADimensionsKept'])>0 ) ):
inputProcessing=inputProcessing+" %s(%u)"%(configuration['decompositionType'],configuration['PCADimensionsKept'])
if (configuration['PCAAlsoKeepRawData']):
inputProcessing=inputProcessing+"+PCA_RawData"
inputProcessing=inputProcessing+" act("+configuration['activationFunction']+")"
inputProcessing=inputProcessing+" rand("+configuration['weightRandomizationFunction']+")"
inputProcessing=inputProcessing+" "+configuration['optimizer']
if (configuration['balanced2DInputs']):
inputProcessing=inputProcessing+" balanced2DInputs"
if (configuration['useQuadLoss']!=0):
inputProcessing=inputProcessing+" quadLoss"
if (configuration['setConstantSeedForReproducibleTraining']!=1):
inputProcessing=inputProcessing+" random seed"
if (configuration['include2DInputVisibilityFlags']==0):
inputProcessing=inputProcessing+" novis2Dflag"
experimentDescription=""
experimentDescription=experimentDescription+"group %u"%(configuration["groupOutputs"])
if (configuration['useRadians']):
experimentDescription=experimentDescription+" radians"
#--------------------------------------------------------------------
if ('outputValueDistribution' in configuration):
if (configuration['outputValueDistribution']=='balanced'):
experimentDescription=experimentDescription+" balanced offset"
elif (configuration['outputValueDistribution']=='positive'):
experimentDescription=experimentDescription+" positive offset"
elif (configuration['outputValueDistribution']=='negative'):
experimentDescription=experimentDescription+" negative offset"
#--------------------------------------------------------------------
if ('outputNormalizationStrategy' in configuration):
experimentDescription=experimentDescription+" outputNormalizationStrategy="+configuration['outputNormalizationStrategy']
#--------------------------------------------------------------------
if (float(configuration['outputMultiplier'])!=1.0):
experimentDescription=experimentDescription+" outputScaling=%0.2f" % float(configuration['outputMultiplier'])
experimentDescription=experimentDescription+" NNDepth=%u"%configuration['neuralNetworkDepth']
#FIRST! RECORD!
with open(filename, 'w') as f:
f.write("""
Training summary of experiment %s for %s
"""%(configuration['label'],configuration['hierarchyPartName']))
#Add the hostname..
import socket
f.write("%s
\n"%socket.gethostname())
f.write("""
| Date |
Part |
BatchSize |
Epochs |
λ |
Remember |
Occlusions |
Input Processing |
Hard Mining |
| %s |
%s |
%u |
%u/%u/%u |
%0.2f |
c %u/p %u |
%u |
%s |
|
"""% (
configuration['date'],
configuration['hierarchyPartName'],
configuration['defaultBatchSize'],
configuration["defaultNumberOfEpochs"],configuration["highNumberOfEpochs"],configuration["veryHighNumberOfEpochs"],
configuration["lamda"],
configuration["rememberConsecutiveWeights"],configuration["rememberWeights"],
configuration["ignoreOcclusions"]==0,
inputProcessing
)
)
f.write("""
| Serial |
Start |
End |
Training Samples |
Model Size |
Dropout/L.R |
Description |
| %s |
%u |
%u |
%u |
%s |
%0.2f/%0.5f |
%s |
| Joint |
R² / Start Loss / M.A.E |
R² / End Loss / M.A.E |
Tr.Epochs |
Min/Max |
Offset |
Scalar |
Scalar Fr. |
"""% (
configuration['label'],
configuration['startPosition'],
configuration['endPosition'],
configuration['trainingSamples'],
numberOfModelParametersStr,
configuration['dropoutRate'],
configuration['learningRate'],
experimentDescription
)
)
f.close()
#----------------------------------
try:
lowestLossAchievedAt = 0
if ("loss" in history.history) and ("mae" in history.history):
# Initialize variables to store the initial and lowest loss
initial_loss = history.history['loss'][0]
lowest_loss = initial_loss
initial_mae = history.history['mae'][0]
lowest_mae = initial_mae
# Iterate through the history object
count = 0
for i, loss in enumerate(history.history['loss']):
# Update the lowest loss if a lower value is found
if loss < lowest_loss:
lowest_loss = loss
lowestLossAchievedAt = count
count = count + 1
lowest_mae = history.history['mae'][lowestLossAchievedAt]
#By default don't scale
#----------------------------------------------------------------------------
outputMinimumValue = 0.0
outputMaximumValue = 0.0
outputOffsetValue = 0.0
outputScalarValues = 1.0
outputScalarFractionValues = 1.0
#----------------------------------------------------------------------------
for v in range(0,len(configuration["outputOffsetLabels"])):
if (outputName.lower()==configuration["outputOffsetLabels"][v].lower()):
#we found a rule!
outputMinimumValue = float(configuration["outputOffsetMinima"][v])
outputMaximumValue = float(configuration["outputOffsetMaxima"][v])
outputOffsetValue = float(configuration["outputOffsetValues"][v])
outputScalarValues = float(configuration["outputScalarValues"][v])
outputScalarFractionValues = float(configuration["outputScalarFractionValues"][v])
#----------------------------------------------------------------------------
initialVAL = ""
lowestVAL = ""
if ("val_loss" in history.history) and ("val_mae" in history.history):
initial_VALloss = history.history['val_loss'][0]
lowest_VALloss = history.history['val_loss'][lowestLossAchievedAt]
initial_VALmae = history.history['val_mae'][0]
lowest_VALmae = history.history['val_mae'][lowestLossAchievedAt]
initial_VALmae = initial_VALmae * outputScalarFractionValues
lowest_VALmae = lowest_VALmae * outputScalarFractionValues
#--------------------------------------
initialVAL = " - "
if ("test_rsquared_start" in metrics):
initialVAL = " - R² %0.2f/"%(metrics["test_rsquared_start"])
initialVAL = initialVAL + "%0.4f/%0.4f" % (initial_VALloss,initial_VALmae)
#--------------------------------------
lowestVAL = " - "
if ("test_rsquared_end" in metrics):
lowestVAL = " - R² %0.2f/"%(metrics["test_rsquared_end"])
lowestVAL = lowestVAL + "%0.4f/%0.4f" % (lowest_VALloss,lowest_VALmae)
#Every output now gets scaled always
initial_mae = initial_mae * outputScalarFractionValues
lowest_mae = lowest_mae * outputScalarFractionValues
with open(filename, 'a') as f:
f.write("| ")
f.write(outputName)
f.write(" | ")
#------------------------------------------------
#Start Loss
f.write("")
if ("train_rsquared_start" in metrics):
f.write("R² %0.2f/"%(metrics["train_rsquared_start"]))
f.write("%0.4f/%0.4f%s"%(initial_loss,initial_mae,initialVAL))
f.write(" | ")
#------------------------------------------------
#End Loss
f.write("")
if ("train_rsquared_end" in metrics):
f.write("R² %0.2f/"%(metrics["train_rsquared_end"]))
f.write("%0.4f/%0.4f%s"%(lowest_loss,lowest_mae,lowestVAL))
f.write(" | ")
#------------------------------------------------
#Training Epochs ----------------------------
f.write("")
f.write("%u"%(lowestLossAchievedAt))
f.write(" | ")
#Min/Max ----------------------------
f.write("")
f.write("%0.4f/%0.4f"%(outputMinimumValue,outputMaximumValue))
f.write(" | ")
#Offset -----------------------------
f.write("")
f.write("%0.4f"%(outputOffsetValue))
f.write(" | ")
#Scalar -----------------------------
f.write("")
f.write("%0.4f"%(outputScalarValues))
f.write(" | ")
f.write("")
f.write("%0.4f"%(outputScalarFractionValues))
f.write(" | ")
#------------------------------------------------
f.write("
")
f.close()
except:
print("An exception occurred in logTrainingResults")
def regularTraining(tensorboardLabel,mocapNETNetwork,numberOfEpochs,batchSize,earlyStoppingPatience,trainInput,trainOutput,testInput,testOutput,minD,modelIsTrivial=False,haveTestSet=False,useHalfFloats=False):
#We use a checkpoint system to return best model..
if (os.path.isfile("bestW.hdf5")):
print(bcolors.WARNING,"Found a forgotten checkpoint file, erasing it to avoid trouble",bcolors.ENDC)
os.system('rm bestW.hdf5')
#whatToMonitor='mean_absolute_error'
#minimumDelta=0.05
whatToMonitor='loss'
metrics = dict()
if (useHalfFloats):
print("Early stopping will use MAE instead of loss due to half floats..")
whatToMonitor='mae'
minimumDelta=minD
#To see use :
#tensorboard --logdir step0_upperbody_all/tensorboard --bind_all
#------------------------------------------------------------------------
tensorboard = keras.callbacks.TensorBoard(log_dir=tensorboardLabel,histogram_freq=1)
#------------------------------------------------------------------------
earlystopper = keras.callbacks.EarlyStopping(
monitor=whatToMonitor,
min_delta=minimumDelta,
patience=earlyStoppingPatience,
verbose=1,
mode='auto'
)
#-------------------------------------------------------------------------
checkpointer = keras.callbacks.ModelCheckpoint(
filepath="bestW.hdf5",
monitor=whatToMonitor,
mode='min',
verbose=1,
save_freq='epoch',
save_best_only=True,
save_weights_only=True
)
#------------------------------------------------------------------------
callbacks = [
earlystopper,
checkpointer,
tensorboard
]
#------------------------------------------------------------------------
print("regularTraining begins -> BatchSize=%u / NumberOfEpochs=%u "%(batchSize,numberOfEpochs))
#------------------------------------------------------------------------
if (haveTestSet==False):
#Train without any test data ( probably to conserve memory )
if (not modelIsTrivial):
metrics["train_rsquared_start"] = getRSquaredForNeuralNetwork(mocapNETNetwork,trainInput,trainOutput)
history = mocapNETNetwork.fit(
trainInput,trainOutput,
epochs=numberOfEpochs,
batch_size=batchSize,
shuffle=True,
#steps_per_epoch=5, #<- Use more steps per epoch?
callbacks=callbacks
)
if (not modelIsTrivial):
metrics["train_rsquared_end"] = getRSquaredForNeuralNetwork(mocapNETNetwork,trainInput,trainOutput)
else:
#Train with test data
if (not modelIsTrivial):
metrics["train_rsquared_start"] = getRSquaredForNeuralNetwork(mocapNETNetwork,trainInput,trainOutput)
metrics["test_rsquared_start"] = getRSquaredForNeuralNetwork(mocapNETNetwork,testInput,testOutput)
history = mocapNETNetwork.fit(
trainInput,trainOutput,
epochs=numberOfEpochs,
batch_size=batchSize,
shuffle=True,
validation_data=(testInput,testOutput),
#validation_split=0.2,
callbacks=callbacks
)
if (not modelIsTrivial):
metrics["train_rsquared_end"] = getRSquaredForNeuralNetwork(mocapNETNetwork,trainInput,trainOutput)
metrics["test_rsquared_end"] = getRSquaredForNeuralNetwork(mocapNETNetwork,testInput,testOutput)
#------------------------------------------------------------------------
if (checkIfFileExists('bestW.hdf5')):
print("We use the best possible model from our ModelCheckpoint")
mocapNETNetwork.load_weights('bestW.hdf5')
os.system('rm bestW.hdf5') #Get rid of the checkpoint as soon as we are done reading it
else:
print("No bestW.hdf5 file found, just using last iteration..")
#------------------------------------------------------------------------
return history,mocapNETNetwork,metrics
#-------------------------------------------------------------------------------------------------------------------------------------------------
def compareTrainingOutputs(groundTruth,neuralOutput):
if (len(groundTruth)!=len(neuralOutput)):
print("Outputs have a different size")
return np.nan
values = len(groundTruth)
losses = (groundTruth[:]-neuralOutput[:])**2
return losses
#----------------------------------------------------
def appendHistory(baseHistory,historyToAppend):
#print("baseHistory -> ",type(baseHistory))
#print("baseHistory Contents -> ",baseHistory)
#print("historyToAppend -> ",type(historyToAppend))
#print("historyToAppend Contents -> ",historyToAppend)
#print("baseHistory.history -> ",type(baseHistory.history))
#print("historyToAppend.history -> ",type(historyToAppend.history))
#-----------------------------------------------------------------------------------------------------------
if ("mae" in baseHistory.history) and ("mae" in historyToAppend.history):
baseHistory.history['mae'] = baseHistory.history['mae'] + historyToAppend.history['mae']
if ("loss" in baseHistory.history) and ("loss" in historyToAppend.history):
baseHistory.history['loss'] = baseHistory.history['loss'] + historyToAppend.history['loss']
if ("val_loss" in baseHistory.history) and ("val_loss" in historyToAppend.history):
baseHistory.history['val_loss'] = baseHistory.history['val_loss'] + historyToAppend.history['val_loss']
if ("val_mae" in baseHistory.history) and ("val_mae" in historyToAppend.history):
baseHistory.history['val_mae'] = baseHistory.history['val_mae'] + historyToAppend.history['val_mae']
#-----------------------------------------------------------------------------------------------------------
return baseHistory
def getLossManually(mocapNETNetwork,trainInput,trainOutput):
predictions = mocapNETNetwork.predict(trainInput)
losses = compareTrainingOutputs(predictions,trainOutput)
#print(losses)
print("Calculating Loss Statistics :")
#--------------------------
maximum = np.max(losses)
minimum = np.min(losses)
median = np.median(losses)
mean = np.mean(losses)
from tools import calculateStandardDeviationInPlaceKnowingMean,convertStandardDeviationToVariance
std = calculateStandardDeviationInPlaceKnowingMean(losses,mean) #np.std(losses)
var = convertStandardDeviationToVariance(std) #np.var(losses)
#--------------------------
titleString="Min=%0.2f,Max=%0.2f,Median=%0.2f,Mean=%0.2f,Std=%0.2f,Var=%0.2f" % (minimum,maximum,median,mean,std,var)
print(bcolors.WARNING," %s " % titleString,bcolors.ENDC)
#difficultyRating = 1.5
difficultyRating = 5.0 # 4.0 1.5 2.8
badScoreAbove = mean + difficultyRating * np.sqrt(std)
print("Threshold for difficult poses is ",badScoreAbove)
difficultPosesIndexes=list()
numberOfTrainingSamples = len(trainInput)
for z in range(0,numberOfTrainingSamples):
if (np.any(losses[z]>badScoreAbove)):
difficultPosesIndexes.append(z)
del losses
return difficultPosesIndexes,mean,std
def onlineHardExampleMiningTraining(tensorboardLabel,mocapNETNetwork,numberOfEpochs,numberOfHardEpochs,numberOfNormalEpochsAfterHard,batchSize,earlyStoppingPatience,trainInput,trainOutput,testInput,testOutput,minD,modelIsTrivial=False,haveTestSet=False,useHalfFloats=False):
#First do a regular training..
halfEpochs=int(numberOfEpochs/2)
if (numberOfEpochs==1):
halfEpochs=numberOfEpochs
print(" Online Hard Example Mining Training session .. ")
metrics = dict()
if (not modelIsTrivial):
metrics["train_rsquared_start"] = getRSquaredForNeuralNetwork(mocapNETNetwork,trainInput,trainOutput)
dtypeSelected=np.float32
if (useHalfFloats):
dtypeSelected=np.float16
totalHistory,mocapNETNetwork = regularTraining(tensorboardLabel,mocapNETNetwork,halfEpochs,batchSize,earlyStoppingPatience,trainInput,trainOutput,testInput,testOutput,minD,haveTestSet=haveTestSet,useHalfFloats=useHalfFloats)
if (numberOfEpochs==1):
print(" Trivial output will not mine etc. ")
return totalHistory
bestTrainingMAE=0.0
successfulUpdates=0
REGULAR_EPOCHS_AFTER_HARD=numberOfNormalEpochsAfterHard
HARD_EPOCHS=numberOfHardEpochs
miningEpochs = int(halfEpochs/2)
print("Getting initial state of network")
difficultPosesIndexes,mean,std = getLossManually(mocapNETNetwork,trainInput,trainOutput)
print("Backing up model with mae ",mean)
mocapNETNetwork.save_weights("modelBackup.h5")
bestTrainingMAE=mean
for i in range(0,miningEpochs):
#-------------------------------------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------------------------------------
numberOfTrainingSamples = len(trainInput)
inputSize = len (trainInput[1])
outputSize = len (trainOutput[1])
ratioOfDatasetThatIsDifficult = float ( len(difficultPosesIndexes) / numberOfTrainingSamples )
#If more than 10% of the dataset is difficult
if (ratioOfDatasetThatIsDifficult>0.5):
print(bcolors.FAIL," More than half of the dataset is hard (%u samples) so we train on all samples as hard %u/%u" % (len(difficultPosesIndexes),i,miningEpochs),bcolors.ENDC)
regularHistory,mocapNETNetwork = regularTraining(tensorboardLabel,mocapNETNetwork,HARD_EPOCHS,batchSize,5,trainInput,trainOutput,testInput,testOutput,minD,haveTestSet=haveTestSet,useHalfFloats=useHalfFloats) #difficultInput,difficultOutput
totalHistory = appendHistory(totalHistory,regularHistory)
elif (ratioOfDatasetThatIsDifficult>0.1):
difficultInput = np.full([len(difficultPosesIndexes),inputSize],fill_value=0,dtype=dtypeSelected,order='C')
difficultOutput = np.full([len(difficultPosesIndexes),outputSize],fill_value=0,dtype=dtypeSelected,order='C')
for z in range(0,len(difficultPosesIndexes)):
for field in range(0,inputSize):
difficultInput[z,field]=trainInput[difficultPosesIndexes[z],field]
for field in range(0,outputSize):
difficultOutput[z,field]=trainOutput[difficultPosesIndexes[z],field]
print(bcolors.OKBLUE," Will now train on %u difficult samples %u/%u" % (len(difficultPosesIndexes),i,miningEpochs),bcolors.ENDC)
newHistory,mocapNETNetwork = regularTraining(tensorboardLabel,mocapNETNetwork,HARD_EPOCHS,batchSize,5,difficultInput,difficultOutput,testInput,testOutput,minD,haveTestSet=haveTestSet,useHalfFloats=useHalfFloats)
totalHistory = appendHistory(totalHistory,newHistory)
del difficultInput
del difficultOutput
if (mean