From 04f1375b45c5fe50ee40d2db1f69a38b94d93f8b Mon Sep 17 00:00:00 2001 From: qing <1771677662@qq.com> Date: Tue, 25 Aug 2026 11:34:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E7=A5=9E=E7=BB=8F=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=87=8D=E6=9E=84=E6=88=90=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot4cj/cjpm.toml | 2 +- bot4cj/src/main.cj | 2 +- bot4cj/src/math/Af.cj | 192 ----------------------------------------- bot4cj/src/math/Ini.cj | 28 ------ bot4cj/src/math/nn.cj | 154 --------------------------------- 5 files changed, 2 insertions(+), 376 deletions(-) delete mode 100644 bot4cj/src/math/Af.cj delete mode 100644 bot4cj/src/math/Ini.cj delete mode 100644 bot4cj/src/math/nn.cj diff --git a/bot4cj/cjpm.toml b/bot4cj/cjpm.toml index d6cd163..0fcfd04 100644 --- a/bot4cj/cjpm.toml +++ b/bot4cj/cjpm.toml @@ -21,7 +21,7 @@ spi4cj = "1.0.0" #lua4cj = { git = "https://gitcode.com/qingss0/lua4cj.git", branch="main" } lua4cj = "1.0.0" - "cangjie_tpc::matrix4cj" = "1.0.5" + nn4cj = { git = "https://gitcode.com/qingss0/nn4cj.git", branch="main"} # 这种x86机器人开发板感觉不经常使用,我没用过,不知道里面的i2c调用是不是参数是一样的 [target.x86_64-unknown-linux-gnu] [target.x86_64-unknown-linux-gnu.dependencies] diff --git a/bot4cj/src/main.cj b/bot4cj/src/main.cj index 82a71c7..c06792f 100644 --- a/bot4cj/src/main.cj +++ b/bot4cj/src/main.cj @@ -13,8 +13,8 @@ import std.io.* import std.fs.* import stdx.encoding.json.* import bot4cj.hd.* -import bot4cj.math.* import ctype4cj.* +import nn4cj.* /* ---- 神经网络输出路径 ---- */ var NNS_OUT: Option = None diff --git a/bot4cj/src/math/Af.cj b/bot4cj/src/math/Af.cj deleted file mode 100644 index 7914678..0000000 --- a/bot4cj/src/math/Af.cj +++ /dev/null @@ -1,192 +0,0 @@ -package bot4cj.math -import std.math.* -import cangjie_tpc::matrix4cj.Matrix - -/* - * -------- Activation Functions 激活函数族 -------- - * TODO(20260516-qing): 增加序列化、反序列化工厂函数 - * TODO(20260825-qing): 改为使用matrix4cj库 - */ -public enum Af { - - None | Sigmoid | ReLU | Leaky_ReLU(Float64) | Tanh - - /* -------- 执行激活函数 -------- */ - public func forward(x: Matrix) { - match(this) { - case None => none(x) - case Sigmoid => sigmoid(x) - case ReLU => relu(x) - case Leaky_ReLU(alpha) => leaky_relu(x, alpha) - case Tanh => tanh(x) - } - } - - /* -------- 激活函数的导数 -------- */ - public func backward(y: Matrix) { - match(this) { - case None => none_dot(y) - case Sigmoid => sigmoid_dot(y) - case ReLU => relu_dot(y) - case Leaky_ReLU(alpha) => leaky_relu_dot(y, alpha) - case Tanh => tanh_dot(y) - } - } - - /* -------- 序列化与反序列化 -------- */ - public func get_type(): String { - return match(this) { - case None => "None" - case Sigmoid => "Sigmoid" - case ReLU => "ReLU" - case Leaky_ReLU(alpha) => "Leaky_ReLU" - case Tanh => "Tanh" - } - } - - /* NOTE(20260825-qing): 这个函数在序列化时可能会有用 */ - public func get_value(): Float64 { - return match(this) { - case None => Float64(0.0f64) - case Sigmoid => Float64(0.0f64) - case ReLU => Float64(0.0f64) - case Leaky_ReLU(alpha) => alpha - case Tanh => Float64(0.0f64) - case Softmax => Float64(0.0f64) - } - } - - /* -------- 空的激活函数 -------- */ - private static func none(M: Matrix) { - return M.copy() - } - - /* -------- 空激活函数的导数 -------- */ - private static func none_dot(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - return Matrix(row, col, 1.0f64) - } - - /* -------- S型生长曲线 -------- */ - private static func sigmoid(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 = 1.0f64 / (1.0f64 + exp(-x1)) - N.set(r, c, x2) - } - } - return N - } - - /* -------- S型生长曲线的导数 -------- */ - private static func sigmoid_dot(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 = 1.0f64 / (1.0f64 + exp(-x1)) - let x3 = x2 * (1.0f64 - x2) - N.set(r, c, x3) - } - } - return N - } - - /* -------- 线性整流单元 -------- */ - private static func relu(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 =if (x1 > 0.0f64) { x1 } else{ 0.0f64 } - N.set(r, c, x2) - } - } - return N - } - - /* -------- 线性整流单元的导数 -------- */ - private static func relu_dot(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 =if (x1 > 0.0f64) { 1.0f64 } else{ 0.0f64 } - N.set(r, c, x2) - } - } - return N - } - - /* -------- 带泄露的线性整流单元 -------- */ - private static func leaky_relu(M: Matrix, alpha: Float64) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 =if (x1 > 0.0f64) { x1 } else{ x1 * alpha } - N.set(r, c, x2) - } - } - return N - } - - /* -------- 带泄露的整流单元导数 -------- */ - private static func leaky_relu_dot(M: Matrix, alpha: Float64) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 =if (x1 > 0.0f64) { 1.0f64 } else{ alpha } - N.set(r, c, x2) - } - } - return N - } - - /* -------- 双曲正切函数 --------*/ - private static func tanh(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let x1 = M.get(r, c) - let x2 = tanh(x1) - N.set(r, c, x2) - } - } - return N - } - - /* -------- 双曲正切函数的导数 -------- */ - private static func tanh_dot(M: Matrix) { - let row = M.getRowDimension() - let col = M.getColumnDimension() - let N = Matrix(row, col) - for (r in 0..row) { - for (c in 0..col) { - let y_val = M.get(r, c) - let rea = 1.0f64 - y_val * y_val - N.set(r, c, rea) - } - } - return N - } - -} diff --git a/bot4cj/src/math/Ini.cj b/bot4cj/src/math/Ini.cj deleted file mode 100644 index e0a5e0c..0000000 --- a/bot4cj/src/math/Ini.cj +++ /dev/null @@ -1,28 +0,0 @@ -package bot4cj.math -import std.random.* -import std.time.* -import std.math.* - -/* -------- 神经网络使用的权重矩阵初始化类 -------- - * TODO(20260517-qing): 将该函数改为枚举类,统一一个接口,根据模式匹配执行初始化 - * - 这样在矩阵式中可以定义初始化方式 */ -public class Ini { - - /* xavier正态初始化 - 返回数组 */ - public static func xavierNormalInit(fan_in: Int64, fan_out: Int64): Array> { - let seed = DateTime.now().nanosecond - let random = Random(UInt64(seed)) - let sigma = sqrt(2.0f64 / Float64(fan_in + fan_out)) /* 标准差 */ - var array = Array>(fan_in, repeat: Array(fan_out, repeat: random.nextGaussianFloat64(mean: 0.0f64, sigma: sigma))) - return array - } - - /* xavier正态初始化 - 返回数组 */ - public static func xavierUniformInit(fan_in: Int64, fan_out: Int64): Array> { - let limit = sqrt(6.0f64 / Float64(fan_in + fan_out)) - let seed = DateTime.now().nanosecond - let random = Random(UInt64(seed)) - var array = Array>(fan_in, repeat: Array(fan_out, repeat: (random.nextFloat64() * 2.0f64 - 1.0f64) * limit)) - return array - } -} diff --git a/bot4cj/src/math/nn.cj b/bot4cj/src/math/nn.cj deleted file mode 100644 index 33bd0d0..0000000 --- a/bot4cj/src/math/nn.cj +++ /dev/null @@ -1,154 +0,0 @@ -package bot4cj.math -import std.time.* -import std.fs.* -import std.io.* -import std.random.* -import std.convert.* -import std.collection.* -import cangjie_tpc::matrix4cj.Matrix - - -public class Nns { - - let nns = ArrayList() - - public func add(layer: Nn) { - nns.add(layer) - } - - /* 【神经网络训练】 - * description: 输入一组原始数据和教师数据,进行神经网络训练 - * @param nns: 输入神经网络结构 - * @param m: 输入一组原始数据 - * @param t: 输入一组教师数据 - * @param discount: 输入本次训练的折扣系数 - */ - public func train(m: Matrix, t: Matrix, discount: Float64) { - - /* ======== 这个对象用于暂时占位 ======== */ - var res = Option.None - - /* ======== 正向传播 ======== */ - for (idx in 0..nns.size) { - let x = if (idx == 0) { m } else { res.getOrThrow() } - res = nns[idx].forward(x) - } - - /* ======== 计算误差 ======== */ - var errs = res.getOrThrow().minus(t) - - /* ======== 反向传播 ======== */ - for (idx in (nns.size-1)..=0:-1) { - errs = nns[idx].backward(errs) - } - - /* ======== 梯度更新 ======== */ - for (idx in 0..nns.size) { - nns[idx].update(discount) - } - - /* ======== 计算MSE损失 ======== - FIXME*(20260517-qing): 对于多个结果计算误差(目前只计算了第一个结果) */ - - let t0 = t.get(0, 0) - let r0 = res.getOrThrow().get(0, 0) - let loss0 = 0.5 * (t0 - r0) * (t0 - r0) - //let loss1 = 0.5 * (t1 - r1) * (t1 - r1) - //return (loss0 + loss1) / 2.0 - return loss0 - } -} - -/* - * 20260823版本的神经网络,使用matrix4cj库 - * TODO: 1.使用matrix4cj重写 - * 2.使用数组表示批次 - */ -public class Nn { - - /* ---- 形状 ---- */ - let inputno: Int64 - let outputno:Int64 - /* ---- 参数 ---- */ - var weights: Matrix /* (inputs, outputs) */ - var bias: Matrix /* (1, output) */ - /* ---- 学习 ---- */ - let lr: Float64 - let f: Af /* 激活函数 */ - /* ---- 缓存 ----*/ - var prev_input: Option = None - var prev_raw_output: Option = None - var prev_output: Option = None - var prev_weight_grad: Option = None - /* ---- 梯度 ----*/ - var weights_grad: Option = None - var bias_grad: Option = None - - /* ---- 初始化器 ---- */ - public init(i: Int64, o: Int64, lr: Float64, f: Af) { - inputno = i - outputno= o - this.lr = lr - this.f = f - weights = Matrix(Ini.xavierNormalInit(i, o)) - bias = Matrix(1, o) - } - - /* ---- 推理 ---- */ - public func forward(x: Matrix) { - prev_input = x - var r = x.times(weights) - r = r.plus(bias) - prev_raw_output = r - var r1 = f.forward(r) - prev_output = r1 - return r1 - } - - /* ---- 反向传播 ---- */ - public func backward(e: Matrix) { - let fb = f.backward(prev_raw_output.getOrThrow()) - let first = e.arrayTimes(fb) - let mx = prev_input.getOrThrow().transpose() - weights_grad = mx.times(first) - bias_grad = first - let e_up = first.times(weights.transpose()) - return e_up - } - - /* -------- 更新权重值、偏爱因子 -------- - * NOTE: discount(折扣)是为了方便深度强化学习给出奖励值 */ - public func update(discount: Float64) { - weights = weights.minus(weights_grad.getOrThrow() * lr * discount) - bias = bias.minus(bias_grad.getOrThrow() * lr * discount) - } - -} - -public func testNn() { - let m = Matrix(1, 2) - let t = Matrix(1, 2) - - //let random = Random() - let random = Random(UInt64(DateTime.now().nanosecond)) - let a = random.nextInt8(2) - let b = random.nextInt8(2) - let t0 = if ((a == 0 && b == 0) || (a ==1 && b == 1)) { 1.0f64 } else { 0.0f64 } - let t1 = if (a != b) { 1.0f64 } else { 0.0f64 } - m.set(0, 0, Float64(a)) - m.set(0, 1, Float64(b)) - t.set(0, 0, t0) - t.set(0, 1, t1) - - let nns = Nns() - nns.add(Nn(2, 4, 0.01f64, Af.Leaky_ReLU(0.1f64))) - nns.add(Nn(4, 2, 0.01f64, Af.Sigmoid)) - let num = 1000 - let prt_num = 100 - for (i in 0..num) { - let loss = nns.train(m, t, 1.0f64) - if (i % prt_num == prt_num-1) { - println("${i}\t: ${loss}") - } - } -}