Skip to content
Snippets Groups Projects
network-test.py 8.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • johannes bilk's avatar
    johannes bilk committed
    import numpy as np
    import sys
    from matplotlib import pyplot as plt
    from nn.linear import Linear, Dropout, Flatten
    from nn.convolution2D import Convolution2D, Unsqueeze
    from nn.optim import SGD, SGDMomentum, NesterovMomentum, AdaGrad, AdaDelta, RMSprop, Adam
    from nn.scheduler import ExponentialLR, SteppedLR, CyclicalLR
    from nn.sequential import Sequential
    from nn.parallel import Parallel
    from nn.loss import CrossEntropyLoss, MSELoss, NLLLoss, MAELoss, FocalLoss
    from nn.activation import Tanh, SoftMax, Sigmoid, SoftPlus, Relu, Elu, LeakyRelu, SoftSign, Identity
    from data.data import Data
    from utility.timer import Time
    from nn.observable import NetworkObservables
    from metric.confusionMatrix import ConfusionMatrix
    from nn.batchNorm import BatchNorm1D, BatchNorm2D
    from utility.progressbar import Progressbar
    from settings.networkSettings import NetworkSettings
    
    
    def actiPicker(acti: str):
        if acti == 'tanh':
            return Tanh()
        elif acti == 'elu':
            return Elu()
        elif acti == 'relu':
            return Relu()
        elif acti == 'lrelu':
            return LeakyRelu()
        elif acti == 'sigmoid':
            return Sigmoid()
        elif acti == 'id':
            return Identity()
        elif acti == 'softplus':
            return SoftPlus()
        elif acti == 'softmax':
            return SoftMax()
        elif acti == 'softsign':
            return SoftSign()
    
    
    if __name__ == "__main__":
        settings = NetworkSettings()
        try:
            configFile = sys.argv[1]
            settings.getConfig(configFile)
            settings.setConfig()
        except IndexError:
            pass
        print(settings)
    
        # Initialize a timer to measure the runtime of different parts of the code
        timer = Time()
    
        # Loading some test data
        print("Importing data...\n")
        timer.start()
        data = Data(trainAmount=settings['trainAmount'], evalAmount=settings['validAmount'], batchSize=settings['batchSize'], kFold=settings['kFold'], dataPath=settings['dataPath'], normalize=settings['normalize'])
        #data.generateTestData(settings['numCategories'])
        data.inputFeatures(*settings['features'])
        data.importData(*settings['dataFiles'])
        print(data)
        timer.record("Importing Data")
    
        # Create and initialize the Network
        print("Setting up network")
        timer.start()
        # Configuring number of Neurons
    
        # Setting up Convolution
        network = Sequential()
        if len(settings['convolutions']) > 0:
            neurons = 0
            convolutions = Parallel()
            for key in settings['convolutions']:
                conv = Sequential()
                kernels = settings['kernelSize'][key]
                channels = settings['channels'][key]
                activations = settings['activationConv'][key]
                norms = settings['convNorm'][key]
                xSize, ySize = 9, 9
                for i, (inChan, outChan, kern, acti, norm) in enumerate(zip(channels, channels[1:], kernels, activations, norms)):
                    if i == 0:
                        conv.append(Unsqueeze((inChan, xSize, ySize)))
                    xSize = int((xSize - kern[0])/1 + 1)
                    ySize = int((ySize - kern[0])/1 + 1)
                    conv.append(Convolution2D(inChan, outChan, kern))
                    conv.append(actiPicker(acti))
                    if norm is True:
                        conv.append(BatchNorm2D((outChan, xSize, ySize)))
                neurons += (xSize * ySize * outChan)
                convolutions.append(conv)
            network.append(convolutions)
        else:
            neurons = settings['numNeurons'][0]
    
        # Adding Linear Layer
        network.append(Flatten())
        # this code is a bit ugly and I am not sure it will work under all conditions
        for i, (inFeat, outFeat, drop, acti, norm) in enumerate(zip(settings['numNeurons'], settings['numNeurons'][1:], settings['dropoutRate'], settings['activationLin'], settings['linearNorm'])):
            if i == 0:
                network.append(Linear(neurons,outFeat))
                network.append(Dropout(outFeat,drop))
                network.append(actiPicker(acti))
                if norm is True:
                    network.append(BatchNorm1D(outFeat))
            elif i == settings['numLayers'] - 1:
                network.append(Linear(inFeat,settings['numCategories']))
                network.append(SoftMax())
            else:
                network.append(Linear(inFeat,outFeat))
                network.append(Dropout(outFeat,drop))
                network.append(actiPicker(acti))
                if norm is True:
                    network.append(BatchNorm1D(outFeat))
    
        print(network)
        timer.record('Network setup')
    
        # Setting up loss func
        print("Setting up loss/optimizer")
        timer.start()
        if settings['lossFunction'] == 'entropy':
            lossFunc = CrossEntropyLoss()
        elif settings['lossFunction'] == 'nllloss':
            lossFunc = NLLLoss()
        elif settings['lossFunction'] == 'focalloss':
            lossFunc = FocalLoss()
        elif settings['lossFunction'] == 'mseloss':
            lossFunc = MSELoss()
        elif settings['lossFunction'] == 'maeloss':
            lossFunc = MAELoss()
    
        # Setting up opimizer
        if settings['optim'] == 'sgd':
            optim = SGD(network, settings['learningRate'])
        elif settings['optim'] == 'momentum':
            optim = SGDMomentum(network, settings['learningRate'], settings['momentum'])
        elif settings['optim'] == 'nesterov':
            optim = NesterovMomentum(network, settings['learningRate'], settings['momentum'])
        elif settings['optim'] == 'adagrad':
            optim = AdaGrad(network, settings['learningRate'])
        elif settings['optim'] == 'adadelta':
            optim = AdaDelta(network, settings['learningRate'])
        elif settings['optim'] == 'rmsprop':
            optim = RMSprop(network, settings['learningRate'])
        elif settings['optim'] == 'adam':
            optim = Adam(network, settings['learningRate'])
    
        # LR scheduler
        scheduler = None
        if settings['scheduler'] == 'exponential':
            scheduler = ExponentialLR(optim, settings['decayrate'])
        elif settings['scheduler'] == 'stepped':
            scheduler = SteppedLR(optim, settings['decayrate'], settings['stepSize'])
        elif settings['scheduler'] == 'else':
            scheduler = CyclicalLR(optim, 1/5, 15, 5)
        timer.record('Network setup')
        print(optim)
        print(lossFunc)
    
        # Beginn training
        print("Beginn training...")
        timer.start()
        metrics = NetworkObservables(settings['epochs'])
        epochs = settings['epochs']
        for i in range(settings['epochs']):
            data.trainMode()
            network.train()
            length = len(data.train)
            bar = Progressbar(f'epoch {str(i+1).zfill(len(str(epochs)))}/{epochs}', length, 55)
            losses = []
            for item in data.train:
                inputs = item['data']
                labels = item['labels']
                prediction = network(inputs)
                losses.append(lossFunc(prediction, labels))
                gradient = lossFunc.backward()
                optim.step(gradient)
                bar.step()
            data.evalMode()
            network.eval()
            accuracies = []
            valLosses = []
            for item in data.train:
                inputs = item['data']
                labels = item['labels']
                prediction = network(inputs)
                valLosses.append(lossFunc(prediction, labels))
                accuracies.append(np.sum(prediction.argmax(1) == labels.argmax(1)) / len(prediction))
                bar.step()
            if scheduler is not None:
                scheduler.step()
            metrics.update('losses', np.mean(losses))
            metrics.update('validation', np.mean(valLosses))
            metrics.update('accuracy', np.mean(accuracies))
            metrics.update('learningRate', optim.learningRate)
            metrics.print()
            metrics.step()
            data.fold()
            #bar.finish()
        timer.record('Training')
    
        # plotting training metrics
        fig, ax = plt.subplots()
        ax3 = ax.twinx()
        lns1 = ax.plot(metrics.losses.values, label='Train Loss')
        lns2 = ax.plot(metrics.validation.values, label='Eval Loss')
        lns3 = ax.plot(metrics.accuracy.values, label='Accuracy')
        lns4 = ax3.plot(metrics.learningRate.values, label='learning rate', color='tab:gray', ls='--')
    
        lns = lns1+lns2+lns3+lns4
        labs = [lab.get_label() for lab in lns]
        ax.legend(lns, labs)
    
        ax.grid(ls=':')
        plt.show()
    
        # evaluating on test data
        print("\nMaking predictions...")
        timer.start()
        confusion = ConfusionMatrix(settings['numCategories'])
        network.eval()
        length = len(data.eval)
        bar = Progressbar('evaluation', length)
        for item in data.eval:
            inputs = item['data']
            labels = item['labels']
            prediction = network(inputs)
            confusion.update(prediction, labels)
            bar.step()
    
        # Calculate and print confusion matrix
        confusion.percentages()
        confusion.calcScores()
        timer.record("Prediction")
        print()
        print(confusion)
        print()
    
        # Print total execution time
        print(timer)