chore: 改名同步 TransPyV -> ViperC(源码/配置内的纯替换)

This commit is contained in:
TermiNexus committed 2026-10-12 15:06:50 +08:00
1 parent 33d91e5d17
commit 85b89b6e8d
16 files changed
+314 -314

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Desktop chat client: vqt6 GUI, requests(https) for network, json for parsing responses",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "Standalone Viper repro for CreateProcessA returning 0 / GetLastError=87",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+2 -2
View File
@@ -1,9 +1,9 @@
# main2.vp — ViperFLProject fltk GUI 测试(回调 + 控件展示)
#
# 构建需 TPV/TPC 支持 project.vpj linker.static_libs 静态链接
# 构建需 VPC/TPC 支持 project.vpj linker.static_libs 静态链接
# (本工程已配置链接 ../includes/fltk/cfltk/build 下的 cfltk2 + FLTK 静态库)。
#
# 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(TPV 自动把函数名
# 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(VPC 自动把函数名
# bitcast 为函数指针)。回调签名统一为 def cb(w: bytes, data: bytes),
# 其中 w 是触发回调的控件指针,data 是注册时传入的用户数据。
import t, c
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ViperFLProject - FLTK GUI Test",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+293 -293
View File
@@ -1,293 +1,293 @@
# -*- coding: utf-8 -*-
# ============================================================
# ViperMNIST - 28x28 手写数字识别(MLP / CNN, torch-lite)
#
# 入口分发:
# * 无命令行参数 → 启动 Qt6 图形面板(数据/训练/推理, 含 3D 网络图)
# * 带命令行参数 → 走原 CLI(train / use)
#
# CLI 用法:
# app.exe --mode train --data-dir data --epochs 5 --batch 64 --lr 0.01 \
# --hidden 256 --save models/mnist.bin --limit 60000
# app.exe --mode train --arch cnn --c1 8 --c2 16 (卷积 + 池化, 更抗形变)
# app.exe --mode use --data-dir data --load models/mnist.bin --show 10
# --download 自动下载缺失数据; --file 指定本地已下载 .gz(可 1~2 次)
# --no-aug 关闭数据增强(默认开: 训练时随机平移 ±2px)
# 注: use 模式的架构/hidden/通道以模型文件头为准, 无需与命令行走一致
#
# 模型: MLP = Linear(784->hidden) -> ReLU -> Linear(hidden->10)
# CNN = Conv(1->c1,3x3,pad1) -> ReLU -> MaxPool2 -> Conv(c1->c2,3x3,pad1)
# -> ReLU -> MaxPool2 -> Linear(49*c2->hidden) -> ReLU -> Linear(hidden->10)
# 权重形状同 PyTorch: Conv(out,in,k,k) / Linear(out,in), b(out)
# 计算: torch-lite 线性前向走 vipersimd.simd_dot4d, relu 走 simd_max4d
# ============================================================
import t, c
from stdint import *
import stdlib
import string
import stdio
import sys
import memhub
import argparse
import requests
import torch
import w32.win32console as w32cmd
import lib.MnistData as MnistData
import lib.MnistNet as MnistNet
import lib.AppGui as AppGui
define CODE_PAGE = 65001 # UTF-8 控制台
# 主内存池(CLI 与 GUI 共用)
define POOL_SIZE = 536870912 # 512 MB
# ============================================================
# CLI
# ============================================================
def run_cli(pool: memhub.MemBuddy*) -> int:
parser: argparse.ArgumentParser* = argparse.ArgumentParser(
"ViperMNIST", "28x28 MNIST 手写数字识别 (train/use)", pool=pool)
parser.add_argument("--mode", None, argparse.STRING, 0, "train", False,
argparse.STORE, "train=训练 / use=加载模型推理")
parser.add_argument("--data-dir", None, argparse.STRING, 0, "data", False,
argparse.STORE, "MNIST IDX 文件所在目录")
parser.add_argument("--epochs", None, argparse.INT, 5, None, False,
argparse.STORE, "训练轮数")
parser.add_argument("--batch", None, argparse.INT, 64, None, False,
argparse.STORE, "批大小")
parser.add_argument("--lr", None, argparse.STRING, 0, "0.01", False,
argparse.STORE, "学习率(小数; 训练用重球法, 默认 0.01)")
parser.add_argument("--hidden", None, argparse.INT, 256, None, False,
argparse.STORE, "隐藏层宽度(CNN 下为 FC1 宽度)")
parser.add_argument("--arch", None, argparse.STRING, 0, "mlp", False,
argparse.STORE, "架构: mlp=全连接 / cnn=卷积+池化")
parser.add_argument("--c1", None, argparse.INT, 8, None, False,
argparse.STORE, "CNN conv1 通道数(仅 --arch cnn 生效)")
parser.add_argument("--c2", None, argparse.INT, 16, None, False,
argparse.STORE, "CNN conv2 通道数(仅 --arch cnn 生效)")
parser.add_argument("--no-aug", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "关闭数据增强(默认开启: 训练时随机平移 ±2px)")
parser.add_argument("--limit", None, argparse.INT, 0, None, False,
argparse.STORE, "样本上限(0=全部)")
parser.add_argument("--save", None, argparse.STRING, 0, "mnist.bin",
False, argparse.STORE, "训练保存路径")
parser.add_argument("--load", None, argparse.STRING, 0, "mnist.bin",
False, argparse.STORE, "推理加载路径")
parser.add_argument("--show", None, argparse.INT, 10, None, False,
argparse.STORE, "use 模式打印前 N 条预测")
parser.add_argument("--seed", None, argparse.INT, 42, None, False,
argparse.STORE, "随机种子")
parser.add_argument("--download", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "自动下载缺失的 MNIST 数据")
parser.add_argument("--file", None, argparse.STRING, 0, None, False,
argparse.STORE, "本地已下载的 .gz(可 1~2 次: 图像/标签各一份), 优先本地解压替代联网")
parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "显示帮助并退出")
args: argparse.ParsedArgs* = parser.parse_args(sys._argc, sys._argv)
if args is None:
stdio.printf("参数解析失败\n")
return 1
if args.get_bool("help"):
parser.print_help()
return 0
mode: str = args.get_str("mode")
data_dir: str = args.get_str("data-dir")
epochs: int = args.get_int("epochs")
batch: int = args.get_int("batch")
hidden: int = args.get_int("hidden")
limit: int = args.get_int("limit")
show: int = args.get_int("show")
seed: int = args.get_int("seed")
save_path: str = args.get_str("save")
load_path: str = args.get_str("load")
arch_str: str = args.get_str("arch")
c1_arg: int = args.get_int("c1")
c2_arg: int = args.get_int("c2")
lr_str: str = args.get_str("lr")
download: int = 0
if args.get_bool("download"):
download = 1
no_aug: int = 0
if args.get_bool("no-aug"):
no_aug = 1
# --file 本地 .gz(可 1~2 次): 按文件名含 -labels-/-images- 归类, 无名匹配按先后补空位
loc_im: str = None
loc_lb: str = None
i_arg: int = 1
while i_arg + 1 < sys._argc:
if string.strcmp(sys._argv[i_arg], "--file") == 0:
fv: str = sys._argv[i_arg + 1]
is_lb: int = 0
if string.strstr(fv, "-labels-") is not None:
is_lb = 1
is_im: int = 0
if string.strstr(fv, "-images-") is not None:
is_im = 1
if is_lb != 0 and is_im == 0 and loc_lb is None:
loc_lb = fv
elif is_im != 0 and is_lb == 0 and loc_im is None:
loc_im = fv
elif loc_im is None:
loc_im = fv
elif loc_lb is None:
loc_lb = fv
i_arg += 2
else:
i_arg += 1
file_set: int = 0
if loc_im is not None or loc_lb is not None:
file_set = 1
lr: double = double(0.01)
if lr_str is not None and string.strlen(lr_str) > 0:
lr = MnistData.atof(lr_str, lr)
MnistNet.rand_seed(uint64(seed))
torch.manual_seed(int64(seed))
h: sizet = sizet(hidden)
# 架构与数据增强: 与 GUI 口径一致(通道数只在 CNN 下有意义)
arch: int = MnistNet.ARCH_MLP
if string.strcmp(arch_str, "cnn") == 0 or string.strcmp(arch_str, "CNN") == 0:
arch = MnistNet.ARCH_CNN
c1: sizet = 0
c2: sizet = 0
if arch == MnistNet.ARCH_CNN:
c1 = sizet(c1_arg)
c2 = sizet(c2_arg)
augment: int = 1
if no_aug != 0:
augment = 0
stdio.printf("ViperMNIST mode=%s data=%s limit=%d hidden=%d epochs=%d batch=%d lr=%.3f arch=%s\n",
mode, data_dir, limit, hidden, epochs, batch, lr, arch_str)
p_img: str = stdlib.malloc(1024)
p_lbl: str = stdlib.malloc(1024)
if string.strcmp(mode, "train") == 0:
net: MnistNet.Net* = MnistNet.Net(pool, h, sizet(arch), c1, c2)
if MnistNet.net_ok(net) == 0:
stdio.printf("FAIL: 网络分配失败\n")
return 1
MnistNet.init_net_weights(net)
MnistData.idx_paths(data_dir, 0, p_img, p_lbl)
if download != 0 or file_set != 0:
if MnistData.ensure_mnist(data_dir, 0, download, loc_im, loc_lb) != 0:
stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n")
return 1
cap: sizet = sizet(60000)
if limit > 0 and limit < 60000:
cap = sizet(limit)
xbuf: double* = stdlib.malloc(cap * MnistData.N_IN * 8)
ybuf: int* = stdlib.malloc(cap * 4)
if xbuf is None or ybuf is None:
stdio.printf("FAIL: 训练数据缓冲分配失败\n")
return 1
n_im: sizet = MnistData.load_mnist_images(p_img, xbuf, cap)
n_lb: sizet = MnistData.load_mnist_labels(p_lbl, ybuf, cap)
n_tr: sizet = n_im
if n_lb < n_tr:
n_tr = n_lb
stdio.printf("加载训练样本=%zu 张 (%s)\n", n_tr, MnistNet.arch_name(arch))
if n_tr == 0:
stdio.printf("未找到可用数据。如 data 目录文件残缺/损坏, 请加 --download 重新拉取或用 --file 指定本地 .gz\n")
return 1
MnistNet.prog_init()
MnistNet.train_run(pool, net, xbuf, ybuf, n_tr,
sizet(batch), sizet(epochs), lr, save_path, augment)
stdlib.free(xbuf)
stdlib.free(ybuf)
elif string.strcmp(mode, "use") == 0:
# 架构/hidden/通道以模型文件头为准(命令行给的对推理无意义), 先读头再建网
minfo: int* = stdlib.malloc(20)
if minfo is None:
stdio.printf("FAIL: 模型头缓冲分配失败\n")
return 1
if MnistNet.peek_model(load_path, minfo) == 0:
stdlib.free(minfo)
stdio.printf("加载模型失败, 请先训练(--mode train): %s\n", load_path)
return 1
f_arch: int = minfo[0]
f_hidden: int = minfo[1]
f_c1: int = minfo[2]
f_c2: int = minfo[3]
stdlib.free(minfo)
uh: sizet = sizet(f_hidden)
uc1: sizet = 0
uc2: sizet = 0
if f_arch == MnistNet.ARCH_CNN:
uc1 = sizet(f_c1)
uc2 = sizet(f_c2)
net2: MnistNet.Net* = MnistNet.Net(pool, uh, sizet(f_arch),
uc1, uc2)
if MnistNet.net_ok(net2) == 0:
stdio.printf("FAIL: 网络分配失败\n")
return 1
MnistData.idx_paths(data_dir, 1, p_img, p_lbl)
if download != 0 or file_set != 0:
if MnistData.ensure_mnist(data_dir, 1, download, loc_im, loc_lb) != 0:
stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n")
return 1
cap2: sizet = sizet(10000)
if limit > 0 and limit < 10000:
cap2 = sizet(limit)
xbuf2: double* = stdlib.malloc(cap2 * MnistData.N_IN * 8)
ybuf2: int* = stdlib.malloc(cap2 * 4)
if xbuf2 is None or ybuf2 is None:
stdio.printf("FAIL: 测试数据缓冲分配失败\n")
return 1
n_te: sizet = MnistData.load_mnist_images(p_img, xbuf2, cap2)
n_tl: sizet = MnistData.load_mnist_labels(p_lbl, ybuf2, cap2)
if n_tl < n_te:
n_te = n_tl
stdio.printf("加载测试样本=%zu 张\n", n_te)
if n_te == 0:
return 1
if MnistNet.load_model(net2, load_path) != 0:
stdio.printf("加载模型失败, 请先训练(--mode train)\n")
return 1
stdio.printf("加载模型: %s (%s, hidden=%d)\n",
load_path, MnistNet.arch_name(f_arch), f_hidden)
MnistNet.evaluate_net(pool, net2, xbuf2, ybuf2, n_te,
sizet(batch), sizet(show))
stdlib.free(xbuf2)
stdlib.free(ybuf2)
else:
stdio.printf("未知模式: %s (可选 train/use)\n", mode)
return 1
stdlib.free(p_img)
stdlib.free(p_lbl)
return 0
# ============================================================
# 入口
# ============================================================
def main() -> int:
# UTF-8 控制台(与 TransPyV main 一致)
w32cmd.SetConsoleOutputCP(CODE_PAGE)
w32cmd.SetConsoleCP(CODE_PAGE)
# 主内存池: CLI 与 GUI 共用, 先建池再解析 argv(GUI 分支也需要池)
arena: bytes = stdlib.malloc(POOL_SIZE)
if arena is None:
stdio.printf("FAIL: 无法分配主池\n")
return 1
mb: memhub.MemBuddy* = memhub.MemBuddy(arena, POOL_SIZE, 0)
if mb is None:
stdio.printf("FAIL: MemBuddy 初始化失败\n")
return 1
argparse._mbuddy = mb
sys._mbuddy = mb
requests._mbuddy = mb # requests/https 内部用 _mbuddy 分配响应缓冲
sys._init_argv()
# 无参数 → Qt 面板; 有参数 → CLI
if sys._argc <= 1:
return AppGui.run(mb)
return run_cli(mb)
# -*- coding: utf-8 -*-
# ============================================================
# ViperMNIST - 28x28 手写数字识别(MLP / CNN, torch-lite)
#
# 入口分发:
# * 无命令行参数 → 启动 Qt6 图形面板(数据/训练/推理, 含 3D 网络图)
# * 带命令行参数 → 走原 CLI(train / use)
#
# CLI 用法:
# app.exe --mode train --data-dir data --epochs 5 --batch 64 --lr 0.01 \
# --hidden 256 --save models/mnist.bin --limit 60000
# app.exe --mode train --arch cnn --c1 8 --c2 16 (卷积 + 池化, 更抗形变)
# app.exe --mode use --data-dir data --load models/mnist.bin --show 10
# --download 自动下载缺失数据; --file 指定本地已下载 .gz(可 1~2 次)
# --no-aug 关闭数据增强(默认开: 训练时随机平移 ±2px)
# 注: use 模式的架构/hidden/通道以模型文件头为准, 无需与命令行走一致
#
# 模型: MLP = Linear(784->hidden) -> ReLU -> Linear(hidden->10)
# CNN = Conv(1->c1,3x3,pad1) -> ReLU -> MaxPool2 -> Conv(c1->c2,3x3,pad1)
# -> ReLU -> MaxPool2 -> Linear(49*c2->hidden) -> ReLU -> Linear(hidden->10)
# 权重形状同 PyTorch: Conv(out,in,k,k) / Linear(out,in), b(out)
# 计算: torch-lite 线性前向走 vipersimd.simd_dot4d, relu 走 simd_max4d
# ============================================================
import t, c
from stdint import *
import stdlib
import string
import stdio
import sys
import memhub
import argparse
import requests
import torch
import w32.win32console as w32cmd
import lib.MnistData as MnistData
import lib.MnistNet as MnistNet
import lib.AppGui as AppGui
define CODE_PAGE = 65001 # UTF-8 控制台
# 主内存池(CLI 与 GUI 共用)
define POOL_SIZE = 536870912 # 512 MB
# ============================================================
# CLI
# ============================================================
def run_cli(pool: memhub.MemBuddy*) -> int:
parser: argparse.ArgumentParser* = argparse.ArgumentParser(
"ViperMNIST", "28x28 MNIST 手写数字识别 (train/use)", pool=pool)
parser.add_argument("--mode", None, argparse.STRING, 0, "train", False,
argparse.STORE, "train=训练 / use=加载模型推理")
parser.add_argument("--data-dir", None, argparse.STRING, 0, "data", False,
argparse.STORE, "MNIST IDX 文件所在目录")
parser.add_argument("--epochs", None, argparse.INT, 5, None, False,
argparse.STORE, "训练轮数")
parser.add_argument("--batch", None, argparse.INT, 64, None, False,
argparse.STORE, "批大小")
parser.add_argument("--lr", None, argparse.STRING, 0, "0.01", False,
argparse.STORE, "学习率(小数; 训练用重球法, 默认 0.01)")
parser.add_argument("--hidden", None, argparse.INT, 256, None, False,
argparse.STORE, "隐藏层宽度(CNN 下为 FC1 宽度)")
parser.add_argument("--arch", None, argparse.STRING, 0, "mlp", False,
argparse.STORE, "架构: mlp=全连接 / cnn=卷积+池化")
parser.add_argument("--c1", None, argparse.INT, 8, None, False,
argparse.STORE, "CNN conv1 通道数(仅 --arch cnn 生效)")
parser.add_argument("--c2", None, argparse.INT, 16, None, False,
argparse.STORE, "CNN conv2 通道数(仅 --arch cnn 生效)")
parser.add_argument("--no-aug", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "关闭数据增强(默认开启: 训练时随机平移 ±2px)")
parser.add_argument("--limit", None, argparse.INT, 0, None, False,
argparse.STORE, "样本上限(0=全部)")
parser.add_argument("--save", None, argparse.STRING, 0, "mnist.bin",
False, argparse.STORE, "训练保存路径")
parser.add_argument("--load", None, argparse.STRING, 0, "mnist.bin",
False, argparse.STORE, "推理加载路径")
parser.add_argument("--show", None, argparse.INT, 10, None, False,
argparse.STORE, "use 模式打印前 N 条预测")
parser.add_argument("--seed", None, argparse.INT, 42, None, False,
argparse.STORE, "随机种子")
parser.add_argument("--download", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "自动下载缺失的 MNIST 数据")
parser.add_argument("--file", None, argparse.STRING, 0, None, False,
argparse.STORE, "本地已下载的 .gz(可 1~2 次: 图像/标签各一份), 优先本地解压替代联网")
parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "显示帮助并退出")
args: argparse.ParsedArgs* = parser.parse_args(sys._argc, sys._argv)
if args is None:
stdio.printf("参数解析失败\n")
return 1
if args.get_bool("help"):
parser.print_help()
return 0
mode: str = args.get_str("mode")
data_dir: str = args.get_str("data-dir")
epochs: int = args.get_int("epochs")
batch: int = args.get_int("batch")
hidden: int = args.get_int("hidden")
limit: int = args.get_int("limit")
show: int = args.get_int("show")
seed: int = args.get_int("seed")
save_path: str = args.get_str("save")
load_path: str = args.get_str("load")
arch_str: str = args.get_str("arch")
c1_arg: int = args.get_int("c1")
c2_arg: int = args.get_int("c2")
lr_str: str = args.get_str("lr")
download: int = 0
if args.get_bool("download"):
download = 1
no_aug: int = 0
if args.get_bool("no-aug"):
no_aug = 1
# --file 本地 .gz(可 1~2 次): 按文件名含 -labels-/-images- 归类, 无名匹配按先后补空位
loc_im: str = None
loc_lb: str = None
i_arg: int = 1
while i_arg + 1 < sys._argc:
if string.strcmp(sys._argv[i_arg], "--file") == 0:
fv: str = sys._argv[i_arg + 1]
is_lb: int = 0
if string.strstr(fv, "-labels-") is not None:
is_lb = 1
is_im: int = 0
if string.strstr(fv, "-images-") is not None:
is_im = 1
if is_lb != 0 and is_im == 0 and loc_lb is None:
loc_lb = fv
elif is_im != 0 and is_lb == 0 and loc_im is None:
loc_im = fv
elif loc_im is None:
loc_im = fv
elif loc_lb is None:
loc_lb = fv
i_arg += 2
else:
i_arg += 1
file_set: int = 0
if loc_im is not None or loc_lb is not None:
file_set = 1
lr: double = double(0.01)
if lr_str is not None and string.strlen(lr_str) > 0:
lr = MnistData.atof(lr_str, lr)
MnistNet.rand_seed(uint64(seed))
torch.manual_seed(int64(seed))
h: sizet = sizet(hidden)
# 架构与数据增强: 与 GUI 口径一致(通道数只在 CNN 下有意义)
arch: int = MnistNet.ARCH_MLP
if string.strcmp(arch_str, "cnn") == 0 or string.strcmp(arch_str, "CNN") == 0:
arch = MnistNet.ARCH_CNN
c1: sizet = 0
c2: sizet = 0
if arch == MnistNet.ARCH_CNN:
c1 = sizet(c1_arg)
c2 = sizet(c2_arg)
augment: int = 1
if no_aug != 0:
augment = 0
stdio.printf("ViperMNIST mode=%s data=%s limit=%d hidden=%d epochs=%d batch=%d lr=%.3f arch=%s\n",
mode, data_dir, limit, hidden, epochs, batch, lr, arch_str)
p_img: str = stdlib.malloc(1024)
p_lbl: str = stdlib.malloc(1024)
if string.strcmp(mode, "train") == 0:
net: MnistNet.Net* = MnistNet.Net(pool, h, sizet(arch), c1, c2)
if MnistNet.net_ok(net) == 0:
stdio.printf("FAIL: 网络分配失败\n")
return 1
MnistNet.init_net_weights(net)
MnistData.idx_paths(data_dir, 0, p_img, p_lbl)
if download != 0 or file_set != 0:
if MnistData.ensure_mnist(data_dir, 0, download, loc_im, loc_lb) != 0:
stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n")
return 1
cap: sizet = sizet(60000)
if limit > 0 and limit < 60000:
cap = sizet(limit)
xbuf: double* = stdlib.malloc(cap * MnistData.N_IN * 8)
ybuf: int* = stdlib.malloc(cap * 4)
if xbuf is None or ybuf is None:
stdio.printf("FAIL: 训练数据缓冲分配失败\n")
return 1
n_im: sizet = MnistData.load_mnist_images(p_img, xbuf, cap)
n_lb: sizet = MnistData.load_mnist_labels(p_lbl, ybuf, cap)
n_tr: sizet = n_im
if n_lb < n_tr:
n_tr = n_lb
stdio.printf("加载训练样本=%zu 张 (%s)\n", n_tr, MnistNet.arch_name(arch))
if n_tr == 0:
stdio.printf("未找到可用数据。如 data 目录文件残缺/损坏, 请加 --download 重新拉取或用 --file 指定本地 .gz\n")
return 1
MnistNet.prog_init()
MnistNet.train_run(pool, net, xbuf, ybuf, n_tr,
sizet(batch), sizet(epochs), lr, save_path, augment)
stdlib.free(xbuf)
stdlib.free(ybuf)
elif string.strcmp(mode, "use") == 0:
# 架构/hidden/通道以模型文件头为准(命令行给的对推理无意义), 先读头再建网
minfo: int* = stdlib.malloc(20)
if minfo is None:
stdio.printf("FAIL: 模型头缓冲分配失败\n")
return 1
if MnistNet.peek_model(load_path, minfo) == 0:
stdlib.free(minfo)
stdio.printf("加载模型失败, 请先训练(--mode train): %s\n", load_path)
return 1
f_arch: int = minfo[0]
f_hidden: int = minfo[1]
f_c1: int = minfo[2]
f_c2: int = minfo[3]
stdlib.free(minfo)
uh: sizet = sizet(f_hidden)
uc1: sizet = 0
uc2: sizet = 0
if f_arch == MnistNet.ARCH_CNN:
uc1 = sizet(f_c1)
uc2 = sizet(f_c2)
net2: MnistNet.Net* = MnistNet.Net(pool, uh, sizet(f_arch),
uc1, uc2)
if MnistNet.net_ok(net2) == 0:
stdio.printf("FAIL: 网络分配失败\n")
return 1
MnistData.idx_paths(data_dir, 1, p_img, p_lbl)
if download != 0 or file_set != 0:
if MnistData.ensure_mnist(data_dir, 1, download, loc_im, loc_lb) != 0:
stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n")
return 1
cap2: sizet = sizet(10000)
if limit > 0 and limit < 10000:
cap2 = sizet(limit)
xbuf2: double* = stdlib.malloc(cap2 * MnistData.N_IN * 8)
ybuf2: int* = stdlib.malloc(cap2 * 4)
if xbuf2 is None or ybuf2 is None:
stdio.printf("FAIL: 测试数据缓冲分配失败\n")
return 1
n_te: sizet = MnistData.load_mnist_images(p_img, xbuf2, cap2)
n_tl: sizet = MnistData.load_mnist_labels(p_lbl, ybuf2, cap2)
if n_tl < n_te:
n_te = n_tl
stdio.printf("加载测试样本=%zu 张\n", n_te)
if n_te == 0:
return 1
if MnistNet.load_model(net2, load_path) != 0:
stdio.printf("加载模型失败, 请先训练(--mode train)\n")
return 1
stdio.printf("加载模型: %s (%s, hidden=%d)\n",
load_path, MnistNet.arch_name(f_arch), f_hidden)
MnistNet.evaluate_net(pool, net2, xbuf2, ybuf2, n_te,
sizet(batch), sizet(show))
stdlib.free(xbuf2)
stdlib.free(ybuf2)
else:
stdio.printf("未知模式: %s (可选 train/use)\n", mode)
return 1
stdlib.free(p_img)
stdlib.free(p_lbl)
return 0
# ============================================================
# 入口
# ============================================================
def main() -> int:
# UTF-8 控制台(与 ViperC main 一致)
w32cmd.SetConsoleOutputCP(CODE_PAGE)
w32cmd.SetConsoleCP(CODE_PAGE)
# 主内存池: CLI 与 GUI 共用, 先建池再解析 argv(GUI 分支也需要池)
arena: bytes = stdlib.malloc(POOL_SIZE)
if arena is None:
stdio.printf("FAIL: 无法分配主池\n")
return 1
mb: memhub.MemBuddy* = memhub.MemBuddy(arena, POOL_SIZE, 0)
if mb is None:
stdio.printf("FAIL: MemBuddy 初始化失败\n")
return 1
argparse._mbuddy = mb
sys._mbuddy = mb
requests._mbuddy = mb # requests/https 内部用 _mbuddy 分配响应缓冲
sys._init_argv()
# 无参数 → Qt 面板; 有参数 → CLI
if sys._argc <= 1:
return AppGui.run(mb)
return run_cli(mb)
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "2.0.0",
"description": "MNIST 手写数字识别(28x28 灰度, 两层 MLP): 无参数启动 vqt6 Qt 面板(数据/训练/推理 + 3D 网络图 + Qt Charts 曲线), 带参数走原 CLI(train/use); 计算走 includes/torch (仿 PyTorch 迷你库, 线性层内积 vipersimd dot4/relu max4d)",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ViperOpenSSLProject - OpenSSL 3.x FFI Test",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "0.1.0",
"description": "vqt6 第一个示例 - 创建一个 Qt6 窗口,点击按钮退出",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": ["-filetype=obj", "-relocation-model=pic"]
+1 -1
View File
@@ -676,7 +676,7 @@ def main() -> int:
leaf.setChecked(1)
leaf.setSize(1200)
g1.addChild(leaf)
leaf = vqt6.QTreeWidgetItem("网络与调试工具(QtNetwork + TPV)[220 MB]")
leaf = vqt6.QTreeWidgetItem("网络与调试工具(QtNetwork + VPC)[220 MB]")
leaf.setCheckable(1)
leaf.setChecked(0)
leaf.setSize(220)
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ViperQtProject - Qt6 GUI Test",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ViperRequestsTest - HTTP(S) Client Test",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+2 -2
View File
@@ -108,7 +108,7 @@ out[i] = a[i] * b[i] + c[i] # 元素独立, 单趟融合乘加; 每元素
| 文件 | 说明 |
| --- | --- |
| `project.vpj` | Viper 工程配置(产物 `.tpv_build/output/app.exe`) |
| `project.vpj` | Viper 工程配置(产物 `__vpcbuild__/output/app.exe`) |
| `App/main.vp` | Viper 实现: 8 个内核(FMA/ADD/MUL/SQRT × SIMD/原生) + 线程绑定 + QPC/周期双计时 + 进程内多 run; 自解析命令行 `[runs] [len] [iters] [mode]`(GetCommandLineA, 不依赖 sys/memhub) |
| `bench_c.c` | 手写 C: 裸数组 + **全指针 `__restrict`**(fill/内核/校验和/local 指针都加) + noinline, `-O2 -mavx2 -mfma -ffp-contract=fast` 自动向量化单趟 FMA |
| `bench_cpp.cpp` | 手写 C++: `std::vector` + `__restrict`, 同口径(`-O2 -mavx2 -mfma -ffp-contract=fast`) |
@@ -131,7 +131,7 @@ out[i] = a[i] * b[i] + c[i] # 元素独立, 单趟融合乘加; 每元素
### 5.1 构建 Viper 部分(一次性)
在本工程目录(`ViperSpeedBenchmark/`)用你惯用的 tpv 方式构建 `project.vpj`,
产物应为 `.tpv_build/output/app.exe`。若未构建, `run_bench.py` 会提示并**跳过
产物应为 `__vpcbuild__/output/app.exe`。若未构建, `run_bench.py` 会提示并**跳过
全部 Viper 内核变体** 继续其它实现。
> **改了 `App/main.vp` 或 `includes/vipersimd.vp` 后必须重建**, 否则任一 Viper
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "同内核多实现测速基准: out[i]=a[i]*b[i]+c[i] (len=16384, iters=65536, 每次run≈2.147e9 flops; 工作集512KiB 常驻私有L2)。Viper 侧第4个命令行参数 mode 可切 8 个内核: FMA/ADD/MUL/SQRT 各一对 SIMD(simd_*_array) 与 原生(scalar_*_array), 用于 SIMD 加速比对照; mode=0 的 FMA SIMD 与 C/C++/Python 对齐",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+5 -5
View File
@@ -188,7 +188,7 @@ NATIVE_FLAGS = ["-O2", "-mavx2", "-mfma", "-ffp-contract=fast"]
# Viper 内核实现名 -> (传给 app.exe 的第 4 个参数 mode, 显示名)。
# 全部共用同一个 .tpv_build/output/app.exe, 只差这一个 mode 参数 —— 除"跑哪份内核"
# 全部共用同一个 __vpcbuild__/output/app.exe, 只差这一个 mode 参数 —— 除"跑哪份内核"
# 外没有任何差异, 这是 SIMD vs 原生 对照可信的前提(见 App/main.vp 的 KERNEL_* 常量)。
# 命名规则: `<op>` = SIMD, `scalar_<op>` = 同操作的标量(原生)对照。
VIPER_KERNELS = [
@@ -257,7 +257,7 @@ def iters_for(size):
def viper_exe(root):
return root / ".tpv_build" / "output" / "app.exe"
return root / "__vpcbuild__" / "output" / "app.exe"
# ------------------------------------------------------------
@@ -431,7 +431,7 @@ def build_arg_parser():
p.add_argument("--py-mode", default=None, choices=["auto", "numpy", "pure"],
help="覆盖 bench_py.py 的运行模式(auto/numpy/pure)")
p.add_argument("--viper-exe", default=None,
help="覆盖 Viper 产物路径(默认 .tpv_build/output/app.exe)")
help="覆盖 Viper 产物路径(默认 __vpcbuild__/output/app.exe)")
p.add_argument("--flops-check", action="store_true",
help="核对 RESULT 行的 flops 字段是否与 CFG 总运算量一致, "
"并报告 flops≈2e9(时长≈1s)的行占比及降规模提示")
@@ -536,7 +536,7 @@ def main(argv=None):
+ ", ".join(f"{n}(mode={VIPER_MODE[n]})" for n in viper_wanted))
else:
emit(f"[viper] 未找到 Viper 产物: {vpy_exe}")
emit(" 请先在本工程目录用 tpv 构建 project.vpj(生成 .tpv_build/output/app.exe),")
emit(" 请先在本工程目录用 tpv 构建 project.vpj(生成 __vpcbuild__/output/app.exe),")
emit(" 本次将跳过全部 Viper 内核变体。")
# ---- 逐尺寸 × 逐实现跑测(每组=一次进程启动) ----
@@ -804,7 +804,7 @@ def main(argv=None):
f" | [{lab_other}] {other_us:>11.3f} us {gfl(other_us):>8.3f} GFLOPS"
f" | {aff_txt} | {'PASS' if st['passed'] else 'FAIL'}")
if not any(im == "viper" for (_, im) in results):
emit(" (viper 已跳过: 请先构建 .tpv_build/output/app.exe)")
emit(" (viper 已跳过: 请先构建 __vpcbuild__/output/app.exe)")
for impl, note in compile_notes:
emit(f" ({impl} 已跳过: 编译失败, 见上方)")
emit("=" * 78)
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "Standard Template Project",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "ViperZipfileProject - zipfile 模块测试",
"version": "1.0.0",
"source_dir": "./App",
"build_dir": "./.tpv_build",
"build_dir": "./__vpcbuild__",
"compiler": {
"cmd": "llc",
"flags": [