引入matrix4cj创建了一个新的神经网络
This commit is contained in:
1 parent
c4154d4db9
commit
cc72248e26
4 files changed
+235
-32
No files matched your search
@@ -21,6 +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"
|
||||
# 这种x86机器人开发板感觉不经常使用,我没用过,不知道里面的i2c调用是不是参数是一样的
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
[target.x86_64-unknown-linux-gnu.dependencies]
|
||||
|
||||
+67
-32
@@ -1,15 +1,23 @@
|
||||
package bot4cj
|
||||
import std.io.*
|
||||
import std.fs.*
|
||||
|
||||
/*
|
||||
* 机器人脚本解析器 - 仓颉语言
|
||||
*
|
||||
*/
|
||||
|
||||
import std.argopt.*
|
||||
import std.collection.*
|
||||
import std.env.*
|
||||
import std.time.*
|
||||
import std.argopt.*
|
||||
import std.convert.*
|
||||
import std.collection.*
|
||||
import std.random.*
|
||||
import std.io.*
|
||||
import std.fs.*
|
||||
import stdx.encoding.json.*
|
||||
import bot4cj.hd.*
|
||||
import bot4cj.math.*
|
||||
import ctype4cj.*
|
||||
import cangjie_tpc::matrix4cj.Matrix
|
||||
|
||||
/* ---- 神经网络输出路径 ---- */
|
||||
var NNS_OUT: Option<String> = None
|
||||
@@ -17,10 +25,10 @@ main(args: Array<String>): Int64 {
|
||||
|
||||
/* ---- 解析命令行参数 ---- */
|
||||
let specs = [
|
||||
ArgumentSpec.Long("help", ArgumentMode.NoValue), /* ---- 拉起帮助菜单 ---- */
|
||||
ArgumentSpec.Short(r'i', ArgumentMode.RequiredValue), /* ---- 神经网络模型 - 输入 ---- */
|
||||
ArgumentSpec.Short(r'o', ArgumentMode.RequiredValue), /* ---- 神经网络模型 - 输出 ---- */
|
||||
ArgumentSpec.Long("test", ArgumentMode.RequiredValue) /* ---- 运行一个测试分支 - 需要输入测试类型 ---- */
|
||||
ArgumentSpec.Long("help", ArgumentMode.NoValue), /* ---- 拉起帮助 ---- */
|
||||
ArgumentSpec.Short(r'i', ArgumentMode.RequiredValue), /* ---- 输入模型 ---- */
|
||||
ArgumentSpec.Short(r'o', ArgumentMode.RequiredValue), /* ---- 输出模型 ---- */
|
||||
ArgumentSpec.Long("test", ArgumentMode.RequiredValue) /* ---- 输入一个测试 ---- */
|
||||
]
|
||||
|
||||
/* ---- 执行解析 ---- */
|
||||
@@ -30,10 +38,10 @@ main(args: Array<String>): Int64 {
|
||||
//---------------------------
|
||||
/* 读取设置项 */
|
||||
|
||||
/*---------------------------*/
|
||||
/*---------------------------*/
|
||||
/* 初始化神经网络 (init nn)
|
||||
* TODO: 可以去掉内部初始化参数,使用矩阵式模板进行初始化 */
|
||||
/*
|
||||
* 初始化神经网络 (init nn)
|
||||
* TODO: 可以去掉内部初始化参数,使用矩阵式模板进行初始化
|
||||
*/
|
||||
|
||||
|
||||
//var nns: ArrayList<Nn> =
|
||||
@@ -53,28 +61,27 @@ main(args: Array<String>): Int64 {
|
||||
NNS_OUT = Option<String>.Some(options['o'])
|
||||
}
|
||||
|
||||
/*---------------------------*/
|
||||
/*---------------------------*/
|
||||
/* 分支选择 */
|
||||
|
||||
|
||||
/* -------- 拉起帮助手册
|
||||
* -------- */
|
||||
/* -------- 拉起帮助手册 -------- */
|
||||
if (options.contains("help")) {
|
||||
print_help()
|
||||
return 0
|
||||
}
|
||||
|
||||
/* -------- 启动一个测试分支
|
||||
* -------- */
|
||||
/* -------- 启动一个测试分支 -------- */
|
||||
else if (options.contains("test")) {
|
||||
run_test(options["test"])
|
||||
return 0
|
||||
}
|
||||
|
||||
/* -------- 缺省行为:从标准输入获取动作脚本
|
||||
* --------
|
||||
* -------- TODO(20260519-qing): 进行脚本引入(相对路径也可,从**环境变量**的路径中搜寻也可) */
|
||||
/*
|
||||
* 缺省行为:从标准输入获取动作脚本
|
||||
*
|
||||
* TODO(20260519-qing): 进行脚本引入(相对路径也可,从**环境变量**的路径中搜寻也可)
|
||||
*/
|
||||
else {
|
||||
let consoleReader = getStdIn()
|
||||
let robot = RobotStruct(consoleReader)
|
||||
@@ -82,12 +89,11 @@ main(args: Array<String>): Int64 {
|
||||
robot.active()
|
||||
robot.run()
|
||||
}
|
||||
finally {
|
||||
robot.deactive()
|
||||
}
|
||||
|
||||
/* ---- NOTE(20260523-qing): 储存微调网络模型
|
||||
* ---- */
|
||||
/* 无论有没有成功激活,都进行清理 */
|
||||
finally { robot.deactive() }
|
||||
|
||||
/* NOTE(20260523-qing): 储存微调网络模型 */
|
||||
// let consoleReader = getStdIn()
|
||||
// run_action_drl(consoleReader, nns)
|
||||
// if (options.contains("o")) {
|
||||
@@ -98,8 +104,7 @@ main(args: Array<String>): Int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
/* -------- 打印帮助手册
|
||||
* -------- */
|
||||
/* -------- 打印帮助手册 -------- */
|
||||
func print_help()
|
||||
{
|
||||
println("这是一个机器人动作脚本解析器。")
|
||||
@@ -112,13 +117,14 @@ func print_help()
|
||||
println("-o 设置输出的模型的路径")
|
||||
}
|
||||
|
||||
/* -------- 集成多种常规测试、临时测试
|
||||
* -------- */
|
||||
/* -------- 集成多种常规测试、临时测试 -------- */
|
||||
func run_test(key: String) {
|
||||
|
||||
/* ----------- 神经网络与门测试
|
||||
* -----------
|
||||
* ----------- INFO: 我们使用随机生成的动态数据集,这样会导致一些后果 */
|
||||
/*
|
||||
* 神经网络与门测试
|
||||
*
|
||||
* INFO: 我们使用随机生成的动态数据集,这样会导致一些后果
|
||||
*/
|
||||
if (key == "nn") {
|
||||
let nn_t = ArrayList<Nn1>()
|
||||
nn_t.add(Nn1(2, 4, 0.05f32, Af.Leaky_ReLU(FP32(0.01))))
|
||||
@@ -139,6 +145,35 @@ func run_test(key: String) {
|
||||
}
|
||||
}
|
||||
|
||||
else if (key == "nn1") {
|
||||
|
||||
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(Nn2(2, 4, 0.01f64, Af.ReLU))
|
||||
nns.add(Nn2(4, 2, 0.01f64, Af.ReLU))
|
||||
let num = 200
|
||||
let prt_num = 10
|
||||
for (i in 0..num) {
|
||||
let loss = nns.train(m, t, 1.0f64)
|
||||
if (i % prt_num == prt_num-1) {
|
||||
println("${i}\t: ${loss}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if (key == "cnn") {
|
||||
testCNN()
|
||||
|
||||
@@ -21,6 +21,15 @@ public class Ini {
|
||||
}
|
||||
}
|
||||
|
||||
/* xavier正态初始化 - 返回数组 */
|
||||
public static func xavierNormalInit(fan_in: Int64, fan_out: Int64): Array<Array<Float64>> {
|
||||
let seed = DateTime.now().nanosecond
|
||||
let random = Random(UInt64(seed))
|
||||
let sigma = sqrt(2.0f64 / Float64(fan_in + fan_out)) /* 标准差 */
|
||||
var array = Array<Array<Float64>>(fan_in, repeat: Array<Float64>(fan_out, repeat: random.nextGaussianFloat64(mean: 0.0f64, sigma: sigma)))
|
||||
return array
|
||||
}
|
||||
|
||||
/* -------- Glorot均匀初始化 -------- */
|
||||
public static func xavierUniformInit(target: Matrix1, fan_in: Int64, fan_out: Int64) {
|
||||
let limit = sqrt(6.0f32 / Float32(fan_in + fan_out))
|
||||
@@ -34,4 +43,13 @@ public class Ini {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* xavier正态初始化 - 返回数组 */
|
||||
public static func xavierUniformInit(fan_in: Int64, fan_out: Int64): Array<Array<Float64>> {
|
||||
let limit = sqrt(6.0f64 / Float64(fan_in + fan_out))
|
||||
let seed = DateTime.now().nanosecond
|
||||
let random = Random(UInt64(seed))
|
||||
var array = Array<Array<Float64>>(fan_in, repeat: Array<Float64>(fan_out, repeat: (random.nextFloat64() * 2.0f64 - 1.0f64) * limit))
|
||||
return array
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package bot4cj.math
|
||||
import std.fs.*
|
||||
import std.io.*
|
||||
import std.convert.*
|
||||
import std.collection.*
|
||||
import cangjie_tpc::matrix4cj.Matrix
|
||||
//foreign func Sigmoid_do(m: CPointer<Unit>): CPointer<Unit>
|
||||
//foreign func Sigmoid_dot(m: CPointer<Unit>): CPointer<Unit>
|
||||
//foreign func ReLU_do(m: CPointer<Unit>): CPointer<Unit>
|
||||
@@ -12,6 +14,153 @@ import std.convert.*
|
||||
//foreign func Tanh_dot(m: CPointer<Unit>): CPointer<Unit>
|
||||
|
||||
|
||||
|
||||
public class Nns {
|
||||
|
||||
let nns = ArrayList<Nn2>()
|
||||
|
||||
public func add(layer: Nn2) {
|
||||
nns.add(layer)
|
||||
}
|
||||
|
||||
/* 【神经网络训练】
|
||||
* description: 输入一组原始数据和教师数据,进行神经网络训练
|
||||
* @param nns: 输入神经网络结构
|
||||
* @param m: 输入一组原始数据
|
||||
* @param t: 输入一组教师数据
|
||||
* @param discount: 输入本次训练的折扣系数
|
||||
*/
|
||||
public func train(m: Matrix, t: Matrix, discount: Float64) {
|
||||
|
||||
/* ======== 这个对象用于暂时占位 ======== */
|
||||
var res = Option<Matrix>.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 Nn2 {
|
||||
|
||||
/* ---- 形状 ---- */
|
||||
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<Matrix> = None
|
||||
var prev_raw_output: Option<Matrix> = None
|
||||
var prev_output: Option<Matrix> = None
|
||||
var prev_weight_grad: Option<Matrix> = None
|
||||
/* ---- 梯度 ----*/
|
||||
var weights_grad: Option<Matrix> = None
|
||||
var bias_grad: Option<Matrix> = None
|
||||
|
||||
/* -------- 带泄露的线性整流单元 -------- */
|
||||
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
|
||||
}
|
||||
/* ---- 初始化器 ---- */
|
||||
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 = leaky_relu(r, 0.01f64)
|
||||
prev_output = r1
|
||||
return r1
|
||||
}
|
||||
|
||||
/* ---- 反向传播 ---- */
|
||||
public func backward(e: Matrix) {
|
||||
let fb = leaky_relu_dot(prev_raw_output.getOrThrow(), 0.01f64)
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------- 新版的神经网络,使用原生矩阵对象实现 --------
|
||||
* TODO(20260517-qing): 增加batch批次处理,使用ArrayList<Matrix1>
|
||||
* TODO*(20260519-qing): 将神经网络转换为MatrixObject矩阵式对象
|
||||
|
||||
Reference in new issue
Block a user