# Program introduction

According to the game data of the hero League, this experiment builds a fully connected network classification model, optimizes the number of nodes and dropout probability of the neural network with particle swarm optimization algorithm, and finally compares the prediction accuracy of the default model and the optimized model on the game results of the hero League

Particle swarm optimization (PSO) is an evolutionary computing technology, which originates from the study of bird predation behavior. The basic idea of particle swarm optimization algorithm is to find the optimal solution through the cooperation and information sharing among individuals in the group. Its advantages are fast convergence and simple implementation, while its disadvantages are easy to fall into local optimization

# code analysis

Import module

```from tensorflow.keras.layers import Input,Dense,Dropout,Activation
import matplotlib.pyplot as plt
from tensorflow.keras.models import Model
from sklearn.metrics import accuracy_score
import pandas as pd
import numpy as np
import json
from copy import deepcopy
```

The data is the 10 minute battle situation of each game of the hero League. The opponent of the hero League is divided into red and blue sides. blueWins refers to whether the blue side wins. Other columns are basically Bruce Lee, wild monster and economy. Forgive me for my unclear explanation... When I was in graduate school, I was promoted to silver. I had to be scolded every game because of the loading problem. By the way, I always installed girls and played auxiliary games in it, because there were fewer people scolding me. My friends were full. So it was not me that was wrong, but the world

```data = pd.read_csv("Static/high_diamond_ranked_10min.csv").iloc[:,1:]
print("Data size:",data.shape)
print("Show the first 5 rows and columns of data")
```
```Data size: (9879, 39)
Show the first 5 rows and columns of data
```
blueWins blueWardsPlaced blueWardsDestroyed blueFirstBlood blueKills
0 0 28 2 1 9
1 0 12 1 0 5
2 0 15 0 0 7
3 0 43 1 0 4
4 0 75 4 0 6

Cut the data set into training, verification and testing. Here, only the verification set is used for PSO tuning, and the best checkpoint is not saved for neural network training

```data = data.sample(frac=1.0)#Scramble data
trainData = data.iloc[:6000]#Training set
xTrain = trainData.values[:,1:]
yTrain = trainData.values[:,:1]
valData = data.iloc[6000:8000]#Validation set
xVal = valData.values[:,1:]
yVal = valData.values[:,:1]
testData = data.iloc[8000:]#Test set
xTest = testData.values[:,1:]
yTest = testData.values[:,:1]
```

One particle is one scheme. In this experiment, one particle is an array (number of nodes and dropout probability). PSO is the process of calculating the fitness of each particle's corresponding scheme and finding the most suitable scheme. The following PSO class will iterate the particles according to the characteristics of the particles to be optimized, and support the characteristics of decimal or integer. If it is a self-determined discrete interval, it can be in the fitness function, The fitness of illegal particles is given a penalty value. After instantiating this class, it is necessary to specify the fitness function to iterate the particle scheme to the iterate function. The particle swarm optimization algorithm in this experiment is the simplest form, and the update formula is as follows:

```class PSO():
def __init__(self,featureNum,featureArea,featureLimit,featureType,particleNum=5,epochMax=10,c1=2,c2=2):
'''
Particle swarm optimization
:param featureNum: Particle characteristic number
:param featureArea: Characteristic upper and lower bound matrix
:param featureLimit: The upper and lower boundary of the feature is also the opening and closing of the interval. 0 is excluded and 1 is included
:param featureType: Feature type int float
:param particleNum: Number of particles
:param epochMax: Maximum number of iterations
:param c1: Self cognitive learning factor
:param c2: Group cognitive learning factor
'''
#As shown above
self.featureNum = featureNum
self.featureArea = np.array(featureArea).reshape(featureNum,2)
self.featureLimit = np.array(featureLimit).reshape(featureNum,2)
self.featureType = featureType
self.particleNum = particleNum
self.epochMax = epochMax
self.c1 = c1
self.c2 = c2
self.epoch = 0#Number of iterations
#Self optimal fitness record
self.pBest = [-1e+10 for i in range(particleNum)]
self.pBestArgs = [None for i in range(particleNum)]
#Global optimal fitness record
self.gBest = -1e+10
self.gBestArgs = None
#Initialize all particles
self.particles = [self.initParticle() for i in range(particleNum)]
#Initializes the learning speed of all particles
self.vs = [np.random.uniform(0,1,size=featureNum) for i in range(particleNum)]
#Iteration history
self.gHistory = {"features%d"%i:[] for i in range(featureNum)}
self.gHistory["Intra group average"] = []
self.gHistory["global optimum "] = []

def standardValue(self,value,lowArea,upArea,lowLimit,upLimit,valueType):
'''
Normalize an eigenvalue to fall within the interval
:param value: characteristic value
:param lowArea: lower limit
:param upArea: upper limit
:param lowLimit: Lower limit opening and closing interval
:param upLimit: Upper limit opening and closing interval
:param valueType: Feature type
:return: Corrected value
'''
if value < lowArea:
value = lowArea
if value > upArea:
value = upArea
if valueType is int:
value = np.round(value,0)

#The lower limit is a closed interval
if value <= lowArea and lowLimit==0:
value = lowArea + 1
#The upper limit is a closed interval
if value >= upArea and upLimit==0:
value = upArea - 1
elif valueType is float:
#The lower limit is a closed interval
if value <= lowArea and lowLimit == 0:
value = lowArea + 1e-10
#Upper limit = closed
if value >= upArea and upLimit==0:
value = upArea - 1e-10
return value

def initParticle(self):
'''Initialize 1 particle randomly'''
values = []
#Initialize so many features
for i in range(self.featureNum):
#Upper and lower limits of the feature
lowArea = self.featureArea[i][0]
upArea = self.featureArea[i][1]
#The upper and lower bounds of this feature
lowLimit = self.featureLimit[i][0]
upLimit = self.featureLimit[i][1]
#Random value
value = np.random.uniform(0,1) * (upArea-lowArea) + lowArea
value = self.standardValue(value,lowArea,upArea,lowLimit,upLimit,self.featureType[i])
values.append(value)
return values

def iterate(self,calFitness):
'''
Start iteration
:param calFitness:The input of fitness function is all features and global best fitness of a particle, and the output is fitness
'''
while self.epoch<self.epochMax:
self.epoch += 1
for i,particle in enumerate(self.particles):
#The fitness of the particle
fitness = calFitness(particle,self.gBest)
#Update the particle's own cognitive best solution
if self.pBest[i] < fitness:
self.pBest[i] = fitness
self.pBestArgs[i] = deepcopy(particle)
#Update global best practices
if self.gBest < fitness:
self.gBest = fitness
self.gBestArgs = deepcopy(particle)
#Update particle
for i, particle in enumerate(self.particles):
#Update speed
self.vs[i] = np.array(self.vs[i]) + self.c1*np.random.uniform(0,1,size=self.featureNum)*(np.array(self.pBestArgs[i])-np.array(self.particles[i])) + self.c2*np.random.uniform(0,1,size=self.featureNum)*(np.array(self.gBestArgs)-np.array(self.particles[i]))
#Update eigenvalue
self.particles[i] = np.array(particle) + self.vs[i]
#Canonical eigenvalue
values = []
for j in range(self.featureNum):
#Upper and lower limits of the feature
lowArea = self.featureArea[j][0]
upArea = self.featureArea[j][1]
#The upper and lower bounds of this feature
lowLimit = self.featureLimit[j][0]
upLimit = self.featureLimit[j][1]
#Random value
value =self.particles[i][j]
value = self.standardValue(value,lowArea,upArea,lowLimit,upLimit,self.featureType[j])
values.append(value)
self.particles[i] = values
#Save historical data
for i in range(self.featureNum):
self.gHistory["features%d"%i].append(self.gBestArgs[i])
self.gHistory["Intra group average"].append(np.mean(self.pBest))
self.gHistory["global optimum "].append(self.gBest)
print("PSO epoch:%d/%d Intra group average:%.4f global optimum :%.4f"%(self.epoch,self.epochMax,np.mean(self.pBest),self.gBest))

```

buildNet function constructs a simple fully connected classification network according to the number of network nodes and dropout probability. Its input feature number is 38 and the output feature number is 1 (of course, super parameters such as network layer number and learning rate can also be selected for optimization. In order to facilitate learning, only these two super parameters are selected for experiment) and trains the network

```def buildNet(nodeNum,p):
'''
Build a fully connected network for training, return the model and training history, verify the accuracy of the set and test the accuracy of the set
:param nodeNum: Number of network nodes
:param p: dropout probability
'''
#38 game features of input layer
inputLayer = Input(shape=(38,))

#Middle layer
middle = Dense(nodeNum)(inputLayer)
middle = Dropout(p)(middle)

#Output layer II Classification
outputLayer = Dense(1,activation="sigmoid")(middle)

#Model II Classification loss
model = Model(inputs=inputLayer,outputs=outputLayer)
model.compile(optimizer=optimizer,loss="binary_crossentropy",metrics=['acc'])

#train
history = model.fit(xTrain,yTrain,verbose=0,batch_size=1000,epochs=100,validation_data=(xVal,yVal)).history

#Validation set accuracy
valAcc = accuracy_score(yVal,model.predict(xVal).round(0))
#Test set accuracy
testAcc = accuracy_score(yTest,model.predict(xTest).round(0))
return model,history,valAcc,testAcc
```

In order to compare with the optimized model, we train a neural network with default parameters. Its super parameter value is the average value of each super parameter interval, and train and print the network structure and training index

```nodeArea = [10,200]#Node number interval
pArea = [0,0.5]#dropout probability interval
#Training a neural network according to interval average
nodeNum = int(np.mean(nodeArea))
p = np.mean(pArea)
defaultNet,defaultHistory,defaultValAcc,defaultTestAcc = buildNet(nodeNum,p)
defaultNet.summary()
print("\n Number of nodes in the default network:%d dropout probability:%.2f Validation set accuracy:%.4f Test set accuracy:%.4f"%(nodeNum,p,defaultValAcc,defaultTestAcc))
```
```Model: "model_346"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_347 (InputLayer)       [(None, 38)]              0
_________________________________________________________________
dense_691 (Dense)            (None, 105)               4095
_________________________________________________________________
dropout_346 (Dropout)        (None, 105)               0
_________________________________________________________________
dense_692 (Dense)            (None, 1)                 106
=================================================================
Total params: 4,201
Trainable params: 4,201
Non-trainable params: 0
_________________________________________________________________

Number of nodes in the default network:105 dropout probability:0.25 Validation set accuracy:0.6535 Test set accuracy:0.6578
```

Instantiate the PSO model, input the interval information and start the iteration. The fitness function is to input 1 each particle and the global optimal fitness, and return the accuracy of the verification set of the corresponding scheme of the particle

```featureNum = 2#2 features to be optimized
featureArea = [nodeArea,pArea]#2 characteristic value ranges
featureLimit = [[1,1],[0,1]]#The opening and closing of the value range 0 is the closed interval and 1 is the open interval
featureType = [int,float]#Type of 2 features
#Particle swarm optimization class
pso = PSO(featureNum,featureArea,featureLimit,featureType)
def calFitness(particle,gBest):
'''Fitness function, input an array of particles and the global optimal fitness, and return the fitness corresponding to the particle'''
nodeNum,p = particle#Take out the eigenvalues of particles
net,history,valAcc,testAcc = buildNet(nodeNum,p)
#The particle scheme exceeds the global optimum
if valAcc>gBest:
#Save model and corresponding information
net.save("Static/best.h5")
history = pd.DataFrame(history)
history.to_excel("Static/best.xlsx",index=None)
with open("Static/info.json","w") as f:
f.write(json.dumps({"valAcc":valAcc,"testAcc":testAcc}))
return valAcc
#Start swimming with particle swarm optimization
pso.iterate(calFitness)
#Load the best model and the corresponding training history
with open("Static/info.json","r") as f:
bestValAcc = float(info["valAcc"])
bestTestAcc = float(info["testAcc"])
print("Accuracy of verification set of optimal model:%.4f Test set accuracy:%.4f"%(bestValAcc,bestTestAcc))
```
```PSO epoch:1/10 Intra group average:0.7210 global optimum :0.7280
PSO epoch:2/10 Intra group average:0.7210 global optimum :0.7280
PSO epoch:3/10 Intra group average:0.7251 global optimum :0.7280
PSO epoch:4/10 Intra group average:0.7275 global optimum :0.7350
PSO epoch:5/10 Intra group average:0.7275 global optimum :0.7350
PSO epoch:6/10 Intra group average:0.7299 global optimum :0.7350
PSO epoch:7/10 Intra group average:0.7313 global optimum :0.7350
PSO epoch:8/10 Intra group average:0.7313 global optimum :0.7350
PSO epoch:9/10 Intra group average:0.7313 global optimum :0.7350
PSO epoch:10/10 Intra group average:0.7313 global optimum :0.7350
Accuracy of verification set of optimal model:0.7350 Test set accuracy:0.7350
```

View the transformation of PSO optimal solution with the number of iterations

```history = pd.DataFrame(pso.gHistory)
history["epoch"] = range(1,history.shape[0]+1)
history
```
Feature 0 Feature 1 Intra group average global optimum epoch
0 50.0 0.267706 0.7210 0.728 1
1 50.0 0.267706 0.7210 0.728 2
2 50.0 0.267706 0.7251 0.728 3
3 57.0 0.201336 0.7275 0.735 4
4 57.0 0.201336 0.7275 0.735 5
5 57.0 0.201336 0.7299 0.735 6
6 57.0 0.201336 0.7313 0.735 7
7 57.0 0.201336 0.7313 0.735 8
8 57.0 0.201336 0.7313 0.735 9
9 57.0 0.201336 0.7313 0.735 10

Comparing the accuracy of the default parameter model and PSO tuning model is a little effective, just for learning

```fig, ax = plt.subplots()
x = np.arange(2)
a = [defaultValAcc,bestValAcc]
b = [defaultTestAcc,bestTestAcc]
total_width, n = 0.8, 2
width = total_width / n
x = x - (total_width - width) / 2
ax.bar(x, a,  width=width, label='val',color="#00BFFF")
for x1,y1 in zip(x,a):
plt.text(x1,y1+0.01,'%.3f' %y1, ha='center',va='bottom')
ax.bar(x + width, b, width=width, label='test',color="#FFA500")
for x1,y1 in zip(x,b):
plt.text(x1+width,y1+0.01,'%.3f' %y1, ha='center',va='bottom')
ax.legend()
ax.set_xticks([0,  1])
ax.set_ylim([0,1.2])
ax.set_ylabel("acc")
ax.set_xticklabels(["default net","PSO-net"])
fig.savefig("Static/contrast.png",dpi=250)
```

Posted by echoindia756 on Thu, 25 Nov 2021 17:40:48 -0800