├── createDataAndPlot.py └── your_first_network.py /createDataAndPlot.py: -------------------------------------------------------------------------------- 1 | #生成数据和可视化 2 | import numpy as np 3 | import math 4 | import random 5 | import matplotlib.pyplot as plt 6 | 7 | NUM_OF_DATA = 800 8 | CLASIFICATION_TYPE ='ring' 9 | 10 | def tag_entry(x, y): 11 | if CLASIFICATION_TYPE == 'circle': 12 | if x**2+y**2 > 1: # 如果距离原点半径大于某值,则标为1 13 | tag = 1 14 | else:# 小于某值则标为0 15 | tag = 0 16 | 17 | if CLASIFICATION_TYPE == 'ring': 18 | if x**2+y**2 > 1 and x**2+y**2 < 2: # 19 | tag = 1 20 | else:# 21 | tag = 0 22 | elif CLASIFICATION_TYPE == 'line': 23 | if x > 0: # 如果距离原点半径大于某值,则标为1 24 | tag = 1 25 | else:# 小于某值则标为0 26 | tag = 0 27 | 28 | elif CLASIFICATION_TYPE == 'cross': 29 | if x*y > 0: # 如果距离原点半径大于某值,则标为1 30 | tag = 1 31 | else:# 小于某值则标为0 32 | tag = 0 33 | return tag 34 | 35 | def creat_data(num_of_data): 36 | entry_list = [] 37 | for i in range(num_of_data): 38 | x = random.uniform(-2, 2) 39 | y = random.uniform(-2, 2) 40 | tag = tag_entry(x, y) 41 | entry = [x, y, tag] 42 | entry_list.append(entry) 43 | return np.array(entry_list) 44 | 45 | #---------可视化----------------- 46 | def plot_data(data, title): 47 | color = [] 48 | for i in data[:, 2]: 49 | if i == 0: 50 | color.append("orange") 51 | else: 52 | color.append("blue") 53 | 54 | plt.scatter(data[:, 0], data[:, 1], c=color) 55 | plt.title(title) 56 | plt.show() 57 | 58 | # ----------------------- 59 | if __name__ == "__main__": 60 | data = creat_data(NUM_OF_DATA) 61 | print(data) 62 | plot_data(data, 'Demo') -------------------------------------------------------------------------------- /your_first_network.py: -------------------------------------------------------------------------------- 1 | #Python手搓神经网络 2 | #这是B站教程的相关代码请结合下面地址中的教程使用: 3 | #https://www.bilibili.com/video/BV1py4y1F7vp/?spm_id_from=333.999.section.playall&vd_source=036afdc841b709a63dcc3989925f751a 4 | import numpy as np 5 | import createDataAndPlot as cp 6 | import copy 7 | import math 8 | 9 | NETWORK_SHAPE = [2, 100, 200, 100, 50, 2] 10 | BATCH_SIZE = 30 11 | LEARNING_RATE = 0.015 12 | LOSS_THRESHOLD = 0.1 13 | FORCE_TRAIN_THRESHOLD = 0.05 14 | 15 | force_train = False 16 | random_train = False 17 | n_improved = 0 18 | n_not_improved = 0 19 | current_loss = 1 20 | 21 | 22 | #标准化函数 23 | def normalize(array): 24 | max_number = np.max(np.absolute(array), axis=1, keepdims=True) 25 | scale_rate = np.where(max_number == 0, 1, 1/max_number) 26 | norm = array * scale_rate 27 | return norm 28 | 29 | #向量标准化函数 30 | def vector_normalize(array): 31 | max_number = np.max(np.absolute(array)) 32 | scale_rate = np.where(max_number == 0, 1, 1/max_number) 33 | norm = array * scale_rate 34 | return norm 35 | 36 | # 激活函数 37 | def activation_ReLU(inputs): 38 | return np.maximum(0, inputs) 39 | 40 | #分类函数 41 | def classify(probabilities): 42 | classification = np.rint(probabilities[:, 1]) 43 | return classification 44 | 45 | # softmax激活函数 46 | def activation_softmax(inputs): 47 | max_values = np.max(inputs, axis=1, keepdims=True) 48 | slided_inputs = inputs - max_values 49 | exp_values = np.exp(slided_inputs) 50 | norm_base = np.sum(exp_values, axis=1, keepdims=True) 51 | norm_values = exp_values/norm_base 52 | return norm_values 53 | 54 | #损失函数1 55 | def precise_loss_function(predicted, real): 56 | real_matrix = np.zeros((len(real), 2)) 57 | real_matrix[:, 1] = real 58 | real_matrix[:, 0] = 1 - real 59 | product = np.sum(predicted*real_matrix, axis=1) 60 | return 1 - product 61 | 62 | #损失函数2 63 | def loss_function(predicted, real): 64 | condition = (predicted > 0.5) 65 | binary_predicted = np.where(condition, 1, 0) 66 | real_matrix = np.zeros((len(real), 2)) 67 | real_matrix[:, 1] = real 68 | real_matrix[:, 0] = 1 - real 69 | product = np.sum(predicted*real_matrix, axis=1) 70 | return 1 - product 71 | 72 | #需求函数 73 | def get_final_layer_preAct_damands(predicted_values, target_vector): 74 | target = np.zeros((len(target_vector), 2)) 75 | target[:, 1] = target_vector 76 | target[:, 0] = 1 - target_vector 77 | 78 | for i in range(len(target_vector)): 79 | if np.dot(target[i], predicted_values[i]) > 0.5: 80 | target[i] = np.array([0, 0]) 81 | else: 82 | target[i] = (target[i] - 0.5) * 2 83 | return target 84 | 85 | #------------------------------------------------------------- 86 | #定义一个层类 87 | class Layer: 88 | def __init__(self, n_inputs, n_neurons): 89 | self.weights = np.random.randn(n_inputs, n_neurons) 90 | self.biases = np.random.randn(n_neurons) 91 | 92 | def layer_forward(self, inputs): 93 | self.output = np.dot(inputs, self.weights) + self.biases 94 | return self.output 95 | 96 | def layer_backward(self, preWeights_values, afterWeights_demands): 97 | preWeights_damands = np.dot(afterWeights_demands, self.weights.T) 98 | 99 | condition = (preWeights_values > 0) 100 | value_derivatives = np.where(condition, 1, 0) 101 | 102 | preActs_demands = value_derivatives*preWeights_damands 103 | norm_preActs_demands = normalize(preActs_demands) 104 | 105 | weight_adjust_matrix = self.get_weight_adjust_matrix(preWeights_values, afterWeights_demands) 106 | norm_weight_adjust_matrix = normalize(weight_adjust_matrix) 107 | 108 | return (norm_preActs_demands, norm_weight_adjust_matrix) 109 | 110 | def get_weight_adjust_matrix(self, preWeights_values, aftWeights_demands): 111 | plain_weights = np.full(self.weights.shape, 1) 112 | weights_adjust_matrix = np.full(self.weights.shape, 0.0) 113 | plain_weights_T = plain_weights.T 114 | 115 | for i in range(BATCH_SIZE): 116 | weights_adjust_matrix += (plain_weights_T*preWeights_values[i, :]).T*aftWeights_demands[i, :] 117 | weights_adjust_matrix = weights_adjust_matrix/BATCH_SIZE 118 | return weights_adjust_matrix 119 | 120 | #----------------------------------------------------------------- 121 | #定义一个网络类 122 | class Network: 123 | def __init__(self, network_shape): 124 | self.shape = network_shape 125 | self.layers = [] 126 | for i in range(len(network_shape)-1): 127 | layer = Layer(network_shape[i], network_shape[i+1]) 128 | self.layers.append(layer) 129 | 130 | #前馈运算函数 131 | def network_forward(self, inputs): 132 | outputs = [inputs] 133 | for i in range(len(self.layers)): 134 | layer_sum = self.layers[i].layer_forward(outputs[i]) 135 | if i < len(self.layers)-1: 136 | layer_output = activation_ReLU(layer_sum) 137 | layer_output = normalize(layer_output) 138 | else: 139 | layer_output = activation_softmax(layer_sum) 140 | outputs.append(layer_output) 141 | return outputs 142 | 143 | #反向传播函数 144 | def network_backward(self, layer_outputs, target_vector): 145 | backup_network = copy.deepcopy(self) # 备用网络 146 | preAct_demands = get_final_layer_preAct_damands(layer_outputs[-1], target_vector) 147 | for i in range(len(self.layers)): 148 | layer = backup_network.layers[len(self.layers) - (1+i)] # 倒序 149 | if i != 0: 150 | layer.biases += LEARNING_RATE * np.mean(preAct_demands, axis=0) 151 | layer.biases = vector_normalize(layer.biases) 152 | 153 | outputs = layer_outputs[len(layer_outputs) - (2+i)] 154 | results_list = layer.layer_backward(outputs, preAct_demands) 155 | preAct_demands = results_list[0] 156 | weights_adjust_matrix = results_list[1] 157 | layer.weights += LEARNING_RATE * weights_adjust_matrix 158 | layer.weights = normalize(layer.weights) 159 | return backup_network 160 | 161 | #单批次训练 162 | def one_batch_train(self, batch): 163 | global force_train, random_train, n_improved, n_not_improved 164 | 165 | inputs = batch[:,(0, 1)] 166 | targets = copy.deepcopy(batch[:, 2]).astype(int) # 标准答案 167 | outputs = self.network_forward(inputs) 168 | precise_loss = precise_loss_function(outputs[-1], targets) 169 | loss = loss_function(outputs[-1], targets) 170 | 171 | if np.mean(loss) <= LOSS_THRESHOLD:#损失函数小于这个值就不需要训练了 172 | print('No need for training') 173 | else: 174 | backup_network = self.network_backward(outputs, targets) 175 | backup_outputs = backup_network.network_forward(inputs) 176 | backup_precise_loss = precise_loss_function(backup_outputs[-1], targets) 177 | backup_loss = loss_function(backup_outputs[-1], targets) 178 | 179 | if np.mean(precise_loss) >= np.mean(backup_precise_loss) or np.mean(loss) >= np.mean(backup_loss): 180 | for i in range(len(self.layers)): 181 | self.layers[i].weights = backup_network.layers[i].weights.copy() 182 | self.layers[i].biases = backup_network.layers[i].biases.copy() 183 | print('Improved') 184 | n_improved += 1 185 | 186 | else: 187 | if force_train: 188 | for i in range(len(self.layers)): 189 | self.layers[i].weights = backup_network.layers[i].weights.copy() 190 | self.layers[i].biases = backup_network.layers[i].biases.copy() 191 | print('Force train') 192 | if random_train: 193 | self.random_update() 194 | print("Random update") 195 | else: 196 | print('No improvement') 197 | n_not_improved += 1 198 | print('-----------------------------------------') 199 | 200 | #多批次训练 201 | def train(self, n_entries): 202 | global force_train, random_train, n_improved, n_not_improved 203 | n_improved = 0 204 | n_not_improved = 0 205 | 206 | n_batches = math.ceil(n_entries/BATCH_SIZE) 207 | for i in range(n_batches): 208 | batch = cp.creat_data(BATCH_SIZE) 209 | self.one_batch_train(batch) 210 | improvement_rate = n_improved/(n_improved + n_not_improved) 211 | print("Improvement rate") 212 | print(format(improvement_rate, ".0%")) 213 | if improvement_rate <= FORCE_TRAIN_THRESHOLD: 214 | force_train = True 215 | else: 216 | force_train = False 217 | if n_improved == 0: 218 | random_train = True 219 | else: 220 | random_train = False 221 | 222 | data = cp.creat_data(800) 223 | inputs = data[:, (0, 1)] 224 | outputs = self.network_forward(inputs) 225 | classification = classify(outputs[-1]) 226 | data[:, 2] = classification 227 | cp.plot_data(data, "After training") 228 | 229 | #随机更新 230 | def random_update(self): 231 | random_network = Network(NETWORK_SHAPE) 232 | for i in range(len(self.layers)): 233 | weights_change = random_network.layers[i].weights 234 | biases_change = random_network.layers[i].biases 235 | self.layers[i].weights += weights_change 236 | self.layers[i].biases += biases_change 237 | 238 | #核验LOSS值 239 | def check_loss(self): 240 | data = cp.creat_data(1000) 241 | inputs = data[:, (0, 1)] 242 | targets = copy.deepcopy(data[:, 2]).astype(int) # 标准答案 243 | outputs = self.network_forward(inputs) 244 | loss = loss_function(outputs[-1], targets) 245 | return np.mean(loss) 246 | 247 | #-------------MAIN------------------------- 248 | def main(): 249 | global current_loss 250 | data = cp.creat_data(800) #生成数据 251 | cp.plot_data(data, "Right classification") 252 | 253 | #选择起始网络 254 | use_this_network = 'n' #No 255 | while use_this_network != 'Y' and use_this_network != 'y': 256 | network = Network(NETWORK_SHAPE) 257 | inputs = data[:, (0, 1)] 258 | outputs = network.network_forward(inputs) 259 | classification = classify(outputs[-1]) 260 | data[:, 2] = classification 261 | cp.plot_data(data, "Choose network") 262 | use_this_network = input("Use this network? Y to yes, N to No \n") 263 | 264 | #进行训练 265 | do_train = input("Train? Y to yes, N to No \n") 266 | while do_train == 'Y' or do_train == 'y' or do_train.isnumeric() == True: 267 | if do_train.isnumeric() == True: 268 | n_entries = int(do_train) 269 | else: 270 | n_entries = int(input("Enter the number of data entries used to train. \n")) 271 | 272 | network.train(n_entries) 273 | do_train = input("Train? Y to yes, N to No \n") 274 | 275 | #演示训练效果 276 | inputs = data[:, (0, 1)] 277 | outputs = network.network_forward(inputs) 278 | classification = classify(outputs[-1]) 279 | data[:, 2] = classification 280 | cp.plot_data(data, "After training") 281 | print("谢谢,再见!") 282 | #----------------TEST------------------------- 283 | def test(): 284 | pass 285 | 286 | #--------------运行--------------------- 287 | main() 288 | --------------------------------------------------------------------------------