Train using gradient

This commit is contained in:
Dominik Moritz Roth 2021-09-26 23:13:43 +02:00
parent 06a0461e93
commit 98aaec1e22
3 changed files with 44 additions and 40 deletions

View File

@ -373,7 +373,7 @@ def scoreOpinions(G, globMu, globStd):
def scoreUnread(G, globMu, globStd): def scoreUnread(G, globMu, globStd):
for n in list(G.nodes): for n in list(G.nodes):
feedbacks = [globMu] feedbacks = [globMu]
ws = [getWeightForType('mu')] ws = [['mu']]
node = G.nodes[n] node = G.nodes[n]
if node['t'] == 'book': if node['t'] == 'book':
if node['rating'] == None: if node['rating'] == None:
@ -381,7 +381,7 @@ def scoreUnread(G, globMu, globStd):
for adj in adjacens: for adj in adjacens:
adjNode = G.nodes[adj] adjNode = G.nodes[adj]
if 'score' in adjNode and adjNode['score'] != None: if 'score' in adjNode and adjNode['score'] != None:
w = getWeightForType(adjNode['t'], G[n][adj]['weight'] if 'weight' in G[n][adj] else 1) w = [adjNode['t'], G[n][adj]['weight'] if 'weight' in G[n][adj] else 1]
for fb in adjNode['feedbacks']: for fb in adjNode['feedbacks']:
feedbacks.append(fb) feedbacks.append(fb)
ws.append(w) ws.append(w)
@ -389,19 +389,20 @@ def scoreUnread(G, globMu, globStd):
node['mean'], node['std'] = norm.fit(feedbacks) node['mean'], node['std'] = norm.fit(feedbacks)
node['se'] = globStd / math.sqrt(len(feedbacks)) node['se'] = globStd / math.sqrt(len(feedbacks))
feedbacks.append(node['std']) feedbacks.append(node['std'])
ws.append(getWeightForType('sigma')) ws.append(['sigma'])
feedbacks.append(node['se']) feedbacks.append(node['se'])
ws.append(getWeightForType('se')) ws.append(['se'])
feedbacks.append(globMu) feedbacks.append(globMu)
ws.append(getWeightForType('bias')) ws.append(['bias'])
node['score'] = sum([fb*w for fb, w in zip(feedbacks, ws)])/sum(ws) node['score'] = sum([fb*getWeightForType(w[0], w[1] if len(w)>1 else 1) for fb, w in zip(feedbacks, ws)])/sum([getWeightForType(w[0], w[1] if len(w)>1 else 1) for w in ws])
node['_act'] = feedbacks
node['_wgh'] = ws
else: else:
node['score'] = globMu + errorFac*globStd + len(feedbacks)*0.0000000001 node['score'] = globMu + errorFac*globStd + len(feedbacks)*0.0000000001
if 'series' in node: if 'series' in node:
if node['series_index'] == 1.0: if node['series_index'] == 1.0:
node['score'] += 0.000000001 node['score'] += 0.000000001
# TODO: Make this neural and train it
def getWeightForType(nodeType, edgeWeight=1): def getWeightForType(nodeType, edgeWeight=1):
global weights global weights
w = weights[nodeType] w = weights[nodeType]
@ -789,6 +790,9 @@ def evaluateFitness(books, debugPrint=False):
boundsLoss = 0 boundsLoss = 0
linSepLoss = [] linSepLoss = []
errSq = [] errSq = []
gradient = {}
for wt in weights:
gradient[wt] = 0
mu, sigma = genScores(G, books) mu, sigma = genScores(G, books)
for b in G.nodes: for b in G.nodes:
if b in ratedBooks: if b in ratedBooks:
@ -800,6 +804,9 @@ def evaluateFitness(books, debugPrint=False):
else: else:
errSq.append((rating - G.nodes[b]['score'])**2) errSq.append((rating - G.nodes[b]['score'])**2)
G.nodes[b]['rating'] = rating G.nodes[b]['rating'] = rating
for wt in weights:
scoreB = sum([a*(1.001 if wt==w[0] else 1)*weights[w[0]]*(w[1] if len(w)>1 else 1) for a,w in zip(G.nodes[b]['_act'], G.nodes[b]['_wgh'])])/sum([(1.001 if wt==w[0] else 1)*weights[w[0]]*(w[1] if len(w)>1 else 1) for w in G.nodes[b]['_wgh']])
gradient[wt] += ((rating - G.nodes[b]['score'])**2 - (rating - scoreB)**2)*1000
if 'score' in G.nodes[b] and G.nodes[b]['score'] != None: if 'score' in G.nodes[b] and G.nodes[b]['score'] != None:
score = G.nodes[b]['score'] score = G.nodes[b]['score']
if score > 10.0: if score > 10.0:
@ -809,49 +816,45 @@ def evaluateFitness(books, debugPrint=False):
# reward seperation linearly # reward seperation linearly
linSepLoss.append(abs(score - mu)) linSepLoss.append(abs(score - mu))
regressionLoss = sum([(1-w)**2 for w in weights.values()]) regressionLoss = sum([(1-w)**2 for w in weights.values()])
for g in gradient:
gradient[g] /= len(errSq)
if debugPrint: if debugPrint:
print(sum(errSq)/len(errSq), 0.005*regressionLoss, 0.2*boundsLoss/len(ratedBooks), 1.0*sum(linSepLoss)/len(linSepLoss)) print(sum(errSq)/len(errSq), 0.005*regressionLoss, 0.2*boundsLoss/len(ratedBooks), 1.0*sum(linSepLoss)/len(linSepLoss))
return sum(errSq)/len(errSq) + 0.005*regressionLoss + 0.2*boundsLoss/len(ratedBooks) - 1.0*sum(linSepLoss)/len(linSepLoss) fit = sum(errSq)/len(errSq) + 0.005*regressionLoss + 0.2*boundsLoss/len(ratedBooks) - 1.0*sum(linSepLoss)/len(linSepLoss)
return fit, gradient
def train(gamma = 1, maxEmptySteps=-1): def train(gamma = 1, full=True):
global weights global weights
if full:
for wt in weights:
weights[wt] = random.random()
books = loadBooksFromDB() books = loadBooksFromDB()
bestWeights = copy.copy(weights) bestWeights = copy.copy(weights)
best_mse = evaluateFitness(books) mse, gradient = evaluateFitness(books)
w = list(weights.keys()) best_mse = mse
attr = random.choice(w) delta = 1
delta = gamma * (-0.5 + (0.75 + 0.25*random.random())) stagLen = 0
emptyStepsLeft = maxEmptySteps
while gamma > 1.0e-08: while gamma > 1.0e-06 and delta > 1.0e-06:
print({'mse': best_mse, 'w': weights, 'gamma': gamma}) last_mse = mse
weights = copy.copy(bestWeights) print({'mse': mse, 'w': weights, 'gamma': gamma, 'delta': delta})
if gamma < 0.01: print(gradient)
while random.random() < 0.5: delta = sum(gradient[g]**2 for g in gradient)
attr = random.choice(w) for wt in weights:
weights[attr] = -0.1+random.random()*1.5+random.random() weights[wt] += gamma*gradient[wt]
mse, gradient = evaluateFitness(books)
if mse < last_mse:
gamma = gamma*1.25
else: else:
weights[attr] += delta gamma *= 0.25
if attr not in ['sigma', 'mu', 'se']:
weights[attr] = min(max(0.0, weights[attr]), 5.0)
mse = evaluateFitness(books)
if mse < best_mse: if mse < best_mse:
saveWeights(weights) saveWeights(weights)
gamma = min(max(gamma*1.75, 0.01), 1)
bestWeights = copy.copy(weights) bestWeights = copy.copy(weights)
best_mse = mse
delta *= 2
if random.random() < 0.10:
attr = random.choice(w)
emptyStepsLeft = maxEmptySteps
else: else:
weights = copy.copy(bestWeights) stagLen += 1
gamma *= 0.8 if stagLen == 3 or mse > 100:
attr = random.choice(w) for wt in weights:
delta = gamma * (-0.5 + (0.75 + 0.25*random.random())) weights[wt] = random.random()
emptyStepsLeft -= 1
if emptyStepsLeft == 0:
return
def saveWeights(weights): def saveWeights(weights):
with open('neuralWeights.json', 'w') as f: with open('neuralWeights.json', 'w') as f:
@ -900,7 +903,7 @@ def cliInterface():
args = parser.parse_args() args = parser.parse_args()
if args.cmd=="train": if args.cmd=="train":
train(args.g, -1 if args.full else 32) train(args.g, args.full)
exit() exit()
G, books = buildFullGraph() G, books = buildFullGraph()

View File

@ -1 +1 @@
{"topList": 4.173476109103811, "recommender": 2.204400674657485, "author": 4.2062120384245425, "series": 0.086990081240546, "tag": 0.2896280973944825, "mu": 2.0656384571269544, "sigma": 0.25275483246754604, "se": 3.20651748273233, "bias": 1.2331776397132} {"topList": 4.605030088443722, "recommender": 3.3234411783311066, "author": 4.6589079802163855, "series": 0.6203580388042937, "tag": 0.6051529346000674, "mu": 1.3820384196729414, "sigma": 2.059654503148757, "se": 3.25936622066864, "bias": 1.9033827699091248}

1
neuralWeights.json.bak Normal file
View File

@ -0,0 +1 @@
{"topList": 4.173476109103811, "recommender": 2.204400674657485, "author": 4.2062120384245425, "series": 0.086990081240546, "tag": 0.2896280973944825, "mu": 2.0656384571269544, "sigma": 0.25275483246754604, "se": 3.20651748273233, "bias": 1.2331776397132}