找回密码
 立即注册
查看: 23|回复: 0

[作品展示] np_simple监督学习模块,神经网络学习模块

[复制链接]
发表于 昨天 23:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

×
和豆包一起熬了三个大存档,才写出来的
但是确实了解到了很多知识了

这里吧代码分享出来
和神经网络有关数学知识
太多了
这里我简单提一下
是高中会学的矩阵变换
in_向量*[w1]+b1=hidden_向量
hidden_向量(激活)*[w2]+b2=out_向量
w1,w2,b1,b2是网络矩阵,通过学习调整这些参数
in_向量是你的问题,out_向量是他的结果
刚才说到的激活是指
将hidden中每一项的分量如果<0,输出0,否则输出自己本身
使自己具有非线性能力(对于不同需要跳变的问题有不同计算方式)

那么为什么几乎所有问题都可以用这种方式解决呢?
那也不是,只是大部分问题了

因为神经网络它会自己去泛化这种问题的解题公式
但是你不知到它的过程
这就是
黑盒

内部数据是很难看懂的

总结到这了
使用文档在代码里


  1. import numpy as np
  2. """
  3. simple_nn 单隐藏层神经网络模块,仅支持监督训练
  4. ==============================
  5. 整体架构:输入层 → 隐藏层(LeakyReLU) → 输出层(线性,无激活)
  6. 设计思路:
  7.     神经网络内部计算只负责非线性变换,不强行把输出压缩到0~1。
  8.     sigmoid 单独作为外部后处理函数,使用者按需调用,用来把原生输出映射至0~1。
  9.     D1参数:LeakyReLU负数区间斜率,缓解原生ReLU神经元死亡问题。

  10. 对外可用函数:
  11.     leaky_relu(x, d1=0.01)
  12.     leaky_relu_deriv(x, d1=0.01)
  13.     sigmoid(x)  # 独立后处理函数,映射实数到0~1

  14. NeuralNet 类方法列表:
  15.     forward(x):正向传播,返回前向快照对象ForwardResult
  16.     fit(x, y_true):监督训练,输入+标准答案,自动反向传播更新权重
  17.     custom_learn(x, score_func):自定义外部打分函数训练,不需要标准答案
  18.     set_weights_manual(w1_list,b1_list,w2_list,b2_list):
  19.         用原生Python嵌套列表手动设置权重偏置,不经过训练

  20. ForwardResult 快照对象属性:
  21.     x: 输入数据
  22.     z1: 隐藏层激活前的值
  23.     a1: 隐藏层LeakyReLU激活后的值
  24.     z2: 输出层激活前的值
  25.     a2: 网络原生输出(线性,无值域压缩,可正可负)
  26.     calc_loss(y_true): 计算均方误差损失
  27. #-----------------------------#
  28. 参数:
  29. T=4.0、F=-4.0、mid=0.0 为 logit 域目标;
  30. 经过 sigmoid 压缩后对应概率约 0.98、0.02、0.5。
  31. T、F 是偏向两端的目标,mid 是中间不确定目标。
  32. 用于快捷匹配。
  33. bound_dict是默认事件字典序
  34. 事件字典序
  35. 用途:接收0~1的概率值,按预设的区间规则解释成value
  36. 约定:字典key是区间起点(闭区间),value是对应标签;书写顺序无关,查询时自动排序
  37. 注意:仅用于推理阶段解释概率,训练目标是logit的 T、F、mid

  38. """

  39. # ===== 激活函数(模块内可用,sigmoid单独独立出来,用户按需调用) =====
  40. def leaky_relu(x, d1=0.01):
  41.     return np.where(x > 0, x, d1 * x)

  42. def leaky_relu_deriv(x, d1=0.01):
  43.     return np.where(x > 0, 1.0, d1)

  44. # Sigmoid单独独立!网络内部forward不再自动调用它
  45. def sigmoid(x):
  46.     return 1.0 / (1.0 + np.exp(-x))

  47. def logit(p):
  48.     """
  49.     逆Sigmoid函数:0~1概率转回对应的logit值
  50.     :param p: 概率,范围0~1
  51.     :return: logit实数
  52.     """
  53.     q = np.clip(p, 1e-6, 1 - 1e-6)
  54.     return np.log(q / (1 - q))
  55. #比对函数(事件字典序查找)
  56. def lookup_tag(p, bound_dict):
  57.     "对事件字典序进行查找"
  58.     if p < 0.0 or p > 1.0:
  59.         raise ValueError("概率数值必须在 0.0 ~ 1.0 之间")
  60.     start_points = sorted(bound_dict.keys())
  61.     selected = start_points[0]
  62.     for s in start_points:
  63.         if s <= p:
  64.             selected = s
  65.         else:
  66.             break
  67.     return bound_dict[selected]

  68. #工具包
  69. def find_max_index(lst):
  70.     """寻找最大值下标"""
  71.     idx = lst.index(max(lst))
  72.     return idx
  73.    
  74. def find_max_key(d):
  75.     """寻找最大值的键,d.type为dict"""
  76.     best_key = max(d, key=d.get)
  77.     return best_key


  78. # ===== 前向结果快照类 =====
  79. class ForwardResult:
  80.     def __init__(self, x, z1, a1, z2, a2):
  81.         self.x = x
  82.         self.z1 = z1
  83.         self.a1 = a1
  84.         self.z2 = z2
  85.         self.a2 = a2  # a2现在是【原生线性输出】,没有经过sigmoid,可以是任意实数
  86.         self.out = a2.flatten().tolist()
  87.         """out才是结果向量"""

  88.     def calc_loss(self, y_true):
  89.         """内置损失:均方误差,fit方法使用"""
  90.         return np.mean((self.a2 - y_true) ** 2)

  91. # ===== 神经网络主类 =====
  92. class NeuralNet:
  93.     def __init__(self,input_size,hidden_size,output_size,init=True, d1=0.01):
  94.         self.in_size = input_size
  95.         self.hidden_size = hidden_size
  96.         self.out_size = output_size
  97.         self.d1 = d1 # LeakyReLU的负区间斜率D1,用来防止神经元死亡
  98.         
  99.         if init:
  100.             self.w1 = np.random.randn(input_size, hidden_size) * 0.1
  101.         else:
  102.             self.w1 = np.zeros((input_size, hidden_size))
  103.         self.b1 = np.zeros((1, hidden_size))
  104.         
  105.         if init:
  106.             self.w2 = np.random.randn(hidden_size, output_size) * 0.1
  107.         else:
  108.             self.w2 = np.zeros((hidden_size, output_size))
  109.         self.b2 = np.zeros((1, output_size))
  110.         self.learn_rate = 0.1#学习率

  111.     # 方法1:正向传播
  112.     def forward(self, x):
  113.         x=np.array([x])
  114.         z1 = np.dot(x, self.w1) + self.b1
  115.         a1 = leaky_relu(z1, self.d1)
  116.         z2 = np.dot(a1, self.w2) + self.b2
  117.         a2 = z2   # 输出层:线性,**不套sigmoid**,原生输出
  118.         return ForwardResult(x, z1, a1, z2, a2)

  119.     # 方法2:传统训练:输入+真实标签,自动一步训练(前向+反向更新)
  120.     def fit(self, x, y_true):
  121.         y_true = np.array([y_true])
  122.         res = self.forward(x)
  123.         loss = res.calc_loss(y_true)
  124.         # ===== 输出层现在是线性激活,导数=1!=====
  125.         dZ2 = (res.a2 - y_true) * 1.0
  126.         dW2 = np.dot(res.a1.T, dZ2)
  127.         db2 = np.sum(dZ2, axis=0, keepdims=True)

  128.         # 隐藏层梯度:LeakyReLU导数,使用z1
  129.         dZ1 = np.dot(dZ2, self.w2.T) * leaky_relu_deriv(res.z1, self.d1)
  130.         dW1 = np.dot(res.x.T, dZ1)
  131.         db1 = np.sum(dZ1, axis=0, keepdims=True)
  132.         self.w2 -= self.learn_rate * dW2
  133.         self.b2 -= self.learn_rate * db2
  134.         self.w1 -= self.learn_rate * dW1
  135.         self.b1 -= self.learn_rate * db1
  136.         return loss

  137.         # 5.链式反向传播,计算各参数梯度
  138.         dW2 = np.dot(res.a1.T, dZ2)
  139.         db2 = np.sum(dZ2, axis=0, keepdims=True)

  140.         dZ1 = np.dot(dZ2, self.w2.T) * leaky_relu_deriv(res.z1, self.d1)
  141.         dW1 = np.dot(x.T, dZ1)
  142.         db1 = np.sum(dZ1, axis=0, keepdims=True)

  143.         # 6.更新权重
  144.         self.w2 -= self.learn_rate * dW2
  145.         self.b2 -= self.learn_rate * db2
  146.         self.w1 -= self.learn_rate * dW1
  147.         self.b1 -= self.learn_rate * db1

  148.         return loss
  149.    
  150.     # 方法4:手动设置权重,输入为原生嵌套列表
  151.     def set_weights_manual(self, w1_list, b1_list, w2_list, b2_list):
  152.         """
  153.         手动填入权重、偏置,使用Python嵌套list,不是numpy数组
  154.         w1_list: 嵌套列表,shape [input_size, hidden_size]
  155.         b1_list: 嵌套列表,shape [1, hidden_size]
  156.         w2_list: 嵌套列表,shape [hidden_size, output_size]
  157.         b2_list: 嵌套列表,shape [1, output_size]
  158.         """
  159.         new_w1 = np.array(w1_list, dtype=np.float64)
  160.         new_b1 = np.array(b1_list, dtype=np.float64)
  161.         new_w2 = np.array(w2_list, dtype=np.float64)
  162.         new_b2 = np.array(b2_list, dtype=np.float64)

  163.         if new_w1.shape != (self.in_size, self.hidden_size):
  164.             raise ValueError(f"w1_list 维度错误!需要 ({self.in_size},{self.hidden_size})")
  165.         if new_b1.shape != (1, self.hidden_size):
  166.             raise ValueError(f"b1_list 维度错误!需要 (1,{self.hidden_size})")
  167.         if new_w2.shape != (self.hidden_size, self.out_size):
  168.             raise ValueError(f"w2_list 维度错误!需要 ({self.hidden_size},{self.out_size})")
  169.         if new_b2.shape != (1, self.out_size):
  170.             raise ValueError(f"b2_list 维度错误!需要 (1,{self.out_size})")
  171.         
  172.         self.w1 = new_w1
  173.         self.b1 = new_b1
  174.         self.w2 = new_w2
  175.         self.b2 = new_b2

  176.     def train(self,callback,epoch=10):#批训练 epoch:次数
  177.         """
  178.         函数callback无输入,输出两个列表in和out 自动生成训练数据
  179.         last输出最后一次损失
  180.         """
  181.         for i in range(epoch):
  182.             in_,out_=callback()
  183.             last = self.fit(in_,out_)
  184.         return last
  185.    
  186.     def explore(self,temp):
  187.         """给自己产生神经扰动并附加于自身"""
  188.         noise_w1 = np.random.normal(-temp,temp,size=self.w1.shape)
  189.         self.w1 += noise_w1

  190.         noise_w2 = np.random.normal(-temp,temp,size=self.w2.shape)
  191.         self.w2 += noise_w2
  192.         
  193.     def copy(self):
  194.         """返回自身数据到新的NeuralNet对象"""
  195.         co = NeuralNet(self.input_size,self.hidden_size,self.output_size,dl = self.dl)
  196.         co.learn_rate = self.learn_rate
  197.         co.w1 = self.w1.copy()
  198.         co.b1 = self.b1.copy()
  199.         co.w2 = self.w2.copy()
  200.         co.b2 = self.b2.copy()
  201.         return co

  202. #默认参数
  203. T=sigmoid(4.0)#在神经训练中大约为sigmoid(0.98)近似表示是
  204. F=sigmoid(-4.0)#在神经训练中大约为sigmoid(0.02)近似表示否
  205. mid=sigmoid(0)#中间


  206. bound_dict = {
  207.     0.0: "NO",
  208.     0.1: "UNCERTAIN",
  209.     0.9: "YES"
  210. }
复制代码


还有测试程序


  1. import simple_nn

  2. ne = simple_nn.NeuralNet(2,10,1)
  3. ne.learn_rate = 0.02

  4. in_ = ([0,0],[0,1],[1,0],[1,1])
  5. out_ = (0, 1, 1, 0) # 与门

  6. for i in range(0,19999):
  7.     if i % 1000== 0:
  8.         print(f"训练了{i}次")
  9.     for x_list, target in zip(in_, out_):
  10.         if target==0:
  11.             loss = ne.fit(x_list,[simple_nn.logit(0.05)])
  12.         else:
  13.             loss = ne.fit(x_list,[simple_nn.logit(0.95)])
  14.     if i % 1000 == 0:
  15.         print(f"轮{i}, loss={loss:.4f}")

  16. print("\n=====预测,输入两个0/1=====")
  17. v1 = float(input("输入第一个值:"))
  18. v2 = float(input("输入第二个值:"))
  19. res = ne.forward([v1,v2])
  20. print("神经网络输出out:", res.a2[0][0])
  21. p = simple_nn.sigmoid(res.out[0])
  22. print("映射概率sigmoid0~1:", p)
  23. if p>=0.9:
  24.     print("答案是1吗?")
  25. if p<=0.1:
  26.     print("答案是0吗?")

复制代码

大致功能,给它一大堆或门的真值表
最后看它记不记得住

可以把v1,v2换成浮点值发现它可以得出答案
说明程序成功运行
记得在pip下载numpy
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|鱼C工作室 ( 粤ICP备18085999号-1 )

GMT+8, 2026-11-8 04:54

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表