(本人最初发布于HackMD:HackMD链接,链接内容为繁体字)
1.问题描述
自定义一个MLP来学习8位奇偶校验(8BPC)问题8BPC问题是从8位(1字节)二进制输入生成单个奇偶校验位 如果二进制输入中的数字1为奇数,则生成的奇偶校验位必须为1;否则,生成的奇偶校验位必须为零。
2.产生训练数据(data和labels)
八个二进制位,一共有256种不同的组合,也就是相当于把0-256转换为二进制的形式表示,然后根据奇偶,将得到1或0的label。
#首先生成训练和测试所用的data和labels
#八个二进制位,一共有256种不同的组合,也就是相当于把0-256转换为二进制的形式表示,然后根据奇偶,将得到1或0的label
import numpy as np
def getParityBit(bitString:str) -> int:
if type(bitString) is not str:
raise TypeError('Expected str; got %s' % type(bitString))
parityBit = False
for c in bitString:
if c == '1':
parityBit = not parityBit
rel = 1 if parityBit else 0
return rel
def createDataAndLabels():
data = []
labels = []
for i in range(256):
intToBinary = '{0:08b}'.format(i)
data.append(list(map(int, intToBinary)))
labels.append([getParityBit(intToBinary)])
return (np.array(data), np.array(labels))
3.定义所用到的激活函数
#定义需要用到的激活函数,tanh,ReLU,Sigmoid
import numpy as np
class tanh:
def __init__(self):
pass
def forward(self, x):
out = np.tanh(x)
self.o = out
return out
def backward(self, dout):
dx = dout*(1.0 - self.o**2)
return dx
class ReLU:
def __init__(self):
pass
def forward(self, x):
self.mask = (x<=0)
out = x
out[out<=0] = 0
return out
def backward(self, dout):
dx = dout
dx[self.mask] = 0
return dx
class Sigmoid:
def __init__(self):
pass
def forward(self, x):
out = 1.0/(1+np.exp(-x))
self.o = out
return out
def backward(self, dout):
dx = dout*self.o*(1-self.o)
return dx
#定义loss function
class Loss:
def __init__(self):
pass
def forward(self, y, ybar):
self.y = y
self.ybar = ybar
return np.sum((y-ybar)**2)
def backward(self, dout):
dy = -(2*(self.y -self.ybar))
return dy
#该神经网络使用线性神经网络
class Linear:
def __init__(self, m, n):
self.W = np.random.randn(m, n)/8.0
self.b = np.random.rand(1, n)/8.0
self.dW, self.db = None, None
def forward(self, x):
self.x = x
out = np.dot(x, self.W)+self.b
return out
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis=0)
return dx
4.创建MLP_Model类
#定义MLP_Model类,可以用来创建模型
class MLP_Model:
def __init__(self, inDegree:int, layerType:list, outDegree):
self.degree = list(map(int, str(inDegree))) + outDegree
layerType = [x.lower() for x in layerType]
self.supportFuncTable = {
'relu' : ReLU,
'sigmoid' : Sigmoid,
'tanh' : tanh
}
self.layers = []
self.actFunctions = []
self.last_dW ,self.last_db = [], []
for i in range(len(self.degree)-1):
self.layers.append(Linear(self.degree[i], self.degree[i+1]))
self.actFunctions.append(self.supportFuncTable[layerType[i]]())
self.last_dW.append(0)
self.last_db.append(0)
self.loss = Loss()
def forward(self, x):
for i in range(len(self.layers) - 1):
x = self.layers[i].forward(x)
x = self.actFunctions[i].forward(x)
x = self.layers[-1].forward(x)
self.ybar = self.actFunctions[-1].forward(x)
return self.ybar
def backward(self, y):
self.L = self.loss.forward(y, self.ybar)
g = self.loss.backward(1)
for i in range(len(self.layers)-1, -1, -1):
g = self.actFunctions[i].backward(g)
g = self.layers[i].backward(g)
def update(self, eta, alpha):
for i in range(len(self.layers)):
self.layers[i].W += -eta*self.layers[i].dW + alpha*self.last_dW[i]
self.layers[i].b += -eta*self.layers[i].db + alpha*self.last_db[i]
self.last_dW[i] = eta*self.layers[i].dW
self.last_db[i] = eta*self.layers[i].db
#predict方法用来预测结果
def predict(self, x):
self.forward(x)
return np.array([1]) if model.ybar > 0.5 else np.array([0])
5.创建并训练模型
使用刚才定义的createDataAndLabels函数,产生data和labels
Data, Labels = createDataAndLabels()
①使用两层神经网(ReLU+Sigmoid)
先创建一个具有一个Relu层和一个sigmoid层的模型
#定义模型model,每一笔data的维度为8,第一层的激活函数为relu,然后是sigmoid得到一个数值,也就是输出
model = MLP_Model(8,
['relu', 'sigmoid'],
[100, 1])
#设置eta和alpha为0.001和0.0001
eta, alpha = 0.001, 0.0001
#将epochs设置为20000,每隔100个epochs显示一次
max_epochs, check_epochs = 20000, 100
printPointOfEporch = []
printPointOfLoss = []
for e in range(max_epochs):
model.forward(Data)
model.backward(Labels)
model.update(eta, alpha)
#每隔100个epochs显示一次loss
if (e+1) % check_epochs == 0:
print('epoch:{0:2d}------loss:{1:2.4f}'.format(e+1, model.L))
printPointOfEporch.append(e), printPointOfLoss.append(model.L)
打印训练过程
#打印训练过程
import matplotlib.pyplot as plt
import numpy as np
plt.title("only one relu layer")
#根据刚才设置的20000÷100=200个loss结果,来打印训练过程
plt.plot(printPointOfEporch, printPointOfLoss)
plt.show()
②使用三层神经网(ReLU+ReLU+Sigmoid)
创建一个具有两个ReLU层和一个Sigmoid层的模型
#定义一个三层神经网的模型
model = MLP_Model(8,
['relu', 'relu', 'sigmoid'],
[100,40,1])
#设置eta和alpha为0.001和0.0001
eta, alpha = 0.001, 0.0001
#将epochs设置为20000,每隔100个epochs显示一次
max_epochs, check_epochs = 20000, 100
printPointOfEporch = []
printPointOfLoss = []
for e in range(max_epochs):
model.forward(Data)
model.backward(Labels)
model.update(eta, alpha)
#每隔100个epochs显示一次loss
if (e+1) % check_epochs == 0:
print('epoch:{0:2d}------loss:{1:2.4f}'.format(e+1, model.L))
printPointOfEporch.append(e), printPointOfLoss.append(model.L)
打印训练过程
#打印训练过程
import matplotlib.pyplot as plt
import numpy as np
plt.title("two relu layers")
#根据刚才设置的20000÷100=200个loss结果,来打印训练过程
plt.plot(printPointOfEporch, printPointOfLoss)
plt.show()
③使用四层神经网(ReLU+ReLU+ReLU+Sigmoid)
创建具有三个ReLU层和一个Sigmoid层的模型
#定义一个四层神经网的模型
model = MLP_Model(8,
['relu', 'relu', 'relu', 'sigmoid'],
[100,70,30,1])
#设置eta和alpha为0.001和0.0001
eta, alpha = 0.001, 0.0001
#将epochs设置为20000,每隔100个epochs显示一次
max_epochs, check_epochs = 20000, 100
printPointOfEporch = []
printPointOfLoss = []
for e in range(max_epochs):
model.forward(Data)
model.backward(Labels)
model.update(eta, alpha)
#每隔100个epochs显示一次loss
if (e+1) % check_epochs == 0:
print('epoch:{0:2d}------loss:{1:2.4f}'.format(e+1, model.L))
printPointOfEporch.append(e), printPointOfLoss.append(model.L)
打印训练过程
#打印训练过程
import matplotlib.pyplot as plt
import numpy as np
plt.title("three relu layers")
#根据刚才设置的20000÷100=200个loss结果,来打印训练过程
plt.plot(printPointOfEporch, printPointOfLoss)
plt.show()
6.测试模型
#预测一下结果
model.predict([1,0,1,1,0,1,1,0])
model.predict([0,1,0,1,1,1,0,0])