上周的热门开源项目,Star 数增长犹如坐上了火箭,一飞冲天。短短一周就飙升了 6k Star 的多格式文档解析和导出神器 Docling,支持库和命令行的使用方式。全新的可视化爬虫平台 Maxun,则在刚开源时便轻松斩获了 4k Star。而本地优先的个人理财工具 Actual,支持 Docker 自托管,让用户可以将数据掌握在自己手里。如果你在寻找机器学习的 Python 库,可以去 best-of-ml-python 看一看,它涵盖了 34 个分类,共计 920 个优秀的机器学习 Python 库。

最后,免费的 Windows 应用卸载利器(Bulk-Crap-Uninstaller)和 B 站视频空降助手(BilibiliSponsorBlock),凭借着简单实用、开箱即用的特点,迅速赢得了广大用户的青睐。

  • 本文目录
    • 1. 热门开源项目
      • 1.1 多格式文档解析和导出工具:Docling
      • 1.2 本地优先的个人理财工具:Actual
      • 1.3 简单干净的 Hugo 主题:hugo-PaperMod
      • 1.4 开源的无代码网页数据提取平台:Maxun
      • 1.5 顶级的机器学习 Python 库列表:best-of-ml-python
    • 2. HelloGitHub 热评
      • 2.1 B 站视频空降助手:BilibiliSponsorBlock
      • 2.2 免费的 Windows 应用卸载神器:Bulk-Crap-Uninstaller
    • 3. 结尾

1. 热门开源项目

1.1 多格式文档解析和导出工具:Docling

主语言:Python

Star:7.9k

周增长:6k

这是一个由 IBM 开源的 Python 工具,专门用于将各类文档转化为适合生成式 AI 使用的工具。它能够将 PDF、DOCX、PPTX、图片、HTML、Markdown 等多种流行文档格式,导出为 Markdown 和 JSON 格式,支持多种 OCR 引擎(PDF)、统一的文档对象(DoclingDocument),轻松集成检索增强生成(RAG)和问答应用,适用于需要将文档作为生成式 AI 模型输入的场景。

from docling.document_converter import DocumentConverter

source = "url"  # document per local path or URL
converter = DocumentConverter()
result = converter.convert(source)
print(result.document.export_to_markdown())  # output: "## Docling Technical Report[...]"

GitHub 地址→
github.com/DS4SD/docling

1.2 本地优先的个人理财工具:Actual

主语言:TypeScript

Star:15k

周增长:600

这是一款完全免费开源、本地优先的个人理财工具。它采用 Node.js 编写,拥有简洁的界面和直观的现金流报告,支持 Docker 自建、导入交易数据和多设备同步,以及可选的端到端加密功能,注重保护用户隐私和数据安全。

GitHub 地址→
github.com/actualbudget/actual

1.3 简单干净的 Hugo 主题:hugo-PaperMod

主语言:HTML

Star:10k

这是一个快速、简洁、响应式的 Hugo 主题。它基于 hugo-paper 开发,并在此基础上增加了更多功能和自定义选项,支持多语言、自动切换明暗主题、SEO 友好、社交媒体分享按钮、封面图片、导航栏等功能。此外,它还提供了常规、主页信息和个人资料三种模式,可用于快速构建不同风格的个人博客。

GitHub 地址→
github.com/adityatelange/hugo-PaperMod

1.4 开源的无代码网页数据提取平台:Maxun

主语言:TypeScript

Star:4k

周增长:3k

这是一款全新的无代码网页数据提取平台,无需编程即可轻松抓取网站的数据,支持列表/文本抓取、截图、自定义代理、自动处理分页和滚动等功能。作为一个新的开源项目,它的功能还在不停迭代,计划推比如适应网站布局变化和登录后数据提取等新功能。

GitHub 地址→
github.com/getmaxun/maxun

1.5 顶级的机器学习 Python 库列表:best-of-ml-python

主语言:Other

Star:17k

周增长:1.2k

该项目提供了一个高质量的机器学习 Python 库列表,包含超过 900 个开源项目,并按照项目质量评分进行排名,每周更新一次。所有开源项目被分成了 30 多个分类,包括机器学习框架、数据可视化、自然语言处理、OCR、模型序部署等,便于不同应用领域的开发者快速找到所需的机器学习工具和资源。

GitHub 地址→
github.com/ml-tooling/best-of-ml-python

2. HelloGitHub 热评

在此章节中,我们将为大家介绍本周 HelloGitHub 网站上的热门开源项目,我们不仅希望您能从中收获开源神器和编程知识,更渴望“听”到您的声音。欢迎您与我们分享使用这些
开源项目的亲身体验和评价
,用最真实反馈为开源项目的作者注入动力。

2.1 B 站视频空降助手:BilibiliSponsorBlock

主语言:TypeScript

这是一款能够自动跳过 B 站视频中恰饭片段和开场、结尾动画的浏览器插件,所有标注数据均由网友贡献,支持 Chrome、Edge 和 FireFox 浏览器。

项目详情→
hellogithub.com/repository/298fa9ba909c49428c1dc7f8c401bbbd

2.2 免费的 Windows 应用卸载神器:Bulk-Crap-Uninstaller

主语言:C#

这是一个用 C# 开发的 Windows 软件卸载工具,能够快速删除大量不需要的应用程序。它完全免费、开箱即用,支持批量和强制卸载、清理残留文件、检测隐藏或受保护的已注册应用等功能。虽然面向 IT 专业人员设计,但其简单的默认设置,让任何人都能轻松上手。

项目详情→
hellogithub.com/repository/e5745984014e47f1a33648c0425256a0

3. 结尾

以上就是本期「GitHub 热点速览」的全部内容,希望你能够在这里找到自己感兴趣的开源项目,如果你有其他好玩、有趣的 GitHub 开源项目想要分享,欢迎来
HelloGitHub
与我们交流和讨论。

往期回顾

教程名称:使用 C# 入门深度学习

作者:痴者工良

地址:

https://torch.whuanle.cn

1.2 Pytorch 基础

本文内容介绍 Pytorcn 的基础 API,主要是数组的创建方式和运算方式,由于相关内容跟 Numpy 比较相似,并且 Numpy 类型可以转 torch.Tensor,因此对 Numpy 感兴趣的读者可以参考笔者的其它文章:

  • Python 之 Numpy 框架入门

https://www.whuanle.cn/archives/21461

https://www.cnblogs.com/whuanle/p/17855578.html


提示:学习本文时,如果对线性代数有足够的了解,则学习效果更佳,没有线性代数基础也没关系,后面会学习到。本文会同时使用 Python 和 C# 编写示例,方便各位读者对照差异,在后续的章节学习中,基本只会使用 C# 编写示例。


基础使用

由于神经网络中的数值很多以向量或数组等形式存在,不像日常编程中的数值类型那么简单,因此打印数值信息是我们学习了解或调试程序的一种手段,下面我们来观察程序是怎么打印 Pytorch 中复杂数据类型的。


打印

下面使用 Pytorch 创建一个从 0..9 的数组,接着打印数组。

Python:

import torch
x = torch.arange(10)
print(x)
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])


C# 版本不使用
Console.WriteLine()
,而是使用官方提供的库。

using TorchSharp;

var x = torch.arange(10);
x.print(style:TensorStringStyle.Default);
x.print(style:TensorStringStyle.Numpy);
x.print(style:TensorStringStyle.Metadata);
x.print(style:TensorStringStyle.Julia);
x.print(style:TensorStringStyle.CSharp);
[10], type = Int64, device = cpu 0 1 2 3 4 5 6 7 8 9
[0, 1, 2, ... 7, 8, 9]
[10], type = Int64, device = cpu
[10], type = Int64, device = cpu 0 1 2 3 4 5 6 7 8 9
[10], type = Int64, device = cpu, value = long [] {0L, 1L, 2L, ... 7L, 8L, 9L}


Python 打印的结果比较容易理解,C# 默认打印的方式比较难看,所以一般来说,可视化都使用
TensorStringStyle.Numpy
枚举。

C# 打印数值时,参数有个
string? fltFormat = "g5"
,表示精确度的意思,即打印的小数位数。

在 Maomi.Torch 包中提供了一些扩展方法,读者可以使用
x.print_numpy()
扩展直接打印对应风格的信息。


对于后面的章节来说,默认都引入 Python 的 torch 包名称、C# 的 TorchSharp 命名空间,后续代码示例可能会省略引入代码,读者自行引入。


基本数据类型

Pytorch 的数据类型跟我们编程语言中的基本类型不太一样,读者要注意区别。

具体详细的官方文档参考链接:

https://pytorch.org/docs/stable/tensor_attributes.html

https://pytorch.ac.cn/docs/stable/tensor_attributes.html


Pytorch 创建的数据类型以
torch.Tensor
表示,
torch.Tensor
是用来处理机器学习模型中的各种数据的基础结构,包括标量、向量、矩阵以及更高维度的张量。
如果笔者没理解错的话,在 Pytorch 中创建的 Tensor 对象就叫张量。开发者可以通过各种形式的数据在 Pytorch 创建 Tensor

Pytorch 创建的数据类型,都使用 Tensor 对象表示。

对于这句话的理解,建议看完本文再回头看看。


PyTorch 有十二种不同的数据类型,列表如下:

数据类型 dtype
32 位浮点数 torch.float32

torch.float
64 位浮点数 torch.float64

torch.double
64 位复数 torch.complex64

torch.cfloat
128 位复数 torch.complex128

torch.cdouble
16 位浮点数 torch.float16

torch.half
16 位浮点数 torch.bfloat16
8 位整数(无符号) torch.uint8
8 位整数(有符号) torch.int8
16 位整数(有符号) torch.int16

torch.short
32 位整数(有符号) torch.int32

torch.int
64 位整数(有符号) torch.int64

torch.long
布尔值 torch.bool


下面示范在创建一个数值全为 1 的数组时,设置数组的类型。

Python:

float_tensor = torch.ones(1, dtype=torch.float)
double_tensor = torch.ones(1, dtype=torch.double)
complex_float_tensor = torch.ones(1, dtype=torch.complex64)
complex_double_tensor = torch.ones(1, dtype=torch.complex128)
int_tensor = torch.ones(1, dtype=torch.int)
long_tensor = torch.ones(1, dtype=torch.long)
uint_tensor = torch.ones(1, dtype=torch.uint8)


C#:

var float_tensor = torch.ones(1, dtype: torch.float32);
var double_tensor = torch.ones(1, dtype: torch.float64);
var complex_float_tensor = torch.ones(1, dtype: torch.complex64);
var complex_double_tensor = torch.ones(1, dtype: torch.complex128);
var int_tensor = torch.ones(1, dtype: torch.int32); ;
var long_tensor = torch.ones(1, dtype: torch.int64);
var uint_tensor = torch.ones(1, dtype: torch.uint8);


在 C# 中, torch.ScalarType 枚举表示 Pytorch 的数据类型,所以可以有以下两种方式指定数据类型。

例如:

var arr = torch.zeros(3,3,3, torch.ScalarType.Float32);
arr.print_numpy();

或:

var arr = torch.zeros(3,3,3, torch.float32);
arr.print_numpy();


CPU 或 GPU 运算

我们知道,AI 模型可以在 CPU 下运行,也可以在 GPU 下运行,Pytorch 的数据也可以这样做,在创建数据类型时就设置绑定的设备,在运算使用会使用对应的设备进行运算。

一般使用
cpu
表示 CPU,使用
cuda

cuda:{显卡序号}
表示 GPU。


下面编写代码判断 Pytorch 正在使用 GPU 还是 CPU 运行。


Python:

print(torch.get_default_device())


C#:

 Console.WriteLine(torch.get_default_device())


如果当前设备支持 GPU,则使用 GPU 启动 Pytorch,否则使用 CPU 启动 Pytorch。可以通过
torch.device('cuda')

torch.device('cuda:0')
指定使用 GPU 、指定使用哪个 GPU。


Python:

if torch.cuda.is_available():
    print("当前设备支持 GPU")
    device = torch.device('cuda')
    # 使用 GPU 启动
    torch.set_default_device(device)
    current_device = torch.cuda.current_device()
    print(f"绑定的 GPU 为:{current_device}")
else:
    # 不支持 GPU,使用 CPU 启动
    device = torch.device('cpu')
    torch.set_default_device(device)

default_device = torch.get_default_device()
print(f"当前正在使用 {default_device}")


C#:

if (torch.cuda.is_available())
{
    Console.WriteLine("当前设备支持 GPU");
    var device = torch.device("cuda",index:0);
    // 使用 GPU 启动
    torch.set_default_device(device);
}
else
{
    var device = torch.device("cpu");
    // 使用 CPU 启动
    torch.set_default_device(device);
    Console.WriteLine("当前正在使用 CPU");
}

var default_device = torch.get_default_device();
Console.WriteLine($"当前正在使用 {default_device}");

C# 没有
torch.cuda.current_device()
这个方法,建议默认设置使用哪块 GPU,即设置 index 参数。


另外可以通过使用
torch.cuda.device_count()
获取设备有多少个显卡,这里不再赘述。


Pytorch 还支持针对单独的数据类型设置使用 CPU 还是 GPU,还可以让两者混合运算,这里不再赘述。


Tensor 类型

在 Pytorch 中,可以将标量、数组等类型转换为 Tensor 类型,Tensor 表示的数据结构就叫张量。

x = torch.tensor(3.0);


基本数组

Pytorch 使用
asarray()
函数将 obj 值转换为数组,其定义如下:

torch.asarray(obj, *, dtype=None, device=None, copy=None, requires_grad=False) → Tensor

官方 API 文档:
https://pytorch.org/docs/stable/generated/torch.asarray.html#torch-asarray


obj
可以是以下之一:

  • a tensor(张量)
  • a NumPy array or a NumPy scalar(NumPy 数组或 NumPy 标量)
  • a DLPack capsule
  • an object that implements Python’s buffer protocol
  • a scalar(标量)
  • a sequence of scalars(标量序列)

笔者不会的或者本文用不到的,就不翻译了。


比如说,传入一个平常的数组类型,转换成 Pytorch 中的数组类型。


Python:

arr = torch.asarray([1,2,3,4,5,6], dtype=torch.float)
print(arr)


C#:

var arr = torch.from_array(new float[] { 1, 2, 3, 4, 5 });
arr.print(style: TensorStringStyle.Numpy);


请注意,两种语言的版本差异有些大。

前面提到过,可以给单独的数据类型设置使用 CPU 还是 GPU。

device = torch.device("cuda",index=0)
arr = torch.asarray(obj=[1,2,3,4,5,6], dtype=torch.float, device=device)
print(arr)


将数据类型转换为使用 CPU 设备:

device = torch.device("cuda",index=0)
arr = torch.asarray(obj=[1,2,3,4,5,6], dtype=torch.float, device=device)
arr = arr.cpu()
print(arr)


但是将数据在 GPU、CPU 之间转换,会消耗一定的性能。


生成数组

torch.zeros

用于创建一个元素全为 0 的数组,可以指定数组大小,其定义如下:

torch.zeros(*size, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor


Python:

arr = torch.zeros(10, dtype=torch.float)
print(arr)


C#:

var arr = torch.zeros(10);
arr.print(style: TensorStringStyle.Numpy);


另外,可以指定生成的数组维度,例如下面指定生成
2*3
的多维数组。

var arr = torch.zeros(2,3, torch.float32);
arr.print(style: TensorStringStyle.Numpy); 

代码为 C# 语言。


打印:

[[0, 0, 0] [0, 0, 0]]


我们还可以生成多种维度的数组,例如下面生成一个
3*3*3
的数组:

var arr = torch.zeros(3,3,3, torch.float32);
arr.print(style: TensorStringStyle.Numpy); 


为了方便理解,下面将打印结果做了格式化处理。

[
[[0, 0, 0]  [0, 0, 0]  [0, 0, 0]]
[[0, 0, 0]  [0, 0, 0]  [0, 0, 0]]
[[0, 0, 0]  [0, 0, 0]  [0, 0, 0]]
]


torch.ones

创建一个全由 1 填充的数组,使用方法跟 torch.zeros 完全一致,因此这里不再赘述。


torch.empty

创建一个未初始化的数组,使用方法跟 torch.zeros 完全一致,因此这里不再赘述。

由于其没有初始化内存,因此内存区域会残留数据,元素的值不确定。


复制函数

此外,上面三个函数还有对应的原型复制函数:

torch.ones_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor
torch.zeros_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor
torch.empty_like(input, *, dtype=None, layout=None, device=None, requires_grad=False, memory_format=torch.preserve_format) → Tensor


它们的作用是根据数组类型,拷贝一个相同的结构,然后填充对应值。

如下示例,复制数组相同的结构,但是填充的值为 1。

var arr = torch.ones_like(torch.zeros(3, 3, 3));
arr.print(style: TensorStringStyle.Numpy);

该代码语言为 C#。


[
[[1, 1, 1]  [1, 1, 1]  [1, 1, 1]]
[[1, 1, 1]  [1, 1, 1]  [1, 1, 1]]
[[1, 1, 1]  [1, 1, 1]  [1, 1, 1]]
]


torch.rand

torch.rand 会生成一个张量,数组会填充来自
[0,1)
区间上的均匀分布的随机数。

函数定义如下:

torch.rand(*size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor


例如生成
2*3
大小的,范围在
[0,1)
区间的随机数,使用 C# 编写代码:

var arr = torch.rand(2,3);
arr.print(style: TensorStringStyle.Numpy);
[[0.60446, 0.058962, 0.65601] [0.58197, 0.76914, 0.16542]]


由于 C# 绘制图形的库不像 Python matplotlib 简单易用,因此读者可以引用 Maomi.Torch.ScottPlot、Maomi.ScottPlot.Winforms 两个包,可以快速转换 Pytorch 类型和生成绘制窗口 。下面示范使用编写代码绘制均匀分布的随机数,方便使用 Python matplotlib 和 Maomi.ScottPlot.Winforms 框架显示图形。

Python:

import torch
import matplotlib.pyplot as plt

arr = torch.rand(100, dtype=torch.float)

print(arr)

x = arr.numpy()
y = x
plt.scatter(x,y)
plt.show()


C#:

using Maomi.Torch;
using Maomi.Plot;
using TorchSharp;

var x = torch.rand(100);

x.print(style: TensorStringStyle.Numpy);

ScottPlot.Plot myPlot = new();
myPlot.Add.Scatter(x, x);
var form = myPlot.Show(400, 300);


由图可知,生成的随机数是均匀散布在
[0,1)
区间内。


torch.randn

生成具有给定形状的标准正态分布(平均值为0,方差为1)的随机样本。随机样本取值范围是[0,1)。

定义如下:

torch.randn(*size, *, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False) → Tensor

官方文档:
https://pytorch.ac.cn/docs/stable/generated/torch.randn.html#torch.rand


由于 C# 不好绘图,这里使用 Python 编写示例:

import torch
import matplotlib.pyplot as plt

arr = torch.randn(100, dtype=torch.float)

print(arr)

x = arr.numpy()
y = x
plt.hist(x, bins=30, alpha=0.5, color='b', edgecolor='black')

plt.show()

x 坐标轴是数值,y 坐标轴是出现次数。

image-20241103125947540


torch.randint

在某个区间内生成随机数。

定义如下:

torch.randint(low=0, high, size, \*, generator=None, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor


比如在 0-100 范围内生成 10 个元素,安装
5*2
结构组成,使用 C# 代码编写。

var arr = torch.randint(low: 0, high: 100, size: new int[] { 5, 2 });
arr.print(style: TensorStringStyle.Numpy);
[[17, 46] [89, 52] [10, 89] [80, 91] [52, 91]]


如果要生成某个区间的浮点数,则可以使用
torch.rand
,但是因为
torch.rand
生成范围是
[0,1)
,因此需要自行乘以倍数。例如要生成
[0,100)
的随机数。

var arr = torch.rand(size: 100, dtype: torch.ScalarType.Float32) * 100;
arr.print(style: TensorStringStyle.Numpy);  


torch.arange

指定区间以及步长,均匀提取元素生成数组。

定义如下:

torch.arange(start=0, end, step=1, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor


比如说,需要生成
[0,1,2,3,4,5,6,7,8,9]
这样的数组,可以使用:

var arr = torch.arange(start: 0, stop: 10, step: 1);
arr.print(style: TensorStringStyle.Numpy);


如果将步长改成 0.5。

var arr = torch.arange(start: 0, stop: 10, step: 0.5);
[0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000,
        4.5000, 5.0000, 5.5000, 6.0000, 6.5000, 7.0000, 7.5000, 8.0000, 8.5000,
        9.0000, 9.5000]


数组操作和计算


在 Pytorch 中,往往使用 dim(dimension) 参数表示轴,轴就是张量的层数。

有以下数组:

[[ 1, 2, 3 ], { 4, 5, 6 ]]

如果把
a = [1,2,3]

b = [4,5,6]
,则:

[a,b]


那么当我们要获取
a
时,
dim(a) = 0

dim(b) = 1

var arr = torch.from_array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } });

arr.print(style: TensorStringStyle.Numpy);

// 打印维度
arr.shape.print();

var a = arr[0];
a.print();
var b = arr[1];
b.print();
[[1, 2, 3] [4, 5, 6]]
[2, 3]
[3], type = Int32, device = cpu 1 2 3
[3], type = Int32, device = cpu 4 5 6


这里我们分两步理解,由于该数组是
2*3
数组,可以使用
.shape.print()
打印出来。

由于第一层有两个元素,因此可以使用
Tensor[i]
获取第一层的第 i 个元素,其中
i<2

同理,由于 a、b 的下一层都有 3 个元素,因此第二层
n<3


例如要将数组的
3

6
两个元素取出来。

用 C# 可以这样写,但是打印的时候不能选 TensorStringStyle.Numpy ,否则打印不出来。

var arr = torch.from_array(new[,] { { 1, 2, 3 }, { 4, 5, 6 } });

var a = arr[0, 2];
a.print(style: TensorStringStyle.CSharp);
var b = arr[1, 2];
b.print(style: TensorStringStyle.CSharp);


同理,如果数组有三层,可以这样获取
3

6
两个元素

var arr = torch.from_array(new[, ,] { { { 1, 2, 3 } }, { { 4, 5, 6 } } });

var a = arr[0, 0, 2];
a.print(style: TensorStringStyle.CSharp);
var b = arr[1, 0, 2];
b.print(style: TensorStringStyle.CSharp);


如果要取出一部分元素,TorchCsharp 可以使用
a[i..j]
的语法截取,示例如下。

var arr = torch.from_array(new int[] { 1, 2, 3 });
arr = arr[0..2];
arr.print(style: TensorStringStyle.Numpy);
[1, 2]


数组排序

Pytorch 中有一些排序函数:

sort
:沿给定维度按值升序对
input
张量的元素进行排序。

argsort
:它是沿指定轴的间接排序,本文不讲解。

msort
:按值对
input
张量沿其第一维以升序排序。
torch.msort(t)
等效于
torch.sort(t, dim=0)


sort
可以降序或升序,参数说明如下:

torch.sort(input, dim=-1, descending=False, stable=False, *, out=None)
  • input
    (张量) – 输入张量。
  • dim
    (int,可选) – 要排序的维度
  • descending
    (bool,可选) – 控制排序顺序(升序或降序)
  • stable
    (boo,可选) – 使排序例程稳定,从而保证等效元素的顺序得以保留。


示例:

var arr = torch.arange(start: 0, stop: 10, step: 1);

// 或者使用 torch.sort(arr, descending: true)
(torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort(descending: true);

a1.Values.print(style: TensorStringStyle.Numpy);
[9, 8, 7, ... 2, 1, 0]


Values 是排序后的结果,Indices 是排序的规则。


如果数组结构比较复杂,默认不设置参数时,只有最内层数组进行排序。如下代码所示,有两层数组。

var arr = torch.from_array(new[,] { { 4, 6, 5 }, { 8, 9, 7 }, { 3, 2, 1 } });

(torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort();

a1.Values.print(style: TensorStringStyle.Numpy);
a1.Indices.print(style: TensorStringStyle.Numpy);
[[4, 5, 6] [7, 8, 9] [1, 2, 3]]
[[0, 2, 1] [2, 0, 1] [2, 1, 0]]

Indices 会记录当前元素在以前的排序位置。


当设置
arr.sort(dim: 0);
时,按照第一层排序。

[[3, 2, 1] [4, 6, 5] [8, 9, 7]]
[[2, 2, 2] [0, 0, 0] [1, 1, 1]]


当设置
arr.sort(dim: 1);
时,只有里面一层排序。

[[4, 5, 6] [7, 8, 9] [1, 2, 3]]
[[0, 2, 1] [2, 0, 1] [2, 1, 0]]


当一个张量的维度比较大时,我们可以这样逐层排序。

var arr = torch.from_array(new[, ,] { { { 4, 6, 5 }, { 8, 9, 7 }, { 3, 2, 1 } } });

var dimCount = arr.shape.Length;
for (int i = dimCount - 1; i >= 0; i--)
{
    (torch.Tensor Values, torch.Tensor Indices) a1 = arr.sort(dim: i);
    arr = a1.Values;
    arr.print(style: TensorStringStyle.Numpy);
}
[[[1, 2, 3]  [4, 5, 6]  [7, 8, 9]]]


C# 多维数组没有 Python 那么方便,会要求每一层的元素个数必须一致。

例如下面的数组声明是对的:

var array = new int[, , ]
{
    {
        { 10, 12, 11},{ 14, 15, 11 }
    },
    {
        { 4, 6, 5 }, { 8, 9, 7 }
    }
};


如果层数元素个数不一致会报错:

image-20241103203955447


另外要注意,C# 有多维数组和交错数组,下面是交错数组的声明方式,TorchSharp 并不支持。多维数组是数组,交错数组是数组的数组,或数组的数组的数组,要注意区分。

var array = new int[][][]
{
    new int[][]
    {
        new int[] { 1, 2, 3 },
        new int[] { 4, 5, 6 },
        new int[] { 7, 8, 9 }
    },
    new int[][]
    {
        new int[] { 10, 12, 11 },
        new int[] { 14, 15, 13 }
    }
};

image-20241103204339232


数组运算符

在 PyTorch 中,张量支持许多运算符,下面列举部分加以说明:


算术运算符

  • +
    :加法,如
    a + b
  • -
    :减法,如
    a - b
  • *
    :元素级乘法,如
    a * b
  • /
    :元素级除法,如
    a / b
  • //
    :元素级整除,如
    a // b
    ,TorchCsharp 不支持。
  • %
    :取模运算,如
    a % b
  • **
    :幂运算,如
    a ** b
    ,TorchCsharp 不支持,使用
    .pow(x)
    代替。


逻辑运算符

  • ==
    :元素级相等比较,如
    a == b
  • !=
    :元素级不等于比较,如
    a != b
  • >
    :元素级大于比较,如
    a > b
  • <
    :元素级小于比较,如
    a < b
  • >=
    :元素级大于等于比较,如
    a >= b
  • <=
    :元素级小于等于比较,如
    a <= b


位运算符

  • &
    :按位与运算,如
    a & b
  • |
    :按位或运算,如
    a | b
  • ^
    :按位异或运算,如
    a ^ b
  • ~
    :按位取反运算,如
    ~a
  • <<
    :按位左移,如
    a << b
  • >>
    :按位右移,如
    a >> b


索引和切片

  • [i]
    :索引运算符,如
    a[i]
  • [i:j]
    :切片运算符,如
    a[i:j]
    ,TorchCsharp 使用
    a[i..j]
    语法。
  • [i, j]
    :多维索引运算符,如
    a[i, j]


例如张量每个元素的值
*10

var arr = torch.from_array(new int[] { 1, 2, 3 });
arr = arr * 10;
arr.print(style: TensorStringStyle.Numpy);
[10, 20, 30]


此外,还有 Pytorch 还很多函数,后面的章节中会逐渐学习。


一、概述

木舟平台分为微服务平台和物联网平台, 上面几篇都是介绍如何通过网络组件接入设备,那么此篇文章就细致介绍下在木舟平台下如何构建微服务。

木舟 (Kayak) 是什么?

木舟(Kayak)是基于.NET6.0软件环境下的surging微服务引擎进行开发的, 平台包含了微服务和物联网平台。支持异步和响应式编程开发,功能包含了物模型,设备,产品,网络组件的统一管理和微服务平台下的注册中心,服务路由,模块,中间服务等管理。还有多协议适配(TCP,MQTT,UDP,CoAP,HTTP,Grpc,websocket,rtmp,httpflv,webservice,等),通过灵活多样的配置适配能够接入不同厂家不同协议等设备。并且通过设备告警,消息通知,数据可视化等功能。能够让你能快速建立起微服务物联网平台系统。

二、构建服务

创建服务接口,继承IServiceKey,添加特性[ServiceBundle("api/{Service}/{Method}")] 配置routepath,代码如下:

   [ServiceBundle("api/{Service}/{Method}")]public interfaceITestApiService:IServiceKey
{
public Task<string> SayHello(stringname);
}

创建服务实例,继承ProxyServiceBase, ITestApiService, ISingleInstance,如果只是业务处理只需继承ProxyServiceBase,继承ISingleInstance表示注入的生命周期 为单例模式,添加特性ModuleName标识一个服务多个实例,可以在调用的时候传入ServiceKey

    [ModuleName("Test")]public classTestService : ProxyServiceBase, ITestApiService, ISingleInstance
{
public Task<string> SayHello(stringname)
{
return Task.FromResult($"{name} say:hello world");
}
}

二、身份鉴权

webapi调用必然会牵涉到身份鉴权,用户登录问题,而surging 已经集成了一套jwt验证机制

然后在Stage配置节上配置ApiGetWay

   "ApiGetWay": {"AccessTokenExpireTimeSpan": "240","AuthorizationRoutePath": "api/sysuser/authentication",//身份鉴权服务的routepath
     "AuthorizationServiceKey": null,"TokenEndpointPath": "api/oauth2/token",//映射调用的routepath
     "CacheMode": "MemoryCache" //MemoryCache or  gateway.Redis save token
   }

然后在接口方法上加上  [Authorization(AuthType = AuthorizationType.JWT)] 特性,服务调用就要进行身份鉴权

    public interfaceIModuleService : IServiceKey
{
[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<bool>>Add(ModuleModel model);

[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<bool>>Modify(ModuleModel model);

[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<Page<ModuleModel>>>GetPageAsync(ModuleQuery query);

}

三、缓存拦截

surging 可以支持拦截缓存,可以通过
ServiceCacheIntercept特性进行配置,获取缓存可以通过
CachingMethod.Get
, 删除缓存可以通过
CachingMethod.Remove
,可以支持MemoryCache,Redis, 可以支持一,二级缓存,

启用EnableStageCache表示网关调用也可以走缓存拦截(注:不支持模型参数)

 [ServiceBundle("api/{Service}/{Method}")]public interfaceIProductService : IServiceKey
{
[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Remove,
"GetProducts", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
Task
<ApiResult<bool>>Add(ProductModel model);

[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<ProductModel>> GetProduct(intid);

[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<Page<ProductModel>>>GetPageAsync(ProductQuery query);

[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<List<ProductModel>>>GetProductByCondition(ProductQuery query);

[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Remove,
"GetProducts", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
[ServiceLogIntercept]
Task
<ApiResult<bool>> DeleteById(List<int>ids);

[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Remove,
"GetProducts", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
Task
<ApiResult<bool>>Modify(ProductModel model);


[Authorization(AuthType
=AuthorizationType.JWT)]
Task
<ApiResult<bool>>Validate(ProductModel model);

[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Remove,
"GetProducts", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
Task
<ApiResult<bool>> Stop(List<int>ids);

[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Remove,
"GetProducts", CacheSectionType = "ddlCache", Mode = CacheTargetType.MemoryCache, EnableStageCache = true)]
Task
<ApiResult<bool>> Open(List<int>ids);

[Authorization(AuthType
=AuthorizationType.JWT)]
[ServiceCacheIntercept(CachingMethod.Get, Key
= "GetProducts", CacheSectionType = "ddlCache", EnableL2Cache = false, Mode = CacheTargetType.MemoryCache, Time = 480, EnableStageCache = true)]
Task
<ApiResult<List<ProductModel>>>GetProducts();


}

参数如果是非模型集合类型的参数,缓存key 会取第一个参数值,如果是模型参数就需要添加CacheKey特性,代码如下:

    public classPropertyThresholdQuery
{
[CacheKey(
1)]public string PropertyCode { get; set; }
[CacheKey(
2)]public string ProductCode { get; set; }
[CacheKey(
3)]public string DeviceCode { get; set; }
}

四、服务管理

1.平台是支持服务路由管理,此项功能除了可以查看元数据,服务节点,服务规则外,还可以在权重轮询负载算法情况下,改变权重可以让更多的访问调用到此服务节点上,还有可以优雅的移除服务节点

选择权重轮询负载分流算法,代码如下:

    [ServiceBundle("api/{Service}/{Method}")]public interfaceITestApiService:IServiceKey
{
//[Authorization(AuthType = AuthorizationType.JWT)] [Command(ShuntStrategy =AddressSelectorMode.RoundRobin)]public Task<string> SayHello(stringname);
}

以下是编辑权重

2. 热部署中间服务

3. 黑白名单,添加IP地址或者IP段就能限制相关IP访问

就比如访问api/testapi,结果如下:

4.支持swagger API文档

五、分布式链路追踪

支持skywalking 分布式链路追踪

六 、构建发布

1. 微服务发布:

发布微服务的时候,需要引用的是微服务,不要引用stage, 如下图

2. 网关发布, 引用服务接口和聚合服务(中间服务)模块,还有stage 模块

七、总结

以上是木舟平台如何构建服务,平台定于11月20日发布1.0社区版本。也请大家到时候关注捧场。

来源:晓飞的算法工程笔记 公众号,转载请注明出处

论文: CLIP Adaptation by Intra-modal Overlap Reduction

创新点


  • 提出一种基于轻量级适配的新方法,直接在图像空间中减少
    CLIP
    中的模态内重叠(
    IMO
    )。新特征与任何利用缓存模型的无训练方法兼容,这些新特征提高了所有被检查的无训练方法的整体性能。
  • 表明直接减少模态内重叠(
    IMO
    )与性能之间存在正相关关系。
  • 探索了通过在监督和自监督方式下训练轻量级适配器来减少模态内重叠(
    IMO
    )的可能性。

内容概述


许多方法尝试将预训练的基础
CLIP
模型适应于少样本分类,因为
CLIP
在大规模语料库上进行训练,它能够通过适应少样本分类而具有良好的泛化能力。但当尝试在与预训练数据的分布差异显著的数据集上使用这一基础模型时,观察到性能并不理想。

论文分析了图像空间内的模态重叠,从嵌入表示的角度出发。由于对比训练最大化了配对图像和文本之间的余弦相似性(跨模态),而忽略了图像与图像之间的相似性(模态内),在图像空间中比较来自
CLIP
的嵌入是有问题的。这导致了非配对(不同类别的图像)和配对图像(同一类别的图像)之间存在显著的模态内重叠(
IMO
),这影响了依赖于图像空间相似性进行预测的少样本无训练分类方法的性能。

为了解决模态内的重叠,在
Google Open Images
数据集的通用样本集上训练一个轻量级适配器。只需训练一个
epoch
,即可提高少样本无训练分类的准确性。

通过广泛的证明了其有效性,减少模态内重叠可以带来 a ) 在多个标准数据集上提高性能,b ) 增强对分布变化的鲁棒性,以及 c ) 提高特征方差,使特征在下游任务中更具区分能力。

模态内重叠


模态内重叠分析

由于对比学习最大化了成对图像与文本之间的余弦相似度(模态间),但忽略了图像与图像之间的相似度(模态内),导致模态内重叠(
IMO
)。

通过适应校正模态内重叠(
IMO

为了在
CLIP
视觉编码器中校正模态内重叠(
IMO
),引入了瓶颈适配器并在来自
Google Open Images
数据集的小样本图像上以监督方式进行微调。适配器是轻量级组件,向模型中添加了
0.80%
(大约
1M
)的新参数。

微调得到新的
CLIP
视觉编码器(
VEimo
)后,利用它创建一个改进的缓存模型,类似于
Tip-Adapter
。使用校正了
IMO
的编码
N
个类别各
K
张的训练图像
\(G_{train} \in \mathbb{R}^{NK\times d}\)
,将这些编码作为键,它们对应的
one-hot
编码标签
\(L_k, k \in \{1, NK\}\)
作为值,以形成键值缓存模型,目的是增强
CLIP
模型的先验知识。

给定一个通过
VEimo
编码的测试图像
\(U_i \in \mathbb{R}^{d}\)

Affinity
矩阵
\(Y\)

Tip-Adapter
++(
TA
++)的对数计算如下(用于
softmax
标签预测):

\[\begin{equation}
Y = exp(-\beta(1-U_i G_{train}^T)), Y \in \mathbb{R}^{NK}
\label{eq:ta_affinity_modgap}
\end{equation}
\]

\[\begin{equation}
\text{TA++logits} = T_i W^T + \alpha YL_{train}, \text{TA++logits} \in \mathbb{R}^{N}
\end{equation}
\]

同样,通过用校正后的
IMO
矩阵
\(Y\)
替换标准
Tip-X
的亲和矩阵
\(A\)
来改进标准
Tip-X
,从而获得
Tip-X
++(
TX
++)的对数值(用于
softmax
标签预测):

\[\begin{equation}
\text{TX++logits} = T_i W^T + \alpha YL_{train} + \gamma \phi(-M) L_{train}, \text{TX++logits} \in \mathbb{R}^{N}
\end{equation}
\]

主要实验



如果本文对你有帮助,麻烦点个赞或在看呗~
更多内容请关注 微信公众号【晓飞的算法工程笔记】

work-life balance.

本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议。转载请注明来自
唯你

简介

cargo deny 是一个 Rust 工具,用于检查项目依赖项的许可证、安全性和其他合规性问题。在 Rust CI(持续集成)中,cargo deny 扮演着重要角色:

  • 许可证检查:
    确保项目使用的所有依赖项的许可证都符合项目的许可政策。
  • 安全漏洞扫描:
    检查依赖项是否存在已知的安全漏洞。
  • 依赖项合规性:
    验证依赖项是否符合项目的其他要求,如版本限制或来源限制。
  • 禁用特定依赖项:
    允许明确禁止使用某些依赖项。

在 CI 流程中,cargo deny 通常作为一个检查步骤运行,以确保项目在构建和部署之前满足所有合规性要求。这有助于维护项目的质量、安全性和法律合规性。

一句话:
cargo deny 让你合法合规放心使用第三方依赖

使用

cargo install --locked cargo-deny && cargo deny init && cargo deny check

常见错误

使用 cargo-deny 报错 failed to open advisory database

   Installed package `cargo-deny v0.16.1` (executable `cargo-deny.exe`)
PS E:\Rust\easy-publish> cargo deny check
2024-11-11 02:07:34 [ERROR] failed to fetch advisory database https://github.com/RustSec/advisory-db: An IO error occurred when talking to the server: error sending request for url (https://github.com/RustSec/advisory-db/info/refs?service=git-upload-pack)

方案一: 可以尝试:
1.  删除 ~/.cargo/advisory-db/ 目录,然后使用 cargo deny fetch / cargo deny check 重新下载它。多试几次?
2.  在 deny.toml 配置中的 git 地址修改为 gitee 上的镜像地址:
https://gitee.com/tyr-rust-bootcamp-mirror/advisory-db.git
3.  删掉 deny.toml,执行 cargo deny init 重新生成一个,然后按照你的需要修改。
4.  检查你的网络,想办法~

方案二:可以尝试通过运行:cargo deny check advisories 解决

升级最新版本,大量 this key has been removed

image.png
解决办法:

  1. 先删除原项目下的 deny.toml 配置文件
  2. 在项目根目录下运行命令行
    cargo deny init
    重新生成一份新版本 deny.toml 文件
  3. 在 deny.toml 中找到 allow 然后将原来 allow 中许可证,类似如下代码,拷贝到新 deny.toml 中即可
allow = [
    "MIT",
    "Apache-2.0",
    "Apache-2.0 WITH LLVM-exception",
    "Unicode-DFS-2016",
    "MPL-2.0",
    "BSD-2-Clause",
    "BSD-3-Clause",
    "ISC",
    "CC0-1.0",
    "OpenSSL",
]
  1. 运行
    cargo deny check
    重新检测一波,是否正常