classBaseNode(ABC):def__init__(self,*inbound_nodes,name=None):self.name=nameself._value=Noneself.inbound_nodes=[xforxininbound_nodes]self.outbound_nodes=[]self.gradients=dict()fornodeinself.inbound_nodes:node.outbound_nodes.append(self)def__str__(self):size=str(self.value.shape)ifself.valueisnotNoneelse"null"return"<Node name: %s, Node size: %s>"%(self.name,size)@propertydefvalue(self)->ndarray:returnself._value@value.setterdefvalue(self,value):err_msg="'value' has to be a number or a numpy array!"assertisinstance(value,(ndarray,int,float)),err_msgself._value=value@abstractmethoddefforward(self):return@abstractmethoddefbackward(self):return
2.2 创建InputNode类
用于存储训练、测试数据。其中indexes属性用来存储每个Batch中的数据下标。
classInputNode(BaseNode):def__init__(self,value:ndarray,name=None):BaseNode.__init__(self,name=name)self.value=valueself.indexes=None@propertydefvalue(self):err_msg="Indexes is None!"assertself.indexesisnotNone,err_msgreturnself._value[self.indexes]@value.setterdefvalue(self,value:ndarray):BaseNode.value.fset(self,value)defforward(self):returndefbackward(self):self.gradients={self:0}fornodeinself.outbound_nodes:self.gradients[self]+=node.gradients[self]
def__str__(self):ifnotself.nodes_sorted:return"Network has not be trained yet!"print("Network informantion:\n")ret=["learning rate:",str(self._learning_rate),"\n"]fornodeinself.nodes_sorted:ret.append(node.name)ret.append(str(node.value.shape))ret.append("\n")return" ".join(ret)
defforward(self):assertself.nodes_sortedisnotNone,"nodes_sorted is empty!"fornodeinself.nodes_sorted:node.forward()defbackward(self):assertself.nodes_sortedisnotNone,"nodes_sorted is empty!"fornodeinself.nodes_sorted[::-1]:node.backward()defforward_and_backward(self):self.forward()self.backward()
deffit(self,data:ndarray,label:ndarray,n_hidden:int,epochs:int,batch_size:int,learning_rate:float):label=label.reshape(-1,1)n_sample,n_feature=data.shapeself.build_network(data,label,n_hidden,n_feature)self.learning_rate=learning_rateprint("Total number of samples = {}".format(n_sample))self.train_network(epochs,n_sample,batch_size)self.pop_unused_nodes()
@run_timedefmain():print("Tesing the performance of MLP....")data,label=load_boston_house_prices()data=min_max_scale(data)data_train,data_test,label_train,label_test=train_test_split(data,label,random_state=20)reg=MLP()reg.fit(data=data_train,label=label_train,n_hidden=8,epochs=1000,batch_size=8,learning_rate=0.0008)get_r2(reg,data_test,label_test)print(reg)