From eac56f983d90f7dc846db1397ca1a8bb12d1bb62 Mon Sep 17 00:00:00 2001 From: "E. Almqvist" Date: Tue, 20 Oct 2020 15:51:40 +0200 Subject: [PATCH] Made the AILib into a module --- rgbAI/lib/ailib/__pycache__/ai.cpython-38.pyc | Bin 0 -> 4648 bytes rgbAI/lib/ailib/ai.py | 165 +++++++++++++++++ rgbAI/lib/func.py | 166 ------------------ rgbAI/main.py | 2 +- 4 files changed, 166 insertions(+), 167 deletions(-) create mode 100644 rgbAI/lib/ailib/__pycache__/ai.cpython-38.pyc create mode 100644 rgbAI/lib/ailib/ai.py delete mode 100644 rgbAI/lib/func.py diff --git a/rgbAI/lib/ailib/__pycache__/ai.cpython-38.pyc b/rgbAI/lib/ailib/__pycache__/ai.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa2344de7cd910272901498e9be0dfed05e42a35 GIT binary patch literal 4648 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 literal 0 HcmV?d00001 diff --git a/rgbAI/lib/ailib/ai.py b/rgbAI/lib/ailib/ai.py new file mode 100644 index 0000000..afa9348 --- /dev/null +++ b/rgbAI/lib/ailib/ai.py @@ -0,0 +1,165 @@ +import numpy as np +from copy import deepcopy as copy + +def sigmoid(x): + return 1/(1 + np.exp(-x)) + +def correctFunc(inp:np.array): # generates the correct answer for the AI + return np.asarray( [1.0 - inp[0], 1.0 - inp[1], 1.0 - inp[2]] ) # basically invert the rgb values + +def calcCost( predicted:np.array, correct:np.array ): # cost function, lower -> good, higher -> bad, bad bot, bad + costSum = 0 + maxLen = len(correct) + + for i in range(maxLen): + costSum += abs((predicted[i] - correct[i])) + + return costSum / maxLen + +def getThinkCost( inp:np.array, predicted:np.array ): + corr = correctFunc(inp) + return calcCost( predicted, corr ) + +def genRandomMatrix( x:int, y:int, min: float=0.0, max: float=1.0 ): # generate a matrix with x, y dimensions with random values from min-max in it + # apply ranger with * and - + mat = np.random.rand(x, y) - 0.25 + return mat + +def think( inp:np.array, obj, layerIndex: int=0 ): # recursive thinking, hehe + maxLayer = len(obj.weights) - 1 + weightedLayer = np.dot( inp, obj.weights[layerIndex] ) # dot multiply the input and the weights + layer = sigmoid( np.add(weightedLayer, obj.bias[layerIndex]) ) # add the biases + + if( layerIndex < maxLayer ): + return think( layer, obj, layerIndex + 1 ) + else: + out = np.squeeze(np.asarray(layer)) + return out + +def propDer( dCost, dProp ): + # Calculate the partial derivative for that prop + return dCost / dProp + +def compareAIobjects( inp, obj1, obj2 ): + # Compare the two instances + res1 = think( inp, obj1 ) + cost1 = getThinkCost( inp, res1 ) # get the cost + + res2 = think( inp, obj2 ) + cost2 = getThinkCost( inp, res2 ) # get the second cost + + # Actually calculate stuff + dCost = cost2 - cost1 + return dCost, cost1 + +def compareInstanceWeight( obj, inp, theta:float, layerIndex:int, neuronIndex_X:int, neuronIndex_Y:int ): + # Create new a instance of the object + obj2 = copy(obj) # annoying way to create a new instance of the object + + obj2.weights[layerIndex][neuronIndex_X][neuronIndex_Y] += theta # mutate the second objects neuron + dCost, curCost = compareAIobjects( inp, obj, obj2 ) # compare the two and get the dCost with respect to the weights + + return dCost, curCost + +def compareInstanceBias( obj, inp, theta:float, layerIndex:int, biasIndex:int ): + obj2 = copy(obj) + + obj2.bias[layerIndex][0][biasIndex] += theta # do the same thing for the bias + dCost, curCost = compareAIobjects( inp, obj, obj2 ) + + return dCost, curCost + +def getChangeInCost( obj, inp, theta, layerIndex ): + mirrorObj = copy(obj) + + # Fill the buffer with None so that the dCost can replace it later + dCost_W = np.zeros( shape = mirrorObj.weights[layerIndex].shape ) # fill it with a placeholder + dCost_B = np.zeros( shape = mirrorObj.bias[layerIndex].shape ) + + # Get the cost change for the weights + weightLenX = len(dCost_W) + weightLenY = len(dCost_W[0]) + + for x in range(weightLenX): # get the dCost for each x,y + for y in range(weightLenY): + dCost_W[x][y], curCostWeight = compareInstanceWeight( obj, inp, theta, layerIndex, x, y ) + + # Get the cost change for the biases + biasLenY = len(dCost_B[0]) + for index in range(biasLenY): + dCost_B[0][index], curCostBias = compareInstanceBias( obj, inp, theta, layerIndex, index ) + + return dCost_W, dCost_B, (curCostBias + curCostWeight)/2 + + + +def gradient( inp:np.array, obj, theta:float, maxLayer:int, layerIndex: int=0, grads=None, obj1=None, obj2=None ): # Calculate the gradient for that prop + # Check if grads exists, if not create the buffer + if( not grads ): + grads = [None] * (maxLayer+1) + + dCost_W, dCost_B, meanCurCost = getChangeInCost( obj, inp, theta, layerIndex ) + + # Calculate the gradient for the layer + weightDer = propDer( dCost_W, theta ) + biasDer = propDer( dCost_B, theta ) + + # Append the gradients to the list + grads[layerIndex] = { + "weight": weightDer, + "bias": biasDer + } + + newLayer = layerIndex + 1 + if( newLayer <= maxLayer ): + return gradient( inp, obj, theta, maxLayer, newLayer, grads, obj1, obj2 ) + else: + return grads, dCost_W, dCost_B, meanCurCost + +def calculateSteepness( cost:float, gradient:np.matrix ): + gradLen = np.linalg.norm( gradient ) # basically calculate the hessian but transform the gradient into a scalar (its length) + ddCost = cost / gradLen + + return np.arcsin( ddCost ) / 180 # the gradients "angle" cannot become steeper than 180. + +def getLearningRate( cost:float, gradient:dict, maxLen:int ): + learningrate = { + "weight": [], + "bias": [] + } + + for i in range(maxLen): + learningrate["weights"][i] = calculateSteepness( cost, gradient["weight"][i] ) + learningrate["bias"][i] = calculateSteepness( cost, gradient["bias"][i] ) + + +def mutateProps( inpObj, curCost:float, maxLen:int, gradient:list ): + obj = copy(inpObj) + + for i in range(maxLen): + obj.weights[i] -= getLearningRate( curCost, gradient[i]["weight"], maxLen ) * gradient[i]["weight"] # mutate the weights + obj.bias[i] -= getLearningRate( curCost, gradient[i]["weight"], maxLen ) * gradient[i]["bias"] + + return obj + +def learn( inputNum:int, targetCost:float, obj, theta:float, curCost: float=None ): + # Calculate the derivative for: + # Cost in respect to weights + # Cost in respect to biases + + # i.e. : W' = W - lr * gradient (respect to W in layer i) = W - lr*[ dC / dW[i] ... ] + # So if we change all the weights with i.e. 0.01 = theta, then we can derive the gradient with math and stuff + + inp = np.asarray(np.random.rand( 1, inputNum ))[0] # create a random learning sample + + while( not curCost or curCost > targetCost ): # targetCost is the target for the cost function + maxLen = len(obj.bias) + grads, costW, costB, curCost = gradient( inp, obj, theta, maxLen - 1 ) + + obj = mutateProps( obj, curCost, maxLen, grads ) # mutate the props for next round + print(f"Cost: {curCost}") + + + print("DONE\n") + print(obj.weights) + print(obj.bias) diff --git a/rgbAI/lib/func.py b/rgbAI/lib/func.py deleted file mode 100644 index da0b9a2..0000000 --- a/rgbAI/lib/func.py +++ /dev/null @@ -1,166 +0,0 @@ -import numpy as np -from copy import deepcopy as copy - -class AIlib: - def sigmoid(x): - return 1/(1 + np.exp(-x)) - - def correctFunc(inp:np.array): # generates the correct answer for the AI - return np.asarray( [1.0 - inp[0], 1.0 - inp[1], 1.0 - inp[2]] ) # basically invert the rgb values - - def calcCost( predicted:np.array, correct:np.array ): # cost function, lower -> good, higher -> bad, bad bot, bad - costSum = 0 - maxLen = len(correct) - - for i in range(maxLen): - costSum += abs((predicted[i] - correct[i])) - - return costSum / maxLen - - def getThinkCost( inp:np.array, predicted:np.array ): - corr = AIlib.correctFunc(inp) - return AIlib.calcCost( predicted, corr ) - - def genRandomMatrix( x:int, y:int, min: float=0.0, max: float=1.0 ): # generate a matrix with x, y dimensions with random values from min-max in it - # apply ranger with * and - - mat = np.random.rand(x, y) - 0.25 - return mat - - def think( inp:np.array, obj, layerIndex: int=0 ): # recursive thinking, hehe - maxLayer = len(obj.weights) - 1 - weightedLayer = np.dot( inp, obj.weights[layerIndex] ) # dot multiply the input and the weights - layer = AIlib.sigmoid( np.add(weightedLayer, obj.bias[layerIndex]) ) # add the biases - - if( layerIndex < maxLayer ): - return AIlib.think( layer, obj, layerIndex + 1 ) - else: - out = np.squeeze(np.asarray(layer)) - return out - - def propDer( dCost, dProp ): - # Calculate the partial derivative for that prop - return dCost / dProp - - def compareAIobjects( inp, obj1, obj2 ): - # Compare the two instances - res1 = AIlib.think( inp, obj1 ) - cost1 = AIlib.getThinkCost( inp, res1 ) # get the cost - - res2 = AIlib.think( inp, obj2 ) - cost2 = AIlib.getThinkCost( inp, res2 ) # get the second cost - - # Actually calculate stuff - dCost = cost2 - cost1 - return dCost, cost1 - - def compareInstanceWeight( obj, inp, theta:float, layerIndex:int, neuronIndex_X:int, neuronIndex_Y:int ): - # Create new a instance of the object - obj2 = copy(obj) # annoying way to create a new instance of the object - - obj2.weights[layerIndex][neuronIndex_X][neuronIndex_Y] += theta # mutate the second objects neuron - dCost, curCost = AIlib.compareAIobjects( inp, obj, obj2 ) # compare the two and get the dCost with respect to the weights - - return dCost, curCost - - def compareInstanceBias( obj, inp, theta:float, layerIndex:int, biasIndex:int ): - obj2 = copy(obj) - - obj2.bias[layerIndex][0][biasIndex] += theta # do the same thing for the bias - dCost, curCost = AIlib.compareAIobjects( inp, obj, obj2 ) - - return dCost, curCost - - def getChangeInCost( obj, inp, theta, layerIndex ): - mirrorObj = copy(obj) - - # Fill the buffer with None so that the dCost can replace it later - dCost_W = np.zeros( shape = mirrorObj.weights[layerIndex].shape ) # fill it with a placeholder - dCost_B = np.zeros( shape = mirrorObj.bias[layerIndex].shape ) - - # Get the cost change for the weights - weightLenX = len(dCost_W) - weightLenY = len(dCost_W[0]) - - for x in range(weightLenX): # get the dCost for each x,y - for y in range(weightLenY): - dCost_W[x][y], curCostWeight = AIlib.compareInstanceWeight( obj, inp, theta, layerIndex, x, y ) - - # Get the cost change for the biases - biasLenY = len(dCost_B[0]) - for index in range(biasLenY): - dCost_B[0][index], curCostBias = AIlib.compareInstanceBias( obj, inp, theta, layerIndex, index ) - - return dCost_W, dCost_B, (curCostBias + curCostWeight)/2 - - - - def gradient( inp:np.array, obj, theta:float, maxLayer:int, layerIndex: int=0, grads=None, obj1=None, obj2=None ): # Calculate the gradient for that prop - # Check if grads exists, if not create the buffer - if( not grads ): - grads = [None] * (maxLayer+1) - - dCost_W, dCost_B, meanCurCost = AIlib.getChangeInCost( obj, inp, theta, layerIndex ) - - # Calculate the gradient for the layer - weightDer = AIlib.propDer( dCost_W, theta ) - biasDer = AIlib.propDer( dCost_B, theta ) - - # Append the gradients to the list - grads[layerIndex] = { - "weight": weightDer, - "bias": biasDer - } - - newLayer = layerIndex + 1 - if( newLayer <= maxLayer ): - return AIlib.gradient( inp, obj, theta, maxLayer, newLayer, grads, obj1, obj2 ) - else: - return grads, dCost_W, dCost_B, meanCurCost - - def calculateSteepness( cost:float, gradient:np.matrix ): - gradLen = np.linalg.norm( gradient ) # basically calculate the hessian but transform the gradient into a scalar (its length) - ddCost = cost / gradLen - - return np.arcsin( ddCost ) / 180 # the gradients "angle" cannot become steeper than 180. - - def getLearningRate( cost:float, gradient:dict, maxLen:int ): - learningrate = { - "weight": [], - "bias": [] - } - - for i in range(maxLen): - learningrate["weights"][i] = AIlib.calculateSteepness( cost, gradient["weight"][i] ) - learningrate["bias"][i] = AIlib.calculateSteepness( cost, gradient["bias"][i] ) - - - def mutateProps( inpObj, curCost:float, maxLen:int, gradient:list ): - obj = copy(inpObj) - - for i in range(maxLen): - obj.weights[i] -= AIlib.getLearningRate( curCost, gradient[i]["weight"], maxLen ) * gradient[i]["weight"] # mutate the weights - obj.bias[i] -= AIlib.getLearningRate( curCost, gradient[i]["weight"], maxLen ) * gradient[i]["bias"] - - return obj - - def learn( inputNum:int, targetCost:float, obj, theta:float, curCost: float=None ): - # Calculate the derivative for: - # Cost in respect to weights - # Cost in respect to biases - - # i.e. : W' = W - lr * gradient (respect to W in layer i) = W - lr*[ dC / dW[i] ... ] - # So if we change all the weights with i.e. 0.01 = theta, then we can derive the gradient with math and stuff - - inp = np.asarray(np.random.rand( 1, inputNum ))[0] # create a random learning sample - - while( not curCost or curCost > targetCost ): # targetCost is the target for the cost function - maxLen = len(obj.bias) - grads, costW, costB, curCost = AIlib.gradient( inp, obj, theta, maxLen - 1 ) - - obj = AIlib.mutateProps( obj, curCost, maxLen, grads ) # mutate the props for next round - print(f"Cost: {curCost}") - - - print("DONE\n") - print(obj.weights) - print(obj.bias) diff --git a/rgbAI/main.py b/rgbAI/main.py index 3042392..84b095c 100755 --- a/rgbAI/main.py +++ b/rgbAI/main.py @@ -1,6 +1,6 @@ #!/usr/bin/env python import numpy as np -from lib.func import AIlib as ai +from lib.ailib import ai class rgb(object): def __init__(self, loadedWeights: np.matrix=None, loadedBias: np.matrix=None):